diff options
Diffstat (limited to 'drivers')
158 files changed, 5634 insertions, 29131 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 050323fd79e9..7916f4b86d23 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -24,8 +24,6 @@ source "drivers/scsi/Kconfig" | |||
24 | 24 | ||
25 | source "drivers/ata/Kconfig" | 25 | source "drivers/ata/Kconfig" |
26 | 26 | ||
27 | source "drivers/cdrom/Kconfig" | ||
28 | |||
29 | source "drivers/md/Kconfig" | 27 | source "drivers/md/Kconfig" |
30 | 28 | ||
31 | source "drivers/message/fusion/Kconfig" | 29 | source "drivers/message/fusion/Kconfig" |
@@ -54,6 +52,8 @@ source "drivers/spi/Kconfig" | |||
54 | 52 | ||
55 | source "drivers/w1/Kconfig" | 53 | source "drivers/w1/Kconfig" |
56 | 54 | ||
55 | source "drivers/power/Kconfig" | ||
56 | |||
57 | source "drivers/hwmon/Kconfig" | 57 | source "drivers/hwmon/Kconfig" |
58 | 58 | ||
59 | source "drivers/mfd/Kconfig" | 59 | source "drivers/mfd/Kconfig" |
diff --git a/drivers/Makefile b/drivers/Makefile index adad2f3d438a..503d82569449 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -61,6 +61,7 @@ obj-$(CONFIG_I2O) += message/ | |||
61 | obj-$(CONFIG_RTC_LIB) += rtc/ | 61 | obj-$(CONFIG_RTC_LIB) += rtc/ |
62 | obj-y += i2c/ | 62 | obj-y += i2c/ |
63 | obj-$(CONFIG_W1) += w1/ | 63 | obj-$(CONFIG_W1) += w1/ |
64 | obj-$(CONFIG_POWER_SUPPLY) += power/ | ||
64 | obj-$(CONFIG_HWMON) += hwmon/ | 65 | obj-$(CONFIG_HWMON) += hwmon/ |
65 | obj-$(CONFIG_PHONE) += telephony/ | 66 | obj-$(CONFIG_PHONE) += telephony/ |
66 | obj-$(CONFIG_MD) += md/ | 67 | obj-$(CONFIG_MD) += md/ |
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index 674bf81c6e66..423ed08fb6f7 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c | |||
@@ -1246,7 +1246,7 @@ repeat: | |||
1246 | del_timer(&motor_off_timer); | 1246 | del_timer(&motor_off_timer); |
1247 | 1247 | ||
1248 | ReqCnt = 0; | 1248 | ReqCnt = 0; |
1249 | ReqCmd = CURRENT->cmd; | 1249 | ReqCmd = rq_data_dir(CURRENT); |
1250 | ReqBlock = CURRENT->sector; | 1250 | ReqBlock = CURRENT->sector; |
1251 | ReqBuffer = CURRENT->buffer; | 1251 | ReqBuffer = CURRENT->buffer; |
1252 | setup_req_params(drive); | 1252 | setup_req_params(drive); |
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 689a4c3542ba..d85520f78e68 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c | |||
@@ -439,7 +439,7 @@ static void mfm_rw_intr(void) | |||
439 | a choice of command end or some data which is ready to be collected */ | 439 | a choice of command end or some data which is ready to be collected */ |
440 | /* I think we have to transfer data while the interrupt line is on and its | 440 | /* I think we have to transfer data while the interrupt line is on and its |
441 | not any other type of interrupt */ | 441 | not any other type of interrupt */ |
442 | if (CURRENT->cmd == WRITE) { | 442 | if (rq_data_dir(CURRENT) == WRITE) { |
443 | extern void hdc63463_writedma(void); | 443 | extern void hdc63463_writedma(void); |
444 | if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { | 444 | if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { |
445 | printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n"); | 445 | printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n"); |
@@ -799,7 +799,7 @@ static void issue_request(unsigned int block, unsigned int nsect, | |||
799 | raw_cmd.head = start_head; | 799 | raw_cmd.head = start_head; |
800 | raw_cmd.cylinder = track / p->heads; | 800 | raw_cmd.cylinder = track / p->heads; |
801 | raw_cmd.cmdtype = CURRENT->cmd; | 801 | raw_cmd.cmdtype = CURRENT->cmd; |
802 | raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD; | 802 | raw_cmd.cmdcode = rq_data_dir(CURRENT) == WRITE ? CMD_WD : CMD_RD; |
803 | raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ | 803 | raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ |
804 | raw_cmd.cmddata[1] = raw_cmd.head; | 804 | raw_cmd.cmddata[1] = raw_cmd.head; |
805 | raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8; | 805 | raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8; |
@@ -830,7 +830,7 @@ static void issue_request(unsigned int block, unsigned int nsect, | |||
830 | hdc63463_dataleft = nsect * 256; /* Better way? */ | 830 | hdc63463_dataleft = nsect * 256; /* Better way? */ |
831 | 831 | ||
832 | DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n", | 832 | DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n", |
833 | raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ", | 833 | raw_cmd.dev + 'a', rq_data_dir(CURRENT) == READ ? "read" : "writ", |
834 | raw_cmd.cylinder, | 834 | raw_cmd.cylinder, |
835 | raw_cmd.head, | 835 | raw_cmd.head, |
836 | raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT); | 836 | raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT); |
@@ -917,13 +917,6 @@ static void mfm_request(void) | |||
917 | 917 | ||
918 | DBG("mfm_request: block after offset=%d\n", block); | 918 | DBG("mfm_request: block after offset=%d\n", block); |
919 | 919 | ||
920 | if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) { | ||
921 | printk("unknown mfm-command %d\n", CURRENT->cmd); | ||
922 | end_request(CURRENT, 0); | ||
923 | Busy = 0; | ||
924 | printk("mfm: continue 4\n"); | ||
925 | continue; | ||
926 | } | ||
927 | issue_request(block, nsect, CURRENT); | 920 | issue_request(block, nsect, CURRENT); |
928 | 921 | ||
929 | break; | 922 | break; |
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ca5229d24d8e..11e4eb9f304e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #include <linux/libata.h> | 46 | #include <linux/libata.h> |
47 | 47 | ||
48 | #define DRV_NAME "ahci" | 48 | #define DRV_NAME "ahci" |
49 | #define DRV_VERSION "2.2" | 49 | #define DRV_VERSION "2.3" |
50 | 50 | ||
51 | 51 | ||
52 | enum { | 52 | enum { |
@@ -54,7 +54,7 @@ enum { | |||
54 | AHCI_MAX_PORTS = 32, | 54 | AHCI_MAX_PORTS = 32, |
55 | AHCI_MAX_SG = 168, /* hardware max is 64K */ | 55 | AHCI_MAX_SG = 168, /* hardware max is 64K */ |
56 | AHCI_DMA_BOUNDARY = 0xffffffff, | 56 | AHCI_DMA_BOUNDARY = 0xffffffff, |
57 | AHCI_USE_CLUSTERING = 0, | 57 | AHCI_USE_CLUSTERING = 1, |
58 | AHCI_MAX_CMDS = 32, | 58 | AHCI_MAX_CMDS = 32, |
59 | AHCI_CMD_SZ = 32, | 59 | AHCI_CMD_SZ = 32, |
60 | AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, | 60 | AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, |
@@ -81,6 +81,7 @@ enum { | |||
81 | board_ahci_vt8251 = 2, | 81 | board_ahci_vt8251 = 2, |
82 | board_ahci_ign_iferr = 3, | 82 | board_ahci_ign_iferr = 3, |
83 | board_ahci_sb600 = 4, | 83 | board_ahci_sb600 = 4, |
84 | board_ahci_mv = 5, | ||
84 | 85 | ||
85 | /* global controller registers */ | 86 | /* global controller registers */ |
86 | HOST_CAP = 0x00, /* host capabilities */ | 87 | HOST_CAP = 0x00, /* host capabilities */ |
@@ -171,6 +172,8 @@ enum { | |||
171 | AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ | 172 | AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ |
172 | AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ | 173 | AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ |
173 | AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ | 174 | AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ |
175 | AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ | ||
176 | AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */ | ||
174 | 177 | ||
175 | AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 178 | AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
176 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | | 179 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | |
@@ -228,9 +231,12 @@ static void ahci_thaw(struct ata_port *ap); | |||
228 | static void ahci_error_handler(struct ata_port *ap); | 231 | static void ahci_error_handler(struct ata_port *ap); |
229 | static void ahci_vt8251_error_handler(struct ata_port *ap); | 232 | static void ahci_vt8251_error_handler(struct ata_port *ap); |
230 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); | 233 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); |
234 | static int ahci_port_resume(struct ata_port *ap); | ||
235 | static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); | ||
236 | static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, | ||
237 | u32 opts); | ||
231 | #ifdef CONFIG_PM | 238 | #ifdef CONFIG_PM |
232 | static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); | 239 | static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); |
233 | static int ahci_port_resume(struct ata_port *ap); | ||
234 | static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); | 240 | static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); |
235 | static int ahci_pci_device_resume(struct pci_dev *pdev); | 241 | static int ahci_pci_device_resume(struct pci_dev *pdev); |
236 | #endif | 242 | #endif |
@@ -327,14 +333,14 @@ static const struct ata_port_info ahci_port_info[] = { | |||
327 | { | 333 | { |
328 | .flags = AHCI_FLAG_COMMON, | 334 | .flags = AHCI_FLAG_COMMON, |
329 | .pio_mask = 0x1f, /* pio0-4 */ | 335 | .pio_mask = 0x1f, /* pio0-4 */ |
330 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 336 | .udma_mask = ATA_UDMA6, |
331 | .port_ops = &ahci_ops, | 337 | .port_ops = &ahci_ops, |
332 | }, | 338 | }, |
333 | /* board_ahci_pi */ | 339 | /* board_ahci_pi */ |
334 | { | 340 | { |
335 | .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, | 341 | .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, |
336 | .pio_mask = 0x1f, /* pio0-4 */ | 342 | .pio_mask = 0x1f, /* pio0-4 */ |
337 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 343 | .udma_mask = ATA_UDMA6, |
338 | .port_ops = &ahci_ops, | 344 | .port_ops = &ahci_ops, |
339 | }, | 345 | }, |
340 | /* board_ahci_vt8251 */ | 346 | /* board_ahci_vt8251 */ |
@@ -342,14 +348,14 @@ static const struct ata_port_info ahci_port_info[] = { | |||
342 | .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME | | 348 | .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME | |
343 | AHCI_FLAG_NO_NCQ, | 349 | AHCI_FLAG_NO_NCQ, |
344 | .pio_mask = 0x1f, /* pio0-4 */ | 350 | .pio_mask = 0x1f, /* pio0-4 */ |
345 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 351 | .udma_mask = ATA_UDMA6, |
346 | .port_ops = &ahci_vt8251_ops, | 352 | .port_ops = &ahci_vt8251_ops, |
347 | }, | 353 | }, |
348 | /* board_ahci_ign_iferr */ | 354 | /* board_ahci_ign_iferr */ |
349 | { | 355 | { |
350 | .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, | 356 | .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, |
351 | .pio_mask = 0x1f, /* pio0-4 */ | 357 | .pio_mask = 0x1f, /* pio0-4 */ |
352 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 358 | .udma_mask = ATA_UDMA6, |
353 | .port_ops = &ahci_ops, | 359 | .port_ops = &ahci_ops, |
354 | }, | 360 | }, |
355 | /* board_ahci_sb600 */ | 361 | /* board_ahci_sb600 */ |
@@ -358,7 +364,19 @@ static const struct ata_port_info ahci_port_info[] = { | |||
358 | AHCI_FLAG_IGN_SERR_INTERNAL | | 364 | AHCI_FLAG_IGN_SERR_INTERNAL | |
359 | AHCI_FLAG_32BIT_ONLY, | 365 | AHCI_FLAG_32BIT_ONLY, |
360 | .pio_mask = 0x1f, /* pio0-4 */ | 366 | .pio_mask = 0x1f, /* pio0-4 */ |
361 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 367 | .udma_mask = ATA_UDMA6, |
368 | .port_ops = &ahci_ops, | ||
369 | }, | ||
370 | /* board_ahci_mv */ | ||
371 | { | ||
372 | .sht = &ahci_sht, | ||
373 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | ||
374 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | | ||
375 | ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI | | ||
376 | AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | | ||
377 | AHCI_FLAG_MV_PATA, | ||
378 | .pio_mask = 0x1f, /* pio0-4 */ | ||
379 | .udma_mask = ATA_UDMA6, | ||
362 | .port_ops = &ahci_ops, | 380 | .port_ops = &ahci_ops, |
363 | }, | 381 | }, |
364 | }; | 382 | }; |
@@ -456,6 +474,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
456 | { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ | 474 | { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ |
457 | { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ | 475 | { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ |
458 | 476 | ||
477 | /* Marvell */ | ||
478 | { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ | ||
479 | |||
459 | /* Generic, PCI class code for AHCI */ | 480 | /* Generic, PCI class code for AHCI */ |
460 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 481 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
461 | PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, | 482 | PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, |
@@ -481,11 +502,17 @@ static inline int ahci_nr_ports(u32 cap) | |||
481 | return (cap & 0x1f) + 1; | 502 | return (cap & 0x1f) + 1; |
482 | } | 503 | } |
483 | 504 | ||
484 | static inline void __iomem *ahci_port_base(struct ata_port *ap) | 505 | static inline void __iomem *__ahci_port_base(struct ata_host *host, |
506 | unsigned int port_no) | ||
485 | { | 507 | { |
486 | void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; | 508 | void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; |
509 | |||
510 | return mmio + 0x100 + (port_no * 0x80); | ||
511 | } | ||
487 | 512 | ||
488 | return mmio + 0x100 + (ap->port_no * 0x80); | 513 | static inline void __iomem *ahci_port_base(struct ata_port *ap) |
514 | { | ||
515 | return __ahci_port_base(ap->host, ap->port_no); | ||
489 | } | 516 | } |
490 | 517 | ||
491 | /** | 518 | /** |
@@ -535,6 +562,20 @@ static void ahci_save_initial_config(struct pci_dev *pdev, | |||
535 | hpriv->saved_port_map = port_map; | 562 | hpriv->saved_port_map = port_map; |
536 | } | 563 | } |
537 | 564 | ||
565 | /* | ||
566 | * Temporary Marvell 6145 hack: PATA port presence | ||
567 | * is asserted through the standard AHCI port | ||
568 | * presence register, as bit 4 (counting from 0) | ||
569 | */ | ||
570 | if (pi->flags & AHCI_FLAG_MV_PATA) { | ||
571 | dev_printk(KERN_ERR, &pdev->dev, | ||
572 | "MV_AHCI HACK: port_map %x -> %x\n", | ||
573 | hpriv->port_map, | ||
574 | hpriv->port_map & 0xf); | ||
575 | |||
576 | port_map &= 0xf; | ||
577 | } | ||
578 | |||
538 | /* cross check port_map and cap.n_ports */ | 579 | /* cross check port_map and cap.n_ports */ |
539 | if (pi->flags & AHCI_FLAG_HONOR_PI) { | 580 | if (pi->flags & AHCI_FLAG_HONOR_PI) { |
540 | u32 tmp_port_map = port_map; | 581 | u32 tmp_port_map = port_map; |
@@ -740,7 +781,7 @@ static void ahci_power_down(struct ata_port *ap) | |||
740 | } | 781 | } |
741 | #endif | 782 | #endif |
742 | 783 | ||
743 | static void ahci_init_port(struct ata_port *ap) | 784 | static void ahci_start_port(struct ata_port *ap) |
744 | { | 785 | { |
745 | /* enable FIS reception */ | 786 | /* enable FIS reception */ |
746 | ahci_start_fis_rx(ap); | 787 | ahci_start_fis_rx(ap); |
@@ -814,39 +855,62 @@ static int ahci_reset_controller(struct ata_host *host) | |||
814 | return 0; | 855 | return 0; |
815 | } | 856 | } |
816 | 857 | ||
858 | static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, | ||
859 | int port_no, void __iomem *mmio, | ||
860 | void __iomem *port_mmio) | ||
861 | { | ||
862 | const char *emsg = NULL; | ||
863 | int rc; | ||
864 | u32 tmp; | ||
865 | |||
866 | /* make sure port is not active */ | ||
867 | rc = ahci_deinit_port(ap, &emsg); | ||
868 | if (rc) | ||
869 | dev_printk(KERN_WARNING, &pdev->dev, | ||
870 | "%s (%d)\n", emsg, rc); | ||
871 | |||
872 | /* clear SError */ | ||
873 | tmp = readl(port_mmio + PORT_SCR_ERR); | ||
874 | VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); | ||
875 | writel(tmp, port_mmio + PORT_SCR_ERR); | ||
876 | |||
877 | /* clear port IRQ */ | ||
878 | tmp = readl(port_mmio + PORT_IRQ_STAT); | ||
879 | VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); | ||
880 | if (tmp) | ||
881 | writel(tmp, port_mmio + PORT_IRQ_STAT); | ||
882 | |||
883 | writel(1 << port_no, mmio + HOST_IRQ_STAT); | ||
884 | } | ||
885 | |||
817 | static void ahci_init_controller(struct ata_host *host) | 886 | static void ahci_init_controller(struct ata_host *host) |
818 | { | 887 | { |
819 | struct pci_dev *pdev = to_pci_dev(host->dev); | 888 | struct pci_dev *pdev = to_pci_dev(host->dev); |
820 | void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; | 889 | void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; |
821 | int i, rc; | 890 | int i; |
891 | void __iomem *port_mmio; | ||
822 | u32 tmp; | 892 | u32 tmp; |
823 | 893 | ||
824 | for (i = 0; i < host->n_ports; i++) { | 894 | if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) { |
825 | struct ata_port *ap = host->ports[i]; | 895 | port_mmio = __ahci_port_base(host, 4); |
826 | void __iomem *port_mmio = ahci_port_base(ap); | ||
827 | const char *emsg = NULL; | ||
828 | |||
829 | if (ata_port_is_dummy(ap)) | ||
830 | continue; | ||
831 | |||
832 | /* make sure port is not active */ | ||
833 | rc = ahci_deinit_port(ap, &emsg); | ||
834 | if (rc) | ||
835 | dev_printk(KERN_WARNING, &pdev->dev, | ||
836 | "%s (%d)\n", emsg, rc); | ||
837 | 896 | ||
838 | /* clear SError */ | 897 | writel(0, port_mmio + PORT_IRQ_MASK); |
839 | tmp = readl(port_mmio + PORT_SCR_ERR); | ||
840 | VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); | ||
841 | writel(tmp, port_mmio + PORT_SCR_ERR); | ||
842 | 898 | ||
843 | /* clear port IRQ */ | 899 | /* clear port IRQ */ |
844 | tmp = readl(port_mmio + PORT_IRQ_STAT); | 900 | tmp = readl(port_mmio + PORT_IRQ_STAT); |
845 | VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); | 901 | VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); |
846 | if (tmp) | 902 | if (tmp) |
847 | writel(tmp, port_mmio + PORT_IRQ_STAT); | 903 | writel(tmp, port_mmio + PORT_IRQ_STAT); |
904 | } | ||
848 | 905 | ||
849 | writel(1 << i, mmio + HOST_IRQ_STAT); | 906 | for (i = 0; i < host->n_ports; i++) { |
907 | struct ata_port *ap = host->ports[i]; | ||
908 | |||
909 | port_mmio = ahci_port_base(ap); | ||
910 | if (ata_port_is_dummy(ap)) | ||
911 | continue; | ||
912 | |||
913 | ahci_port_init(pdev, ap, i, mmio, port_mmio); | ||
850 | } | 914 | } |
851 | 915 | ||
852 | tmp = readl(mmio + HOST_CTL); | 916 | tmp = readl(mmio + HOST_CTL); |
@@ -1232,7 +1296,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) | |||
1232 | ata_port_abort(ap); | 1296 | ata_port_abort(ap); |
1233 | } | 1297 | } |
1234 | 1298 | ||
1235 | static void ahci_host_intr(struct ata_port *ap) | 1299 | static void ahci_port_intr(struct ata_port *ap) |
1236 | { | 1300 | { |
1237 | void __iomem *port_mmio = ap->ioaddr.cmd_addr; | 1301 | void __iomem *port_mmio = ap->ioaddr.cmd_addr; |
1238 | struct ata_eh_info *ehi = &ap->eh_info; | 1302 | struct ata_eh_info *ehi = &ap->eh_info; |
@@ -1358,7 +1422,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance) | |||
1358 | 1422 | ||
1359 | ap = host->ports[i]; | 1423 | ap = host->ports[i]; |
1360 | if (ap) { | 1424 | if (ap) { |
1361 | ahci_host_intr(ap); | 1425 | ahci_port_intr(ap); |
1362 | VPRINTK("port %u\n", i); | 1426 | VPRINTK("port %u\n", i); |
1363 | } else { | 1427 | } else { |
1364 | VPRINTK("port %u (no irq)\n", i); | 1428 | VPRINTK("port %u (no irq)\n", i); |
@@ -1466,7 +1530,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) | |||
1466 | ahci_power_down(ap); | 1530 | ahci_power_down(ap); |
1467 | else { | 1531 | else { |
1468 | ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); | 1532 | ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); |
1469 | ahci_init_port(ap); | 1533 | ahci_start_port(ap); |
1470 | } | 1534 | } |
1471 | 1535 | ||
1472 | return rc; | 1536 | return rc; |
@@ -1475,7 +1539,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) | |||
1475 | static int ahci_port_resume(struct ata_port *ap) | 1539 | static int ahci_port_resume(struct ata_port *ap) |
1476 | { | 1540 | { |
1477 | ahci_power_up(ap); | 1541 | ahci_power_up(ap); |
1478 | ahci_init_port(ap); | 1542 | ahci_start_port(ap); |
1479 | 1543 | ||
1480 | return 0; | 1544 | return 0; |
1481 | } | 1545 | } |
@@ -1573,13 +1637,8 @@ static int ahci_port_start(struct ata_port *ap) | |||
1573 | 1637 | ||
1574 | ap->private_data = pp; | 1638 | ap->private_data = pp; |
1575 | 1639 | ||
1576 | /* power up port */ | 1640 | /* engage engines, captain */ |
1577 | ahci_power_up(ap); | 1641 | return ahci_port_resume(ap); |
1578 | |||
1579 | /* initialize port */ | ||
1580 | ahci_init_port(ap); | ||
1581 | |||
1582 | return 0; | ||
1583 | } | 1642 | } |
1584 | 1643 | ||
1585 | static void ahci_port_stop(struct ata_port *ap) | 1644 | static void ahci_port_stop(struct ata_port *ap) |
@@ -1724,7 +1783,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1724 | if (rc) | 1783 | if (rc) |
1725 | return rc; | 1784 | return rc; |
1726 | 1785 | ||
1727 | if (pci_enable_msi(pdev)) | 1786 | if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev)) |
1728 | pci_intx(pdev, 1); | 1787 | pci_intx(pdev, 1); |
1729 | 1788 | ||
1730 | hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); | 1789 | hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); |
@@ -1745,14 +1804,18 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1745 | host->private_data = hpriv; | 1804 | host->private_data = hpriv; |
1746 | 1805 | ||
1747 | for (i = 0; i < host->n_ports; i++) { | 1806 | for (i = 0; i < host->n_ports; i++) { |
1748 | if (hpriv->port_map & (1 << i)) { | 1807 | struct ata_port *ap = host->ports[i]; |
1749 | struct ata_port *ap = host->ports[i]; | 1808 | void __iomem *port_mmio = ahci_port_base(ap); |
1750 | void __iomem *port_mmio = ahci_port_base(ap); | ||
1751 | 1809 | ||
1810 | /* standard SATA port setup */ | ||
1811 | if (hpriv->port_map & (1 << i)) { | ||
1752 | ap->ioaddr.cmd_addr = port_mmio; | 1812 | ap->ioaddr.cmd_addr = port_mmio; |
1753 | ap->ioaddr.scr_addr = port_mmio + PORT_SCR; | 1813 | ap->ioaddr.scr_addr = port_mmio + PORT_SCR; |
1754 | } else | 1814 | } |
1755 | host->ports[i]->ops = &ata_dummy_port_ops; | 1815 | |
1816 | /* disabled/not-implemented port */ | ||
1817 | else | ||
1818 | ap->ops = &ata_dummy_port_ops; | ||
1756 | } | 1819 | } |
1757 | 1820 | ||
1758 | /* initialize adapter */ | 1821 | /* initialize adapter */ |
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 4c6e95c95e4a..430fcf4f9ef3 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c | |||
@@ -143,10 +143,10 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id | |||
143 | u16 command; | 143 | u16 command; |
144 | static const struct ata_port_info info = { | 144 | static const struct ata_port_info info = { |
145 | .sht = &generic_sht, | 145 | .sht = &generic_sht, |
146 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 146 | .flags = ATA_FLAG_SLAVE_POSS, |
147 | .pio_mask = 0x1f, | 147 | .pio_mask = 0x1f, |
148 | .mwdma_mask = 0x07, | 148 | .mwdma_mask = 0x07, |
149 | .udma_mask = 0x3f, | 149 | .udma_mask = ATA_UDMA5, |
150 | .port_ops = &generic_port_ops | 150 | .port_ops = &generic_port_ops |
151 | }; | 151 | }; |
152 | const struct ata_port_info *ppi[] = { &info, NULL }; | 152 | const struct ata_port_info *ppi[] = { &info, NULL }; |
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 9c07b88631be..6a3bfef58e13 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c | |||
@@ -200,6 +200,8 @@ static const struct pci_device_id piix_pci_tbl[] = { | |||
200 | /* ICH7/7-R (i945, i975) UDMA 100*/ | 200 | /* ICH7/7-R (i945, i975) UDMA 100*/ |
201 | { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, | 201 | { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, |
202 | { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, | 202 | { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, |
203 | /* ICH8 Mobile PATA Controller */ | ||
204 | { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, | ||
203 | 205 | ||
204 | /* NOTE: The following PCI ids must be kept in sync with the | 206 | /* NOTE: The following PCI ids must be kept in sync with the |
205 | * list in drivers/pci/quirks.c. | 207 | * list in drivers/pci/quirks.c. |
@@ -495,7 +497,7 @@ static struct ata_port_info piix_port_info[] = { | |||
495 | .flags = PIIX_SATA_FLAGS, | 497 | .flags = PIIX_SATA_FLAGS, |
496 | .pio_mask = 0x1f, /* pio0-4 */ | 498 | .pio_mask = 0x1f, /* pio0-4 */ |
497 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 499 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
498 | .udma_mask = 0x7f, /* udma0-6 */ | 500 | .udma_mask = ATA_UDMA6, |
499 | .port_ops = &piix_sata_ops, | 501 | .port_ops = &piix_sata_ops, |
500 | }, | 502 | }, |
501 | 503 | ||
@@ -505,7 +507,7 @@ static struct ata_port_info piix_port_info[] = { | |||
505 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, | 507 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, |
506 | .pio_mask = 0x1f, /* pio0-4 */ | 508 | .pio_mask = 0x1f, /* pio0-4 */ |
507 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 509 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
508 | .udma_mask = 0x7f, /* udma0-6 */ | 510 | .udma_mask = ATA_UDMA6, |
509 | .port_ops = &piix_sata_ops, | 511 | .port_ops = &piix_sata_ops, |
510 | }, | 512 | }, |
511 | 513 | ||
@@ -516,7 +518,7 @@ static struct ata_port_info piix_port_info[] = { | |||
516 | PIIX_FLAG_AHCI, | 518 | PIIX_FLAG_AHCI, |
517 | .pio_mask = 0x1f, /* pio0-4 */ | 519 | .pio_mask = 0x1f, /* pio0-4 */ |
518 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 520 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
519 | .udma_mask = 0x7f, /* udma0-6 */ | 521 | .udma_mask = ATA_UDMA6, |
520 | .port_ops = &piix_sata_ops, | 522 | .port_ops = &piix_sata_ops, |
521 | }, | 523 | }, |
522 | 524 | ||
@@ -527,7 +529,7 @@ static struct ata_port_info piix_port_info[] = { | |||
527 | PIIX_FLAG_AHCI, | 529 | PIIX_FLAG_AHCI, |
528 | .pio_mask = 0x1f, /* pio0-4 */ | 530 | .pio_mask = 0x1f, /* pio0-4 */ |
529 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 531 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
530 | .udma_mask = 0x7f, /* udma0-6 */ | 532 | .udma_mask = ATA_UDMA6, |
531 | .port_ops = &piix_sata_ops, | 533 | .port_ops = &piix_sata_ops, |
532 | }, | 534 | }, |
533 | 535 | ||
@@ -538,7 +540,7 @@ static struct ata_port_info piix_port_info[] = { | |||
538 | PIIX_FLAG_AHCI, | 540 | PIIX_FLAG_AHCI, |
539 | .pio_mask = 0x1f, /* pio0-4 */ | 541 | .pio_mask = 0x1f, /* pio0-4 */ |
540 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 542 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
541 | .udma_mask = 0x7f, /* udma0-6 */ | 543 | .udma_mask = ATA_UDMA6, |
542 | .port_ops = &piix_sata_ops, | 544 | .port_ops = &piix_sata_ops, |
543 | }, | 545 | }, |
544 | 546 | ||
@@ -685,8 +687,14 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) | |||
685 | if (adev->class == ATA_DEV_ATA) | 687 | if (adev->class == ATA_DEV_ATA) |
686 | control |= 4; /* PPE enable */ | 688 | control |= 4; /* PPE enable */ |
687 | 689 | ||
690 | /* PIO configuration clears DTE unconditionally. It will be | ||
691 | * programmed in set_dmamode which is guaranteed to be called | ||
692 | * after set_piomode if any DMA mode is available. | ||
693 | */ | ||
688 | pci_read_config_word(dev, master_port, &master_data); | 694 | pci_read_config_word(dev, master_port, &master_data); |
689 | if (is_slave) { | 695 | if (is_slave) { |
696 | /* clear TIME1|IE1|PPE1|DTE1 */ | ||
697 | master_data &= 0xff0f; | ||
690 | /* Enable SITRE (seperate slave timing register) */ | 698 | /* Enable SITRE (seperate slave timing register) */ |
691 | master_data |= 0x4000; | 699 | master_data |= 0x4000; |
692 | /* enable PPE1, IE1 and TIME1 as needed */ | 700 | /* enable PPE1, IE1 and TIME1 as needed */ |
@@ -694,12 +702,14 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) | |||
694 | pci_read_config_byte(dev, slave_port, &slave_data); | 702 | pci_read_config_byte(dev, slave_port, &slave_data); |
695 | slave_data &= (ap->port_no ? 0x0f : 0xf0); | 703 | slave_data &= (ap->port_no ? 0x0f : 0xf0); |
696 | /* Load the timing nibble for this slave */ | 704 | /* Load the timing nibble for this slave */ |
697 | slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); | 705 | slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) |
706 | << (ap->port_no ? 4 : 0); | ||
698 | } else { | 707 | } else { |
699 | /* Master keeps the bits in a different format */ | 708 | /* clear ISP|RCT|TIME0|IE0|PPE0|DTE0 */ |
700 | master_data &= 0xccf8; | 709 | master_data &= 0xccf0; |
701 | /* Enable PPE, IE and TIME as appropriate */ | 710 | /* Enable PPE, IE and TIME as appropriate */ |
702 | master_data |= control; | 711 | master_data |= control; |
712 | /* load ISP and RCT */ | ||
703 | master_data |= | 713 | master_data |= |
704 | (timings[pio][0] << 12) | | 714 | (timings[pio][0] << 12) | |
705 | (timings[pio][1] << 8); | 715 | (timings[pio][1] << 8); |
@@ -816,7 +826,7 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i | |||
816 | master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ | 826 | master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ |
817 | master_data |= control << 4; | 827 | master_data |= control << 4; |
818 | pci_read_config_byte(dev, 0x44, &slave_data); | 828 | pci_read_config_byte(dev, 0x44, &slave_data); |
819 | slave_data &= (0x0F + 0xE1 * ap->port_no); | 829 | slave_data &= (ap->port_no ? 0x0f : 0xf0); |
820 | /* Load the matching timing */ | 830 | /* Load the matching timing */ |
821 | slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); | 831 | slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); |
822 | pci_write_config_byte(dev, 0x44, slave_data); | 832 | pci_write_config_byte(dev, 0x44, slave_data); |
@@ -828,8 +838,11 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i | |||
828 | (timings[pio][0] << 12) | | 838 | (timings[pio][0] << 12) | |
829 | (timings[pio][1] << 8); | 839 | (timings[pio][1] << 8); |
830 | } | 840 | } |
831 | udma_enable &= ~(1 << devid); | 841 | |
832 | pci_write_config_word(dev, master_port, master_data); | 842 | if (ap->udma_mask) { |
843 | udma_enable &= ~(1 << devid); | ||
844 | pci_write_config_word(dev, master_port, master_data); | ||
845 | } | ||
833 | } | 846 | } |
834 | /* Don't scribble on 0x48 if the controller does not support UDMA */ | 847 | /* Don't scribble on 0x48 if the controller does not support UDMA */ |
835 | if (ap->udma_mask) | 848 | if (ap->udma_mask) |
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 02236739b40f..c059f78ad944 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -24,15 +24,13 @@ | |||
24 | #include <acpi/acmacros.h> | 24 | #include <acpi/acmacros.h> |
25 | #include <acpi/actypes.h> | 25 | #include <acpi/actypes.h> |
26 | 26 | ||
27 | #define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff) | ||
28 | #define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */ | ||
29 | #define NO_PORT_MULT 0xffff | 27 | #define NO_PORT_MULT 0xffff |
30 | #define SATA_ADR_RSVD 0xffffffff | 28 | #define SATA_ADR(root,pmp) (((root) << 16) | (pmp)) |
31 | 29 | ||
32 | #define REGS_PER_GTF 7 | 30 | #define REGS_PER_GTF 7 |
33 | struct taskfile_array { | 31 | struct ata_acpi_gtf { |
34 | u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ | 32 | u8 tf[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ |
35 | }; | 33 | } __packed; |
36 | 34 | ||
37 | /* | 35 | /* |
38 | * Helper - belongs in the PCI layer somewhere eventually | 36 | * Helper - belongs in the PCI layer somewhere eventually |
@@ -42,237 +40,173 @@ static int is_pci_dev(struct device *dev) | |||
42 | return (dev->bus == &pci_bus_type); | 40 | return (dev->bus == &pci_bus_type); |
43 | } | 41 | } |
44 | 42 | ||
43 | static void ata_acpi_associate_sata_port(struct ata_port *ap) | ||
44 | { | ||
45 | acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); | ||
46 | |||
47 | ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr); | ||
48 | } | ||
49 | |||
50 | static void ata_acpi_associate_ide_port(struct ata_port *ap) | ||
51 | { | ||
52 | int max_devices, i; | ||
53 | |||
54 | ap->acpi_handle = acpi_get_child(ap->host->acpi_handle, ap->port_no); | ||
55 | if (!ap->acpi_handle) | ||
56 | return; | ||
57 | |||
58 | max_devices = 1; | ||
59 | if (ap->flags & ATA_FLAG_SLAVE_POSS) | ||
60 | max_devices++; | ||
61 | |||
62 | for (i = 0; i < max_devices; i++) { | ||
63 | struct ata_device *dev = &ap->device[i]; | ||
64 | |||
65 | dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); | ||
66 | } | ||
67 | } | ||
68 | |||
45 | /** | 69 | /** |
46 | * sata_get_dev_handle - finds acpi_handle and PCI device.function | 70 | * ata_acpi_associate - associate ATA host with ACPI objects |
47 | * @dev: device to locate | 71 | * @host: target ATA host |
48 | * @handle: returned acpi_handle for @dev | 72 | * |
49 | * @pcidevfn: return PCI device.func for @dev | 73 | * Look up ACPI objects associated with @host and initialize |
74 | * acpi_handle fields of @host, its ports and devices accordingly. | ||
50 | * | 75 | * |
51 | * This function is somewhat SATA-specific. Or at least the | 76 | * LOCKING: |
52 | * PATA & SATA versions of this function are different, | 77 | * EH context. |
53 | * so it's not entirely generic code. | ||
54 | * | 78 | * |
55 | * Returns 0 on success, <0 on error. | 79 | * RETURNS: |
80 | * 0 on success, -errno on failure. | ||
56 | */ | 81 | */ |
57 | static int sata_get_dev_handle(struct device *dev, acpi_handle *handle, | 82 | void ata_acpi_associate(struct ata_host *host) |
58 | acpi_integer *pcidevfn) | ||
59 | { | 83 | { |
60 | struct pci_dev *pci_dev; | 84 | int i; |
61 | acpi_integer addr; | 85 | |
62 | 86 | if (!is_pci_dev(host->dev) || libata_noacpi) | |
63 | if (!is_pci_dev(dev)) | 87 | return; |
64 | return -ENODEV; | 88 | |
65 | 89 | host->acpi_handle = DEVICE_ACPI_HANDLE(host->dev); | |
66 | pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */ | 90 | if (!host->acpi_handle) |
67 | /* Please refer to the ACPI spec for the syntax of _ADR. */ | 91 | return; |
68 | addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); | 92 | |
69 | *pcidevfn = addr; | 93 | for (i = 0; i < host->n_ports; i++) { |
70 | *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); | 94 | struct ata_port *ap = host->ports[i]; |
71 | if (!*handle) | 95 | |
72 | return -ENODEV; | 96 | if (host->ports[0]->flags & ATA_FLAG_ACPI_SATA) |
73 | return 0; | 97 | ata_acpi_associate_sata_port(ap); |
98 | else | ||
99 | ata_acpi_associate_ide_port(ap); | ||
100 | } | ||
74 | } | 101 | } |
75 | 102 | ||
76 | /** | 103 | /** |
77 | * pata_get_dev_handle - finds acpi_handle and PCI device.function | 104 | * ata_acpi_gtm - execute _GTM |
78 | * @dev: device to locate | 105 | * @ap: target ATA port |
79 | * @handle: returned acpi_handle for @dev | 106 | * @gtm: out parameter for _GTM result |
80 | * @pcidevfn: return PCI device.func for @dev | 107 | * |
108 | * Evaluate _GTM and store the result in @gtm. | ||
81 | * | 109 | * |
82 | * The PATA and SATA versions of this function are different. | 110 | * LOCKING: |
111 | * EH context. | ||
83 | * | 112 | * |
84 | * Returns 0 on success, <0 on error. | 113 | * RETURNS: |
114 | * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. | ||
85 | */ | 115 | */ |
86 | static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, | 116 | static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) |
87 | acpi_integer *pcidevfn) | ||
88 | { | 117 | { |
89 | unsigned int bus, devnum, func; | 118 | struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; |
90 | acpi_integer addr; | 119 | union acpi_object *out_obj; |
91 | acpi_handle dev_handle, parent_handle; | ||
92 | struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, | ||
93 | .pointer = NULL}; | ||
94 | acpi_status status; | 120 | acpi_status status; |
95 | struct acpi_device_info *dinfo = NULL; | 121 | int rc = 0; |
96 | int ret = -ENODEV; | 122 | |
97 | struct pci_dev *pdev; | 123 | status = acpi_evaluate_object(ap->acpi_handle, "_GTM", NULL, &output); |
98 | 124 | ||
99 | if (!is_pci_dev(dev)) | 125 | rc = -ENOENT; |
100 | return -ENODEV; | 126 | if (status == AE_NOT_FOUND) |
101 | 127 | goto out_free; | |
102 | pdev = to_pci_dev(dev); | 128 | |
103 | 129 | rc = -EINVAL; | |
104 | bus = pdev->bus->number; | 130 | if (ACPI_FAILURE(status)) { |
105 | devnum = PCI_SLOT(pdev->devfn); | 131 | ata_port_printk(ap, KERN_ERR, |
106 | func = PCI_FUNC(pdev->devfn); | 132 | "ACPI get timing mode failed (AE 0x%x)\n", |
107 | 133 | status); | |
108 | dev_handle = DEVICE_ACPI_HANDLE(dev); | 134 | goto out_free; |
109 | parent_handle = DEVICE_ACPI_HANDLE(dev->parent); | ||
110 | |||
111 | status = acpi_get_object_info(parent_handle, &buffer); | ||
112 | if (ACPI_FAILURE(status)) | ||
113 | goto err; | ||
114 | |||
115 | dinfo = buffer.pointer; | ||
116 | if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && | ||
117 | dinfo->address == bus) { | ||
118 | /* ACPI spec for _ADR for PCI bus: */ | ||
119 | addr = (acpi_integer)(devnum << 16 | func); | ||
120 | *pcidevfn = addr; | ||
121 | *handle = dev_handle; | ||
122 | } else { | ||
123 | goto err; | ||
124 | } | 135 | } |
125 | 136 | ||
126 | if (!*handle) | 137 | out_obj = output.pointer; |
127 | goto err; | 138 | if (out_obj->type != ACPI_TYPE_BUFFER) { |
128 | ret = 0; | 139 | ata_port_printk(ap, KERN_WARNING, |
129 | err: | 140 | "_GTM returned unexpected object type 0x%x\n", |
130 | kfree(dinfo); | 141 | out_obj->type); |
131 | return ret; | ||
132 | } | ||
133 | 142 | ||
134 | struct walk_info { /* can be trimmed some */ | 143 | goto out_free; |
135 | struct device *dev; | ||
136 | struct acpi_device *adev; | ||
137 | acpi_handle handle; | ||
138 | acpi_integer pcidevfn; | ||
139 | unsigned int drivenum; | ||
140 | acpi_handle obj_handle; | ||
141 | struct ata_port *ataport; | ||
142 | struct ata_device *atadev; | ||
143 | u32 sata_adr; | ||
144 | int status; | ||
145 | char basepath[ACPI_PATHNAME_MAX]; | ||
146 | int basepath_len; | ||
147 | }; | ||
148 | |||
149 | static acpi_status get_devices(acpi_handle handle, | ||
150 | u32 level, void *context, void **return_value) | ||
151 | { | ||
152 | acpi_status status; | ||
153 | struct walk_info *winfo = context; | ||
154 | struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
155 | char *pathname; | ||
156 | struct acpi_buffer buffer; | ||
157 | struct acpi_device_info *dinfo; | ||
158 | |||
159 | status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf); | ||
160 | if (status) | ||
161 | goto ret; | ||
162 | pathname = namebuf.pointer; | ||
163 | |||
164 | buffer.length = ACPI_ALLOCATE_BUFFER; | ||
165 | buffer.pointer = NULL; | ||
166 | status = acpi_get_object_info(handle, &buffer); | ||
167 | if (ACPI_FAILURE(status)) | ||
168 | goto out2; | ||
169 | |||
170 | dinfo = buffer.pointer; | ||
171 | |||
172 | /* find full device path name for pcidevfn */ | ||
173 | if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && | ||
174 | dinfo->address == winfo->pcidevfn) { | ||
175 | if (ata_msg_probe(winfo->ataport)) | ||
176 | ata_dev_printk(winfo->atadev, KERN_DEBUG, | ||
177 | ":%s: matches pcidevfn (0x%llx)\n", | ||
178 | pathname, winfo->pcidevfn); | ||
179 | strlcpy(winfo->basepath, pathname, | ||
180 | sizeof(winfo->basepath)); | ||
181 | winfo->basepath_len = strlen(pathname); | ||
182 | goto out; | ||
183 | } | 144 | } |
184 | 145 | ||
185 | /* if basepath is not yet known, ignore this object */ | 146 | if (out_obj->buffer.length != sizeof(struct ata_acpi_gtm)) { |
186 | if (!winfo->basepath_len) | 147 | ata_port_printk(ap, KERN_ERR, |
187 | goto out; | 148 | "_GTM returned invalid length %d\n", |
188 | 149 | out_obj->buffer.length); | |
189 | /* if this object is in scope of basepath, maybe use it */ | 150 | goto out_free; |
190 | if (strncmp(pathname, winfo->basepath, | ||
191 | winfo->basepath_len) == 0) { | ||
192 | if (!(dinfo->valid & ACPI_VALID_ADR)) | ||
193 | goto out; | ||
194 | if (ata_msg_probe(winfo->ataport)) | ||
195 | ata_dev_printk(winfo->atadev, KERN_DEBUG, | ||
196 | "GOT ONE: (%s) root_port = 0x%llx," | ||
197 | " port_num = 0x%llx\n", pathname, | ||
198 | SATA_ROOT_PORT(dinfo->address), | ||
199 | SATA_PORT_NUMBER(dinfo->address)); | ||
200 | /* heuristics: */ | ||
201 | if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT) | ||
202 | if (ata_msg_probe(winfo->ataport)) | ||
203 | ata_dev_printk(winfo->atadev, | ||
204 | KERN_DEBUG, "warning: don't" | ||
205 | " know how to handle SATA port" | ||
206 | " multiplier\n"); | ||
207 | if (SATA_ROOT_PORT(dinfo->address) == | ||
208 | winfo->ataport->port_no && | ||
209 | SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) { | ||
210 | if (ata_msg_probe(winfo->ataport)) | ||
211 | ata_dev_printk(winfo->atadev, | ||
212 | KERN_DEBUG, | ||
213 | "THIS ^^^^^ is the requested" | ||
214 | " SATA drive (handle = 0x%p)\n", | ||
215 | handle); | ||
216 | winfo->sata_adr = dinfo->address; | ||
217 | winfo->obj_handle = handle; | ||
218 | } | ||
219 | } | 151 | } |
220 | out: | ||
221 | kfree(dinfo); | ||
222 | out2: | ||
223 | kfree(pathname); | ||
224 | 152 | ||
225 | ret: | 153 | memcpy(gtm, out_obj->buffer.pointer, sizeof(struct ata_acpi_gtm)); |
226 | return status; | 154 | rc = 0; |
155 | out_free: | ||
156 | kfree(output.pointer); | ||
157 | return rc; | ||
227 | } | 158 | } |
228 | 159 | ||
229 | /* Get the SATA drive _ADR object. */ | 160 | /** |
230 | static int get_sata_adr(struct device *dev, acpi_handle handle, | 161 | * ata_acpi_stm - execute _STM |
231 | acpi_integer pcidevfn, unsigned int drive, | 162 | * @ap: target ATA port |
232 | struct ata_port *ap, | 163 | * @stm: timing parameter to _STM |
233 | struct ata_device *atadev, u32 *dev_adr) | 164 | * |
165 | * Evaluate _STM with timing parameter @stm. | ||
166 | * | ||
167 | * LOCKING: | ||
168 | * EH context. | ||
169 | * | ||
170 | * RETURNS: | ||
171 | * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. | ||
172 | */ | ||
173 | static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) | ||
234 | { | 174 | { |
235 | acpi_status status; | 175 | acpi_status status; |
236 | struct walk_info *winfo; | 176 | struct acpi_object_list input; |
237 | int err = -ENOMEM; | 177 | union acpi_object in_params[3]; |
238 | |||
239 | winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL); | ||
240 | if (!winfo) | ||
241 | goto out; | ||
242 | |||
243 | winfo->dev = dev; | ||
244 | winfo->atadev = atadev; | ||
245 | winfo->ataport = ap; | ||
246 | if (acpi_bus_get_device(handle, &winfo->adev) < 0) | ||
247 | if (ata_msg_probe(ap)) | ||
248 | ata_dev_printk(winfo->atadev, KERN_DEBUG, | ||
249 | "acpi_bus_get_device failed\n"); | ||
250 | winfo->handle = handle; | ||
251 | winfo->pcidevfn = pcidevfn; | ||
252 | winfo->drivenum = drive; | ||
253 | 178 | ||
254 | status = acpi_get_devices(NULL, get_devices, winfo, NULL); | 179 | in_params[0].type = ACPI_TYPE_BUFFER; |
180 | in_params[0].buffer.length = sizeof(struct ata_acpi_gtm); | ||
181 | in_params[0].buffer.pointer = (u8 *)stm; | ||
182 | /* Buffers for id may need byteswapping ? */ | ||
183 | in_params[1].type = ACPI_TYPE_BUFFER; | ||
184 | in_params[1].buffer.length = 512; | ||
185 | in_params[1].buffer.pointer = (u8 *)ap->device[0].id; | ||
186 | in_params[2].type = ACPI_TYPE_BUFFER; | ||
187 | in_params[2].buffer.length = 512; | ||
188 | in_params[2].buffer.pointer = (u8 *)ap->device[1].id; | ||
189 | |||
190 | input.count = 3; | ||
191 | input.pointer = in_params; | ||
192 | |||
193 | status = acpi_evaluate_object(ap->acpi_handle, "_STM", &input, NULL); | ||
194 | |||
195 | if (status == AE_NOT_FOUND) | ||
196 | return -ENOENT; | ||
255 | if (ACPI_FAILURE(status)) { | 197 | if (ACPI_FAILURE(status)) { |
256 | if (ata_msg_probe(ap)) | 198 | ata_port_printk(ap, KERN_ERR, |
257 | ata_dev_printk(winfo->atadev, KERN_DEBUG, | 199 | "ACPI set timing mode failed (status=0x%x)\n", status); |
258 | "%s: acpi_get_devices failed\n", | 200 | return -EINVAL; |
259 | __FUNCTION__); | ||
260 | err = -ENODEV; | ||
261 | } else { | ||
262 | *dev_adr = winfo->sata_adr; | ||
263 | atadev->obj_handle = winfo->obj_handle; | ||
264 | err = 0; | ||
265 | } | 201 | } |
266 | kfree(winfo); | 202 | return 0; |
267 | out: | ||
268 | return err; | ||
269 | } | 203 | } |
270 | 204 | ||
271 | /** | 205 | /** |
272 | * do_drive_get_GTF - get the drive bootup default taskfile settings | 206 | * ata_dev_get_GTF - get the drive bootup default taskfile settings |
273 | * @dev: target ATA device | 207 | * @dev: target ATA device |
274 | * @gtf_length: number of bytes of _GTF data returned at @gtf_address | 208 | * @gtf: output parameter for buffer containing _GTF taskfile arrays |
275 | * @gtf_address: buffer containing _GTF taskfile arrays | 209 | * @ptr_to_free: pointer which should be freed |
276 | * | 210 | * |
277 | * This applies to both PATA and SATA drives. | 211 | * This applies to both PATA and SATA drives. |
278 | * | 212 | * |
@@ -282,121 +216,41 @@ out: | |||
282 | * The <variable number> is not known in advance, so have ACPI-CA | 216 | * The <variable number> is not known in advance, so have ACPI-CA |
283 | * allocate the buffer as needed and return it, then free it later. | 217 | * allocate the buffer as needed and return it, then free it later. |
284 | * | 218 | * |
285 | * The returned @gtf_length and @gtf_address are only valid if the | 219 | * LOCKING: |
286 | * function return value is 0. | 220 | * EH context. |
221 | * | ||
222 | * RETURNS: | ||
223 | * Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't | ||
224 | * contain valid data. -errno on other errors. | ||
287 | */ | 225 | */ |
288 | static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, | 226 | static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, |
289 | unsigned long *gtf_address, unsigned long *obj_loc) | 227 | void **ptr_to_free) |
290 | { | 228 | { |
291 | struct ata_port *ap = dev->ap; | 229 | struct ata_port *ap = dev->ap; |
292 | acpi_status status; | 230 | acpi_status status; |
293 | acpi_handle dev_handle = NULL; | ||
294 | acpi_handle chan_handle, drive_handle; | ||
295 | acpi_integer pcidevfn = 0; | ||
296 | u32 dev_adr; | ||
297 | struct acpi_buffer output; | 231 | struct acpi_buffer output; |
298 | union acpi_object *out_obj; | 232 | union acpi_object *out_obj; |
299 | struct device *gdev = ap->host->dev; | 233 | int rc = 0; |
300 | int err = -ENODEV; | ||
301 | 234 | ||
302 | *gtf_length = 0; | 235 | /* set up output buffer */ |
303 | *gtf_address = 0UL; | 236 | output.length = ACPI_ALLOCATE_BUFFER; |
304 | *obj_loc = 0UL; | 237 | output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ |
305 | |||
306 | if (libata_noacpi) | ||
307 | return 0; | ||
308 | 238 | ||
309 | if (ata_msg_probe(ap)) | 239 | if (ata_msg_probe(ap)) |
310 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", | 240 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", |
311 | __FUNCTION__, ap->port_no); | 241 | __FUNCTION__, ap->port_no); |
312 | 242 | ||
313 | if (!ata_dev_enabled(dev) || (ap->flags & ATA_FLAG_DISABLED)) { | ||
314 | if (ata_msg_probe(ap)) | ||
315 | ata_dev_printk(dev, KERN_DEBUG, "%s: ERR: " | ||
316 | "ata_dev_present: %d, PORT_DISABLED: %lu\n", | ||
317 | __FUNCTION__, ata_dev_enabled(dev), | ||
318 | ap->flags & ATA_FLAG_DISABLED); | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | /* Don't continue if device has no _ADR method. | ||
323 | * _GTF is intended for known motherboard devices. */ | ||
324 | if (!(ap->flags & ATA_FLAG_ACPI_SATA)) { | ||
325 | err = pata_get_dev_handle(gdev, &dev_handle, &pcidevfn); | ||
326 | if (err < 0) { | ||
327 | if (ata_msg_probe(ap)) | ||
328 | ata_dev_printk(dev, KERN_DEBUG, | ||
329 | "%s: pata_get_dev_handle failed (%d)\n", | ||
330 | __FUNCTION__, err); | ||
331 | goto out; | ||
332 | } | ||
333 | } else { | ||
334 | err = sata_get_dev_handle(gdev, &dev_handle, &pcidevfn); | ||
335 | if (err < 0) { | ||
336 | if (ata_msg_probe(ap)) | ||
337 | ata_dev_printk(dev, KERN_DEBUG, | ||
338 | "%s: sata_get_dev_handle failed (%d\n", | ||
339 | __FUNCTION__, err); | ||
340 | goto out; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /* Get this drive's _ADR info. if not already known. */ | ||
345 | if (!dev->obj_handle) { | ||
346 | if (!(ap->flags & ATA_FLAG_ACPI_SATA)) { | ||
347 | /* get child objects of dev_handle == channel objects, | ||
348 | * + _their_ children == drive objects */ | ||
349 | /* channel is ap->port_no */ | ||
350 | chan_handle = acpi_get_child(dev_handle, | ||
351 | ap->port_no); | ||
352 | if (ata_msg_probe(ap)) | ||
353 | ata_dev_printk(dev, KERN_DEBUG, | ||
354 | "%s: chan adr=%d: chan_handle=0x%p\n", | ||
355 | __FUNCTION__, ap->port_no, | ||
356 | chan_handle); | ||
357 | if (!chan_handle) { | ||
358 | err = -ENODEV; | ||
359 | goto out; | ||
360 | } | ||
361 | /* TBD: could also check ACPI object VALID bits */ | ||
362 | drive_handle = acpi_get_child(chan_handle, dev->devno); | ||
363 | if (!drive_handle) { | ||
364 | err = -ENODEV; | ||
365 | goto out; | ||
366 | } | ||
367 | dev_adr = dev->devno; | ||
368 | dev->obj_handle = drive_handle; | ||
369 | } else { /* for SATA mode */ | ||
370 | dev_adr = SATA_ADR_RSVD; | ||
371 | err = get_sata_adr(gdev, dev_handle, pcidevfn, 0, | ||
372 | ap, dev, &dev_adr); | ||
373 | } | ||
374 | if (err < 0 || dev_adr == SATA_ADR_RSVD || | ||
375 | !dev->obj_handle) { | ||
376 | if (ata_msg_probe(ap)) | ||
377 | ata_dev_printk(dev, KERN_DEBUG, | ||
378 | "%s: get_sata/pata_adr failed: " | ||
379 | "err=%d, dev_adr=%u, obj_handle=0x%p\n", | ||
380 | __FUNCTION__, err, dev_adr, | ||
381 | dev->obj_handle); | ||
382 | goto out; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /* Setting up output buffer */ | ||
387 | output.length = ACPI_ALLOCATE_BUFFER; | ||
388 | output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ | ||
389 | |||
390 | /* _GTF has no input parameters */ | 243 | /* _GTF has no input parameters */ |
391 | err = -EIO; | 244 | status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); |
392 | status = acpi_evaluate_object(dev->obj_handle, "_GTF", | 245 | |
393 | NULL, &output); | ||
394 | if (ACPI_FAILURE(status)) { | 246 | if (ACPI_FAILURE(status)) { |
395 | if (ata_msg_probe(ap)) | 247 | if (status != AE_NOT_FOUND) { |
396 | ata_dev_printk(dev, KERN_DEBUG, | 248 | ata_dev_printk(dev, KERN_WARNING, |
397 | "%s: Run _GTF error: status = 0x%x\n", | 249 | "_GTF evaluation failed (AE 0x%x)\n", |
398 | __FUNCTION__, status); | 250 | status); |
399 | goto out; | 251 | rc = -EIO; |
252 | } | ||
253 | goto out_free; | ||
400 | } | 254 | } |
401 | 255 | ||
402 | if (!output.length || !output.pointer) { | 256 | if (!output.length || !output.pointer) { |
@@ -406,43 +260,39 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, | |||
406 | __FUNCTION__, | 260 | __FUNCTION__, |
407 | (unsigned long long)output.length, | 261 | (unsigned long long)output.length, |
408 | output.pointer); | 262 | output.pointer); |
409 | kfree(output.pointer); | 263 | goto out_free; |
410 | goto out; | ||
411 | } | 264 | } |
412 | 265 | ||
413 | out_obj = output.pointer; | 266 | out_obj = output.pointer; |
414 | if (out_obj->type != ACPI_TYPE_BUFFER) { | 267 | if (out_obj->type != ACPI_TYPE_BUFFER) { |
415 | kfree(output.pointer); | 268 | ata_dev_printk(dev, KERN_WARNING, |
416 | if (ata_msg_probe(ap)) | 269 | "_GTF unexpected object type 0x%x\n", |
417 | ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " | 270 | out_obj->type); |
418 | "error: expected object type of " | 271 | rc = -EINVAL; |
419 | " ACPI_TYPE_BUFFER, got 0x%x\n", | 272 | goto out_free; |
420 | __FUNCTION__, out_obj->type); | ||
421 | err = -ENOENT; | ||
422 | goto out; | ||
423 | } | 273 | } |
424 | 274 | ||
425 | if (!out_obj->buffer.length || !out_obj->buffer.pointer || | 275 | if (out_obj->buffer.length % REGS_PER_GTF) { |
426 | out_obj->buffer.length % REGS_PER_GTF) { | 276 | ata_dev_printk(dev, KERN_WARNING, |
427 | if (ata_msg_drv(ap)) | 277 | "unexpected _GTF length (%d)\n", |
428 | ata_dev_printk(dev, KERN_ERR, | 278 | out_obj->buffer.length); |
429 | "%s: unexpected GTF length (%d) or addr (0x%p)\n", | 279 | rc = -EINVAL; |
430 | __FUNCTION__, out_obj->buffer.length, | 280 | goto out_free; |
431 | out_obj->buffer.pointer); | ||
432 | err = -ENOENT; | ||
433 | goto out; | ||
434 | } | 281 | } |
435 | 282 | ||
436 | *gtf_length = out_obj->buffer.length; | 283 | *ptr_to_free = out_obj; |
437 | *gtf_address = (unsigned long)out_obj->buffer.pointer; | 284 | *gtf = (void *)out_obj->buffer.pointer; |
438 | *obj_loc = (unsigned long)out_obj; | 285 | rc = out_obj->buffer.length / REGS_PER_GTF; |
286 | |||
439 | if (ata_msg_probe(ap)) | 287 | if (ata_msg_probe(ap)) |
440 | ata_dev_printk(dev, KERN_DEBUG, "%s: returning " | 288 | ata_dev_printk(dev, KERN_DEBUG, "%s: returning " |
441 | "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", | 289 | "gtf=%p, gtf_count=%d, ptr_to_free=%p\n", |
442 | __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); | 290 | __FUNCTION__, *gtf, rc, *ptr_to_free); |
443 | err = 0; | 291 | return rc; |
444 | out: | 292 | |
445 | return err; | 293 | out_free: |
294 | kfree(output.pointer); | ||
295 | return rc; | ||
446 | } | 296 | } |
447 | 297 | ||
448 | /** | 298 | /** |
@@ -461,154 +311,99 @@ out: | |||
461 | * function also waits for idle after writing control and before | 311 | * function also waits for idle after writing control and before |
462 | * writing the remaining registers. | 312 | * writing the remaining registers. |
463 | * | 313 | * |
464 | * LOCKING: TBD: | 314 | * LOCKING: |
465 | * Inherited from caller. | 315 | * EH context. |
316 | * | ||
317 | * RETURNS: | ||
318 | * 0 on success, -errno on failure. | ||
466 | */ | 319 | */ |
467 | static void taskfile_load_raw(struct ata_device *dev, | 320 | static int taskfile_load_raw(struct ata_device *dev, |
468 | const struct taskfile_array *gtf) | 321 | const struct ata_acpi_gtf *gtf) |
469 | { | 322 | { |
470 | struct ata_port *ap = dev->ap; | 323 | struct ata_port *ap = dev->ap; |
471 | struct ata_taskfile tf; | 324 | struct ata_taskfile tf, rtf; |
472 | unsigned int err; | 325 | unsigned int err_mask; |
473 | 326 | ||
474 | if (ata_msg_probe(ap)) | 327 | if ((gtf->tf[0] == 0) && (gtf->tf[1] == 0) && (gtf->tf[2] == 0) |
475 | ata_dev_printk(dev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " | 328 | && (gtf->tf[3] == 0) && (gtf->tf[4] == 0) && (gtf->tf[5] == 0) |
476 | "%02x %02x %02x %02x %02x %02x %02x\n", | 329 | && (gtf->tf[6] == 0)) |
477 | __FUNCTION__, | 330 | return 0; |
478 | gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], | ||
479 | gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); | ||
480 | |||
481 | if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0) | ||
482 | && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0) | ||
483 | && (gtf->tfa[6] == 0)) | ||
484 | return; | ||
485 | 331 | ||
486 | ata_tf_init(dev, &tf); | 332 | ata_tf_init(dev, &tf); |
487 | 333 | ||
488 | /* convert gtf to tf */ | 334 | /* convert gtf to tf */ |
489 | tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ | 335 | tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ |
490 | tf.protocol = ATA_PROT_NODATA; | 336 | tf.protocol = ATA_PROT_NODATA; |
491 | tf.feature = gtf->tfa[0]; /* 0x1f1 */ | 337 | tf.feature = gtf->tf[0]; /* 0x1f1 */ |
492 | tf.nsect = gtf->tfa[1]; /* 0x1f2 */ | 338 | tf.nsect = gtf->tf[1]; /* 0x1f2 */ |
493 | tf.lbal = gtf->tfa[2]; /* 0x1f3 */ | 339 | tf.lbal = gtf->tf[2]; /* 0x1f3 */ |
494 | tf.lbam = gtf->tfa[3]; /* 0x1f4 */ | 340 | tf.lbam = gtf->tf[3]; /* 0x1f4 */ |
495 | tf.lbah = gtf->tfa[4]; /* 0x1f5 */ | 341 | tf.lbah = gtf->tf[4]; /* 0x1f5 */ |
496 | tf.device = gtf->tfa[5]; /* 0x1f6 */ | 342 | tf.device = gtf->tf[5]; /* 0x1f6 */ |
497 | tf.command = gtf->tfa[6]; /* 0x1f7 */ | 343 | tf.command = gtf->tf[6]; /* 0x1f7 */ |
498 | |||
499 | err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | ||
500 | if (err && ata_msg_probe(ap)) | ||
501 | ata_dev_printk(dev, KERN_ERR, | ||
502 | "%s: ata_exec_internal failed: %u\n", | ||
503 | __FUNCTION__, err); | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * do_drive_set_taskfiles - write the drive taskfile settings from _GTF | ||
508 | * @dev: target ATA device | ||
509 | * @gtf_length: total number of bytes of _GTF taskfiles | ||
510 | * @gtf_address: location of _GTF taskfile arrays | ||
511 | * | ||
512 | * This applies to both PATA and SATA drives. | ||
513 | * | ||
514 | * Write {gtf_address, length gtf_length} in groups of | ||
515 | * REGS_PER_GTF bytes. | ||
516 | */ | ||
517 | static int do_drive_set_taskfiles(struct ata_device *dev, | ||
518 | unsigned int gtf_length, | ||
519 | unsigned long gtf_address) | ||
520 | { | ||
521 | struct ata_port *ap = dev->ap; | ||
522 | int err = -ENODEV; | ||
523 | int gtf_count = gtf_length / REGS_PER_GTF; | ||
524 | int ix; | ||
525 | struct taskfile_array *gtf; | ||
526 | 344 | ||
527 | if (ata_msg_probe(ap)) | 345 | if (ata_msg_probe(ap)) |
528 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", | 346 | ata_dev_printk(dev, KERN_DEBUG, "executing ACPI cmd " |
529 | __FUNCTION__, ap->port_no); | 347 | "%02x/%02x:%02x:%02x:%02x:%02x:%02x\n", |
530 | 348 | tf.command, tf.feature, tf.nsect, | |
531 | if (libata_noacpi || !(ap->flags & ATA_FLAG_ACPI_SATA)) | 349 | tf.lbal, tf.lbam, tf.lbah, tf.device); |
532 | return 0; | 350 | |
533 | 351 | rtf = tf; | |
534 | if (!ata_dev_enabled(dev) || (ap->flags & ATA_FLAG_DISABLED)) | 352 | err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0); |
535 | goto out; | 353 | if (err_mask) { |
536 | if (!gtf_count) /* shouldn't be here */ | 354 | ata_dev_printk(dev, KERN_ERR, |
537 | goto out; | 355 | "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " |
538 | 356 | "(Emask=0x%x Stat=0x%02x Err=0x%02x)\n", | |
539 | if (gtf_length % REGS_PER_GTF) { | 357 | tf.command, tf.feature, tf.nsect, tf.lbal, tf.lbam, |
540 | if (ata_msg_drv(ap)) | 358 | tf.lbah, tf.device, err_mask, rtf.command, rtf.feature); |
541 | ata_dev_printk(dev, KERN_ERR, | 359 | return -EIO; |
542 | "%s: unexpected GTF length (%d)\n", | ||
543 | __FUNCTION__, gtf_length); | ||
544 | goto out; | ||
545 | } | ||
546 | |||
547 | for (ix = 0; ix < gtf_count; ix++) { | ||
548 | gtf = (struct taskfile_array *) | ||
549 | (gtf_address + ix * REGS_PER_GTF); | ||
550 | |||
551 | /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ | ||
552 | taskfile_load_raw(dev, gtf); | ||
553 | } | 360 | } |
554 | 361 | ||
555 | err = 0; | 362 | return 0; |
556 | out: | ||
557 | return err; | ||
558 | } | 363 | } |
559 | 364 | ||
560 | /** | 365 | /** |
561 | * ata_acpi_exec_tfs - get then write drive taskfile settings | 366 | * ata_acpi_exec_tfs - get then write drive taskfile settings |
562 | * @ap: the ata_port for the drive | 367 | * @dev: target ATA device |
563 | * | 368 | * |
564 | * This applies to both PATA and SATA drives. | 369 | * Evaluate _GTF and excute returned taskfiles. |
370 | * | ||
371 | * LOCKING: | ||
372 | * EH context. | ||
373 | * | ||
374 | * RETURNS: | ||
375 | * Number of executed taskfiles on success, 0 if _GTF doesn't exist or | ||
376 | * doesn't contain valid data. -errno on other errors. | ||
565 | */ | 377 | */ |
566 | int ata_acpi_exec_tfs(struct ata_port *ap) | 378 | static int ata_acpi_exec_tfs(struct ata_device *dev) |
567 | { | 379 | { |
568 | int ix; | 380 | struct ata_acpi_gtf *gtf = NULL; |
569 | int ret = 0; | 381 | void *ptr_to_free = NULL; |
570 | unsigned int gtf_length; | 382 | int gtf_count, i, rc; |
571 | unsigned long gtf_address; | 383 | |
572 | unsigned long obj_loc; | 384 | /* get taskfiles */ |
573 | 385 | rc = ata_dev_get_GTF(dev, >f, &ptr_to_free); | |
574 | if (libata_noacpi) | 386 | if (rc < 0) |
575 | return 0; | 387 | return rc; |
576 | /* | 388 | gtf_count = rc; |
577 | * TBD - implement PATA support. For now, | 389 | |
578 | * we should not run GTF on PATA devices since some | 390 | /* execute them */ |
579 | * PATA require execution of GTM/STM before GTF. | 391 | for (i = 0, rc = 0; i < gtf_count; i++) { |
580 | */ | 392 | int tmp; |
581 | if (!(ap->flags & ATA_FLAG_ACPI_SATA)) | 393 | |
582 | return 0; | 394 | /* ACPI errors are eventually ignored. Run till the |
583 | 395 | * end even after errors. | |
584 | for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { | 396 | */ |
585 | struct ata_device *dev = &ap->device[ix]; | 397 | tmp = taskfile_load_raw(dev, gtf++); |
586 | 398 | if (!rc) | |
587 | if (!ata_dev_enabled(dev)) | 399 | rc = tmp; |
588 | continue; | ||
589 | |||
590 | ret = do_drive_get_GTF(dev, >f_length, >f_address, | ||
591 | &obj_loc); | ||
592 | if (ret < 0) { | ||
593 | if (ata_msg_probe(ap)) | ||
594 | ata_port_printk(ap, KERN_DEBUG, | ||
595 | "%s: get_GTF error (%d)\n", | ||
596 | __FUNCTION__, ret); | ||
597 | break; | ||
598 | } | ||
599 | |||
600 | ret = do_drive_set_taskfiles(dev, gtf_length, gtf_address); | ||
601 | kfree((void *)obj_loc); | ||
602 | if (ret < 0) { | ||
603 | if (ata_msg_probe(ap)) | ||
604 | ata_port_printk(ap, KERN_DEBUG, | ||
605 | "%s: set_taskfiles error (%d)\n", | ||
606 | __FUNCTION__, ret); | ||
607 | break; | ||
608 | } | ||
609 | } | 400 | } |
610 | 401 | ||
611 | return ret; | 402 | kfree(ptr_to_free); |
403 | |||
404 | if (rc == 0) | ||
405 | return gtf_count; | ||
406 | return rc; | ||
612 | } | 407 | } |
613 | 408 | ||
614 | /** | 409 | /** |
@@ -620,62 +415,25 @@ int ata_acpi_exec_tfs(struct ata_port *ap) | |||
620 | * ATM this function never returns a failure. It is an optional | 415 | * ATM this function never returns a failure. It is an optional |
621 | * method and if it fails for whatever reason, we should still | 416 | * method and if it fails for whatever reason, we should still |
622 | * just keep going. | 417 | * just keep going. |
418 | * | ||
419 | * LOCKING: | ||
420 | * EH context. | ||
421 | * | ||
422 | * RETURNS: | ||
423 | * 0 on success, -errno on failure. | ||
623 | */ | 424 | */ |
624 | int ata_acpi_push_id(struct ata_device *dev) | 425 | static int ata_acpi_push_id(struct ata_device *dev) |
625 | { | 426 | { |
626 | struct ata_port *ap = dev->ap; | 427 | struct ata_port *ap = dev->ap; |
627 | acpi_handle handle; | ||
628 | acpi_integer pcidevfn; | ||
629 | int err; | 428 | int err; |
630 | struct device *gdev = ap->host->dev; | ||
631 | u32 dev_adr; | ||
632 | acpi_status status; | 429 | acpi_status status; |
633 | struct acpi_object_list input; | 430 | struct acpi_object_list input; |
634 | union acpi_object in_params[1]; | 431 | union acpi_object in_params[1]; |
635 | 432 | ||
636 | if (libata_noacpi) | ||
637 | return 0; | ||
638 | |||
639 | if (ata_msg_probe(ap)) | 433 | if (ata_msg_probe(ap)) |
640 | ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", | 434 | ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", |
641 | __FUNCTION__, dev->devno, ap->port_no); | 435 | __FUNCTION__, dev->devno, ap->port_no); |
642 | 436 | ||
643 | /* Don't continue if not a SATA device. */ | ||
644 | if (!(ap->flags & ATA_FLAG_ACPI_SATA)) { | ||
645 | if (ata_msg_probe(ap)) | ||
646 | ata_dev_printk(dev, KERN_DEBUG, | ||
647 | "%s: Not a SATA device\n", __FUNCTION__); | ||
648 | goto out; | ||
649 | } | ||
650 | |||
651 | /* Don't continue if device has no _ADR method. | ||
652 | * _SDD is intended for known motherboard devices. */ | ||
653 | err = sata_get_dev_handle(gdev, &handle, &pcidevfn); | ||
654 | if (err < 0) { | ||
655 | if (ata_msg_probe(ap)) | ||
656 | ata_dev_printk(dev, KERN_DEBUG, | ||
657 | "%s: sata_get_dev_handle failed (%d\n", | ||
658 | __FUNCTION__, err); | ||
659 | goto out; | ||
660 | } | ||
661 | |||
662 | /* Get this drive's _ADR info, if not already known */ | ||
663 | if (!dev->obj_handle) { | ||
664 | dev_adr = SATA_ADR_RSVD; | ||
665 | err = get_sata_adr(gdev, handle, pcidevfn, dev->devno, ap, dev, | ||
666 | &dev_adr); | ||
667 | if (err < 0 || dev_adr == SATA_ADR_RSVD || | ||
668 | !dev->obj_handle) { | ||
669 | if (ata_msg_probe(ap)) | ||
670 | ata_dev_printk(dev, KERN_DEBUG, | ||
671 | "%s: get_sata_adr failed: " | ||
672 | "err=%d, dev_adr=%u, obj_handle=0x%p\n", | ||
673 | __FUNCTION__, err, dev_adr, | ||
674 | dev->obj_handle); | ||
675 | goto out; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | /* Give the drive Identify data to the drive via the _SDD method */ | 437 | /* Give the drive Identify data to the drive via the _SDD method */ |
680 | /* _SDD: set up input parameters */ | 438 | /* _SDD: set up input parameters */ |
681 | input.count = 1; | 439 | input.count = 1; |
@@ -687,20 +445,150 @@ int ata_acpi_push_id(struct ata_device *dev) | |||
687 | 445 | ||
688 | /* It's OK for _SDD to be missing too. */ | 446 | /* It's OK for _SDD to be missing too. */ |
689 | swap_buf_le16(dev->id, ATA_ID_WORDS); | 447 | swap_buf_le16(dev->id, ATA_ID_WORDS); |
690 | status = acpi_evaluate_object(dev->obj_handle, "_SDD", &input, NULL); | 448 | status = acpi_evaluate_object(dev->acpi_handle, "_SDD", &input, NULL); |
691 | swap_buf_le16(dev->id, ATA_ID_WORDS); | 449 | swap_buf_le16(dev->id, ATA_ID_WORDS); |
692 | 450 | ||
693 | err = ACPI_FAILURE(status) ? -EIO : 0; | 451 | err = ACPI_FAILURE(status) ? -EIO : 0; |
694 | if (err < 0) { | 452 | if (err < 0) |
695 | if (ata_msg_probe(ap)) | 453 | ata_dev_printk(dev, KERN_WARNING, |
696 | ata_dev_printk(dev, KERN_DEBUG, | 454 | "ACPI _SDD failed (AE 0x%x)\n", status); |
697 | "%s _SDD error: status = 0x%x\n", | 455 | |
698 | __FUNCTION__, status); | 456 | return err; |
457 | } | ||
458 | |||
459 | /** | ||
460 | * ata_acpi_on_suspend - ATA ACPI hook called on suspend | ||
461 | * @ap: target ATA port | ||
462 | * | ||
463 | * This function is called when @ap is about to be suspended. All | ||
464 | * devices are already put to sleep but the port_suspend() callback | ||
465 | * hasn't been executed yet. Error return from this function aborts | ||
466 | * suspend. | ||
467 | * | ||
468 | * LOCKING: | ||
469 | * EH context. | ||
470 | * | ||
471 | * RETURNS: | ||
472 | * 0 on success, -errno on failure. | ||
473 | */ | ||
474 | int ata_acpi_on_suspend(struct ata_port *ap) | ||
475 | { | ||
476 | unsigned long flags; | ||
477 | int rc; | ||
478 | |||
479 | /* proceed iff per-port acpi_handle is valid */ | ||
480 | if (!ap->acpi_handle) | ||
481 | return 0; | ||
482 | BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); | ||
483 | |||
484 | /* store timing parameters */ | ||
485 | rc = ata_acpi_gtm(ap, &ap->acpi_gtm); | ||
486 | |||
487 | spin_lock_irqsave(ap->lock, flags); | ||
488 | if (rc == 0) | ||
489 | ap->pflags |= ATA_PFLAG_GTM_VALID; | ||
490 | else | ||
491 | ap->pflags &= ~ATA_PFLAG_GTM_VALID; | ||
492 | spin_unlock_irqrestore(ap->lock, flags); | ||
493 | |||
494 | if (rc == -ENOENT) | ||
495 | rc = 0; | ||
496 | return rc; | ||
497 | } | ||
498 | |||
499 | /** | ||
500 | * ata_acpi_on_resume - ATA ACPI hook called on resume | ||
501 | * @ap: target ATA port | ||
502 | * | ||
503 | * This function is called when @ap is resumed - right after port | ||
504 | * itself is resumed but before any EH action is taken. | ||
505 | * | ||
506 | * LOCKING: | ||
507 | * EH context. | ||
508 | */ | ||
509 | void ata_acpi_on_resume(struct ata_port *ap) | ||
510 | { | ||
511 | int i; | ||
512 | |||
513 | if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) { | ||
514 | BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); | ||
515 | |||
516 | /* restore timing parameters */ | ||
517 | ata_acpi_stm(ap, &ap->acpi_gtm); | ||
699 | } | 518 | } |
700 | 519 | ||
701 | /* always return success */ | 520 | /* schedule _GTF */ |
702 | out: | 521 | for (i = 0; i < ATA_MAX_DEVICES; i++) |
703 | return 0; | 522 | ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING; |
704 | } | 523 | } |
705 | 524 | ||
525 | /** | ||
526 | * ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration | ||
527 | * @dev: target ATA device | ||
528 | * | ||
529 | * This function is called when @dev is about to be configured. | ||
530 | * IDENTIFY data might have been modified after this hook is run. | ||
531 | * | ||
532 | * LOCKING: | ||
533 | * EH context. | ||
534 | * | ||
535 | * RETURNS: | ||
536 | * Positive number if IDENTIFY data needs to be refreshed, 0 if not, | ||
537 | * -errno on failure. | ||
538 | */ | ||
539 | int ata_acpi_on_devcfg(struct ata_device *dev) | ||
540 | { | ||
541 | struct ata_port *ap = dev->ap; | ||
542 | struct ata_eh_context *ehc = &ap->eh_context; | ||
543 | int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; | ||
544 | int rc; | ||
545 | |||
546 | if (!dev->acpi_handle) | ||
547 | return 0; | ||
548 | |||
549 | /* do we need to do _GTF? */ | ||
550 | if (!(dev->flags & ATA_DFLAG_ACPI_PENDING) && | ||
551 | !(acpi_sata && (ehc->i.flags & ATA_EHI_DID_HARDRESET))) | ||
552 | return 0; | ||
553 | |||
554 | /* do _SDD if SATA */ | ||
555 | if (acpi_sata) { | ||
556 | rc = ata_acpi_push_id(dev); | ||
557 | if (rc) | ||
558 | goto acpi_err; | ||
559 | } | ||
560 | |||
561 | /* do _GTF */ | ||
562 | rc = ata_acpi_exec_tfs(dev); | ||
563 | if (rc < 0) | ||
564 | goto acpi_err; | ||
565 | |||
566 | dev->flags &= ~ATA_DFLAG_ACPI_PENDING; | ||
567 | |||
568 | /* refresh IDENTIFY page if any _GTF command has been executed */ | ||
569 | if (rc > 0) { | ||
570 | rc = ata_dev_reread_id(dev, 0); | ||
571 | if (rc < 0) { | ||
572 | ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY " | ||
573 | "after ACPI commands\n"); | ||
574 | return rc; | ||
575 | } | ||
576 | } | ||
706 | 577 | ||
578 | return 0; | ||
579 | |||
580 | acpi_err: | ||
581 | /* let EH retry on the first failure, disable ACPI on the second */ | ||
582 | if (dev->flags & ATA_DFLAG_ACPI_FAILED) { | ||
583 | ata_dev_printk(dev, KERN_WARNING, "ACPI on devcfg failed the " | ||
584 | "second time, disabling (errno=%d)\n", rc); | ||
585 | |||
586 | dev->acpi_handle = NULL; | ||
587 | |||
588 | /* if port is working, request IDENTIFY reload and continue */ | ||
589 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) | ||
590 | rc = 1; | ||
591 | } | ||
592 | dev->flags |= ATA_DFLAG_ACPI_FAILED; | ||
593 | return rc; | ||
594 | } | ||
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 981b397cb46b..5b25311ba885 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -1845,7 +1845,8 @@ static void ata_dev_config_ncq(struct ata_device *dev, | |||
1845 | int ata_dev_configure(struct ata_device *dev) | 1845 | int ata_dev_configure(struct ata_device *dev) |
1846 | { | 1846 | { |
1847 | struct ata_port *ap = dev->ap; | 1847 | struct ata_port *ap = dev->ap; |
1848 | int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; | 1848 | struct ata_eh_context *ehc = &ap->eh_context; |
1849 | int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; | ||
1849 | const u16 *id = dev->id; | 1850 | const u16 *id = dev->id; |
1850 | unsigned int xfer_mask; | 1851 | unsigned int xfer_mask; |
1851 | char revbuf[7]; /* XYZ-99\0 */ | 1852 | char revbuf[7]; /* XYZ-99\0 */ |
@@ -1862,15 +1863,10 @@ int ata_dev_configure(struct ata_device *dev) | |||
1862 | if (ata_msg_probe(ap)) | 1863 | if (ata_msg_probe(ap)) |
1863 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); | 1864 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); |
1864 | 1865 | ||
1865 | /* set _SDD */ | 1866 | /* let ACPI work its magic */ |
1866 | rc = ata_acpi_push_id(dev); | 1867 | rc = ata_acpi_on_devcfg(dev); |
1867 | if (rc) { | 1868 | if (rc) |
1868 | ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n", | 1869 | return rc; |
1869 | rc); | ||
1870 | } | ||
1871 | |||
1872 | /* retrieve and execute the ATA task file of _GTF */ | ||
1873 | ata_acpi_exec_tfs(ap); | ||
1874 | 1870 | ||
1875 | /* print device capabilities */ | 1871 | /* print device capabilities */ |
1876 | if (ata_msg_probe(ap)) | 1872 | if (ata_msg_probe(ap)) |
@@ -3359,7 +3355,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) | |||
3359 | return 0; | 3355 | return 0; |
3360 | 3356 | ||
3361 | /* if SATA, resume phy */ | 3357 | /* if SATA, resume phy */ |
3362 | if (ap->cbl == ATA_CBL_SATA) { | 3358 | if (ap->flags & ATA_FLAG_SATA) { |
3363 | rc = sata_phy_resume(ap, timing, deadline); | 3359 | rc = sata_phy_resume(ap, timing, deadline); |
3364 | /* whine about phy resume failure but proceed */ | 3360 | /* whine about phy resume failure but proceed */ |
3365 | if (rc && rc != -EOPNOTSUPP) | 3361 | if (rc && rc != -EOPNOTSUPP) |
@@ -4107,6 +4103,68 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) | |||
4107 | } | 4103 | } |
4108 | 4104 | ||
4109 | /** | 4105 | /** |
4106 | * ata_fill_sg_dumb - Fill PCI IDE PRD table | ||
4107 | * @qc: Metadata associated with taskfile to be transferred | ||
4108 | * | ||
4109 | * Fill PCI IDE PRD (scatter-gather) table with segments | ||
4110 | * associated with the current disk command. Perform the fill | ||
4111 | * so that we avoid writing any length 64K records for | ||
4112 | * controllers that don't follow the spec. | ||
4113 | * | ||
4114 | * LOCKING: | ||
4115 | * spin_lock_irqsave(host lock) | ||
4116 | * | ||
4117 | */ | ||
4118 | static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) | ||
4119 | { | ||
4120 | struct ata_port *ap = qc->ap; | ||
4121 | struct scatterlist *sg; | ||
4122 | unsigned int idx; | ||
4123 | |||
4124 | WARN_ON(qc->__sg == NULL); | ||
4125 | WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); | ||
4126 | |||
4127 | idx = 0; | ||
4128 | ata_for_each_sg(sg, qc) { | ||
4129 | u32 addr, offset; | ||
4130 | u32 sg_len, len, blen; | ||
4131 | |||
4132 | /* determine if physical DMA addr spans 64K boundary. | ||
4133 | * Note h/w doesn't support 64-bit, so we unconditionally | ||
4134 | * truncate dma_addr_t to u32. | ||
4135 | */ | ||
4136 | addr = (u32) sg_dma_address(sg); | ||
4137 | sg_len = sg_dma_len(sg); | ||
4138 | |||
4139 | while (sg_len) { | ||
4140 | offset = addr & 0xffff; | ||
4141 | len = sg_len; | ||
4142 | if ((offset + sg_len) > 0x10000) | ||
4143 | len = 0x10000 - offset; | ||
4144 | |||
4145 | blen = len & 0xffff; | ||
4146 | ap->prd[idx].addr = cpu_to_le32(addr); | ||
4147 | if (blen == 0) { | ||
4148 | /* Some PATA chipsets like the CS5530 can't | ||
4149 | cope with 0x0000 meaning 64K as the spec says */ | ||
4150 | ap->prd[idx].flags_len = cpu_to_le32(0x8000); | ||
4151 | blen = 0x8000; | ||
4152 | ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000); | ||
4153 | } | ||
4154 | ap->prd[idx].flags_len = cpu_to_le32(blen); | ||
4155 | VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); | ||
4156 | |||
4157 | idx++; | ||
4158 | sg_len -= len; | ||
4159 | addr += len; | ||
4160 | } | ||
4161 | } | ||
4162 | |||
4163 | if (idx) | ||
4164 | ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); | ||
4165 | } | ||
4166 | |||
4167 | /** | ||
4110 | * ata_check_atapi_dma - Check whether ATAPI DMA can be supported | 4168 | * ata_check_atapi_dma - Check whether ATAPI DMA can be supported |
4111 | * @qc: Metadata associated with taskfile to check | 4169 | * @qc: Metadata associated with taskfile to check |
4112 | * | 4170 | * |
@@ -4153,6 +4211,23 @@ void ata_qc_prep(struct ata_queued_cmd *qc) | |||
4153 | ata_fill_sg(qc); | 4211 | ata_fill_sg(qc); |
4154 | } | 4212 | } |
4155 | 4213 | ||
4214 | /** | ||
4215 | * ata_dumb_qc_prep - Prepare taskfile for submission | ||
4216 | * @qc: Metadata associated with taskfile to be prepared | ||
4217 | * | ||
4218 | * Prepare ATA taskfile for submission. | ||
4219 | * | ||
4220 | * LOCKING: | ||
4221 | * spin_lock_irqsave(host lock) | ||
4222 | */ | ||
4223 | void ata_dumb_qc_prep(struct ata_queued_cmd *qc) | ||
4224 | { | ||
4225 | if (!(qc->flags & ATA_QCFLAG_DMAMAP)) | ||
4226 | return; | ||
4227 | |||
4228 | ata_fill_sg_dumb(qc); | ||
4229 | } | ||
4230 | |||
4156 | void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } | 4231 | void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } |
4157 | 4232 | ||
4158 | /** | 4233 | /** |
@@ -5660,7 +5735,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) | |||
5660 | */ | 5735 | */ |
5661 | int sata_scr_valid(struct ata_port *ap) | 5736 | int sata_scr_valid(struct ata_port *ap) |
5662 | { | 5737 | { |
5663 | return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read; | 5738 | return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read; |
5664 | } | 5739 | } |
5665 | 5740 | ||
5666 | /** | 5741 | /** |
@@ -6293,6 +6368,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) | |||
6293 | if (rc) | 6368 | if (rc) |
6294 | return rc; | 6369 | return rc; |
6295 | 6370 | ||
6371 | /* associate with ACPI nodes */ | ||
6372 | ata_acpi_associate(host); | ||
6373 | |||
6296 | /* set cable, sata_spd_limit and report */ | 6374 | /* set cable, sata_spd_limit and report */ |
6297 | for (i = 0; i < host->n_ports; i++) { | 6375 | for (i = 0; i < host->n_ports; i++) { |
6298 | struct ata_port *ap = host->ports[i]; | 6376 | struct ata_port *ap = host->ports[i]; |
@@ -6324,7 +6402,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) | |||
6324 | if (!ata_port_is_dummy(ap)) | 6402 | if (!ata_port_is_dummy(ap)) |
6325 | ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " | 6403 | ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " |
6326 | "ctl 0x%p bmdma 0x%p irq %d\n", | 6404 | "ctl 0x%p bmdma 0x%p irq %d\n", |
6327 | ap->cbl == ATA_CBL_SATA ? 'S' : 'P', | 6405 | (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', |
6328 | ata_mode_string(xfer_mask), | 6406 | ata_mode_string(xfer_mask), |
6329 | ap->ioaddr.cmd_addr, | 6407 | ap->ioaddr.cmd_addr, |
6330 | ap->ioaddr.ctl_addr, | 6408 | ap->ioaddr.ctl_addr, |
@@ -6822,6 +6900,7 @@ EXPORT_SYMBOL_GPL(ata_do_set_mode); | |||
6822 | EXPORT_SYMBOL_GPL(ata_data_xfer); | 6900 | EXPORT_SYMBOL_GPL(ata_data_xfer); |
6823 | EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); | 6901 | EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); |
6824 | EXPORT_SYMBOL_GPL(ata_qc_prep); | 6902 | EXPORT_SYMBOL_GPL(ata_qc_prep); |
6903 | EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); | ||
6825 | EXPORT_SYMBOL_GPL(ata_noop_qc_prep); | 6904 | EXPORT_SYMBOL_GPL(ata_noop_qc_prep); |
6826 | EXPORT_SYMBOL_GPL(ata_bmdma_setup); | 6905 | EXPORT_SYMBOL_GPL(ata_bmdma_setup); |
6827 | EXPORT_SYMBOL_GPL(ata_bmdma_start); | 6906 | EXPORT_SYMBOL_GPL(ata_bmdma_start); |
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f7582c9c320e..9ee0a8c08d96 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -2154,19 +2154,25 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) | |||
2154 | 2154 | ||
2155 | WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); | 2155 | WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); |
2156 | 2156 | ||
2157 | /* tell ACPI we're suspending */ | ||
2158 | rc = ata_acpi_on_suspend(ap); | ||
2159 | if (rc) | ||
2160 | goto out; | ||
2161 | |||
2157 | /* suspend */ | 2162 | /* suspend */ |
2158 | ata_eh_freeze_port(ap); | 2163 | ata_eh_freeze_port(ap); |
2159 | 2164 | ||
2160 | if (ap->ops->port_suspend) | 2165 | if (ap->ops->port_suspend) |
2161 | rc = ap->ops->port_suspend(ap, ap->pm_mesg); | 2166 | rc = ap->ops->port_suspend(ap, ap->pm_mesg); |
2162 | 2167 | ||
2168 | out: | ||
2163 | /* report result */ | 2169 | /* report result */ |
2164 | spin_lock_irqsave(ap->lock, flags); | 2170 | spin_lock_irqsave(ap->lock, flags); |
2165 | 2171 | ||
2166 | ap->pflags &= ~ATA_PFLAG_PM_PENDING; | 2172 | ap->pflags &= ~ATA_PFLAG_PM_PENDING; |
2167 | if (rc == 0) | 2173 | if (rc == 0) |
2168 | ap->pflags |= ATA_PFLAG_SUSPENDED; | 2174 | ap->pflags |= ATA_PFLAG_SUSPENDED; |
2169 | else | 2175 | else if (ap->pflags & ATA_PFLAG_FROZEN) |
2170 | ata_port_schedule_eh(ap); | 2176 | ata_port_schedule_eh(ap); |
2171 | 2177 | ||
2172 | if (ap->pm_result) { | 2178 | if (ap->pm_result) { |
@@ -2207,6 +2213,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) | |||
2207 | if (ap->ops->port_resume) | 2213 | if (ap->ops->port_resume) |
2208 | rc = ap->ops->port_resume(ap); | 2214 | rc = ap->ops->port_resume(ap); |
2209 | 2215 | ||
2216 | /* tell ACPI that we're resuming */ | ||
2217 | ata_acpi_on_resume(ap); | ||
2218 | |||
2210 | /* report result */ | 2219 | /* report result */ |
2211 | spin_lock_irqsave(ap->lock, flags); | 2220 | spin_lock_irqsave(ap->lock, flags); |
2212 | ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); | 2221 | ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 4ddf00c8c5f5..cfde22da07ac 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -2620,7 +2620,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) | |||
2620 | ata_dev_printk(dev, KERN_WARNING, | 2620 | ata_dev_printk(dev, KERN_WARNING, |
2621 | "invalid multi_count %u ignored\n", | 2621 | "invalid multi_count %u ignored\n", |
2622 | multi_count); | 2622 | multi_count); |
2623 | } | 2623 | } |
2624 | 2624 | ||
2625 | /* READ/WRITE LONG use a non-standard sect_size */ | 2625 | /* READ/WRITE LONG use a non-standard sect_size */ |
2626 | qc->sect_size = ATA_SECT_SIZE; | 2626 | qc->sect_size = ATA_SECT_SIZE; |
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 5e2466658420..ba17fc5f2e99 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h | |||
@@ -98,17 +98,15 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host); | |||
98 | 98 | ||
99 | /* libata-acpi.c */ | 99 | /* libata-acpi.c */ |
100 | #ifdef CONFIG_ATA_ACPI | 100 | #ifdef CONFIG_ATA_ACPI |
101 | extern int ata_acpi_exec_tfs(struct ata_port *ap); | 101 | extern void ata_acpi_associate(struct ata_host *host); |
102 | extern int ata_acpi_push_id(struct ata_device *dev); | 102 | extern int ata_acpi_on_suspend(struct ata_port *ap); |
103 | extern void ata_acpi_on_resume(struct ata_port *ap); | ||
104 | extern int ata_acpi_on_devcfg(struct ata_device *adev); | ||
103 | #else | 105 | #else |
104 | static inline int ata_acpi_exec_tfs(struct ata_port *ap) | 106 | static inline void ata_acpi_associate(struct ata_host *host) { } |
105 | { | 107 | static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } |
106 | return 0; | 108 | static inline void ata_acpi_on_resume(struct ata_port *ap) { } |
107 | } | 109 | static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; } |
108 | static inline int ata_acpi_push_id(struct ata_device *dev) | ||
109 | { | ||
110 | return 0; | ||
111 | } | ||
112 | #endif | 110 | #endif |
113 | 111 | ||
114 | /* libata-scsi.c */ | 112 | /* libata-scsi.c */ |
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 75e95bdbe02f..30c4276ec882 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c | |||
@@ -520,14 +520,14 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
520 | { | 520 | { |
521 | static const struct ata_port_info info_early = { | 521 | static const struct ata_port_info info_early = { |
522 | .sht = &ali_sht, | 522 | .sht = &ali_sht, |
523 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 523 | .flags = ATA_FLAG_SLAVE_POSS, |
524 | .pio_mask = 0x1f, | 524 | .pio_mask = 0x1f, |
525 | .port_ops = &ali_early_port_ops | 525 | .port_ops = &ali_early_port_ops |
526 | }; | 526 | }; |
527 | /* Revision 0x20 added DMA */ | 527 | /* Revision 0x20 added DMA */ |
528 | static const struct ata_port_info info_20 = { | 528 | static const struct ata_port_info info_20 = { |
529 | .sht = &ali_sht, | 529 | .sht = &ali_sht, |
530 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, | 530 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, |
531 | .pio_mask = 0x1f, | 531 | .pio_mask = 0x1f, |
532 | .mwdma_mask = 0x07, | 532 | .mwdma_mask = 0x07, |
533 | .port_ops = &ali_20_port_ops | 533 | .port_ops = &ali_20_port_ops |
@@ -535,7 +535,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
535 | /* Revision 0x20 with support logic added UDMA */ | 535 | /* Revision 0x20 with support logic added UDMA */ |
536 | static const struct ata_port_info info_20_udma = { | 536 | static const struct ata_port_info info_20_udma = { |
537 | .sht = &ali_sht, | 537 | .sht = &ali_sht, |
538 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, | 538 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, |
539 | .pio_mask = 0x1f, | 539 | .pio_mask = 0x1f, |
540 | .mwdma_mask = 0x07, | 540 | .mwdma_mask = 0x07, |
541 | .udma_mask = 0x07, /* UDMA33 */ | 541 | .udma_mask = 0x07, /* UDMA33 */ |
@@ -544,37 +544,37 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
544 | /* Revision 0xC2 adds UDMA66 */ | 544 | /* Revision 0xC2 adds UDMA66 */ |
545 | static const struct ata_port_info info_c2 = { | 545 | static const struct ata_port_info info_c2 = { |
546 | .sht = &ali_sht, | 546 | .sht = &ali_sht, |
547 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, | 547 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, |
548 | .pio_mask = 0x1f, | 548 | .pio_mask = 0x1f, |
549 | .mwdma_mask = 0x07, | 549 | .mwdma_mask = 0x07, |
550 | .udma_mask = 0x1f, | 550 | .udma_mask = ATA_UDMA4, |
551 | .port_ops = &ali_c2_port_ops | 551 | .port_ops = &ali_c2_port_ops |
552 | }; | 552 | }; |
553 | /* Revision 0xC3 is UDMA66 for now */ | 553 | /* Revision 0xC3 is UDMA66 for now */ |
554 | static const struct ata_port_info info_c3 = { | 554 | static const struct ata_port_info info_c3 = { |
555 | .sht = &ali_sht, | 555 | .sht = &ali_sht, |
556 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, | 556 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, |
557 | .pio_mask = 0x1f, | 557 | .pio_mask = 0x1f, |
558 | .mwdma_mask = 0x07, | 558 | .mwdma_mask = 0x07, |
559 | .udma_mask = 0x1f, | 559 | .udma_mask = ATA_UDMA4, |
560 | .port_ops = &ali_c2_port_ops | 560 | .port_ops = &ali_c2_port_ops |
561 | }; | 561 | }; |
562 | /* Revision 0xC4 is UDMA100 */ | 562 | /* Revision 0xC4 is UDMA100 */ |
563 | static const struct ata_port_info info_c4 = { | 563 | static const struct ata_port_info info_c4 = { |
564 | .sht = &ali_sht, | 564 | .sht = &ali_sht, |
565 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, | 565 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48, |
566 | .pio_mask = 0x1f, | 566 | .pio_mask = 0x1f, |
567 | .mwdma_mask = 0x07, | 567 | .mwdma_mask = 0x07, |
568 | .udma_mask = 0x3f, | 568 | .udma_mask = ATA_UDMA5, |
569 | .port_ops = &ali_c2_port_ops | 569 | .port_ops = &ali_c2_port_ops |
570 | }; | 570 | }; |
571 | /* Revision 0xC5 is UDMA133 with LBA48 DMA */ | 571 | /* Revision 0xC5 is UDMA133 with LBA48 DMA */ |
572 | static const struct ata_port_info info_c5 = { | 572 | static const struct ata_port_info info_c5 = { |
573 | .sht = &ali_sht, | 573 | .sht = &ali_sht, |
574 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 574 | .flags = ATA_FLAG_SLAVE_POSS, |
575 | .pio_mask = 0x1f, | 575 | .pio_mask = 0x1f, |
576 | .mwdma_mask = 0x07, | 576 | .mwdma_mask = 0x07, |
577 | .udma_mask = 0x7f, | 577 | .udma_mask = ATA_UDMA6, |
578 | .port_ops = &ali_c5_port_ops | 578 | .port_ops = &ali_c5_port_ops |
579 | }; | 579 | }; |
580 | 580 | ||
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index a16f629b7b38..b9c44c575ce3 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c | |||
@@ -541,7 +541,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
541 | static const struct ata_port_info info[10] = { | 541 | static const struct ata_port_info info[10] = { |
542 | { /* 0: AMD 7401 */ | 542 | { /* 0: AMD 7401 */ |
543 | .sht = &amd_sht, | 543 | .sht = &amd_sht, |
544 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 544 | .flags = ATA_FLAG_SLAVE_POSS, |
545 | .pio_mask = 0x1f, | 545 | .pio_mask = 0x1f, |
546 | .mwdma_mask = 0x07, /* No SWDMA */ | 546 | .mwdma_mask = 0x07, /* No SWDMA */ |
547 | .udma_mask = 0x07, /* UDMA 33 */ | 547 | .udma_mask = 0x07, /* UDMA 33 */ |
@@ -549,74 +549,74 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
549 | }, | 549 | }, |
550 | { /* 1: Early AMD7409 - no swdma */ | 550 | { /* 1: Early AMD7409 - no swdma */ |
551 | .sht = &amd_sht, | 551 | .sht = &amd_sht, |
552 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 552 | .flags = ATA_FLAG_SLAVE_POSS, |
553 | .pio_mask = 0x1f, | 553 | .pio_mask = 0x1f, |
554 | .mwdma_mask = 0x07, | 554 | .mwdma_mask = 0x07, |
555 | .udma_mask = 0x1f, /* UDMA 66 */ | 555 | .udma_mask = ATA_UDMA4, /* UDMA 66 */ |
556 | .port_ops = &amd66_port_ops | 556 | .port_ops = &amd66_port_ops |
557 | }, | 557 | }, |
558 | { /* 2: AMD 7409, no swdma errata */ | 558 | { /* 2: AMD 7409, no swdma errata */ |
559 | .sht = &amd_sht, | 559 | .sht = &amd_sht, |
560 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 560 | .flags = ATA_FLAG_SLAVE_POSS, |
561 | .pio_mask = 0x1f, | 561 | .pio_mask = 0x1f, |
562 | .mwdma_mask = 0x07, | 562 | .mwdma_mask = 0x07, |
563 | .udma_mask = 0x1f, /* UDMA 66 */ | 563 | .udma_mask = ATA_UDMA4, /* UDMA 66 */ |
564 | .port_ops = &amd66_port_ops | 564 | .port_ops = &amd66_port_ops |
565 | }, | 565 | }, |
566 | { /* 3: AMD 7411 */ | 566 | { /* 3: AMD 7411 */ |
567 | .sht = &amd_sht, | 567 | .sht = &amd_sht, |
568 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 568 | .flags = ATA_FLAG_SLAVE_POSS, |
569 | .pio_mask = 0x1f, | 569 | .pio_mask = 0x1f, |
570 | .mwdma_mask = 0x07, | 570 | .mwdma_mask = 0x07, |
571 | .udma_mask = 0x3f, /* UDMA 100 */ | 571 | .udma_mask = ATA_UDMA5, /* UDMA 100 */ |
572 | .port_ops = &amd100_port_ops | 572 | .port_ops = &amd100_port_ops |
573 | }, | 573 | }, |
574 | { /* 4: AMD 7441 */ | 574 | { /* 4: AMD 7441 */ |
575 | .sht = &amd_sht, | 575 | .sht = &amd_sht, |
576 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 576 | .flags = ATA_FLAG_SLAVE_POSS, |
577 | .pio_mask = 0x1f, | 577 | .pio_mask = 0x1f, |
578 | .mwdma_mask = 0x07, | 578 | .mwdma_mask = 0x07, |
579 | .udma_mask = 0x3f, /* UDMA 100 */ | 579 | .udma_mask = ATA_UDMA5, /* UDMA 100 */ |
580 | .port_ops = &amd100_port_ops | 580 | .port_ops = &amd100_port_ops |
581 | }, | 581 | }, |
582 | { /* 5: AMD 8111*/ | 582 | { /* 5: AMD 8111*/ |
583 | .sht = &amd_sht, | 583 | .sht = &amd_sht, |
584 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 584 | .flags = ATA_FLAG_SLAVE_POSS, |
585 | .pio_mask = 0x1f, | 585 | .pio_mask = 0x1f, |
586 | .mwdma_mask = 0x07, | 586 | .mwdma_mask = 0x07, |
587 | .udma_mask = 0x7f, /* UDMA 133, no swdma */ | 587 | .udma_mask = ATA_UDMA6, /* UDMA 133, no swdma */ |
588 | .port_ops = &amd133_port_ops | 588 | .port_ops = &amd133_port_ops |
589 | }, | 589 | }, |
590 | { /* 6: AMD 8111 UDMA 100 (Serenade) */ | 590 | { /* 6: AMD 8111 UDMA 100 (Serenade) */ |
591 | .sht = &amd_sht, | 591 | .sht = &amd_sht, |
592 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 592 | .flags = ATA_FLAG_SLAVE_POSS, |
593 | .pio_mask = 0x1f, | 593 | .pio_mask = 0x1f, |
594 | .mwdma_mask = 0x07, | 594 | .mwdma_mask = 0x07, |
595 | .udma_mask = 0x3f, /* UDMA 100, no swdma */ | 595 | .udma_mask = ATA_UDMA5, /* UDMA 100, no swdma */ |
596 | .port_ops = &amd133_port_ops | 596 | .port_ops = &amd133_port_ops |
597 | }, | 597 | }, |
598 | { /* 7: Nvidia Nforce */ | 598 | { /* 7: Nvidia Nforce */ |
599 | .sht = &amd_sht, | 599 | .sht = &amd_sht, |
600 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 600 | .flags = ATA_FLAG_SLAVE_POSS, |
601 | .pio_mask = 0x1f, | 601 | .pio_mask = 0x1f, |
602 | .mwdma_mask = 0x07, | 602 | .mwdma_mask = 0x07, |
603 | .udma_mask = 0x3f, /* UDMA 100 */ | 603 | .udma_mask = ATA_UDMA5, /* UDMA 100 */ |
604 | .port_ops = &nv100_port_ops | 604 | .port_ops = &nv100_port_ops |
605 | }, | 605 | }, |
606 | { /* 8: Nvidia Nforce2 and later */ | 606 | { /* 8: Nvidia Nforce2 and later */ |
607 | .sht = &amd_sht, | 607 | .sht = &amd_sht, |
608 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 608 | .flags = ATA_FLAG_SLAVE_POSS, |
609 | .pio_mask = 0x1f, | 609 | .pio_mask = 0x1f, |
610 | .mwdma_mask = 0x07, | 610 | .mwdma_mask = 0x07, |
611 | .udma_mask = 0x7f, /* UDMA 133, no swdma */ | 611 | .udma_mask = ATA_UDMA6, /* UDMA 133, no swdma */ |
612 | .port_ops = &nv133_port_ops | 612 | .port_ops = &nv133_port_ops |
613 | }, | 613 | }, |
614 | { /* 9: AMD CS5536 (Geode companion) */ | 614 | { /* 9: AMD CS5536 (Geode companion) */ |
615 | .sht = &amd_sht, | 615 | .sht = &amd_sht, |
616 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 616 | .flags = ATA_FLAG_SLAVE_POSS, |
617 | .pio_mask = 0x1f, | 617 | .pio_mask = 0x1f, |
618 | .mwdma_mask = 0x07, | 618 | .mwdma_mask = 0x07, |
619 | .udma_mask = 0x3f, /* UDMA 100 */ | 619 | .udma_mask = ATA_UDMA5, /* UDMA 100 */ |
620 | .port_ops = &amd100_port_ops | 620 | .port_ops = &amd100_port_ops |
621 | } | 621 | } |
622 | }; | 622 | }; |
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 03b6ddd2abd2..ce589d96ca42 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c | |||
@@ -416,7 +416,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) | |||
416 | static int printed_version; | 416 | static int printed_version; |
417 | static const struct ata_port_info info_6210 = { | 417 | static const struct ata_port_info info_6210 = { |
418 | .sht = &artop_sht, | 418 | .sht = &artop_sht, |
419 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 419 | .flags = ATA_FLAG_SLAVE_POSS, |
420 | .pio_mask = 0x1f, /* pio0-4 */ | 420 | .pio_mask = 0x1f, /* pio0-4 */ |
421 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 421 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
422 | .udma_mask = ATA_UDMA2, | 422 | .udma_mask = ATA_UDMA2, |
@@ -424,7 +424,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) | |||
424 | }; | 424 | }; |
425 | static const struct ata_port_info info_626x = { | 425 | static const struct ata_port_info info_626x = { |
426 | .sht = &artop_sht, | 426 | .sht = &artop_sht, |
427 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 427 | .flags = ATA_FLAG_SLAVE_POSS, |
428 | .pio_mask = 0x1f, /* pio0-4 */ | 428 | .pio_mask = 0x1f, /* pio0-4 */ |
429 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 429 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
430 | .udma_mask = ATA_UDMA4, | 430 | .udma_mask = ATA_UDMA4, |
@@ -432,7 +432,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) | |||
432 | }; | 432 | }; |
433 | static const struct ata_port_info info_626x_fast = { | 433 | static const struct ata_port_info info_626x_fast = { |
434 | .sht = &artop_sht, | 434 | .sht = &artop_sht, |
435 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 435 | .flags = ATA_FLAG_SLAVE_POSS, |
436 | .pio_mask = 0x1f, /* pio0-4 */ | 436 | .pio_mask = 0x1f, /* pio0-4 */ |
437 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 437 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
438 | .udma_mask = ATA_UDMA5, | 438 | .udma_mask = ATA_UDMA5, |
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 844914681a2a..80509be49e7a 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c | |||
@@ -270,7 +270,7 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
270 | { | 270 | { |
271 | static const struct ata_port_info info = { | 271 | static const struct ata_port_info info = { |
272 | .sht = &atiixp_sht, | 272 | .sht = &atiixp_sht, |
273 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 273 | .flags = ATA_FLAG_SLAVE_POSS, |
274 | .pio_mask = 0x1f, | 274 | .pio_mask = 0x1f, |
275 | .mwdma_mask = 0x06, /* No MWDMA0 support */ | 275 | .mwdma_mask = 0x06, /* No MWDMA0 support */ |
276 | .udma_mask = 0x3F, | 276 | .udma_mask = 0x3F, |
@@ -285,6 +285,7 @@ static const struct pci_device_id atiixp[] = { | |||
285 | { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), }, | 285 | { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), }, |
286 | { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), }, | 286 | { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), }, |
287 | { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), }, | 287 | { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), }, |
288 | { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), }, | ||
288 | 289 | ||
289 | { }, | 290 | { }, |
290 | }; | 291 | }; |
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 31cbf8daa299..0feb5ae8c486 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c | |||
@@ -251,7 +251,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
251 | { | 251 | { |
252 | static const struct ata_port_info info = { | 252 | static const struct ata_port_info info = { |
253 | .sht = &cmd640_sht, | 253 | .sht = &cmd640_sht, |
254 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 254 | .flags = ATA_FLAG_SLAVE_POSS, |
255 | .pio_mask = 0x1f, | 255 | .pio_mask = 0x1f, |
256 | .port_ops = &cmd640_port_ops | 256 | .port_ops = &cmd640_port_ops |
257 | }; | 257 | }; |
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 320a5b10aa98..dc443e7dc37c 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c | |||
@@ -380,21 +380,21 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
380 | static const struct ata_port_info cmd_info[6] = { | 380 | static const struct ata_port_info cmd_info[6] = { |
381 | { /* CMD 643 - no UDMA */ | 381 | { /* CMD 643 - no UDMA */ |
382 | .sht = &cmd64x_sht, | 382 | .sht = &cmd64x_sht, |
383 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 383 | .flags = ATA_FLAG_SLAVE_POSS, |
384 | .pio_mask = 0x1f, | 384 | .pio_mask = 0x1f, |
385 | .mwdma_mask = 0x07, | 385 | .mwdma_mask = 0x07, |
386 | .port_ops = &cmd64x_port_ops | 386 | .port_ops = &cmd64x_port_ops |
387 | }, | 387 | }, |
388 | { /* CMD 646 with broken UDMA */ | 388 | { /* CMD 646 with broken UDMA */ |
389 | .sht = &cmd64x_sht, | 389 | .sht = &cmd64x_sht, |
390 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 390 | .flags = ATA_FLAG_SLAVE_POSS, |
391 | .pio_mask = 0x1f, | 391 | .pio_mask = 0x1f, |
392 | .mwdma_mask = 0x07, | 392 | .mwdma_mask = 0x07, |
393 | .port_ops = &cmd64x_port_ops | 393 | .port_ops = &cmd64x_port_ops |
394 | }, | 394 | }, |
395 | { /* CMD 646 with working UDMA */ | 395 | { /* CMD 646 with working UDMA */ |
396 | .sht = &cmd64x_sht, | 396 | .sht = &cmd64x_sht, |
397 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 397 | .flags = ATA_FLAG_SLAVE_POSS, |
398 | .pio_mask = 0x1f, | 398 | .pio_mask = 0x1f, |
399 | .mwdma_mask = 0x07, | 399 | .mwdma_mask = 0x07, |
400 | .udma_mask = ATA_UDMA1, | 400 | .udma_mask = ATA_UDMA1, |
@@ -402,14 +402,14 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
402 | }, | 402 | }, |
403 | { /* CMD 646 rev 1 */ | 403 | { /* CMD 646 rev 1 */ |
404 | .sht = &cmd64x_sht, | 404 | .sht = &cmd64x_sht, |
405 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 405 | .flags = ATA_FLAG_SLAVE_POSS, |
406 | .pio_mask = 0x1f, | 406 | .pio_mask = 0x1f, |
407 | .mwdma_mask = 0x07, | 407 | .mwdma_mask = 0x07, |
408 | .port_ops = &cmd646r1_port_ops | 408 | .port_ops = &cmd646r1_port_ops |
409 | }, | 409 | }, |
410 | { /* CMD 648 */ | 410 | { /* CMD 648 */ |
411 | .sht = &cmd64x_sht, | 411 | .sht = &cmd64x_sht, |
412 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 412 | .flags = ATA_FLAG_SLAVE_POSS, |
413 | .pio_mask = 0x1f, | 413 | .pio_mask = 0x1f, |
414 | .mwdma_mask = 0x07, | 414 | .mwdma_mask = 0x07, |
415 | .udma_mask = ATA_UDMA2, | 415 | .udma_mask = ATA_UDMA2, |
@@ -417,7 +417,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
417 | }, | 417 | }, |
418 | { /* CMD 649 */ | 418 | { /* CMD 649 */ |
419 | .sht = &cmd64x_sht, | 419 | .sht = &cmd64x_sht, |
420 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 420 | .flags = ATA_FLAG_SLAVE_POSS, |
421 | .pio_mask = 0x1f, | 421 | .pio_mask = 0x1f, |
422 | .mwdma_mask = 0x07, | 422 | .mwdma_mask = 0x07, |
423 | .udma_mask = ATA_UDMA3, | 423 | .udma_mask = ATA_UDMA3, |
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 00cf0134079c..6bf037d82b5a 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c | |||
@@ -146,7 +146,7 @@ static struct scsi_host_template cs5520_sht = { | |||
146 | .queuecommand = ata_scsi_queuecmd, | 146 | .queuecommand = ata_scsi_queuecmd, |
147 | .can_queue = ATA_DEF_QUEUE, | 147 | .can_queue = ATA_DEF_QUEUE, |
148 | .this_id = ATA_SHT_THIS_ID, | 148 | .this_id = ATA_SHT_THIS_ID, |
149 | .sg_tablesize = LIBATA_MAX_PRD, | 149 | .sg_tablesize = LIBATA_DUMB_MAX_PRD, |
150 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | 150 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, |
151 | .emulated = ATA_SHT_EMULATED, | 151 | .emulated = ATA_SHT_EMULATED, |
152 | .use_clustering = ATA_SHT_USE_CLUSTERING, | 152 | .use_clustering = ATA_SHT_USE_CLUSTERING, |
@@ -178,7 +178,7 @@ static struct ata_port_operations cs5520_port_ops = { | |||
178 | .bmdma_start = ata_bmdma_start, | 178 | .bmdma_start = ata_bmdma_start, |
179 | .bmdma_stop = ata_bmdma_stop, | 179 | .bmdma_stop = ata_bmdma_stop, |
180 | .bmdma_status = ata_bmdma_status, | 180 | .bmdma_status = ata_bmdma_status, |
181 | .qc_prep = ata_qc_prep, | 181 | .qc_prep = ata_dumb_qc_prep, |
182 | .qc_issue = ata_qc_issue_prot, | 182 | .qc_issue = ata_qc_issue_prot, |
183 | .data_xfer = ata_data_xfer, | 183 | .data_xfer = ata_data_xfer, |
184 | 184 | ||
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 848f0309bf03..3fca5898642b 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c | |||
@@ -167,7 +167,7 @@ static struct scsi_host_template cs5530_sht = { | |||
167 | .queuecommand = ata_scsi_queuecmd, | 167 | .queuecommand = ata_scsi_queuecmd, |
168 | .can_queue = ATA_DEF_QUEUE, | 168 | .can_queue = ATA_DEF_QUEUE, |
169 | .this_id = ATA_SHT_THIS_ID, | 169 | .this_id = ATA_SHT_THIS_ID, |
170 | .sg_tablesize = LIBATA_MAX_PRD, | 170 | .sg_tablesize = LIBATA_DUMB_MAX_PRD, |
171 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | 171 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, |
172 | .emulated = ATA_SHT_EMULATED, | 172 | .emulated = ATA_SHT_EMULATED, |
173 | .use_clustering = ATA_SHT_USE_CLUSTERING, | 173 | .use_clustering = ATA_SHT_USE_CLUSTERING, |
@@ -201,7 +201,7 @@ static struct ata_port_operations cs5530_port_ops = { | |||
201 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | 201 | .post_internal_cmd = ata_bmdma_post_internal_cmd, |
202 | .cable_detect = ata_cable_40wire, | 202 | .cable_detect = ata_cable_40wire, |
203 | 203 | ||
204 | .qc_prep = ata_qc_prep, | 204 | .qc_prep = ata_dumb_qc_prep, |
205 | .qc_issue = cs5530_qc_issue_prot, | 205 | .qc_issue = cs5530_qc_issue_prot, |
206 | 206 | ||
207 | .data_xfer = ata_data_xfer, | 207 | .data_xfer = ata_data_xfer, |
@@ -337,7 +337,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
337 | { | 337 | { |
338 | static const struct ata_port_info info = { | 338 | static const struct ata_port_info info = { |
339 | .sht = &cs5530_sht, | 339 | .sht = &cs5530_sht, |
340 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 340 | .flags = ATA_FLAG_SLAVE_POSS, |
341 | .pio_mask = 0x1f, | 341 | .pio_mask = 0x1f, |
342 | .mwdma_mask = 0x07, | 342 | .mwdma_mask = 0x07, |
343 | .udma_mask = 0x07, | 343 | .udma_mask = 0x07, |
@@ -346,7 +346,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
346 | /* The docking connector doesn't do UDMA, and it seems not MWDMA */ | 346 | /* The docking connector doesn't do UDMA, and it seems not MWDMA */ |
347 | static const struct ata_port_info info_palmax_secondary = { | 347 | static const struct ata_port_info info_palmax_secondary = { |
348 | .sht = &cs5530_sht, | 348 | .sht = &cs5530_sht, |
349 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 349 | .flags = ATA_FLAG_SLAVE_POSS, |
350 | .pio_mask = 0x1f, | 350 | .pio_mask = 0x1f, |
351 | .port_ops = &cs5530_port_ops | 351 | .port_ops = &cs5530_port_ops |
352 | }; | 352 | }; |
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index aa3256fb9f7a..360b6f32e17e 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c | |||
@@ -225,10 +225,10 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
225 | { | 225 | { |
226 | static const struct ata_port_info info = { | 226 | static const struct ata_port_info info = { |
227 | .sht = &cs5535_sht, | 227 | .sht = &cs5535_sht, |
228 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 228 | .flags = ATA_FLAG_SLAVE_POSS, |
229 | .pio_mask = 0x1f, | 229 | .pio_mask = 0x1f, |
230 | .mwdma_mask = 0x07, | 230 | .mwdma_mask = 0x07, |
231 | .udma_mask = 0x1f, | 231 | .udma_mask = ATA_UDMA4, |
232 | .port_ops = &cs5535_port_ops | 232 | .port_ops = &cs5535_port_ops |
233 | }; | 233 | }; |
234 | const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; | 234 | const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; |
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index d41a7691dd8e..6cbc8778bf4f 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c | |||
@@ -167,7 +167,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i | |||
167 | { | 167 | { |
168 | static const struct ata_port_info info = { | 168 | static const struct ata_port_info info = { |
169 | .sht = &cy82c693_sht, | 169 | .sht = &cy82c693_sht, |
170 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 170 | .flags = ATA_FLAG_SLAVE_POSS, |
171 | .pio_mask = 0x1f, | 171 | .pio_mask = 0x1f, |
172 | .mwdma_mask = 0x07, | 172 | .mwdma_mask = 0x07, |
173 | .port_ops = &cy82c693_port_ops | 173 | .port_ops = &cy82c693_port_ops |
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 079248a9b460..c8ba59c56114 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c | |||
@@ -303,7 +303,7 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
303 | static int printed_version; | 303 | static int printed_version; |
304 | static const struct ata_port_info info = { | 304 | static const struct ata_port_info info = { |
305 | .sht = &efar_sht, | 305 | .sht = &efar_sht, |
306 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 306 | .flags = ATA_FLAG_SLAVE_POSS, |
307 | .pio_mask = 0x1f, /* pio0-4 */ | 307 | .pio_mask = 0x1f, /* pio0-4 */ |
308 | .mwdma_mask = 0x07, /* mwdma1-2 */ | 308 | .mwdma_mask = 0x07, /* mwdma1-2 */ |
309 | .udma_mask = 0x0f, /* UDMA 66 */ | 309 | .udma_mask = 0x0f, /* UDMA 66 */ |
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 0c9cb6090711..6f7d34ad19ef 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c | |||
@@ -393,10 +393,10 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
393 | { | 393 | { |
394 | static const struct ata_port_info info_hpt366 = { | 394 | static const struct ata_port_info info_hpt366 = { |
395 | .sht = &hpt36x_sht, | 395 | .sht = &hpt36x_sht, |
396 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 396 | .flags = ATA_FLAG_SLAVE_POSS, |
397 | .pio_mask = 0x1f, | 397 | .pio_mask = 0x1f, |
398 | .mwdma_mask = 0x07, | 398 | .mwdma_mask = 0x07, |
399 | .udma_mask = 0x1f, | 399 | .udma_mask = ATA_UDMA4, |
400 | .port_ops = &hpt366_port_ops | 400 | .port_ops = &hpt366_port_ops |
401 | }; | 401 | }; |
402 | struct ata_port_info info = info_hpt366; | 402 | struct ata_port_info info = info_hpt366; |
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index a8c0cbeca399..b0af65aadde3 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c | |||
@@ -889,25 +889,25 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
889 | /* HPT370 - UDMA100 */ | 889 | /* HPT370 - UDMA100 */ |
890 | static const struct ata_port_info info_hpt370 = { | 890 | static const struct ata_port_info info_hpt370 = { |
891 | .sht = &hpt37x_sht, | 891 | .sht = &hpt37x_sht, |
892 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 892 | .flags = ATA_FLAG_SLAVE_POSS, |
893 | .pio_mask = 0x1f, | 893 | .pio_mask = 0x1f, |
894 | .mwdma_mask = 0x07, | 894 | .mwdma_mask = 0x07, |
895 | .udma_mask = 0x3f, | 895 | .udma_mask = ATA_UDMA5, |
896 | .port_ops = &hpt370_port_ops | 896 | .port_ops = &hpt370_port_ops |
897 | }; | 897 | }; |
898 | /* HPT370A - UDMA100 */ | 898 | /* HPT370A - UDMA100 */ |
899 | static const struct ata_port_info info_hpt370a = { | 899 | static const struct ata_port_info info_hpt370a = { |
900 | .sht = &hpt37x_sht, | 900 | .sht = &hpt37x_sht, |
901 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 901 | .flags = ATA_FLAG_SLAVE_POSS, |
902 | .pio_mask = 0x1f, | 902 | .pio_mask = 0x1f, |
903 | .mwdma_mask = 0x07, | 903 | .mwdma_mask = 0x07, |
904 | .udma_mask = 0x3f, | 904 | .udma_mask = ATA_UDMA5, |
905 | .port_ops = &hpt370a_port_ops | 905 | .port_ops = &hpt370a_port_ops |
906 | }; | 906 | }; |
907 | /* HPT370 - UDMA100 */ | 907 | /* HPT370 - UDMA100 */ |
908 | static const struct ata_port_info info_hpt370_33 = { | 908 | static const struct ata_port_info info_hpt370_33 = { |
909 | .sht = &hpt37x_sht, | 909 | .sht = &hpt37x_sht, |
910 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 910 | .flags = ATA_FLAG_SLAVE_POSS, |
911 | .pio_mask = 0x1f, | 911 | .pio_mask = 0x1f, |
912 | .mwdma_mask = 0x07, | 912 | .mwdma_mask = 0x07, |
913 | .udma_mask = 0x0f, | 913 | .udma_mask = 0x0f, |
@@ -916,7 +916,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
916 | /* HPT370A - UDMA100 */ | 916 | /* HPT370A - UDMA100 */ |
917 | static const struct ata_port_info info_hpt370a_33 = { | 917 | static const struct ata_port_info info_hpt370a_33 = { |
918 | .sht = &hpt37x_sht, | 918 | .sht = &hpt37x_sht, |
919 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 919 | .flags = ATA_FLAG_SLAVE_POSS, |
920 | .pio_mask = 0x1f, | 920 | .pio_mask = 0x1f, |
921 | .mwdma_mask = 0x07, | 921 | .mwdma_mask = 0x07, |
922 | .udma_mask = 0x0f, | 922 | .udma_mask = 0x0f, |
@@ -925,19 +925,19 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
925 | /* HPT371, 372 and friends - UDMA133 */ | 925 | /* HPT371, 372 and friends - UDMA133 */ |
926 | static const struct ata_port_info info_hpt372 = { | 926 | static const struct ata_port_info info_hpt372 = { |
927 | .sht = &hpt37x_sht, | 927 | .sht = &hpt37x_sht, |
928 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 928 | .flags = ATA_FLAG_SLAVE_POSS, |
929 | .pio_mask = 0x1f, | 929 | .pio_mask = 0x1f, |
930 | .mwdma_mask = 0x07, | 930 | .mwdma_mask = 0x07, |
931 | .udma_mask = 0x7f, | 931 | .udma_mask = ATA_UDMA6, |
932 | .port_ops = &hpt372_port_ops | 932 | .port_ops = &hpt372_port_ops |
933 | }; | 933 | }; |
934 | /* HPT374 - UDMA100 */ | 934 | /* HPT374 - UDMA100 */ |
935 | static const struct ata_port_info info_hpt374 = { | 935 | static const struct ata_port_info info_hpt374 = { |
936 | .sht = &hpt37x_sht, | 936 | .sht = &hpt37x_sht, |
937 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 937 | .flags = ATA_FLAG_SLAVE_POSS, |
938 | .pio_mask = 0x1f, | 938 | .pio_mask = 0x1f, |
939 | .mwdma_mask = 0x07, | 939 | .mwdma_mask = 0x07, |
940 | .udma_mask = 0x3f, | 940 | .udma_mask = ATA_UDMA5, |
941 | .port_ops = &hpt374_port_ops | 941 | .port_ops = &hpt374_port_ops |
942 | }; | 942 | }; |
943 | 943 | ||
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index e947433cb37d..aa29cde09f8b 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c | |||
@@ -490,10 +490,10 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
490 | /* HPT372N and friends - UDMA133 */ | 490 | /* HPT372N and friends - UDMA133 */ |
491 | static const struct ata_port_info info = { | 491 | static const struct ata_port_info info = { |
492 | .sht = &hpt3x2n_sht, | 492 | .sht = &hpt3x2n_sht, |
493 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 493 | .flags = ATA_FLAG_SLAVE_POSS, |
494 | .pio_mask = 0x1f, | 494 | .pio_mask = 0x1f, |
495 | .mwdma_mask = 0x07, | 495 | .mwdma_mask = 0x07, |
496 | .udma_mask = 0x7f, | 496 | .udma_mask = ATA_UDMA6, |
497 | .port_ops = &hpt3x2n_port_ops | 497 | .port_ops = &hpt3x2n_port_ops |
498 | }; | 498 | }; |
499 | struct ata_port_info port = info; | 499 | struct ata_port_info port = info; |
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 8ce5e23a5f75..d928c9105034 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c | |||
@@ -173,7 +173,7 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
173 | { | 173 | { |
174 | static const struct ata_port_info info = { | 174 | static const struct ata_port_info info = { |
175 | .sht = &hpt3x3_sht, | 175 | .sht = &hpt3x3_sht, |
176 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 176 | .flags = ATA_FLAG_SLAVE_POSS, |
177 | .pio_mask = 0x1f, | 177 | .pio_mask = 0x1f, |
178 | .mwdma_mask = 0x07, | 178 | .mwdma_mask = 0x07, |
179 | .udma_mask = 0x07, | 179 | .udma_mask = 0x07, |
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index c791a46df461..321d98b0bed2 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c | |||
@@ -530,7 +530,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info) | |||
530 | 530 | ||
531 | ap->pio_mask = 0x1f; | 531 | ap->pio_mask = 0x1f; |
532 | ap->mwdma_mask = info->mwdma_mask; | 532 | ap->mwdma_mask = info->mwdma_mask; |
533 | ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; | 533 | ap->flags |= ATA_FLAG_SLAVE_POSS; |
534 | ap->ops = &pata_icside_port_ops; | 534 | ap->ops = &pata_icside_port_ops; |
535 | 535 | ||
536 | pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]); | 536 | pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]); |
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 95b0bb61788b..b8af55e89156 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c | |||
@@ -313,10 +313,10 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en | |||
313 | static int printed_version; | 313 | static int printed_version; |
314 | static const struct ata_port_info info = { | 314 | static const struct ata_port_info info = { |
315 | .sht = &it8213_sht, | 315 | .sht = &it8213_sht, |
316 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 316 | .flags = ATA_FLAG_SLAVE_POSS, |
317 | .pio_mask = 0x1f, /* pio0-4 */ | 317 | .pio_mask = 0x1f, /* pio0-4 */ |
318 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 318 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
319 | .udma_mask = 0x1f, /* UDMA 100 */ | 319 | .udma_mask = ATA_UDMA4, /* FIXME: want UDMA 100? */ |
320 | .port_ops = &it8213_ops, | 320 | .port_ops = &it8213_ops, |
321 | }; | 321 | }; |
322 | /* Current IT8213 stuff is single port */ | 322 | /* Current IT8213 stuff is single port */ |
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 12c6e08cc4d1..b67bbf6516ba 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c | |||
@@ -714,17 +714,17 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
714 | 714 | ||
715 | static const struct ata_port_info info_smart = { | 715 | static const struct ata_port_info info_smart = { |
716 | .sht = &it821x_sht, | 716 | .sht = &it821x_sht, |
717 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 717 | .flags = ATA_FLAG_SLAVE_POSS, |
718 | .pio_mask = 0x1f, | 718 | .pio_mask = 0x1f, |
719 | .mwdma_mask = 0x07, | 719 | .mwdma_mask = 0x07, |
720 | .port_ops = &it821x_smart_port_ops | 720 | .port_ops = &it821x_smart_port_ops |
721 | }; | 721 | }; |
722 | static const struct ata_port_info info_passthru = { | 722 | static const struct ata_port_info info_passthru = { |
723 | .sht = &it821x_sht, | 723 | .sht = &it821x_sht, |
724 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 724 | .flags = ATA_FLAG_SLAVE_POSS, |
725 | .pio_mask = 0x1f, | 725 | .pio_mask = 0x1f, |
726 | .mwdma_mask = 0x07, | 726 | .mwdma_mask = 0x07, |
727 | .udma_mask = 0x7f, | 727 | .udma_mask = ATA_UDMA6, |
728 | .port_ops = &it821x_passthru_port_ops | 728 | .port_ops = &it821x_passthru_port_ops |
729 | }; | 729 | }; |
730 | 730 | ||
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 8d2bc1e9e871..4ca7fd6118d5 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c | |||
@@ -1,13 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * ixp4xx PATA/Compact Flash driver | 2 | * ixp4xx PATA/Compact Flash driver |
3 | * Copyright (c) 2006 Tower Technologies | 3 | * Copyright (C) 2006-07 Tower Technologies |
4 | * Author: Alessandro Zummo <a.zummo@towertech.it> | 4 | * Author: Alessandro Zummo <a.zummo@towertech.it> |
5 | * | 5 | * |
6 | * An ATA driver to handle a Compact Flash connected | 6 | * An ATA driver to handle a Compact Flash connected |
7 | * to the ixp4xx expansion bus in TrueIDE mode. The CF | 7 | * to the ixp4xx expansion bus in TrueIDE mode. The CF |
8 | * must have it chip selects connected to two CS lines | 8 | * must have it chip selects connected to two CS lines |
9 | * on the ixp4xx. The interrupt line is optional, if not | 9 | * on the ixp4xx. In the irq is not available, you might |
10 | * specified the driver will run in polling mode. | 10 | * want to modify both this driver and libata to run in |
11 | * polling mode. | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
@@ -23,7 +24,7 @@ | |||
23 | #include <scsi/scsi_host.h> | 24 | #include <scsi/scsi_host.h> |
24 | 25 | ||
25 | #define DRV_NAME "pata_ixp4xx_cf" | 26 | #define DRV_NAME "pata_ixp4xx_cf" |
26 | #define DRV_VERSION "0.1.3" | 27 | #define DRV_VERSION "0.2" |
27 | 28 | ||
28 | static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) | 29 | static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) |
29 | { | 30 | { |
@@ -42,13 +43,6 @@ static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) | |||
42 | return 0; | 43 | return 0; |
43 | } | 44 | } |
44 | 45 | ||
45 | static void ixp4xx_phy_reset(struct ata_port *ap) | ||
46 | { | ||
47 | ap->cbl = ATA_CBL_PATA40; | ||
48 | ata_port_probe(ap); | ||
49 | ata_bus_reset(ap); | ||
50 | } | ||
51 | |||
52 | static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, | 46 | static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, |
53 | unsigned int buflen, int write_data) | 47 | unsigned int buflen, int write_data) |
54 | { | 48 | { |
@@ -56,7 +50,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, | |||
56 | unsigned int words = buflen >> 1; | 50 | unsigned int words = buflen >> 1; |
57 | u16 *buf16 = (u16 *) buf; | 51 | u16 *buf16 = (u16 *) buf; |
58 | struct ata_port *ap = adev->ap; | 52 | struct ata_port *ap = adev->ap; |
59 | void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; | 53 | void __iomem *mmio = ap->ioaddr.data_addr; |
60 | struct ixp4xx_pata_data *data = ap->host->dev->platform_data; | 54 | struct ixp4xx_pata_data *data = ap->host->dev->platform_data; |
61 | 55 | ||
62 | /* set the expansion bus in 16bit mode and restore | 56 | /* set the expansion bus in 16bit mode and restore |
@@ -92,10 +86,6 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, | |||
92 | *data->cs0_cfg |= 0x01; | 86 | *data->cs0_cfg |= 0x01; |
93 | } | 87 | } |
94 | 88 | ||
95 | static void ixp4xx_irq_clear(struct ata_port *ap) | ||
96 | { | ||
97 | } | ||
98 | |||
99 | static struct scsi_host_template ixp4xx_sht = { | 89 | static struct scsi_host_template ixp4xx_sht = { |
100 | .module = THIS_MODULE, | 90 | .module = THIS_MODULE, |
101 | .name = DRV_NAME, | 91 | .name = DRV_NAME, |
@@ -115,29 +105,32 @@ static struct scsi_host_template ixp4xx_sht = { | |||
115 | }; | 105 | }; |
116 | 106 | ||
117 | static struct ata_port_operations ixp4xx_port_ops = { | 107 | static struct ata_port_operations ixp4xx_port_ops = { |
118 | .set_mode = ixp4xx_set_mode, | 108 | .set_mode = ixp4xx_set_mode, |
119 | .mode_filter = ata_pci_default_filter, | 109 | .mode_filter = ata_pci_default_filter, |
120 | 110 | ||
121 | .port_disable = ata_port_disable, | 111 | .port_disable = ata_port_disable, |
122 | .tf_load = ata_tf_load, | 112 | .tf_load = ata_tf_load, |
123 | .tf_read = ata_tf_read, | 113 | .tf_read = ata_tf_read, |
124 | .check_status = ata_check_status, | 114 | .exec_command = ata_exec_command, |
125 | .exec_command = ata_exec_command, | 115 | .check_status = ata_check_status, |
126 | .dev_select = ata_std_dev_select, | 116 | .dev_select = ata_std_dev_select, |
127 | 117 | ||
128 | .qc_prep = ata_qc_prep, | 118 | .freeze = ata_bmdma_freeze, |
129 | .qc_issue = ata_qc_issue_prot, | 119 | .thaw = ata_bmdma_thaw, |
130 | .eng_timeout = ata_eng_timeout, | 120 | .error_handler = ata_bmdma_error_handler, |
131 | .data_xfer = ixp4xx_mmio_data_xfer, | 121 | .post_internal_cmd = ata_bmdma_post_internal_cmd, |
132 | .cable_detect = ata_cable_40wire, | 122 | |
133 | 123 | .qc_prep = ata_qc_prep, | |
134 | .irq_clear = ixp4xx_irq_clear, | 124 | .qc_issue = ata_qc_issue_prot, |
135 | .irq_on = ata_irq_on, | 125 | .data_xfer = ixp4xx_mmio_data_xfer, |
136 | .irq_ack = ata_irq_ack, | 126 | .cable_detect = ata_cable_40wire, |
137 | 127 | ||
138 | .port_start = ata_port_start, | 128 | .irq_handler = ata_interrupt, |
139 | 129 | .irq_clear = ata_bmdma_irq_clear, | |
140 | .phy_reset = ixp4xx_phy_reset, | 130 | .irq_on = ata_irq_on, |
131 | .irq_ack = ata_dummy_irq_ack, | ||
132 | |||
133 | .port_start = ata_port_start, | ||
141 | }; | 134 | }; |
142 | 135 | ||
143 | static void ixp4xx_setup_port(struct ata_ioports *ioaddr, | 136 | static void ixp4xx_setup_port(struct ata_ioports *ioaddr, |
@@ -178,7 +171,6 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) | |||
178 | struct ata_host *host; | 171 | struct ata_host *host; |
179 | struct ata_port *ap; | 172 | struct ata_port *ap; |
180 | struct ixp4xx_pata_data *data = pdev->dev.platform_data; | 173 | struct ixp4xx_pata_data *data = pdev->dev.platform_data; |
181 | int rc; | ||
182 | 174 | ||
183 | cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 175 | cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
184 | cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 176 | cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
@@ -211,10 +203,6 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) | |||
211 | ap->pio_mask = 0x1f; /* PIO4 */ | 203 | ap->pio_mask = 0x1f; /* PIO4 */ |
212 | ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI; | 204 | ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI; |
213 | 205 | ||
214 | /* run in polling mode if no irq has been assigned */ | ||
215 | if (!irq) | ||
216 | ap->flags |= ATA_FLAG_PIO_POLLING; | ||
217 | |||
218 | ixp4xx_setup_port(&ap->ioaddr, data); | 206 | ixp4xx_setup_port(&ap->ioaddr, data); |
219 | 207 | ||
220 | dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); | 208 | dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); |
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 2af7ff8256ca..4d67f238eee2 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c | |||
@@ -193,11 +193,11 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i | |||
193 | { | 193 | { |
194 | static const struct ata_port_info info = { | 194 | static const struct ata_port_info info = { |
195 | .sht = &jmicron_sht, | 195 | .sht = &jmicron_sht, |
196 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 196 | .flags = ATA_FLAG_SLAVE_POSS, |
197 | 197 | ||
198 | .pio_mask = 0x1f, | 198 | .pio_mask = 0x1f, |
199 | .mwdma_mask = 0x07, | 199 | .mwdma_mask = 0x07, |
200 | .udma_mask = 0x3f, | 200 | .udma_mask = ATA_UDMA5, |
201 | 201 | ||
202 | .port_ops = &jmicron_ops, | 202 | .port_ops = &jmicron_ops, |
203 | }; | 203 | }; |
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index edbfe0dbbf78..87594c04d3a3 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c | |||
@@ -163,22 +163,22 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i | |||
163 | { | 163 | { |
164 | static const struct ata_port_info info = { | 164 | static const struct ata_port_info info = { |
165 | .sht = &marvell_sht, | 165 | .sht = &marvell_sht, |
166 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 166 | .flags = ATA_FLAG_SLAVE_POSS, |
167 | 167 | ||
168 | .pio_mask = 0x1f, | 168 | .pio_mask = 0x1f, |
169 | .mwdma_mask = 0x07, | 169 | .mwdma_mask = 0x07, |
170 | .udma_mask = 0x3f, | 170 | .udma_mask = ATA_UDMA5, |
171 | 171 | ||
172 | .port_ops = &marvell_ops, | 172 | .port_ops = &marvell_ops, |
173 | }; | 173 | }; |
174 | static const struct ata_port_info info_sata = { | 174 | static const struct ata_port_info info_sata = { |
175 | .sht = &marvell_sht, | 175 | .sht = &marvell_sht, |
176 | /* Slave possible as its magically mapped not real */ | 176 | /* Slave possible as its magically mapped not real */ |
177 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 177 | .flags = ATA_FLAG_SLAVE_POSS, |
178 | 178 | ||
179 | .pio_mask = 0x1f, | 179 | .pio_mask = 0x1f, |
180 | .mwdma_mask = 0x07, | 180 | .mwdma_mask = 0x07, |
181 | .udma_mask = 0x7f, | 181 | .udma_mask = ATA_UDMA6, |
182 | 182 | ||
183 | .port_ops = &marvell_ops, | 183 | .port_ops = &marvell_ops, |
184 | }; | 184 | }; |
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 81f563458666..40eb574828bf 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c | |||
@@ -94,12 +94,12 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e | |||
94 | static int printed_version; | 94 | static int printed_version; |
95 | static const struct ata_port_info info = { | 95 | static const struct ata_port_info info = { |
96 | .sht = &netcell_sht, | 96 | .sht = &netcell_sht, |
97 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 97 | .flags = ATA_FLAG_SLAVE_POSS, |
98 | /* Actually we don't really care about these as the | 98 | /* Actually we don't really care about these as the |
99 | firmware deals with it */ | 99 | firmware deals with it */ |
100 | .pio_mask = 0x1f, /* pio0-4 */ | 100 | .pio_mask = 0x1f, /* pio0-4 */ |
101 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 101 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
102 | .udma_mask = 0x3f, /* UDMA 133 */ | 102 | .udma_mask = ATA_UDMA5, /* UDMA 133 */ |
103 | .port_ops = &netcell_ops, | 103 | .port_ops = &netcell_ops, |
104 | }; | 104 | }; |
105 | const struct ata_port_info *port_info[] = { &info, NULL }; | 105 | const struct ata_port_info *port_info[] = { &info, NULL }; |
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index ea70ec744879..2f5d714ebfc4 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c | |||
@@ -193,7 +193,7 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
193 | { | 193 | { |
194 | static const struct ata_port_info info = { | 194 | static const struct ata_port_info info = { |
195 | .sht = &ns87410_sht, | 195 | .sht = &ns87410_sht, |
196 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 196 | .flags = ATA_FLAG_SLAVE_POSS, |
197 | .pio_mask = 0x0F, | 197 | .pio_mask = 0x0F, |
198 | .port_ops = &ns87410_port_ops | 198 | .port_ops = &ns87410_port_ops |
199 | }; | 199 | }; |
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 29c23ddd6550..091a70a0ef1c 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c | |||
@@ -291,7 +291,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e | |||
291 | static int printed_version; | 291 | static int printed_version; |
292 | static const struct ata_port_info info = { | 292 | static const struct ata_port_info info = { |
293 | .sht = &oldpiix_sht, | 293 | .sht = &oldpiix_sht, |
294 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 294 | .flags = ATA_FLAG_SLAVE_POSS, |
295 | .pio_mask = 0x1f, /* pio0-4 */ | 295 | .pio_mask = 0x1f, /* pio0-4 */ |
296 | .mwdma_mask = 0x07, /* mwdma1-2 */ | 296 | .mwdma_mask = 0x07, /* mwdma1-2 */ |
297 | .port_ops = &oldpiix_pata_ops, | 297 | .port_ops = &oldpiix_pata_ops, |
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 1c44653e1e06..458bf67f766f 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c | |||
@@ -218,7 +218,7 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
218 | { | 218 | { |
219 | static const struct ata_port_info info = { | 219 | static const struct ata_port_info info = { |
220 | .sht = &opti_sht, | 220 | .sht = &opti_sht, |
221 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 221 | .flags = ATA_FLAG_SLAVE_POSS, |
222 | .pio_mask = 0x1f, | 222 | .pio_mask = 0x1f, |
223 | .port_ops = &opti_port_ops | 223 | .port_ops = &opti_port_ops |
224 | }; | 224 | }; |
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 3093b02286ce..f89bdfde16d0 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c | |||
@@ -484,14 +484,14 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
484 | { | 484 | { |
485 | static const struct ata_port_info info_82c700 = { | 485 | static const struct ata_port_info info_82c700 = { |
486 | .sht = &optidma_sht, | 486 | .sht = &optidma_sht, |
487 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 487 | .flags = ATA_FLAG_SLAVE_POSS, |
488 | .pio_mask = 0x1f, | 488 | .pio_mask = 0x1f, |
489 | .mwdma_mask = 0x07, | 489 | .mwdma_mask = 0x07, |
490 | .port_ops = &optidma_port_ops | 490 | .port_ops = &optidma_port_ops |
491 | }; | 491 | }; |
492 | static const struct ata_port_info info_82c700_udma = { | 492 | static const struct ata_port_info info_82c700_udma = { |
493 | .sht = &optidma_sht, | 493 | .sht = &optidma_sht, |
494 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 494 | .flags = ATA_FLAG_SLAVE_POSS, |
495 | .pio_mask = 0x1f, | 495 | .pio_mask = 0x1f, |
496 | .mwdma_mask = 0x07, | 496 | .mwdma_mask = 0x07, |
497 | .udma_mask = 0x07, | 497 | .udma_mask = 0x07, |
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index d277246b7337..92447bed5e77 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c | |||
@@ -320,7 +320,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id | |||
320 | static const struct ata_port_info info[3] = { | 320 | static const struct ata_port_info info[3] = { |
321 | { | 321 | { |
322 | .sht = &pdc202xx_sht, | 322 | .sht = &pdc202xx_sht, |
323 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 323 | .flags = ATA_FLAG_SLAVE_POSS, |
324 | .pio_mask = 0x1f, | 324 | .pio_mask = 0x1f, |
325 | .mwdma_mask = 0x07, | 325 | .mwdma_mask = 0x07, |
326 | .udma_mask = ATA_UDMA2, | 326 | .udma_mask = ATA_UDMA2, |
@@ -328,7 +328,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id | |||
328 | }, | 328 | }, |
329 | { | 329 | { |
330 | .sht = &pdc202xx_sht, | 330 | .sht = &pdc202xx_sht, |
331 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 331 | .flags = ATA_FLAG_SLAVE_POSS, |
332 | .pio_mask = 0x1f, | 332 | .pio_mask = 0x1f, |
333 | .mwdma_mask = 0x07, | 333 | .mwdma_mask = 0x07, |
334 | .udma_mask = ATA_UDMA4, | 334 | .udma_mask = ATA_UDMA4, |
@@ -336,7 +336,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id | |||
336 | }, | 336 | }, |
337 | { | 337 | { |
338 | .sht = &pdc202xx_sht, | 338 | .sht = &pdc202xx_sht, |
339 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 339 | .flags = ATA_FLAG_SLAVE_POSS, |
340 | .pio_mask = 0x1f, | 340 | .pio_mask = 0x1f, |
341 | .mwdma_mask = 0x07, | 341 | .mwdma_mask = 0x07, |
342 | .udma_mask = ATA_UDMA5, | 342 | .udma_mask = ATA_UDMA5, |
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index cbb7866940d6..79f841bca593 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c | |||
@@ -139,6 +139,7 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) | |||
139 | struct resource *io_res, *ctl_res; | 139 | struct resource *io_res, *ctl_res; |
140 | struct ata_host *host; | 140 | struct ata_host *host; |
141 | struct ata_port *ap; | 141 | struct ata_port *ap; |
142 | struct pata_platform_info *pp_info; | ||
142 | unsigned int mmio; | 143 | unsigned int mmio; |
143 | 144 | ||
144 | /* | 145 | /* |
@@ -208,11 +209,12 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) | |||
208 | 209 | ||
209 | ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; | 210 | ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; |
210 | 211 | ||
211 | pata_platform_setup_port(&ap->ioaddr, pdev->dev.platform_data); | 212 | pp_info = (struct pata_platform_info *)(pdev->dev.platform_data); |
213 | pata_platform_setup_port(&ap->ioaddr, pp_info); | ||
212 | 214 | ||
213 | /* activate */ | 215 | /* activate */ |
214 | return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, | 216 | return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, |
215 | 0, &pata_platform_sht); | 217 | pp_info->irq_flags, &pata_platform_sht); |
216 | } | 218 | } |
217 | 219 | ||
218 | /** | 220 | /** |
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index ba96b54f5b87..7d1aabed422d 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c | |||
@@ -257,7 +257,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e | |||
257 | static int printed_version; | 257 | static int printed_version; |
258 | static const struct ata_port_info info = { | 258 | static const struct ata_port_info info = { |
259 | .sht = &radisys_sht, | 259 | .sht = &radisys_sht, |
260 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 260 | .flags = ATA_FLAG_SLAVE_POSS, |
261 | .pio_mask = 0x1f, /* pio0-4 */ | 261 | .pio_mask = 0x1f, /* pio0-4 */ |
262 | .mwdma_mask = 0x07, /* mwdma1-2 */ | 262 | .mwdma_mask = 0x07, /* mwdma1-2 */ |
263 | .udma_mask = 0x14, /* UDMA33/66 only */ | 263 | .udma_mask = 0x14, /* UDMA33/66 only */ |
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index a3488b41ad26..7632fcb070ca 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c | |||
@@ -133,7 +133,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en | |||
133 | static int printed_version; | 133 | static int printed_version; |
134 | static const struct ata_port_info info = { | 134 | static const struct ata_port_info info = { |
135 | .sht = &rz1000_sht, | 135 | .sht = &rz1000_sht, |
136 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 136 | .flags = ATA_FLAG_SLAVE_POSS, |
137 | .pio_mask = 0x1f, | 137 | .pio_mask = 0x1f, |
138 | .port_ops = &rz1000_port_ops | 138 | .port_ops = &rz1000_port_ops |
139 | }; | 139 | }; |
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 1233063ab9a8..b8b2d11e4180 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c | |||
@@ -185,7 +185,7 @@ static struct scsi_host_template sc1200_sht = { | |||
185 | .queuecommand = ata_scsi_queuecmd, | 185 | .queuecommand = ata_scsi_queuecmd, |
186 | .can_queue = ATA_DEF_QUEUE, | 186 | .can_queue = ATA_DEF_QUEUE, |
187 | .this_id = ATA_SHT_THIS_ID, | 187 | .this_id = ATA_SHT_THIS_ID, |
188 | .sg_tablesize = LIBATA_MAX_PRD, | 188 | .sg_tablesize = LIBATA_DUMB_MAX_PRD, |
189 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | 189 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, |
190 | .emulated = ATA_SHT_EMULATED, | 190 | .emulated = ATA_SHT_EMULATED, |
191 | .use_clustering = ATA_SHT_USE_CLUSTERING, | 191 | .use_clustering = ATA_SHT_USE_CLUSTERING, |
@@ -219,7 +219,7 @@ static struct ata_port_operations sc1200_port_ops = { | |||
219 | .bmdma_stop = ata_bmdma_stop, | 219 | .bmdma_stop = ata_bmdma_stop, |
220 | .bmdma_status = ata_bmdma_status, | 220 | .bmdma_status = ata_bmdma_status, |
221 | 221 | ||
222 | .qc_prep = ata_qc_prep, | 222 | .qc_prep = ata_dumb_qc_prep, |
223 | .qc_issue = sc1200_qc_issue_prot, | 223 | .qc_issue = sc1200_qc_issue_prot, |
224 | 224 | ||
225 | .data_xfer = ata_data_xfer, | 225 | .data_xfer = ata_data_xfer, |
@@ -245,7 +245,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
245 | { | 245 | { |
246 | static const struct ata_port_info info = { | 246 | static const struct ata_port_info info = { |
247 | .sht = &sc1200_sht, | 247 | .sht = &sc1200_sht, |
248 | .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, | 248 | .flags = ATA_FLAG_SLAVE_POSS, |
249 | .pio_mask = 0x1f, | 249 | .pio_mask = 0x1f, |
250 | .mwdma_mask = 0x07, | 250 | .mwdma_mask = 0x07, |
251 | .udma_mask = 0x07, | 251 | .udma_mask = 0x07, |
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 1e8f421963c7..0231aba51ca4 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c | |||
@@ -478,31 +478,31 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id | |||
478 | static const struct ata_port_info info[4] = { | 478 | static const struct ata_port_info info[4] = { |
479 | { /* OSB4 */ | 479 | { /* OSB4 */ |
480 | .sht = &serverworks_sht, | 480 | .sht = &serverworks_sht, |
481 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 481 | .flags = ATA_FLAG_SLAVE_POSS, |
482 | .pio_mask = 0x1f, | 482 | .pio_mask = 0x1f, |
483 | .mwdma_mask = 0x07, | 483 | .mwdma_mask = 0x07, |
484 | .udma_mask = 0x07, | 484 | .udma_mask = 0x07, |
485 | .port_ops = &serverworks_osb4_port_ops | 485 | .port_ops = &serverworks_osb4_port_ops |
486 | }, { /* OSB4 no UDMA */ | 486 | }, { /* OSB4 no UDMA */ |
487 | .sht = &serverworks_sht, | 487 | .sht = &serverworks_sht, |
488 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 488 | .flags = ATA_FLAG_SLAVE_POSS, |
489 | .pio_mask = 0x1f, | 489 | .pio_mask = 0x1f, |
490 | .mwdma_mask = 0x07, | 490 | .mwdma_mask = 0x07, |
491 | .udma_mask = 0x00, | 491 | .udma_mask = 0x00, |
492 | .port_ops = &serverworks_osb4_port_ops | 492 | .port_ops = &serverworks_osb4_port_ops |
493 | }, { /* CSB5 */ | 493 | }, { /* CSB5 */ |
494 | .sht = &serverworks_sht, | 494 | .sht = &serverworks_sht, |
495 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 495 | .flags = ATA_FLAG_SLAVE_POSS, |
496 | .pio_mask = 0x1f, | 496 | .pio_mask = 0x1f, |
497 | .mwdma_mask = 0x07, | 497 | .mwdma_mask = 0x07, |
498 | .udma_mask = 0x1f, | 498 | .udma_mask = ATA_UDMA4, |
499 | .port_ops = &serverworks_csb_port_ops | 499 | .port_ops = &serverworks_csb_port_ops |
500 | }, { /* CSB5 - later revisions*/ | 500 | }, { /* CSB5 - later revisions*/ |
501 | .sht = &serverworks_sht, | 501 | .sht = &serverworks_sht, |
502 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 502 | .flags = ATA_FLAG_SLAVE_POSS, |
503 | .pio_mask = 0x1f, | 503 | .pio_mask = 0x1f, |
504 | .mwdma_mask = 0x07, | 504 | .mwdma_mask = 0x07, |
505 | .udma_mask = 0x3f, | 505 | .udma_mask = ATA_UDMA5, |
506 | .port_ops = &serverworks_csb_port_ops | 506 | .port_ops = &serverworks_csb_port_ops |
507 | } | 507 | } |
508 | }; | 508 | }; |
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 440e2cb6ee75..b0cd52d6e3fb 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #define DRV_NAME "pata_sil680" | 35 | #define DRV_NAME "pata_sil680" |
36 | #define DRV_VERSION "0.4.6" | 36 | #define DRV_VERSION "0.4.6" |
37 | 37 | ||
38 | #define SIL680_MMIO_BAR 5 | ||
39 | |||
38 | /** | 40 | /** |
39 | * sil680_selreg - return register base | 41 | * sil680_selreg - return register base |
40 | * @hwif: interface | 42 | * @hwif: interface |
@@ -293,8 +295,8 @@ static u8 sil680_init_chip(struct pci_dev *pdev) | |||
293 | 295 | ||
294 | pci_read_config_byte(pdev, 0x8A, &tmpbyte); | 296 | pci_read_config_byte(pdev, 0x8A, &tmpbyte); |
295 | 297 | ||
296 | printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n", | 298 | dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n", |
297 | tmpbyte & 1, tmpbyte & 0x30); | 299 | tmpbyte & 1, tmpbyte & 0x30); |
298 | 300 | ||
299 | switch(tmpbyte & 0x30) { | 301 | switch(tmpbyte & 0x30) { |
300 | case 0x00: | 302 | case 0x00: |
@@ -315,8 +317,8 @@ static u8 sil680_init_chip(struct pci_dev *pdev) | |||
315 | } | 317 | } |
316 | 318 | ||
317 | pci_read_config_byte(pdev, 0x8A, &tmpbyte); | 319 | pci_read_config_byte(pdev, 0x8A, &tmpbyte); |
318 | printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n", | 320 | dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n", |
319 | tmpbyte & 1, tmpbyte & 0x30); | 321 | tmpbyte & 1, tmpbyte & 0x30); |
320 | 322 | ||
321 | pci_write_config_byte(pdev, 0xA1, 0x72); | 323 | pci_write_config_byte(pdev, 0xA1, 0x72); |
322 | pci_write_config_word(pdev, 0xA2, 0x328A); | 324 | pci_write_config_word(pdev, 0xA2, 0x328A); |
@@ -339,22 +341,23 @@ static u8 sil680_init_chip(struct pci_dev *pdev) | |||
339 | return tmpbyte & 0x30; | 341 | return tmpbyte & 0x30; |
340 | } | 342 | } |
341 | 343 | ||
342 | static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | 344 | static int __devinit sil680_init_one(struct pci_dev *pdev, |
345 | const struct pci_device_id *id) | ||
343 | { | 346 | { |
344 | static const struct ata_port_info info = { | 347 | static const struct ata_port_info info = { |
345 | .sht = &sil680_sht, | 348 | .sht = &sil680_sht, |
346 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 349 | .flags = ATA_FLAG_SLAVE_POSS, |
347 | .pio_mask = 0x1f, | 350 | .pio_mask = 0x1f, |
348 | .mwdma_mask = 0x07, | 351 | .mwdma_mask = 0x07, |
349 | .udma_mask = 0x7f, | 352 | .udma_mask = ATA_UDMA6, |
350 | .port_ops = &sil680_port_ops | 353 | .port_ops = &sil680_port_ops |
351 | }; | 354 | }; |
352 | static const struct ata_port_info info_slow = { | 355 | static const struct ata_port_info info_slow = { |
353 | .sht = &sil680_sht, | 356 | .sht = &sil680_sht, |
354 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 357 | .flags = ATA_FLAG_SLAVE_POSS, |
355 | .pio_mask = 0x1f, | 358 | .pio_mask = 0x1f, |
356 | .mwdma_mask = 0x07, | 359 | .mwdma_mask = 0x07, |
357 | .udma_mask = 0x3f, | 360 | .udma_mask = ATA_UDMA5, |
358 | .port_ops = &sil680_port_ops | 361 | .port_ops = &sil680_port_ops |
359 | }; | 362 | }; |
360 | const struct ata_port_info *ppi[] = { &info, NULL }; | 363 | const struct ata_port_info *ppi[] = { &info, NULL }; |
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index cfe4ec6eb3d5..2b4508206a6c 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c | |||
@@ -732,7 +732,7 @@ static const struct ata_port_operations sis_old_ops = { | |||
732 | 732 | ||
733 | static const struct ata_port_info sis_info = { | 733 | static const struct ata_port_info sis_info = { |
734 | .sht = &sis_sht, | 734 | .sht = &sis_sht, |
735 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 735 | .flags = ATA_FLAG_SLAVE_POSS, |
736 | .pio_mask = 0x1f, /* pio0-4 */ | 736 | .pio_mask = 0x1f, /* pio0-4 */ |
737 | .mwdma_mask = 0x07, | 737 | .mwdma_mask = 0x07, |
738 | .udma_mask = 0, | 738 | .udma_mask = 0, |
@@ -740,7 +740,7 @@ static const struct ata_port_info sis_info = { | |||
740 | }; | 740 | }; |
741 | static const struct ata_port_info sis_info33 = { | 741 | static const struct ata_port_info sis_info33 = { |
742 | .sht = &sis_sht, | 742 | .sht = &sis_sht, |
743 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 743 | .flags = ATA_FLAG_SLAVE_POSS, |
744 | .pio_mask = 0x1f, /* pio0-4 */ | 744 | .pio_mask = 0x1f, /* pio0-4 */ |
745 | .mwdma_mask = 0x07, | 745 | .mwdma_mask = 0x07, |
746 | .udma_mask = ATA_UDMA2, /* UDMA 33 */ | 746 | .udma_mask = ATA_UDMA2, /* UDMA 33 */ |
@@ -748,28 +748,28 @@ static const struct ata_port_info sis_info33 = { | |||
748 | }; | 748 | }; |
749 | static const struct ata_port_info sis_info66 = { | 749 | static const struct ata_port_info sis_info66 = { |
750 | .sht = &sis_sht, | 750 | .sht = &sis_sht, |
751 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 751 | .flags = ATA_FLAG_SLAVE_POSS, |
752 | .pio_mask = 0x1f, /* pio0-4 */ | 752 | .pio_mask = 0x1f, /* pio0-4 */ |
753 | .udma_mask = ATA_UDMA4, /* UDMA 66 */ | 753 | .udma_mask = ATA_UDMA4, /* UDMA 66 */ |
754 | .port_ops = &sis_66_ops, | 754 | .port_ops = &sis_66_ops, |
755 | }; | 755 | }; |
756 | static const struct ata_port_info sis_info100 = { | 756 | static const struct ata_port_info sis_info100 = { |
757 | .sht = &sis_sht, | 757 | .sht = &sis_sht, |
758 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 758 | .flags = ATA_FLAG_SLAVE_POSS, |
759 | .pio_mask = 0x1f, /* pio0-4 */ | 759 | .pio_mask = 0x1f, /* pio0-4 */ |
760 | .udma_mask = ATA_UDMA5, | 760 | .udma_mask = ATA_UDMA5, |
761 | .port_ops = &sis_100_ops, | 761 | .port_ops = &sis_100_ops, |
762 | }; | 762 | }; |
763 | static const struct ata_port_info sis_info100_early = { | 763 | static const struct ata_port_info sis_info100_early = { |
764 | .sht = &sis_sht, | 764 | .sht = &sis_sht, |
765 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 765 | .flags = ATA_FLAG_SLAVE_POSS, |
766 | .udma_mask = ATA_UDMA5, | 766 | .udma_mask = ATA_UDMA5, |
767 | .pio_mask = 0x1f, /* pio0-4 */ | 767 | .pio_mask = 0x1f, /* pio0-4 */ |
768 | .port_ops = &sis_66_ops, | 768 | .port_ops = &sis_66_ops, |
769 | }; | 769 | }; |
770 | static const struct ata_port_info sis_info133 = { | 770 | static const struct ata_port_info sis_info133 = { |
771 | .sht = &sis_sht, | 771 | .sht = &sis_sht, |
772 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 772 | .flags = ATA_FLAG_SLAVE_POSS, |
773 | .pio_mask = 0x1f, /* pio0-4 */ | 773 | .pio_mask = 0x1f, /* pio0-4 */ |
774 | .udma_mask = ATA_UDMA6, | 774 | .udma_mask = ATA_UDMA6, |
775 | .port_ops = &sis_133_ops, | 775 | .port_ops = &sis_133_ops, |
@@ -783,7 +783,7 @@ const struct ata_port_info sis_info133_for_sata = { | |||
783 | }; | 783 | }; |
784 | static const struct ata_port_info sis_info133_early = { | 784 | static const struct ata_port_info sis_info133_early = { |
785 | .sht = &sis_sht, | 785 | .sht = &sis_sht, |
786 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 786 | .flags = ATA_FLAG_SLAVE_POSS, |
787 | .pio_mask = 0x1f, /* pio0-4 */ | 787 | .pio_mask = 0x1f, /* pio0-4 */ |
788 | .udma_mask = ATA_UDMA6, | 788 | .udma_mask = ATA_UDMA6, |
789 | .port_ops = &sis_133_early_ops, | 789 | .port_ops = &sis_133_early_ops, |
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index e5aaec43694d..bde734189623 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c | |||
@@ -303,14 +303,14 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id | |||
303 | { | 303 | { |
304 | static const struct ata_port_info info_dma = { | 304 | static const struct ata_port_info info_dma = { |
305 | .sht = &sl82c105_sht, | 305 | .sht = &sl82c105_sht, |
306 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 306 | .flags = ATA_FLAG_SLAVE_POSS, |
307 | .pio_mask = 0x1f, | 307 | .pio_mask = 0x1f, |
308 | .mwdma_mask = 0x07, | 308 | .mwdma_mask = 0x07, |
309 | .port_ops = &sl82c105_port_ops | 309 | .port_ops = &sl82c105_port_ops |
310 | }; | 310 | }; |
311 | static const struct ata_port_info info_early = { | 311 | static const struct ata_port_info info_early = { |
312 | .sht = &sl82c105_sht, | 312 | .sht = &sl82c105_sht, |
313 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 313 | .flags = ATA_FLAG_SLAVE_POSS, |
314 | .pio_mask = 0x1f, | 314 | .pio_mask = 0x1f, |
315 | .port_ops = &sl82c105_port_ops | 315 | .port_ops = &sl82c105_port_ops |
316 | }; | 316 | }; |
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index b1d3076dfe51..af21f443db6e 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c | |||
@@ -235,7 +235,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) | |||
235 | { | 235 | { |
236 | static const struct ata_port_info info = { | 236 | static const struct ata_port_info info = { |
237 | .sht = &triflex_sht, | 237 | .sht = &triflex_sht, |
238 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | 238 | .flags = ATA_FLAG_SLAVE_POSS, |
239 | .pio_mask = 0x1f, | 239 | .pio_mask = 0x1f, |
240 | .mwdma_mask = 0x07, | 240 | .mwdma_mask = 0x07, |
241 | .port_ops = &triflex_port_ops | 241 | .port_ops = &triflex_port_ops |
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 63eca299c62b..f0cadbe6aa11 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c | |||
@@ -471,7 +471,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
471 | .flags = ATA_FLAG_SLAVE_POSS, | 471 | .flags = ATA_FLAG_SLAVE_POSS, |
472 | .pio_mask = 0x1f, | 472 | .pio_mask = 0x1f, |
473 | .mwdma_mask = 0x07, | 473 | .mwdma_mask = 0x07, |
474 | .udma_mask = 0x7, | 474 | .udma_mask = ATA_UDMA2, |
475 | .port_ops = &via_port_ops | 475 | .port_ops = &via_port_ops |
476 | }; | 476 | }; |
477 | /* VIA UDMA 66 devices */ | 477 | /* VIA UDMA 66 devices */ |
@@ -480,7 +480,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
480 | .flags = ATA_FLAG_SLAVE_POSS, | 480 | .flags = ATA_FLAG_SLAVE_POSS, |
481 | .pio_mask = 0x1f, | 481 | .pio_mask = 0x1f, |
482 | .mwdma_mask = 0x07, | 482 | .mwdma_mask = 0x07, |
483 | .udma_mask = 0x1f, | 483 | .udma_mask = ATA_UDMA4, |
484 | .port_ops = &via_port_ops | 484 | .port_ops = &via_port_ops |
485 | }; | 485 | }; |
486 | /* VIA UDMA 100 devices */ | 486 | /* VIA UDMA 100 devices */ |
@@ -489,7 +489,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
489 | .flags = ATA_FLAG_SLAVE_POSS, | 489 | .flags = ATA_FLAG_SLAVE_POSS, |
490 | .pio_mask = 0x1f, | 490 | .pio_mask = 0x1f, |
491 | .mwdma_mask = 0x07, | 491 | .mwdma_mask = 0x07, |
492 | .udma_mask = 0x3f, | 492 | .udma_mask = ATA_UDMA5, |
493 | .port_ops = &via_port_ops | 493 | .port_ops = &via_port_ops |
494 | }; | 494 | }; |
495 | /* UDMA133 with bad AST (All current 133) */ | 495 | /* UDMA133 with bad AST (All current 133) */ |
@@ -498,7 +498,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
498 | .flags = ATA_FLAG_SLAVE_POSS, | 498 | .flags = ATA_FLAG_SLAVE_POSS, |
499 | .pio_mask = 0x1f, | 499 | .pio_mask = 0x1f, |
500 | .mwdma_mask = 0x07, | 500 | .mwdma_mask = 0x07, |
501 | .udma_mask = 0x7f, /* FIXME: should check north bridge */ | 501 | .udma_mask = ATA_UDMA6, /* FIXME: should check north bridge */ |
502 | .port_ops = &via_port_ops | 502 | .port_ops = &via_port_ops |
503 | }; | 503 | }; |
504 | struct ata_port_info type; | 504 | struct ata_port_info type; |
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index f12c2b6ac08e..bec1de594de8 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c | |||
@@ -145,32 +145,32 @@ static struct scsi_host_template adma_ata_sht = { | |||
145 | .name = DRV_NAME, | 145 | .name = DRV_NAME, |
146 | .ioctl = ata_scsi_ioctl, | 146 | .ioctl = ata_scsi_ioctl, |
147 | .queuecommand = ata_scsi_queuecmd, | 147 | .queuecommand = ata_scsi_queuecmd, |
148 | .slave_configure = ata_scsi_slave_config, | ||
149 | .slave_destroy = ata_scsi_slave_destroy, | ||
150 | .bios_param = ata_std_bios_param, | ||
151 | .proc_name = DRV_NAME, | ||
148 | .can_queue = ATA_DEF_QUEUE, | 152 | .can_queue = ATA_DEF_QUEUE, |
149 | .this_id = ATA_SHT_THIS_ID, | 153 | .this_id = ATA_SHT_THIS_ID, |
150 | .sg_tablesize = LIBATA_MAX_PRD, | 154 | .sg_tablesize = LIBATA_MAX_PRD, |
155 | .dma_boundary = ADMA_DMA_BOUNDARY, | ||
151 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | 156 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, |
152 | .emulated = ATA_SHT_EMULATED, | ||
153 | .use_clustering = ENABLE_CLUSTERING, | 157 | .use_clustering = ENABLE_CLUSTERING, |
154 | .proc_name = DRV_NAME, | 158 | .emulated = ATA_SHT_EMULATED, |
155 | .dma_boundary = ADMA_DMA_BOUNDARY, | ||
156 | .slave_configure = ata_scsi_slave_config, | ||
157 | .slave_destroy = ata_scsi_slave_destroy, | ||
158 | .bios_param = ata_std_bios_param, | ||
159 | }; | 159 | }; |
160 | 160 | ||
161 | static const struct ata_port_operations adma_ata_ops = { | 161 | static const struct ata_port_operations adma_ata_ops = { |
162 | .port_disable = ata_port_disable, | 162 | .port_disable = ata_port_disable, |
163 | .tf_load = ata_tf_load, | 163 | .tf_load = ata_tf_load, |
164 | .tf_read = ata_tf_read, | 164 | .tf_read = ata_tf_read, |
165 | .check_status = ata_check_status, | ||
166 | .check_atapi_dma = adma_check_atapi_dma, | ||
167 | .exec_command = ata_exec_command, | 165 | .exec_command = ata_exec_command, |
166 | .check_status = ata_check_status, | ||
168 | .dev_select = ata_std_dev_select, | 167 | .dev_select = ata_std_dev_select, |
169 | .phy_reset = adma_phy_reset, | 168 | .phy_reset = adma_phy_reset, |
169 | .check_atapi_dma = adma_check_atapi_dma, | ||
170 | .data_xfer = ata_data_xfer, | ||
170 | .qc_prep = adma_qc_prep, | 171 | .qc_prep = adma_qc_prep, |
171 | .qc_issue = adma_qc_issue, | 172 | .qc_issue = adma_qc_issue, |
172 | .eng_timeout = adma_eng_timeout, | 173 | .eng_timeout = adma_eng_timeout, |
173 | .data_xfer = ata_data_xfer, | ||
174 | .irq_clear = adma_irq_clear, | 174 | .irq_clear = adma_irq_clear, |
175 | .irq_on = ata_irq_on, | 175 | .irq_on = ata_irq_on, |
176 | .irq_ack = ata_irq_ack, | 176 | .irq_ack = ata_irq_ack, |
@@ -188,7 +188,7 @@ static struct ata_port_info adma_port_info[] = { | |||
188 | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | | 188 | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | |
189 | ATA_FLAG_PIO_POLLING, | 189 | ATA_FLAG_PIO_POLLING, |
190 | .pio_mask = 0x10, /* pio4 */ | 190 | .pio_mask = 0x10, /* pio4 */ |
191 | .udma_mask = 0x1f, /* udma0-4 */ | 191 | .udma_mask = ATA_UDMA4, |
192 | .port_ops = &adma_ata_ops, | 192 | .port_ops = &adma_ata_ops, |
193 | }, | 193 | }, |
194 | }; | 194 | }; |
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index dc3bbce04676..3de183461c3c 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c | |||
@@ -192,7 +192,7 @@ static void inic_reset_port(void __iomem *port_base) | |||
192 | 192 | ||
193 | static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg) | 193 | static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg) |
194 | { | 194 | { |
195 | void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; | 195 | void __iomem *scr_addr = ap->ioaddr.scr_addr; |
196 | void __iomem *addr; | 196 | void __iomem *addr; |
197 | u32 val; | 197 | u32 val; |
198 | 198 | ||
@@ -210,7 +210,7 @@ static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg) | |||
210 | 210 | ||
211 | static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) | 211 | static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) |
212 | { | 212 | { |
213 | void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; | 213 | void __iomem *scr_addr = ap->ioaddr.scr_addr; |
214 | void __iomem *addr; | 214 | void __iomem *addr; |
215 | 215 | ||
216 | if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) | 216 | if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) |
@@ -594,7 +594,7 @@ static struct ata_port_info inic_port_info = { | |||
594 | .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, | 594 | .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, |
595 | .pio_mask = 0x1f, /* pio0-4 */ | 595 | .pio_mask = 0x1f, /* pio0-4 */ |
596 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 596 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
597 | .udma_mask = 0x7f, /* udma0-6 */ | 597 | .udma_mask = ATA_UDMA6, |
598 | .port_ops = &inic_port_ops | 598 | .port_ops = &inic_port_ops |
599 | }; | 599 | }; |
600 | 600 | ||
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 590f2f92b4e0..3873b29c80d6 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -526,44 +526,44 @@ static const struct ata_port_info mv_port_info[] = { | |||
526 | { /* chip_504x */ | 526 | { /* chip_504x */ |
527 | .flags = MV_COMMON_FLAGS, | 527 | .flags = MV_COMMON_FLAGS, |
528 | .pio_mask = 0x1f, /* pio0-4 */ | 528 | .pio_mask = 0x1f, /* pio0-4 */ |
529 | .udma_mask = 0x7f, /* udma0-6 */ | 529 | .udma_mask = ATA_UDMA6, |
530 | .port_ops = &mv5_ops, | 530 | .port_ops = &mv5_ops, |
531 | }, | 531 | }, |
532 | { /* chip_508x */ | 532 | { /* chip_508x */ |
533 | .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), | 533 | .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), |
534 | .pio_mask = 0x1f, /* pio0-4 */ | 534 | .pio_mask = 0x1f, /* pio0-4 */ |
535 | .udma_mask = 0x7f, /* udma0-6 */ | 535 | .udma_mask = ATA_UDMA6, |
536 | .port_ops = &mv5_ops, | 536 | .port_ops = &mv5_ops, |
537 | }, | 537 | }, |
538 | { /* chip_5080 */ | 538 | { /* chip_5080 */ |
539 | .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), | 539 | .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), |
540 | .pio_mask = 0x1f, /* pio0-4 */ | 540 | .pio_mask = 0x1f, /* pio0-4 */ |
541 | .udma_mask = 0x7f, /* udma0-6 */ | 541 | .udma_mask = ATA_UDMA6, |
542 | .port_ops = &mv5_ops, | 542 | .port_ops = &mv5_ops, |
543 | }, | 543 | }, |
544 | { /* chip_604x */ | 544 | { /* chip_604x */ |
545 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), | 545 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), |
546 | .pio_mask = 0x1f, /* pio0-4 */ | 546 | .pio_mask = 0x1f, /* pio0-4 */ |
547 | .udma_mask = 0x7f, /* udma0-6 */ | 547 | .udma_mask = ATA_UDMA6, |
548 | .port_ops = &mv6_ops, | 548 | .port_ops = &mv6_ops, |
549 | }, | 549 | }, |
550 | { /* chip_608x */ | 550 | { /* chip_608x */ |
551 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | | 551 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | |
552 | MV_FLAG_DUAL_HC), | 552 | MV_FLAG_DUAL_HC), |
553 | .pio_mask = 0x1f, /* pio0-4 */ | 553 | .pio_mask = 0x1f, /* pio0-4 */ |
554 | .udma_mask = 0x7f, /* udma0-6 */ | 554 | .udma_mask = ATA_UDMA6, |
555 | .port_ops = &mv6_ops, | 555 | .port_ops = &mv6_ops, |
556 | }, | 556 | }, |
557 | { /* chip_6042 */ | 557 | { /* chip_6042 */ |
558 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), | 558 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), |
559 | .pio_mask = 0x1f, /* pio0-4 */ | 559 | .pio_mask = 0x1f, /* pio0-4 */ |
560 | .udma_mask = 0x7f, /* udma0-6 */ | 560 | .udma_mask = ATA_UDMA6, |
561 | .port_ops = &mv_iie_ops, | 561 | .port_ops = &mv_iie_ops, |
562 | }, | 562 | }, |
563 | { /* chip_7042 */ | 563 | { /* chip_7042 */ |
564 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), | 564 | .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), |
565 | .pio_mask = 0x1f, /* pio0-4 */ | 565 | .pio_mask = 0x1f, /* pio0-4 */ |
566 | .udma_mask = 0x7f, /* udma0-6 */ | 566 | .udma_mask = ATA_UDMA6, |
567 | .port_ops = &mv_iie_ops, | 567 | .port_ops = &mv_iie_ops, |
568 | }, | 568 | }, |
569 | }; | 569 | }; |
@@ -2338,7 +2338,7 @@ static void mv_print_info(struct ata_host *host) | |||
2338 | struct pci_dev *pdev = to_pci_dev(host->dev); | 2338 | struct pci_dev *pdev = to_pci_dev(host->dev); |
2339 | struct mv_host_priv *hpriv = host->private_data; | 2339 | struct mv_host_priv *hpriv = host->private_data; |
2340 | u8 rev_id, scc; | 2340 | u8 rev_id, scc; |
2341 | const char *scc_s; | 2341 | const char *scc_s, *gen; |
2342 | 2342 | ||
2343 | /* Use this to determine the HW stepping of the chip so we know | 2343 | /* Use this to determine the HW stepping of the chip so we know |
2344 | * what errata to workaround | 2344 | * what errata to workaround |
@@ -2351,11 +2351,20 @@ static void mv_print_info(struct ata_host *host) | |||
2351 | else if (scc == 0x01) | 2351 | else if (scc == 0x01) |
2352 | scc_s = "RAID"; | 2352 | scc_s = "RAID"; |
2353 | else | 2353 | else |
2354 | scc_s = "unknown"; | 2354 | scc_s = "?"; |
2355 | |||
2356 | if (IS_GEN_I(hpriv)) | ||
2357 | gen = "I"; | ||
2358 | else if (IS_GEN_II(hpriv)) | ||
2359 | gen = "II"; | ||
2360 | else if (IS_GEN_IIE(hpriv)) | ||
2361 | gen = "IIE"; | ||
2362 | else | ||
2363 | gen = "?"; | ||
2355 | 2364 | ||
2356 | dev_printk(KERN_INFO, &pdev->dev, | 2365 | dev_printk(KERN_INFO, &pdev->dev, |
2357 | "%u slots %u ports %s mode IRQ via %s\n", | 2366 | "Gen-%s %u slots %u ports %s mode IRQ via %s\n", |
2358 | (unsigned)MV_MAX_Q_DEPTH, host->n_ports, | 2367 | gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports, |
2359 | scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); | 2368 | scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); |
2360 | } | 2369 | } |
2361 | 2370 | ||
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 6dc0b011a6b7..2ad5872fe90c 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c | |||
@@ -45,8 +45,7 @@ | |||
45 | #include "sata_promise.h" | 45 | #include "sata_promise.h" |
46 | 46 | ||
47 | #define DRV_NAME "sata_promise" | 47 | #define DRV_NAME "sata_promise" |
48 | #define DRV_VERSION "2.07" | 48 | #define DRV_VERSION "2.08" |
49 | |||
50 | 49 | ||
51 | enum { | 50 | enum { |
52 | PDC_MAX_PORTS = 4, | 51 | PDC_MAX_PORTS = 4, |
@@ -94,7 +93,7 @@ enum { | |||
94 | board_20319 = 2, /* FastTrak S150 TX4 */ | 93 | board_20319 = 2, /* FastTrak S150 TX4 */ |
95 | board_20619 = 3, /* FastTrak TX4000 */ | 94 | board_20619 = 3, /* FastTrak TX4000 */ |
96 | board_2057x = 4, /* SATAII150 Tx2plus */ | 95 | board_2057x = 4, /* SATAII150 Tx2plus */ |
97 | board_2057x_pata = 5, /* SATAII150 Tx2plus */ | 96 | board_2057x_pata = 5, /* SATAII150 Tx2plus PATA port */ |
98 | board_40518 = 6, /* SATAII150 Tx4 */ | 97 | board_40518 = 6, /* SATAII150 Tx4 */ |
99 | 98 | ||
100 | PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */ | 99 | PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */ |
@@ -124,7 +123,6 @@ enum { | |||
124 | PDC_FLAG_4_PORTS = (1 << 26), /* 4 ports */ | 123 | PDC_FLAG_4_PORTS = (1 << 26), /* 4 ports */ |
125 | }; | 124 | }; |
126 | 125 | ||
127 | |||
128 | struct pdc_port_priv { | 126 | struct pdc_port_priv { |
129 | u8 *pkt; | 127 | u8 *pkt; |
130 | dma_addr_t pkt_dma; | 128 | dma_addr_t pkt_dma; |
@@ -252,7 +250,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
252 | PDC_FLAG_SATA_PATA, | 250 | PDC_FLAG_SATA_PATA, |
253 | .pio_mask = 0x1f, /* pio0-4 */ | 251 | .pio_mask = 0x1f, /* pio0-4 */ |
254 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 252 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
255 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 253 | .udma_mask = ATA_UDMA6, |
256 | .port_ops = &pdc_old_sata_ops, | 254 | .port_ops = &pdc_old_sata_ops, |
257 | }, | 255 | }, |
258 | 256 | ||
@@ -261,7 +259,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
261 | .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, | 259 | .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, |
262 | .pio_mask = 0x1f, /* pio0-4 */ | 260 | .pio_mask = 0x1f, /* pio0-4 */ |
263 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 261 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
264 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 262 | .udma_mask = ATA_UDMA6, |
265 | .port_ops = &pdc_pata_ops, | 263 | .port_ops = &pdc_pata_ops, |
266 | }, | 264 | }, |
267 | 265 | ||
@@ -271,7 +269,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
271 | PDC_FLAG_4_PORTS, | 269 | PDC_FLAG_4_PORTS, |
272 | .pio_mask = 0x1f, /* pio0-4 */ | 270 | .pio_mask = 0x1f, /* pio0-4 */ |
273 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 271 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
274 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 272 | .udma_mask = ATA_UDMA6, |
275 | .port_ops = &pdc_old_sata_ops, | 273 | .port_ops = &pdc_old_sata_ops, |
276 | }, | 274 | }, |
277 | 275 | ||
@@ -281,7 +279,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
281 | PDC_FLAG_4_PORTS, | 279 | PDC_FLAG_4_PORTS, |
282 | .pio_mask = 0x1f, /* pio0-4 */ | 280 | .pio_mask = 0x1f, /* pio0-4 */ |
283 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 281 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
284 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 282 | .udma_mask = ATA_UDMA6, |
285 | .port_ops = &pdc_pata_ops, | 283 | .port_ops = &pdc_pata_ops, |
286 | }, | 284 | }, |
287 | 285 | ||
@@ -291,7 +289,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
291 | PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA, | 289 | PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA, |
292 | .pio_mask = 0x1f, /* pio0-4 */ | 290 | .pio_mask = 0x1f, /* pio0-4 */ |
293 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 291 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
294 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 292 | .udma_mask = ATA_UDMA6, |
295 | .port_ops = &pdc_sata_ops, | 293 | .port_ops = &pdc_sata_ops, |
296 | }, | 294 | }, |
297 | 295 | ||
@@ -301,7 +299,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
301 | PDC_FLAG_GEN_II, | 299 | PDC_FLAG_GEN_II, |
302 | .pio_mask = 0x1f, /* pio0-4 */ | 300 | .pio_mask = 0x1f, /* pio0-4 */ |
303 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 301 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
304 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 302 | .udma_mask = ATA_UDMA6, |
305 | .port_ops = &pdc_pata_ops, | 303 | .port_ops = &pdc_pata_ops, |
306 | }, | 304 | }, |
307 | 305 | ||
@@ -311,7 +309,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
311 | PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS, | 309 | PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS, |
312 | .pio_mask = 0x1f, /* pio0-4 */ | 310 | .pio_mask = 0x1f, /* pio0-4 */ |
313 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 311 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
314 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 312 | .udma_mask = ATA_UDMA6, |
315 | .port_ops = &pdc_sata_ops, | 313 | .port_ops = &pdc_sata_ops, |
316 | }, | 314 | }, |
317 | }; | 315 | }; |
@@ -340,7 +338,6 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = { | |||
340 | { } /* terminate list */ | 338 | { } /* terminate list */ |
341 | }; | 339 | }; |
342 | 340 | ||
343 | |||
344 | static struct pci_driver pdc_ata_pci_driver = { | 341 | static struct pci_driver pdc_ata_pci_driver = { |
345 | .name = DRV_NAME, | 342 | .name = DRV_NAME, |
346 | .id_table = pdc_ata_pci_tbl, | 343 | .id_table = pdc_ata_pci_tbl, |
@@ -348,7 +345,6 @@ static struct pci_driver pdc_ata_pci_driver = { | |||
348 | .remove = ata_pci_remove_one, | 345 | .remove = ata_pci_remove_one, |
349 | }; | 346 | }; |
350 | 347 | ||
351 | |||
352 | static int pdc_common_port_start(struct ata_port *ap) | 348 | static int pdc_common_port_start(struct ata_port *ap) |
353 | { | 349 | { |
354 | struct device *dev = ap->host->dev; | 350 | struct device *dev = ap->host->dev; |
@@ -382,7 +378,7 @@ static int pdc_sata_port_start(struct ata_port *ap) | |||
382 | 378 | ||
383 | /* fix up PHYMODE4 align timing */ | 379 | /* fix up PHYMODE4 align timing */ |
384 | if (ap->flags & PDC_FLAG_GEN_II) { | 380 | if (ap->flags & PDC_FLAG_GEN_II) { |
385 | void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr; | 381 | void __iomem *mmio = ap->ioaddr.scr_addr; |
386 | unsigned int tmp; | 382 | unsigned int tmp; |
387 | 383 | ||
388 | tmp = readl(mmio + 0x014); | 384 | tmp = readl(mmio + 0x014); |
@@ -418,7 +414,7 @@ static void pdc_reset_port(struct ata_port *ap) | |||
418 | static int pdc_pata_cable_detect(struct ata_port *ap) | 414 | static int pdc_pata_cable_detect(struct ata_port *ap) |
419 | { | 415 | { |
420 | u8 tmp; | 416 | u8 tmp; |
421 | void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; | 417 | void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; |
422 | 418 | ||
423 | tmp = readb(mmio); | 419 | tmp = readb(mmio); |
424 | if (tmp & 0x01) | 420 | if (tmp & 0x01) |
@@ -438,7 +434,6 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) | |||
438 | return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); | 434 | return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); |
439 | } | 435 | } |
440 | 436 | ||
441 | |||
442 | static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, | 437 | static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, |
443 | u32 val) | 438 | u32 val) |
444 | { | 439 | { |
@@ -573,7 +568,7 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) | |||
573 | 568 | ||
574 | static void pdc_freeze(struct ata_port *ap) | 569 | static void pdc_freeze(struct ata_port *ap) |
575 | { | 570 | { |
576 | void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; | 571 | void __iomem *mmio = ap->ioaddr.cmd_addr; |
577 | u32 tmp; | 572 | u32 tmp; |
578 | 573 | ||
579 | tmp = readl(mmio + PDC_CTLSTAT); | 574 | tmp = readl(mmio + PDC_CTLSTAT); |
@@ -585,7 +580,7 @@ static void pdc_freeze(struct ata_port *ap) | |||
585 | 580 | ||
586 | static void pdc_thaw(struct ata_port *ap) | 581 | static void pdc_thaw(struct ata_port *ap) |
587 | { | 582 | { |
588 | void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; | 583 | void __iomem *mmio = ap->ioaddr.cmd_addr; |
589 | u32 tmp; | 584 | u32 tmp; |
590 | 585 | ||
591 | /* clear IRQ */ | 586 | /* clear IRQ */ |
@@ -657,8 +652,8 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, | |||
657 | ata_port_abort(ap); | 652 | ata_port_abort(ap); |
658 | } | 653 | } |
659 | 654 | ||
660 | static inline unsigned int pdc_host_intr( struct ata_port *ap, | 655 | static inline unsigned int pdc_host_intr(struct ata_port *ap, |
661 | struct ata_queued_cmd *qc) | 656 | struct ata_queued_cmd *qc) |
662 | { | 657 | { |
663 | unsigned int handled = 0; | 658 | unsigned int handled = 0; |
664 | void __iomem *port_mmio = ap->ioaddr.cmd_addr; | 659 | void __iomem *port_mmio = ap->ioaddr.cmd_addr; |
@@ -685,10 +680,10 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap, | |||
685 | handled = 1; | 680 | handled = 1; |
686 | break; | 681 | break; |
687 | 682 | ||
688 | default: | 683 | default: |
689 | ap->stats.idle_irq++; | 684 | ap->stats.idle_irq++; |
690 | break; | 685 | break; |
691 | } | 686 | } |
692 | 687 | ||
693 | return handled; | 688 | return handled; |
694 | } | 689 | } |
@@ -701,6 +696,18 @@ static void pdc_irq_clear(struct ata_port *ap) | |||
701 | readl(mmio + PDC_INT_SEQMASK); | 696 | readl(mmio + PDC_INT_SEQMASK); |
702 | } | 697 | } |
703 | 698 | ||
699 | static inline int pdc_is_sataii_tx4(unsigned long flags) | ||
700 | { | ||
701 | const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS; | ||
702 | return (flags & mask) == mask; | ||
703 | } | ||
704 | |||
705 | static inline unsigned int pdc_port_no_to_ata_no(unsigned int port_no, int is_sataii_tx4) | ||
706 | { | ||
707 | static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; | ||
708 | return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no; | ||
709 | } | ||
710 | |||
704 | static irqreturn_t pdc_interrupt (int irq, void *dev_instance) | 711 | static irqreturn_t pdc_interrupt (int irq, void *dev_instance) |
705 | { | 712 | { |
706 | struct ata_host *host = dev_instance; | 713 | struct ata_host *host = dev_instance; |
@@ -807,7 +814,6 @@ static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) | |||
807 | ata_tf_load(ap, tf); | 814 | ata_tf_load(ap, tf); |
808 | } | 815 | } |
809 | 816 | ||
810 | |||
811 | static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) | 817 | static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) |
812 | { | 818 | { |
813 | WARN_ON (tf->protocol == ATA_PROT_DMA || | 819 | WARN_ON (tf->protocol == ATA_PROT_DMA || |
@@ -867,7 +873,6 @@ static void pdc_ata_setup_port(struct ata_port *ap, | |||
867 | ap->ioaddr.scr_addr = scr_addr; | 873 | ap->ioaddr.scr_addr = scr_addr; |
868 | } | 874 | } |
869 | 875 | ||
870 | |||
871 | static void pdc_host_init(struct ata_host *host) | 876 | static void pdc_host_init(struct ata_host *host) |
872 | { | 877 | { |
873 | void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; | 878 | void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; |
@@ -955,10 +960,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e | |||
955 | 960 | ||
956 | if (pi->flags & PDC_FLAG_SATA_PATA) { | 961 | if (pi->flags & PDC_FLAG_SATA_PATA) { |
957 | u8 tmp = readb(base + PDC_FLASH_CTL+1); | 962 | u8 tmp = readb(base + PDC_FLASH_CTL+1); |
958 | if (!(tmp & 0x80)) { | 963 | if (!(tmp & 0x80)) |
959 | ppi[n_ports++] = pi + 1; | 964 | ppi[n_ports++] = pi + 1; |
960 | dev_printk(KERN_INFO, &pdev->dev, "PATA port found\n"); | ||
961 | } | ||
962 | } | 965 | } |
963 | 966 | ||
964 | host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); | 967 | host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); |
@@ -968,22 +971,12 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e | |||
968 | } | 971 | } |
969 | host->iomap = pcim_iomap_table(pdev); | 972 | host->iomap = pcim_iomap_table(pdev); |
970 | 973 | ||
971 | is_sataii_tx4 = 0; | 974 | is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags); |
972 | if ((pi->flags & (PDC_FLAG_GEN_II|PDC_FLAG_4_PORTS)) == (PDC_FLAG_GEN_II|PDC_FLAG_4_PORTS)) { | ||
973 | is_sataii_tx4 = 1; | ||
974 | dev_printk(KERN_INFO, &pdev->dev, "applying SATAII TX4 port numbering workaround\n"); | ||
975 | } | ||
976 | for (i = 0; i < host->n_ports; i++) { | 975 | for (i = 0; i < host->n_ports; i++) { |
977 | static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; | 976 | unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4); |
978 | int ata_nr; | ||
979 | |||
980 | ata_nr = i; | ||
981 | if (is_sataii_tx4) | ||
982 | ata_nr = sataii_tx4_port_remap[i]; | ||
983 | |||
984 | pdc_ata_setup_port(host->ports[i], | 977 | pdc_ata_setup_port(host->ports[i], |
985 | base + 0x200 + ata_nr * 0x80, | 978 | base + 0x200 + ata_no * 0x80, |
986 | base + 0x400 + ata_nr * 0x100); | 979 | base + 0x400 + ata_no * 0x100); |
987 | } | 980 | } |
988 | 981 | ||
989 | /* initialize adapter */ | 982 | /* initialize adapter */ |
@@ -1002,19 +995,16 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e | |||
1002 | &pdc_ata_sht); | 995 | &pdc_ata_sht); |
1003 | } | 996 | } |
1004 | 997 | ||
1005 | |||
1006 | static int __init pdc_ata_init(void) | 998 | static int __init pdc_ata_init(void) |
1007 | { | 999 | { |
1008 | return pci_register_driver(&pdc_ata_pci_driver); | 1000 | return pci_register_driver(&pdc_ata_pci_driver); |
1009 | } | 1001 | } |
1010 | 1002 | ||
1011 | |||
1012 | static void __exit pdc_ata_exit(void) | 1003 | static void __exit pdc_ata_exit(void) |
1013 | { | 1004 | { |
1014 | pci_unregister_driver(&pdc_ata_pci_driver); | 1005 | pci_unregister_driver(&pdc_ata_pci_driver); |
1015 | } | 1006 | } |
1016 | 1007 | ||
1017 | |||
1018 | MODULE_AUTHOR("Jeff Garzik"); | 1008 | MODULE_AUTHOR("Jeff Garzik"); |
1019 | MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver"); | 1009 | MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver"); |
1020 | MODULE_LICENSE("GPL"); | 1010 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 6688ccb66320..9ab554da89bf 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c | |||
@@ -176,7 +176,7 @@ static const struct ata_port_info qs_port_info[] = { | |||
176 | //FIXME ATA_FLAG_SRST | | 176 | //FIXME ATA_FLAG_SRST | |
177 | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, | 177 | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, |
178 | .pio_mask = 0x10, /* pio4 */ | 178 | .pio_mask = 0x10, /* pio4 */ |
179 | .udma_mask = 0x7f, /* udma0-6 */ | 179 | .udma_mask = ATA_UDMA6, |
180 | .port_ops = &qs_ata_ops, | 180 | .port_ops = &qs_ata_ops, |
181 | }, | 181 | }, |
182 | }; | 182 | }; |
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index a3b339bcf3cf..2a86dc4598d0 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c | |||
@@ -218,7 +218,7 @@ static const struct ata_port_info sil_port_info[] = { | |||
218 | .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, | 218 | .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, |
219 | .pio_mask = 0x1f, /* pio0-4 */ | 219 | .pio_mask = 0x1f, /* pio0-4 */ |
220 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 220 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
221 | .udma_mask = 0x3f, /* udma0-5 */ | 221 | .udma_mask = ATA_UDMA5, |
222 | .port_ops = &sil_ops, | 222 | .port_ops = &sil_ops, |
223 | }, | 223 | }, |
224 | /* sil_3112_no_sata_irq */ | 224 | /* sil_3112_no_sata_irq */ |
@@ -227,7 +227,7 @@ static const struct ata_port_info sil_port_info[] = { | |||
227 | SIL_FLAG_NO_SATA_IRQ, | 227 | SIL_FLAG_NO_SATA_IRQ, |
228 | .pio_mask = 0x1f, /* pio0-4 */ | 228 | .pio_mask = 0x1f, /* pio0-4 */ |
229 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 229 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
230 | .udma_mask = 0x3f, /* udma0-5 */ | 230 | .udma_mask = ATA_UDMA5, |
231 | .port_ops = &sil_ops, | 231 | .port_ops = &sil_ops, |
232 | }, | 232 | }, |
233 | /* sil_3512 */ | 233 | /* sil_3512 */ |
@@ -235,7 +235,7 @@ static const struct ata_port_info sil_port_info[] = { | |||
235 | .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, | 235 | .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, |
236 | .pio_mask = 0x1f, /* pio0-4 */ | 236 | .pio_mask = 0x1f, /* pio0-4 */ |
237 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 237 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
238 | .udma_mask = 0x3f, /* udma0-5 */ | 238 | .udma_mask = ATA_UDMA5, |
239 | .port_ops = &sil_ops, | 239 | .port_ops = &sil_ops, |
240 | }, | 240 | }, |
241 | /* sil_3114 */ | 241 | /* sil_3114 */ |
@@ -243,7 +243,7 @@ static const struct ata_port_info sil_port_info[] = { | |||
243 | .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, | 243 | .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, |
244 | .pio_mask = 0x1f, /* pio0-4 */ | 244 | .pio_mask = 0x1f, /* pio0-4 */ |
245 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 245 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
246 | .udma_mask = 0x3f, /* udma0-5 */ | 246 | .udma_mask = ATA_UDMA5, |
247 | .port_ops = &sil_ops, | 247 | .port_ops = &sil_ops, |
248 | }, | 248 | }, |
249 | }; | 249 | }; |
@@ -262,8 +262,9 @@ static const struct { | |||
262 | unsigned long sfis_cfg; /* SATA FIS reception config register */ | 262 | unsigned long sfis_cfg; /* SATA FIS reception config register */ |
263 | } sil_port[] = { | 263 | } sil_port[] = { |
264 | /* port 0 ... */ | 264 | /* port 0 ... */ |
265 | { 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c }, | 265 | /* tf ctl bmdma bmdma2 fifo scr sien mode sfis */ |
266 | { 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc }, | 266 | { 0x80, 0x8A, 0x0, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c }, |
267 | { 0xC0, 0xCA, 0x8, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc }, | ||
267 | { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c }, | 268 | { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c }, |
268 | { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc }, | 269 | { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc }, |
269 | /* ... port 3 */ | 270 | /* ... port 3 */ |
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 0ddfae9911cd..ac43a30ebe29 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c | |||
@@ -426,7 +426,7 @@ static const struct ata_port_info sil24_port_info[] = { | |||
426 | SIL24_FLAG_PCIX_IRQ_WOC, | 426 | SIL24_FLAG_PCIX_IRQ_WOC, |
427 | .pio_mask = 0x1f, /* pio0-4 */ | 427 | .pio_mask = 0x1f, /* pio0-4 */ |
428 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 428 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
429 | .udma_mask = 0x3f, /* udma0-5 */ | 429 | .udma_mask = ATA_UDMA5, /* udma0-5 */ |
430 | .port_ops = &sil24_ops, | 430 | .port_ops = &sil24_ops, |
431 | }, | 431 | }, |
432 | /* sil_3132 */ | 432 | /* sil_3132 */ |
@@ -434,7 +434,7 @@ static const struct ata_port_info sil24_port_info[] = { | |||
434 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), | 434 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), |
435 | .pio_mask = 0x1f, /* pio0-4 */ | 435 | .pio_mask = 0x1f, /* pio0-4 */ |
436 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 436 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
437 | .udma_mask = 0x3f, /* udma0-5 */ | 437 | .udma_mask = ATA_UDMA5, /* udma0-5 */ |
438 | .port_ops = &sil24_ops, | 438 | .port_ops = &sil24_ops, |
439 | }, | 439 | }, |
440 | /* sil_3131/sil_3531 */ | 440 | /* sil_3131/sil_3531 */ |
@@ -442,7 +442,7 @@ static const struct ata_port_info sil24_port_info[] = { | |||
442 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), | 442 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), |
443 | .pio_mask = 0x1f, /* pio0-4 */ | 443 | .pio_mask = 0x1f, /* pio0-4 */ |
444 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 444 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
445 | .udma_mask = 0x3f, /* udma0-5 */ | 445 | .udma_mask = ATA_UDMA5, /* udma0-5 */ |
446 | .port_ops = &sil24_ops, | 446 | .port_ops = &sil24_ops, |
447 | }, | 447 | }, |
448 | }; | 448 | }; |
@@ -888,7 +888,7 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) | |||
888 | if (status & (1 << i)) { | 888 | if (status & (1 << i)) { |
889 | struct ata_port *ap = host->ports[i]; | 889 | struct ata_port *ap = host->ports[i]; |
890 | if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { | 890 | if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { |
891 | sil24_host_intr(host->ports[i]); | 891 | sil24_host_intr(ap); |
892 | handled++; | 892 | handled++; |
893 | } else | 893 | } else |
894 | printk(KERN_ERR DRV_NAME | 894 | printk(KERN_ERR DRV_NAME |
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index f111c984a359..fd80bcf1b236 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c | |||
@@ -133,7 +133,7 @@ static const struct ata_port_info sis_port_info = { | |||
133 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | 133 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, |
134 | .pio_mask = 0x1f, | 134 | .pio_mask = 0x1f, |
135 | .mwdma_mask = 0x7, | 135 | .mwdma_mask = 0x7, |
136 | .udma_mask = 0x7f, | 136 | .udma_mask = ATA_UDMA6, |
137 | .port_ops = &sis_ops, | 137 | .port_ops = &sis_ops, |
138 | }; | 138 | }; |
139 | 139 | ||
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index bcb2cd8b063d..63fe99afd59f 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c | |||
@@ -107,7 +107,7 @@ static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) | |||
107 | { | 107 | { |
108 | if (sc_reg > SCR_CONTROL) | 108 | if (sc_reg > SCR_CONTROL) |
109 | return 0xffffffffU; | 109 | return 0xffffffffU; |
110 | return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); | 110 | return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); |
111 | } | 111 | } |
112 | 112 | ||
113 | 113 | ||
@@ -116,7 +116,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, | |||
116 | { | 116 | { |
117 | if (sc_reg > SCR_CONTROL) | 117 | if (sc_reg > SCR_CONTROL) |
118 | return; | 118 | return; |
119 | writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); | 119 | writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); |
120 | } | 120 | } |
121 | 121 | ||
122 | 122 | ||
@@ -197,7 +197,8 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc) | |||
197 | struct ata_port *ap = qc->ap; | 197 | struct ata_port *ap = qc->ap; |
198 | unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); | 198 | unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); |
199 | u8 dmactl; | 199 | u8 dmactl; |
200 | void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; | 200 | void __iomem *mmio = ap->ioaddr.bmdma_addr; |
201 | |||
201 | /* load PRD table addr. */ | 202 | /* load PRD table addr. */ |
202 | mb(); /* make sure PRD table writes are visible to controller */ | 203 | mb(); /* make sure PRD table writes are visible to controller */ |
203 | writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); | 204 | writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); |
@@ -225,7 +226,7 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc) | |||
225 | static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) | 226 | static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) |
226 | { | 227 | { |
227 | struct ata_port *ap = qc->ap; | 228 | struct ata_port *ap = qc->ap; |
228 | void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; | 229 | void __iomem *mmio = ap->ioaddr.bmdma_addr; |
229 | u8 dmactl; | 230 | u8 dmactl; |
230 | 231 | ||
231 | /* start host DMA transaction */ | 232 | /* start host DMA transaction */ |
@@ -253,7 +254,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) | |||
253 | 254 | ||
254 | static u8 k2_stat_check_status(struct ata_port *ap) | 255 | static u8 k2_stat_check_status(struct ata_port *ap) |
255 | { | 256 | { |
256 | return readl((void __iomem *) ap->ioaddr.status_addr); | 257 | return readl(ap->ioaddr.status_addr); |
257 | } | 258 | } |
258 | 259 | ||
259 | #ifdef CONFIG_PPC_OF | 260 | #ifdef CONFIG_PPC_OF |
@@ -360,7 +361,7 @@ static const struct ata_port_info k2_port_info[] = { | |||
360 | ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA, | 361 | ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA, |
361 | .pio_mask = 0x1f, | 362 | .pio_mask = 0x1f, |
362 | .mwdma_mask = 0x07, | 363 | .mwdma_mask = 0x07, |
363 | .udma_mask = 0x7f, | 364 | .udma_mask = ATA_UDMA6, |
364 | .port_ops = &k2_sata_ops, | 365 | .port_ops = &k2_sata_ops, |
365 | }, | 366 | }, |
366 | /* board_svw8 */ | 367 | /* board_svw8 */ |
@@ -370,7 +371,7 @@ static const struct ata_port_info k2_port_info[] = { | |||
370 | K2_FLAG_SATA_8_PORTS, | 371 | K2_FLAG_SATA_8_PORTS, |
371 | .pio_mask = 0x1f, | 372 | .pio_mask = 0x1f, |
372 | .mwdma_mask = 0x07, | 373 | .mwdma_mask = 0x07, |
373 | .udma_mask = 0x7f, | 374 | .udma_mask = ATA_UDMA6, |
374 | .port_ops = &k2_sata_ops, | 375 | .port_ops = &k2_sata_ops, |
375 | }, | 376 | }, |
376 | }; | 377 | }; |
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 2d14f3d56d92..5193bd8647ba 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c | |||
@@ -30,6 +30,54 @@ | |||
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | 32 | ||
33 | /* | ||
34 | Theory of operation | ||
35 | ------------------- | ||
36 | |||
37 | The SX4 (PDC20621) chip features a single Host DMA (HDMA) copy | ||
38 | engine, DIMM memory, and four ATA engines (one per SATA port). | ||
39 | Data is copied to/from DIMM memory by the HDMA engine, before | ||
40 | handing off to one (or more) of the ATA engines. The ATA | ||
41 | engines operate solely on DIMM memory. | ||
42 | |||
43 | The SX4 behaves like a PATA chip, with no SATA controls or | ||
44 | knowledge whatsoever, leading to the presumption that | ||
45 | PATA<->SATA bridges exist on SX4 boards, external to the | ||
46 | PDC20621 chip itself. | ||
47 | |||
48 | The chip is quite capable, supporting an XOR engine and linked | ||
49 | hardware commands (permits a string to transactions to be | ||
50 | submitted and waited-on as a single unit), and an optional | ||
51 | microprocessor. | ||
52 | |||
53 | The limiting factor is largely software. This Linux driver was | ||
54 | written to multiplex the single HDMA engine to copy disk | ||
55 | transactions into a fixed DIMM memory space, from where an ATA | ||
56 | engine takes over. As a result, each WRITE looks like this: | ||
57 | |||
58 | submit HDMA packet to hardware | ||
59 | hardware copies data from system memory to DIMM | ||
60 | hardware raises interrupt | ||
61 | |||
62 | submit ATA packet to hardware | ||
63 | hardware executes ATA WRITE command, w/ data in DIMM | ||
64 | hardware raises interrupt | ||
65 | |||
66 | and each READ looks like this: | ||
67 | |||
68 | submit ATA packet to hardware | ||
69 | hardware executes ATA READ command, w/ data in DIMM | ||
70 | hardware raises interrupt | ||
71 | |||
72 | submit HDMA packet to hardware | ||
73 | hardware copies data from DIMM to system memory | ||
74 | hardware raises interrupt | ||
75 | |||
76 | This is a very slow, lock-step way of doing things that can | ||
77 | certainly be improved by motivated kernel hackers. | ||
78 | |||
79 | */ | ||
80 | |||
33 | #include <linux/kernel.h> | 81 | #include <linux/kernel.h> |
34 | #include <linux/module.h> | 82 | #include <linux/module.h> |
35 | #include <linux/pci.h> | 83 | #include <linux/pci.h> |
@@ -58,6 +106,8 @@ enum { | |||
58 | PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ | 106 | PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ |
59 | PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */ | 107 | PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */ |
60 | 108 | ||
109 | PDC_CTLSTAT = 0x60, /* IDEn control / status */ | ||
110 | |||
61 | PDC_20621_SEQCTL = 0x400, | 111 | PDC_20621_SEQCTL = 0x400, |
62 | PDC_20621_SEQMASK = 0x480, | 112 | PDC_20621_SEQMASK = 0x480, |
63 | PDC_20621_GENERAL_CTL = 0x484, | 113 | PDC_20621_GENERAL_CTL = 0x484, |
@@ -87,48 +137,60 @@ enum { | |||
87 | 137 | ||
88 | board_20621 = 0, /* FastTrak S150 SX4 */ | 138 | board_20621 = 0, /* FastTrak S150 SX4 */ |
89 | 139 | ||
90 | PDC_RESET = (1 << 11), /* HDMA reset */ | 140 | PDC_MASK_INT = (1 << 10), /* HDMA/ATA mask int */ |
141 | PDC_RESET = (1 << 11), /* HDMA/ATA reset */ | ||
142 | PDC_DMA_ENABLE = (1 << 7), /* DMA start/stop */ | ||
91 | 143 | ||
92 | PDC_MAX_HDMA = 32, | 144 | PDC_MAX_HDMA = 32, |
93 | PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1), | 145 | PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1), |
94 | 146 | ||
95 | PDC_DIMM0_SPD_DEV_ADDRESS = 0x50, | 147 | PDC_DIMM0_SPD_DEV_ADDRESS = 0x50, |
96 | PDC_DIMM1_SPD_DEV_ADDRESS = 0x51, | 148 | PDC_DIMM1_SPD_DEV_ADDRESS = 0x51, |
97 | PDC_MAX_DIMM_MODULE = 0x02, | 149 | PDC_I2C_CONTROL = 0x48, |
98 | PDC_I2C_CONTROL_OFFSET = 0x48, | 150 | PDC_I2C_ADDR_DATA = 0x4C, |
99 | PDC_I2C_ADDR_DATA_OFFSET = 0x4C, | 151 | PDC_DIMM0_CONTROL = 0x80, |
100 | PDC_DIMM0_CONTROL_OFFSET = 0x80, | 152 | PDC_DIMM1_CONTROL = 0x84, |
101 | PDC_DIMM1_CONTROL_OFFSET = 0x84, | 153 | PDC_SDRAM_CONTROL = 0x88, |
102 | PDC_SDRAM_CONTROL_OFFSET = 0x88, | 154 | PDC_I2C_WRITE = 0, /* master -> slave */ |
103 | PDC_I2C_WRITE = 0x00000000, | 155 | PDC_I2C_READ = (1 << 6), /* master <- slave */ |
104 | PDC_I2C_READ = 0x00000040, | 156 | PDC_I2C_START = (1 << 7), /* start I2C proto */ |
105 | PDC_I2C_START = 0x00000080, | 157 | PDC_I2C_MASK_INT = (1 << 5), /* mask I2C interrupt */ |
106 | PDC_I2C_MASK_INT = 0x00000020, | 158 | PDC_I2C_COMPLETE = (1 << 16), /* I2C normal compl. */ |
107 | PDC_I2C_COMPLETE = 0x00010000, | 159 | PDC_I2C_NO_ACK = (1 << 20), /* slave no-ack addr */ |
108 | PDC_I2C_NO_ACK = 0x00100000, | 160 | PDC_DIMM_SPD_SUBADDRESS_START = 0x00, |
109 | PDC_DIMM_SPD_SUBADDRESS_START = 0x00, | 161 | PDC_DIMM_SPD_SUBADDRESS_END = 0x7F, |
110 | PDC_DIMM_SPD_SUBADDRESS_END = 0x7F, | 162 | PDC_DIMM_SPD_ROW_NUM = 3, |
111 | PDC_DIMM_SPD_ROW_NUM = 3, | 163 | PDC_DIMM_SPD_COLUMN_NUM = 4, |
112 | PDC_DIMM_SPD_COLUMN_NUM = 4, | 164 | PDC_DIMM_SPD_MODULE_ROW = 5, |
113 | PDC_DIMM_SPD_MODULE_ROW = 5, | 165 | PDC_DIMM_SPD_TYPE = 11, |
114 | PDC_DIMM_SPD_TYPE = 11, | 166 | PDC_DIMM_SPD_FRESH_RATE = 12, |
115 | PDC_DIMM_SPD_FRESH_RATE = 12, | 167 | PDC_DIMM_SPD_BANK_NUM = 17, |
116 | PDC_DIMM_SPD_BANK_NUM = 17, | 168 | PDC_DIMM_SPD_CAS_LATENCY = 18, |
117 | PDC_DIMM_SPD_CAS_LATENCY = 18, | 169 | PDC_DIMM_SPD_ATTRIBUTE = 21, |
118 | PDC_DIMM_SPD_ATTRIBUTE = 21, | 170 | PDC_DIMM_SPD_ROW_PRE_CHARGE = 27, |
119 | PDC_DIMM_SPD_ROW_PRE_CHARGE = 27, | 171 | PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, |
120 | PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, | 172 | PDC_DIMM_SPD_RAS_CAS_DELAY = 29, |
121 | PDC_DIMM_SPD_RAS_CAS_DELAY = 29, | 173 | PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30, |
122 | PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30, | 174 | PDC_DIMM_SPD_SYSTEM_FREQ = 126, |
123 | PDC_DIMM_SPD_SYSTEM_FREQ = 126, | 175 | PDC_CTL_STATUS = 0x08, |
124 | PDC_CTL_STATUS = 0x08, | 176 | PDC_DIMM_WINDOW_CTLR = 0x0C, |
125 | PDC_DIMM_WINDOW_CTLR = 0x0C, | 177 | PDC_TIME_CONTROL = 0x3C, |
126 | PDC_TIME_CONTROL = 0x3C, | 178 | PDC_TIME_PERIOD = 0x40, |
127 | PDC_TIME_PERIOD = 0x40, | 179 | PDC_TIME_COUNTER = 0x44, |
128 | PDC_TIME_COUNTER = 0x44, | 180 | PDC_GENERAL_CTLR = 0x484, |
129 | PDC_GENERAL_CTLR = 0x484, | 181 | PCI_PLL_INIT = 0x8A531824, |
130 | PCI_PLL_INIT = 0x8A531824, | 182 | PCI_X_TCOUNT = 0xEE1E5CFF, |
131 | PCI_X_TCOUNT = 0xEE1E5CFF | 183 | |
184 | /* PDC_TIME_CONTROL bits */ | ||
185 | PDC_TIMER_BUZZER = (1 << 10), | ||
186 | PDC_TIMER_MODE_PERIODIC = 0, /* bits 9:8 == 00 */ | ||
187 | PDC_TIMER_MODE_ONCE = (1 << 8), /* bits 9:8 == 01 */ | ||
188 | PDC_TIMER_ENABLE = (1 << 7), | ||
189 | PDC_TIMER_MASK_INT = (1 << 5), | ||
190 | PDC_TIMER_SEQ_MASK = 0x1f, /* SEQ ID for timer */ | ||
191 | PDC_TIMER_DEFAULT = PDC_TIMER_MODE_ONCE | | ||
192 | PDC_TIMER_ENABLE | | ||
193 | PDC_TIMER_MASK_INT, | ||
132 | }; | 194 | }; |
133 | 195 | ||
134 | 196 | ||
@@ -217,7 +279,7 @@ static const struct ata_port_info pdc_port_info[] = { | |||
217 | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, | 279 | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, |
218 | .pio_mask = 0x1f, /* pio0-4 */ | 280 | .pio_mask = 0x1f, /* pio0-4 */ |
219 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 281 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
220 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 282 | .udma_mask = ATA_UDMA6, |
221 | .port_ops = &pdc_20621_ops, | 283 | .port_ops = &pdc_20621_ops, |
222 | }, | 284 | }, |
223 | 285 | ||
@@ -999,17 +1061,17 @@ static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device, | |||
999 | i2creg |= subaddr << 16; | 1061 | i2creg |= subaddr << 16; |
1000 | 1062 | ||
1001 | /* Set the device and subaddress */ | 1063 | /* Set the device and subaddress */ |
1002 | writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET); | 1064 | writel(i2creg, mmio + PDC_I2C_ADDR_DATA); |
1003 | readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); | 1065 | readl(mmio + PDC_I2C_ADDR_DATA); |
1004 | 1066 | ||
1005 | /* Write Control to perform read operation, mask int */ | 1067 | /* Write Control to perform read operation, mask int */ |
1006 | writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, | 1068 | writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, |
1007 | mmio + PDC_I2C_CONTROL_OFFSET); | 1069 | mmio + PDC_I2C_CONTROL); |
1008 | 1070 | ||
1009 | for (count = 0; count <= 1000; count ++) { | 1071 | for (count = 0; count <= 1000; count ++) { |
1010 | status = readl(mmio + PDC_I2C_CONTROL_OFFSET); | 1072 | status = readl(mmio + PDC_I2C_CONTROL); |
1011 | if (status & PDC_I2C_COMPLETE) { | 1073 | if (status & PDC_I2C_COMPLETE) { |
1012 | status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); | 1074 | status = readl(mmio + PDC_I2C_ADDR_DATA); |
1013 | break; | 1075 | break; |
1014 | } else if (count == 1000) | 1076 | } else if (count == 1000) |
1015 | return 0; | 1077 | return 0; |
@@ -1099,8 +1161,8 @@ static int pdc20621_prog_dimm0(struct ata_host *host) | |||
1099 | data |= (((size / 16) - 1) << 16); | 1161 | data |= (((size / 16) - 1) << 16); |
1100 | data |= (0 << 23); | 1162 | data |= (0 << 23); |
1101 | data |= 8; | 1163 | data |= 8; |
1102 | writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); | 1164 | writel(data, mmio + PDC_DIMM0_CONTROL); |
1103 | readl(mmio + PDC_DIMM0_CONTROL_OFFSET); | 1165 | readl(mmio + PDC_DIMM0_CONTROL); |
1104 | return size; | 1166 | return size; |
1105 | } | 1167 | } |
1106 | 1168 | ||
@@ -1122,27 +1184,27 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host) | |||
1122 | */ | 1184 | */ |
1123 | 1185 | ||
1124 | data = 0x022259F1; | 1186 | data = 0x022259F1; |
1125 | writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); | 1187 | writel(data, mmio + PDC_SDRAM_CONTROL); |
1126 | readl(mmio + PDC_SDRAM_CONTROL_OFFSET); | 1188 | readl(mmio + PDC_SDRAM_CONTROL); |
1127 | 1189 | ||
1128 | /* Turn on for ECC */ | 1190 | /* Turn on for ECC */ |
1129 | pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, | 1191 | pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, |
1130 | PDC_DIMM_SPD_TYPE, &spd0); | 1192 | PDC_DIMM_SPD_TYPE, &spd0); |
1131 | if (spd0 == 0x02) { | 1193 | if (spd0 == 0x02) { |
1132 | data |= (0x01 << 16); | 1194 | data |= (0x01 << 16); |
1133 | writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); | 1195 | writel(data, mmio + PDC_SDRAM_CONTROL); |
1134 | readl(mmio + PDC_SDRAM_CONTROL_OFFSET); | 1196 | readl(mmio + PDC_SDRAM_CONTROL); |
1135 | printk(KERN_ERR "Local DIMM ECC Enabled\n"); | 1197 | printk(KERN_ERR "Local DIMM ECC Enabled\n"); |
1136 | } | 1198 | } |
1137 | 1199 | ||
1138 | /* DIMM Initialization Select/Enable (bit 18/19) */ | 1200 | /* DIMM Initialization Select/Enable (bit 18/19) */ |
1139 | data &= (~(1<<18)); | 1201 | data &= (~(1<<18)); |
1140 | data |= (1<<19); | 1202 | data |= (1<<19); |
1141 | writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); | 1203 | writel(data, mmio + PDC_SDRAM_CONTROL); |
1142 | 1204 | ||
1143 | error = 1; | 1205 | error = 1; |
1144 | for (i = 1; i <= 10; i++) { /* polling ~5 secs */ | 1206 | for (i = 1; i <= 10; i++) { /* polling ~5 secs */ |
1145 | data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET); | 1207 | data = readl(mmio + PDC_SDRAM_CONTROL); |
1146 | if (!(data & (1<<19))) { | 1208 | if (!(data & (1<<19))) { |
1147 | error = 0; | 1209 | error = 0; |
1148 | break; | 1210 | break; |
@@ -1176,7 +1238,7 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) | |||
1176 | VPRINTK("Time Period Register (0x40): 0x%x\n", time_period); | 1238 | VPRINTK("Time Period Register (0x40): 0x%x\n", time_period); |
1177 | 1239 | ||
1178 | /* Enable timer */ | 1240 | /* Enable timer */ |
1179 | writel(0x00001a0, mmio + PDC_TIME_CONTROL); | 1241 | writel(PDC_TIMER_DEFAULT, mmio + PDC_TIME_CONTROL); |
1180 | readl(mmio + PDC_TIME_CONTROL); | 1242 | readl(mmio + PDC_TIME_CONTROL); |
1181 | 1243 | ||
1182 | /* Wait 3 seconds */ | 1244 | /* Wait 3 seconds */ |
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 6815de7cca79..aca71819f6e8 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c | |||
@@ -129,7 +129,7 @@ static const struct ata_port_info uli_port_info = { | |||
129 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 129 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
130 | ATA_FLAG_IGN_SIMPLEX, | 130 | ATA_FLAG_IGN_SIMPLEX, |
131 | .pio_mask = 0x1f, /* pio0-4 */ | 131 | .pio_mask = 0x1f, /* pio0-4 */ |
132 | .udma_mask = 0x7f, /* udma0-6 */ | 132 | .udma_mask = ATA_UDMA6, |
133 | .port_ops = &uli_ops, | 133 | .port_ops = &uli_ops, |
134 | }; | 134 | }; |
135 | 135 | ||
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index e8b90e7b42dd..a4c0832033d8 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c | |||
@@ -223,7 +223,7 @@ static const struct ata_port_info vt6420_port_info = { | |||
223 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | 223 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, |
224 | .pio_mask = 0x1f, | 224 | .pio_mask = 0x1f, |
225 | .mwdma_mask = 0x07, | 225 | .mwdma_mask = 0x07, |
226 | .udma_mask = 0x7f, | 226 | .udma_mask = ATA_UDMA6, |
227 | .port_ops = &vt6420_sata_ops, | 227 | .port_ops = &vt6420_sata_ops, |
228 | }; | 228 | }; |
229 | 229 | ||
@@ -231,7 +231,7 @@ static struct ata_port_info vt6421_sport_info = { | |||
231 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | 231 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, |
232 | .pio_mask = 0x1f, | 232 | .pio_mask = 0x1f, |
233 | .mwdma_mask = 0x07, | 233 | .mwdma_mask = 0x07, |
234 | .udma_mask = 0x7f, | 234 | .udma_mask = ATA_UDMA6, |
235 | .port_ops = &vt6421_sata_ops, | 235 | .port_ops = &vt6421_sata_ops, |
236 | }; | 236 | }; |
237 | 237 | ||
@@ -239,7 +239,7 @@ static struct ata_port_info vt6421_pport_info = { | |||
239 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY, | 239 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY, |
240 | .pio_mask = 0x1f, | 240 | .pio_mask = 0x1f, |
241 | .mwdma_mask = 0, | 241 | .mwdma_mask = 0, |
242 | .udma_mask = 0x7f, | 242 | .udma_mask = ATA_UDMA6, |
243 | .port_ops = &vt6421_pata_ops, | 243 | .port_ops = &vt6421_pata_ops, |
244 | }; | 244 | }; |
245 | 245 | ||
@@ -303,9 +303,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) | |||
303 | if (!(ap->pflags & ATA_PFLAG_LOADING)) | 303 | if (!(ap->pflags & ATA_PFLAG_LOADING)) |
304 | goto skip_scr; | 304 | goto skip_scr; |
305 | 305 | ||
306 | /* Resume phy. This is the old resume sequence from | 306 | /* Resume phy. This is the old SATA resume sequence */ |
307 | * __sata_phy_reset(). | ||
308 | */ | ||
309 | svia_scr_write(ap, SCR_CONTROL, 0x300); | 307 | svia_scr_write(ap, SCR_CONTROL, 0x300); |
310 | svia_scr_read(ap, SCR_CONTROL); /* flush */ | 308 | svia_scr_read(ap, SCR_CONTROL); /* flush */ |
311 | 309 | ||
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 81330175fc89..1b5d81faa102 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c | |||
@@ -371,7 +371,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d | |||
371 | ATA_FLAG_MMIO, | 371 | ATA_FLAG_MMIO, |
372 | .pio_mask = 0x1f, | 372 | .pio_mask = 0x1f, |
373 | .mwdma_mask = 0x07, | 373 | .mwdma_mask = 0x07, |
374 | .udma_mask = 0x7f, | 374 | .udma_mask = ATA_UDMA6, |
375 | .port_ops = &vsc_sata_ops, | 375 | .port_ops = &vsc_sata_ops, |
376 | }; | 376 | }; |
377 | const struct ata_port_info *ppi[] = { &pi, NULL }; | 377 | const struct ata_port_info *ppi[] = { &pi, NULL }; |
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index b4c8319138b2..6e23af1ecbdb 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig | |||
@@ -2,9 +2,12 @@ | |||
2 | # Block device driver configuration | 2 | # Block device driver configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | if BLOCK | 5 | menuconfig BLK_DEV |
6 | bool "Block devices" | ||
7 | depends on BLOCK | ||
8 | default y | ||
6 | 9 | ||
7 | menu "Block devices" | 10 | if BLK_DEV |
8 | 11 | ||
9 | config BLK_DEV_FD | 12 | config BLK_DEV_FD |
10 | tristate "Normal floppy disk support" | 13 | tristate "Normal floppy disk support" |
@@ -56,40 +59,9 @@ config AMIGA_Z2RAM | |||
56 | To compile this driver as a module, choose M here: the | 59 | To compile this driver as a module, choose M here: the |
57 | module will be called z2ram. | 60 | module will be called z2ram. |
58 | 61 | ||
59 | config ATARI_ACSI | ||
60 | tristate "Atari ACSI support" | ||
61 | depends on ATARI && BROKEN | ||
62 | ---help--- | ||
63 | This enables support for the Atari ACSI interface. The driver | ||
64 | supports hard disks and CD-ROMs, which have 512-byte sectors, or can | ||
65 | be switched to that mode. Due to the ACSI command format, only disks | ||
66 | up to 1 GB are supported. Special support for certain ACSI to SCSI | ||
67 | adapters, which could relax that, isn't included yet. The ACSI | ||
68 | driver is also the basis for certain other drivers for devices | ||
69 | attached to the ACSI bus: Atari SLM laser printer, BioNet-100 | ||
70 | Ethernet, and PAMsNet Ethernet. If you want to use one of these | ||
71 | devices, you need ACSI support, too. | ||
72 | |||
73 | To compile this driver as a module, choose M here: the | ||
74 | module will be called acsi. | ||
75 | |||
76 | comment "Some devices (e.g. CD jukebox) support multiple LUNs" | ||
77 | depends on ATARI && ATARI_ACSI | ||
78 | |||
79 | config ACSI_MULTI_LUN | ||
80 | bool "Probe all LUNs on each ACSI device" | ||
81 | depends on ATARI_ACSI | ||
82 | help | ||
83 | If you have a ACSI device that supports more than one LUN (Logical | ||
84 | Unit Number), e.g. a CD jukebox, you should say Y here so that all | ||
85 | will be found by the ACSI driver. An ACSI device with multiple LUNs | ||
86 | acts logically like multiple ACSI devices. The vast majority of ACSI | ||
87 | devices have only one LUN, and so most people can say N here and | ||
88 | should in fact do so, because it is safer. | ||
89 | |||
90 | config ATARI_SLM | 62 | config ATARI_SLM |
91 | tristate "Atari SLM laser printer support" | 63 | tristate "Atari SLM laser printer support" |
92 | depends on ATARI && ATARI_ACSI!=n | 64 | depends on ATARI |
93 | help | 65 | help |
94 | If you have an Atari SLM laser printer, say Y to include support for | 66 | If you have an Atari SLM laser printer, say Y to include support for |
95 | it in the kernel. Otherwise, say N. This driver is also available as | 67 | it in the kernel. Otherwise, say N. This driver is also available as |
@@ -453,6 +425,4 @@ config ATA_OVER_ETH | |||
453 | 425 | ||
454 | source "drivers/s390/block/Kconfig" | 426 | source "drivers/s390/block/Kconfig" |
455 | 427 | ||
456 | endmenu | 428 | endif # BLK_DEV |
457 | |||
458 | endif | ||
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index dd88e33c1eb1..e5f98acc5d52 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile | |||
@@ -9,7 +9,6 @@ obj-$(CONFIG_MAC_FLOPPY) += swim3.o | |||
9 | obj-$(CONFIG_BLK_DEV_FD) += floppy.o | 9 | obj-$(CONFIG_BLK_DEV_FD) += floppy.o |
10 | obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o | 10 | obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o |
11 | obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o | 11 | obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o |
12 | obj-$(CONFIG_ATARI_ACSI) += acsi.o | ||
13 | obj-$(CONFIG_ATARI_SLM) += acsi_slm.o | 12 | obj-$(CONFIG_ATARI_SLM) += acsi_slm.o |
14 | obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o | 13 | obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o |
15 | obj-$(CONFIG_BLK_DEV_RAM) += rd.o | 14 | obj-$(CONFIG_BLK_DEV_RAM) += rd.o |
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c deleted file mode 100644 index e3d9152e231a..000000000000 --- a/drivers/block/acsi.c +++ /dev/null | |||
@@ -1,1825 +0,0 @@ | |||
1 | /* | ||
2 | * acsi.c -- Device driver for Atari ACSI hard disks | ||
3 | * | ||
4 | * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> | ||
5 | * | ||
6 | * Some parts are based on hd.c by Linus Torvalds | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file COPYING in the main directory of this archive for | ||
10 | * more details. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * Still to in this file: | ||
16 | * - If a command ends with an error status (!= 0), the following | ||
17 | * REQUEST SENSE commands (4 to fill the ST-DMA FIFO) are done by | ||
18 | * polling the _IRQ signal (not interrupt-driven). This should be | ||
19 | * avoided in future because it takes up a non-neglectible time in | ||
20 | * the interrupt service routine while interrupts are disabled. | ||
21 | * Maybe a timer interrupt will get lost :-( | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * General notes: | ||
26 | * | ||
27 | * - All ACSI devices (disks, CD-ROMs, ...) use major number 28. | ||
28 | * Minors are organized like it is with SCSI: The upper 4 bits | ||
29 | * identify the device, the lower 4 bits the partition. | ||
30 | * The device numbers (the upper 4 bits) are given in the same | ||
31 | * order as the devices are found on the bus. | ||
32 | * - Up to 8 LUNs are supported for each target (if CONFIG_ACSI_MULTI_LUN | ||
33 | * is defined), but only a total of 16 devices (due to minor | ||
34 | * numbers...). Note that Atari allows only a maximum of 4 targets | ||
35 | * (i.e. controllers, not devices) on the ACSI bus! | ||
36 | * - A optimizing scheme similar to SCSI scatter-gather is implemented. | ||
37 | * - Removable media are supported. After a medium change to device | ||
38 | * is reinitialized (partition check etc.). Also, if the device | ||
39 | * knows the PREVENT/ALLOW MEDIUM REMOVAL command, the door should | ||
40 | * be locked and unlocked when mounting the first or unmounting the | ||
41 | * last filesystem on the device. The code is untested, because I | ||
42 | * don't have a removable hard disk. | ||
43 | * | ||
44 | */ | ||
45 | |||
46 | #include <linux/module.h> | ||
47 | #include <linux/errno.h> | ||
48 | #include <linux/signal.h> | ||
49 | #include <linux/timer.h> | ||
50 | #include <linux/fs.h> | ||
51 | #include <linux/kernel.h> | ||
52 | #include <linux/genhd.h> | ||
53 | #include <linux/delay.h> | ||
54 | #include <linux/mm.h> | ||
55 | #include <linux/major.h> | ||
56 | #include <linux/slab.h> | ||
57 | #include <linux/interrupt.h> | ||
58 | #include <scsi/scsi.h> /* for SCSI_IOCTL_GET_IDLUN */ | ||
59 | #include <scsi/scsi_ioctl.h> | ||
60 | #include <linux/hdreg.h> /* for HDIO_GETGEO */ | ||
61 | #include <linux/blkpg.h> | ||
62 | #include <linux/buffer_head.h> | ||
63 | #include <linux/blkdev.h> | ||
64 | |||
65 | #include <asm/setup.h> | ||
66 | #include <asm/pgtable.h> | ||
67 | #include <asm/system.h> | ||
68 | #include <asm/uaccess.h> | ||
69 | #include <asm/atarihw.h> | ||
70 | #include <asm/atariints.h> | ||
71 | #include <asm/atari_acsi.h> | ||
72 | #include <asm/atari_stdma.h> | ||
73 | #include <asm/atari_stram.h> | ||
74 | |||
75 | static void (*do_acsi)(void) = NULL; | ||
76 | static struct request_queue *acsi_queue; | ||
77 | #define QUEUE (acsi_queue) | ||
78 | #define CURRENT elv_next_request(acsi_queue) | ||
79 | |||
80 | #define DEBUG | ||
81 | #undef DEBUG_DETECT | ||
82 | #undef NO_WRITE | ||
83 | |||
84 | #define MAX_ERRORS 8 /* Max read/write errors/sector */ | ||
85 | #define MAX_LUN 8 /* Max LUNs per target */ | ||
86 | #define MAX_DEV 16 | ||
87 | |||
88 | #define ACSI_BUFFER_SIZE (16*1024) /* "normal" ACSI buffer size */ | ||
89 | #define ACSI_BUFFER_MINSIZE (2048) /* min. buf size if ext. DMA */ | ||
90 | #define ACSI_BUFFER_SIZE_ORDER 2 /* order size for above */ | ||
91 | #define ACSI_BUFFER_MINSIZE_ORDER 0 /* order size for above */ | ||
92 | #define ACSI_BUFFER_SECTORS (ACSI_BUFFER_SIZE/512) | ||
93 | |||
94 | #define ACSI_BUFFER_ORDER \ | ||
95 | (ATARIHW_PRESENT(EXTD_DMA) ? \ | ||
96 | ACSI_BUFFER_MINSIZE_ORDER : \ | ||
97 | ACSI_BUFFER_SIZE_ORDER) | ||
98 | |||
99 | #define ACSI_TIMEOUT (4*HZ) | ||
100 | |||
101 | /* minimum delay between two commands */ | ||
102 | |||
103 | #define COMMAND_DELAY 500 | ||
104 | |||
105 | typedef enum { | ||
106 | NONE, HARDDISK, CDROM | ||
107 | } ACSI_TYPE; | ||
108 | |||
109 | struct acsi_info_struct { | ||
110 | ACSI_TYPE type; /* type of device */ | ||
111 | unsigned target; /* target number */ | ||
112 | unsigned lun; /* LUN in target controller */ | ||
113 | unsigned removable : 1; /* Flag for removable media */ | ||
114 | unsigned read_only : 1; /* Flag for read only devices */ | ||
115 | unsigned old_atari_disk : 1; /* Is an old Atari disk */ | ||
116 | unsigned changed : 1; /* Medium has been changed */ | ||
117 | unsigned long size; /* #blocks */ | ||
118 | int access_count; | ||
119 | } acsi_info[MAX_DEV]; | ||
120 | |||
121 | /* | ||
122 | * SENSE KEYS | ||
123 | */ | ||
124 | |||
125 | #define NO_SENSE 0x00 | ||
126 | #define RECOVERED_ERROR 0x01 | ||
127 | #define NOT_READY 0x02 | ||
128 | #define MEDIUM_ERROR 0x03 | ||
129 | #define HARDWARE_ERROR 0x04 | ||
130 | #define ILLEGAL_REQUEST 0x05 | ||
131 | #define UNIT_ATTENTION 0x06 | ||
132 | #define DATA_PROTECT 0x07 | ||
133 | #define BLANK_CHECK 0x08 | ||
134 | #define COPY_ABORTED 0x0a | ||
135 | #define ABORTED_COMMAND 0x0b | ||
136 | #define VOLUME_OVERFLOW 0x0d | ||
137 | #define MISCOMPARE 0x0e | ||
138 | |||
139 | |||
140 | /* | ||
141 | * DEVICE TYPES | ||
142 | */ | ||
143 | |||
144 | #define TYPE_DISK 0x00 | ||
145 | #define TYPE_TAPE 0x01 | ||
146 | #define TYPE_WORM 0x04 | ||
147 | #define TYPE_ROM 0x05 | ||
148 | #define TYPE_MOD 0x07 | ||
149 | #define TYPE_NO_LUN 0x7f | ||
150 | |||
151 | /* The data returned by MODE SENSE differ between the old Atari | ||
152 | * hard disks and SCSI disks connected to ACSI. In the following, both | ||
153 | * formats are defined and some macros to operate on them potably. | ||
154 | */ | ||
155 | |||
156 | typedef struct { | ||
157 | unsigned long dummy[2]; | ||
158 | unsigned long sector_size; | ||
159 | unsigned char format_code; | ||
160 | #define ATARI_SENSE_FORMAT_FIX 1 | ||
161 | #define ATARI_SENSE_FORMAT_CHNG 2 | ||
162 | unsigned char cylinders_h; | ||
163 | unsigned char cylinders_l; | ||
164 | unsigned char heads; | ||
165 | unsigned char reduced_h; | ||
166 | unsigned char reduced_l; | ||
167 | unsigned char precomp_h; | ||
168 | unsigned char precomp_l; | ||
169 | unsigned char landing_zone; | ||
170 | unsigned char steprate; | ||
171 | unsigned char type; | ||
172 | #define ATARI_SENSE_TYPE_FIXCHNG_MASK 4 | ||
173 | #define ATARI_SENSE_TYPE_SOFTHARD_MASK 8 | ||
174 | #define ATARI_SENSE_TYPE_FIX 4 | ||
175 | #define ATARI_SENSE_TYPE_CHNG 0 | ||
176 | #define ATARI_SENSE_TYPE_SOFT 0 | ||
177 | #define ATARI_SENSE_TYPE_HARD 8 | ||
178 | unsigned char sectors; | ||
179 | } ATARI_SENSE_DATA; | ||
180 | |||
181 | #define ATARI_CAPACITY(sd) \ | ||
182 | (((int)((sd).cylinders_h<<8)|(sd).cylinders_l) * \ | ||
183 | (sd).heads * (sd).sectors) | ||
184 | |||
185 | |||
186 | typedef struct { | ||
187 | unsigned char dummy1; | ||
188 | unsigned char medium_type; | ||
189 | unsigned char dummy2; | ||
190 | unsigned char descriptor_size; | ||
191 | unsigned long block_count; | ||
192 | unsigned long sector_size; | ||
193 | /* Page 0 data */ | ||
194 | unsigned char page_code; | ||
195 | unsigned char page_size; | ||
196 | unsigned char page_flags; | ||
197 | unsigned char qualifier; | ||
198 | } SCSI_SENSE_DATA; | ||
199 | |||
200 | #define SCSI_CAPACITY(sd) ((sd).block_count & 0xffffff) | ||
201 | |||
202 | |||
203 | typedef union { | ||
204 | ATARI_SENSE_DATA atari; | ||
205 | SCSI_SENSE_DATA scsi; | ||
206 | } SENSE_DATA; | ||
207 | |||
208 | #define SENSE_TYPE_UNKNOWN 0 | ||
209 | #define SENSE_TYPE_ATARI 1 | ||
210 | #define SENSE_TYPE_SCSI 2 | ||
211 | |||
212 | #define SENSE_TYPE(sd) \ | ||
213 | (((sd).atari.dummy[0] == 8 && \ | ||
214 | ((sd).atari.format_code == 1 || \ | ||
215 | (sd).atari.format_code == 2)) ? SENSE_TYPE_ATARI : \ | ||
216 | ((sd).scsi.dummy1 >= 11) ? SENSE_TYPE_SCSI : \ | ||
217 | SENSE_TYPE_UNKNOWN) | ||
218 | |||
219 | #define CAPACITY(sd) \ | ||
220 | (SENSE_TYPE(sd) == SENSE_TYPE_ATARI ? \ | ||
221 | ATARI_CAPACITY((sd).atari) : \ | ||
222 | SCSI_CAPACITY((sd).scsi)) | ||
223 | |||
224 | #define SECTOR_SIZE(sd) \ | ||
225 | (SENSE_TYPE(sd) == SENSE_TYPE_ATARI ? \ | ||
226 | (sd).atari.sector_size : \ | ||
227 | (sd).scsi.sector_size & 0xffffff) | ||
228 | |||
229 | /* Default size if capacity cannot be determined (1 GByte) */ | ||
230 | #define DEFAULT_SIZE 0x1fffff | ||
231 | |||
232 | #define CARTRCH_STAT(aip,buf) \ | ||
233 | (aip->old_atari_disk ? \ | ||
234 | (((buf)[0] & 0x7f) == 0x28) : \ | ||
235 | ((((buf)[0] & 0x70) == 0x70) ? \ | ||
236 | (((buf)[2] & 0x0f) == 0x06) : \ | ||
237 | (((buf)[0] & 0x0f) == 0x06))) \ | ||
238 | |||
239 | /* These two are also exported to other drivers that work on the ACSI bus and | ||
240 | * need an ST-RAM buffer. */ | ||
241 | char *acsi_buffer; | ||
242 | unsigned long phys_acsi_buffer; | ||
243 | |||
244 | static int NDevices; | ||
245 | |||
246 | static int CurrentNReq; | ||
247 | static int CurrentNSect; | ||
248 | static char *CurrentBuffer; | ||
249 | |||
250 | static DEFINE_SPINLOCK(acsi_lock); | ||
251 | |||
252 | |||
253 | #define SET_TIMER() mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT) | ||
254 | #define CLEAR_TIMER() del_timer(&acsi_timer) | ||
255 | |||
256 | static unsigned long STramMask; | ||
257 | #define STRAM_ADDR(a) (((a) & STramMask) == 0) | ||
258 | |||
259 | |||
260 | |||
261 | /* ACSI commands */ | ||
262 | |||
263 | static char tur_cmd[6] = { 0x00, 0, 0, 0, 0, 0 }; | ||
264 | static char modesense_cmd[6] = { 0x1a, 0, 0, 0, 24, 0 }; | ||
265 | static char modeselect_cmd[6] = { 0x15, 0, 0, 0, 12, 0 }; | ||
266 | static char inquiry_cmd[6] = { 0x12, 0, 0, 0,255, 0 }; | ||
267 | static char reqsense_cmd[6] = { 0x03, 0, 0, 0, 4, 0 }; | ||
268 | static char read_cmd[6] = { 0x08, 0, 0, 0, 0, 0 }; | ||
269 | static char write_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 }; | ||
270 | static char pa_med_rem_cmd[6] = { 0x1e, 0, 0, 0, 0, 0 }; | ||
271 | |||
272 | #define CMDSET_TARG_LUN(cmd,targ,lun) \ | ||
273 | do { \ | ||
274 | cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5; \ | ||
275 | cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5; \ | ||
276 | } while(0) | ||
277 | |||
278 | #define CMDSET_BLOCK(cmd,blk) \ | ||
279 | do { \ | ||
280 | unsigned long __blk = (blk); \ | ||
281 | cmd[3] = __blk; __blk >>= 8; \ | ||
282 | cmd[2] = __blk; __blk >>= 8; \ | ||
283 | cmd[1] = (cmd[1] & 0xe0) | (__blk & 0x1f); \ | ||
284 | } while(0) | ||
285 | |||
286 | #define CMDSET_LEN(cmd,len) \ | ||
287 | do { \ | ||
288 | cmd[4] = (len); \ | ||
289 | } while(0) | ||
290 | |||
291 | /* ACSI errors (from REQUEST SENSE); There are two tables, one for the | ||
292 | * old Atari disks and one for SCSI on ACSI disks. | ||
293 | */ | ||
294 | |||
295 | struct acsi_error { | ||
296 | unsigned char code; | ||
297 | const char *text; | ||
298 | } atari_acsi_errors[] = { | ||
299 | { 0x00, "No error (??)" }, | ||
300 | { 0x01, "No index pulses" }, | ||
301 | { 0x02, "Seek not complete" }, | ||
302 | { 0x03, "Write fault" }, | ||
303 | { 0x04, "Drive not ready" }, | ||
304 | { 0x06, "No Track 00 signal" }, | ||
305 | { 0x10, "ECC error in ID field" }, | ||
306 | { 0x11, "Uncorrectable data error" }, | ||
307 | { 0x12, "ID field address mark not found" }, | ||
308 | { 0x13, "Data field address mark not found" }, | ||
309 | { 0x14, "Record not found" }, | ||
310 | { 0x15, "Seek error" }, | ||
311 | { 0x18, "Data check in no retry mode" }, | ||
312 | { 0x19, "ECC error during verify" }, | ||
313 | { 0x1a, "Access to bad block" }, | ||
314 | { 0x1c, "Unformatted or bad format" }, | ||
315 | { 0x20, "Invalid command" }, | ||
316 | { 0x21, "Invalid block address" }, | ||
317 | { 0x23, "Volume overflow" }, | ||
318 | { 0x24, "Invalid argument" }, | ||
319 | { 0x25, "Invalid drive number" }, | ||
320 | { 0x26, "Byte zero parity check" }, | ||
321 | { 0x28, "Cartride changed" }, | ||
322 | { 0x2c, "Error count overflow" }, | ||
323 | { 0x30, "Controller selftest failed" } | ||
324 | }, | ||
325 | |||
326 | scsi_acsi_errors[] = { | ||
327 | { 0x00, "No error (??)" }, | ||
328 | { 0x01, "Recovered error" }, | ||
329 | { 0x02, "Drive not ready" }, | ||
330 | { 0x03, "Uncorrectable medium error" }, | ||
331 | { 0x04, "Hardware error" }, | ||
332 | { 0x05, "Illegal request" }, | ||
333 | { 0x06, "Unit attention (Reset or cartridge changed)" }, | ||
334 | { 0x07, "Data protection" }, | ||
335 | { 0x08, "Blank check" }, | ||
336 | { 0x0b, "Aborted Command" }, | ||
337 | { 0x0d, "Volume overflow" } | ||
338 | }; | ||
339 | |||
340 | |||
341 | |||
342 | /***************************** Prototypes *****************************/ | ||
343 | |||
344 | static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int | ||
345 | rwflag, int enable); | ||
346 | static int acsi_reqsense( char *buffer, int targ, int lun); | ||
347 | static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip); | ||
348 | static irqreturn_t acsi_interrupt (int irq, void *data); | ||
349 | static void unexpected_acsi_interrupt( void ); | ||
350 | static void bad_rw_intr( void ); | ||
351 | static void read_intr( void ); | ||
352 | static void write_intr( void); | ||
353 | static void acsi_times_out( unsigned long dummy ); | ||
354 | static void copy_to_acsibuffer( void ); | ||
355 | static void copy_from_acsibuffer( void ); | ||
356 | static void do_end_requests( void ); | ||
357 | static void do_acsi_request( request_queue_t * ); | ||
358 | static void redo_acsi_request( void ); | ||
359 | static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int | ||
360 | cmd, unsigned long arg ); | ||
361 | static int acsi_open( struct inode * inode, struct file * filp ); | ||
362 | static int acsi_release( struct inode * inode, struct file * file ); | ||
363 | static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag ); | ||
364 | static int acsi_change_blk_size( int target, int lun); | ||
365 | static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ); | ||
366 | static int acsi_revalidate (struct gendisk *disk); | ||
367 | |||
368 | /************************* End of Prototypes **************************/ | ||
369 | |||
370 | |||
371 | DEFINE_TIMER(acsi_timer, acsi_times_out, 0, 0); | ||
372 | |||
373 | |||
374 | #ifdef CONFIG_ATARI_SLM | ||
375 | |||
376 | extern int attach_slm( int target, int lun ); | ||
377 | extern int slm_init( void ); | ||
378 | |||
379 | #endif | ||
380 | |||
381 | |||
382 | |||
383 | /*********************************************************************** | ||
384 | * | ||
385 | * ACSI primitives | ||
386 | * | ||
387 | **********************************************************************/ | ||
388 | |||
389 | |||
390 | /* | ||
391 | * The following two functions wait for _IRQ to become Low or High, | ||
392 | * resp., with a timeout. The 'timeout' parameter is in jiffies | ||
393 | * (10ms). | ||
394 | * If the functions are called with timer interrupts on (int level < | ||
395 | * 6), the timeout is based on the 'jiffies' variable to provide exact | ||
396 | * timeouts for device probing etc. | ||
397 | * If interrupts are disabled, the number of tries is based on the | ||
398 | * 'loops_per_jiffy' variable. A rough estimation is sufficient here... | ||
399 | */ | ||
400 | |||
401 | #define INT_LEVEL \ | ||
402 | ({ unsigned __sr; \ | ||
403 | __asm__ __volatile__ ( "movew %/sr,%0" : "=dm" (__sr) ); \ | ||
404 | (__sr >> 8) & 7; \ | ||
405 | }) | ||
406 | |||
407 | int acsi_wait_for_IRQ( unsigned timeout ) | ||
408 | |||
409 | { | ||
410 | if (INT_LEVEL < 6) { | ||
411 | unsigned long maxjif = jiffies + timeout; | ||
412 | while (time_before(jiffies, maxjif)) | ||
413 | if (!(mfp.par_dt_reg & 0x20)) return( 1 ); | ||
414 | } | ||
415 | else { | ||
416 | long tries = loops_per_jiffy / 8 * timeout; | ||
417 | while( --tries >= 0 ) | ||
418 | if (!(mfp.par_dt_reg & 0x20)) return( 1 ); | ||
419 | } | ||
420 | return( 0 ); /* timeout! */ | ||
421 | } | ||
422 | |||
423 | |||
424 | int acsi_wait_for_noIRQ( unsigned timeout ) | ||
425 | |||
426 | { | ||
427 | if (INT_LEVEL < 6) { | ||
428 | unsigned long maxjif = jiffies + timeout; | ||
429 | while (time_before(jiffies, maxjif)) | ||
430 | if (mfp.par_dt_reg & 0x20) return( 1 ); | ||
431 | } | ||
432 | else { | ||
433 | long tries = loops_per_jiffy * timeout / 8; | ||
434 | while( tries-- >= 0 ) | ||
435 | if (mfp.par_dt_reg & 0x20) return( 1 ); | ||
436 | } | ||
437 | return( 0 ); /* timeout! */ | ||
438 | } | ||
439 | |||
440 | static struct timeval start_time; | ||
441 | |||
442 | void | ||
443 | acsi_delay_start(void) | ||
444 | { | ||
445 | do_gettimeofday(&start_time); | ||
446 | } | ||
447 | |||
448 | /* wait from acsi_delay_start to now usec (<1E6) usec */ | ||
449 | |||
450 | void | ||
451 | acsi_delay_end(long usec) | ||
452 | { | ||
453 | struct timeval end_time; | ||
454 | long deltau,deltas; | ||
455 | do_gettimeofday(&end_time); | ||
456 | deltau=end_time.tv_usec - start_time.tv_usec; | ||
457 | deltas=end_time.tv_sec - start_time.tv_sec; | ||
458 | if (deltas > 1 || deltas < 0) | ||
459 | return; | ||
460 | if (deltas > 0) | ||
461 | deltau += 1000*1000; | ||
462 | if (deltau >= usec) | ||
463 | return; | ||
464 | udelay(usec-deltau); | ||
465 | } | ||
466 | |||
467 | /* acsicmd_dma() sends an ACSI command and sets up the DMA to transfer | ||
468 | * 'blocks' blocks of 512 bytes from/to 'buffer'. | ||
469 | * Because the _IRQ signal is used for handshaking the command bytes, | ||
470 | * the ACSI interrupt has to be disabled in this function. If the end | ||
471 | * of the operation should be signalled by a real interrupt, it has to be | ||
472 | * reenabled afterwards. | ||
473 | */ | ||
474 | |||
475 | static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable) | ||
476 | |||
477 | { unsigned long flags, paddr; | ||
478 | int i; | ||
479 | |||
480 | #ifdef NO_WRITE | ||
481 | if (rwflag || *cmd == 0x0a) { | ||
482 | printk( "ACSI: Write commands disabled!\n" ); | ||
483 | return( 0 ); | ||
484 | } | ||
485 | #endif | ||
486 | |||
487 | rwflag = rwflag ? 0x100 : 0; | ||
488 | paddr = virt_to_phys( buffer ); | ||
489 | |||
490 | acsi_delay_end(COMMAND_DELAY); | ||
491 | DISABLE_IRQ(); | ||
492 | |||
493 | local_irq_save(flags); | ||
494 | /* Low on A1 */ | ||
495 | dma_wd.dma_mode_status = 0x88 | rwflag; | ||
496 | MFPDELAY(); | ||
497 | |||
498 | /* set DMA address */ | ||
499 | dma_wd.dma_lo = (unsigned char)paddr; | ||
500 | paddr >>= 8; | ||
501 | MFPDELAY(); | ||
502 | dma_wd.dma_md = (unsigned char)paddr; | ||
503 | paddr >>= 8; | ||
504 | MFPDELAY(); | ||
505 | if (ATARIHW_PRESENT(EXTD_DMA)) | ||
506 | st_dma_ext_dmahi = (unsigned short)paddr; | ||
507 | else | ||
508 | dma_wd.dma_hi = (unsigned char)paddr; | ||
509 | MFPDELAY(); | ||
510 | local_irq_restore(flags); | ||
511 | |||
512 | /* send the command bytes except the last */ | ||
513 | for( i = 0; i < 5; ++i ) { | ||
514 | DMA_LONG_WRITE( *cmd++, 0x8a | rwflag ); | ||
515 | udelay(20); | ||
516 | if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ | ||
517 | } | ||
518 | |||
519 | /* Clear FIFO and switch DMA to correct direction */ | ||
520 | dma_wd.dma_mode_status = 0x92 | (rwflag ^ 0x100); | ||
521 | MFPDELAY(); | ||
522 | dma_wd.dma_mode_status = 0x92 | rwflag; | ||
523 | MFPDELAY(); | ||
524 | |||
525 | /* How many sectors for DMA */ | ||
526 | dma_wd.fdc_acces_seccount = blocks; | ||
527 | MFPDELAY(); | ||
528 | |||
529 | /* send last command byte */ | ||
530 | dma_wd.dma_mode_status = 0x8a | rwflag; | ||
531 | MFPDELAY(); | ||
532 | DMA_LONG_WRITE( *cmd++, 0x0a | rwflag ); | ||
533 | if (enable) | ||
534 | ENABLE_IRQ(); | ||
535 | udelay(80); | ||
536 | |||
537 | return( 1 ); | ||
538 | } | ||
539 | |||
540 | |||
541 | /* | ||
542 | * acsicmd_nodma() sends an ACSI command that requires no DMA. | ||
543 | */ | ||
544 | |||
545 | int acsicmd_nodma( const char *cmd, int enable) | ||
546 | |||
547 | { int i; | ||
548 | |||
549 | acsi_delay_end(COMMAND_DELAY); | ||
550 | DISABLE_IRQ(); | ||
551 | |||
552 | /* send first command byte */ | ||
553 | dma_wd.dma_mode_status = 0x88; | ||
554 | MFPDELAY(); | ||
555 | DMA_LONG_WRITE( *cmd++, 0x8a ); | ||
556 | udelay(20); | ||
557 | if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ | ||
558 | |||
559 | /* send the intermediate command bytes */ | ||
560 | for( i = 0; i < 4; ++i ) { | ||
561 | DMA_LONG_WRITE( *cmd++, 0x8a ); | ||
562 | udelay(20); | ||
563 | if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ | ||
564 | } | ||
565 | |||
566 | /* send last command byte */ | ||
567 | DMA_LONG_WRITE( *cmd++, 0x0a ); | ||
568 | if (enable) | ||
569 | ENABLE_IRQ(); | ||
570 | udelay(80); | ||
571 | |||
572 | return( 1 ); | ||
573 | /* Note that the ACSI interrupt is still disabled after this | ||
574 | * function. If you want to get the IRQ delivered, enable it manually! | ||
575 | */ | ||
576 | } | ||
577 | |||
578 | |||
579 | static int acsi_reqsense( char *buffer, int targ, int lun) | ||
580 | |||
581 | { | ||
582 | CMDSET_TARG_LUN( reqsense_cmd, targ, lun); | ||
583 | if (!acsicmd_dma( reqsense_cmd, buffer, 1, 0, 0 )) return( 0 ); | ||
584 | if (!acsi_wait_for_IRQ( 10 )) return( 0 ); | ||
585 | acsi_getstatus(); | ||
586 | if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); | ||
587 | if (!acsi_wait_for_IRQ( 10 )) return( 0 ); | ||
588 | acsi_getstatus(); | ||
589 | if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); | ||
590 | if (!acsi_wait_for_IRQ( 10 )) return( 0 ); | ||
591 | acsi_getstatus(); | ||
592 | if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); | ||
593 | if (!acsi_wait_for_IRQ( 10 )) return( 0 ); | ||
594 | acsi_getstatus(); | ||
595 | dma_cache_maintenance( virt_to_phys(buffer), 16, 0 ); | ||
596 | |||
597 | return( 1 ); | ||
598 | } | ||
599 | |||
600 | |||
601 | /* | ||
602 | * ACSI status phase: get the status byte from the bus | ||
603 | * | ||
604 | * I've seen several times that a 0xff status is read, propably due to | ||
605 | * a timing error. In this case, the procedure is repeated after the | ||
606 | * next _IRQ edge. | ||
607 | */ | ||
608 | |||
609 | int acsi_getstatus( void ) | ||
610 | |||
611 | { int status; | ||
612 | |||
613 | DISABLE_IRQ(); | ||
614 | for(;;) { | ||
615 | if (!acsi_wait_for_IRQ( 100 )) { | ||
616 | acsi_delay_start(); | ||
617 | return( -1 ); | ||
618 | } | ||
619 | dma_wd.dma_mode_status = 0x8a; | ||
620 | MFPDELAY(); | ||
621 | status = dma_wd.fdc_acces_seccount; | ||
622 | if (status != 0xff) break; | ||
623 | #ifdef DEBUG | ||
624 | printk("ACSI: skipping 0xff status byte\n" ); | ||
625 | #endif | ||
626 | udelay(40); | ||
627 | acsi_wait_for_noIRQ( 20 ); | ||
628 | } | ||
629 | dma_wd.dma_mode_status = 0x80; | ||
630 | udelay(40); | ||
631 | acsi_wait_for_noIRQ( 20 ); | ||
632 | |||
633 | acsi_delay_start(); | ||
634 | return( status & 0x1f ); /* mask of the device# */ | ||
635 | } | ||
636 | |||
637 | |||
638 | #if (defined(CONFIG_ATARI_SLM) || defined(CONFIG_ATARI_SLM_MODULE)) | ||
639 | |||
640 | /* Receive data in an extended status phase. Needed by SLM printer. */ | ||
641 | |||
642 | int acsi_extstatus( char *buffer, int cnt ) | ||
643 | |||
644 | { int status; | ||
645 | |||
646 | DISABLE_IRQ(); | ||
647 | udelay(80); | ||
648 | while( cnt-- > 0 ) { | ||
649 | if (!acsi_wait_for_IRQ( 40 )) return( 0 ); | ||
650 | dma_wd.dma_mode_status = 0x8a; | ||
651 | MFPDELAY(); | ||
652 | status = dma_wd.fdc_acces_seccount; | ||
653 | MFPDELAY(); | ||
654 | *buffer++ = status & 0xff; | ||
655 | udelay(40); | ||
656 | } | ||
657 | return( 1 ); | ||
658 | } | ||
659 | |||
660 | |||
661 | /* Finish an extended status phase */ | ||
662 | |||
663 | void acsi_end_extstatus( void ) | ||
664 | |||
665 | { | ||
666 | dma_wd.dma_mode_status = 0x80; | ||
667 | udelay(40); | ||
668 | acsi_wait_for_noIRQ( 20 ); | ||
669 | acsi_delay_start(); | ||
670 | } | ||
671 | |||
672 | |||
673 | /* Send data in an extended command phase */ | ||
674 | |||
675 | int acsi_extcmd( unsigned char *buffer, int cnt ) | ||
676 | |||
677 | { | ||
678 | while( cnt-- > 0 ) { | ||
679 | DMA_LONG_WRITE( *buffer++, 0x8a ); | ||
680 | udelay(20); | ||
681 | if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ | ||
682 | } | ||
683 | return( 1 ); | ||
684 | } | ||
685 | |||
686 | #endif | ||
687 | |||
688 | |||
689 | static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip) | ||
690 | |||
691 | { int atari_err, i, errcode; | ||
692 | struct acsi_error *arr; | ||
693 | |||
694 | atari_err = aip->old_atari_disk; | ||
695 | if (atari_err) | ||
696 | errcode = errblk[0] & 0x7f; | ||
697 | else | ||
698 | if ((errblk[0] & 0x70) == 0x70) | ||
699 | errcode = errblk[2] & 0x0f; | ||
700 | else | ||
701 | errcode = errblk[0] & 0x0f; | ||
702 | |||
703 | printk( KERN_ERR "ACSI error 0x%02x", errcode ); | ||
704 | |||
705 | if (errblk[0] & 0x80) | ||
706 | printk( " for sector %d", | ||
707 | ((errblk[1] & 0x1f) << 16) | | ||
708 | (errblk[2] << 8) | errblk[0] ); | ||
709 | |||
710 | arr = atari_err ? atari_acsi_errors : scsi_acsi_errors; | ||
711 | i = atari_err ? sizeof(atari_acsi_errors)/sizeof(*atari_acsi_errors) : | ||
712 | sizeof(scsi_acsi_errors)/sizeof(*scsi_acsi_errors); | ||
713 | |||
714 | for( --i; i >= 0; --i ) | ||
715 | if (arr[i].code == errcode) break; | ||
716 | if (i >= 0) | ||
717 | printk( ": %s\n", arr[i].text ); | ||
718 | } | ||
719 | |||
720 | /******************************************************************* | ||
721 | * | ||
722 | * ACSI interrupt routine | ||
723 | * Test, if this is a ACSI interrupt and call the irq handler | ||
724 | * Otherwise ignore this interrupt. | ||
725 | * | ||
726 | *******************************************************************/ | ||
727 | |||
728 | static irqreturn_t acsi_interrupt(int irq, void *data ) | ||
729 | |||
730 | { void (*acsi_irq_handler)(void) = do_acsi; | ||
731 | |||
732 | do_acsi = NULL; | ||
733 | CLEAR_TIMER(); | ||
734 | |||
735 | if (!acsi_irq_handler) | ||
736 | acsi_irq_handler = unexpected_acsi_interrupt; | ||
737 | acsi_irq_handler(); | ||
738 | return IRQ_HANDLED; | ||
739 | } | ||
740 | |||
741 | |||
742 | /****************************************************************** | ||
743 | * | ||
744 | * The Interrupt handlers | ||
745 | * | ||
746 | *******************************************************************/ | ||
747 | |||
748 | |||
749 | static void unexpected_acsi_interrupt( void ) | ||
750 | |||
751 | { | ||
752 | printk( KERN_WARNING "Unexpected ACSI interrupt\n" ); | ||
753 | } | ||
754 | |||
755 | |||
756 | /* This function is called in case of errors. Because we cannot reset | ||
757 | * the ACSI bus or a single device, there is no other choice than | ||
758 | * retrying several times :-( | ||
759 | */ | ||
760 | |||
761 | static void bad_rw_intr( void ) | ||
762 | |||
763 | { | ||
764 | if (!CURRENT) | ||
765 | return; | ||
766 | |||
767 | if (++CURRENT->errors >= MAX_ERRORS) | ||
768 | end_request(CURRENT, 0); | ||
769 | /* Otherwise just retry */ | ||
770 | } | ||
771 | |||
772 | |||
773 | static void read_intr( void ) | ||
774 | |||
775 | { int status; | ||
776 | |||
777 | status = acsi_getstatus(); | ||
778 | if (status != 0) { | ||
779 | struct gendisk *disk = CURRENT->rq_disk; | ||
780 | struct acsi_info_struct *aip = disk->private_data; | ||
781 | printk(KERN_ERR "%s: ", disk->disk_name); | ||
782 | if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun)) | ||
783 | printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); | ||
784 | else { | ||
785 | acsi_print_error(acsi_buffer, aip); | ||
786 | if (CARTRCH_STAT(aip, acsi_buffer)) | ||
787 | aip->changed = 1; | ||
788 | } | ||
789 | ENABLE_IRQ(); | ||
790 | bad_rw_intr(); | ||
791 | redo_acsi_request(); | ||
792 | return; | ||
793 | } | ||
794 | |||
795 | dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 ); | ||
796 | if (CurrentBuffer == acsi_buffer) | ||
797 | copy_from_acsibuffer(); | ||
798 | |||
799 | do_end_requests(); | ||
800 | redo_acsi_request(); | ||
801 | } | ||
802 | |||
803 | |||
804 | static void write_intr(void) | ||
805 | |||
806 | { int status; | ||
807 | |||
808 | status = acsi_getstatus(); | ||
809 | if (status != 0) { | ||
810 | struct gendisk *disk = CURRENT->rq_disk; | ||
811 | struct acsi_info_struct *aip = disk->private_data; | ||
812 | printk( KERN_ERR "%s: ", disk->disk_name); | ||
813 | if (!acsi_reqsense( acsi_buffer, aip->target, aip->lun)) | ||
814 | printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); | ||
815 | else { | ||
816 | acsi_print_error(acsi_buffer, aip); | ||
817 | if (CARTRCH_STAT(aip, acsi_buffer)) | ||
818 | aip->changed = 1; | ||
819 | } | ||
820 | bad_rw_intr(); | ||
821 | redo_acsi_request(); | ||
822 | return; | ||
823 | } | ||
824 | |||
825 | do_end_requests(); | ||
826 | redo_acsi_request(); | ||
827 | } | ||
828 | |||
829 | |||
830 | static void acsi_times_out( unsigned long dummy ) | ||
831 | |||
832 | { | ||
833 | DISABLE_IRQ(); | ||
834 | if (!do_acsi) return; | ||
835 | |||
836 | do_acsi = NULL; | ||
837 | printk( KERN_ERR "ACSI timeout\n" ); | ||
838 | if (!CURRENT) | ||
839 | return; | ||
840 | if (++CURRENT->errors >= MAX_ERRORS) { | ||
841 | #ifdef DEBUG | ||
842 | printk( KERN_ERR "ACSI: too many errors.\n" ); | ||
843 | #endif | ||
844 | end_request(CURRENT, 0); | ||
845 | } | ||
846 | |||
847 | redo_acsi_request(); | ||
848 | } | ||
849 | |||
850 | |||
851 | |||
852 | /*********************************************************************** | ||
853 | * | ||
854 | * Scatter-gather utility functions | ||
855 | * | ||
856 | ***********************************************************************/ | ||
857 | |||
858 | |||
859 | static void copy_to_acsibuffer( void ) | ||
860 | |||
861 | { int i; | ||
862 | char *src, *dst; | ||
863 | struct buffer_head *bh; | ||
864 | |||
865 | src = CURRENT->buffer; | ||
866 | dst = acsi_buffer; | ||
867 | bh = CURRENT->bh; | ||
868 | |||
869 | if (!bh) | ||
870 | memcpy( dst, src, CurrentNSect*512 ); | ||
871 | else | ||
872 | for( i = 0; i < CurrentNReq; ++i ) { | ||
873 | memcpy( dst, src, bh->b_size ); | ||
874 | dst += bh->b_size; | ||
875 | if ((bh = bh->b_reqnext)) | ||
876 | src = bh->b_data; | ||
877 | } | ||
878 | } | ||
879 | |||
880 | |||
881 | static void copy_from_acsibuffer( void ) | ||
882 | |||
883 | { int i; | ||
884 | char *src, *dst; | ||
885 | struct buffer_head *bh; | ||
886 | |||
887 | dst = CURRENT->buffer; | ||
888 | src = acsi_buffer; | ||
889 | bh = CURRENT->bh; | ||
890 | |||
891 | if (!bh) | ||
892 | memcpy( dst, src, CurrentNSect*512 ); | ||
893 | else | ||
894 | for( i = 0; i < CurrentNReq; ++i ) { | ||
895 | memcpy( dst, src, bh->b_size ); | ||
896 | src += bh->b_size; | ||
897 | if ((bh = bh->b_reqnext)) | ||
898 | dst = bh->b_data; | ||
899 | } | ||
900 | } | ||
901 | |||
902 | |||
903 | static void do_end_requests( void ) | ||
904 | |||
905 | { int i, n; | ||
906 | |||
907 | if (!CURRENT->bh) { | ||
908 | CURRENT->nr_sectors -= CurrentNSect; | ||
909 | CURRENT->current_nr_sectors -= CurrentNSect; | ||
910 | CURRENT->sector += CurrentNSect; | ||
911 | if (CURRENT->nr_sectors == 0) | ||
912 | end_request(CURRENT, 1); | ||
913 | } | ||
914 | else { | ||
915 | for( i = 0; i < CurrentNReq; ++i ) { | ||
916 | n = CURRENT->bh->b_size >> 9; | ||
917 | CURRENT->nr_sectors -= n; | ||
918 | CURRENT->current_nr_sectors -= n; | ||
919 | CURRENT->sector += n; | ||
920 | end_request(CURRENT, 1); | ||
921 | } | ||
922 | } | ||
923 | } | ||
924 | |||
925 | |||
926 | |||
927 | |||
928 | /*********************************************************************** | ||
929 | * | ||
930 | * do_acsi_request and friends | ||
931 | * | ||
932 | ***********************************************************************/ | ||
933 | |||
934 | static void do_acsi_request( request_queue_t * q ) | ||
935 | |||
936 | { | ||
937 | stdma_lock( acsi_interrupt, NULL ); | ||
938 | redo_acsi_request(); | ||
939 | } | ||
940 | |||
941 | |||
942 | static void redo_acsi_request( void ) | ||
943 | { | ||
944 | unsigned block, target, lun, nsect; | ||
945 | char *buffer; | ||
946 | unsigned long pbuffer; | ||
947 | struct buffer_head *bh; | ||
948 | struct gendisk *disk; | ||
949 | struct acsi_info_struct *aip; | ||
950 | |||
951 | repeat: | ||
952 | CLEAR_TIMER(); | ||
953 | |||
954 | if (do_acsi) | ||
955 | return; | ||
956 | |||
957 | if (!CURRENT) { | ||
958 | do_acsi = NULL; | ||
959 | ENABLE_IRQ(); | ||
960 | stdma_release(); | ||
961 | return; | ||
962 | } | ||
963 | |||
964 | disk = CURRENT->rq_disk; | ||
965 | aip = disk->private_data; | ||
966 | if (CURRENT->bh) { | ||
967 | if (!CURRENT->bh && !buffer_locked(CURRENT->bh)) | ||
968 | panic("ACSI: block not locked"); | ||
969 | } | ||
970 | |||
971 | block = CURRENT->sector; | ||
972 | if (block+CURRENT->nr_sectors >= get_capacity(disk)) { | ||
973 | #ifdef DEBUG | ||
974 | printk( "%s: attempted access for blocks %d...%ld past end of device at block %ld.\n", | ||
975 | disk->disk_name, | ||
976 | block, block + CURRENT->nr_sectors - 1, | ||
977 | get_capacity(disk)); | ||
978 | #endif | ||
979 | end_request(CURRENT, 0); | ||
980 | goto repeat; | ||
981 | } | ||
982 | if (aip->changed) { | ||
983 | printk( KERN_NOTICE "%s: request denied because cartridge has " | ||
984 | "been changed.\n", disk->disk_name); | ||
985 | end_request(CURRENT, 0); | ||
986 | goto repeat; | ||
987 | } | ||
988 | |||
989 | target = aip->target; | ||
990 | lun = aip->lun; | ||
991 | |||
992 | /* Find out how many sectors should be transferred from/to | ||
993 | * consecutive buffers and thus can be done with a single command. | ||
994 | */ | ||
995 | buffer = CURRENT->buffer; | ||
996 | pbuffer = virt_to_phys(buffer); | ||
997 | nsect = CURRENT->current_nr_sectors; | ||
998 | CurrentNReq = 1; | ||
999 | |||
1000 | if ((bh = CURRENT->bh) && bh != CURRENT->bhtail) { | ||
1001 | if (!STRAM_ADDR(pbuffer)) { | ||
1002 | /* If transfer is done via the ACSI buffer anyway, we can | ||
1003 | * assemble as much bh's as fit in the buffer. | ||
1004 | */ | ||
1005 | while( (bh = bh->b_reqnext) ) { | ||
1006 | if (nsect + (bh->b_size>>9) > ACSI_BUFFER_SECTORS) break; | ||
1007 | nsect += bh->b_size >> 9; | ||
1008 | ++CurrentNReq; | ||
1009 | if (bh == CURRENT->bhtail) break; | ||
1010 | } | ||
1011 | buffer = acsi_buffer; | ||
1012 | pbuffer = phys_acsi_buffer; | ||
1013 | } | ||
1014 | else { | ||
1015 | unsigned long pendadr, pnewadr; | ||
1016 | pendadr = pbuffer + nsect*512; | ||
1017 | while( (bh = bh->b_reqnext) ) { | ||
1018 | pnewadr = virt_to_phys(bh->b_data); | ||
1019 | if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break; | ||
1020 | nsect += bh->b_size >> 9; | ||
1021 | pendadr = pnewadr + bh->b_size; | ||
1022 | ++CurrentNReq; | ||
1023 | if (bh == CURRENT->bhtail) break; | ||
1024 | } | ||
1025 | } | ||
1026 | } | ||
1027 | else { | ||
1028 | if (!STRAM_ADDR(pbuffer)) { | ||
1029 | buffer = acsi_buffer; | ||
1030 | pbuffer = phys_acsi_buffer; | ||
1031 | if (nsect > ACSI_BUFFER_SECTORS) | ||
1032 | nsect = ACSI_BUFFER_SECTORS; | ||
1033 | } | ||
1034 | } | ||
1035 | CurrentBuffer = buffer; | ||
1036 | CurrentNSect = nsect; | ||
1037 | |||
1038 | if (rq_data_dir(CURRENT) == WRITE) { | ||
1039 | CMDSET_TARG_LUN( write_cmd, target, lun ); | ||
1040 | CMDSET_BLOCK( write_cmd, block ); | ||
1041 | CMDSET_LEN( write_cmd, nsect ); | ||
1042 | if (buffer == acsi_buffer) | ||
1043 | copy_to_acsibuffer(); | ||
1044 | dma_cache_maintenance( pbuffer, nsect*512, 1 ); | ||
1045 | do_acsi = write_intr; | ||
1046 | if (!acsicmd_dma( write_cmd, buffer, nsect, 1, 1)) { | ||
1047 | do_acsi = NULL; | ||
1048 | printk( KERN_ERR "ACSI (write): Timeout in command block\n" ); | ||
1049 | bad_rw_intr(); | ||
1050 | goto repeat; | ||
1051 | } | ||
1052 | SET_TIMER(); | ||
1053 | return; | ||
1054 | } | ||
1055 | if (rq_data_dir(CURRENT) == READ) { | ||
1056 | CMDSET_TARG_LUN( read_cmd, target, lun ); | ||
1057 | CMDSET_BLOCK( read_cmd, block ); | ||
1058 | CMDSET_LEN( read_cmd, nsect ); | ||
1059 | do_acsi = read_intr; | ||
1060 | if (!acsicmd_dma( read_cmd, buffer, nsect, 0, 1)) { | ||
1061 | do_acsi = NULL; | ||
1062 | printk( KERN_ERR "ACSI (read): Timeout in command block\n" ); | ||
1063 | bad_rw_intr(); | ||
1064 | goto repeat; | ||
1065 | } | ||
1066 | SET_TIMER(); | ||
1067 | return; | ||
1068 | } | ||
1069 | panic("unknown ACSI command"); | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | |||
1074 | /*********************************************************************** | ||
1075 | * | ||
1076 | * Misc functions: ioctl, open, release, check_change, ... | ||
1077 | * | ||
1078 | ***********************************************************************/ | ||
1079 | |||
1080 | static int acsi_getgeo(struct block_device *bdev, struct hd_geometry *geo) | ||
1081 | { | ||
1082 | struct acsi_info_struct *aip = bdev->bd_disk->private_data; | ||
1083 | |||
1084 | /* | ||
1085 | * Just fake some geometry here, it's nonsense anyway | ||
1086 | * To make it easy, use Adaptec's usual 64/32 mapping | ||
1087 | */ | ||
1088 | geo->heads = 64; | ||
1089 | geo->sectors = 32; | ||
1090 | geo->cylinders = aip->size >> 11; | ||
1091 | return 0; | ||
1092 | } | ||
1093 | |||
1094 | static int acsi_ioctl( struct inode *inode, struct file *file, | ||
1095 | unsigned int cmd, unsigned long arg ) | ||
1096 | { | ||
1097 | struct gendisk *disk = inode->i_bdev->bd_disk; | ||
1098 | struct acsi_info_struct *aip = disk->private_data; | ||
1099 | switch (cmd) { | ||
1100 | case SCSI_IOCTL_GET_IDLUN: | ||
1101 | /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */ | ||
1102 | put_user( aip->target | (aip->lun << 8), | ||
1103 | &((Scsi_Idlun *) arg)->dev_id ); | ||
1104 | put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); | ||
1105 | return 0; | ||
1106 | default: | ||
1107 | return -EINVAL; | ||
1108 | } | ||
1109 | } | ||
1110 | |||
1111 | |||
1112 | /* | ||
1113 | * Open a device, check for read-only and lock the medium if it is | ||
1114 | * removable. | ||
1115 | * | ||
1116 | * Changes by Martin Rogge, 9th Aug 1995: | ||
1117 | * Check whether check_disk_change (and therefore revalidate_acsidisk) | ||
1118 | * was successful. They fail when there is no medium in the drive. | ||
1119 | * | ||
1120 | * The problem of media being changed during an operation can be | ||
1121 | * ignored because of the prevent_removal code. | ||
1122 | * | ||
1123 | * Added check for the validity of the device number. | ||
1124 | * | ||
1125 | */ | ||
1126 | |||
1127 | static int acsi_open( struct inode * inode, struct file * filp ) | ||
1128 | { | ||
1129 | struct gendisk *disk = inode->i_bdev->bd_disk; | ||
1130 | struct acsi_info_struct *aip = disk->private_data; | ||
1131 | |||
1132 | if (aip->access_count == 0 && aip->removable) { | ||
1133 | #if 0 | ||
1134 | aip->changed = 1; /* safety first */ | ||
1135 | #endif | ||
1136 | check_disk_change( inode->i_bdev ); | ||
1137 | if (aip->changed) /* revalidate was not successful (no medium) */ | ||
1138 | return -ENXIO; | ||
1139 | acsi_prevent_removal(aip, 1); | ||
1140 | } | ||
1141 | aip->access_count++; | ||
1142 | |||
1143 | if (filp && filp->f_mode) { | ||
1144 | check_disk_change( inode->i_bdev ); | ||
1145 | if (filp->f_mode & 2) { | ||
1146 | if (aip->read_only) { | ||
1147 | acsi_release( inode, filp ); | ||
1148 | return -EROFS; | ||
1149 | } | ||
1150 | } | ||
1151 | } | ||
1152 | |||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | /* | ||
1157 | * Releasing a block device means we sync() it, so that it can safely | ||
1158 | * be forgotten about... | ||
1159 | */ | ||
1160 | |||
1161 | static int acsi_release( struct inode * inode, struct file * file ) | ||
1162 | { | ||
1163 | struct gendisk *disk = inode->i_bdev->bd_disk; | ||
1164 | struct acsi_info_struct *aip = disk->private_data; | ||
1165 | if (--aip->access_count == 0 && aip->removable) | ||
1166 | acsi_prevent_removal(aip, 0); | ||
1167 | return( 0 ); | ||
1168 | } | ||
1169 | |||
1170 | /* | ||
1171 | * Prevent or allow a media change for removable devices. | ||
1172 | */ | ||
1173 | |||
1174 | static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag) | ||
1175 | { | ||
1176 | stdma_lock( NULL, NULL ); | ||
1177 | |||
1178 | CMDSET_TARG_LUN(pa_med_rem_cmd, aip->target, aip->lun); | ||
1179 | CMDSET_LEN( pa_med_rem_cmd, flag ); | ||
1180 | |||
1181 | if (acsicmd_nodma(pa_med_rem_cmd, 0) && acsi_wait_for_IRQ(3*HZ)) | ||
1182 | acsi_getstatus(); | ||
1183 | /* Do not report errors -- some devices may not know this command. */ | ||
1184 | |||
1185 | ENABLE_IRQ(); | ||
1186 | stdma_release(); | ||
1187 | } | ||
1188 | |||
1189 | static int acsi_media_change(struct gendisk *disk) | ||
1190 | { | ||
1191 | struct acsi_info_struct *aip = disk->private_data; | ||
1192 | |||
1193 | if (!aip->removable) | ||
1194 | return 0; | ||
1195 | |||
1196 | if (aip->changed) | ||
1197 | /* We can be sure that the medium has been changed -- REQUEST | ||
1198 | * SENSE has reported this earlier. | ||
1199 | */ | ||
1200 | return 1; | ||
1201 | |||
1202 | /* If the flag isn't set, make a test by reading block 0. | ||
1203 | * If errors happen, it seems to be better to say "changed"... | ||
1204 | */ | ||
1205 | stdma_lock( NULL, NULL ); | ||
1206 | CMDSET_TARG_LUN(read_cmd, aip->target, aip->lun); | ||
1207 | CMDSET_BLOCK( read_cmd, 0 ); | ||
1208 | CMDSET_LEN( read_cmd, 1 ); | ||
1209 | if (acsicmd_dma(read_cmd, acsi_buffer, 1, 0, 0) && | ||
1210 | acsi_wait_for_IRQ(3*HZ)) { | ||
1211 | if (acsi_getstatus()) { | ||
1212 | if (acsi_reqsense(acsi_buffer, aip->target, aip->lun)) { | ||
1213 | if (CARTRCH_STAT(aip, acsi_buffer)) | ||
1214 | aip->changed = 1; | ||
1215 | } | ||
1216 | else { | ||
1217 | printk( KERN_ERR "%s: REQUEST SENSE failed in test for " | ||
1218 | "medium change; assuming a change\n", disk->disk_name ); | ||
1219 | aip->changed = 1; | ||
1220 | } | ||
1221 | } | ||
1222 | } | ||
1223 | else { | ||
1224 | printk( KERN_ERR "%s: Test for medium changed timed out; " | ||
1225 | "assuming a change\n", disk->disk_name); | ||
1226 | aip->changed = 1; | ||
1227 | } | ||
1228 | ENABLE_IRQ(); | ||
1229 | stdma_release(); | ||
1230 | |||
1231 | /* Now, after reading a block, the changed status is surely valid. */ | ||
1232 | return aip->changed; | ||
1233 | } | ||
1234 | |||
1235 | |||
1236 | static int acsi_change_blk_size( int target, int lun) | ||
1237 | |||
1238 | { int i; | ||
1239 | |||
1240 | for (i=0; i<12; i++) | ||
1241 | acsi_buffer[i] = 0; | ||
1242 | |||
1243 | acsi_buffer[3] = 8; | ||
1244 | acsi_buffer[10] = 2; | ||
1245 | CMDSET_TARG_LUN( modeselect_cmd, target, lun); | ||
1246 | |||
1247 | if (!acsicmd_dma( modeselect_cmd, acsi_buffer, 1,1,0) || | ||
1248 | !acsi_wait_for_IRQ( 3*HZ ) || | ||
1249 | acsi_getstatus() != 0 ) { | ||
1250 | return(0); | ||
1251 | } | ||
1252 | return(1); | ||
1253 | } | ||
1254 | |||
1255 | |||
1256 | static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ) | ||
1257 | |||
1258 | { | ||
1259 | int page; | ||
1260 | |||
1261 | CMDSET_TARG_LUN( modesense_cmd, target, lun ); | ||
1262 | for (page=0; page<4; page++) { | ||
1263 | modesense_cmd[2] = page; | ||
1264 | if (!acsicmd_dma( modesense_cmd, acsi_buffer, 1, 0, 0 ) || | ||
1265 | !acsi_wait_for_IRQ( 3*HZ ) || | ||
1266 | acsi_getstatus()) | ||
1267 | continue; | ||
1268 | |||
1269 | /* read twice to jump over the second 16-byte border! */ | ||
1270 | udelay(300); | ||
1271 | if (acsi_wait_for_noIRQ( 20 ) && | ||
1272 | acsicmd_nodma( modesense_cmd, 0 ) && | ||
1273 | acsi_wait_for_IRQ( 3*HZ ) && | ||
1274 | acsi_getstatus() == 0) | ||
1275 | break; | ||
1276 | } | ||
1277 | if (page == 4) { | ||
1278 | return(0); | ||
1279 | } | ||
1280 | |||
1281 | dma_cache_maintenance( phys_acsi_buffer, sizeof(SENSE_DATA), 0 ); | ||
1282 | *sd = *(SENSE_DATA *)acsi_buffer; | ||
1283 | |||
1284 | /* Validity check, depending on type of data */ | ||
1285 | |||
1286 | switch( SENSE_TYPE(*sd) ) { | ||
1287 | |||
1288 | case SENSE_TYPE_ATARI: | ||
1289 | if (CAPACITY(*sd) == 0) | ||
1290 | goto invalid_sense; | ||
1291 | break; | ||
1292 | |||
1293 | case SENSE_TYPE_SCSI: | ||
1294 | if (sd->scsi.descriptor_size != 8) | ||
1295 | goto invalid_sense; | ||
1296 | break; | ||
1297 | |||
1298 | case SENSE_TYPE_UNKNOWN: | ||
1299 | |||
1300 | printk( KERN_ERR "ACSI target %d, lun %d: Cannot interpret " | ||
1301 | "sense data\n", target, lun ); | ||
1302 | |||
1303 | invalid_sense: | ||
1304 | |||
1305 | #ifdef DEBUG | ||
1306 | { int i; | ||
1307 | printk( "Mode sense data for ACSI target %d, lun %d seem not valid:", | ||
1308 | target, lun ); | ||
1309 | for( i = 0; i < sizeof(SENSE_DATA); ++i ) | ||
1310 | printk( "%02x ", (unsigned char)acsi_buffer[i] ); | ||
1311 | printk( "\n" ); | ||
1312 | } | ||
1313 | #endif | ||
1314 | return( 0 ); | ||
1315 | } | ||
1316 | |||
1317 | return( 1 ); | ||
1318 | } | ||
1319 | |||
1320 | |||
1321 | |||
1322 | /******************************************************************* | ||
1323 | * | ||
1324 | * Initialization | ||
1325 | * | ||
1326 | ********************************************************************/ | ||
1327 | |||
1328 | |||
1329 | extern struct block_device_operations acsi_fops; | ||
1330 | |||
1331 | static struct gendisk *acsi_gendisk[MAX_DEV]; | ||
1332 | |||
1333 | #define MAX_SCSI_DEVICE_CODE 10 | ||
1334 | |||
1335 | static const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = | ||
1336 | { | ||
1337 | "Direct-Access ", | ||
1338 | "Sequential-Access", | ||
1339 | "Printer ", | ||
1340 | "Processor ", | ||
1341 | "WORM ", | ||
1342 | "CD-ROM ", | ||
1343 | "Scanner ", | ||
1344 | "Optical Device ", | ||
1345 | "Medium Changer ", | ||
1346 | "Communications " | ||
1347 | }; | ||
1348 | |||
1349 | static void print_inquiry(unsigned char *data) | ||
1350 | { | ||
1351 | int i; | ||
1352 | |||
1353 | printk(KERN_INFO " Vendor: "); | ||
1354 | for (i = 8; i < 16; i++) | ||
1355 | { | ||
1356 | if (data[i] >= 0x20 && i < data[4] + 5) | ||
1357 | printk("%c", data[i]); | ||
1358 | else | ||
1359 | printk(" "); | ||
1360 | } | ||
1361 | |||
1362 | printk(" Model: "); | ||
1363 | for (i = 16; i < 32; i++) | ||
1364 | { | ||
1365 | if (data[i] >= 0x20 && i < data[4] + 5) | ||
1366 | printk("%c", data[i]); | ||
1367 | else | ||
1368 | printk(" "); | ||
1369 | } | ||
1370 | |||
1371 | printk(" Rev: "); | ||
1372 | for (i = 32; i < 36; i++) | ||
1373 | { | ||
1374 | if (data[i] >= 0x20 && i < data[4] + 5) | ||
1375 | printk("%c", data[i]); | ||
1376 | else | ||
1377 | printk(" "); | ||
1378 | } | ||
1379 | |||
1380 | printk("\n"); | ||
1381 | |||
1382 | i = data[0] & 0x1f; | ||
1383 | |||
1384 | printk(KERN_INFO " Type: %s ", (i < MAX_SCSI_DEVICE_CODE | ||
1385 | ? scsi_device_types[i] | ||
1386 | : "Unknown ")); | ||
1387 | printk(" ANSI SCSI revision: %02x", data[2] & 0x07); | ||
1388 | if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1) | ||
1389 | printk(" CCS\n"); | ||
1390 | else | ||
1391 | printk("\n"); | ||
1392 | } | ||
1393 | |||
1394 | |||
1395 | /* | ||
1396 | * Changes by Martin Rogge, 9th Aug 1995: | ||
1397 | * acsi_devinit has been taken out of acsi_geninit, because it needs | ||
1398 | * to be called from revalidate_acsidisk. The result of request sense | ||
1399 | * is now checked for DRIVE NOT READY. | ||
1400 | * | ||
1401 | * The structure *aip is only valid when acsi_devinit returns | ||
1402 | * DEV_SUPPORTED. | ||
1403 | * | ||
1404 | */ | ||
1405 | |||
1406 | #define DEV_NONE 0 | ||
1407 | #define DEV_UNKNOWN 1 | ||
1408 | #define DEV_SUPPORTED 2 | ||
1409 | #define DEV_SLM 3 | ||
1410 | |||
1411 | static int acsi_devinit(struct acsi_info_struct *aip) | ||
1412 | { | ||
1413 | int status, got_inquiry; | ||
1414 | SENSE_DATA sense; | ||
1415 | unsigned char reqsense, extsense; | ||
1416 | |||
1417 | /*****************************************************************/ | ||
1418 | /* Do a TEST UNIT READY command to test the presence of a device */ | ||
1419 | /*****************************************************************/ | ||
1420 | |||
1421 | CMDSET_TARG_LUN(tur_cmd, aip->target, aip->lun); | ||
1422 | if (!acsicmd_nodma(tur_cmd, 0)) { | ||
1423 | /* timed out -> no device here */ | ||
1424 | #ifdef DEBUG_DETECT | ||
1425 | printk("target %d lun %d: timeout\n", aip->target, aip->lun); | ||
1426 | #endif | ||
1427 | return DEV_NONE; | ||
1428 | } | ||
1429 | |||
1430 | /*************************/ | ||
1431 | /* Read the ACSI status. */ | ||
1432 | /*************************/ | ||
1433 | |||
1434 | status = acsi_getstatus(); | ||
1435 | if (status) { | ||
1436 | if (status == 0x12) { | ||
1437 | /* The SLM printer should be the only device that | ||
1438 | * responds with the error code in the status byte. In | ||
1439 | * correct status bytes, bit 4 is never set. | ||
1440 | */ | ||
1441 | printk( KERN_INFO "Detected SLM printer at id %d lun %d\n", | ||
1442 | aip->target, aip->lun); | ||
1443 | return DEV_SLM; | ||
1444 | } | ||
1445 | /* ignore CHECK CONDITION, since some devices send a | ||
1446 | UNIT ATTENTION */ | ||
1447 | if ((status & 0x1e) != 0x2) { | ||
1448 | #ifdef DEBUG_DETECT | ||
1449 | printk("target %d lun %d: status %d\n", | ||
1450 | aip->target, aip->lun, status); | ||
1451 | #endif | ||
1452 | return DEV_UNKNOWN; | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | /*******************************/ | ||
1457 | /* Do a REQUEST SENSE command. */ | ||
1458 | /*******************************/ | ||
1459 | |||
1460 | if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun)) { | ||
1461 | printk( KERN_WARNING "acsi_reqsense failed\n"); | ||
1462 | acsi_buffer[0] = 0; | ||
1463 | acsi_buffer[2] = UNIT_ATTENTION; | ||
1464 | } | ||
1465 | reqsense = acsi_buffer[0]; | ||
1466 | extsense = acsi_buffer[2] & 0xf; | ||
1467 | if (status) { | ||
1468 | if ((reqsense & 0x70) == 0x70) { /* extended sense */ | ||
1469 | if (extsense != UNIT_ATTENTION && | ||
1470 | extsense != NOT_READY) { | ||
1471 | #ifdef DEBUG_DETECT | ||
1472 | printk("target %d lun %d: extended sense %d\n", | ||
1473 | aip->target, aip->lun, extsense); | ||
1474 | #endif | ||
1475 | return DEV_UNKNOWN; | ||
1476 | } | ||
1477 | } | ||
1478 | else { | ||
1479 | if (reqsense & 0x7f) { | ||
1480 | #ifdef DEBUG_DETECT | ||
1481 | printk("target %d lun %d: sense %d\n", | ||
1482 | aip->target, aip->lun, reqsense); | ||
1483 | #endif | ||
1484 | return DEV_UNKNOWN; | ||
1485 | } | ||
1486 | } | ||
1487 | } | ||
1488 | else | ||
1489 | if (reqsense == 0x4) { /* SH204 Bug workaround */ | ||
1490 | #ifdef DEBUG_DETECT | ||
1491 | printk("target %d lun %d status=0 sense=4\n", | ||
1492 | aip->target, aip->lun); | ||
1493 | #endif | ||
1494 | return DEV_UNKNOWN; | ||
1495 | } | ||
1496 | |||
1497 | /***********************************************************/ | ||
1498 | /* Do an INQUIRY command to get more infos on this device. */ | ||
1499 | /***********************************************************/ | ||
1500 | |||
1501 | /* Assume default values */ | ||
1502 | aip->removable = 1; | ||
1503 | aip->read_only = 0; | ||
1504 | aip->old_atari_disk = 0; | ||
1505 | aip->changed = (extsense == NOT_READY); /* medium inserted? */ | ||
1506 | aip->size = DEFAULT_SIZE; | ||
1507 | got_inquiry = 0; | ||
1508 | /* Fake inquiry result for old atari disks */ | ||
1509 | memcpy(acsi_buffer, "\000\000\001\000 Adaptec 40xx" | ||
1510 | " ", 40); | ||
1511 | CMDSET_TARG_LUN(inquiry_cmd, aip->target, aip->lun); | ||
1512 | if (acsicmd_dma(inquiry_cmd, acsi_buffer, 1, 0, 0) && | ||
1513 | acsi_getstatus() == 0) { | ||
1514 | acsicmd_nodma(inquiry_cmd, 0); | ||
1515 | acsi_getstatus(); | ||
1516 | dma_cache_maintenance( phys_acsi_buffer, 256, 0 ); | ||
1517 | got_inquiry = 1; | ||
1518 | aip->removable = !!(acsi_buffer[1] & 0x80); | ||
1519 | } | ||
1520 | if (aip->type == NONE) /* only at boot time */ | ||
1521 | print_inquiry(acsi_buffer); | ||
1522 | switch(acsi_buffer[0]) { | ||
1523 | case TYPE_DISK: | ||
1524 | aip->type = HARDDISK; | ||
1525 | break; | ||
1526 | case TYPE_ROM: | ||
1527 | aip->type = CDROM; | ||
1528 | aip->read_only = 1; | ||
1529 | break; | ||
1530 | default: | ||
1531 | return DEV_UNKNOWN; | ||
1532 | } | ||
1533 | /****************************/ | ||
1534 | /* Do a MODE SENSE command. */ | ||
1535 | /****************************/ | ||
1536 | |||
1537 | if (!acsi_mode_sense(aip->target, aip->lun, &sense)) { | ||
1538 | printk( KERN_WARNING "No mode sense data.\n" ); | ||
1539 | return DEV_UNKNOWN; | ||
1540 | } | ||
1541 | if ((SECTOR_SIZE(sense) != 512) && | ||
1542 | ((aip->type != CDROM) || | ||
1543 | !acsi_change_blk_size(aip->target, aip->lun) || | ||
1544 | !acsi_mode_sense(aip->target, aip->lun, &sense) || | ||
1545 | (SECTOR_SIZE(sense) != 512))) { | ||
1546 | printk( KERN_WARNING "Sector size != 512 not supported.\n" ); | ||
1547 | return DEV_UNKNOWN; | ||
1548 | } | ||
1549 | /* There are disks out there that claim to have 0 sectors... */ | ||
1550 | if (CAPACITY(sense)) | ||
1551 | aip->size = CAPACITY(sense); /* else keep DEFAULT_SIZE */ | ||
1552 | if (!got_inquiry && SENSE_TYPE(sense) == SENSE_TYPE_ATARI) { | ||
1553 | /* If INQUIRY failed and the sense data suggest an old | ||
1554 | * Atari disk (SH20x, Megafile), the disk is not removable | ||
1555 | */ | ||
1556 | aip->removable = 0; | ||
1557 | aip->old_atari_disk = 1; | ||
1558 | } | ||
1559 | |||
1560 | /******************/ | ||
1561 | /* We've done it. */ | ||
1562 | /******************/ | ||
1563 | |||
1564 | return DEV_SUPPORTED; | ||
1565 | } | ||
1566 | |||
1567 | EXPORT_SYMBOL(acsi_delay_start); | ||
1568 | EXPORT_SYMBOL(acsi_delay_end); | ||
1569 | EXPORT_SYMBOL(acsi_wait_for_IRQ); | ||
1570 | EXPORT_SYMBOL(acsi_wait_for_noIRQ); | ||
1571 | EXPORT_SYMBOL(acsicmd_nodma); | ||
1572 | EXPORT_SYMBOL(acsi_getstatus); | ||
1573 | EXPORT_SYMBOL(acsi_buffer); | ||
1574 | EXPORT_SYMBOL(phys_acsi_buffer); | ||
1575 | |||
1576 | #ifdef CONFIG_ATARI_SLM_MODULE | ||
1577 | void acsi_attach_SLMs( int (*attach_func)( int, int ) ); | ||
1578 | |||
1579 | EXPORT_SYMBOL(acsi_extstatus); | ||
1580 | EXPORT_SYMBOL(acsi_end_extstatus); | ||
1581 | EXPORT_SYMBOL(acsi_extcmd); | ||
1582 | EXPORT_SYMBOL(acsi_attach_SLMs); | ||
1583 | |||
1584 | /* to remember IDs of SLM devices, SLM module is loaded later | ||
1585 | * (index is target#, contents is lun#, -1 means "no SLM") */ | ||
1586 | int SLM_devices[8]; | ||
1587 | #endif | ||
1588 | |||
1589 | static struct block_device_operations acsi_fops = { | ||
1590 | .owner = THIS_MODULE, | ||
1591 | .open = acsi_open, | ||
1592 | .release = acsi_release, | ||
1593 | .ioctl = acsi_ioctl, | ||
1594 | .getgeo = acsi_getgeo, | ||
1595 | .media_changed = acsi_media_change, | ||
1596 | .revalidate_disk= acsi_revalidate, | ||
1597 | }; | ||
1598 | |||
1599 | #ifdef CONFIG_ATARI_SLM_MODULE | ||
1600 | /* call attach_slm() for each device that is a printer; needed for init of SLM | ||
1601 | * driver as a module, since it's not yet present if acsi.c is inited and thus | ||
1602 | * the bus gets scanned. */ | ||
1603 | void acsi_attach_SLMs( int (*attach_func)( int, int ) ) | ||
1604 | { | ||
1605 | int i, n = 0; | ||
1606 | |||
1607 | for( i = 0; i < 8; ++i ) | ||
1608 | if (SLM_devices[i] >= 0) | ||
1609 | n += (*attach_func)( i, SLM_devices[i] ); | ||
1610 | printk( KERN_INFO "Found %d SLM printer(s) total.\n", n ); | ||
1611 | } | ||
1612 | #endif /* CONFIG_ATARI_SLM_MODULE */ | ||
1613 | |||
1614 | |||
1615 | int acsi_init( void ) | ||
1616 | { | ||
1617 | int err = 0; | ||
1618 | int i, target, lun; | ||
1619 | struct acsi_info_struct *aip; | ||
1620 | #ifdef CONFIG_ATARI_SLM | ||
1621 | int n_slm = 0; | ||
1622 | #endif | ||
1623 | if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ACSI)) | ||
1624 | return 0; | ||
1625 | if (register_blkdev(ACSI_MAJOR, "ad")) { | ||
1626 | err = -EBUSY; | ||
1627 | goto out1; | ||
1628 | } | ||
1629 | if (!(acsi_buffer = | ||
1630 | (char *)atari_stram_alloc(ACSI_BUFFER_SIZE, "acsi"))) { | ||
1631 | err = -ENOMEM; | ||
1632 | printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" ); | ||
1633 | goto out2; | ||
1634 | } | ||
1635 | phys_acsi_buffer = virt_to_phys( acsi_buffer ); | ||
1636 | STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; | ||
1637 | |||
1638 | acsi_queue = blk_init_queue(do_acsi_request, &acsi_lock); | ||
1639 | if (!acsi_queue) { | ||
1640 | err = -ENOMEM; | ||
1641 | goto out2a; | ||
1642 | } | ||
1643 | #ifdef CONFIG_ATARI_SLM | ||
1644 | err = slm_init(); | ||
1645 | #endif | ||
1646 | if (err) | ||
1647 | goto out3; | ||
1648 | |||
1649 | printk( KERN_INFO "Probing ACSI devices:\n" ); | ||
1650 | NDevices = 0; | ||
1651 | #ifdef CONFIG_ATARI_SLM_MODULE | ||
1652 | for( i = 0; i < 8; ++i ) | ||
1653 | SLM_devices[i] = -1; | ||
1654 | #endif | ||
1655 | stdma_lock(NULL, NULL); | ||
1656 | |||
1657 | for (target = 0; target < 8 && NDevices < MAX_DEV; ++target) { | ||
1658 | lun = 0; | ||
1659 | do { | ||
1660 | aip = &acsi_info[NDevices]; | ||
1661 | aip->type = NONE; | ||
1662 | aip->target = target; | ||
1663 | aip->lun = lun; | ||
1664 | i = acsi_devinit(aip); | ||
1665 | switch (i) { | ||
1666 | case DEV_SUPPORTED: | ||
1667 | printk( KERN_INFO "Detected "); | ||
1668 | switch (aip->type) { | ||
1669 | case HARDDISK: | ||
1670 | printk("disk"); | ||
1671 | break; | ||
1672 | case CDROM: | ||
1673 | printk("cdrom"); | ||
1674 | break; | ||
1675 | default: | ||
1676 | } | ||
1677 | printk(" ad%c at id %d lun %d ", | ||
1678 | 'a' + NDevices, target, lun); | ||
1679 | if (aip->removable) | ||
1680 | printk("(removable) "); | ||
1681 | if (aip->read_only) | ||
1682 | printk("(read-only) "); | ||
1683 | if (aip->size == DEFAULT_SIZE) | ||
1684 | printk(" unkown size, using default "); | ||
1685 | printk("%ld MByte\n", | ||
1686 | (aip->size*512+1024*1024/2)/(1024*1024)); | ||
1687 | NDevices++; | ||
1688 | break; | ||
1689 | case DEV_SLM: | ||
1690 | #ifdef CONFIG_ATARI_SLM | ||
1691 | n_slm += attach_slm( target, lun ); | ||
1692 | break; | ||
1693 | #endif | ||
1694 | #ifdef CONFIG_ATARI_SLM_MODULE | ||
1695 | SLM_devices[target] = lun; | ||
1696 | break; | ||
1697 | #endif | ||
1698 | /* neither of the above: fall through to unknown device */ | ||
1699 | case DEV_UNKNOWN: | ||
1700 | printk( KERN_INFO "Detected unsupported device at " | ||
1701 | "id %d lun %d\n", target, lun); | ||
1702 | break; | ||
1703 | } | ||
1704 | } | ||
1705 | #ifdef CONFIG_ACSI_MULTI_LUN | ||
1706 | while (i != DEV_NONE && ++lun < MAX_LUN); | ||
1707 | #else | ||
1708 | while (0); | ||
1709 | #endif | ||
1710 | } | ||
1711 | |||
1712 | /* reenable interrupt */ | ||
1713 | ENABLE_IRQ(); | ||
1714 | stdma_release(); | ||
1715 | |||
1716 | #ifndef CONFIG_ATARI_SLM | ||
1717 | printk( KERN_INFO "Found %d ACSI device(s) total.\n", NDevices ); | ||
1718 | #else | ||
1719 | printk( KERN_INFO "Found %d ACSI device(s) and %d SLM printer(s) total.\n", | ||
1720 | NDevices, n_slm ); | ||
1721 | #endif | ||
1722 | err = -ENOMEM; | ||
1723 | for( i = 0; i < NDevices; ++i ) { | ||
1724 | acsi_gendisk[i] = alloc_disk(16); | ||
1725 | if (!acsi_gendisk[i]) | ||
1726 | goto out4; | ||
1727 | } | ||
1728 | |||
1729 | for( i = 0; i < NDevices; ++i ) { | ||
1730 | struct gendisk *disk = acsi_gendisk[i]; | ||
1731 | sprintf(disk->disk_name, "ad%c", 'a'+i); | ||
1732 | aip = &acsi_info[NDevices]; | ||
1733 | disk->major = ACSI_MAJOR; | ||
1734 | disk->first_minor = i << 4; | ||
1735 | if (acsi_info[i].type != HARDDISK) | ||
1736 | disk->minors = 1; | ||
1737 | disk->fops = &acsi_fops; | ||
1738 | disk->private_data = &acsi_info[i]; | ||
1739 | set_capacity(disk, acsi_info[i].size); | ||
1740 | disk->queue = acsi_queue; | ||
1741 | add_disk(disk); | ||
1742 | } | ||
1743 | return 0; | ||
1744 | out4: | ||
1745 | while (i--) | ||
1746 | put_disk(acsi_gendisk[i]); | ||
1747 | out3: | ||
1748 | blk_cleanup_queue(acsi_queue); | ||
1749 | out2a: | ||
1750 | atari_stram_free( acsi_buffer ); | ||
1751 | out2: | ||
1752 | unregister_blkdev( ACSI_MAJOR, "ad" ); | ||
1753 | out1: | ||
1754 | return err; | ||
1755 | } | ||
1756 | |||
1757 | |||
1758 | #ifdef MODULE | ||
1759 | |||
1760 | MODULE_LICENSE("GPL"); | ||
1761 | |||
1762 | int init_module(void) | ||
1763 | { | ||
1764 | int err; | ||
1765 | |||
1766 | if ((err = acsi_init())) | ||
1767 | return( err ); | ||
1768 | printk( KERN_INFO "ACSI driver loaded as module.\n"); | ||
1769 | return( 0 ); | ||
1770 | } | ||
1771 | |||
1772 | void cleanup_module(void) | ||
1773 | { | ||
1774 | int i; | ||
1775 | del_timer( &acsi_timer ); | ||
1776 | blk_cleanup_queue(acsi_queue); | ||
1777 | atari_stram_free( acsi_buffer ); | ||
1778 | |||
1779 | if (unregister_blkdev( ACSI_MAJOR, "ad" ) != 0) | ||
1780 | printk( KERN_ERR "acsi: cleanup_module failed\n"); | ||
1781 | |||
1782 | for (i = 0; i < NDevices; i++) { | ||
1783 | del_gendisk(acsi_gendisk[i]); | ||
1784 | put_disk(acsi_gendisk[i]); | ||
1785 | } | ||
1786 | } | ||
1787 | #endif | ||
1788 | |||
1789 | /* | ||
1790 | * This routine is called to flush all partitions and partition tables | ||
1791 | * for a changed scsi disk, and then re-read the new partition table. | ||
1792 | * If we are revalidating a disk because of a media change, then we | ||
1793 | * enter with usage == 0. If we are using an ioctl, we automatically have | ||
1794 | * usage == 1 (we need an open channel to use an ioctl :-), so this | ||
1795 | * is our limit. | ||
1796 | * | ||
1797 | * Changes by Martin Rogge, 9th Aug 1995: | ||
1798 | * got cd-roms to work by calling acsi_devinit. There are only two problems: | ||
1799 | * First, if there is no medium inserted, the status will remain "changed". | ||
1800 | * That is no problem at all, but our design of three-valued logic (medium | ||
1801 | * changed, medium not changed, no medium inserted). | ||
1802 | * Secondly the check could fail completely and the drive could deliver | ||
1803 | * nonsensical data, which could mess up the acsi_info[] structure. In | ||
1804 | * that case we try to make the entry safe. | ||
1805 | * | ||
1806 | */ | ||
1807 | |||
1808 | static int acsi_revalidate(struct gendisk *disk) | ||
1809 | { | ||
1810 | struct acsi_info_struct *aip = disk->private_data; | ||
1811 | stdma_lock( NULL, NULL ); | ||
1812 | if (acsi_devinit(aip) != DEV_SUPPORTED) { | ||
1813 | printk( KERN_ERR "ACSI: revalidate failed for target %d lun %d\n", | ||
1814 | aip->target, aip->lun); | ||
1815 | aip->size = 0; | ||
1816 | aip->read_only = 1; | ||
1817 | aip->removable = 1; | ||
1818 | aip->changed = 1; /* next acsi_open will try again... */ | ||
1819 | } | ||
1820 | |||
1821 | ENABLE_IRQ(); | ||
1822 | stdma_release(); | ||
1823 | set_capacity(disk, aip->size); | ||
1824 | return 0; | ||
1825 | } | ||
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 27a139025ced..6ce8b897e262 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c | |||
@@ -1363,7 +1363,7 @@ static void redo_fd_request(void) | |||
1363 | #ifdef DEBUG | 1363 | #ifdef DEBUG |
1364 | printk("fd: sector %ld + %d requested for %s\n", | 1364 | printk("fd: sector %ld + %d requested for %s\n", |
1365 | CURRENT->sector,cnt, | 1365 | CURRENT->sector,cnt, |
1366 | (CURRENT->cmd==READ)?"read":"write"); | 1366 | (rq_data_dir(CURRENT) == READ) ? "read" : "write"); |
1367 | #endif | 1367 | #endif |
1368 | block = CURRENT->sector + cnt; | 1368 | block = CURRENT->sector + cnt; |
1369 | if ((int)block > floppy->blocks) { | 1369 | if ((int)block > floppy->blocks) { |
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5acc6c44aead..0fcad430474e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -87,6 +87,7 @@ static const struct pci_device_id cciss_pci_device_id[] = { | |||
87 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3214}, | 87 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3214}, |
88 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215}, | 88 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215}, |
89 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3237}, | 89 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3237}, |
90 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D}, | ||
90 | {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 91 | {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
91 | PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, | 92 | PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, |
92 | {0,} | 93 | {0,} |
@@ -119,6 +120,7 @@ static struct board_type products[] = { | |||
119 | {0x3214103C, "Smart Array E200i", &SA5_access, 120}, | 120 | {0x3214103C, "Smart Array E200i", &SA5_access, 120}, |
120 | {0x3215103C, "Smart Array E200i", &SA5_access, 120}, | 121 | {0x3215103C, "Smart Array E200i", &SA5_access, 120}, |
121 | {0x3237103C, "Smart Array E500", &SA5_access, 512}, | 122 | {0x3237103C, "Smart Array E500", &SA5_access, 512}, |
123 | {0x323D103C, "Smart Array P700m", &SA5_access, 512}, | ||
122 | {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120}, | 124 | {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120}, |
123 | }; | 125 | }; |
124 | 126 | ||
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 0ed5470d2533..4503290da407 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -74,6 +74,7 @@ | |||
74 | #include <linux/highmem.h> | 74 | #include <linux/highmem.h> |
75 | #include <linux/gfp.h> | 75 | #include <linux/gfp.h> |
76 | #include <linux/kthread.h> | 76 | #include <linux/kthread.h> |
77 | #include <linux/splice.h> | ||
77 | 78 | ||
78 | #include <asm/uaccess.h> | 79 | #include <asm/uaccess.h> |
79 | 80 | ||
@@ -401,50 +402,73 @@ struct lo_read_data { | |||
401 | }; | 402 | }; |
402 | 403 | ||
403 | static int | 404 | static int |
404 | lo_read_actor(read_descriptor_t *desc, struct page *page, | 405 | lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, |
405 | unsigned long offset, unsigned long size) | 406 | struct splice_desc *sd) |
406 | { | 407 | { |
407 | unsigned long count = desc->count; | 408 | struct lo_read_data *p = sd->u.data; |
408 | struct lo_read_data *p = desc->arg.data; | ||
409 | struct loop_device *lo = p->lo; | 409 | struct loop_device *lo = p->lo; |
410 | struct page *page = buf->page; | ||
410 | sector_t IV; | 411 | sector_t IV; |
412 | size_t size; | ||
413 | int ret; | ||
411 | 414 | ||
412 | IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9); | 415 | ret = buf->ops->confirm(pipe, buf); |
416 | if (unlikely(ret)) | ||
417 | return ret; | ||
413 | 418 | ||
414 | if (size > count) | 419 | IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + |
415 | size = count; | 420 | (buf->offset >> 9); |
421 | size = sd->len; | ||
422 | if (size > p->bsize) | ||
423 | size = p->bsize; | ||
416 | 424 | ||
417 | if (lo_do_transfer(lo, READ, page, offset, p->page, p->offset, size, IV)) { | 425 | if (lo_do_transfer(lo, READ, page, buf->offset, p->page, p->offset, size, IV)) { |
418 | size = 0; | ||
419 | printk(KERN_ERR "loop: transfer error block %ld\n", | 426 | printk(KERN_ERR "loop: transfer error block %ld\n", |
420 | page->index); | 427 | page->index); |
421 | desc->error = -EINVAL; | 428 | size = -EINVAL; |
422 | } | 429 | } |
423 | 430 | ||
424 | flush_dcache_page(p->page); | 431 | flush_dcache_page(p->page); |
425 | 432 | ||
426 | desc->count = count - size; | 433 | if (size > 0) |
427 | desc->written += size; | 434 | p->offset += size; |
428 | p->offset += size; | 435 | |
429 | return size; | 436 | return size; |
430 | } | 437 | } |
431 | 438 | ||
432 | static int | 439 | static int |
440 | lo_direct_splice_actor(struct pipe_inode_info *pipe, struct splice_desc *sd) | ||
441 | { | ||
442 | return __splice_from_pipe(pipe, sd, lo_splice_actor); | ||
443 | } | ||
444 | |||
445 | static int | ||
433 | do_lo_receive(struct loop_device *lo, | 446 | do_lo_receive(struct loop_device *lo, |
434 | struct bio_vec *bvec, int bsize, loff_t pos) | 447 | struct bio_vec *bvec, int bsize, loff_t pos) |
435 | { | 448 | { |
436 | struct lo_read_data cookie; | 449 | struct lo_read_data cookie; |
450 | struct splice_desc sd; | ||
437 | struct file *file; | 451 | struct file *file; |
438 | int retval; | 452 | long retval; |
439 | 453 | ||
440 | cookie.lo = lo; | 454 | cookie.lo = lo; |
441 | cookie.page = bvec->bv_page; | 455 | cookie.page = bvec->bv_page; |
442 | cookie.offset = bvec->bv_offset; | 456 | cookie.offset = bvec->bv_offset; |
443 | cookie.bsize = bsize; | 457 | cookie.bsize = bsize; |
458 | |||
459 | sd.len = 0; | ||
460 | sd.total_len = bvec->bv_len; | ||
461 | sd.flags = 0; | ||
462 | sd.pos = pos; | ||
463 | sd.u.data = &cookie; | ||
464 | |||
444 | file = lo->lo_backing_file; | 465 | file = lo->lo_backing_file; |
445 | retval = file->f_op->sendfile(file, &pos, bvec->bv_len, | 466 | retval = splice_direct_to_actor(file, &sd, lo_direct_splice_actor); |
446 | lo_read_actor, &cookie); | 467 | |
447 | return (retval < 0)? retval: 0; | 468 | if (retval < 0) |
469 | return retval; | ||
470 | |||
471 | return 0; | ||
448 | } | 472 | } |
449 | 473 | ||
450 | static int | 474 | static int |
@@ -679,8 +703,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file, | |||
679 | if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) | 703 | if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) |
680 | goto out_putf; | 704 | goto out_putf; |
681 | 705 | ||
682 | /* new backing store needs to support loop (eg sendfile) */ | 706 | /* new backing store needs to support loop (eg splice_read) */ |
683 | if (!inode->i_fop->sendfile) | 707 | if (!inode->i_fop->splice_read) |
684 | goto out_putf; | 708 | goto out_putf; |
685 | 709 | ||
686 | /* size of the new backing store needs to be the same */ | 710 | /* size of the new backing store needs to be the same */ |
@@ -760,7 +784,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, | |||
760 | * If we can't read - sorry. If we only can't write - well, | 784 | * If we can't read - sorry. If we only can't write - well, |
761 | * it's going to be read-only. | 785 | * it's going to be read-only. |
762 | */ | 786 | */ |
763 | if (!file->f_op->sendfile) | 787 | if (!file->f_op->splice_read) |
764 | goto out_putf; | 788 | goto out_putf; |
765 | if (aops->prepare_write && aops->commit_write) | 789 | if (aops->prepare_write && aops->commit_write) |
766 | lo_flags |= LO_FLAGS_USE_AOPS; | 790 | lo_flags |= LO_FLAGS_USE_AOPS; |
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 069ae39a9cd9..c575fb1d585f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c | |||
@@ -416,7 +416,7 @@ static void nbd_clear_que(struct nbd_device *lo) | |||
416 | /* | 416 | /* |
417 | * We always wait for result of write, for now. It would be nice to make it optional | 417 | * We always wait for result of write, for now. It would be nice to make it optional |
418 | * in future | 418 | * in future |
419 | * if ((req->cmd == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) | 419 | * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) |
420 | * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } | 420 | * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } |
421 | */ | 421 | */ |
422 | 422 | ||
diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig deleted file mode 100644 index 4b12e9031fb3..000000000000 --- a/drivers/cdrom/Kconfig +++ /dev/null | |||
@@ -1,213 +0,0 @@ | |||
1 | # | ||
2 | # CDROM driver configuration | ||
3 | # | ||
4 | |||
5 | menu "Old CD-ROM drivers (not SCSI, not IDE)" | ||
6 | depends on ISA && BLOCK | ||
7 | |||
8 | config CD_NO_IDESCSI | ||
9 | bool "Support non-SCSI/IDE/ATAPI CDROM drives" | ||
10 | ---help--- | ||
11 | If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y | ||
12 | here, otherwise N. Read the CD-ROM-HOWTO, available from | ||
13 | <http://www.tldp.org/docs.html#howto>. | ||
14 | |||
15 | Note that the answer to this question doesn't directly affect the | ||
16 | kernel: saying N will just cause the configurator to skip all | ||
17 | the questions about these CD-ROM drives. If you are unsure what you | ||
18 | have, say Y and find out whether you have one of the following | ||
19 | drives. | ||
20 | |||
21 | For each of these drivers, a <file:Documentation/cdrom/{driver_name}> | ||
22 | exists. Especially in cases where you do not know exactly which kind | ||
23 | of drive you have you should read there. Most of these drivers use a | ||
24 | file drivers/cdrom/{driver_name}.h where you can define your | ||
25 | interface parameters and switch some internal goodies. | ||
26 | |||
27 | To compile these CD-ROM drivers as a module, choose M instead of Y. | ||
28 | |||
29 | If you want to use any of these CD-ROM drivers, you also have to | ||
30 | answer Y or M to "ISO 9660 CD-ROM file system support" below (this | ||
31 | answer will get "defaulted" for you if you enable any of the Linux | ||
32 | CD-ROM drivers). | ||
33 | |||
34 | config AZTCD | ||
35 | tristate "Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support" | ||
36 | depends on CD_NO_IDESCSI | ||
37 | ---help--- | ||
38 | This is your driver if you have an Aztech CDA268-01A, Orchid | ||
39 | CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or | ||
40 | CR540 CD-ROM drive. This driver -- just like all these CD-ROM | ||
41 | drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such | ||
42 | as Aztech CDA269-031SE. Please read the file | ||
43 | <file:Documentation/cdrom/aztcd>. | ||
44 | |||
45 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
46 | file system support" below, because that's the file system used on | ||
47 | CD-ROMs. | ||
48 | |||
49 | To compile this driver as a module, choose M here: the | ||
50 | module will be called aztcd. | ||
51 | |||
52 | config GSCD | ||
53 | tristate "Goldstar R420 CDROM support" | ||
54 | depends on CD_NO_IDESCSI | ||
55 | ---help--- | ||
56 | If this is your CD-ROM drive, say Y here. As described in the file | ||
57 | <file:Documentation/cdrom/gscd>, you might have to change a setting | ||
58 | in the file <file:drivers/cdrom/gscd.h> before compiling the | ||
59 | kernel. Please read the file <file:Documentation/cdrom/gscd>. | ||
60 | |||
61 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
62 | file system support" below, because that's the file system used on | ||
63 | CD-ROMs. | ||
64 | |||
65 | To compile this driver as a module, choose M here: the | ||
66 | module will be called gscd. | ||
67 | |||
68 | config SBPCD | ||
69 | tristate "Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support" | ||
70 | depends on CD_NO_IDESCSI && BROKEN_ON_SMP | ||
71 | ---help--- | ||
72 | This driver supports most of the drives which use the Panasonic or | ||
73 | Sound Blaster interface. Please read the file | ||
74 | <file:Documentation/cdrom/sbpcd>. | ||
75 | |||
76 | The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives | ||
77 | (sometimes labeled "Creative"), the Creative Labs CD200, the | ||
78 | Longshine LCS-7260, the "IBM External ISA CD-ROM" (in fact a CR-56x | ||
79 | model), the TEAC CD-55A fall under this category. Some other | ||
80 | "electrically compatible" drives (Vertos, Genoa, some Funai models) | ||
81 | are currently not supported; for the Sanyo H94A drive currently a | ||
82 | separate driver (asked later) is responsible. Most drives have a | ||
83 | uniquely shaped faceplate, with a caddyless motorized drawer, but | ||
84 | without external brand markings. The older CR-52x drives have a | ||
85 | caddy and manual loading/eject, but still no external markings. The | ||
86 | driver is able to do an extended auto-probing for interface | ||
87 | addresses and drive types; this can help to find facts in cases you | ||
88 | are not sure, but can consume some time during the boot process if | ||
89 | none of the supported drives gets found. Once your drive got found, | ||
90 | you should enter the reported parameters into | ||
91 | <file:drivers/cdrom/sbpcd.h> and set "DISTRIBUTION 0" there. | ||
92 | |||
93 | This driver can support up to four CD-ROM controller cards, and each | ||
94 | card can support up to four CD-ROM drives; if you say Y here, you | ||
95 | will be asked how many controller cards you have. If compiled as a | ||
96 | module, only one controller card (but with up to four drives) is | ||
97 | usable. | ||
98 | |||
99 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
100 | file system support" below, because that's the file system used on | ||
101 | CD-ROMs. | ||
102 | |||
103 | To compile this driver as a module, choose M here: the | ||
104 | module will be called sbpcd. | ||
105 | |||
106 | config MCDX | ||
107 | tristate "Mitsumi CDROM support" | ||
108 | depends on CD_NO_IDESCSI | ||
109 | ---help--- | ||
110 | Use this driver if you want to be able to use your Mitsumi LU-005, | ||
111 | FX-001 or FX-001D CD-ROM drive. | ||
112 | |||
113 | Please read the file <file:Documentation/cdrom/mcdx>. | ||
114 | |||
115 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
116 | file system support" below, because that's the file system used on | ||
117 | CD-ROMs. | ||
118 | |||
119 | To compile this driver as a module, choose M here: the | ||
120 | module will be called mcdx. | ||
121 | |||
122 | config OPTCD | ||
123 | tristate "Optics Storage DOLPHIN 8000AT CDROM support" | ||
124 | depends on CD_NO_IDESCSI | ||
125 | ---help--- | ||
126 | This is the driver for the 'DOLPHIN' drive with a 34-pin Sony | ||
127 | compatible interface. It also works with the Lasermate CR328A. If | ||
128 | you have one of those, say Y. This driver does not work for the | ||
129 | Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that | ||
130 | one. Please read the file <file:Documentation/cdrom/optcd>. | ||
131 | |||
132 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
133 | file system support" below, because that's the file system used on | ||
134 | CD-ROMs. | ||
135 | |||
136 | To compile this driver as a module, choose M here: the | ||
137 | module will be called optcd. | ||
138 | |||
139 | config CM206 | ||
140 | tristate "Philips/LMS CM206 CDROM support" | ||
141 | depends on CD_NO_IDESCSI && BROKEN_ON_SMP | ||
142 | ---help--- | ||
143 | If you have a Philips/LMS CD-ROM drive cm206 in combination with a | ||
144 | cm260 host adapter card, say Y here. Please also read the file | ||
145 | <file:Documentation/cdrom/cm206>. | ||
146 | |||
147 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
148 | file system support" below, because that's the file system used on | ||
149 | CD-ROMs. | ||
150 | |||
151 | To compile this driver as a module, choose M here: the | ||
152 | module will be called cm206. | ||
153 | |||
154 | config SJCD | ||
155 | tristate "Sanyo CDR-H94A CDROM support" | ||
156 | depends on CD_NO_IDESCSI | ||
157 | help | ||
158 | If this is your CD-ROM drive, say Y here and read the file | ||
159 | <file:Documentation/cdrom/sjcd>. You should then also say Y or M to | ||
160 | "ISO 9660 CD-ROM file system support" below, because that's the | ||
161 | file system used on CD-ROMs. | ||
162 | |||
163 | To compile this driver as a module, choose M here: the | ||
164 | module will be called sjcd. | ||
165 | |||
166 | config ISP16_CDI | ||
167 | tristate "ISP16/MAD16/Mozart soft configurable cdrom interface support" | ||
168 | depends on CD_NO_IDESCSI | ||
169 | ---help--- | ||
170 | These are sound cards with built-in cdrom interfaces using the OPTi | ||
171 | 82C928 or 82C929 chips. Say Y here to have them detected and | ||
172 | possibly configured at boot time. In addition, You'll have to say Y | ||
173 | to a driver for the particular cdrom drive you have attached to the | ||
174 | card. Read <file:Documentation/cdrom/isp16> for details. | ||
175 | |||
176 | To compile this driver as a module, choose M here: the | ||
177 | module will be called isp16. | ||
178 | |||
179 | config CDU31A | ||
180 | tristate "Sony CDU31A/CDU33A CDROM support" | ||
181 | depends on CD_NO_IDESCSI && BROKEN_ON_SMP | ||
182 | ---help--- | ||
183 | These CD-ROM drives have a spring-pop-out caddyless drawer, and a | ||
184 | rectangular green LED centered beneath it. NOTE: these CD-ROM | ||
185 | drives will not be auto detected by the kernel at boot time; you | ||
186 | have to provide the interface address as an option to the kernel at | ||
187 | boot time as described in <file:Documentation/cdrom/cdu31a> or fill | ||
188 | in your parameters into <file:drivers/cdrom/cdu31a.c>. Try "man | ||
189 | bootparam" or see the documentation of your boot loader (lilo or | ||
190 | loadlin) about how to pass options to the kernel. | ||
191 | |||
192 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
193 | file system support" below, because that's the file system used on | ||
194 | CD-ROMs. | ||
195 | |||
196 | To compile this driver as a module, choose M here: the | ||
197 | module will be called cdu31a. | ||
198 | |||
199 | config CDU535 | ||
200 | tristate "Sony CDU535 CDROM support" | ||
201 | depends on CD_NO_IDESCSI | ||
202 | ---help--- | ||
203 | This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM | ||
204 | drives. Please read the file <file:Documentation/cdrom/sonycd535>. | ||
205 | |||
206 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
207 | file system support" below, because that's the file system used on | ||
208 | CD-ROMs. | ||
209 | |||
210 | To compile this driver as a module, choose M here: the | ||
211 | module will be called sonycd535. | ||
212 | |||
213 | endmenu | ||
diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile index d1d1e5a4be73..774c180a4e11 100644 --- a/drivers/cdrom/Makefile +++ b/drivers/cdrom/Makefile | |||
@@ -10,14 +10,4 @@ obj-$(CONFIG_BLK_DEV_SR) += cdrom.o | |||
10 | obj-$(CONFIG_PARIDE_PCD) += cdrom.o | 10 | obj-$(CONFIG_PARIDE_PCD) += cdrom.o |
11 | obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o | 11 | obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o |
12 | 12 | ||
13 | obj-$(CONFIG_AZTCD) += aztcd.o | ||
14 | obj-$(CONFIG_CDU31A) += cdu31a.o cdrom.o | ||
15 | obj-$(CONFIG_CM206) += cm206.o cdrom.o | ||
16 | obj-$(CONFIG_GSCD) += gscd.o | ||
17 | obj-$(CONFIG_ISP16_CDI) += isp16.o | ||
18 | obj-$(CONFIG_MCDX) += mcdx.o cdrom.o | ||
19 | obj-$(CONFIG_OPTCD) += optcd.o | ||
20 | obj-$(CONFIG_SBPCD) += sbpcd.o cdrom.o | ||
21 | obj-$(CONFIG_SJCD) += sjcd.o | ||
22 | obj-$(CONFIG_CDU535) += sonycd535.o | ||
23 | obj-$(CONFIG_VIOCD) += viocd.o cdrom.o | 13 | obj-$(CONFIG_VIOCD) += viocd.o cdrom.o |
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c deleted file mode 100644 index 1f9fb7a96703..000000000000 --- a/drivers/cdrom/aztcd.c +++ /dev/null | |||
@@ -1,2492 +0,0 @@ | |||
1 | #define AZT_VERSION "2.60" | ||
2 | |||
3 | /* $Id: aztcd.c,v 2.60 1997/11/29 09:51:19 root Exp root $ | ||
4 | linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver | ||
5 | |||
6 | Copyright (C) 1994-98 Werner Zimmermann(Werner.Zimmermann@fht-esslingen.de) | ||
7 | |||
8 | based on Mitsumi CDROM driver by Martin Hariss and preworks by | ||
9 | Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby | ||
10 | Schirmer. | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2, or (at your option) | ||
15 | any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | |||
26 | HISTORY | ||
27 | V0.0 Adaption to Aztech CD268-01A Version 1.3 | ||
28 | Version is PRE_ALPHA, unresolved points: | ||
29 | 1. I use busy wait instead of timer wait in STEN_LOW,DTEN_LOW | ||
30 | thus driver causes CPU overhead and is very slow | ||
31 | 2. could not find a way to stop the drive, when it is | ||
32 | in data read mode, therefore I had to set | ||
33 | msf.end.min/sec/frame to 0:0:1 (in azt_poll); so only one | ||
34 | frame can be read in sequence, this is also the reason for | ||
35 | 3. getting 'timeout in state 4' messages, but nevertheless | ||
36 | it works | ||
37 | W.Zimmermann, Oct. 31, 1994 | ||
38 | V0.1 Version is ALPHA, problems #2 and #3 resolved. | ||
39 | W.Zimmermann, Nov. 3, 1994 | ||
40 | V0.2 Modification to some comments, debugging aids for partial test | ||
41 | with Borland C under DOS eliminated. Timer interrupt wait | ||
42 | STEN_LOW_WAIT additionally to busy wait for STEN_LOW implemented; | ||
43 | use it only for the 'slow' commands (ACMD_GET_Q_CHANNEL, ACMD_ | ||
44 | SEEK_TO_LEAD_IN), all other commands are so 'fast', that busy | ||
45 | waiting seems better to me than interrupt rescheduling. | ||
46 | Besides that, when used in the wrong place, STEN_LOW_WAIT causes | ||
47 | kernel panic. | ||
48 | In function aztPlay command ACMD_PLAY_AUDIO added, should make | ||
49 | audio functions work. The Aztech drive needs different commands | ||
50 | to read data tracks and play audio tracks. | ||
51 | W.Zimmermann, Nov. 8, 1994 | ||
52 | V0.3 Recognition of missing drive during boot up improved (speeded up). | ||
53 | W.Zimmermann, Nov. 13, 1994 | ||
54 | V0.35 Rewrote the control mechanism in azt_poll (formerly mcd_poll) | ||
55 | including removal of all 'goto' commands. :-); | ||
56 | J. Nardone, Nov. 14, 1994 | ||
57 | V0.4 Renamed variables and constants to 'azt' instead of 'mcd'; had | ||
58 | to make some "compatibility" defines in azt.h; please note, | ||
59 | that the source file was renamed to azt.c, the include file to | ||
60 | azt.h | ||
61 | Speeded up drive recognition during init (will be a little bit | ||
62 | slower than before if no drive is installed!); suggested by | ||
63 | Robby Schirmer. | ||
64 | read_count declared volatile and set to AZT_BUF_SIZ to make | ||
65 | drive faster (now 300kB/sec, was 60kB/sec before, measured | ||
66 | by 'time dd if=/dev/cdrom of=/dev/null bs=2048 count=4096'; | ||
67 | different AZT_BUF_SIZes were test, above 16 no further im- | ||
68 | provement seems to be possible; suggested by E.Moenkeberg. | ||
69 | W.Zimmermann, Nov. 18, 1994 | ||
70 | V0.42 Included getAztStatus command in GetQChannelInfo() to allow | ||
71 | reading Q-channel info on audio disks, if drive is stopped, | ||
72 | and some other bug fixes in the audio stuff, suggested by | ||
73 | Robby Schirmer. | ||
74 | Added more ioctls (reading data in mode 1 and mode 2). | ||
75 | Completely removed the old azt_poll() routine. | ||
76 | Detection of ORCHID CDS-3110 in aztcd_init implemented. | ||
77 | Additional debugging aids (see the readme file). | ||
78 | W.Zimmermann, Dec. 9, 1994 | ||
79 | V0.50 Autodetection of drives implemented. | ||
80 | W.Zimmermann, Dec. 12, 1994 | ||
81 | V0.52 Prepared for including in the standard kernel, renamed most | ||
82 | variables to contain 'azt', included autoconf.h | ||
83 | W.Zimmermann, Dec. 16, 1994 | ||
84 | V0.6 Version for being included in the standard Linux kernel. | ||
85 | Renamed source and header file to aztcd.c and aztcd.h | ||
86 | W.Zimmermann, Dec. 24, 1994 | ||
87 | V0.7 Changed VERIFY_READ to VERIFY_WRITE in aztcd_ioctl, case | ||
88 | CDROMREADMODE1 and CDROMREADMODE2; bug fix in the ioctl, | ||
89 | which causes kernel crashes when playing audio, changed | ||
90 | include-files (config.h instead of autoconf.h, removed | ||
91 | delay.h) | ||
92 | W.Zimmermann, Jan. 8, 1995 | ||
93 | V0.72 Some more modifications for adaption to the standard kernel. | ||
94 | W.Zimmermann, Jan. 16, 1995 | ||
95 | V0.80 aztcd is now part of the standard kernel since version 1.1.83. | ||
96 | Modified the SET_TIMER and CLEAR_TIMER macros to comply with | ||
97 | the new timer scheme. | ||
98 | W.Zimmermann, Jan. 21, 1995 | ||
99 | V0.90 Included CDROMVOLCTRL, but with my Aztech drive I can only turn | ||
100 | the channels on and off. If it works better with your drive, | ||
101 | please mail me. Also implemented ACMD_CLOSE for CDROMSTART. | ||
102 | W.Zimmermann, Jan. 24, 1995 | ||
103 | V1.00 Implemented close and lock tray commands. Patches supplied by | ||
104 | Frank Racis | ||
105 | Added support for loadable MODULEs, so aztcd can now also be | ||
106 | loaded by insmod and removed by rmmod during run time | ||
107 | Werner Zimmermann, Mar. 24, 95 | ||
108 | V1.10 Implemented soundcard configuration for Orchid CDS-3110 drives | ||
109 | connected to Soundwave32 cards. Release for LST 2.1. | ||
110 | (still experimental) | ||
111 | Werner Zimmermann, May 8, 95 | ||
112 | V1.20 Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but | ||
113 | sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver- | ||
114 | sion needs an update of Dosemu0.60's cdrom.c, which will come with the | ||
115 | next revision of Dosemu. | ||
116 | Also Soundwave32 support now works. | ||
117 | Werner Zimmermann, May 22, 95 | ||
118 | V1.30 Auto-eject feature. Inspired by Franc Racis (racis@psu.edu) | ||
119 | Werner Zimmermann, July 4, 95 | ||
120 | V1.40 Started multisession support. Implementation copied from mcdx.c | ||
121 | by Heiko Schlittermann. Not tested yet. | ||
122 | Werner Zimmermann, July 15, 95 | ||
123 | V1.50 Implementation of ioctl CDROMRESET, continued multisession, began | ||
124 | XA, but still untested. Heavy modifications to drive status de- | ||
125 | tection. | ||
126 | Werner Zimmermann, July 25, 95 | ||
127 | V1.60 XA support now should work. Speeded up drive recognition in cases, | ||
128 | where no drive is installed. | ||
129 | Werner Zimmermann, August 8, 1995 | ||
130 | V1.70 Multisession support now is completed, but there is still not | ||
131 | enough testing done. If you can test it, please contact me. For | ||
132 | details please read Documentation/cdrom/aztcd | ||
133 | Werner Zimmermann, August 19, 1995 | ||
134 | V1.80 Modification to suit the new kernel boot procedure introduced | ||
135 | with kernel 1.3.33. Will definitely not work with older kernels. | ||
136 | Programming done by Linus himself. | ||
137 | Werner Zimmermann, October 11, 1995 | ||
138 | V1.90 Support for Conrad TXC drives, thank's to Jochen Kunz and Olaf Kaluza. | ||
139 | Werner Zimmermann, October 21, 1995 | ||
140 | V2.00 Changed #include "blk.h" to <linux/blk.h> as the directory | ||
141 | structure was changed. README.aztcd is now /usr/src/docu- | ||
142 | mentation/cdrom/aztcd | ||
143 | Werner Zimmermann, November 10, 95 | ||
144 | V2.10 Started to modify azt_poll to prevent reading beyond end of | ||
145 | tracks. | ||
146 | Werner Zimmermann, December 3, 95 | ||
147 | V2.20 Changed some comments | ||
148 | Werner Zimmermann, April 1, 96 | ||
149 | V2.30 Implemented support for CyCDROM CR520, CR940, Code for CR520 | ||
150 | delivered by H.Berger with preworks by E.Moenkeberg. | ||
151 | Werner Zimmermann, April 29, 96 | ||
152 | V2.40 Reorganized the placement of functions in the source code file | ||
153 | to reflect the layered approach; did not actually change code | ||
154 | Werner Zimmermann, May 1, 96 | ||
155 | V2.50 Heiko Eissfeldt suggested to remove some VERIFY_READs in | ||
156 | aztcd_ioctl; check_aztcd_media_change modified | ||
157 | Werner Zimmermann, May 16, 96 | ||
158 | V2.60 Implemented Auto-Probing; made changes for kernel's 2.1.xx blocksize | ||
159 | Adaption to linux kernel > 2.1.0 | ||
160 | Werner Zimmermann, Nov 29, 97 | ||
161 | |||
162 | November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
163 | Removed init_module & cleanup_module in favor of | ||
164 | module_init & module_exit. | ||
165 | Torben Mathiasen <tmm@image.dk> | ||
166 | */ | ||
167 | |||
168 | #include <linux/blkdev.h> | ||
169 | #include "aztcd.h" | ||
170 | |||
171 | #include <linux/module.h> | ||
172 | #include <linux/errno.h> | ||
173 | #include <linux/mm.h> | ||
174 | #include <linux/timer.h> | ||
175 | #include <linux/fs.h> | ||
176 | #include <linux/kernel.h> | ||
177 | #include <linux/cdrom.h> | ||
178 | #include <linux/ioport.h> | ||
179 | #include <linux/string.h> | ||
180 | #include <linux/major.h> | ||
181 | |||
182 | #include <linux/init.h> | ||
183 | |||
184 | #include <asm/system.h> | ||
185 | #include <asm/io.h> | ||
186 | |||
187 | #include <asm/uaccess.h> | ||
188 | |||
189 | /*########################################################################### | ||
190 | Defines | ||
191 | ########################################################################### | ||
192 | */ | ||
193 | |||
194 | #define MAJOR_NR AZTECH_CDROM_MAJOR | ||
195 | #define QUEUE (azt_queue) | ||
196 | #define CURRENT elv_next_request(azt_queue) | ||
197 | #define SET_TIMER(func, jifs) delay_timer.expires = jiffies + (jifs); \ | ||
198 | delay_timer.function = (void *) (func); \ | ||
199 | add_timer(&delay_timer); | ||
200 | |||
201 | #define CLEAR_TIMER del_timer(&delay_timer); | ||
202 | |||
203 | #define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\ | ||
204 | return value;} | ||
205 | #define RETURN(message) {printk("aztcd: Warning: %s failed\n",message);\ | ||
206 | return;} | ||
207 | |||
208 | /* Macros to switch the IDE-interface to the slave device and back to the master*/ | ||
209 | #define SWITCH_IDE_SLAVE outb_p(0xa0,azt_port+6); \ | ||
210 | outb_p(0x10,azt_port+6); \ | ||
211 | outb_p(0x00,azt_port+7); \ | ||
212 | outb_p(0x10,azt_port+6); | ||
213 | #define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6); | ||
214 | |||
215 | |||
216 | #if 0 | ||
217 | #define AZT_TEST | ||
218 | #define AZT_TEST1 /* <int-..> */ | ||
219 | #define AZT_TEST2 /* do_aztcd_request */ | ||
220 | #define AZT_TEST3 /* AZT_S_state */ | ||
221 | #define AZT_TEST4 /* QUICK_LOOP-counter */ | ||
222 | #define AZT_TEST5 /* port(1) state */ | ||
223 | #define AZT_DEBUG | ||
224 | #define AZT_DEBUG_MULTISESSION | ||
225 | #endif | ||
226 | |||
227 | static struct request_queue *azt_queue; | ||
228 | |||
229 | static int current_valid(void) | ||
230 | { | ||
231 | return CURRENT && | ||
232 | CURRENT->cmd == READ && | ||
233 | CURRENT->sector != -1; | ||
234 | } | ||
235 | |||
236 | #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA) | ||
237 | #define AZT_BUF_SIZ 16 | ||
238 | |||
239 | #define READ_TIMEOUT 3000 | ||
240 | |||
241 | #define azt_port aztcd /*needed for the modutils */ | ||
242 | |||
243 | /*########################################################################## | ||
244 | Type Definitions | ||
245 | ########################################################################## | ||
246 | */ | ||
247 | enum azt_state_e { AZT_S_IDLE, /* 0 */ | ||
248 | AZT_S_START, /* 1 */ | ||
249 | AZT_S_MODE, /* 2 */ | ||
250 | AZT_S_READ, /* 3 */ | ||
251 | AZT_S_DATA, /* 4 */ | ||
252 | AZT_S_STOP, /* 5 */ | ||
253 | AZT_S_STOPPING /* 6 */ | ||
254 | }; | ||
255 | enum azt_read_modes { AZT_MODE_0, /*read mode for audio disks, not supported by Aztech firmware */ | ||
256 | AZT_MODE_1, /*read mode for normal CD-ROMs */ | ||
257 | AZT_MODE_2 /*read mode for XA CD-ROMs */ | ||
258 | }; | ||
259 | |||
260 | /*########################################################################## | ||
261 | Global Variables | ||
262 | ########################################################################## | ||
263 | */ | ||
264 | static int aztPresent = 0; | ||
265 | |||
266 | static volatile int azt_transfer_is_active = 0; | ||
267 | |||
268 | static char azt_buf[CD_FRAMESIZE_RAW * AZT_BUF_SIZ]; /*buffer for block size conversion */ | ||
269 | #if AZT_PRIVATE_IOCTLS | ||
270 | static char buf[CD_FRAMESIZE_RAW]; /*separate buffer for the ioctls */ | ||
271 | #endif | ||
272 | |||
273 | static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn; | ||
274 | static volatile int azt_buf_in, azt_buf_out = -1; | ||
275 | static volatile int azt_error = 0; | ||
276 | static int azt_open_count = 0; | ||
277 | static volatile enum azt_state_e azt_state = AZT_S_IDLE; | ||
278 | #ifdef AZT_TEST3 | ||
279 | static volatile enum azt_state_e azt_state_old = AZT_S_STOP; | ||
280 | static volatile int azt_st_old = 0; | ||
281 | #endif | ||
282 | static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1; | ||
283 | |||
284 | static int azt_mode = -1; | ||
285 | static volatile int azt_read_count = 1; | ||
286 | |||
287 | static int azt_port = AZT_BASE_ADDR; | ||
288 | |||
289 | module_param(azt_port, int, 0); | ||
290 | |||
291 | static int azt_port_auto[16] = AZT_BASE_AUTO; | ||
292 | |||
293 | static char azt_cont = 0; | ||
294 | static char azt_init_end = 0; | ||
295 | static char azt_auto_eject = AZT_AUTO_EJECT; | ||
296 | |||
297 | static int AztTimeout, AztTries; | ||
298 | static DECLARE_WAIT_QUEUE_HEAD(azt_waitq); | ||
299 | static DEFINE_TIMER(delay_timer, NULL, 0, 0); | ||
300 | |||
301 | static struct azt_DiskInfo DiskInfo; | ||
302 | static struct azt_Toc Toc[MAX_TRACKS]; | ||
303 | static struct azt_Play_msf azt_Play; | ||
304 | |||
305 | static int aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
306 | static char aztDiskChanged = 1; | ||
307 | static char aztTocUpToDate = 0; | ||
308 | |||
309 | static unsigned char aztIndatum; | ||
310 | static unsigned long aztTimeOutCount; | ||
311 | static int aztCmd = 0; | ||
312 | |||
313 | static DEFINE_SPINLOCK(aztSpin); | ||
314 | |||
315 | /*########################################################################### | ||
316 | Function Prototypes | ||
317 | ########################################################################### | ||
318 | */ | ||
319 | /* CDROM Drive Low Level I/O Functions */ | ||
320 | static void aztStatTimer(void); | ||
321 | |||
322 | /* CDROM Drive Command Functions */ | ||
323 | static int aztGetDiskInfo(void); | ||
324 | #if AZT_MULTISESSION | ||
325 | static int aztGetMultiDiskInfo(void); | ||
326 | #endif | ||
327 | static int aztGetToc(int multi); | ||
328 | |||
329 | /* Kernel Interface Functions */ | ||
330 | static int check_aztcd_media_change(struct gendisk *disk); | ||
331 | static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | ||
332 | unsigned long arg); | ||
333 | static int aztcd_open(struct inode *ip, struct file *fp); | ||
334 | static int aztcd_release(struct inode *inode, struct file *file); | ||
335 | |||
336 | static struct block_device_operations azt_fops = { | ||
337 | .owner = THIS_MODULE, | ||
338 | .open = aztcd_open, | ||
339 | .release = aztcd_release, | ||
340 | .ioctl = aztcd_ioctl, | ||
341 | .media_changed = check_aztcd_media_change, | ||
342 | }; | ||
343 | |||
344 | /* Aztcd State Machine: Controls Drive Operating State */ | ||
345 | static void azt_poll(void); | ||
346 | |||
347 | /* Miscellaneous support functions */ | ||
348 | static void azt_hsg2msf(long hsg, struct msf *msf); | ||
349 | static long azt_msf2hsg(struct msf *mp); | ||
350 | static void azt_bin2bcd(unsigned char *p); | ||
351 | static int azt_bcd2bin(unsigned char bcd); | ||
352 | |||
353 | /*########################################################################## | ||
354 | CDROM Drive Low Level I/O Functions | ||
355 | ########################################################################## | ||
356 | */ | ||
357 | /* Macros for the drive hardware interface handshake, these macros use | ||
358 | busy waiting */ | ||
359 | /* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/ | ||
360 | # define OP_OK op_ok() | ||
361 | static void op_ok(void) | ||
362 | { | ||
363 | aztTimeOutCount = 0; | ||
364 | do { | ||
365 | aztIndatum = inb(DATA_PORT); | ||
366 | aztTimeOutCount++; | ||
367 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
368 | printk("aztcd: Error Wait OP_OK\n"); | ||
369 | break; | ||
370 | } | ||
371 | } while (aztIndatum != AFL_OP_OK); | ||
372 | } | ||
373 | |||
374 | /* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/ | ||
375 | #if 0 | ||
376 | # define PA_OK pa_ok() | ||
377 | static void pa_ok(void) | ||
378 | { | ||
379 | aztTimeOutCount = 0; | ||
380 | do { | ||
381 | aztIndatum = inb(DATA_PORT); | ||
382 | aztTimeOutCount++; | ||
383 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
384 | printk("aztcd: Error Wait PA_OK\n"); | ||
385 | break; | ||
386 | } | ||
387 | } while (aztIndatum != AFL_PA_OK); | ||
388 | } | ||
389 | #endif | ||
390 | |||
391 | /* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/ | ||
392 | # define STEN_LOW sten_low() | ||
393 | static void sten_low(void) | ||
394 | { | ||
395 | aztTimeOutCount = 0; | ||
396 | do { | ||
397 | aztIndatum = inb(STATUS_PORT); | ||
398 | aztTimeOutCount++; | ||
399 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
400 | if (azt_init_end) | ||
401 | printk | ||
402 | ("aztcd: Error Wait STEN_LOW commands:%x\n", | ||
403 | aztCmd); | ||
404 | break; | ||
405 | } | ||
406 | } while (aztIndatum & AFL_STATUS); | ||
407 | } | ||
408 | |||
409 | /* Wait for DTEN=Low = handshake signal 'Data available'*/ | ||
410 | # define DTEN_LOW dten_low() | ||
411 | static void dten_low(void) | ||
412 | { | ||
413 | aztTimeOutCount = 0; | ||
414 | do { | ||
415 | aztIndatum = inb(STATUS_PORT); | ||
416 | aztTimeOutCount++; | ||
417 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
418 | printk("aztcd: Error Wait DTEN_OK\n"); | ||
419 | break; | ||
420 | } | ||
421 | } while (aztIndatum & AFL_DATA); | ||
422 | } | ||
423 | |||
424 | /* | ||
425 | * Macro for timer wait on STEN=Low, should only be used for 'slow' commands; | ||
426 | * may cause kernel panic when used in the wrong place | ||
427 | */ | ||
428 | #define STEN_LOW_WAIT statusAzt() | ||
429 | static void statusAzt(void) | ||
430 | { | ||
431 | AztTimeout = AZT_STATUS_DELAY; | ||
432 | SET_TIMER(aztStatTimer, HZ / 100); | ||
433 | sleep_on(&azt_waitq); | ||
434 | if (AztTimeout <= 0) | ||
435 | printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n", | ||
436 | aztCmd); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | static void aztStatTimer(void) | ||
441 | { | ||
442 | if (!(inb(STATUS_PORT) & AFL_STATUS)) { | ||
443 | wake_up(&azt_waitq); | ||
444 | return; | ||
445 | } | ||
446 | AztTimeout--; | ||
447 | if (AztTimeout <= 0) { | ||
448 | wake_up(&azt_waitq); | ||
449 | printk("aztcd: Error aztStatTimer: Timeout\n"); | ||
450 | return; | ||
451 | } | ||
452 | SET_TIMER(aztStatTimer, HZ / 100); | ||
453 | } | ||
454 | |||
455 | /*########################################################################## | ||
456 | CDROM Drive Command Functions | ||
457 | ########################################################################## | ||
458 | */ | ||
459 | /* | ||
460 | * Send a single command, return -1 on error, else 0 | ||
461 | */ | ||
462 | static int aztSendCmd(int cmd) | ||
463 | { | ||
464 | unsigned char data; | ||
465 | int retry; | ||
466 | |||
467 | #ifdef AZT_DEBUG | ||
468 | printk("aztcd: Executing command %x\n", cmd); | ||
469 | #endif | ||
470 | |||
471 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) | ||
472 | SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */ | ||
473 | |||
474 | aztCmd = cmd; | ||
475 | outb(POLLED, MODE_PORT); | ||
476 | do { | ||
477 | if (inb(STATUS_PORT) & AFL_STATUS) | ||
478 | break; | ||
479 | inb(DATA_PORT); /* if status left from last command, read and */ | ||
480 | } while (1); /* discard it */ | ||
481 | do { | ||
482 | if (inb(STATUS_PORT) & AFL_DATA) | ||
483 | break; | ||
484 | inb(DATA_PORT); /* if data left from last command, read and */ | ||
485 | } while (1); /* discard it */ | ||
486 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
487 | outb((unsigned char) cmd, CMD_PORT); | ||
488 | STEN_LOW; | ||
489 | data = inb(DATA_PORT); | ||
490 | if (data == AFL_OP_OK) { | ||
491 | return 0; | ||
492 | } /*OP_OK? */ | ||
493 | if (data == AFL_OP_ERR) { | ||
494 | STEN_LOW; | ||
495 | data = inb(DATA_PORT); | ||
496 | printk | ||
497 | ("### Error 1 aztcd: aztSendCmd %x Error Code %x\n", | ||
498 | cmd, data); | ||
499 | } | ||
500 | } | ||
501 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
502 | printk("### Error 2 aztcd: aztSendCmd %x \n", cmd); | ||
503 | azt_error = 0xA5; | ||
504 | } | ||
505 | RETURNM("aztSendCmd", -1); | ||
506 | } | ||
507 | |||
508 | /* | ||
509 | * Send a play or read command to the drive, return -1 on error, else 0 | ||
510 | */ | ||
511 | static int sendAztCmd(int cmd, struct azt_Play_msf *params) | ||
512 | { | ||
513 | unsigned char data; | ||
514 | int retry; | ||
515 | |||
516 | #ifdef AZT_DEBUG | ||
517 | printk("aztcd: play start=%02x:%02x:%02x end=%02x:%02x:%02x\n", | ||
518 | params->start.min, params->start.sec, params->start.frame, | ||
519 | params->end.min, params->end.sec, params->end.frame); | ||
520 | #endif | ||
521 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
522 | aztSendCmd(cmd); | ||
523 | outb(params->start.min, CMD_PORT); | ||
524 | outb(params->start.sec, CMD_PORT); | ||
525 | outb(params->start.frame, CMD_PORT); | ||
526 | outb(params->end.min, CMD_PORT); | ||
527 | outb(params->end.sec, CMD_PORT); | ||
528 | outb(params->end.frame, CMD_PORT); | ||
529 | STEN_LOW; | ||
530 | data = inb(DATA_PORT); | ||
531 | if (data == AFL_PA_OK) { | ||
532 | return 0; | ||
533 | } /*PA_OK ? */ | ||
534 | if (data == AFL_PA_ERR) { | ||
535 | STEN_LOW; | ||
536 | data = inb(DATA_PORT); | ||
537 | printk | ||
538 | ("### Error 1 aztcd: sendAztCmd %x Error Code %x\n", | ||
539 | cmd, data); | ||
540 | } | ||
541 | } | ||
542 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
543 | printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd); | ||
544 | azt_error = 0xA5; | ||
545 | } | ||
546 | RETURNM("sendAztCmd", -1); | ||
547 | } | ||
548 | |||
549 | /* | ||
550 | * Send a seek command to the drive, return -1 on error, else 0 | ||
551 | */ | ||
552 | static int aztSeek(struct azt_Play_msf *params) | ||
553 | { | ||
554 | unsigned char data; | ||
555 | int retry; | ||
556 | |||
557 | #ifdef AZT_DEBUG | ||
558 | printk("aztcd: aztSeek %02x:%02x:%02x\n", | ||
559 | params->start.min, params->start.sec, params->start.frame); | ||
560 | #endif | ||
561 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
562 | aztSendCmd(ACMD_SEEK); | ||
563 | outb(params->start.min, CMD_PORT); | ||
564 | outb(params->start.sec, CMD_PORT); | ||
565 | outb(params->start.frame, CMD_PORT); | ||
566 | STEN_LOW; | ||
567 | data = inb(DATA_PORT); | ||
568 | if (data == AFL_PA_OK) { | ||
569 | return 0; | ||
570 | } /*PA_OK ? */ | ||
571 | if (data == AFL_PA_ERR) { | ||
572 | STEN_LOW; | ||
573 | data = inb(DATA_PORT); | ||
574 | printk("### Error 1 aztcd: aztSeek\n"); | ||
575 | } | ||
576 | } | ||
577 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
578 | printk("### Error 2 aztcd: aztSeek\n "); | ||
579 | azt_error = 0xA5; | ||
580 | } | ||
581 | RETURNM("aztSeek", -1); | ||
582 | } | ||
583 | |||
584 | /* Send a Set Disk Type command | ||
585 | does not seem to work with Aztech drives, behavior is completely indepen- | ||
586 | dent on which mode is set ??? | ||
587 | */ | ||
588 | static int aztSetDiskType(int type) | ||
589 | { | ||
590 | unsigned char data; | ||
591 | int retry; | ||
592 | |||
593 | #ifdef AZT_DEBUG | ||
594 | printk("aztcd: set disk type command: type= %i\n", type); | ||
595 | #endif | ||
596 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
597 | aztSendCmd(ACMD_SET_DISK_TYPE); | ||
598 | outb(type, CMD_PORT); | ||
599 | STEN_LOW; | ||
600 | data = inb(DATA_PORT); | ||
601 | if (data == AFL_PA_OK) { /*PA_OK ? */ | ||
602 | azt_read_mode = type; | ||
603 | return 0; | ||
604 | } | ||
605 | if (data == AFL_PA_ERR) { | ||
606 | STEN_LOW; | ||
607 | data = inb(DATA_PORT); | ||
608 | printk | ||
609 | ("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n", | ||
610 | type, data); | ||
611 | } | ||
612 | } | ||
613 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
614 | printk("### Error 2 aztcd: aztSetDiskType %x\n ", type); | ||
615 | azt_error = 0xA5; | ||
616 | } | ||
617 | RETURNM("aztSetDiskType", -1); | ||
618 | } | ||
619 | |||
620 | |||
621 | /* used in azt_poll to poll the status, expects another program to issue a | ||
622 | * ACMD_GET_STATUS directly before | ||
623 | */ | ||
624 | static int aztStatus(void) | ||
625 | { | ||
626 | int st; | ||
627 | /* int i; | ||
628 | |||
629 | i = inb(STATUS_PORT) & AFL_STATUS; is STEN=0? ??? | ||
630 | if (!i) | ||
631 | */ STEN_LOW; | ||
632 | if (aztTimeOutCount < AZT_TIMEOUT) { | ||
633 | st = inb(DATA_PORT) & 0xFF; | ||
634 | return st; | ||
635 | } else | ||
636 | RETURNM("aztStatus", -1); | ||
637 | } | ||
638 | |||
639 | /* | ||
640 | * Get the drive status | ||
641 | */ | ||
642 | static int getAztStatus(void) | ||
643 | { | ||
644 | int st; | ||
645 | |||
646 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
647 | RETURNM("getAztStatus 1", -1); | ||
648 | STEN_LOW; | ||
649 | st = inb(DATA_PORT) & 0xFF; | ||
650 | #ifdef AZT_DEBUG | ||
651 | printk("aztcd: Status = %x\n", st); | ||
652 | #endif | ||
653 | if ((st == 0xFF) || (st & AST_CMD_CHECK)) { | ||
654 | printk | ||
655 | ("aztcd: AST_CMD_CHECK error or no status available\n"); | ||
656 | return -1; | ||
657 | } | ||
658 | |||
659 | if (((st & AST_MODE_BITS) != AST_BUSY) | ||
660 | && (aztAudioStatus == CDROM_AUDIO_PLAY)) | ||
661 | /* XXX might be an error? look at q-channel? */ | ||
662 | aztAudioStatus = CDROM_AUDIO_COMPLETED; | ||
663 | |||
664 | if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) { | ||
665 | aztDiskChanged = 1; | ||
666 | aztTocUpToDate = 0; | ||
667 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
668 | } | ||
669 | return st; | ||
670 | } | ||
671 | |||
672 | |||
673 | /* | ||
674 | * Send a 'Play' command and get the status. Use only from the top half. | ||
675 | */ | ||
676 | static int aztPlay(struct azt_Play_msf *arg) | ||
677 | { | ||
678 | if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0) | ||
679 | RETURNM("aztPlay", -1); | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * Subroutines to automatically close the door (tray) and | ||
685 | * lock it closed when the cd is mounted. Leave the tray | ||
686 | * locking as an option | ||
687 | */ | ||
688 | static void aztCloseDoor(void) | ||
689 | { | ||
690 | aztSendCmd(ACMD_CLOSE); | ||
691 | STEN_LOW; | ||
692 | return; | ||
693 | } | ||
694 | |||
695 | static void aztLockDoor(void) | ||
696 | { | ||
697 | #if AZT_ALLOW_TRAY_LOCK | ||
698 | aztSendCmd(ACMD_LOCK); | ||
699 | STEN_LOW; | ||
700 | #endif | ||
701 | return; | ||
702 | } | ||
703 | |||
704 | static void aztUnlockDoor(void) | ||
705 | { | ||
706 | #if AZT_ALLOW_TRAY_LOCK | ||
707 | aztSendCmd(ACMD_UNLOCK); | ||
708 | STEN_LOW; | ||
709 | #endif | ||
710 | return; | ||
711 | } | ||
712 | |||
713 | /* | ||
714 | * Read a value from the drive. Should return quickly, so a busy wait | ||
715 | * is used to avoid excessive rescheduling. The read command itself must | ||
716 | * be issued with aztSendCmd() directly before | ||
717 | */ | ||
718 | static int aztGetValue(unsigned char *result) | ||
719 | { | ||
720 | int s; | ||
721 | |||
722 | STEN_LOW; | ||
723 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
724 | printk("aztcd: aztGetValue timeout\n"); | ||
725 | return -1; | ||
726 | } | ||
727 | s = inb(DATA_PORT) & 0xFF; | ||
728 | *result = (unsigned char) s; | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | /* | ||
733 | * Read the current Q-channel info. Also used for reading the | ||
734 | * table of contents. | ||
735 | */ | ||
736 | static int aztGetQChannelInfo(struct azt_Toc *qp) | ||
737 | { | ||
738 | unsigned char notUsed; | ||
739 | int st; | ||
740 | |||
741 | #ifdef AZT_DEBUG | ||
742 | printk("aztcd: starting aztGetQChannelInfo Time:%li\n", jiffies); | ||
743 | #endif | ||
744 | if ((st = getAztStatus()) == -1) | ||
745 | RETURNM("aztGetQChannelInfo 1", -1); | ||
746 | if (aztSendCmd(ACMD_GET_Q_CHANNEL)) | ||
747 | RETURNM("aztGetQChannelInfo 2", -1); | ||
748 | /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */ | ||
749 | if (aztGetValue(¬Used)) | ||
750 | RETURNM("aztGetQChannelInfo 3", -1); /*??? Nullbyte einlesen */ | ||
751 | if ((st & AST_MODE_BITS) == AST_INITIAL) { | ||
752 | qp->ctrl_addr = 0; /* when audio stop ACMD_GET_Q_CHANNEL returns */ | ||
753 | qp->track = 0; /* only one byte with Aztech drives */ | ||
754 | qp->pointIndex = 0; | ||
755 | qp->trackTime.min = 0; | ||
756 | qp->trackTime.sec = 0; | ||
757 | qp->trackTime.frame = 0; | ||
758 | qp->diskTime.min = 0; | ||
759 | qp->diskTime.sec = 0; | ||
760 | qp->diskTime.frame = 0; | ||
761 | return 0; | ||
762 | } else { | ||
763 | if (aztGetValue(&qp->ctrl_addr) < 0) | ||
764 | RETURNM("aztGetQChannelInfo 4", -1); | ||
765 | if (aztGetValue(&qp->track) < 0) | ||
766 | RETURNM("aztGetQChannelInfo 4", -1); | ||
767 | if (aztGetValue(&qp->pointIndex) < 0) | ||
768 | RETURNM("aztGetQChannelInfo 4", -1); | ||
769 | if (aztGetValue(&qp->trackTime.min) < 0) | ||
770 | RETURNM("aztGetQChannelInfo 4", -1); | ||
771 | if (aztGetValue(&qp->trackTime.sec) < 0) | ||
772 | RETURNM("aztGetQChannelInfo 4", -1); | ||
773 | if (aztGetValue(&qp->trackTime.frame) < 0) | ||
774 | RETURNM("aztGetQChannelInfo 4", -1); | ||
775 | if (aztGetValue(¬Used) < 0) | ||
776 | RETURNM("aztGetQChannelInfo 4", -1); | ||
777 | if (aztGetValue(&qp->diskTime.min) < 0) | ||
778 | RETURNM("aztGetQChannelInfo 4", -1); | ||
779 | if (aztGetValue(&qp->diskTime.sec) < 0) | ||
780 | RETURNM("aztGetQChannelInfo 4", -1); | ||
781 | if (aztGetValue(&qp->diskTime.frame) < 0) | ||
782 | RETURNM("aztGetQChannelInfo 4", -1); | ||
783 | } | ||
784 | #ifdef AZT_DEBUG | ||
785 | printk("aztcd: exiting aztGetQChannelInfo Time:%li\n", jiffies); | ||
786 | #endif | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | /* | ||
791 | * Read the table of contents (TOC) and TOC header if necessary | ||
792 | */ | ||
793 | static int aztUpdateToc(void) | ||
794 | { | ||
795 | int st; | ||
796 | |||
797 | #ifdef AZT_DEBUG | ||
798 | printk("aztcd: starting aztUpdateToc Time:%li\n", jiffies); | ||
799 | #endif | ||
800 | if (aztTocUpToDate) | ||
801 | return 0; | ||
802 | |||
803 | if (aztGetDiskInfo() < 0) | ||
804 | return -EIO; | ||
805 | |||
806 | if (aztGetToc(0) < 0) | ||
807 | return -EIO; | ||
808 | |||
809 | /*audio disk detection | ||
810 | with my Aztech drive there is no audio status bit, so I use the copy | ||
811 | protection bit of the first track. If this track is copy protected | ||
812 | (copy bit = 0), I assume, it's an audio disk. Strange, but works ??? */ | ||
813 | if (!(Toc[DiskInfo.first].ctrl_addr & 0x40)) | ||
814 | DiskInfo.audio = 1; | ||
815 | else | ||
816 | DiskInfo.audio = 0; | ||
817 | |||
818 | /* XA detection */ | ||
819 | if (!DiskInfo.audio) { | ||
820 | azt_Play.start.min = 0; /*XA detection only seems to work */ | ||
821 | azt_Play.start.sec = 2; /*when we play a track */ | ||
822 | azt_Play.start.frame = 0; | ||
823 | azt_Play.end.min = 0; | ||
824 | azt_Play.end.sec = 0; | ||
825 | azt_Play.end.frame = 1; | ||
826 | if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) | ||
827 | return -1; | ||
828 | DTEN_LOW; | ||
829 | for (st = 0; st < CD_FRAMESIZE; st++) | ||
830 | inb(DATA_PORT); | ||
831 | } | ||
832 | DiskInfo.xa = getAztStatus() & AST_MODE; | ||
833 | if (DiskInfo.xa) { | ||
834 | printk | ||
835 | ("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n"); | ||
836 | } | ||
837 | |||
838 | /*multisession detection | ||
839 | support for multisession CDs is done automatically with Aztech drives, | ||
840 | we don't have to take care about TOC redirection; if we want the isofs | ||
841 | to take care about redirection, we have to set AZT_MULTISESSION to 1 */ | ||
842 | DiskInfo.multi = 0; | ||
843 | #if AZT_MULTISESSION | ||
844 | if (DiskInfo.xa) { | ||
845 | aztGetMultiDiskInfo(); /*here Disk.Info.multi is set */ | ||
846 | } | ||
847 | #endif | ||
848 | if (DiskInfo.multi) { | ||
849 | DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min; | ||
850 | DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec; | ||
851 | DiskInfo.lastSession.frame = | ||
852 | Toc[DiskInfo.next].diskTime.frame; | ||
853 | printk("aztcd: Multisession support experimental\n"); | ||
854 | } else { | ||
855 | DiskInfo.lastSession.min = | ||
856 | Toc[DiskInfo.first].diskTime.min; | ||
857 | DiskInfo.lastSession.sec = | ||
858 | Toc[DiskInfo.first].diskTime.sec; | ||
859 | DiskInfo.lastSession.frame = | ||
860 | Toc[DiskInfo.first].diskTime.frame; | ||
861 | } | ||
862 | |||
863 | aztTocUpToDate = 1; | ||
864 | #ifdef AZT_DEBUG | ||
865 | printk("aztcd: exiting aztUpdateToc Time:%li\n", jiffies); | ||
866 | #endif | ||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | |||
871 | /* Read the table of contents header, i.e. no. of tracks and start of first | ||
872 | * track | ||
873 | */ | ||
874 | static int aztGetDiskInfo(void) | ||
875 | { | ||
876 | int limit; | ||
877 | unsigned char test; | ||
878 | struct azt_Toc qInfo; | ||
879 | |||
880 | #ifdef AZT_DEBUG | ||
881 | printk("aztcd: starting aztGetDiskInfo Time:%li\n", jiffies); | ||
882 | #endif | ||
883 | if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) | ||
884 | RETURNM("aztGetDiskInfo 1", -1); | ||
885 | STEN_LOW_WAIT; | ||
886 | test = 0; | ||
887 | for (limit = 300; limit > 0; limit--) { | ||
888 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
889 | RETURNM("aztGetDiskInfo 2", -1); | ||
890 | if (qInfo.pointIndex == 0xA0) { /*Number of FirstTrack */ | ||
891 | DiskInfo.first = qInfo.diskTime.min; | ||
892 | DiskInfo.first = azt_bcd2bin(DiskInfo.first); | ||
893 | test = test | 0x01; | ||
894 | } | ||
895 | if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */ | ||
896 | DiskInfo.last = qInfo.diskTime.min; | ||
897 | DiskInfo.last = azt_bcd2bin(DiskInfo.last); | ||
898 | test = test | 0x02; | ||
899 | } | ||
900 | if (qInfo.pointIndex == 0xA2) { /*DiskLength */ | ||
901 | DiskInfo.diskLength.min = qInfo.diskTime.min; | ||
902 | DiskInfo.diskLength.sec = qInfo.diskTime.sec; | ||
903 | DiskInfo.diskLength.frame = qInfo.diskTime.frame; | ||
904 | test = test | 0x04; | ||
905 | } | ||
906 | if ((qInfo.pointIndex == DiskInfo.first) && (test & 0x01)) { /*StartTime of First Track */ | ||
907 | DiskInfo.firstTrack.min = qInfo.diskTime.min; | ||
908 | DiskInfo.firstTrack.sec = qInfo.diskTime.sec; | ||
909 | DiskInfo.firstTrack.frame = qInfo.diskTime.frame; | ||
910 | test = test | 0x08; | ||
911 | } | ||
912 | if (test == 0x0F) | ||
913 | break; | ||
914 | } | ||
915 | #ifdef AZT_DEBUG | ||
916 | printk("aztcd: exiting aztGetDiskInfo Time:%li\n", jiffies); | ||
917 | printk | ||
918 | ("Disk Info: first %d last %d length %02X:%02X.%02X dez first %02X:%02X.%02X dez\n", | ||
919 | DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min, | ||
920 | DiskInfo.diskLength.sec, DiskInfo.diskLength.frame, | ||
921 | DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec, | ||
922 | DiskInfo.firstTrack.frame); | ||
923 | #endif | ||
924 | if (test != 0x0F) | ||
925 | return -1; | ||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | #if AZT_MULTISESSION | ||
930 | /* | ||
931 | * Get Multisession Disk Info | ||
932 | */ | ||
933 | static int aztGetMultiDiskInfo(void) | ||
934 | { | ||
935 | int limit, k = 5; | ||
936 | unsigned char test; | ||
937 | struct azt_Toc qInfo; | ||
938 | |||
939 | #ifdef AZT_DEBUG | ||
940 | printk("aztcd: starting aztGetMultiDiskInfo\n"); | ||
941 | #endif | ||
942 | |||
943 | do { | ||
944 | azt_Play.start.min = Toc[DiskInfo.last + 1].diskTime.min; | ||
945 | azt_Play.start.sec = Toc[DiskInfo.last + 1].diskTime.sec; | ||
946 | azt_Play.start.frame = | ||
947 | Toc[DiskInfo.last + 1].diskTime.frame; | ||
948 | test = 0; | ||
949 | |||
950 | for (limit = 30; limit > 0; limit--) { /*Seek for LeadIn of next session */ | ||
951 | if (aztSeek(&azt_Play)) | ||
952 | RETURNM("aztGetMultiDiskInfo 1", -1); | ||
953 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
954 | RETURNM("aztGetMultiDiskInfo 2", -1); | ||
955 | if ((qInfo.track == 0) && (qInfo.pointIndex)) | ||
956 | break; /*LeadIn found */ | ||
957 | if ((azt_Play.start.sec += 10) > 59) { | ||
958 | azt_Play.start.sec = 0; | ||
959 | azt_Play.start.min++; | ||
960 | } | ||
961 | } | ||
962 | if (!limit) | ||
963 | break; /*Check, if a leadin track was found, if not we're | ||
964 | at the end of the disk */ | ||
965 | #ifdef AZT_DEBUG_MULTISESSION | ||
966 | printk("leadin found track %d pointIndex %x limit %d\n", | ||
967 | qInfo.track, qInfo.pointIndex, limit); | ||
968 | #endif | ||
969 | for (limit = 300; limit > 0; limit--) { | ||
970 | if (++azt_Play.start.frame > 74) { | ||
971 | azt_Play.start.frame = 0; | ||
972 | if (azt_Play.start.sec > 59) { | ||
973 | azt_Play.start.sec = 0; | ||
974 | azt_Play.start.min++; | ||
975 | } | ||
976 | } | ||
977 | if (aztSeek(&azt_Play)) | ||
978 | RETURNM("aztGetMultiDiskInfo 3", -1); | ||
979 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
980 | RETURNM("aztGetMultiDiskInfo 4", -1); | ||
981 | if (qInfo.pointIndex == 0xA0) { /*Number of NextTrack */ | ||
982 | DiskInfo.next = qInfo.diskTime.min; | ||
983 | DiskInfo.next = azt_bcd2bin(DiskInfo.next); | ||
984 | test = test | 0x01; | ||
985 | } | ||
986 | if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */ | ||
987 | DiskInfo.last = qInfo.diskTime.min; | ||
988 | DiskInfo.last = azt_bcd2bin(DiskInfo.last); | ||
989 | test = test | 0x02; | ||
990 | } | ||
991 | if (qInfo.pointIndex == 0xA2) { /*DiskLength */ | ||
992 | DiskInfo.diskLength.min = | ||
993 | qInfo.diskTime.min; | ||
994 | DiskInfo.diskLength.sec = | ||
995 | qInfo.diskTime.sec; | ||
996 | DiskInfo.diskLength.frame = | ||
997 | qInfo.diskTime.frame; | ||
998 | test = test | 0x04; | ||
999 | } | ||
1000 | if ((qInfo.pointIndex == DiskInfo.next) && (test & 0x01)) { /*StartTime of Next Track */ | ||
1001 | DiskInfo.nextSession.min = | ||
1002 | qInfo.diskTime.min; | ||
1003 | DiskInfo.nextSession.sec = | ||
1004 | qInfo.diskTime.sec; | ||
1005 | DiskInfo.nextSession.frame = | ||
1006 | qInfo.diskTime.frame; | ||
1007 | test = test | 0x08; | ||
1008 | } | ||
1009 | if (test == 0x0F) | ||
1010 | break; | ||
1011 | } | ||
1012 | #ifdef AZT_DEBUG_MULTISESSION | ||
1013 | printk | ||
1014 | ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez first %02x:%02x.%02x dez next %02x:%02x.%02x dez\n", | ||
1015 | DiskInfo.first, DiskInfo.next, DiskInfo.last, | ||
1016 | DiskInfo.diskLength.min, DiskInfo.diskLength.sec, | ||
1017 | DiskInfo.diskLength.frame, DiskInfo.firstTrack.min, | ||
1018 | DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame, | ||
1019 | DiskInfo.nextSession.min, DiskInfo.nextSession.sec, | ||
1020 | DiskInfo.nextSession.frame); | ||
1021 | #endif | ||
1022 | if (test != 0x0F) | ||
1023 | break; | ||
1024 | else | ||
1025 | DiskInfo.multi = 1; /*found TOC of more than one session */ | ||
1026 | aztGetToc(1); | ||
1027 | } while (--k); | ||
1028 | |||
1029 | #ifdef AZT_DEBUG | ||
1030 | printk("aztcd: exiting aztGetMultiDiskInfo Time:%li\n", jiffies); | ||
1031 | #endif | ||
1032 | return 0; | ||
1033 | } | ||
1034 | #endif | ||
1035 | |||
1036 | /* | ||
1037 | * Read the table of contents (TOC) | ||
1038 | */ | ||
1039 | static int aztGetToc(int multi) | ||
1040 | { | ||
1041 | int i, px; | ||
1042 | int limit; | ||
1043 | struct azt_Toc qInfo; | ||
1044 | |||
1045 | #ifdef AZT_DEBUG | ||
1046 | printk("aztcd: starting aztGetToc Time:%li\n", jiffies); | ||
1047 | #endif | ||
1048 | if (!multi) { | ||
1049 | for (i = 0; i < MAX_TRACKS; i++) | ||
1050 | Toc[i].pointIndex = 0; | ||
1051 | i = DiskInfo.last + 3; | ||
1052 | } else { | ||
1053 | for (i = DiskInfo.next; i < MAX_TRACKS; i++) | ||
1054 | Toc[i].pointIndex = 0; | ||
1055 | i = DiskInfo.last + 4 - DiskInfo.next; | ||
1056 | } | ||
1057 | |||
1058 | /*Is there a good reason to stop motor before TOC read? | ||
1059 | if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1); | ||
1060 | STEN_LOW_WAIT; | ||
1061 | */ | ||
1062 | |||
1063 | if (!multi) { | ||
1064 | azt_mode = 0x05; | ||
1065 | if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) | ||
1066 | RETURNM("aztGetToc 2", -1); | ||
1067 | STEN_LOW_WAIT; | ||
1068 | } | ||
1069 | for (limit = 300; limit > 0; limit--) { | ||
1070 | if (multi) { | ||
1071 | if (++azt_Play.start.sec > 59) { | ||
1072 | azt_Play.start.sec = 0; | ||
1073 | azt_Play.start.min++; | ||
1074 | } | ||
1075 | if (aztSeek(&azt_Play)) | ||
1076 | RETURNM("aztGetToc 3", -1); | ||
1077 | } | ||
1078 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
1079 | break; | ||
1080 | |||
1081 | px = azt_bcd2bin(qInfo.pointIndex); | ||
1082 | |||
1083 | if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) | ||
1084 | if (Toc[px].pointIndex == 0) { | ||
1085 | Toc[px] = qInfo; | ||
1086 | i--; | ||
1087 | } | ||
1088 | |||
1089 | if (i <= 0) | ||
1090 | break; | ||
1091 | } | ||
1092 | |||
1093 | Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; | ||
1094 | Toc[DiskInfo.last].trackTime = DiskInfo.diskLength; | ||
1095 | |||
1096 | #ifdef AZT_DEBUG_MULTISESSION | ||
1097 | printk("aztcd: exiting aztGetToc\n"); | ||
1098 | for (i = 1; i <= DiskInfo.last + 1; i++) | ||
1099 | printk | ||
1100 | ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n", | ||
1101 | i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, | ||
1102 | Toc[i].trackTime.min, Toc[i].trackTime.sec, | ||
1103 | Toc[i].trackTime.frame, Toc[i].diskTime.min, | ||
1104 | Toc[i].diskTime.sec, Toc[i].diskTime.frame); | ||
1105 | for (i = 100; i < 103; i++) | ||
1106 | printk | ||
1107 | ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n", | ||
1108 | i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, | ||
1109 | Toc[i].trackTime.min, Toc[i].trackTime.sec, | ||
1110 | Toc[i].trackTime.frame, Toc[i].diskTime.min, | ||
1111 | Toc[i].diskTime.sec, Toc[i].diskTime.frame); | ||
1112 | #endif | ||
1113 | |||
1114 | return limit > 0 ? 0 : -1; | ||
1115 | } | ||
1116 | |||
1117 | |||
1118 | /*########################################################################## | ||
1119 | Kernel Interface Functions | ||
1120 | ########################################################################## | ||
1121 | */ | ||
1122 | |||
1123 | #ifndef MODULE | ||
1124 | static int __init aztcd_setup(char *str) | ||
1125 | { | ||
1126 | int ints[4]; | ||
1127 | |||
1128 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
1129 | |||
1130 | if (ints[0] > 0) | ||
1131 | azt_port = ints[1]; | ||
1132 | if (ints[1] > 1) | ||
1133 | azt_cont = ints[2]; | ||
1134 | return 1; | ||
1135 | } | ||
1136 | |||
1137 | __setup("aztcd=", aztcd_setup); | ||
1138 | |||
1139 | #endif /* !MODULE */ | ||
1140 | |||
1141 | /* | ||
1142 | * Checking if the media has been changed | ||
1143 | */ | ||
1144 | static int check_aztcd_media_change(struct gendisk *disk) | ||
1145 | { | ||
1146 | if (aztDiskChanged) { /* disk changed */ | ||
1147 | aztDiskChanged = 0; | ||
1148 | return 1; | ||
1149 | } else | ||
1150 | return 0; /* no change */ | ||
1151 | } | ||
1152 | |||
1153 | /* | ||
1154 | * Kernel IO-controls | ||
1155 | */ | ||
1156 | static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | ||
1157 | unsigned long arg) | ||
1158 | { | ||
1159 | int i; | ||
1160 | struct azt_Toc qInfo; | ||
1161 | struct cdrom_ti ti; | ||
1162 | struct cdrom_tochdr tocHdr; | ||
1163 | struct cdrom_msf msf; | ||
1164 | struct cdrom_tocentry entry; | ||
1165 | struct azt_Toc *tocPtr; | ||
1166 | struct cdrom_subchnl subchnl; | ||
1167 | struct cdrom_volctrl volctrl; | ||
1168 | void __user *argp = (void __user *)arg; | ||
1169 | |||
1170 | #ifdef AZT_DEBUG | ||
1171 | printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n", | ||
1172 | cmd, jiffies); | ||
1173 | printk("aztcd Status %x\n", getAztStatus()); | ||
1174 | #endif | ||
1175 | if (!ip) | ||
1176 | RETURNM("aztcd_ioctl 1", -EINVAL); | ||
1177 | if (getAztStatus() < 0) | ||
1178 | RETURNM("aztcd_ioctl 2", -EIO); | ||
1179 | if ((!aztTocUpToDate) || (aztDiskChanged)) { | ||
1180 | if ((i = aztUpdateToc()) < 0) | ||
1181 | RETURNM("aztcd_ioctl 3", i); /* error reading TOC */ | ||
1182 | } | ||
1183 | |||
1184 | switch (cmd) { | ||
1185 | case CDROMSTART: /* Spin up the drive. Don't know, what to do, | ||
1186 | at least close the tray */ | ||
1187 | #if AZT_PRIVATE_IOCTLS | ||
1188 | if (aztSendCmd(ACMD_CLOSE)) | ||
1189 | RETURNM("aztcd_ioctl 4", -1); | ||
1190 | STEN_LOW_WAIT; | ||
1191 | #endif | ||
1192 | break; | ||
1193 | case CDROMSTOP: /* Spin down the drive */ | ||
1194 | if (aztSendCmd(ACMD_STOP)) | ||
1195 | RETURNM("aztcd_ioctl 5", -1); | ||
1196 | STEN_LOW_WAIT; | ||
1197 | /* should we do anything if it fails? */ | ||
1198 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1199 | break; | ||
1200 | case CDROMPAUSE: /* Pause the drive */ | ||
1201 | if (aztAudioStatus != CDROM_AUDIO_PLAY) | ||
1202 | return -EINVAL; | ||
1203 | |||
1204 | if (aztGetQChannelInfo(&qInfo) < 0) { /* didn't get q channel info */ | ||
1205 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1206 | RETURNM("aztcd_ioctl 7", 0); | ||
1207 | } | ||
1208 | azt_Play.start = qInfo.diskTime; /* remember restart point */ | ||
1209 | |||
1210 | if (aztSendCmd(ACMD_PAUSE)) | ||
1211 | RETURNM("aztcd_ioctl 8", -1); | ||
1212 | STEN_LOW_WAIT; | ||
1213 | aztAudioStatus = CDROM_AUDIO_PAUSED; | ||
1214 | break; | ||
1215 | case CDROMRESUME: /* Play it again, Sam */ | ||
1216 | if (aztAudioStatus != CDROM_AUDIO_PAUSED) | ||
1217 | return -EINVAL; | ||
1218 | /* restart the drive at the saved position. */ | ||
1219 | i = aztPlay(&azt_Play); | ||
1220 | if (i < 0) { | ||
1221 | aztAudioStatus = CDROM_AUDIO_ERROR; | ||
1222 | return -EIO; | ||
1223 | } | ||
1224 | aztAudioStatus = CDROM_AUDIO_PLAY; | ||
1225 | break; | ||
1226 | case CDROMMULTISESSION: /*multisession support -- experimental */ | ||
1227 | { | ||
1228 | struct cdrom_multisession ms; | ||
1229 | #ifdef AZT_DEBUG | ||
1230 | printk("aztcd ioctl MULTISESSION\n"); | ||
1231 | #endif | ||
1232 | if (copy_from_user(&ms, argp, | ||
1233 | sizeof(struct cdrom_multisession))) | ||
1234 | return -EFAULT; | ||
1235 | if (ms.addr_format == CDROM_MSF) { | ||
1236 | ms.addr.msf.minute = | ||
1237 | azt_bcd2bin(DiskInfo.lastSession.min); | ||
1238 | ms.addr.msf.second = | ||
1239 | azt_bcd2bin(DiskInfo.lastSession.sec); | ||
1240 | ms.addr.msf.frame = | ||
1241 | azt_bcd2bin(DiskInfo.lastSession. | ||
1242 | frame); | ||
1243 | } else if (ms.addr_format == CDROM_LBA) | ||
1244 | ms.addr.lba = | ||
1245 | azt_msf2hsg(&DiskInfo.lastSession); | ||
1246 | else | ||
1247 | return -EINVAL; | ||
1248 | ms.xa_flag = DiskInfo.xa; | ||
1249 | if (copy_to_user(argp, &ms, | ||
1250 | sizeof(struct cdrom_multisession))) | ||
1251 | return -EFAULT; | ||
1252 | #ifdef AZT_DEBUG | ||
1253 | if (ms.addr_format == CDROM_MSF) | ||
1254 | printk | ||
1255 | ("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n", | ||
1256 | ms.xa_flag, ms.addr.msf.minute, | ||
1257 | ms.addr.msf.second, ms.addr.msf.frame, | ||
1258 | DiskInfo.lastSession.min, | ||
1259 | DiskInfo.lastSession.sec, | ||
1260 | DiskInfo.lastSession.frame); | ||
1261 | else | ||
1262 | printk | ||
1263 | ("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n", | ||
1264 | ms.xa_flag, ms.addr.lba, | ||
1265 | DiskInfo.lastSession.min, | ||
1266 | DiskInfo.lastSession.sec, | ||
1267 | DiskInfo.lastSession.frame); | ||
1268 | #endif | ||
1269 | return 0; | ||
1270 | } | ||
1271 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
1272 | if (copy_from_user(&ti, argp, sizeof ti)) | ||
1273 | return -EFAULT; | ||
1274 | if (ti.cdti_trk0 < DiskInfo.first | ||
1275 | || ti.cdti_trk0 > DiskInfo.last | ||
1276 | || ti.cdti_trk1 < ti.cdti_trk0) { | ||
1277 | return -EINVAL; | ||
1278 | } | ||
1279 | if (ti.cdti_trk1 > DiskInfo.last) | ||
1280 | ti.cdti_trk1 = DiskInfo.last; | ||
1281 | azt_Play.start = Toc[ti.cdti_trk0].diskTime; | ||
1282 | azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime; | ||
1283 | #ifdef AZT_DEBUG | ||
1284 | printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n", | ||
1285 | azt_Play.start.min, azt_Play.start.sec, | ||
1286 | azt_Play.start.frame, azt_Play.end.min, | ||
1287 | azt_Play.end.sec, azt_Play.end.frame); | ||
1288 | #endif | ||
1289 | i = aztPlay(&azt_Play); | ||
1290 | if (i < 0) { | ||
1291 | aztAudioStatus = CDROM_AUDIO_ERROR; | ||
1292 | return -EIO; | ||
1293 | } | ||
1294 | aztAudioStatus = CDROM_AUDIO_PLAY; | ||
1295 | break; | ||
1296 | case CDROMPLAYMSF: /* Play starting at the given MSF address. */ | ||
1297 | /* if (aztAudioStatus == CDROM_AUDIO_PLAY) | ||
1298 | { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1); | ||
1299 | STEN_LOW; | ||
1300 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1301 | } | ||
1302 | */ | ||
1303 | if (copy_from_user(&msf, argp, sizeof msf)) | ||
1304 | return -EFAULT; | ||
1305 | /* convert to bcd */ | ||
1306 | azt_bin2bcd(&msf.cdmsf_min0); | ||
1307 | azt_bin2bcd(&msf.cdmsf_sec0); | ||
1308 | azt_bin2bcd(&msf.cdmsf_frame0); | ||
1309 | azt_bin2bcd(&msf.cdmsf_min1); | ||
1310 | azt_bin2bcd(&msf.cdmsf_sec1); | ||
1311 | azt_bin2bcd(&msf.cdmsf_frame1); | ||
1312 | azt_Play.start.min = msf.cdmsf_min0; | ||
1313 | azt_Play.start.sec = msf.cdmsf_sec0; | ||
1314 | azt_Play.start.frame = msf.cdmsf_frame0; | ||
1315 | azt_Play.end.min = msf.cdmsf_min1; | ||
1316 | azt_Play.end.sec = msf.cdmsf_sec1; | ||
1317 | azt_Play.end.frame = msf.cdmsf_frame1; | ||
1318 | #ifdef AZT_DEBUG | ||
1319 | printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n", | ||
1320 | azt_Play.start.min, azt_Play.start.sec, | ||
1321 | azt_Play.start.frame, azt_Play.end.min, | ||
1322 | azt_Play.end.sec, azt_Play.end.frame); | ||
1323 | #endif | ||
1324 | i = aztPlay(&azt_Play); | ||
1325 | if (i < 0) { | ||
1326 | aztAudioStatus = CDROM_AUDIO_ERROR; | ||
1327 | return -EIO; | ||
1328 | } | ||
1329 | aztAudioStatus = CDROM_AUDIO_PLAY; | ||
1330 | break; | ||
1331 | |||
1332 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
1333 | tocHdr.cdth_trk0 = DiskInfo.first; | ||
1334 | tocHdr.cdth_trk1 = DiskInfo.last; | ||
1335 | if (copy_to_user(argp, &tocHdr, sizeof tocHdr)) | ||
1336 | return -EFAULT; | ||
1337 | break; | ||
1338 | case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ | ||
1339 | if (copy_from_user(&entry, argp, sizeof entry)) | ||
1340 | return -EFAULT; | ||
1341 | if ((!aztTocUpToDate) || aztDiskChanged) | ||
1342 | aztUpdateToc(); | ||
1343 | if (entry.cdte_track == CDROM_LEADOUT) | ||
1344 | tocPtr = &Toc[DiskInfo.last + 1]; | ||
1345 | else if (entry.cdte_track > DiskInfo.last | ||
1346 | || entry.cdte_track < DiskInfo.first) { | ||
1347 | return -EINVAL; | ||
1348 | } else | ||
1349 | tocPtr = &Toc[entry.cdte_track]; | ||
1350 | entry.cdte_adr = tocPtr->ctrl_addr; | ||
1351 | entry.cdte_ctrl = tocPtr->ctrl_addr >> 4; | ||
1352 | if (entry.cdte_format == CDROM_LBA) | ||
1353 | entry.cdte_addr.lba = | ||
1354 | azt_msf2hsg(&tocPtr->diskTime); | ||
1355 | else if (entry.cdte_format == CDROM_MSF) { | ||
1356 | entry.cdte_addr.msf.minute = | ||
1357 | azt_bcd2bin(tocPtr->diskTime.min); | ||
1358 | entry.cdte_addr.msf.second = | ||
1359 | azt_bcd2bin(tocPtr->diskTime.sec); | ||
1360 | entry.cdte_addr.msf.frame = | ||
1361 | azt_bcd2bin(tocPtr->diskTime.frame); | ||
1362 | } else { | ||
1363 | return -EINVAL; | ||
1364 | } | ||
1365 | if (copy_to_user(argp, &entry, sizeof entry)) | ||
1366 | return -EFAULT; | ||
1367 | break; | ||
1368 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
1369 | if (copy_from_user | ||
1370 | (&subchnl, argp, sizeof(struct cdrom_subchnl))) | ||
1371 | return -EFAULT; | ||
1372 | if (aztGetQChannelInfo(&qInfo) < 0) { | ||
1373 | #ifdef AZT_DEBUG | ||
1374 | printk | ||
1375 | ("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n", | ||
1376 | cmd); | ||
1377 | #endif | ||
1378 | return -EIO; | ||
1379 | } | ||
1380 | subchnl.cdsc_audiostatus = aztAudioStatus; | ||
1381 | subchnl.cdsc_adr = qInfo.ctrl_addr; | ||
1382 | subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4; | ||
1383 | subchnl.cdsc_trk = azt_bcd2bin(qInfo.track); | ||
1384 | subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex); | ||
1385 | if (subchnl.cdsc_format == CDROM_LBA) { | ||
1386 | subchnl.cdsc_absaddr.lba = | ||
1387 | azt_msf2hsg(&qInfo.diskTime); | ||
1388 | subchnl.cdsc_reladdr.lba = | ||
1389 | azt_msf2hsg(&qInfo.trackTime); | ||
1390 | } else { /*default */ | ||
1391 | subchnl.cdsc_format = CDROM_MSF; | ||
1392 | subchnl.cdsc_absaddr.msf.minute = | ||
1393 | azt_bcd2bin(qInfo.diskTime.min); | ||
1394 | subchnl.cdsc_absaddr.msf.second = | ||
1395 | azt_bcd2bin(qInfo.diskTime.sec); | ||
1396 | subchnl.cdsc_absaddr.msf.frame = | ||
1397 | azt_bcd2bin(qInfo.diskTime.frame); | ||
1398 | subchnl.cdsc_reladdr.msf.minute = | ||
1399 | azt_bcd2bin(qInfo.trackTime.min); | ||
1400 | subchnl.cdsc_reladdr.msf.second = | ||
1401 | azt_bcd2bin(qInfo.trackTime.sec); | ||
1402 | subchnl.cdsc_reladdr.msf.frame = | ||
1403 | azt_bcd2bin(qInfo.trackTime.frame); | ||
1404 | } | ||
1405 | if (copy_to_user(argp, &subchnl, sizeof(struct cdrom_subchnl))) | ||
1406 | return -EFAULT; | ||
1407 | break; | ||
1408 | case CDROMVOLCTRL: /* Volume control | ||
1409 | * With my Aztech CD268-01A volume control does not work, I can only | ||
1410 | turn the channels on (any value !=0) or off (value==0). Maybe it | ||
1411 | works better with your drive */ | ||
1412 | if (copy_from_user(&volctrl, argp, sizeof(volctrl))) | ||
1413 | return -EFAULT; | ||
1414 | azt_Play.start.min = 0x21; | ||
1415 | azt_Play.start.sec = 0x84; | ||
1416 | azt_Play.start.frame = volctrl.channel0; | ||
1417 | azt_Play.end.min = volctrl.channel1; | ||
1418 | azt_Play.end.sec = volctrl.channel2; | ||
1419 | azt_Play.end.frame = volctrl.channel3; | ||
1420 | sendAztCmd(ACMD_SET_VOLUME, &azt_Play); | ||
1421 | STEN_LOW_WAIT; | ||
1422 | break; | ||
1423 | case CDROMEJECT: | ||
1424 | aztUnlockDoor(); /* Assume user knows what they're doing */ | ||
1425 | /* all drives can at least stop! */ | ||
1426 | if (aztAudioStatus == CDROM_AUDIO_PLAY) { | ||
1427 | if (aztSendCmd(ACMD_STOP)) | ||
1428 | RETURNM("azt_ioctl 10", -1); | ||
1429 | STEN_LOW_WAIT; | ||
1430 | } | ||
1431 | if (aztSendCmd(ACMD_EJECT)) | ||
1432 | RETURNM("azt_ioctl 11", -1); | ||
1433 | STEN_LOW_WAIT; | ||
1434 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1435 | break; | ||
1436 | case CDROMEJECT_SW: | ||
1437 | azt_auto_eject = (char) arg; | ||
1438 | break; | ||
1439 | case CDROMRESET: | ||
1440 | outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */ | ||
1441 | STEN_LOW; | ||
1442 | if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */ | ||
1443 | printk | ||
1444 | ("aztcd: AZTECH CD-ROM drive does not respond\n"); | ||
1445 | } | ||
1446 | break; | ||
1447 | /*Take care, the following code is not compatible with other CD-ROM drivers, | ||
1448 | use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h, | ||
1449 | if you do not want to use it! | ||
1450 | */ | ||
1451 | #if AZT_PRIVATE_IOCTLS | ||
1452 | case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes) */ | ||
1453 | case CDROMREADRAW: /*read data in mode 2 (2336 Bytes) */ | ||
1454 | { | ||
1455 | if (copy_from_user(&msf, argp, sizeof msf)) | ||
1456 | return -EFAULT; | ||
1457 | /* convert to bcd */ | ||
1458 | azt_bin2bcd(&msf.cdmsf_min0); | ||
1459 | azt_bin2bcd(&msf.cdmsf_sec0); | ||
1460 | azt_bin2bcd(&msf.cdmsf_frame0); | ||
1461 | msf.cdmsf_min1 = 0; | ||
1462 | msf.cdmsf_sec1 = 0; | ||
1463 | msf.cdmsf_frame1 = 1; /*read only one frame */ | ||
1464 | azt_Play.start.min = msf.cdmsf_min0; | ||
1465 | azt_Play.start.sec = msf.cdmsf_sec0; | ||
1466 | azt_Play.start.frame = msf.cdmsf_frame0; | ||
1467 | azt_Play.end.min = msf.cdmsf_min1; | ||
1468 | azt_Play.end.sec = msf.cdmsf_sec1; | ||
1469 | azt_Play.end.frame = msf.cdmsf_frame1; | ||
1470 | if (cmd == CDROMREADRAW) { | ||
1471 | if (DiskInfo.xa) { | ||
1472 | return -1; /*XA Disks can't be read raw */ | ||
1473 | } else { | ||
1474 | if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) | ||
1475 | return -1; | ||
1476 | DTEN_LOW; | ||
1477 | insb(DATA_PORT, buf, CD_FRAMESIZE_RAW); | ||
1478 | if (copy_to_user(argp, &buf, CD_FRAMESIZE_RAW)) | ||
1479 | return -EFAULT; | ||
1480 | } | ||
1481 | } else | ||
1482 | /*CDROMREADCOOKED*/ { | ||
1483 | if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) | ||
1484 | return -1; | ||
1485 | DTEN_LOW; | ||
1486 | insb(DATA_PORT, buf, CD_FRAMESIZE); | ||
1487 | if (copy_to_user(argp, &buf, CD_FRAMESIZE)) | ||
1488 | return -EFAULT; | ||
1489 | } | ||
1490 | } | ||
1491 | break; | ||
1492 | case CDROMSEEK: /*seek msf address */ | ||
1493 | if (copy_from_user(&msf, argp, sizeof msf)) | ||
1494 | return -EFAULT; | ||
1495 | /* convert to bcd */ | ||
1496 | azt_bin2bcd(&msf.cdmsf_min0); | ||
1497 | azt_bin2bcd(&msf.cdmsf_sec0); | ||
1498 | azt_bin2bcd(&msf.cdmsf_frame0); | ||
1499 | azt_Play.start.min = msf.cdmsf_min0; | ||
1500 | azt_Play.start.sec = msf.cdmsf_sec0; | ||
1501 | azt_Play.start.frame = msf.cdmsf_frame0; | ||
1502 | if (aztSeek(&azt_Play)) | ||
1503 | return -1; | ||
1504 | break; | ||
1505 | #endif /*end of incompatible code */ | ||
1506 | case CDROMREADMODE1: /*set read data in mode 1 */ | ||
1507 | return aztSetDiskType(AZT_MODE_1); | ||
1508 | case CDROMREADMODE2: /*set read data in mode 2 */ | ||
1509 | return aztSetDiskType(AZT_MODE_2); | ||
1510 | default: | ||
1511 | return -EINVAL; | ||
1512 | } | ||
1513 | #ifdef AZT_DEBUG | ||
1514 | printk("aztcd: exiting aztcd_ioctl Command:%x Time:%li\n", cmd, | ||
1515 | jiffies); | ||
1516 | #endif | ||
1517 | return 0; | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1521 | * Take care of the different block sizes between cdrom and Linux. | ||
1522 | * When Linux gets variable block sizes this will probably go away. | ||
1523 | */ | ||
1524 | static void azt_transfer(void) | ||
1525 | { | ||
1526 | #ifdef AZT_TEST | ||
1527 | printk("aztcd: executing azt_transfer Time:%li\n", jiffies); | ||
1528 | #endif | ||
1529 | if (!current_valid()) | ||
1530 | return; | ||
1531 | |||
1532 | while (CURRENT->nr_sectors) { | ||
1533 | int bn = CURRENT->sector / 4; | ||
1534 | int i; | ||
1535 | for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i); | ||
1536 | if (i < AZT_BUF_SIZ) { | ||
1537 | int offs = (i * 4 + (CURRENT->sector & 3)) * 512; | ||
1538 | int nr_sectors = 4 - (CURRENT->sector & 3); | ||
1539 | if (azt_buf_out != i) { | ||
1540 | azt_buf_out = i; | ||
1541 | if (azt_buf_bn[i] != bn) { | ||
1542 | azt_buf_out = -1; | ||
1543 | continue; | ||
1544 | } | ||
1545 | } | ||
1546 | if (nr_sectors > CURRENT->nr_sectors) | ||
1547 | nr_sectors = CURRENT->nr_sectors; | ||
1548 | memcpy(CURRENT->buffer, azt_buf + offs, | ||
1549 | nr_sectors * 512); | ||
1550 | CURRENT->nr_sectors -= nr_sectors; | ||
1551 | CURRENT->sector += nr_sectors; | ||
1552 | CURRENT->buffer += nr_sectors * 512; | ||
1553 | } else { | ||
1554 | azt_buf_out = -1; | ||
1555 | break; | ||
1556 | } | ||
1557 | } | ||
1558 | } | ||
1559 | |||
1560 | static void do_aztcd_request(request_queue_t * q) | ||
1561 | { | ||
1562 | #ifdef AZT_TEST | ||
1563 | printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT->sector, | ||
1564 | CURRENT->nr_sectors, jiffies); | ||
1565 | #endif | ||
1566 | if (DiskInfo.audio) { | ||
1567 | printk("aztcd: Error, tried to mount an Audio CD\n"); | ||
1568 | end_request(CURRENT, 0); | ||
1569 | return; | ||
1570 | } | ||
1571 | azt_transfer_is_active = 1; | ||
1572 | while (current_valid()) { | ||
1573 | azt_transfer(); | ||
1574 | if (CURRENT->nr_sectors == 0) { | ||
1575 | end_request(CURRENT, 1); | ||
1576 | } else { | ||
1577 | azt_buf_out = -1; /* Want to read a block not in buffer */ | ||
1578 | if (azt_state == AZT_S_IDLE) { | ||
1579 | if ((!aztTocUpToDate) || aztDiskChanged) { | ||
1580 | if (aztUpdateToc() < 0) { | ||
1581 | while (current_valid()) | ||
1582 | end_request(CURRENT, 0); | ||
1583 | break; | ||
1584 | } | ||
1585 | } | ||
1586 | azt_state = AZT_S_START; | ||
1587 | AztTries = 5; | ||
1588 | SET_TIMER(azt_poll, HZ / 100); | ||
1589 | } | ||
1590 | break; | ||
1591 | } | ||
1592 | } | ||
1593 | azt_transfer_is_active = 0; | ||
1594 | #ifdef AZT_TEST2 | ||
1595 | printk | ||
1596 | ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", | ||
1597 | azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]); | ||
1598 | printk(" do_aztcd_request ends Time:%li\n", jiffies); | ||
1599 | #endif | ||
1600 | } | ||
1601 | |||
1602 | |||
1603 | static void azt_invalidate_buffers(void) | ||
1604 | { | ||
1605 | int i; | ||
1606 | |||
1607 | #ifdef AZT_DEBUG | ||
1608 | printk("aztcd: executing azt_invalidate_buffers\n"); | ||
1609 | #endif | ||
1610 | for (i = 0; i < AZT_BUF_SIZ; ++i) | ||
1611 | azt_buf_bn[i] = -1; | ||
1612 | azt_buf_out = -1; | ||
1613 | } | ||
1614 | |||
1615 | /* | ||
1616 | * Open the device special file. Check that a disk is in. | ||
1617 | */ | ||
1618 | static int aztcd_open(struct inode *ip, struct file *fp) | ||
1619 | { | ||
1620 | int st; | ||
1621 | |||
1622 | #ifdef AZT_DEBUG | ||
1623 | printk("aztcd: starting aztcd_open\n"); | ||
1624 | #endif | ||
1625 | |||
1626 | if (aztPresent == 0) | ||
1627 | return -ENXIO; /* no hardware */ | ||
1628 | |||
1629 | if (!azt_open_count && azt_state == AZT_S_IDLE) { | ||
1630 | azt_invalidate_buffers(); | ||
1631 | |||
1632 | st = getAztStatus(); /* check drive status */ | ||
1633 | if (st == -1) | ||
1634 | goto err_out; /* drive doesn't respond */ | ||
1635 | |||
1636 | if (st & AST_DOOR_OPEN) { /* close door, then get the status again. */ | ||
1637 | printk("aztcd: Door Open?\n"); | ||
1638 | aztCloseDoor(); | ||
1639 | st = getAztStatus(); | ||
1640 | } | ||
1641 | |||
1642 | if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) { /*no disk in drive or changed */ | ||
1643 | printk | ||
1644 | ("aztcd: Disk Changed or No Disk in Drive?\n"); | ||
1645 | aztTocUpToDate = 0; | ||
1646 | } | ||
1647 | if (aztUpdateToc()) | ||
1648 | goto err_out; | ||
1649 | |||
1650 | } | ||
1651 | ++azt_open_count; | ||
1652 | aztLockDoor(); | ||
1653 | |||
1654 | #ifdef AZT_DEBUG | ||
1655 | printk("aztcd: exiting aztcd_open\n"); | ||
1656 | #endif | ||
1657 | return 0; | ||
1658 | |||
1659 | err_out: | ||
1660 | return -EIO; | ||
1661 | } | ||
1662 | |||
1663 | |||
1664 | /* | ||
1665 | * On close, we flush all azt blocks from the buffer cache. | ||
1666 | */ | ||
1667 | static int aztcd_release(struct inode *inode, struct file *file) | ||
1668 | { | ||
1669 | #ifdef AZT_DEBUG | ||
1670 | printk("aztcd: executing aztcd_release\n"); | ||
1671 | printk("inode: %p, device: %s file: %p\n", inode, | ||
1672 | inode->i_bdev->bd_disk->disk_name, file); | ||
1673 | #endif | ||
1674 | if (!--azt_open_count) { | ||
1675 | azt_invalidate_buffers(); | ||
1676 | aztUnlockDoor(); | ||
1677 | if (azt_auto_eject) | ||
1678 | aztSendCmd(ACMD_EJECT); | ||
1679 | CLEAR_TIMER; | ||
1680 | } | ||
1681 | return 0; | ||
1682 | } | ||
1683 | |||
1684 | static struct gendisk *azt_disk; | ||
1685 | |||
1686 | /* | ||
1687 | * Test for presence of drive and initialize it. Called at boot time. | ||
1688 | */ | ||
1689 | |||
1690 | static int __init aztcd_init(void) | ||
1691 | { | ||
1692 | long int count, max_count; | ||
1693 | unsigned char result[50]; | ||
1694 | int st; | ||
1695 | void* status = NULL; | ||
1696 | int i = 0; | ||
1697 | int ret = 0; | ||
1698 | |||
1699 | if (azt_port == 0) { | ||
1700 | printk(KERN_INFO "aztcd: no Aztech CD-ROM Initialization"); | ||
1701 | return -EIO; | ||
1702 | } | ||
1703 | |||
1704 | printk(KERN_INFO "aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM " | ||
1705 | "CD-ROM Driver\n"); | ||
1706 | printk(KERN_INFO "aztcd: (C) 1994-98 W.Zimmermann\n"); | ||
1707 | if (azt_port == -1) { | ||
1708 | printk | ||
1709 | ("aztcd: DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n", | ||
1710 | AZT_VERSION); | ||
1711 | } else | ||
1712 | printk | ||
1713 | ("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n", | ||
1714 | AZT_VERSION, azt_port); | ||
1715 | printk(KERN_INFO "aztcd: If you have problems, read /usr/src/linux/" | ||
1716 | "Documentation/cdrom/aztcd\n"); | ||
1717 | |||
1718 | |||
1719 | #ifdef AZT_SW32 /*CDROM connected to Soundwave32 card */ | ||
1720 | if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) { | ||
1721 | printk | ||
1722 | ("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n", | ||
1723 | AZT_SW32_BASE_ADDR, AZT_SW32_INIT, | ||
1724 | AZT_SW32_CONFIG_REG, AZT_SW32_ID_REG); | ||
1725 | return -EIO; | ||
1726 | } else { | ||
1727 | printk(KERN_INFO | ||
1728 | "aztcd: Soundwave32 card detected at %x Version %x\n", | ||
1729 | AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG)); | ||
1730 | outw(AZT_SW32_INIT, AZT_SW32_CONFIG_REG); | ||
1731 | for (count = 0; count < 10000; count++); /*delay a bit */ | ||
1732 | } | ||
1733 | #endif | ||
1734 | |||
1735 | /* check for presence of drive */ | ||
1736 | |||
1737 | if (azt_port == -1) { /* autoprobing for proprietary interface */ | ||
1738 | for (i = 0; (azt_port_auto[i] != 0) && (i < 16); i++) { | ||
1739 | azt_port = azt_port_auto[i]; | ||
1740 | printk(KERN_INFO "aztcd: Autoprobing BaseAddress=0x%x" | ||
1741 | "\n", azt_port); | ||
1742 | /*proprietary interfaces need 4 bytes */ | ||
1743 | if (!request_region(azt_port, 4, "aztcd")) { | ||
1744 | continue; | ||
1745 | } | ||
1746 | outb(POLLED, MODE_PORT); | ||
1747 | inb(CMD_PORT); | ||
1748 | inb(CMD_PORT); | ||
1749 | outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */ | ||
1750 | |||
1751 | aztTimeOutCount = 0; | ||
1752 | do { | ||
1753 | aztIndatum = inb(STATUS_PORT); | ||
1754 | aztTimeOutCount++; | ||
1755 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1756 | break; | ||
1757 | } while (aztIndatum & AFL_STATUS); | ||
1758 | if (inb(DATA_PORT) == AFL_OP_OK) { /* OK drive found */ | ||
1759 | break; | ||
1760 | } | ||
1761 | else { /* Drive not found on this port - try next one */ | ||
1762 | release_region(azt_port, 4); | ||
1763 | } | ||
1764 | } | ||
1765 | if ((i == 16) || (azt_port_auto[i] == 0)) { | ||
1766 | printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n"); | ||
1767 | return -EIO; | ||
1768 | } | ||
1769 | } else { /* no autoprobing */ | ||
1770 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) | ||
1771 | status = request_region(azt_port, 8, "aztcd"); /*IDE-interfaces need 8 bytes */ | ||
1772 | else | ||
1773 | status = request_region(azt_port, 4, "aztcd"); /*proprietary interfaces need 4 bytes */ | ||
1774 | if (!status) { | ||
1775 | printk(KERN_WARNING "aztcd: conflict, I/O port (%X) " | ||
1776 | "already used\n", azt_port); | ||
1777 | return -EIO; | ||
1778 | } | ||
1779 | |||
1780 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) | ||
1781 | SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */ | ||
1782 | |||
1783 | outb(POLLED, MODE_PORT); | ||
1784 | inb(CMD_PORT); | ||
1785 | inb(CMD_PORT); | ||
1786 | outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */ | ||
1787 | |||
1788 | aztTimeOutCount = 0; | ||
1789 | do { | ||
1790 | aztIndatum = inb(STATUS_PORT); | ||
1791 | aztTimeOutCount++; | ||
1792 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1793 | break; | ||
1794 | } while (aztIndatum & AFL_STATUS); | ||
1795 | |||
1796 | if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? If not, reset and try again */ | ||
1797 | #ifndef MODULE | ||
1798 | if (azt_cont != 0x79) { | ||
1799 | printk(KERN_WARNING "aztcd: no AZTECH CD-ROM " | ||
1800 | "drive found-Try boot parameter aztcd=" | ||
1801 | "<BaseAddress>,0x79\n"); | ||
1802 | ret = -EIO; | ||
1803 | goto err_out; | ||
1804 | } | ||
1805 | #else | ||
1806 | if (0) { | ||
1807 | } | ||
1808 | #endif | ||
1809 | else { | ||
1810 | printk(KERN_INFO "aztcd: drive reset - " | ||
1811 | "please wait\n"); | ||
1812 | for (count = 0; count < 50; count++) { | ||
1813 | inb(STATUS_PORT); /*removing all data from earlier tries */ | ||
1814 | inb(DATA_PORT); | ||
1815 | } | ||
1816 | outb(POLLED, MODE_PORT); | ||
1817 | inb(CMD_PORT); | ||
1818 | inb(CMD_PORT); | ||
1819 | getAztStatus(); /*trap errors */ | ||
1820 | outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */ | ||
1821 | STEN_LOW; | ||
1822 | if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */ | ||
1823 | printk(KERN_WARNING "aztcd: no AZTECH " | ||
1824 | "CD-ROM drive found\n"); | ||
1825 | ret = -EIO; | ||
1826 | goto err_out; | ||
1827 | } | ||
1828 | |||
1829 | for (count = 0; count < AZT_TIMEOUT; | ||
1830 | count++) | ||
1831 | barrier(); /* Stop gcc 2.96 being smart */ | ||
1832 | /* use udelay(), damnit -- AV */ | ||
1833 | |||
1834 | if ((st = getAztStatus()) == -1) { | ||
1835 | printk(KERN_WARNING "aztcd: Drive Status" | ||
1836 | " Error Status=%x\n", st); | ||
1837 | ret = -EIO; | ||
1838 | goto err_out; | ||
1839 | } | ||
1840 | #ifdef AZT_DEBUG | ||
1841 | printk(KERN_DEBUG "aztcd: Status = %x\n", st); | ||
1842 | #endif | ||
1843 | outb(POLLED, MODE_PORT); | ||
1844 | inb(CMD_PORT); | ||
1845 | inb(CMD_PORT); | ||
1846 | outb(ACMD_GET_VERSION, CMD_PORT); /*GetVersion */ | ||
1847 | STEN_LOW; | ||
1848 | OP_OK; | ||
1849 | } | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | azt_init_end = 1; | ||
1854 | STEN_LOW; | ||
1855 | result[0] = inb(DATA_PORT); /*reading in a null byte??? */ | ||
1856 | for (count = 1; count < 50; count++) { /*Reading version string */ | ||
1857 | aztTimeOutCount = 0; /*here we must implement STEN_LOW differently */ | ||
1858 | do { | ||
1859 | aztIndatum = inb(STATUS_PORT); /*because we want to exit by timeout */ | ||
1860 | aztTimeOutCount++; | ||
1861 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1862 | break; | ||
1863 | } while (aztIndatum & AFL_STATUS); | ||
1864 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1865 | break; /*all chars read? */ | ||
1866 | result[count] = inb(DATA_PORT); | ||
1867 | } | ||
1868 | if (count > 30) | ||
1869 | max_count = 30; /*print max.30 chars of the version string */ | ||
1870 | else | ||
1871 | max_count = count; | ||
1872 | printk(KERN_INFO "aztcd: FirmwareVersion="); | ||
1873 | for (count = 1; count < max_count; count++) | ||
1874 | printk("%c", result[count]); | ||
1875 | printk("<<>> "); | ||
1876 | |||
1877 | if ((result[1] == 'A') && (result[2] == 'Z') && (result[3] == 'T')) { | ||
1878 | printk("AZTECH drive detected\n"); | ||
1879 | /*AZTECH*/} | ||
1880 | else if ((result[2] == 'C') && (result[3] == 'D') | ||
1881 | && (result[4] == 'D')) { | ||
1882 | printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES */ | ||
1883 | } else if ((result[1] == 0x03) && (result[2] == '5')) { | ||
1884 | printk("TXC or CyCDROM drive detected\n"); /*Conrad TXC, CyCDROM */ | ||
1885 | } else { /*OTHERS or none */ | ||
1886 | printk("\nunknown drive or firmware version detected\n"); | ||
1887 | printk | ||
1888 | ("aztcd may not run stable, if you want to try anyhow,\n"); | ||
1889 | printk("boot with: aztcd=<BaseAddress>,0x79\n"); | ||
1890 | if ((azt_cont != 0x79)) { | ||
1891 | printk("aztcd: FirmwareVersion="); | ||
1892 | for (count = 1; count < 5; count++) | ||
1893 | printk("%c", result[count]); | ||
1894 | printk("<<>> "); | ||
1895 | printk("Aborted\n"); | ||
1896 | ret = -EIO; | ||
1897 | goto err_out; | ||
1898 | } | ||
1899 | } | ||
1900 | azt_disk = alloc_disk(1); | ||
1901 | if (!azt_disk) | ||
1902 | goto err_out; | ||
1903 | |||
1904 | if (register_blkdev(MAJOR_NR, "aztcd")) { | ||
1905 | ret = -EIO; | ||
1906 | goto err_out2; | ||
1907 | } | ||
1908 | |||
1909 | azt_queue = blk_init_queue(do_aztcd_request, &aztSpin); | ||
1910 | if (!azt_queue) { | ||
1911 | ret = -ENOMEM; | ||
1912 | goto err_out3; | ||
1913 | } | ||
1914 | |||
1915 | blk_queue_hardsect_size(azt_queue, 2048); | ||
1916 | azt_disk->major = MAJOR_NR; | ||
1917 | azt_disk->first_minor = 0; | ||
1918 | azt_disk->fops = &azt_fops; | ||
1919 | sprintf(azt_disk->disk_name, "aztcd"); | ||
1920 | azt_disk->queue = azt_queue; | ||
1921 | add_disk(azt_disk); | ||
1922 | azt_invalidate_buffers(); | ||
1923 | aztPresent = 1; | ||
1924 | aztCloseDoor(); | ||
1925 | return 0; | ||
1926 | err_out3: | ||
1927 | unregister_blkdev(MAJOR_NR, "aztcd"); | ||
1928 | err_out2: | ||
1929 | put_disk(azt_disk); | ||
1930 | err_out: | ||
1931 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) { | ||
1932 | SWITCH_IDE_MASTER; | ||
1933 | release_region(azt_port, 8); /*IDE-interface */ | ||
1934 | } else | ||
1935 | release_region(azt_port, 4); /*proprietary interface */ | ||
1936 | return ret; | ||
1937 | |||
1938 | } | ||
1939 | |||
1940 | static void __exit aztcd_exit(void) | ||
1941 | { | ||
1942 | del_gendisk(azt_disk); | ||
1943 | put_disk(azt_disk); | ||
1944 | if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) { | ||
1945 | printk("What's that: can't unregister aztcd\n"); | ||
1946 | return; | ||
1947 | } | ||
1948 | blk_cleanup_queue(azt_queue); | ||
1949 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) { | ||
1950 | SWITCH_IDE_MASTER; | ||
1951 | release_region(azt_port, 8); /*IDE-interface */ | ||
1952 | } else | ||
1953 | release_region(azt_port, 4); /*proprietary interface */ | ||
1954 | printk(KERN_INFO "aztcd module released.\n"); | ||
1955 | } | ||
1956 | |||
1957 | module_init(aztcd_init); | ||
1958 | module_exit(aztcd_exit); | ||
1959 | |||
1960 | /*########################################################################## | ||
1961 | Aztcd State Machine: Controls Drive Operating State | ||
1962 | ########################################################################## | ||
1963 | */ | ||
1964 | static void azt_poll(void) | ||
1965 | { | ||
1966 | int st = 0; | ||
1967 | int loop_ctl = 1; | ||
1968 | int skip = 0; | ||
1969 | |||
1970 | if (azt_error) { | ||
1971 | if (aztSendCmd(ACMD_GET_ERROR)) | ||
1972 | RETURN("azt_poll 1"); | ||
1973 | STEN_LOW; | ||
1974 | azt_error = inb(DATA_PORT) & 0xFF; | ||
1975 | printk("aztcd: I/O error 0x%02x\n", azt_error); | ||
1976 | azt_invalidate_buffers(); | ||
1977 | #ifdef WARN_IF_READ_FAILURE | ||
1978 | if (AztTries == 5) | ||
1979 | printk | ||
1980 | ("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", | ||
1981 | azt_next_bn); | ||
1982 | #endif | ||
1983 | if (!AztTries--) { | ||
1984 | printk | ||
1985 | ("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", | ||
1986 | azt_next_bn); | ||
1987 | if (azt_transfer_is_active) { | ||
1988 | AztTries = 0; | ||
1989 | loop_ctl = 0; | ||
1990 | } | ||
1991 | if (current_valid()) | ||
1992 | end_request(CURRENT, 0); | ||
1993 | AztTries = 5; | ||
1994 | } | ||
1995 | azt_error = 0; | ||
1996 | azt_state = AZT_S_STOP; | ||
1997 | } | ||
1998 | |||
1999 | while (loop_ctl) { | ||
2000 | loop_ctl = 0; /* each case must flip this back to 1 if we want | ||
2001 | to come back up here */ | ||
2002 | switch (azt_state) { | ||
2003 | |||
2004 | case AZT_S_IDLE: | ||
2005 | #ifdef AZT_TEST3 | ||
2006 | if (azt_state != azt_state_old) { | ||
2007 | azt_state_old = azt_state; | ||
2008 | printk("AZT_S_IDLE\n"); | ||
2009 | } | ||
2010 | #endif | ||
2011 | return; | ||
2012 | |||
2013 | case AZT_S_START: | ||
2014 | #ifdef AZT_TEST3 | ||
2015 | if (azt_state != azt_state_old) { | ||
2016 | azt_state_old = azt_state; | ||
2017 | printk("AZT_S_START\n"); | ||
2018 | } | ||
2019 | #endif | ||
2020 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
2021 | RETURN("azt_poll 2"); /*result will be checked by aztStatus() */ | ||
2022 | azt_state = | ||
2023 | azt_mode == 1 ? AZT_S_READ : AZT_S_MODE; | ||
2024 | AztTimeout = 3000; | ||
2025 | break; | ||
2026 | |||
2027 | case AZT_S_MODE: | ||
2028 | #ifdef AZT_TEST3 | ||
2029 | if (azt_state != azt_state_old) { | ||
2030 | azt_state_old = azt_state; | ||
2031 | printk("AZT_S_MODE\n"); | ||
2032 | } | ||
2033 | #endif | ||
2034 | if (!skip) { | ||
2035 | if ((st = aztStatus()) != -1) { | ||
2036 | if ((st & AST_DSK_CHG) | ||
2037 | || (st & AST_NOT_READY)) { | ||
2038 | aztDiskChanged = 1; | ||
2039 | aztTocUpToDate = 0; | ||
2040 | azt_invalidate_buffers(); | ||
2041 | end_request(CURRENT, 0); | ||
2042 | printk | ||
2043 | ("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n"); | ||
2044 | } | ||
2045 | } else | ||
2046 | break; | ||
2047 | } | ||
2048 | skip = 0; | ||
2049 | |||
2050 | if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) { | ||
2051 | aztDiskChanged = 1; | ||
2052 | aztTocUpToDate = 0; | ||
2053 | printk | ||
2054 | ("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n"); | ||
2055 | end_request(CURRENT, 0); | ||
2056 | printk((st & AST_DOOR_OPEN) ? | ||
2057 | "aztcd: door open\n" : | ||
2058 | "aztcd: disk removed\n"); | ||
2059 | if (azt_transfer_is_active) { | ||
2060 | azt_state = AZT_S_START; | ||
2061 | loop_ctl = 1; /* goto immediately */ | ||
2062 | break; | ||
2063 | } | ||
2064 | azt_state = AZT_S_IDLE; | ||
2065 | while (current_valid()) | ||
2066 | end_request(CURRENT, 0); | ||
2067 | return; | ||
2068 | } | ||
2069 | |||
2070 | /* if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3"); | ||
2071 | outb(0x01, DATA_PORT); | ||
2072 | PA_OK; | ||
2073 | STEN_LOW; | ||
2074 | */ | ||
2075 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
2076 | RETURN("azt_poll 4"); | ||
2077 | STEN_LOW; | ||
2078 | azt_mode = 1; | ||
2079 | azt_state = AZT_S_READ; | ||
2080 | AztTimeout = 3000; | ||
2081 | |||
2082 | break; | ||
2083 | |||
2084 | |||
2085 | case AZT_S_READ: | ||
2086 | #ifdef AZT_TEST3 | ||
2087 | if (azt_state != azt_state_old) { | ||
2088 | azt_state_old = azt_state; | ||
2089 | printk("AZT_S_READ\n"); | ||
2090 | } | ||
2091 | #endif | ||
2092 | if (!skip) { | ||
2093 | if ((st = aztStatus()) != -1) { | ||
2094 | if ((st & AST_DSK_CHG) | ||
2095 | || (st & AST_NOT_READY)) { | ||
2096 | aztDiskChanged = 1; | ||
2097 | aztTocUpToDate = 0; | ||
2098 | azt_invalidate_buffers(); | ||
2099 | printk | ||
2100 | ("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n"); | ||
2101 | end_request(CURRENT, 0); | ||
2102 | } | ||
2103 | } else | ||
2104 | break; | ||
2105 | } | ||
2106 | |||
2107 | skip = 0; | ||
2108 | if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) { | ||
2109 | aztDiskChanged = 1; | ||
2110 | aztTocUpToDate = 0; | ||
2111 | printk((st & AST_DOOR_OPEN) ? | ||
2112 | "aztcd: door open\n" : | ||
2113 | "aztcd: disk removed\n"); | ||
2114 | if (azt_transfer_is_active) { | ||
2115 | azt_state = AZT_S_START; | ||
2116 | loop_ctl = 1; | ||
2117 | break; | ||
2118 | } | ||
2119 | azt_state = AZT_S_IDLE; | ||
2120 | while (current_valid()) | ||
2121 | end_request(CURRENT, 0); | ||
2122 | return; | ||
2123 | } | ||
2124 | |||
2125 | if (current_valid()) { | ||
2126 | struct azt_Play_msf msf; | ||
2127 | int i; | ||
2128 | azt_next_bn = CURRENT->sector / 4; | ||
2129 | azt_hsg2msf(azt_next_bn, &msf.start); | ||
2130 | i = 0; | ||
2131 | /* find out in which track we are */ | ||
2132 | while (azt_msf2hsg(&msf.start) > | ||
2133 | azt_msf2hsg(&Toc[++i].trackTime)) { | ||
2134 | }; | ||
2135 | if (azt_msf2hsg(&msf.start) < | ||
2136 | azt_msf2hsg(&Toc[i].trackTime) - | ||
2137 | AZT_BUF_SIZ) { | ||
2138 | azt_read_count = AZT_BUF_SIZ; /*fast, because we read ahead */ | ||
2139 | /*azt_read_count=CURRENT->nr_sectors; slow, no read ahead */ | ||
2140 | } else /* don't read beyond end of track */ | ||
2141 | #if AZT_MULTISESSION | ||
2142 | { | ||
2143 | azt_read_count = | ||
2144 | (azt_msf2hsg(&Toc[i].trackTime) | ||
2145 | / 4) * 4 - | ||
2146 | azt_msf2hsg(&msf.start); | ||
2147 | if (azt_read_count < 0) | ||
2148 | azt_read_count = 0; | ||
2149 | if (azt_read_count > AZT_BUF_SIZ) | ||
2150 | azt_read_count = | ||
2151 | AZT_BUF_SIZ; | ||
2152 | printk | ||
2153 | ("aztcd: warning - trying to read beyond end of track\n"); | ||
2154 | /* printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime)); | ||
2155 | */ } | ||
2156 | #else | ||
2157 | { | ||
2158 | azt_read_count = AZT_BUF_SIZ; | ||
2159 | } | ||
2160 | #endif | ||
2161 | msf.end.min = 0; | ||
2162 | msf.end.sec = 0; | ||
2163 | msf.end.frame = azt_read_count; /*Mitsumi here reads 0xffffff sectors */ | ||
2164 | #ifdef AZT_TEST3 | ||
2165 | printk | ||
2166 | ("---reading msf-address %x:%x:%x %x:%x:%x\n", | ||
2167 | msf.start.min, msf.start.sec, | ||
2168 | msf.start.frame, msf.end.min, | ||
2169 | msf.end.sec, msf.end.frame); | ||
2170 | printk | ||
2171 | ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", | ||
2172 | azt_next_bn, azt_buf_in, azt_buf_out, | ||
2173 | azt_buf_bn[azt_buf_in]); | ||
2174 | #endif | ||
2175 | if (azt_read_mode == AZT_MODE_2) { | ||
2176 | sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode */ | ||
2177 | } else { | ||
2178 | sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode */ | ||
2179 | } | ||
2180 | azt_state = AZT_S_DATA; | ||
2181 | AztTimeout = READ_TIMEOUT; | ||
2182 | } else { | ||
2183 | azt_state = AZT_S_STOP; | ||
2184 | loop_ctl = 1; | ||
2185 | break; | ||
2186 | } | ||
2187 | |||
2188 | break; | ||
2189 | |||
2190 | |||
2191 | case AZT_S_DATA: | ||
2192 | #ifdef AZT_TEST3 | ||
2193 | if (azt_state != azt_state_old) { | ||
2194 | azt_state_old = azt_state; | ||
2195 | printk("AZT_S_DATA\n"); | ||
2196 | } | ||
2197 | #endif | ||
2198 | |||
2199 | st = inb(STATUS_PORT) & AFL_STATUSorDATA; | ||
2200 | |||
2201 | switch (st) { | ||
2202 | |||
2203 | case AFL_DATA: | ||
2204 | #ifdef AZT_TEST3 | ||
2205 | if (st != azt_st_old) { | ||
2206 | azt_st_old = st; | ||
2207 | printk("---AFL_DATA st:%x\n", st); | ||
2208 | } | ||
2209 | #endif | ||
2210 | if (!AztTries--) { | ||
2211 | printk | ||
2212 | ("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", | ||
2213 | azt_next_bn); | ||
2214 | if (azt_transfer_is_active) { | ||
2215 | AztTries = 0; | ||
2216 | break; | ||
2217 | } | ||
2218 | if (current_valid()) | ||
2219 | end_request(CURRENT, 0); | ||
2220 | AztTries = 5; | ||
2221 | } | ||
2222 | azt_state = AZT_S_START; | ||
2223 | AztTimeout = READ_TIMEOUT; | ||
2224 | loop_ctl = 1; | ||
2225 | break; | ||
2226 | |||
2227 | case AFL_STATUSorDATA: | ||
2228 | #ifdef AZT_TEST3 | ||
2229 | if (st != azt_st_old) { | ||
2230 | azt_st_old = st; | ||
2231 | printk | ||
2232 | ("---AFL_STATUSorDATA st:%x\n", | ||
2233 | st); | ||
2234 | } | ||
2235 | #endif | ||
2236 | break; | ||
2237 | |||
2238 | default: | ||
2239 | #ifdef AZT_TEST3 | ||
2240 | if (st != azt_st_old) { | ||
2241 | azt_st_old = st; | ||
2242 | printk("---default: st:%x\n", st); | ||
2243 | } | ||
2244 | #endif | ||
2245 | AztTries = 5; | ||
2246 | if (!current_valid() && azt_buf_in == azt_buf_out) { | ||
2247 | azt_state = AZT_S_STOP; | ||
2248 | loop_ctl = 1; | ||
2249 | break; | ||
2250 | } | ||
2251 | if (azt_read_count <= 0) | ||
2252 | printk | ||
2253 | ("aztcd: warning - try to read 0 frames\n"); | ||
2254 | while (azt_read_count) { /*??? fast read ahead loop */ | ||
2255 | azt_buf_bn[azt_buf_in] = -1; | ||
2256 | DTEN_LOW; /*??? unsolved problem, very | ||
2257 | seldom we get timeouts | ||
2258 | here, don't now the real | ||
2259 | reason. With my drive this | ||
2260 | sometimes also happens with | ||
2261 | Aztech's original driver under | ||
2262 | DOS. Is it a hardware bug? | ||
2263 | I tried to recover from such | ||
2264 | situations here. Zimmermann */ | ||
2265 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
2266 | printk | ||
2267 | ("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n", | ||
2268 | azt_read_count, | ||
2269 | CURRENT->nr_sectors, | ||
2270 | azt_buf_in); | ||
2271 | printk | ||
2272 | ("azt_transfer_is_active:%x\n", | ||
2273 | azt_transfer_is_active); | ||
2274 | azt_read_count = 0; | ||
2275 | azt_state = AZT_S_STOP; | ||
2276 | loop_ctl = 1; | ||
2277 | end_request(CURRENT, 1); /*should we have here (1) or (0)? */ | ||
2278 | } else { | ||
2279 | if (azt_read_mode == | ||
2280 | AZT_MODE_2) { | ||
2281 | insb(DATA_PORT, | ||
2282 | azt_buf + | ||
2283 | CD_FRAMESIZE_RAW | ||
2284 | * azt_buf_in, | ||
2285 | CD_FRAMESIZE_RAW); | ||
2286 | } else { | ||
2287 | insb(DATA_PORT, | ||
2288 | azt_buf + | ||
2289 | CD_FRAMESIZE * | ||
2290 | azt_buf_in, | ||
2291 | CD_FRAMESIZE); | ||
2292 | } | ||
2293 | azt_read_count--; | ||
2294 | #ifdef AZT_TEST3 | ||
2295 | printk | ||
2296 | ("AZT_S_DATA; ---I've read data- read_count: %d\n", | ||
2297 | azt_read_count); | ||
2298 | printk | ||
2299 | ("azt_next_bn:%d azt_buf_in:%d azt_buf_out:%d azt_buf_bn:%d\n", | ||
2300 | azt_next_bn, | ||
2301 | azt_buf_in, | ||
2302 | azt_buf_out, | ||
2303 | azt_buf_bn | ||
2304 | [azt_buf_in]); | ||
2305 | #endif | ||
2306 | azt_buf_bn[azt_buf_in] = | ||
2307 | azt_next_bn++; | ||
2308 | if (azt_buf_out == -1) | ||
2309 | azt_buf_out = | ||
2310 | azt_buf_in; | ||
2311 | azt_buf_in = | ||
2312 | azt_buf_in + 1 == | ||
2313 | AZT_BUF_SIZ ? 0 : | ||
2314 | azt_buf_in + 1; | ||
2315 | } | ||
2316 | } | ||
2317 | if (!azt_transfer_is_active) { | ||
2318 | while (current_valid()) { | ||
2319 | azt_transfer(); | ||
2320 | if (CURRENT->nr_sectors == | ||
2321 | 0) | ||
2322 | end_request(CURRENT, 1); | ||
2323 | else | ||
2324 | break; | ||
2325 | } | ||
2326 | } | ||
2327 | |||
2328 | if (current_valid() | ||
2329 | && (CURRENT->sector / 4 < azt_next_bn | ||
2330 | || CURRENT->sector / 4 > | ||
2331 | azt_next_bn + AZT_BUF_SIZ)) { | ||
2332 | azt_state = AZT_S_STOP; | ||
2333 | loop_ctl = 1; | ||
2334 | break; | ||
2335 | } | ||
2336 | AztTimeout = READ_TIMEOUT; | ||
2337 | if (azt_read_count == 0) { | ||
2338 | azt_state = AZT_S_STOP; | ||
2339 | loop_ctl = 1; | ||
2340 | break; | ||
2341 | } | ||
2342 | break; | ||
2343 | } | ||
2344 | break; | ||
2345 | |||
2346 | |||
2347 | case AZT_S_STOP: | ||
2348 | #ifdef AZT_TEST3 | ||
2349 | if (azt_state != azt_state_old) { | ||
2350 | azt_state_old = azt_state; | ||
2351 | printk("AZT_S_STOP\n"); | ||
2352 | } | ||
2353 | #endif | ||
2354 | if (azt_read_count != 0) | ||
2355 | printk("aztcd: discard data=%x frames\n", | ||
2356 | azt_read_count); | ||
2357 | while (azt_read_count != 0) { | ||
2358 | int i; | ||
2359 | if (!(inb(STATUS_PORT) & AFL_DATA)) { | ||
2360 | if (azt_read_mode == AZT_MODE_2) | ||
2361 | for (i = 0; | ||
2362 | i < CD_FRAMESIZE_RAW; | ||
2363 | i++) | ||
2364 | inb(DATA_PORT); | ||
2365 | else | ||
2366 | for (i = 0; | ||
2367 | i < CD_FRAMESIZE; i++) | ||
2368 | inb(DATA_PORT); | ||
2369 | } | ||
2370 | azt_read_count--; | ||
2371 | } | ||
2372 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
2373 | RETURN("azt_poll 5"); | ||
2374 | azt_state = AZT_S_STOPPING; | ||
2375 | AztTimeout = 1000; | ||
2376 | break; | ||
2377 | |||
2378 | case AZT_S_STOPPING: | ||
2379 | #ifdef AZT_TEST3 | ||
2380 | if (azt_state != azt_state_old) { | ||
2381 | azt_state_old = azt_state; | ||
2382 | printk("AZT_S_STOPPING\n"); | ||
2383 | } | ||
2384 | #endif | ||
2385 | |||
2386 | if ((st = aztStatus()) == -1 && AztTimeout) | ||
2387 | break; | ||
2388 | |||
2389 | if ((st != -1) | ||
2390 | && ((st & AST_DSK_CHG) | ||
2391 | || (st & AST_NOT_READY))) { | ||
2392 | aztDiskChanged = 1; | ||
2393 | aztTocUpToDate = 0; | ||
2394 | azt_invalidate_buffers(); | ||
2395 | printk | ||
2396 | ("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n"); | ||
2397 | end_request(CURRENT, 0); | ||
2398 | } | ||
2399 | |||
2400 | #ifdef AZT_TEST3 | ||
2401 | printk("CURRENT_VALID %d azt_mode %d\n", | ||
2402 | current_valid(), azt_mode); | ||
2403 | #endif | ||
2404 | |||
2405 | if (current_valid()) { | ||
2406 | if (st != -1) { | ||
2407 | if (azt_mode == 1) { | ||
2408 | azt_state = AZT_S_READ; | ||
2409 | loop_ctl = 1; | ||
2410 | skip = 1; | ||
2411 | break; | ||
2412 | } else { | ||
2413 | azt_state = AZT_S_MODE; | ||
2414 | loop_ctl = 1; | ||
2415 | skip = 1; | ||
2416 | break; | ||
2417 | } | ||
2418 | } else { | ||
2419 | azt_state = AZT_S_START; | ||
2420 | AztTimeout = 1; | ||
2421 | } | ||
2422 | } else { | ||
2423 | azt_state = AZT_S_IDLE; | ||
2424 | return; | ||
2425 | } | ||
2426 | break; | ||
2427 | |||
2428 | default: | ||
2429 | printk("aztcd: invalid state %d\n", azt_state); | ||
2430 | return; | ||
2431 | } /* case */ | ||
2432 | } /* while */ | ||
2433 | |||
2434 | |||
2435 | if (!AztTimeout--) { | ||
2436 | printk("aztcd: timeout in state %d\n", azt_state); | ||
2437 | azt_state = AZT_S_STOP; | ||
2438 | if (aztSendCmd(ACMD_STOP)) | ||
2439 | RETURN("azt_poll 6"); | ||
2440 | STEN_LOW_WAIT; | ||
2441 | }; | ||
2442 | |||
2443 | SET_TIMER(azt_poll, HZ / 100); | ||
2444 | } | ||
2445 | |||
2446 | |||
2447 | /*########################################################################### | ||
2448 | * Miscellaneous support functions | ||
2449 | ########################################################################### | ||
2450 | */ | ||
2451 | static void azt_hsg2msf(long hsg, struct msf *msf) | ||
2452 | { | ||
2453 | hsg += 150; | ||
2454 | msf->min = hsg / 4500; | ||
2455 | hsg %= 4500; | ||
2456 | msf->sec = hsg / 75; | ||
2457 | msf->frame = hsg % 75; | ||
2458 | #ifdef AZT_DEBUG | ||
2459 | if (msf->min >= 70) | ||
2460 | printk("aztcd: Error hsg2msf address Minutes\n"); | ||
2461 | if (msf->sec >= 60) | ||
2462 | printk("aztcd: Error hsg2msf address Seconds\n"); | ||
2463 | if (msf->frame >= 75) | ||
2464 | printk("aztcd: Error hsg2msf address Frames\n"); | ||
2465 | #endif | ||
2466 | azt_bin2bcd(&msf->min); /* convert to BCD */ | ||
2467 | azt_bin2bcd(&msf->sec); | ||
2468 | azt_bin2bcd(&msf->frame); | ||
2469 | } | ||
2470 | |||
2471 | static long azt_msf2hsg(struct msf *mp) | ||
2472 | { | ||
2473 | return azt_bcd2bin(mp->frame) + azt_bcd2bin(mp->sec) * 75 | ||
2474 | + azt_bcd2bin(mp->min) * 4500 - CD_MSF_OFFSET; | ||
2475 | } | ||
2476 | |||
2477 | static void azt_bin2bcd(unsigned char *p) | ||
2478 | { | ||
2479 | int u, t; | ||
2480 | |||
2481 | u = *p % 10; | ||
2482 | t = *p / 10; | ||
2483 | *p = u | (t << 4); | ||
2484 | } | ||
2485 | |||
2486 | static int azt_bcd2bin(unsigned char bcd) | ||
2487 | { | ||
2488 | return (bcd >> 4) * 10 + (bcd & 0xF); | ||
2489 | } | ||
2490 | |||
2491 | MODULE_LICENSE("GPL"); | ||
2492 | MODULE_ALIAS_BLOCKDEV_MAJOR(AZTECH_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/aztcd.h b/drivers/cdrom/aztcd.h deleted file mode 100644 index 057501e31628..000000000000 --- a/drivers/cdrom/aztcd.h +++ /dev/null | |||
@@ -1,162 +0,0 @@ | |||
1 | /* $Id: aztcd.h,v 2.60 1997/11/29 09:51:22 root Exp root $ | ||
2 | * | ||
3 | * Definitions for a AztechCD268 CD-ROM interface | ||
4 | * Copyright (C) 1994-98 Werner Zimmermann | ||
5 | * | ||
6 | * based on Mitsumi CDROM driver by Martin Harriss | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | * History: W.Zimmermann adaption to Aztech CD268-01A Version 1.3 | ||
23 | * October 1994 Email: Werner.Zimmermann@fht-esslingen.de | ||
24 | */ | ||
25 | |||
26 | /* *** change this to set the I/O port address of your CD-ROM drive, | ||
27 | set to '-1', if you want autoprobing */ | ||
28 | #define AZT_BASE_ADDR -1 | ||
29 | |||
30 | /* list of autoprobing addresses (not more than 15), last value must be 0x000 | ||
31 | Note: Autoprobing is only enabled, if AZT_BASE_ADDR is set to '-1' ! */ | ||
32 | #define AZT_BASE_AUTO { 0x320, 0x300, 0x310, 0x330, 0x000 } | ||
33 | |||
34 | /* Uncomment this, if your CDROM is connected to a Soundwave32-soundcard | ||
35 | and configure AZT_BASE_ADDR and AZT_SW32_BASE_ADDR */ | ||
36 | /*#define AZT_SW32 1 | ||
37 | */ | ||
38 | |||
39 | #ifdef AZT_SW32 | ||
40 | #define AZT_SW32_BASE_ADDR 0x220 /*I/O port base address of your soundcard*/ | ||
41 | #endif | ||
42 | |||
43 | /* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray | ||
44 | from locking */ | ||
45 | #define AZT_ALLOW_TRAY_LOCK 1 | ||
46 | |||
47 | /*Set this to 1 to allow auto-eject when unmounting a disk, set to 0, if you | ||
48 | don't want the auto-eject feature*/ | ||
49 | #define AZT_AUTO_EJECT 0 | ||
50 | |||
51 | /*Set this to 1, if you want to use incompatible ioctls for reading in raw and | ||
52 | cooked mode */ | ||
53 | #define AZT_PRIVATE_IOCTLS 1 | ||
54 | |||
55 | /*Set this to 1, if you want multisession support by the ISO fs. Even if you set | ||
56 | this value to '0' you can use multisession CDs. In that case the drive's firm- | ||
57 | ware will do the appropriate redirection automatically. The CD will then look | ||
58 | like a single session CD (but nevertheless all data may be read). Please read | ||
59 | chapter '5.1 Multisession support' in README.aztcd for details. Normally it's | ||
60 | uncritical to leave this setting untouched */ | ||
61 | #define AZT_MULTISESSION 1 | ||
62 | |||
63 | /*Uncomment this, if you are using a linux kernel version prior to 2.1.0 */ | ||
64 | /*#define AZT_KERNEL_PRIOR_2_1 */ | ||
65 | |||
66 | /*---------------------------------------------------------------------------*/ | ||
67 | /*-----nothing to be configured for normal applications below this line------*/ | ||
68 | |||
69 | |||
70 | /* Increase this if you get lots of timeouts; if you get kernel panic, replace | ||
71 | STEN_LOW_WAIT by STEN_LOW in the source code */ | ||
72 | #define AZT_STATUS_DELAY 400 /*for timer wait, STEN_LOW_WAIT*/ | ||
73 | #define AZT_TIMEOUT 8000000 /*for busy wait STEN_LOW, DTEN_LOW*/ | ||
74 | #define AZT_FAST_TIMEOUT 10000 /*for reading the version string*/ | ||
75 | |||
76 | /* number of times to retry a command before giving up */ | ||
77 | #define AZT_RETRY_ATTEMPTS 3 | ||
78 | |||
79 | /* port access macros */ | ||
80 | #define CMD_PORT azt_port | ||
81 | #define DATA_PORT azt_port | ||
82 | #define STATUS_PORT azt_port+1 | ||
83 | #define MODE_PORT azt_port+2 | ||
84 | #ifdef AZT_SW32 | ||
85 | #define AZT_SW32_INIT (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16)) | ||
86 | #define AZT_SW32_CONFIG_REG AZT_SW32_BASE_ADDR+0x16 /*Soundwave32 Config. Register*/ | ||
87 | #define AZT_SW32_ID_REG AZT_SW32_BASE_ADDR+0x04 /*Soundwave32 ID Version Register*/ | ||
88 | #endif | ||
89 | |||
90 | /* status bits */ | ||
91 | #define AST_CMD_CHECK 0x80 /* 1 = command error */ | ||
92 | #define AST_DOOR_OPEN 0x40 /* 1 = door is open */ | ||
93 | #define AST_NOT_READY 0x20 /* 1 = no disk in the drive */ | ||
94 | #define AST_DSK_CHG 0x02 /* 1 = disk removed or changed */ | ||
95 | #define AST_MODE 0x01 /* 0=MODE1, 1=MODE2 */ | ||
96 | #define AST_MODE_BITS 0x1C /* Mode Bits */ | ||
97 | #define AST_INITIAL 0x0C /* initial, only valid ... */ | ||
98 | #define AST_BUSY 0x04 /* now playing, only valid | ||
99 | in combination with mode | ||
100 | bits */ | ||
101 | /* flag bits */ | ||
102 | #define AFL_DATA 0x02 /* data available if low */ | ||
103 | #define AFL_STATUS 0x04 /* status available if low */ | ||
104 | #define AFL_OP_OK 0x01 /* OP_OK command correct*/ | ||
105 | #define AFL_PA_OK 0x02 /* PA_OK parameter correct*/ | ||
106 | #define AFL_OP_ERR 0x05 /* error in command*/ | ||
107 | #define AFL_PA_ERR 0x06 /* error in parameters*/ | ||
108 | #define POLLED 0x04 /* polled mode */ | ||
109 | |||
110 | /* commands */ | ||
111 | #define ACMD_SOFT_RESET 0x10 /* reset drive */ | ||
112 | #define ACMD_PLAY_READ 0x20 /* read data track in cooked mode */ | ||
113 | #define ACMD_PLAY_READ_RAW 0x21 /* reading in raw mode*/ | ||
114 | #define ACMD_SEEK 0x30 /* seek msf address*/ | ||
115 | #define ACMD_SEEK_TO_LEADIN 0x31 /* seek to leadin track*/ | ||
116 | #define ACMD_GET_ERROR 0x40 /* get error code */ | ||
117 | #define ACMD_GET_STATUS 0x41 /* get status */ | ||
118 | #define ACMD_GET_Q_CHANNEL 0x50 /* read info from q channel */ | ||
119 | #define ACMD_EJECT 0x60 /* eject/open tray */ | ||
120 | #define ACMD_CLOSE 0x61 /* close tray */ | ||
121 | #define ACMD_LOCK 0x71 /* lock tray closed */ | ||
122 | #define ACMD_UNLOCK 0x72 /* unlock tray */ | ||
123 | #define ACMD_PAUSE 0x80 /* pause */ | ||
124 | #define ACMD_STOP 0x81 /* stop play */ | ||
125 | #define ACMD_PLAY_AUDIO 0x90 /* play audio track */ | ||
126 | #define ACMD_SET_VOLUME 0x93 /* set audio level */ | ||
127 | #define ACMD_GET_VERSION 0xA0 /* get firmware version */ | ||
128 | #define ACMD_SET_DISK_TYPE 0xA1 /* set disk data mode */ | ||
129 | |||
130 | #define MAX_TRACKS 104 | ||
131 | |||
132 | struct msf { | ||
133 | unsigned char min; | ||
134 | unsigned char sec; | ||
135 | unsigned char frame; | ||
136 | }; | ||
137 | |||
138 | struct azt_Play_msf { | ||
139 | struct msf start; | ||
140 | struct msf end; | ||
141 | }; | ||
142 | |||
143 | struct azt_DiskInfo { | ||
144 | unsigned char first; | ||
145 | unsigned char next; | ||
146 | unsigned char last; | ||
147 | struct msf diskLength; | ||
148 | struct msf firstTrack; | ||
149 | unsigned char multi; | ||
150 | struct msf nextSession; | ||
151 | struct msf lastSession; | ||
152 | unsigned char xa; | ||
153 | unsigned char audio; | ||
154 | }; | ||
155 | |||
156 | struct azt_Toc { | ||
157 | unsigned char ctrl_addr; | ||
158 | unsigned char track; | ||
159 | unsigned char pointIndex; | ||
160 | struct msf trackTime; | ||
161 | struct msf diskTime; | ||
162 | }; | ||
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 3625a05bc3d3..aa5468f487ba 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c | |||
@@ -302,7 +302,7 @@ module_param(lockdoor, bool, 0); | |||
302 | module_param(check_media_type, bool, 0); | 302 | module_param(check_media_type, bool, 0); |
303 | module_param(mrw_format_restart, bool, 0); | 303 | module_param(mrw_format_restart, bool, 0); |
304 | 304 | ||
305 | static DEFINE_SPINLOCK(cdrom_lock); | 305 | static DEFINE_MUTEX(cdrom_mutex); |
306 | 306 | ||
307 | static const char *mrw_format_status[] = { | 307 | static const char *mrw_format_status[] = { |
308 | "not mrw", | 308 | "not mrw", |
@@ -438,10 +438,10 @@ int register_cdrom(struct cdrom_device_info *cdi) | |||
438 | cdo->generic_packet = cdrom_dummy_generic_packet; | 438 | cdo->generic_packet = cdrom_dummy_generic_packet; |
439 | 439 | ||
440 | cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); | 440 | cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); |
441 | spin_lock(&cdrom_lock); | 441 | mutex_lock(&cdrom_mutex); |
442 | cdi->next = topCdromPtr; | 442 | cdi->next = topCdromPtr; |
443 | topCdromPtr = cdi; | 443 | topCdromPtr = cdi; |
444 | spin_unlock(&cdrom_lock); | 444 | mutex_unlock(&cdrom_mutex); |
445 | return 0; | 445 | return 0; |
446 | } | 446 | } |
447 | #undef ENSURE | 447 | #undef ENSURE |
@@ -452,7 +452,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) | |||
452 | cdinfo(CD_OPEN, "entering unregister_cdrom\n"); | 452 | cdinfo(CD_OPEN, "entering unregister_cdrom\n"); |
453 | 453 | ||
454 | prev = NULL; | 454 | prev = NULL; |
455 | spin_lock(&cdrom_lock); | 455 | mutex_lock(&cdrom_mutex); |
456 | cdi = topCdromPtr; | 456 | cdi = topCdromPtr; |
457 | while (cdi && cdi != unreg) { | 457 | while (cdi && cdi != unreg) { |
458 | prev = cdi; | 458 | prev = cdi; |
@@ -460,7 +460,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) | |||
460 | } | 460 | } |
461 | 461 | ||
462 | if (cdi == NULL) { | 462 | if (cdi == NULL) { |
463 | spin_unlock(&cdrom_lock); | 463 | mutex_unlock(&cdrom_mutex); |
464 | return -2; | 464 | return -2; |
465 | } | 465 | } |
466 | if (prev) | 466 | if (prev) |
@@ -468,7 +468,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) | |||
468 | else | 468 | else |
469 | topCdromPtr = cdi->next; | 469 | topCdromPtr = cdi->next; |
470 | 470 | ||
471 | spin_unlock(&cdrom_lock); | 471 | mutex_unlock(&cdrom_mutex); |
472 | 472 | ||
473 | if (cdi->exit) | 473 | if (cdi->exit) |
474 | cdi->exit(cdi); | 474 | cdi->exit(cdi); |
@@ -3289,103 +3289,137 @@ static struct cdrom_sysctl_settings { | |||
3289 | int check; /* check media type */ | 3289 | int check; /* check media type */ |
3290 | } cdrom_sysctl_settings; | 3290 | } cdrom_sysctl_settings; |
3291 | 3291 | ||
3292 | enum cdrom_print_option { | ||
3293 | CTL_NAME, | ||
3294 | CTL_SPEED, | ||
3295 | CTL_SLOTS, | ||
3296 | CTL_CAPABILITY | ||
3297 | }; | ||
3298 | |||
3299 | static int cdrom_print_info(const char *header, int val, char *info, | ||
3300 | int *pos, enum cdrom_print_option option) | ||
3301 | { | ||
3302 | const int max_size = sizeof(cdrom_sysctl_settings.info); | ||
3303 | struct cdrom_device_info *cdi; | ||
3304 | int ret; | ||
3305 | |||
3306 | ret = scnprintf(info + *pos, max_size - *pos, header); | ||
3307 | if (!ret) | ||
3308 | return 1; | ||
3309 | |||
3310 | *pos += ret; | ||
3311 | |||
3312 | for (cdi = topCdromPtr; cdi; cdi = cdi->next) { | ||
3313 | switch (option) { | ||
3314 | case CTL_NAME: | ||
3315 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3316 | "\t%s", cdi->name); | ||
3317 | break; | ||
3318 | case CTL_SPEED: | ||
3319 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3320 | "\t%d", cdi->speed); | ||
3321 | break; | ||
3322 | case CTL_SLOTS: | ||
3323 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3324 | "\t%d", cdi->capacity); | ||
3325 | break; | ||
3326 | case CTL_CAPABILITY: | ||
3327 | ret = scnprintf(info + *pos, max_size - *pos, | ||
3328 | "\t%d", CDROM_CAN(val) != 0); | ||
3329 | break; | ||
3330 | default: | ||
3331 | printk(KERN_INFO "cdrom: invalid option%d\n", option); | ||
3332 | return 1; | ||
3333 | } | ||
3334 | if (!ret) | ||
3335 | return 1; | ||
3336 | *pos += ret; | ||
3337 | } | ||
3338 | |||
3339 | return 0; | ||
3340 | } | ||
3341 | |||
3292 | static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, | 3342 | static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, |
3293 | void __user *buffer, size_t *lenp, loff_t *ppos) | 3343 | void __user *buffer, size_t *lenp, loff_t *ppos) |
3294 | { | 3344 | { |
3295 | int pos; | 3345 | int pos; |
3296 | struct cdrom_device_info *cdi; | ||
3297 | char *info = cdrom_sysctl_settings.info; | 3346 | char *info = cdrom_sysctl_settings.info; |
3347 | const int max_size = sizeof(cdrom_sysctl_settings.info); | ||
3298 | 3348 | ||
3299 | if (!*lenp || (*ppos && !write)) { | 3349 | if (!*lenp || (*ppos && !write)) { |
3300 | *lenp = 0; | 3350 | *lenp = 0; |
3301 | return 0; | 3351 | return 0; |
3302 | } | 3352 | } |
3303 | 3353 | ||
3354 | mutex_lock(&cdrom_mutex); | ||
3355 | |||
3304 | pos = sprintf(info, "CD-ROM information, " VERSION "\n"); | 3356 | pos = sprintf(info, "CD-ROM information, " VERSION "\n"); |
3305 | 3357 | ||
3306 | pos += sprintf(info+pos, "\ndrive name:\t"); | 3358 | if (cdrom_print_info("\ndrive name:\t", 0, info, &pos, CTL_NAME)) |
3307 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3359 | goto done; |
3308 | pos += sprintf(info+pos, "\t%s", cdi->name); | 3360 | if (cdrom_print_info("\ndrive speed:\t", 0, info, &pos, CTL_SPEED)) |
3309 | 3361 | goto done; | |
3310 | pos += sprintf(info+pos, "\ndrive speed:\t"); | 3362 | if (cdrom_print_info("\ndrive # of slots:", 0, info, &pos, CTL_SLOTS)) |
3311 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3363 | goto done; |
3312 | pos += sprintf(info+pos, "\t%d", cdi->speed); | 3364 | if (cdrom_print_info("\nCan close tray:\t", |
3313 | 3365 | CDC_CLOSE_TRAY, info, &pos, CTL_CAPABILITY)) | |
3314 | pos += sprintf(info+pos, "\ndrive # of slots:"); | 3366 | goto done; |
3315 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3367 | if (cdrom_print_info("\nCan open tray:\t", |
3316 | pos += sprintf(info+pos, "\t%d", cdi->capacity); | 3368 | CDC_OPEN_TRAY, info, &pos, CTL_CAPABILITY)) |
3317 | 3369 | goto done; | |
3318 | pos += sprintf(info+pos, "\nCan close tray:\t"); | 3370 | if (cdrom_print_info("\nCan lock tray:\t", |
3319 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3371 | CDC_LOCK, info, &pos, CTL_CAPABILITY)) |
3320 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); | 3372 | goto done; |
3321 | 3373 | if (cdrom_print_info("\nCan change speed:", | |
3322 | pos += sprintf(info+pos, "\nCan open tray:\t"); | 3374 | CDC_SELECT_SPEED, info, &pos, CTL_CAPABILITY)) |
3323 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3375 | goto done; |
3324 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); | 3376 | if (cdrom_print_info("\nCan select disk:", |
3325 | 3377 | CDC_SELECT_DISC, info, &pos, CTL_CAPABILITY)) | |
3326 | pos += sprintf(info+pos, "\nCan lock tray:\t"); | 3378 | goto done; |
3327 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3379 | if (cdrom_print_info("\nCan read multisession:", |
3328 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); | 3380 | CDC_MULTI_SESSION, info, &pos, CTL_CAPABILITY)) |
3329 | 3381 | goto done; | |
3330 | pos += sprintf(info+pos, "\nCan change speed:"); | 3382 | if (cdrom_print_info("\nCan read MCN:\t", |
3331 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3383 | CDC_MCN, info, &pos, CTL_CAPABILITY)) |
3332 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); | 3384 | goto done; |
3333 | 3385 | if (cdrom_print_info("\nReports media changed:", | |
3334 | pos += sprintf(info+pos, "\nCan select disk:"); | 3386 | CDC_MEDIA_CHANGED, info, &pos, CTL_CAPABILITY)) |
3335 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3387 | goto done; |
3336 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); | 3388 | if (cdrom_print_info("\nCan play audio:\t", |
3337 | 3389 | CDC_PLAY_AUDIO, info, &pos, CTL_CAPABILITY)) | |
3338 | pos += sprintf(info+pos, "\nCan read multisession:"); | 3390 | goto done; |
3339 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3391 | if (cdrom_print_info("\nCan write CD-R:\t", |
3340 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); | 3392 | CDC_CD_R, info, &pos, CTL_CAPABILITY)) |
3341 | 3393 | goto done; | |
3342 | pos += sprintf(info+pos, "\nCan read MCN:\t"); | 3394 | if (cdrom_print_info("\nCan write CD-RW:", |
3343 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3395 | CDC_CD_RW, info, &pos, CTL_CAPABILITY)) |
3344 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); | 3396 | goto done; |
3345 | 3397 | if (cdrom_print_info("\nCan read DVD:\t", | |
3346 | pos += sprintf(info+pos, "\nReports media changed:"); | 3398 | CDC_DVD, info, &pos, CTL_CAPABILITY)) |
3347 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3399 | goto done; |
3348 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); | 3400 | if (cdrom_print_info("\nCan write DVD-R:", |
3349 | 3401 | CDC_DVD_R, info, &pos, CTL_CAPABILITY)) | |
3350 | pos += sprintf(info+pos, "\nCan play audio:\t"); | 3402 | goto done; |
3351 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3403 | if (cdrom_print_info("\nCan write DVD-RAM:", |
3352 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); | 3404 | CDC_DVD_RAM, info, &pos, CTL_CAPABILITY)) |
3353 | 3405 | goto done; | |
3354 | pos += sprintf(info+pos, "\nCan write CD-R:\t"); | 3406 | if (cdrom_print_info("\nCan read MRW:\t", |
3355 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3407 | CDC_MRW, info, &pos, CTL_CAPABILITY)) |
3356 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); | 3408 | goto done; |
3357 | 3409 | if (cdrom_print_info("\nCan write MRW:\t", | |
3358 | pos += sprintf(info+pos, "\nCan write CD-RW:"); | 3410 | CDC_MRW_W, info, &pos, CTL_CAPABILITY)) |
3359 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3411 | goto done; |
3360 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); | 3412 | if (cdrom_print_info("\nCan write RAM:\t", |
3361 | 3413 | CDC_RAM, info, &pos, CTL_CAPABILITY)) | |
3362 | pos += sprintf(info+pos, "\nCan read DVD:\t"); | 3414 | goto done; |
3363 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3415 | if (!scnprintf(info + pos, max_size - pos, "\n\n")) |
3364 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); | 3416 | goto done; |
3365 | 3417 | doit: | |
3366 | pos += sprintf(info+pos, "\nCan write DVD-R:"); | 3418 | mutex_unlock(&cdrom_mutex); |
3367 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | 3419 | return proc_dostring(ctl, write, filp, buffer, lenp, ppos); |
3368 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); | 3420 | done: |
3369 | 3421 | printk(KERN_INFO "cdrom: info buffer too small\n"); | |
3370 | pos += sprintf(info+pos, "\nCan write DVD-RAM:"); | 3422 | goto doit; |
3371 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3372 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); | ||
3373 | |||
3374 | pos += sprintf(info+pos, "\nCan read MRW:\t"); | ||
3375 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3376 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0); | ||
3377 | |||
3378 | pos += sprintf(info+pos, "\nCan write MRW:\t"); | ||
3379 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3380 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0); | ||
3381 | |||
3382 | pos += sprintf(info+pos, "\nCan write RAM:\t"); | ||
3383 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3384 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0); | ||
3385 | |||
3386 | strcpy(info+pos,"\n\n"); | ||
3387 | |||
3388 | return proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
3389 | } | 3423 | } |
3390 | 3424 | ||
3391 | /* Unfortunately, per device settings are not implemented through | 3425 | /* Unfortunately, per device settings are not implemented through |
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c deleted file mode 100644 index 2157c58755e0..000000000000 --- a/drivers/cdrom/cdu31a.c +++ /dev/null | |||
@@ -1,3251 +0,0 @@ | |||
1 | /* | ||
2 | * Sony CDU-31A CDROM interface device driver. | ||
3 | * | ||
4 | * Corey Minyard (minyard@wf-rch.cirr.com) | ||
5 | * | ||
6 | * Colossians 3:17 | ||
7 | * | ||
8 | * See Documentation/cdrom/cdu31a for additional details about this driver. | ||
9 | * | ||
10 | * The Sony interface device driver handles Sony interface CDROM | ||
11 | * drives and provides a complete block-level interface as well as an | ||
12 | * ioctl() interface compatible with the Sun (as specified in | ||
13 | * include/linux/cdrom.h). With this interface, CDROMs can be | ||
14 | * accessed and standard audio CDs can be played back normally. | ||
15 | * | ||
16 | * WARNING - All autoprobes have been removed from the driver. | ||
17 | * You MUST configure the CDU31A via a LILO config | ||
18 | * at boot time or in lilo.conf. I have the | ||
19 | * following in my lilo.conf: | ||
20 | * | ||
21 | * append="cdu31a=0x1f88,0,PAS" | ||
22 | * | ||
23 | * The first number is the I/O base address of the | ||
24 | * card. The second is the interrupt (0 means none). | ||
25 | * The third should be "PAS" if on a Pro-Audio | ||
26 | * spectrum, or nothing if on something else. | ||
27 | * | ||
28 | * This interface is (unfortunately) a polled interface. This is | ||
29 | * because most Sony interfaces are set up with DMA and interrupts | ||
30 | * disables. Some (like mine) do not even have the capability to | ||
31 | * handle interrupts or DMA. For this reason you will see a lot of | ||
32 | * the following: | ||
33 | * | ||
34 | * retry_count = jiffies+ SONY_JIFFIES_TIMEOUT; | ||
35 | * while (time_before(jiffies, retry_count) && (! <some condition to wait for)) | ||
36 | * { | ||
37 | * while (handle_sony_cd_attention()) | ||
38 | * ; | ||
39 | * | ||
40 | * sony_sleep(); | ||
41 | * } | ||
42 | * if (the condition not met) | ||
43 | * { | ||
44 | * return an error; | ||
45 | * } | ||
46 | * | ||
47 | * This ugly hack waits for something to happen, sleeping a little | ||
48 | * between every try. it also handles attentions, which are | ||
49 | * asynchronous events from the drive informing the driver that a disk | ||
50 | * has been inserted, removed, etc. | ||
51 | * | ||
52 | * NEWS FLASH - The driver now supports interrupts but they are | ||
53 | * turned off by default. Use of interrupts is highly encouraged, it | ||
54 | * cuts CPU usage down to a reasonable level. I had DMA in for a while | ||
55 | * but PC DMA is just too slow. Better to just insb() it. | ||
56 | * | ||
57 | * One thing about these drives: They talk in MSF (Minute Second Frame) format. | ||
58 | * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a | ||
59 | * disk. The funny thing is that these are sent to the drive in BCD, but the | ||
60 | * interface wants to see them in decimal. A lot of conversion goes on. | ||
61 | * | ||
62 | * DRIVER SPECIAL FEATURES | ||
63 | * ----------------------- | ||
64 | * | ||
65 | * This section describes features beyond the normal audio and CD-ROM | ||
66 | * functions of the drive. | ||
67 | * | ||
68 | * XA compatibility | ||
69 | * | ||
70 | * The driver should support XA disks for both the CDU31A and CDU33A. | ||
71 | * It does this transparently, the using program doesn't need to set it. | ||
72 | * | ||
73 | * Multi-Session | ||
74 | * | ||
75 | * A multi-session disk looks just like a normal disk to the user. | ||
76 | * Just mount one normally, and all the data should be there. | ||
77 | * A special thanks to Koen for help with this! | ||
78 | * | ||
79 | * Raw sector I/O | ||
80 | * | ||
81 | * Using the CDROMREADAUDIO it is possible to read raw audio and data | ||
82 | * tracks. Both operations return 2352 bytes per sector. On the data | ||
83 | * tracks, the first 12 bytes is not returned by the drive and the value | ||
84 | * of that data is indeterminate. | ||
85 | * | ||
86 | * | ||
87 | * Copyright (C) 1993 Corey Minyard | ||
88 | * | ||
89 | * This program is free software; you can redistribute it and/or modify | ||
90 | * it under the terms of the GNU General Public License as published by | ||
91 | * the Free Software Foundation; either version 2 of the License, or | ||
92 | * (at your option) any later version. | ||
93 | * | ||
94 | * This program is distributed in the hope that it will be useful, | ||
95 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
96 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
97 | * GNU General Public License for more details. | ||
98 | * | ||
99 | * You should have received a copy of the GNU General Public License | ||
100 | * along with this program; if not, write to the Free Software | ||
101 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
102 | * | ||
103 | * TODO: | ||
104 | * CDs with form1 and form2 sectors cause problems | ||
105 | * with current read-ahead strategy. | ||
106 | * | ||
107 | * Credits: | ||
108 | * Heiko Eissfeldt <heiko@colossus.escape.de> | ||
109 | * For finding abug in the return of the track numbers. | ||
110 | * TOC processing redone for proper multisession support. | ||
111 | * | ||
112 | * | ||
113 | * It probably a little late to be adding a history, but I guess I | ||
114 | * will start. | ||
115 | * | ||
116 | * 10/24/95 - Added support for disabling the eject button when the | ||
117 | * drive is open. Note that there is a small problem | ||
118 | * still here, if the eject button is pushed while the | ||
119 | * drive light is flashing, the drive will return a bad | ||
120 | * status and be reset. It recovers, though. | ||
121 | * | ||
122 | * 03/07/97 - Fixed a problem with timers. | ||
123 | * | ||
124 | * | ||
125 | * 18 Spetember 1997 -- Ported to Uniform CD-ROM driver by | ||
126 | * Heiko Eissfeldt <heiko@colossus.escape.de> with additional | ||
127 | * changes by Erik Andersen <andersee@debian.org> | ||
128 | * | ||
129 | * 24 January 1998 -- Removed the scd_disc_status() function, which was now | ||
130 | * just dead code left over from the port. | ||
131 | * Erik Andersen <andersee@debian.org> | ||
132 | * | ||
133 | * 16 July 1998 -- Drive donated to Erik Andersen by John Kodis | ||
134 | * <kodis@jagunet.com>. Work begun on fixing driver to | ||
135 | * work under 2.1.X. Added temporary extra printks | ||
136 | * which seem to slow it down enough to work. | ||
137 | * | ||
138 | * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
139 | * Removed init_module & cleanup_module in favor of | ||
140 | * module_init & module_exit. | ||
141 | * Torben Mathiasen <tmm@image.dk> | ||
142 | * | ||
143 | * 22 October 2004 -- Make the driver work in 2.6.X | ||
144 | * Added workaround to fix hard lockups on eject | ||
145 | * Fixed door locking problem after mounting empty drive | ||
146 | * Set double-speed drives to double speed by default | ||
147 | * Removed all readahead things - not needed anymore | ||
148 | * Ondrej Zary <rainbow@rainbow-software.org> | ||
149 | */ | ||
150 | |||
151 | #define DEBUG 1 | ||
152 | |||
153 | #include <linux/major.h> | ||
154 | #include <linux/module.h> | ||
155 | #include <linux/errno.h> | ||
156 | #include <linux/signal.h> | ||
157 | #include <linux/sched.h> | ||
158 | #include <linux/timer.h> | ||
159 | #include <linux/fs.h> | ||
160 | #include <linux/kernel.h> | ||
161 | #include <linux/hdreg.h> | ||
162 | #include <linux/genhd.h> | ||
163 | #include <linux/ioport.h> | ||
164 | #include <linux/string.h> | ||
165 | #include <linux/slab.h> | ||
166 | #include <linux/init.h> | ||
167 | #include <linux/interrupt.h> | ||
168 | #include <linux/cdrom.h> | ||
169 | |||
170 | #include <asm/system.h> | ||
171 | #include <asm/io.h> | ||
172 | #include <asm/uaccess.h> | ||
173 | #include <asm/dma.h> | ||
174 | |||
175 | #include "cdu31a.h" | ||
176 | |||
177 | #define MAJOR_NR CDU31A_CDROM_MAJOR | ||
178 | #include <linux/blkdev.h> | ||
179 | |||
180 | #define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10 | ||
181 | |||
182 | #define PFX "CDU31A: " | ||
183 | |||
184 | /* | ||
185 | ** Edit the following data to change interrupts, DMA channels, etc. | ||
186 | ** Default is polled and no DMA. DMA is not recommended for double-speed | ||
187 | ** drives. | ||
188 | */ | ||
189 | static struct { | ||
190 | unsigned short base; /* I/O Base Address */ | ||
191 | short int_num; /* Interrupt Number (-1 means scan for it, | ||
192 | 0 means don't use) */ | ||
193 | } cdu31a_addresses[] __initdata = { | ||
194 | {0} | ||
195 | }; | ||
196 | |||
197 | static int handle_sony_cd_attention(void); | ||
198 | static int read_subcode(void); | ||
199 | static void sony_get_toc(void); | ||
200 | static int scd_spinup(void); | ||
201 | /*static int scd_open(struct inode *inode, struct file *filp);*/ | ||
202 | static int scd_open(struct cdrom_device_info *, int); | ||
203 | static void do_sony_cd_cmd(unsigned char cmd, | ||
204 | unsigned char *params, | ||
205 | unsigned int num_params, | ||
206 | unsigned char *result_buffer, | ||
207 | unsigned int *result_size); | ||
208 | static void size_to_buf(unsigned int size, unsigned char *buf); | ||
209 | |||
210 | /* Parameters for the read-ahead. */ | ||
211 | static unsigned int sony_next_block; /* Next 512 byte block offset */ | ||
212 | static unsigned int sony_blocks_left = 0; /* Number of 512 byte blocks left | ||
213 | in the current read command. */ | ||
214 | |||
215 | |||
216 | /* The base I/O address of the Sony Interface. This is a variable (not a | ||
217 | #define) so it can be easily changed via some future ioctl() */ | ||
218 | static unsigned int cdu31a_port = 0; | ||
219 | module_param(cdu31a_port, uint, 0); | ||
220 | |||
221 | /* | ||
222 | * The following are I/O addresses of the various registers for the drive. The | ||
223 | * comment for the base address also applies here. | ||
224 | */ | ||
225 | static volatile unsigned short sony_cd_cmd_reg; | ||
226 | static volatile unsigned short sony_cd_param_reg; | ||
227 | static volatile unsigned short sony_cd_write_reg; | ||
228 | static volatile unsigned short sony_cd_control_reg; | ||
229 | static volatile unsigned short sony_cd_status_reg; | ||
230 | static volatile unsigned short sony_cd_result_reg; | ||
231 | static volatile unsigned short sony_cd_read_reg; | ||
232 | static volatile unsigned short sony_cd_fifost_reg; | ||
233 | |||
234 | static struct request_queue *cdu31a_queue; | ||
235 | static DEFINE_SPINLOCK(cdu31a_lock); /* queue lock */ | ||
236 | |||
237 | static int sony_spun_up = 0; /* Has the drive been spun up? */ | ||
238 | |||
239 | static int sony_speed = 0; /* Last wanted speed */ | ||
240 | |||
241 | static int sony_xa_mode = 0; /* Is an XA disk in the drive | ||
242 | and the drive a CDU31A? */ | ||
243 | |||
244 | static int sony_raw_data_mode = 1; /* 1 if data tracks, 0 if audio. | ||
245 | For raw data reads. */ | ||
246 | |||
247 | static unsigned int sony_usage = 0; /* How many processes have the | ||
248 | drive open. */ | ||
249 | |||
250 | static int sony_pas_init = 0; /* Initialize the Pro-Audio | ||
251 | Spectrum card? */ | ||
252 | |||
253 | static struct s_sony_session_toc single_toc; /* Holds the | ||
254 | table of | ||
255 | contents. */ | ||
256 | |||
257 | static struct s_all_sessions_toc sony_toc; /* entries gathered from all | ||
258 | sessions */ | ||
259 | |||
260 | static int sony_toc_read = 0; /* Has the TOC been read for | ||
261 | the drive? */ | ||
262 | |||
263 | static struct s_sony_subcode last_sony_subcode; /* Points to the last | ||
264 | subcode address read */ | ||
265 | |||
266 | static DECLARE_MUTEX(sony_sem); /* Semaphore for drive hardware access */ | ||
267 | |||
268 | static int is_double_speed = 0; /* does the drive support double speed ? */ | ||
269 | |||
270 | static int is_auto_eject = 1; /* Door has been locked? 1=No/0=Yes */ | ||
271 | |||
272 | /* | ||
273 | * The audio status uses the values from read subchannel data as specified | ||
274 | * in include/linux/cdrom.h. | ||
275 | */ | ||
276 | static volatile int sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
277 | |||
278 | /* | ||
279 | * The following are a hack for pausing and resuming audio play. The drive | ||
280 | * does not work as I would expect it, if you stop it then start it again, | ||
281 | * the drive seeks back to the beginning and starts over. This holds the | ||
282 | * position during a pause so a resume can restart it. It uses the | ||
283 | * audio status variable above to tell if it is paused. | ||
284 | */ | ||
285 | static unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 }; | ||
286 | static unsigned volatile char final_pos_msf[3] = { 0, 0, 0 }; | ||
287 | |||
288 | /* What IRQ is the drive using? 0 if none. */ | ||
289 | static int cdu31a_irq = 0; | ||
290 | module_param(cdu31a_irq, int, 0); | ||
291 | |||
292 | /* The interrupt handler will wake this queue up when it gets an | ||
293 | interrupts. */ | ||
294 | static DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait); | ||
295 | static int irq_flag = 0; | ||
296 | |||
297 | static int curr_control_reg = 0; /* Current value of the control register */ | ||
298 | |||
299 | /* A disk changed variable. When a disk change is detected, it will | ||
300 | all be set to TRUE. As the upper layers ask for disk_changed status | ||
301 | it will be cleared. */ | ||
302 | static char disk_changed; | ||
303 | |||
304 | /* This was readahead_buffer once... Now it's used only for audio reads */ | ||
305 | static char audio_buffer[CD_FRAMESIZE_RAW]; | ||
306 | |||
307 | /* Used to time a short period to abort an operation after the | ||
308 | drive has been idle for a while. This keeps the light on | ||
309 | the drive from flashing for very long. */ | ||
310 | static struct timer_list cdu31a_abort_timer; | ||
311 | |||
312 | /* Marks if the timeout has started an abort read. This is used | ||
313 | on entry to the drive to tell the code to read out the status | ||
314 | from the abort read. */ | ||
315 | static int abort_read_started = 0; | ||
316 | |||
317 | /* | ||
318 | * Uniform cdrom interface function | ||
319 | * report back, if disc has changed from time of last request. | ||
320 | */ | ||
321 | static int scd_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
322 | { | ||
323 | int retval; | ||
324 | |||
325 | retval = disk_changed; | ||
326 | disk_changed = 0; | ||
327 | |||
328 | return retval; | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Uniform cdrom interface function | ||
333 | * report back, if drive is ready | ||
334 | */ | ||
335 | static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr) | ||
336 | { | ||
337 | if (CDSL_CURRENT != slot_nr) | ||
338 | /* we have no changer support */ | ||
339 | return -EINVAL; | ||
340 | if (sony_spun_up) | ||
341 | return CDS_DISC_OK; | ||
342 | if (down_interruptible(&sony_sem)) | ||
343 | return -ERESTARTSYS; | ||
344 | if (scd_spinup() == 0) | ||
345 | sony_spun_up = 1; | ||
346 | up(&sony_sem); | ||
347 | return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY; | ||
348 | } | ||
349 | |||
350 | static inline void enable_interrupts(void) | ||
351 | { | ||
352 | curr_control_reg |= (SONY_ATTN_INT_EN_BIT | ||
353 | | SONY_RES_RDY_INT_EN_BIT | ||
354 | | SONY_DATA_RDY_INT_EN_BIT); | ||
355 | outb(curr_control_reg, sony_cd_control_reg); | ||
356 | } | ||
357 | |||
358 | static inline void disable_interrupts(void) | ||
359 | { | ||
360 | curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT | ||
361 | | SONY_RES_RDY_INT_EN_BIT | ||
362 | | SONY_DATA_RDY_INT_EN_BIT); | ||
363 | outb(curr_control_reg, sony_cd_control_reg); | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * Wait a little while (used for polling the drive). If in initialization, | ||
368 | * setting a timeout doesn't work, so just loop for a while. | ||
369 | */ | ||
370 | static inline void sony_sleep(void) | ||
371 | { | ||
372 | if (cdu31a_irq <= 0) { | ||
373 | yield(); | ||
374 | } else { /* Interrupt driven */ | ||
375 | DEFINE_WAIT(w); | ||
376 | int first = 1; | ||
377 | |||
378 | while (1) { | ||
379 | prepare_to_wait(&cdu31a_irq_wait, &w, | ||
380 | TASK_INTERRUPTIBLE); | ||
381 | if (first) { | ||
382 | enable_interrupts(); | ||
383 | first = 0; | ||
384 | } | ||
385 | |||
386 | if (irq_flag != 0) | ||
387 | break; | ||
388 | if (!signal_pending(current)) { | ||
389 | schedule(); | ||
390 | continue; | ||
391 | } else | ||
392 | disable_interrupts(); | ||
393 | break; | ||
394 | } | ||
395 | finish_wait(&cdu31a_irq_wait, &w); | ||
396 | irq_flag = 0; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | |||
401 | /* | ||
402 | * The following are convenience routine to read various status and set | ||
403 | * various conditions in the drive. | ||
404 | */ | ||
405 | static inline int is_attention(void) | ||
406 | { | ||
407 | return (inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0; | ||
408 | } | ||
409 | |||
410 | static inline int is_busy(void) | ||
411 | { | ||
412 | return (inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0; | ||
413 | } | ||
414 | |||
415 | static inline int is_data_ready(void) | ||
416 | { | ||
417 | return (inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0; | ||
418 | } | ||
419 | |||
420 | static inline int is_data_requested(void) | ||
421 | { | ||
422 | return (inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0; | ||
423 | } | ||
424 | |||
425 | static inline int is_result_ready(void) | ||
426 | { | ||
427 | return (inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0; | ||
428 | } | ||
429 | |||
430 | static inline int is_param_write_rdy(void) | ||
431 | { | ||
432 | return (inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0; | ||
433 | } | ||
434 | |||
435 | static inline int is_result_reg_not_empty(void) | ||
436 | { | ||
437 | return (inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0; | ||
438 | } | ||
439 | |||
440 | static inline void reset_drive(void) | ||
441 | { | ||
442 | curr_control_reg = 0; | ||
443 | sony_toc_read = 0; | ||
444 | outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg); | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * Uniform cdrom interface function | ||
449 | * reset drive and return when it is ready | ||
450 | */ | ||
451 | static int scd_reset(struct cdrom_device_info *cdi) | ||
452 | { | ||
453 | unsigned long retry_count; | ||
454 | |||
455 | if (down_interruptible(&sony_sem)) | ||
456 | return -ERESTARTSYS; | ||
457 | reset_drive(); | ||
458 | |||
459 | retry_count = jiffies + SONY_RESET_TIMEOUT; | ||
460 | while (time_before(jiffies, retry_count) && (!is_attention())) { | ||
461 | sony_sleep(); | ||
462 | } | ||
463 | |||
464 | up(&sony_sem); | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static inline void clear_attention(void) | ||
469 | { | ||
470 | outb(curr_control_reg | SONY_ATTN_CLR_BIT, sony_cd_control_reg); | ||
471 | } | ||
472 | |||
473 | static inline void clear_result_ready(void) | ||
474 | { | ||
475 | outb(curr_control_reg | SONY_RES_RDY_CLR_BIT, sony_cd_control_reg); | ||
476 | } | ||
477 | |||
478 | static inline void clear_data_ready(void) | ||
479 | { | ||
480 | outb(curr_control_reg | SONY_DATA_RDY_CLR_BIT, | ||
481 | sony_cd_control_reg); | ||
482 | } | ||
483 | |||
484 | static inline void clear_param_reg(void) | ||
485 | { | ||
486 | outb(curr_control_reg | SONY_PARAM_CLR_BIT, sony_cd_control_reg); | ||
487 | } | ||
488 | |||
489 | static inline unsigned char read_status_register(void) | ||
490 | { | ||
491 | return inb(sony_cd_status_reg); | ||
492 | } | ||
493 | |||
494 | static inline unsigned char read_result_register(void) | ||
495 | { | ||
496 | return inb(sony_cd_result_reg); | ||
497 | } | ||
498 | |||
499 | static inline unsigned char read_data_register(void) | ||
500 | { | ||
501 | return inb(sony_cd_read_reg); | ||
502 | } | ||
503 | |||
504 | static inline void write_param(unsigned char param) | ||
505 | { | ||
506 | outb(param, sony_cd_param_reg); | ||
507 | } | ||
508 | |||
509 | static inline void write_cmd(unsigned char cmd) | ||
510 | { | ||
511 | outb(curr_control_reg | SONY_RES_RDY_INT_EN_BIT, | ||
512 | sony_cd_control_reg); | ||
513 | outb(cmd, sony_cd_cmd_reg); | ||
514 | } | ||
515 | |||
516 | static irqreturn_t cdu31a_interrupt(int irq, void *dev_id) | ||
517 | { | ||
518 | unsigned char val; | ||
519 | |||
520 | if (abort_read_started) { | ||
521 | /* We might be waiting for an abort to finish. Don't | ||
522 | disable interrupts yet, though, because we handle | ||
523 | this one here. */ | ||
524 | /* Clear out the result registers. */ | ||
525 | while (is_result_reg_not_empty()) { | ||
526 | val = read_result_register(); | ||
527 | } | ||
528 | clear_data_ready(); | ||
529 | clear_result_ready(); | ||
530 | |||
531 | /* Clear out the data */ | ||
532 | while (is_data_requested()) { | ||
533 | val = read_data_register(); | ||
534 | } | ||
535 | abort_read_started = 0; | ||
536 | |||
537 | /* If something was waiting, wake it up now. */ | ||
538 | if (waitqueue_active(&cdu31a_irq_wait)) { | ||
539 | disable_interrupts(); | ||
540 | irq_flag = 1; | ||
541 | wake_up_interruptible(&cdu31a_irq_wait); | ||
542 | } | ||
543 | } else if (waitqueue_active(&cdu31a_irq_wait)) { | ||
544 | disable_interrupts(); | ||
545 | irq_flag = 1; | ||
546 | wake_up_interruptible(&cdu31a_irq_wait); | ||
547 | } else { | ||
548 | disable_interrupts(); | ||
549 | printk(KERN_NOTICE PFX | ||
550 | "Got an interrupt but nothing was waiting\n"); | ||
551 | } | ||
552 | return IRQ_HANDLED; | ||
553 | } | ||
554 | |||
555 | /* | ||
556 | * give more verbose error messages | ||
557 | */ | ||
558 | static unsigned char *translate_error(unsigned char err_code) | ||
559 | { | ||
560 | static unsigned char errbuf[80]; | ||
561 | |||
562 | switch (err_code) { | ||
563 | case 0x10: return "illegal command "; | ||
564 | case 0x11: return "illegal parameter "; | ||
565 | |||
566 | case 0x20: return "not loaded "; | ||
567 | case 0x21: return "no disc "; | ||
568 | case 0x22: return "not spinning "; | ||
569 | case 0x23: return "spinning "; | ||
570 | case 0x25: return "spindle servo "; | ||
571 | case 0x26: return "focus servo "; | ||
572 | case 0x29: return "eject mechanism "; | ||
573 | case 0x2a: return "audio playing "; | ||
574 | case 0x2c: return "emergency eject "; | ||
575 | |||
576 | case 0x30: return "focus "; | ||
577 | case 0x31: return "frame sync "; | ||
578 | case 0x32: return "subcode address "; | ||
579 | case 0x33: return "block sync "; | ||
580 | case 0x34: return "header address "; | ||
581 | |||
582 | case 0x40: return "illegal track read "; | ||
583 | case 0x41: return "mode 0 read "; | ||
584 | case 0x42: return "illegal mode read "; | ||
585 | case 0x43: return "illegal block size read "; | ||
586 | case 0x44: return "mode read "; | ||
587 | case 0x45: return "form read "; | ||
588 | case 0x46: return "leadout read "; | ||
589 | case 0x47: return "buffer overrun "; | ||
590 | |||
591 | case 0x53: return "unrecoverable CIRC "; | ||
592 | case 0x57: return "unrecoverable LECC "; | ||
593 | |||
594 | case 0x60: return "no TOC "; | ||
595 | case 0x61: return "invalid subcode data "; | ||
596 | case 0x63: return "focus on TOC read "; | ||
597 | case 0x64: return "frame sync on TOC read "; | ||
598 | case 0x65: return "TOC data "; | ||
599 | |||
600 | case 0x70: return "hardware failure "; | ||
601 | case 0x91: return "leadin "; | ||
602 | case 0x92: return "leadout "; | ||
603 | case 0x93: return "data track "; | ||
604 | } | ||
605 | sprintf(errbuf, "unknown 0x%02x ", err_code); | ||
606 | return errbuf; | ||
607 | } | ||
608 | |||
609 | /* | ||
610 | * Set the drive parameters so the drive will auto-spin-up when a | ||
611 | * disk is inserted. | ||
612 | */ | ||
613 | static void set_drive_params(int want_doublespeed) | ||
614 | { | ||
615 | unsigned char res_reg[12]; | ||
616 | unsigned int res_size; | ||
617 | unsigned char params[3]; | ||
618 | |||
619 | |||
620 | params[0] = SONY_SD_AUTO_SPIN_DOWN_TIME; | ||
621 | params[1] = 0x00; /* Never spin down the drive. */ | ||
622 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
623 | params, 2, res_reg, &res_size); | ||
624 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
625 | printk(KERN_NOTICE PFX | ||
626 | "Unable to set spin-down time: 0x%2.2x\n", res_reg[1]); | ||
627 | } | ||
628 | |||
629 | params[0] = SONY_SD_MECH_CONTROL; | ||
630 | params[1] = SONY_AUTO_SPIN_UP_BIT; /* Set auto spin up */ | ||
631 | |||
632 | if (is_auto_eject) | ||
633 | params[1] |= SONY_AUTO_EJECT_BIT; | ||
634 | |||
635 | if (is_double_speed && want_doublespeed) { | ||
636 | params[1] |= SONY_DOUBLE_SPEED_BIT; /* Set the drive to double speed if | ||
637 | possible */ | ||
638 | } | ||
639 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
640 | params, 2, res_reg, &res_size); | ||
641 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
642 | printk(KERN_NOTICE PFX "Unable to set mechanical " | ||
643 | "parameters: 0x%2.2x\n", res_reg[1]); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | /* | ||
648 | * Uniform cdrom interface function | ||
649 | * select reading speed for data access | ||
650 | */ | ||
651 | static int scd_select_speed(struct cdrom_device_info *cdi, int speed) | ||
652 | { | ||
653 | if (speed == 0) | ||
654 | sony_speed = 1; | ||
655 | else | ||
656 | sony_speed = speed - 1; | ||
657 | |||
658 | if (down_interruptible(&sony_sem)) | ||
659 | return -ERESTARTSYS; | ||
660 | set_drive_params(sony_speed); | ||
661 | up(&sony_sem); | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | /* | ||
666 | * Uniform cdrom interface function | ||
667 | * lock or unlock eject button | ||
668 | */ | ||
669 | static int scd_lock_door(struct cdrom_device_info *cdi, int lock) | ||
670 | { | ||
671 | if (lock == 0) { | ||
672 | is_auto_eject = 1; | ||
673 | } else { | ||
674 | is_auto_eject = 0; | ||
675 | } | ||
676 | if (down_interruptible(&sony_sem)) | ||
677 | return -ERESTARTSYS; | ||
678 | set_drive_params(sony_speed); | ||
679 | up(&sony_sem); | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * This code will reset the drive and attempt to restore sane parameters. | ||
685 | */ | ||
686 | static void restart_on_error(void) | ||
687 | { | ||
688 | unsigned char res_reg[12]; | ||
689 | unsigned int res_size; | ||
690 | unsigned long retry_count; | ||
691 | |||
692 | |||
693 | printk(KERN_NOTICE PFX "Resetting drive on error\n"); | ||
694 | reset_drive(); | ||
695 | retry_count = jiffies + SONY_RESET_TIMEOUT; | ||
696 | while (time_before(jiffies, retry_count) && (!is_attention())) { | ||
697 | sony_sleep(); | ||
698 | } | ||
699 | set_drive_params(sony_speed); | ||
700 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); | ||
701 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
702 | printk(KERN_NOTICE PFX "Unable to spin up drive: 0x%2.2x\n", | ||
703 | res_reg[1]); | ||
704 | } | ||
705 | |||
706 | msleep(2000); | ||
707 | |||
708 | sony_get_toc(); | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | * This routine writes data to the parameter register. Since this should | ||
713 | * happen fairly fast, it is polled with no OS waits between. | ||
714 | */ | ||
715 | static int write_params(unsigned char *params, int num_params) | ||
716 | { | ||
717 | unsigned int retry_count; | ||
718 | |||
719 | |||
720 | retry_count = SONY_READY_RETRIES; | ||
721 | while ((retry_count > 0) && (!is_param_write_rdy())) { | ||
722 | retry_count--; | ||
723 | } | ||
724 | if (!is_param_write_rdy()) { | ||
725 | return -EIO; | ||
726 | } | ||
727 | |||
728 | while (num_params > 0) { | ||
729 | write_param(*params); | ||
730 | params++; | ||
731 | num_params--; | ||
732 | } | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | |||
738 | /* | ||
739 | * The following reads data from the command result register. It is a | ||
740 | * fairly complex routine, all status info flows back through this | ||
741 | * interface. The algorithm is stolen directly from the flowcharts in | ||
742 | * the drive manual. | ||
743 | */ | ||
744 | static void | ||
745 | get_result(unsigned char *result_buffer, unsigned int *result_size) | ||
746 | { | ||
747 | unsigned char a, b; | ||
748 | int i; | ||
749 | unsigned long retry_count; | ||
750 | |||
751 | |||
752 | while (handle_sony_cd_attention()); | ||
753 | /* Wait for the result data to be ready */ | ||
754 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
755 | while (time_before(jiffies, retry_count) | ||
756 | && (is_busy() || (!(is_result_ready())))) { | ||
757 | sony_sleep(); | ||
758 | |||
759 | while (handle_sony_cd_attention()); | ||
760 | } | ||
761 | if (is_busy() || (!(is_result_ready()))) { | ||
762 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
763 | result_buffer[0] = 0x20; | ||
764 | result_buffer[1] = SONY_TIMEOUT_OP_ERR; | ||
765 | *result_size = 2; | ||
766 | return; | ||
767 | } | ||
768 | |||
769 | /* | ||
770 | * Get the first two bytes. This determines what else needs | ||
771 | * to be done. | ||
772 | */ | ||
773 | clear_result_ready(); | ||
774 | a = read_result_register(); | ||
775 | *result_buffer = a; | ||
776 | result_buffer++; | ||
777 | |||
778 | /* Check for block error status result. */ | ||
779 | if ((a & 0xf0) == 0x50) { | ||
780 | *result_size = 1; | ||
781 | return; | ||
782 | } | ||
783 | |||
784 | b = read_result_register(); | ||
785 | *result_buffer = b; | ||
786 | result_buffer++; | ||
787 | *result_size = 2; | ||
788 | |||
789 | /* | ||
790 | * 0x20 means an error occurred. Byte 2 will have the error code. | ||
791 | * Otherwise, the command succeeded, byte 2 will have the count of | ||
792 | * how many more status bytes are coming. | ||
793 | * | ||
794 | * The result register can be read 10 bytes at a time, a wait for | ||
795 | * result ready to be asserted must be done between every 10 bytes. | ||
796 | */ | ||
797 | if ((a & 0xf0) != 0x20) { | ||
798 | if (b > 8) { | ||
799 | for (i = 0; i < 8; i++) { | ||
800 | *result_buffer = read_result_register(); | ||
801 | result_buffer++; | ||
802 | (*result_size)++; | ||
803 | } | ||
804 | b = b - 8; | ||
805 | |||
806 | while (b > 10) { | ||
807 | retry_count = SONY_READY_RETRIES; | ||
808 | while ((retry_count > 0) | ||
809 | && (!is_result_ready())) { | ||
810 | retry_count--; | ||
811 | } | ||
812 | if (!is_result_ready()) { | ||
813 | pr_debug(PFX "timeout out %d\n", | ||
814 | __LINE__); | ||
815 | result_buffer[0] = 0x20; | ||
816 | result_buffer[1] = | ||
817 | SONY_TIMEOUT_OP_ERR; | ||
818 | *result_size = 2; | ||
819 | return; | ||
820 | } | ||
821 | |||
822 | clear_result_ready(); | ||
823 | |||
824 | for (i = 0; i < 10; i++) { | ||
825 | *result_buffer = | ||
826 | read_result_register(); | ||
827 | result_buffer++; | ||
828 | (*result_size)++; | ||
829 | } | ||
830 | b = b - 10; | ||
831 | } | ||
832 | |||
833 | if (b > 0) { | ||
834 | retry_count = SONY_READY_RETRIES; | ||
835 | while ((retry_count > 0) | ||
836 | && (!is_result_ready())) { | ||
837 | retry_count--; | ||
838 | } | ||
839 | if (!is_result_ready()) { | ||
840 | pr_debug(PFX "timeout out %d\n", | ||
841 | __LINE__); | ||
842 | result_buffer[0] = 0x20; | ||
843 | result_buffer[1] = | ||
844 | SONY_TIMEOUT_OP_ERR; | ||
845 | *result_size = 2; | ||
846 | return; | ||
847 | } | ||
848 | } | ||
849 | } | ||
850 | |||
851 | while (b > 0) { | ||
852 | *result_buffer = read_result_register(); | ||
853 | result_buffer++; | ||
854 | (*result_size)++; | ||
855 | b--; | ||
856 | } | ||
857 | } | ||
858 | } | ||
859 | |||
860 | /* | ||
861 | * Do a command that does not involve data transfer. This routine must | ||
862 | * be re-entrant from the same task to support being called from the | ||
863 | * data operation code when an error occurs. | ||
864 | */ | ||
865 | static void | ||
866 | do_sony_cd_cmd(unsigned char cmd, | ||
867 | unsigned char *params, | ||
868 | unsigned int num_params, | ||
869 | unsigned char *result_buffer, unsigned int *result_size) | ||
870 | { | ||
871 | unsigned long retry_count; | ||
872 | int num_retries = 0; | ||
873 | |||
874 | retry_cd_operation: | ||
875 | |||
876 | while (handle_sony_cd_attention()); | ||
877 | |||
878 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
879 | while (time_before(jiffies, retry_count) && (is_busy())) { | ||
880 | sony_sleep(); | ||
881 | |||
882 | while (handle_sony_cd_attention()); | ||
883 | } | ||
884 | if (is_busy()) { | ||
885 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
886 | result_buffer[0] = 0x20; | ||
887 | result_buffer[1] = SONY_TIMEOUT_OP_ERR; | ||
888 | *result_size = 2; | ||
889 | } else { | ||
890 | clear_result_ready(); | ||
891 | clear_param_reg(); | ||
892 | |||
893 | write_params(params, num_params); | ||
894 | write_cmd(cmd); | ||
895 | |||
896 | get_result(result_buffer, result_size); | ||
897 | } | ||
898 | |||
899 | if (((result_buffer[0] & 0xf0) == 0x20) | ||
900 | && (num_retries < MAX_CDU31A_RETRIES)) { | ||
901 | num_retries++; | ||
902 | msleep(100); | ||
903 | goto retry_cd_operation; | ||
904 | } | ||
905 | } | ||
906 | |||
907 | |||
908 | /* | ||
909 | * Handle an attention from the drive. This will return 1 if it found one | ||
910 | * or 0 if not (if one is found, the caller might want to call again). | ||
911 | * | ||
912 | * This routine counts the number of consecutive times it is called | ||
913 | * (since this is always called from a while loop until it returns | ||
914 | * a 0), and returns a 0 if it happens too many times. This will help | ||
915 | * prevent a lockup. | ||
916 | */ | ||
917 | static int handle_sony_cd_attention(void) | ||
918 | { | ||
919 | unsigned char atten_code; | ||
920 | static int num_consecutive_attentions = 0; | ||
921 | volatile int val; | ||
922 | |||
923 | |||
924 | #if 0 | ||
925 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
926 | #endif | ||
927 | if (is_attention()) { | ||
928 | if (num_consecutive_attentions > | ||
929 | CDU31A_MAX_CONSECUTIVE_ATTENTIONS) { | ||
930 | printk(KERN_NOTICE PFX "Too many consecutive " | ||
931 | "attentions: %d\n", num_consecutive_attentions); | ||
932 | num_consecutive_attentions = 0; | ||
933 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, | ||
934 | __LINE__); | ||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | clear_attention(); | ||
939 | atten_code = read_result_register(); | ||
940 | |||
941 | switch (atten_code) { | ||
942 | /* Someone changed the CD. Mark it as changed */ | ||
943 | case SONY_MECH_LOADED_ATTN: | ||
944 | disk_changed = 1; | ||
945 | sony_toc_read = 0; | ||
946 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
947 | sony_blocks_left = 0; | ||
948 | break; | ||
949 | |||
950 | case SONY_SPIN_DOWN_COMPLETE_ATTN: | ||
951 | /* Mark the disk as spun down. */ | ||
952 | sony_spun_up = 0; | ||
953 | break; | ||
954 | |||
955 | case SONY_AUDIO_PLAY_DONE_ATTN: | ||
956 | sony_audio_status = CDROM_AUDIO_COMPLETED; | ||
957 | read_subcode(); | ||
958 | break; | ||
959 | |||
960 | case SONY_EJECT_PUSHED_ATTN: | ||
961 | if (is_auto_eject) { | ||
962 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
963 | } | ||
964 | break; | ||
965 | |||
966 | case SONY_LEAD_IN_ERR_ATTN: | ||
967 | case SONY_LEAD_OUT_ERR_ATTN: | ||
968 | case SONY_DATA_TRACK_ERR_ATTN: | ||
969 | case SONY_AUDIO_PLAYBACK_ERR_ATTN: | ||
970 | sony_audio_status = CDROM_AUDIO_ERROR; | ||
971 | break; | ||
972 | } | ||
973 | |||
974 | num_consecutive_attentions++; | ||
975 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
976 | return 1; | ||
977 | } else if (abort_read_started) { | ||
978 | while (is_result_reg_not_empty()) { | ||
979 | val = read_result_register(); | ||
980 | } | ||
981 | clear_data_ready(); | ||
982 | clear_result_ready(); | ||
983 | /* Clear out the data */ | ||
984 | while (is_data_requested()) { | ||
985 | val = read_data_register(); | ||
986 | } | ||
987 | abort_read_started = 0; | ||
988 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
989 | return 1; | ||
990 | } | ||
991 | |||
992 | num_consecutive_attentions = 0; | ||
993 | #if 0 | ||
994 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
995 | #endif | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | |||
1000 | /* Convert from an integer 0-99 to BCD */ | ||
1001 | static inline unsigned int int_to_bcd(unsigned int val) | ||
1002 | { | ||
1003 | int retval; | ||
1004 | |||
1005 | |||
1006 | retval = (val / 10) << 4; | ||
1007 | retval = retval | val % 10; | ||
1008 | return retval; | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | /* Convert from BCD to an integer from 0-99 */ | ||
1013 | static unsigned int bcd_to_int(unsigned int bcd) | ||
1014 | { | ||
1015 | return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); | ||
1016 | } | ||
1017 | |||
1018 | |||
1019 | /* | ||
1020 | * Convert a logical sector value (like the OS would want to use for | ||
1021 | * a block device) to an MSF format. | ||
1022 | */ | ||
1023 | static void log_to_msf(unsigned int log, unsigned char *msf) | ||
1024 | { | ||
1025 | log = log + LOG_START_OFFSET; | ||
1026 | msf[0] = int_to_bcd(log / 4500); | ||
1027 | log = log % 4500; | ||
1028 | msf[1] = int_to_bcd(log / 75); | ||
1029 | msf[2] = int_to_bcd(log % 75); | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | /* | ||
1034 | * Convert an MSF format to a logical sector. | ||
1035 | */ | ||
1036 | static unsigned int msf_to_log(unsigned char *msf) | ||
1037 | { | ||
1038 | unsigned int log; | ||
1039 | |||
1040 | |||
1041 | log = msf[2]; | ||
1042 | log += msf[1] * 75; | ||
1043 | log += msf[0] * 4500; | ||
1044 | log = log - LOG_START_OFFSET; | ||
1045 | |||
1046 | return log; | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | /* | ||
1051 | * Take in integer size value and put it into a buffer like | ||
1052 | * the drive would want to see a number-of-sector value. | ||
1053 | */ | ||
1054 | static void size_to_buf(unsigned int size, unsigned char *buf) | ||
1055 | { | ||
1056 | buf[0] = size / 65536; | ||
1057 | size = size % 65536; | ||
1058 | buf[1] = size / 256; | ||
1059 | buf[2] = size % 256; | ||
1060 | } | ||
1061 | |||
1062 | /* Starts a read operation. Returns 0 on success and 1 on failure. | ||
1063 | The read operation used here allows multiple sequential sectors | ||
1064 | to be read and status returned for each sector. The driver will | ||
1065 | read the output one at a time as the requests come and abort the | ||
1066 | operation if the requested sector is not the next one from the | ||
1067 | drive. */ | ||
1068 | static int | ||
1069 | start_request(unsigned int sector, unsigned int nsect) | ||
1070 | { | ||
1071 | unsigned char params[6]; | ||
1072 | unsigned long retry_count; | ||
1073 | |||
1074 | |||
1075 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1076 | log_to_msf(sector, params); | ||
1077 | size_to_buf(nsect, ¶ms[3]); | ||
1078 | |||
1079 | /* | ||
1080 | * Clear any outstanding attentions and wait for the drive to | ||
1081 | * complete any pending operations. | ||
1082 | */ | ||
1083 | while (handle_sony_cd_attention()); | ||
1084 | |||
1085 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
1086 | while (time_before(jiffies, retry_count) && (is_busy())) { | ||
1087 | sony_sleep(); | ||
1088 | |||
1089 | while (handle_sony_cd_attention()); | ||
1090 | } | ||
1091 | |||
1092 | if (is_busy()) { | ||
1093 | printk(KERN_NOTICE PFX "Timeout while waiting " | ||
1094 | "to issue command\n"); | ||
1095 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1096 | return 1; | ||
1097 | } else { | ||
1098 | /* Issue the command */ | ||
1099 | clear_result_ready(); | ||
1100 | clear_param_reg(); | ||
1101 | |||
1102 | write_params(params, 6); | ||
1103 | write_cmd(SONY_READ_BLKERR_STAT_CMD); | ||
1104 | |||
1105 | sony_blocks_left = nsect * 4; | ||
1106 | sony_next_block = sector * 4; | ||
1107 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1108 | return 0; | ||
1109 | } | ||
1110 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1111 | } | ||
1112 | |||
1113 | /* Abort a pending read operation. Clear all the drive status variables. */ | ||
1114 | static void abort_read(void) | ||
1115 | { | ||
1116 | unsigned char result_reg[2]; | ||
1117 | int result_size; | ||
1118 | volatile int val; | ||
1119 | |||
1120 | |||
1121 | do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size); | ||
1122 | if ((result_reg[0] & 0xf0) == 0x20) { | ||
1123 | printk(KERN_ERR PFX "Aborting read, %s error\n", | ||
1124 | translate_error(result_reg[1])); | ||
1125 | } | ||
1126 | |||
1127 | while (is_result_reg_not_empty()) { | ||
1128 | val = read_result_register(); | ||
1129 | } | ||
1130 | clear_data_ready(); | ||
1131 | clear_result_ready(); | ||
1132 | /* Clear out the data */ | ||
1133 | while (is_data_requested()) { | ||
1134 | val = read_data_register(); | ||
1135 | } | ||
1136 | |||
1137 | sony_blocks_left = 0; | ||
1138 | } | ||
1139 | |||
1140 | /* Called when the timer times out. This will abort the | ||
1141 | pending read operation. */ | ||
1142 | static void handle_abort_timeout(unsigned long data) | ||
1143 | { | ||
1144 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1145 | /* If it is in use, ignore it. */ | ||
1146 | if (down_trylock(&sony_sem) == 0) { | ||
1147 | /* We can't use abort_read(), because it will sleep | ||
1148 | or schedule in the timer interrupt. Just start | ||
1149 | the operation, finish it on the next access to | ||
1150 | the drive. */ | ||
1151 | clear_result_ready(); | ||
1152 | clear_param_reg(); | ||
1153 | write_cmd(SONY_ABORT_CMD); | ||
1154 | |||
1155 | sony_blocks_left = 0; | ||
1156 | abort_read_started = 1; | ||
1157 | up(&sony_sem); | ||
1158 | } | ||
1159 | pr_debug(PFX "Leaving %s\n", __FUNCTION__); | ||
1160 | } | ||
1161 | |||
1162 | /* Actually get one sector of data from the drive. */ | ||
1163 | static void | ||
1164 | input_data_sector(char *buffer) | ||
1165 | { | ||
1166 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1167 | |||
1168 | /* If an XA disk on a CDU31A, skip the first 12 bytes of data from | ||
1169 | the disk. The real data is after that. We can use audio_buffer. */ | ||
1170 | if (sony_xa_mode) | ||
1171 | insb(sony_cd_read_reg, audio_buffer, CD_XA_HEAD); | ||
1172 | |||
1173 | clear_data_ready(); | ||
1174 | |||
1175 | insb(sony_cd_read_reg, buffer, 2048); | ||
1176 | |||
1177 | /* If an XA disk, we have to clear out the rest of the unused | ||
1178 | error correction data. We can use audio_buffer for that. */ | ||
1179 | if (sony_xa_mode) | ||
1180 | insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL); | ||
1181 | |||
1182 | pr_debug(PFX "Leaving %s\n", __FUNCTION__); | ||
1183 | } | ||
1184 | |||
1185 | /* read data from the drive. Note the nsect must be <= 4. */ | ||
1186 | static void | ||
1187 | read_data_block(char *buffer, | ||
1188 | unsigned int block, | ||
1189 | unsigned int nblocks, | ||
1190 | unsigned char res_reg[], int *res_size) | ||
1191 | { | ||
1192 | unsigned long retry_count; | ||
1193 | |||
1194 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1195 | |||
1196 | res_reg[0] = 0; | ||
1197 | res_reg[1] = 0; | ||
1198 | *res_size = 0; | ||
1199 | |||
1200 | /* Wait for the drive to tell us we have something */ | ||
1201 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
1202 | while (time_before(jiffies, retry_count) && !(is_data_ready())) { | ||
1203 | while (handle_sony_cd_attention()); | ||
1204 | |||
1205 | sony_sleep(); | ||
1206 | } | ||
1207 | if (!(is_data_ready())) { | ||
1208 | if (is_result_ready()) { | ||
1209 | get_result(res_reg, res_size); | ||
1210 | if ((res_reg[0] & 0xf0) != 0x20) { | ||
1211 | printk(KERN_NOTICE PFX "Got result that should" | ||
1212 | " have been error: %d\n", res_reg[0]); | ||
1213 | res_reg[0] = 0x20; | ||
1214 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
1215 | *res_size = 2; | ||
1216 | } | ||
1217 | abort_read(); | ||
1218 | } else { | ||
1219 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
1220 | res_reg[0] = 0x20; | ||
1221 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
1222 | *res_size = 2; | ||
1223 | abort_read(); | ||
1224 | } | ||
1225 | } else { | ||
1226 | input_data_sector(buffer); | ||
1227 | sony_blocks_left -= nblocks; | ||
1228 | sony_next_block += nblocks; | ||
1229 | |||
1230 | /* Wait for the status from the drive. */ | ||
1231 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
1232 | while (time_before(jiffies, retry_count) | ||
1233 | && !(is_result_ready())) { | ||
1234 | while (handle_sony_cd_attention()); | ||
1235 | |||
1236 | sony_sleep(); | ||
1237 | } | ||
1238 | |||
1239 | if (!is_result_ready()) { | ||
1240 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
1241 | res_reg[0] = 0x20; | ||
1242 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
1243 | *res_size = 2; | ||
1244 | abort_read(); | ||
1245 | } else { | ||
1246 | get_result(res_reg, res_size); | ||
1247 | |||
1248 | /* If we got a buffer status, handle that. */ | ||
1249 | if ((res_reg[0] & 0xf0) == 0x50) { | ||
1250 | |||
1251 | if ((res_reg[0] == | ||
1252 | SONY_NO_CIRC_ERR_BLK_STAT) | ||
1253 | || (res_reg[0] == | ||
1254 | SONY_NO_LECC_ERR_BLK_STAT) | ||
1255 | || (res_reg[0] == | ||
1256 | SONY_RECOV_LECC_ERR_BLK_STAT)) { | ||
1257 | /* nothing here */ | ||
1258 | } else { | ||
1259 | printk(KERN_ERR PFX "Data block " | ||
1260 | "error: 0x%x\n", res_reg[0]); | ||
1261 | res_reg[0] = 0x20; | ||
1262 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
1263 | *res_size = 2; | ||
1264 | } | ||
1265 | |||
1266 | /* Final transfer is done for read command, get final result. */ | ||
1267 | if (sony_blocks_left == 0) { | ||
1268 | get_result(res_reg, res_size); | ||
1269 | } | ||
1270 | } else if ((res_reg[0] & 0xf0) != 0x20) { | ||
1271 | /* The drive gave me bad status, I don't know what to do. | ||
1272 | Reset the driver and return an error. */ | ||
1273 | printk(KERN_ERR PFX "Invalid block " | ||
1274 | "status: 0x%x\n", res_reg[0]); | ||
1275 | restart_on_error(); | ||
1276 | res_reg[0] = 0x20; | ||
1277 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
1278 | *res_size = 2; | ||
1279 | } | ||
1280 | } | ||
1281 | } | ||
1282 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1283 | } | ||
1284 | |||
1285 | |||
1286 | /* | ||
1287 | * The OS calls this to perform a read or write operation to the drive. | ||
1288 | * Write obviously fail. Reads to a read ahead of sony_buffer_size | ||
1289 | * bytes to help speed operations. This especially helps since the OS | ||
1290 | * uses 1024 byte blocks and the drive uses 2048 byte blocks. Since most | ||
1291 | * data access on a CD is done sequentially, this saves a lot of operations. | ||
1292 | */ | ||
1293 | static void do_cdu31a_request(request_queue_t * q) | ||
1294 | { | ||
1295 | struct request *req; | ||
1296 | int block, nblock, num_retries; | ||
1297 | unsigned char res_reg[12]; | ||
1298 | unsigned int res_size; | ||
1299 | |||
1300 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1301 | |||
1302 | spin_unlock_irq(q->queue_lock); | ||
1303 | if (down_interruptible(&sony_sem)) { | ||
1304 | spin_lock_irq(q->queue_lock); | ||
1305 | return; | ||
1306 | } | ||
1307 | |||
1308 | /* Get drive status before doing anything. */ | ||
1309 | while (handle_sony_cd_attention()); | ||
1310 | |||
1311 | /* Make sure we have a valid TOC. */ | ||
1312 | sony_get_toc(); | ||
1313 | |||
1314 | |||
1315 | /* Make sure the timer is cancelled. */ | ||
1316 | del_timer(&cdu31a_abort_timer); | ||
1317 | |||
1318 | while (1) { | ||
1319 | /* | ||
1320 | * The beginning here is stolen from the hard disk driver. I hope | ||
1321 | * it's right. | ||
1322 | */ | ||
1323 | req = elv_next_request(q); | ||
1324 | if (!req) | ||
1325 | goto end_do_cdu31a_request; | ||
1326 | |||
1327 | if (!sony_spun_up) | ||
1328 | scd_spinup(); | ||
1329 | |||
1330 | block = req->sector; | ||
1331 | nblock = req->nr_sectors; | ||
1332 | pr_debug(PFX "request at block %d, length %d blocks\n", | ||
1333 | block, nblock); | ||
1334 | if (!sony_toc_read) { | ||
1335 | printk(KERN_NOTICE PFX "TOC not read\n"); | ||
1336 | end_request(req, 0); | ||
1337 | continue; | ||
1338 | } | ||
1339 | |||
1340 | /* WTF??? */ | ||
1341 | if (!blk_fs_request(req)) { | ||
1342 | end_request(req, 0); | ||
1343 | continue; | ||
1344 | } | ||
1345 | if (rq_data_dir(req) == WRITE) { | ||
1346 | end_request(req, 0); | ||
1347 | continue; | ||
1348 | } | ||
1349 | |||
1350 | /* | ||
1351 | * If the block address is invalid or the request goes beyond the end of | ||
1352 | * the media, return an error. | ||
1353 | */ | ||
1354 | if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) { | ||
1355 | printk(KERN_NOTICE PFX "Request past end of media\n"); | ||
1356 | end_request(req, 0); | ||
1357 | continue; | ||
1358 | } | ||
1359 | |||
1360 | if (nblock > 4) | ||
1361 | nblock = 4; | ||
1362 | num_retries = 0; | ||
1363 | |||
1364 | try_read_again: | ||
1365 | while (handle_sony_cd_attention()); | ||
1366 | |||
1367 | if (!sony_toc_read) { | ||
1368 | printk(KERN_NOTICE PFX "TOC not read\n"); | ||
1369 | end_request(req, 0); | ||
1370 | continue; | ||
1371 | } | ||
1372 | |||
1373 | /* If no data is left to be read from the drive, start the | ||
1374 | next request. */ | ||
1375 | if (sony_blocks_left == 0) { | ||
1376 | if (start_request(block / 4, nblock / 4)) { | ||
1377 | end_request(req, 0); | ||
1378 | continue; | ||
1379 | } | ||
1380 | } | ||
1381 | /* If the requested block is not the next one waiting in | ||
1382 | the driver, abort the current operation and start a | ||
1383 | new one. */ | ||
1384 | else if (block != sony_next_block) { | ||
1385 | pr_debug(PFX "Read for block %d, expected %d\n", | ||
1386 | block, sony_next_block); | ||
1387 | abort_read(); | ||
1388 | if (!sony_toc_read) { | ||
1389 | printk(KERN_NOTICE PFX "TOC not read\n"); | ||
1390 | end_request(req, 0); | ||
1391 | continue; | ||
1392 | } | ||
1393 | if (start_request(block / 4, nblock / 4)) { | ||
1394 | printk(KERN_NOTICE PFX "start request failed\n"); | ||
1395 | end_request(req, 0); | ||
1396 | continue; | ||
1397 | } | ||
1398 | } | ||
1399 | |||
1400 | read_data_block(req->buffer, block, nblock, res_reg, &res_size); | ||
1401 | |||
1402 | if (res_reg[0] != 0x20) { | ||
1403 | if (!end_that_request_first(req, 1, nblock)) { | ||
1404 | spin_lock_irq(q->queue_lock); | ||
1405 | blkdev_dequeue_request(req); | ||
1406 | end_that_request_last(req, 1); | ||
1407 | spin_unlock_irq(q->queue_lock); | ||
1408 | } | ||
1409 | continue; | ||
1410 | } | ||
1411 | |||
1412 | if (num_retries > MAX_CDU31A_RETRIES) { | ||
1413 | end_request(req, 0); | ||
1414 | continue; | ||
1415 | } | ||
1416 | |||
1417 | num_retries++; | ||
1418 | if (res_reg[1] == SONY_NOT_SPIN_ERR) { | ||
1419 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
1420 | &res_size); | ||
1421 | } else { | ||
1422 | printk(KERN_NOTICE PFX "%s error for block %d, nblock %d\n", | ||
1423 | translate_error(res_reg[1]), block, nblock); | ||
1424 | } | ||
1425 | goto try_read_again; | ||
1426 | } | ||
1427 | end_do_cdu31a_request: | ||
1428 | #if 0 | ||
1429 | /* After finished, cancel any pending operations. */ | ||
1430 | abort_read(); | ||
1431 | #else | ||
1432 | /* Start a timer to time out after a while to disable | ||
1433 | the read. */ | ||
1434 | cdu31a_abort_timer.expires = jiffies + 2 * HZ; /* Wait 2 seconds */ | ||
1435 | add_timer(&cdu31a_abort_timer); | ||
1436 | #endif | ||
1437 | |||
1438 | up(&sony_sem); | ||
1439 | spin_lock_irq(q->queue_lock); | ||
1440 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1441 | } | ||
1442 | |||
1443 | |||
1444 | /* | ||
1445 | * Read the table of contents from the drive and set up TOC if | ||
1446 | * successful. | ||
1447 | */ | ||
1448 | static void sony_get_toc(void) | ||
1449 | { | ||
1450 | unsigned char res_reg[2]; | ||
1451 | unsigned int res_size; | ||
1452 | unsigned char parms[1]; | ||
1453 | int session; | ||
1454 | int num_spin_ups; | ||
1455 | int totaltracks = 0; | ||
1456 | int mint = 99; | ||
1457 | int maxt = 0; | ||
1458 | |||
1459 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1460 | |||
1461 | num_spin_ups = 0; | ||
1462 | if (!sony_toc_read) { | ||
1463 | respinup_on_gettoc: | ||
1464 | /* Ignore the result, since it might error if spinning already. */ | ||
1465 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
1466 | &res_size); | ||
1467 | |||
1468 | do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, | ||
1469 | &res_size); | ||
1470 | |||
1471 | /* The drive sometimes returns error 0. I don't know why, but ignore | ||
1472 | it. It seems to mean the drive has already done the operation. */ | ||
1473 | if ((res_size < 2) | ||
1474 | || ((res_reg[0] != 0) && (res_reg[1] != 0))) { | ||
1475 | /* If the drive is already playing, it's ok. */ | ||
1476 | if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) | ||
1477 | || (res_reg[1] == 0)) { | ||
1478 | goto gettoc_drive_spinning; | ||
1479 | } | ||
1480 | |||
1481 | /* If the drive says it is not spun up (even though we just did it!) | ||
1482 | then retry the operation at least a few times. */ | ||
1483 | if ((res_reg[1] == SONY_NOT_SPIN_ERR) | ||
1484 | && (num_spin_ups < MAX_CDU31A_RETRIES)) { | ||
1485 | num_spin_ups++; | ||
1486 | goto respinup_on_gettoc; | ||
1487 | } | ||
1488 | |||
1489 | printk("cdu31a: Error reading TOC: %x %s\n", | ||
1490 | res_reg[0], translate_error(res_reg[1])); | ||
1491 | return; | ||
1492 | } | ||
1493 | |||
1494 | gettoc_drive_spinning: | ||
1495 | |||
1496 | /* The idea here is we keep asking for sessions until the command | ||
1497 | fails. Then we know what the last valid session on the disk is. | ||
1498 | No need to check session 0, since session 0 is the same as session | ||
1499 | 1; the command returns different information if you give it 0. | ||
1500 | */ | ||
1501 | #if DEBUG | ||
1502 | memset(&sony_toc, 0x0e, sizeof(sony_toc)); | ||
1503 | memset(&single_toc, 0x0f, sizeof(single_toc)); | ||
1504 | #endif | ||
1505 | session = 1; | ||
1506 | while (1) { | ||
1507 | /* This seems to slow things down enough to make it work. This | ||
1508 | * appears to be a problem in do_sony_cd_cmd. This printk seems | ||
1509 | * to address the symptoms... -Erik */ | ||
1510 | pr_debug(PFX "Trying session %d\n", session); | ||
1511 | parms[0] = session; | ||
1512 | do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD, | ||
1513 | parms, 1, res_reg, &res_size); | ||
1514 | |||
1515 | pr_debug(PFX "%2.2x %2.2x\n", res_reg[0], res_reg[1]); | ||
1516 | |||
1517 | if ((res_size < 2) | ||
1518 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
1519 | /* An error reading the TOC, this must be past the last session. */ | ||
1520 | if (session == 1) | ||
1521 | printk | ||
1522 | ("Yikes! Couldn't read any sessions!"); | ||
1523 | break; | ||
1524 | } | ||
1525 | pr_debug(PFX "Reading session %d\n", session); | ||
1526 | |||
1527 | parms[0] = session; | ||
1528 | do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD, | ||
1529 | parms, | ||
1530 | 1, | ||
1531 | (unsigned char *) &single_toc, | ||
1532 | &res_size); | ||
1533 | if ((res_size < 2) | ||
1534 | || ((single_toc.exec_status[0] & 0xf0) == | ||
1535 | 0x20)) { | ||
1536 | printk(KERN_ERR PFX "Error reading " | ||
1537 | "session %d: %x %s\n", | ||
1538 | session, single_toc.exec_status[0], | ||
1539 | translate_error(single_toc. | ||
1540 | exec_status[1])); | ||
1541 | /* An error reading the TOC. Return without sony_toc_read | ||
1542 | set. */ | ||
1543 | return; | ||
1544 | } | ||
1545 | pr_debug(PFX "add0 %01x, con0 %01x, poi0 %02x, " | ||
1546 | "1st trk %d, dsktyp %x, dum0 %x\n", | ||
1547 | single_toc.address0, single_toc.control0, | ||
1548 | single_toc.point0, | ||
1549 | bcd_to_int(single_toc.first_track_num), | ||
1550 | single_toc.disk_type, single_toc.dummy0); | ||
1551 | pr_debug(PFX "add1 %01x, con1 %01x, poi1 %02x, " | ||
1552 | "lst trk %d, dummy1 %x, dum2 %x\n", | ||
1553 | single_toc.address1, single_toc.control1, | ||
1554 | single_toc.point1, | ||
1555 | bcd_to_int(single_toc.last_track_num), | ||
1556 | single_toc.dummy1, single_toc.dummy2); | ||
1557 | pr_debug(PFX "add2 %01x, con2 %01x, poi2 %02x " | ||
1558 | "leadout start min %d, sec %d, frame %d\n", | ||
1559 | single_toc.address2, single_toc.control2, | ||
1560 | single_toc.point2, | ||
1561 | bcd_to_int(single_toc.lead_out_start_msf[0]), | ||
1562 | bcd_to_int(single_toc.lead_out_start_msf[1]), | ||
1563 | bcd_to_int(single_toc.lead_out_start_msf[2])); | ||
1564 | if (res_size > 18 && single_toc.pointb0 > 0xaf) | ||
1565 | pr_debug(PFX "addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n" | ||
1566 | "#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n", | ||
1567 | single_toc.addressb0, | ||
1568 | single_toc.controlb0, | ||
1569 | single_toc.pointb0, | ||
1570 | bcd_to_int(single_toc. | ||
1571 | next_poss_prog_area_msf | ||
1572 | [0]), | ||
1573 | bcd_to_int(single_toc. | ||
1574 | next_poss_prog_area_msf | ||
1575 | [1]), | ||
1576 | bcd_to_int(single_toc. | ||
1577 | next_poss_prog_area_msf | ||
1578 | [2]), | ||
1579 | single_toc.num_mode_5_pointers, | ||
1580 | bcd_to_int(single_toc. | ||
1581 | max_start_outer_leadout_msf | ||
1582 | [0]), | ||
1583 | bcd_to_int(single_toc. | ||
1584 | max_start_outer_leadout_msf | ||
1585 | [1]), | ||
1586 | bcd_to_int(single_toc. | ||
1587 | max_start_outer_leadout_msf | ||
1588 | [2])); | ||
1589 | if (res_size > 27 && single_toc.pointb1 > 0xaf) | ||
1590 | pr_debug(PFX "addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n", | ||
1591 | single_toc.addressb1, | ||
1592 | single_toc.controlb1, | ||
1593 | single_toc.pointb1, | ||
1594 | single_toc.dummyb0_1[0], | ||
1595 | single_toc.dummyb0_1[1], | ||
1596 | single_toc.dummyb0_1[2], | ||
1597 | single_toc.dummyb0_1[3], | ||
1598 | single_toc.num_skip_interval_pointers, | ||
1599 | single_toc.num_skip_track_assignments, | ||
1600 | single_toc.dummyb0_2); | ||
1601 | if (res_size > 36 && single_toc.pointb2 > 0xaf) | ||
1602 | pr_debug(PFX "addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1603 | single_toc.addressb2, | ||
1604 | single_toc.controlb2, | ||
1605 | single_toc.pointb2, | ||
1606 | single_toc.tracksb2[0], | ||
1607 | single_toc.tracksb2[1], | ||
1608 | single_toc.tracksb2[2], | ||
1609 | single_toc.tracksb2[3], | ||
1610 | single_toc.tracksb2[4], | ||
1611 | single_toc.tracksb2[5], | ||
1612 | single_toc.tracksb2[6]); | ||
1613 | if (res_size > 45 && single_toc.pointb3 > 0xaf) | ||
1614 | pr_debug(PFX "addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1615 | single_toc.addressb3, | ||
1616 | single_toc.controlb3, | ||
1617 | single_toc.pointb3, | ||
1618 | single_toc.tracksb3[0], | ||
1619 | single_toc.tracksb3[1], | ||
1620 | single_toc.tracksb3[2], | ||
1621 | single_toc.tracksb3[3], | ||
1622 | single_toc.tracksb3[4], | ||
1623 | single_toc.tracksb3[5], | ||
1624 | single_toc.tracksb3[6]); | ||
1625 | if (res_size > 54 && single_toc.pointb4 > 0xaf) | ||
1626 | pr_debug(PFX "addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1627 | single_toc.addressb4, | ||
1628 | single_toc.controlb4, | ||
1629 | single_toc.pointb4, | ||
1630 | single_toc.tracksb4[0], | ||
1631 | single_toc.tracksb4[1], | ||
1632 | single_toc.tracksb4[2], | ||
1633 | single_toc.tracksb4[3], | ||
1634 | single_toc.tracksb4[4], | ||
1635 | single_toc.tracksb4[5], | ||
1636 | single_toc.tracksb4[6]); | ||
1637 | if (res_size > 63 && single_toc.pointc0 > 0xaf) | ||
1638 | pr_debug(PFX "addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1639 | single_toc.addressc0, | ||
1640 | single_toc.controlc0, | ||
1641 | single_toc.pointc0, | ||
1642 | single_toc.dummyc0[0], | ||
1643 | single_toc.dummyc0[1], | ||
1644 | single_toc.dummyc0[2], | ||
1645 | single_toc.dummyc0[3], | ||
1646 | single_toc.dummyc0[4], | ||
1647 | single_toc.dummyc0[5], | ||
1648 | single_toc.dummyc0[6]); | ||
1649 | #undef DEBUG | ||
1650 | #define DEBUG 0 | ||
1651 | |||
1652 | sony_toc.lead_out_start_msf[0] = | ||
1653 | bcd_to_int(single_toc.lead_out_start_msf[0]); | ||
1654 | sony_toc.lead_out_start_msf[1] = | ||
1655 | bcd_to_int(single_toc.lead_out_start_msf[1]); | ||
1656 | sony_toc.lead_out_start_msf[2] = | ||
1657 | bcd_to_int(single_toc.lead_out_start_msf[2]); | ||
1658 | sony_toc.lead_out_start_lba = | ||
1659 | single_toc.lead_out_start_lba = | ||
1660 | msf_to_log(sony_toc.lead_out_start_msf); | ||
1661 | |||
1662 | /* For points that do not exist, move the data over them | ||
1663 | to the right location. */ | ||
1664 | if (single_toc.pointb0 != 0xb0) { | ||
1665 | memmove(((char *) &single_toc) + 27, | ||
1666 | ((char *) &single_toc) + 18, | ||
1667 | res_size - 18); | ||
1668 | res_size += 9; | ||
1669 | } else if (res_size > 18) { | ||
1670 | sony_toc.lead_out_start_msf[0] = | ||
1671 | bcd_to_int(single_toc. | ||
1672 | max_start_outer_leadout_msf | ||
1673 | [0]); | ||
1674 | sony_toc.lead_out_start_msf[1] = | ||
1675 | bcd_to_int(single_toc. | ||
1676 | max_start_outer_leadout_msf | ||
1677 | [1]); | ||
1678 | sony_toc.lead_out_start_msf[2] = | ||
1679 | bcd_to_int(single_toc. | ||
1680 | max_start_outer_leadout_msf | ||
1681 | [2]); | ||
1682 | sony_toc.lead_out_start_lba = | ||
1683 | msf_to_log(sony_toc. | ||
1684 | lead_out_start_msf); | ||
1685 | } | ||
1686 | if (single_toc.pointb1 != 0xb1) { | ||
1687 | memmove(((char *) &single_toc) + 36, | ||
1688 | ((char *) &single_toc) + 27, | ||
1689 | res_size - 27); | ||
1690 | res_size += 9; | ||
1691 | } | ||
1692 | if (single_toc.pointb2 != 0xb2) { | ||
1693 | memmove(((char *) &single_toc) + 45, | ||
1694 | ((char *) &single_toc) + 36, | ||
1695 | res_size - 36); | ||
1696 | res_size += 9; | ||
1697 | } | ||
1698 | if (single_toc.pointb3 != 0xb3) { | ||
1699 | memmove(((char *) &single_toc) + 54, | ||
1700 | ((char *) &single_toc) + 45, | ||
1701 | res_size - 45); | ||
1702 | res_size += 9; | ||
1703 | } | ||
1704 | if (single_toc.pointb4 != 0xb4) { | ||
1705 | memmove(((char *) &single_toc) + 63, | ||
1706 | ((char *) &single_toc) + 54, | ||
1707 | res_size - 54); | ||
1708 | res_size += 9; | ||
1709 | } | ||
1710 | if (single_toc.pointc0 != 0xc0) { | ||
1711 | memmove(((char *) &single_toc) + 72, | ||
1712 | ((char *) &single_toc) + 63, | ||
1713 | res_size - 63); | ||
1714 | res_size += 9; | ||
1715 | } | ||
1716 | #if DEBUG | ||
1717 | printk(PRINT_INFO PFX "start track lba %u, " | ||
1718 | "leadout start lba %u\n", | ||
1719 | single_toc.start_track_lba, | ||
1720 | single_toc.lead_out_start_lba); | ||
1721 | { | ||
1722 | int i; | ||
1723 | for (i = 0; | ||
1724 | i < | ||
1725 | 1 + | ||
1726 | bcd_to_int(single_toc.last_track_num) | ||
1727 | - | ||
1728 | bcd_to_int(single_toc. | ||
1729 | first_track_num); i++) { | ||
1730 | printk(KERN_INFO PFX "trk %02d: add 0x%01x, con 0x%01x, track %02d, start min %02d, sec %02d, frame %02d\n", | ||
1731 | i, | ||
1732 | single_toc.tracks[i].address, | ||
1733 | single_toc.tracks[i].control, | ||
1734 | bcd_to_int(single_toc. | ||
1735 | tracks[i].track), | ||
1736 | bcd_to_int(single_toc. | ||
1737 | tracks[i]. | ||
1738 | track_start_msf | ||
1739 | [0]), | ||
1740 | bcd_to_int(single_toc. | ||
1741 | tracks[i]. | ||
1742 | track_start_msf | ||
1743 | [1]), | ||
1744 | bcd_to_int(single_toc. | ||
1745 | tracks[i]. | ||
1746 | track_start_msf | ||
1747 | [2])); | ||
1748 | if (mint > | ||
1749 | bcd_to_int(single_toc. | ||
1750 | tracks[i].track)) | ||
1751 | mint = | ||
1752 | bcd_to_int(single_toc. | ||
1753 | tracks[i]. | ||
1754 | track); | ||
1755 | if (maxt < | ||
1756 | bcd_to_int(single_toc. | ||
1757 | tracks[i].track)) | ||
1758 | maxt = | ||
1759 | bcd_to_int(single_toc. | ||
1760 | tracks[i]. | ||
1761 | track); | ||
1762 | } | ||
1763 | printk(KERN_INFO PFX "min track number %d, " | ||
1764 | "max track number %d\n", | ||
1765 | mint, maxt); | ||
1766 | } | ||
1767 | #endif | ||
1768 | |||
1769 | /* prepare a special table of contents for a CD-I disc. They don't have one. */ | ||
1770 | if (single_toc.disk_type == 0x10 && | ||
1771 | single_toc.first_track_num == 2 && | ||
1772 | single_toc.last_track_num == 2 /* CD-I */ ) { | ||
1773 | sony_toc.tracks[totaltracks].address = 1; | ||
1774 | sony_toc.tracks[totaltracks].control = 4; /* force data tracks */ | ||
1775 | sony_toc.tracks[totaltracks].track = 1; | ||
1776 | sony_toc.tracks[totaltracks]. | ||
1777 | track_start_msf[0] = 0; | ||
1778 | sony_toc.tracks[totaltracks]. | ||
1779 | track_start_msf[1] = 2; | ||
1780 | sony_toc.tracks[totaltracks]. | ||
1781 | track_start_msf[2] = 0; | ||
1782 | mint = maxt = 1; | ||
1783 | totaltracks++; | ||
1784 | } else | ||
1785 | /* gather track entries from this session */ | ||
1786 | { | ||
1787 | int i; | ||
1788 | for (i = 0; | ||
1789 | i < | ||
1790 | 1 + | ||
1791 | bcd_to_int(single_toc.last_track_num) | ||
1792 | - | ||
1793 | bcd_to_int(single_toc. | ||
1794 | first_track_num); | ||
1795 | i++, totaltracks++) { | ||
1796 | sony_toc.tracks[totaltracks]. | ||
1797 | address = | ||
1798 | single_toc.tracks[i].address; | ||
1799 | sony_toc.tracks[totaltracks]. | ||
1800 | control = | ||
1801 | single_toc.tracks[i].control; | ||
1802 | sony_toc.tracks[totaltracks]. | ||
1803 | track = | ||
1804 | bcd_to_int(single_toc. | ||
1805 | tracks[i].track); | ||
1806 | sony_toc.tracks[totaltracks]. | ||
1807 | track_start_msf[0] = | ||
1808 | bcd_to_int(single_toc. | ||
1809 | tracks[i]. | ||
1810 | track_start_msf[0]); | ||
1811 | sony_toc.tracks[totaltracks]. | ||
1812 | track_start_msf[1] = | ||
1813 | bcd_to_int(single_toc. | ||
1814 | tracks[i]. | ||
1815 | track_start_msf[1]); | ||
1816 | sony_toc.tracks[totaltracks]. | ||
1817 | track_start_msf[2] = | ||
1818 | bcd_to_int(single_toc. | ||
1819 | tracks[i]. | ||
1820 | track_start_msf[2]); | ||
1821 | if (i == 0) | ||
1822 | single_toc. | ||
1823 | start_track_lba = | ||
1824 | msf_to_log(sony_toc. | ||
1825 | tracks | ||
1826 | [totaltracks]. | ||
1827 | track_start_msf); | ||
1828 | if (mint > | ||
1829 | sony_toc.tracks[totaltracks]. | ||
1830 | track) | ||
1831 | mint = | ||
1832 | sony_toc. | ||
1833 | tracks[totaltracks]. | ||
1834 | track; | ||
1835 | if (maxt < | ||
1836 | sony_toc.tracks[totaltracks]. | ||
1837 | track) | ||
1838 | maxt = | ||
1839 | sony_toc. | ||
1840 | tracks[totaltracks]. | ||
1841 | track; | ||
1842 | } | ||
1843 | } | ||
1844 | sony_toc.first_track_num = mint; | ||
1845 | sony_toc.last_track_num = maxt; | ||
1846 | /* Disk type of last session wins. For example: | ||
1847 | CD-Extra has disk type 0 for the first session, so | ||
1848 | a dumb HiFi CD player thinks it is a plain audio CD. | ||
1849 | We are interested in the disk type of the last session, | ||
1850 | which is 0x20 (XA) for CD-Extra, so we can access the | ||
1851 | data track ... */ | ||
1852 | sony_toc.disk_type = single_toc.disk_type; | ||
1853 | sony_toc.sessions = session; | ||
1854 | |||
1855 | /* don't believe everything :-) */ | ||
1856 | if (session == 1) | ||
1857 | single_toc.start_track_lba = 0; | ||
1858 | sony_toc.start_track_lba = | ||
1859 | single_toc.start_track_lba; | ||
1860 | |||
1861 | if (session > 1 && single_toc.pointb0 == 0xb0 && | ||
1862 | sony_toc.lead_out_start_lba == | ||
1863 | single_toc.lead_out_start_lba) { | ||
1864 | break; | ||
1865 | } | ||
1866 | |||
1867 | /* Let's not get carried away... */ | ||
1868 | if (session > 40) { | ||
1869 | printk(KERN_NOTICE PFX "too many sessions: " | ||
1870 | "%d\n", session); | ||
1871 | break; | ||
1872 | } | ||
1873 | session++; | ||
1874 | } | ||
1875 | sony_toc.track_entries = totaltracks; | ||
1876 | /* add one entry for the LAST track with track number CDROM_LEADOUT */ | ||
1877 | sony_toc.tracks[totaltracks].address = single_toc.address2; | ||
1878 | sony_toc.tracks[totaltracks].control = single_toc.control2; | ||
1879 | sony_toc.tracks[totaltracks].track = CDROM_LEADOUT; | ||
1880 | sony_toc.tracks[totaltracks].track_start_msf[0] = | ||
1881 | sony_toc.lead_out_start_msf[0]; | ||
1882 | sony_toc.tracks[totaltracks].track_start_msf[1] = | ||
1883 | sony_toc.lead_out_start_msf[1]; | ||
1884 | sony_toc.tracks[totaltracks].track_start_msf[2] = | ||
1885 | sony_toc.lead_out_start_msf[2]; | ||
1886 | |||
1887 | sony_toc_read = 1; | ||
1888 | |||
1889 | pr_debug(PFX "Disk session %d, start track: %d, " | ||
1890 | "stop track: %d\n", | ||
1891 | session, single_toc.start_track_lba, | ||
1892 | single_toc.lead_out_start_lba); | ||
1893 | } | ||
1894 | pr_debug(PFX "Leaving %s\n", __FUNCTION__); | ||
1895 | } | ||
1896 | |||
1897 | |||
1898 | /* | ||
1899 | * Uniform cdrom interface function | ||
1900 | * return multisession offset and sector information | ||
1901 | */ | ||
1902 | static int scd_get_last_session(struct cdrom_device_info *cdi, | ||
1903 | struct cdrom_multisession *ms_info) | ||
1904 | { | ||
1905 | if (ms_info == NULL) | ||
1906 | return 1; | ||
1907 | |||
1908 | if (!sony_toc_read) { | ||
1909 | if (down_interruptible(&sony_sem)) | ||
1910 | return -ERESTARTSYS; | ||
1911 | sony_get_toc(); | ||
1912 | up(&sony_sem); | ||
1913 | } | ||
1914 | |||
1915 | ms_info->addr_format = CDROM_LBA; | ||
1916 | ms_info->addr.lba = sony_toc.start_track_lba; | ||
1917 | ms_info->xa_flag = sony_toc.disk_type == SONY_XA_DISK_TYPE || | ||
1918 | sony_toc.disk_type == 0x10 /* CDI */ ; | ||
1919 | |||
1920 | return 0; | ||
1921 | } | ||
1922 | |||
1923 | /* | ||
1924 | * Search for a specific track in the table of contents. | ||
1925 | */ | ||
1926 | static int find_track(int track) | ||
1927 | { | ||
1928 | int i; | ||
1929 | |||
1930 | for (i = 0; i <= sony_toc.track_entries; i++) { | ||
1931 | if (sony_toc.tracks[i].track == track) { | ||
1932 | return i; | ||
1933 | } | ||
1934 | } | ||
1935 | |||
1936 | return -1; | ||
1937 | } | ||
1938 | |||
1939 | |||
1940 | /* | ||
1941 | * Read the subcode and put it in last_sony_subcode for future use. | ||
1942 | */ | ||
1943 | static int read_subcode(void) | ||
1944 | { | ||
1945 | unsigned int res_size; | ||
1946 | |||
1947 | |||
1948 | do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD, | ||
1949 | NULL, | ||
1950 | 0, (unsigned char *) &last_sony_subcode, &res_size); | ||
1951 | if ((res_size < 2) | ||
1952 | || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20)) { | ||
1953 | printk(KERN_ERR PFX "Sony CDROM error %s (read_subcode)\n", | ||
1954 | translate_error(last_sony_subcode.exec_status[1])); | ||
1955 | return -EIO; | ||
1956 | } | ||
1957 | |||
1958 | last_sony_subcode.track_num = | ||
1959 | bcd_to_int(last_sony_subcode.track_num); | ||
1960 | last_sony_subcode.index_num = | ||
1961 | bcd_to_int(last_sony_subcode.index_num); | ||
1962 | last_sony_subcode.abs_msf[0] = | ||
1963 | bcd_to_int(last_sony_subcode.abs_msf[0]); | ||
1964 | last_sony_subcode.abs_msf[1] = | ||
1965 | bcd_to_int(last_sony_subcode.abs_msf[1]); | ||
1966 | last_sony_subcode.abs_msf[2] = | ||
1967 | bcd_to_int(last_sony_subcode.abs_msf[2]); | ||
1968 | |||
1969 | last_sony_subcode.rel_msf[0] = | ||
1970 | bcd_to_int(last_sony_subcode.rel_msf[0]); | ||
1971 | last_sony_subcode.rel_msf[1] = | ||
1972 | bcd_to_int(last_sony_subcode.rel_msf[1]); | ||
1973 | last_sony_subcode.rel_msf[2] = | ||
1974 | bcd_to_int(last_sony_subcode.rel_msf[2]); | ||
1975 | return 0; | ||
1976 | } | ||
1977 | |||
1978 | /* | ||
1979 | * Uniform cdrom interface function | ||
1980 | * return the media catalog number found on some older audio cds | ||
1981 | */ | ||
1982 | static int | ||
1983 | scd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) | ||
1984 | { | ||
1985 | unsigned char resbuffer[2 + 14]; | ||
1986 | unsigned char *mcnp = mcn->medium_catalog_number; | ||
1987 | unsigned char *resp = resbuffer + 3; | ||
1988 | unsigned int res_size; | ||
1989 | |||
1990 | memset(mcn->medium_catalog_number, 0, 14); | ||
1991 | if (down_interruptible(&sony_sem)) | ||
1992 | return -ERESTARTSYS; | ||
1993 | do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD, | ||
1994 | NULL, 0, resbuffer, &res_size); | ||
1995 | up(&sony_sem); | ||
1996 | if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20)); | ||
1997 | else { | ||
1998 | /* packed bcd to single ASCII digits */ | ||
1999 | *mcnp++ = (*resp >> 4) + '0'; | ||
2000 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2001 | *mcnp++ = (*resp >> 4) + '0'; | ||
2002 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2003 | *mcnp++ = (*resp >> 4) + '0'; | ||
2004 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2005 | *mcnp++ = (*resp >> 4) + '0'; | ||
2006 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2007 | *mcnp++ = (*resp >> 4) + '0'; | ||
2008 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2009 | *mcnp++ = (*resp >> 4) + '0'; | ||
2010 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2011 | *mcnp++ = (*resp >> 4) + '0'; | ||
2012 | } | ||
2013 | *mcnp = '\0'; | ||
2014 | return 0; | ||
2015 | } | ||
2016 | |||
2017 | |||
2018 | /* | ||
2019 | * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If | ||
2020 | * the drive is playing, the subchannel needs to be read (since it would be | ||
2021 | * changing). If the drive is paused or completed, the subcode information has | ||
2022 | * already been stored, just use that. The ioctl call wants things in decimal | ||
2023 | * (not BCD), so all the conversions are done. | ||
2024 | */ | ||
2025 | static int sony_get_subchnl_info(struct cdrom_subchnl *schi) | ||
2026 | { | ||
2027 | /* Get attention stuff */ | ||
2028 | while (handle_sony_cd_attention()); | ||
2029 | |||
2030 | sony_get_toc(); | ||
2031 | if (!sony_toc_read) { | ||
2032 | return -EIO; | ||
2033 | } | ||
2034 | |||
2035 | switch (sony_audio_status) { | ||
2036 | case CDROM_AUDIO_NO_STATUS: | ||
2037 | case CDROM_AUDIO_PLAY: | ||
2038 | if (read_subcode() < 0) { | ||
2039 | return -EIO; | ||
2040 | } | ||
2041 | break; | ||
2042 | |||
2043 | case CDROM_AUDIO_PAUSED: | ||
2044 | case CDROM_AUDIO_COMPLETED: | ||
2045 | break; | ||
2046 | |||
2047 | #if 0 | ||
2048 | case CDROM_AUDIO_NO_STATUS: | ||
2049 | schi->cdsc_audiostatus = sony_audio_status; | ||
2050 | return 0; | ||
2051 | break; | ||
2052 | #endif | ||
2053 | case CDROM_AUDIO_INVALID: | ||
2054 | case CDROM_AUDIO_ERROR: | ||
2055 | default: | ||
2056 | return -EIO; | ||
2057 | } | ||
2058 | |||
2059 | schi->cdsc_audiostatus = sony_audio_status; | ||
2060 | schi->cdsc_adr = last_sony_subcode.address; | ||
2061 | schi->cdsc_ctrl = last_sony_subcode.control; | ||
2062 | schi->cdsc_trk = last_sony_subcode.track_num; | ||
2063 | schi->cdsc_ind = last_sony_subcode.index_num; | ||
2064 | if (schi->cdsc_format == CDROM_MSF) { | ||
2065 | schi->cdsc_absaddr.msf.minute = | ||
2066 | last_sony_subcode.abs_msf[0]; | ||
2067 | schi->cdsc_absaddr.msf.second = | ||
2068 | last_sony_subcode.abs_msf[1]; | ||
2069 | schi->cdsc_absaddr.msf.frame = | ||
2070 | last_sony_subcode.abs_msf[2]; | ||
2071 | |||
2072 | schi->cdsc_reladdr.msf.minute = | ||
2073 | last_sony_subcode.rel_msf[0]; | ||
2074 | schi->cdsc_reladdr.msf.second = | ||
2075 | last_sony_subcode.rel_msf[1]; | ||
2076 | schi->cdsc_reladdr.msf.frame = | ||
2077 | last_sony_subcode.rel_msf[2]; | ||
2078 | } else if (schi->cdsc_format == CDROM_LBA) { | ||
2079 | schi->cdsc_absaddr.lba = | ||
2080 | msf_to_log(last_sony_subcode.abs_msf); | ||
2081 | schi->cdsc_reladdr.lba = | ||
2082 | msf_to_log(last_sony_subcode.rel_msf); | ||
2083 | } | ||
2084 | |||
2085 | return 0; | ||
2086 | } | ||
2087 | |||
2088 | /* Get audio data from the drive. This is fairly complex because I | ||
2089 | am looking for status and data at the same time, but if I get status | ||
2090 | then I just look for data. I need to get the status immediately so | ||
2091 | the switch from audio to data tracks will happen quickly. */ | ||
2092 | static void | ||
2093 | read_audio_data(char *buffer, unsigned char res_reg[], int *res_size) | ||
2094 | { | ||
2095 | unsigned long retry_count; | ||
2096 | int result_read; | ||
2097 | |||
2098 | |||
2099 | res_reg[0] = 0; | ||
2100 | res_reg[1] = 0; | ||
2101 | *res_size = 0; | ||
2102 | result_read = 0; | ||
2103 | |||
2104 | /* Wait for the drive to tell us we have something */ | ||
2105 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
2106 | continue_read_audio_wait: | ||
2107 | while (time_before(jiffies, retry_count) && !(is_data_ready()) | ||
2108 | && !(is_result_ready() || result_read)) { | ||
2109 | while (handle_sony_cd_attention()); | ||
2110 | |||
2111 | sony_sleep(); | ||
2112 | } | ||
2113 | if (!(is_data_ready())) { | ||
2114 | if (is_result_ready() && !result_read) { | ||
2115 | get_result(res_reg, res_size); | ||
2116 | |||
2117 | /* Read block status and continue waiting for data. */ | ||
2118 | if ((res_reg[0] & 0xf0) == 0x50) { | ||
2119 | result_read = 1; | ||
2120 | goto continue_read_audio_wait; | ||
2121 | } | ||
2122 | /* Invalid data from the drive. Shut down the operation. */ | ||
2123 | else if ((res_reg[0] & 0xf0) != 0x20) { | ||
2124 | printk(KERN_WARNING PFX "Got result that " | ||
2125 | "should have been error: %d\n", | ||
2126 | res_reg[0]); | ||
2127 | res_reg[0] = 0x20; | ||
2128 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
2129 | *res_size = 2; | ||
2130 | } | ||
2131 | abort_read(); | ||
2132 | } else { | ||
2133 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
2134 | res_reg[0] = 0x20; | ||
2135 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
2136 | *res_size = 2; | ||
2137 | abort_read(); | ||
2138 | } | ||
2139 | } else { | ||
2140 | clear_data_ready(); | ||
2141 | |||
2142 | /* If data block, then get 2340 bytes offset by 12. */ | ||
2143 | if (sony_raw_data_mode) { | ||
2144 | insb(sony_cd_read_reg, buffer + CD_XA_HEAD, | ||
2145 | CD_FRAMESIZE_RAW1); | ||
2146 | } else { | ||
2147 | /* Audio gets the whole 2352 bytes. */ | ||
2148 | insb(sony_cd_read_reg, buffer, CD_FRAMESIZE_RAW); | ||
2149 | } | ||
2150 | |||
2151 | /* If I haven't already gotten the result, get it now. */ | ||
2152 | if (!result_read) { | ||
2153 | /* Wait for the drive to tell us we have something */ | ||
2154 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
2155 | while (time_before(jiffies, retry_count) | ||
2156 | && !(is_result_ready())) { | ||
2157 | while (handle_sony_cd_attention()); | ||
2158 | |||
2159 | sony_sleep(); | ||
2160 | } | ||
2161 | |||
2162 | if (!is_result_ready()) { | ||
2163 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
2164 | res_reg[0] = 0x20; | ||
2165 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
2166 | *res_size = 2; | ||
2167 | abort_read(); | ||
2168 | return; | ||
2169 | } else { | ||
2170 | get_result(res_reg, res_size); | ||
2171 | } | ||
2172 | } | ||
2173 | |||
2174 | if ((res_reg[0] & 0xf0) == 0x50) { | ||
2175 | if ((res_reg[0] == SONY_NO_CIRC_ERR_BLK_STAT) | ||
2176 | || (res_reg[0] == SONY_NO_LECC_ERR_BLK_STAT) | ||
2177 | || (res_reg[0] == SONY_RECOV_LECC_ERR_BLK_STAT) | ||
2178 | || (res_reg[0] == SONY_NO_ERR_DETECTION_STAT)) { | ||
2179 | /* Ok, nothing to do. */ | ||
2180 | } else { | ||
2181 | printk(KERN_ERR PFX "Data block error: 0x%x\n", | ||
2182 | res_reg[0]); | ||
2183 | res_reg[0] = 0x20; | ||
2184 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
2185 | *res_size = 2; | ||
2186 | } | ||
2187 | } else if ((res_reg[0] & 0xf0) != 0x20) { | ||
2188 | /* The drive gave me bad status, I don't know what to do. | ||
2189 | Reset the driver and return an error. */ | ||
2190 | printk(KERN_NOTICE PFX "Invalid block status: 0x%x\n", | ||
2191 | res_reg[0]); | ||
2192 | restart_on_error(); | ||
2193 | res_reg[0] = 0x20; | ||
2194 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
2195 | *res_size = 2; | ||
2196 | } | ||
2197 | } | ||
2198 | } | ||
2199 | |||
2200 | /* Perform a raw data read. This will automatically detect the | ||
2201 | track type and read the proper data (audio or data). */ | ||
2202 | static int read_audio(struct cdrom_read_audio *ra) | ||
2203 | { | ||
2204 | int retval; | ||
2205 | unsigned char params[2]; | ||
2206 | unsigned char res_reg[12]; | ||
2207 | unsigned int res_size; | ||
2208 | unsigned int cframe; | ||
2209 | |||
2210 | if (down_interruptible(&sony_sem)) | ||
2211 | return -ERESTARTSYS; | ||
2212 | if (!sony_spun_up) | ||
2213 | scd_spinup(); | ||
2214 | |||
2215 | /* Set the drive to do raw operations. */ | ||
2216 | params[0] = SONY_SD_DECODE_PARAM; | ||
2217 | params[1] = 0x06 | sony_raw_data_mode; | ||
2218 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2219 | params, 2, res_reg, &res_size); | ||
2220 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2221 | printk(KERN_ERR PFX "Unable to set decode params: 0x%2.2x\n", | ||
2222 | res_reg[1]); | ||
2223 | retval = -EIO; | ||
2224 | goto out_up; | ||
2225 | } | ||
2226 | |||
2227 | /* From here down, we have to goto exit_read_audio instead of returning | ||
2228 | because the drive parameters have to be set back to data before | ||
2229 | return. */ | ||
2230 | |||
2231 | retval = 0; | ||
2232 | if (start_request(ra->addr.lba, ra->nframes)) { | ||
2233 | retval = -EIO; | ||
2234 | goto exit_read_audio; | ||
2235 | } | ||
2236 | |||
2237 | /* For every requested frame. */ | ||
2238 | cframe = 0; | ||
2239 | while (cframe < ra->nframes) { | ||
2240 | read_audio_data(audio_buffer, res_reg, &res_size); | ||
2241 | if ((res_reg[0] & 0xf0) == 0x20) { | ||
2242 | if (res_reg[1] == SONY_BAD_DATA_ERR) { | ||
2243 | printk(KERN_ERR PFX "Data error on audio " | ||
2244 | "sector %d\n", | ||
2245 | ra->addr.lba + cframe); | ||
2246 | } else if (res_reg[1] == SONY_ILL_TRACK_R_ERR) { | ||
2247 | /* Illegal track type, change track types and start over. */ | ||
2248 | sony_raw_data_mode = | ||
2249 | (sony_raw_data_mode) ? 0 : 1; | ||
2250 | |||
2251 | /* Set the drive mode. */ | ||
2252 | params[0] = SONY_SD_DECODE_PARAM; | ||
2253 | params[1] = 0x06 | sony_raw_data_mode; | ||
2254 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2255 | params, | ||
2256 | 2, res_reg, &res_size); | ||
2257 | if ((res_size < 2) | ||
2258 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2259 | printk(KERN_ERR PFX "Unable to set " | ||
2260 | "decode params: 0x%2.2x\n", | ||
2261 | res_reg[1]); | ||
2262 | retval = -EIO; | ||
2263 | goto exit_read_audio; | ||
2264 | } | ||
2265 | |||
2266 | /* Restart the request on the current frame. */ | ||
2267 | if (start_request | ||
2268 | (ra->addr.lba + cframe, | ||
2269 | ra->nframes - cframe)) { | ||
2270 | retval = -EIO; | ||
2271 | goto exit_read_audio; | ||
2272 | } | ||
2273 | |||
2274 | /* Don't go back to the top because don't want to get into | ||
2275 | and infinite loop. A lot of code gets duplicated, but | ||
2276 | that's no big deal, I don't guess. */ | ||
2277 | read_audio_data(audio_buffer, res_reg, | ||
2278 | &res_size); | ||
2279 | if ((res_reg[0] & 0xf0) == 0x20) { | ||
2280 | if (res_reg[1] == | ||
2281 | SONY_BAD_DATA_ERR) { | ||
2282 | printk(KERN_ERR PFX "Data error" | ||
2283 | " on audio sector %d\n", | ||
2284 | ra->addr.lba + | ||
2285 | cframe); | ||
2286 | } else { | ||
2287 | printk(KERN_ERR PFX "Error reading audio data on sector %d: %s\n", | ||
2288 | ra->addr.lba + cframe, | ||
2289 | translate_error | ||
2290 | (res_reg[1])); | ||
2291 | retval = -EIO; | ||
2292 | goto exit_read_audio; | ||
2293 | } | ||
2294 | } else if (copy_to_user(ra->buf + | ||
2295 | (CD_FRAMESIZE_RAW | ||
2296 | * cframe), | ||
2297 | audio_buffer, | ||
2298 | CD_FRAMESIZE_RAW)) { | ||
2299 | retval = -EFAULT; | ||
2300 | goto exit_read_audio; | ||
2301 | } | ||
2302 | } else { | ||
2303 | printk(KERN_ERR PFX "Error reading audio " | ||
2304 | "data on sector %d: %s\n", | ||
2305 | ra->addr.lba + cframe, | ||
2306 | translate_error(res_reg[1])); | ||
2307 | retval = -EIO; | ||
2308 | goto exit_read_audio; | ||
2309 | } | ||
2310 | } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe), | ||
2311 | (char *)audio_buffer, | ||
2312 | CD_FRAMESIZE_RAW)) { | ||
2313 | retval = -EFAULT; | ||
2314 | goto exit_read_audio; | ||
2315 | } | ||
2316 | |||
2317 | cframe++; | ||
2318 | } | ||
2319 | |||
2320 | get_result(res_reg, &res_size); | ||
2321 | if ((res_reg[0] & 0xf0) == 0x20) { | ||
2322 | printk(KERN_ERR PFX "Error return from audio read: %s\n", | ||
2323 | translate_error(res_reg[1])); | ||
2324 | retval = -EIO; | ||
2325 | goto exit_read_audio; | ||
2326 | } | ||
2327 | |||
2328 | exit_read_audio: | ||
2329 | |||
2330 | /* Set the drive mode back to the proper one for the disk. */ | ||
2331 | params[0] = SONY_SD_DECODE_PARAM; | ||
2332 | if (!sony_xa_mode) { | ||
2333 | params[1] = 0x0f; | ||
2334 | } else { | ||
2335 | params[1] = 0x07; | ||
2336 | } | ||
2337 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2338 | params, 2, res_reg, &res_size); | ||
2339 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2340 | printk(KERN_ERR PFX "Unable to reset decode params: 0x%2.2x\n", | ||
2341 | res_reg[1]); | ||
2342 | retval = -EIO; | ||
2343 | } | ||
2344 | |||
2345 | out_up: | ||
2346 | up(&sony_sem); | ||
2347 | |||
2348 | return retval; | ||
2349 | } | ||
2350 | |||
2351 | static int | ||
2352 | do_sony_cd_cmd_chk(const char *name, | ||
2353 | unsigned char cmd, | ||
2354 | unsigned char *params, | ||
2355 | unsigned int num_params, | ||
2356 | unsigned char *result_buffer, unsigned int *result_size) | ||
2357 | { | ||
2358 | do_sony_cd_cmd(cmd, params, num_params, result_buffer, | ||
2359 | result_size); | ||
2360 | if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20)) { | ||
2361 | printk(KERN_ERR PFX "Error %s (CDROM%s)\n", | ||
2362 | translate_error(result_buffer[1]), name); | ||
2363 | return -EIO; | ||
2364 | } | ||
2365 | return 0; | ||
2366 | } | ||
2367 | |||
2368 | /* | ||
2369 | * Uniform cdrom interface function | ||
2370 | * open the tray | ||
2371 | */ | ||
2372 | static int scd_tray_move(struct cdrom_device_info *cdi, int position) | ||
2373 | { | ||
2374 | int retval; | ||
2375 | |||
2376 | if (down_interruptible(&sony_sem)) | ||
2377 | return -ERESTARTSYS; | ||
2378 | if (position == 1 /* open tray */ ) { | ||
2379 | unsigned char res_reg[12]; | ||
2380 | unsigned int res_size; | ||
2381 | |||
2382 | do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, | ||
2383 | &res_size); | ||
2384 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, | ||
2385 | &res_size); | ||
2386 | |||
2387 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
2388 | retval = do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0, | ||
2389 | res_reg, &res_size); | ||
2390 | } else { | ||
2391 | if (0 == scd_spinup()) | ||
2392 | sony_spun_up = 1; | ||
2393 | retval = 0; | ||
2394 | } | ||
2395 | up(&sony_sem); | ||
2396 | return retval; | ||
2397 | } | ||
2398 | |||
2399 | /* | ||
2400 | * The big ugly ioctl handler. | ||
2401 | */ | ||
2402 | static int scd_audio_ioctl(struct cdrom_device_info *cdi, | ||
2403 | unsigned int cmd, void *arg) | ||
2404 | { | ||
2405 | unsigned char res_reg[12]; | ||
2406 | unsigned int res_size; | ||
2407 | unsigned char params[7]; | ||
2408 | int i, retval; | ||
2409 | |||
2410 | if (down_interruptible(&sony_sem)) | ||
2411 | return -ERESTARTSYS; | ||
2412 | switch (cmd) { | ||
2413 | case CDROMSTART: /* Spin up the drive */ | ||
2414 | retval = do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL, | ||
2415 | 0, res_reg, &res_size); | ||
2416 | break; | ||
2417 | |||
2418 | case CDROMSTOP: /* Spin down the drive */ | ||
2419 | do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, | ||
2420 | &res_size); | ||
2421 | |||
2422 | /* | ||
2423 | * Spin the drive down, ignoring the error if the disk was | ||
2424 | * already not spinning. | ||
2425 | */ | ||
2426 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
2427 | retval = do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL, | ||
2428 | 0, res_reg, &res_size); | ||
2429 | break; | ||
2430 | |||
2431 | case CDROMPAUSE: /* Pause the drive */ | ||
2432 | if (do_sony_cd_cmd_chk | ||
2433 | ("PAUSE", SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, | ||
2434 | &res_size)) { | ||
2435 | retval = -EIO; | ||
2436 | break; | ||
2437 | } | ||
2438 | /* Get the current position and save it for resuming */ | ||
2439 | if (read_subcode() < 0) { | ||
2440 | retval = -EIO; | ||
2441 | break; | ||
2442 | } | ||
2443 | cur_pos_msf[0] = last_sony_subcode.abs_msf[0]; | ||
2444 | cur_pos_msf[1] = last_sony_subcode.abs_msf[1]; | ||
2445 | cur_pos_msf[2] = last_sony_subcode.abs_msf[2]; | ||
2446 | sony_audio_status = CDROM_AUDIO_PAUSED; | ||
2447 | retval = 0; | ||
2448 | break; | ||
2449 | |||
2450 | case CDROMRESUME: /* Start the drive after being paused */ | ||
2451 | if (sony_audio_status != CDROM_AUDIO_PAUSED) { | ||
2452 | retval = -EINVAL; | ||
2453 | break; | ||
2454 | } | ||
2455 | |||
2456 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
2457 | &res_size); | ||
2458 | |||
2459 | /* Start the drive at the saved position. */ | ||
2460 | params[1] = int_to_bcd(cur_pos_msf[0]); | ||
2461 | params[2] = int_to_bcd(cur_pos_msf[1]); | ||
2462 | params[3] = int_to_bcd(cur_pos_msf[2]); | ||
2463 | params[4] = int_to_bcd(final_pos_msf[0]); | ||
2464 | params[5] = int_to_bcd(final_pos_msf[1]); | ||
2465 | params[6] = int_to_bcd(final_pos_msf[2]); | ||
2466 | params[0] = 0x03; | ||
2467 | if (do_sony_cd_cmd_chk | ||
2468 | ("RESUME", SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, | ||
2469 | &res_size) < 0) { | ||
2470 | retval = -EIO; | ||
2471 | break; | ||
2472 | } | ||
2473 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
2474 | retval = 0; | ||
2475 | break; | ||
2476 | |||
2477 | case CDROMPLAYMSF: /* Play starting at the given MSF address. */ | ||
2478 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
2479 | &res_size); | ||
2480 | |||
2481 | /* The parameters are given in int, must be converted */ | ||
2482 | for (i = 1; i < 7; i++) { | ||
2483 | params[i] = | ||
2484 | int_to_bcd(((unsigned char *) arg)[i - 1]); | ||
2485 | } | ||
2486 | params[0] = 0x03; | ||
2487 | if (do_sony_cd_cmd_chk | ||
2488 | ("PLAYMSF", SONY_AUDIO_PLAYBACK_CMD, params, 7, | ||
2489 | res_reg, &res_size) < 0) { | ||
2490 | retval = -EIO; | ||
2491 | break; | ||
2492 | } | ||
2493 | |||
2494 | /* Save the final position for pauses and resumes */ | ||
2495 | final_pos_msf[0] = bcd_to_int(params[4]); | ||
2496 | final_pos_msf[1] = bcd_to_int(params[5]); | ||
2497 | final_pos_msf[2] = bcd_to_int(params[6]); | ||
2498 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
2499 | retval = 0; | ||
2500 | break; | ||
2501 | |||
2502 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
2503 | { | ||
2504 | struct cdrom_tochdr *hdr; | ||
2505 | |||
2506 | sony_get_toc(); | ||
2507 | if (!sony_toc_read) { | ||
2508 | retval = -EIO; | ||
2509 | break; | ||
2510 | } | ||
2511 | |||
2512 | hdr = (struct cdrom_tochdr *) arg; | ||
2513 | hdr->cdth_trk0 = sony_toc.first_track_num; | ||
2514 | hdr->cdth_trk1 = sony_toc.last_track_num; | ||
2515 | } | ||
2516 | retval = 0; | ||
2517 | break; | ||
2518 | |||
2519 | case CDROMREADTOCENTRY: /* Read a given table of contents entry */ | ||
2520 | { | ||
2521 | struct cdrom_tocentry *entry; | ||
2522 | int track_idx; | ||
2523 | unsigned char *msf_val = NULL; | ||
2524 | |||
2525 | sony_get_toc(); | ||
2526 | if (!sony_toc_read) { | ||
2527 | retval = -EIO; | ||
2528 | break; | ||
2529 | } | ||
2530 | |||
2531 | entry = (struct cdrom_tocentry *) arg; | ||
2532 | |||
2533 | track_idx = find_track(entry->cdte_track); | ||
2534 | if (track_idx < 0) { | ||
2535 | retval = -EINVAL; | ||
2536 | break; | ||
2537 | } | ||
2538 | |||
2539 | entry->cdte_adr = | ||
2540 | sony_toc.tracks[track_idx].address; | ||
2541 | entry->cdte_ctrl = | ||
2542 | sony_toc.tracks[track_idx].control; | ||
2543 | msf_val = | ||
2544 | sony_toc.tracks[track_idx].track_start_msf; | ||
2545 | |||
2546 | /* Logical buffer address or MSF format requested? */ | ||
2547 | if (entry->cdte_format == CDROM_LBA) { | ||
2548 | entry->cdte_addr.lba = msf_to_log(msf_val); | ||
2549 | } else if (entry->cdte_format == CDROM_MSF) { | ||
2550 | entry->cdte_addr.msf.minute = *msf_val; | ||
2551 | entry->cdte_addr.msf.second = | ||
2552 | *(msf_val + 1); | ||
2553 | entry->cdte_addr.msf.frame = | ||
2554 | *(msf_val + 2); | ||
2555 | } | ||
2556 | } | ||
2557 | retval = 0; | ||
2558 | break; | ||
2559 | |||
2560 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
2561 | { | ||
2562 | struct cdrom_ti *ti = (struct cdrom_ti *) arg; | ||
2563 | int track_idx; | ||
2564 | |||
2565 | sony_get_toc(); | ||
2566 | if (!sony_toc_read) { | ||
2567 | retval = -EIO; | ||
2568 | break; | ||
2569 | } | ||
2570 | |||
2571 | if ((ti->cdti_trk0 < sony_toc.first_track_num) | ||
2572 | || (ti->cdti_trk0 > sony_toc.last_track_num) | ||
2573 | || (ti->cdti_trk1 < ti->cdti_trk0)) { | ||
2574 | retval = -EINVAL; | ||
2575 | break; | ||
2576 | } | ||
2577 | |||
2578 | track_idx = find_track(ti->cdti_trk0); | ||
2579 | if (track_idx < 0) { | ||
2580 | retval = -EINVAL; | ||
2581 | break; | ||
2582 | } | ||
2583 | params[1] = | ||
2584 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2585 | track_start_msf[0]); | ||
2586 | params[2] = | ||
2587 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2588 | track_start_msf[1]); | ||
2589 | params[3] = | ||
2590 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2591 | track_start_msf[2]); | ||
2592 | |||
2593 | /* | ||
2594 | * If we want to stop after the last track, use the lead-out | ||
2595 | * MSF to do that. | ||
2596 | */ | ||
2597 | if (ti->cdti_trk1 >= sony_toc.last_track_num) { | ||
2598 | track_idx = find_track(CDROM_LEADOUT); | ||
2599 | } else { | ||
2600 | track_idx = find_track(ti->cdti_trk1 + 1); | ||
2601 | } | ||
2602 | if (track_idx < 0) { | ||
2603 | retval = -EINVAL; | ||
2604 | break; | ||
2605 | } | ||
2606 | params[4] = | ||
2607 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2608 | track_start_msf[0]); | ||
2609 | params[5] = | ||
2610 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2611 | track_start_msf[1]); | ||
2612 | params[6] = | ||
2613 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2614 | track_start_msf[2]); | ||
2615 | params[0] = 0x03; | ||
2616 | |||
2617 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
2618 | &res_size); | ||
2619 | |||
2620 | do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, | ||
2621 | res_reg, &res_size); | ||
2622 | |||
2623 | if ((res_size < 2) | ||
2624 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2625 | printk(KERN_ERR PFX | ||
2626 | "Params: %x %x %x %x %x %x %x\n", | ||
2627 | params[0], params[1], params[2], | ||
2628 | params[3], params[4], params[5], | ||
2629 | params[6]); | ||
2630 | printk(KERN_ERR PFX | ||
2631 | "Error %s (CDROMPLAYTRKIND)\n", | ||
2632 | translate_error(res_reg[1])); | ||
2633 | retval = -EIO; | ||
2634 | break; | ||
2635 | } | ||
2636 | |||
2637 | /* Save the final position for pauses and resumes */ | ||
2638 | final_pos_msf[0] = bcd_to_int(params[4]); | ||
2639 | final_pos_msf[1] = bcd_to_int(params[5]); | ||
2640 | final_pos_msf[2] = bcd_to_int(params[6]); | ||
2641 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
2642 | retval = 0; | ||
2643 | break; | ||
2644 | } | ||
2645 | |||
2646 | case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ | ||
2647 | { | ||
2648 | struct cdrom_volctrl *volctrl = | ||
2649 | (struct cdrom_volctrl *) arg; | ||
2650 | |||
2651 | params[0] = SONY_SD_AUDIO_VOLUME; | ||
2652 | params[1] = volctrl->channel0; | ||
2653 | params[2] = volctrl->channel1; | ||
2654 | retval = do_sony_cd_cmd_chk("VOLCTRL", | ||
2655 | SONY_SET_DRIVE_PARAM_CMD, | ||
2656 | params, 3, res_reg, | ||
2657 | &res_size); | ||
2658 | break; | ||
2659 | } | ||
2660 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
2661 | retval = sony_get_subchnl_info((struct cdrom_subchnl *) arg); | ||
2662 | break; | ||
2663 | |||
2664 | default: | ||
2665 | retval = -EINVAL; | ||
2666 | break; | ||
2667 | } | ||
2668 | up(&sony_sem); | ||
2669 | return retval; | ||
2670 | } | ||
2671 | |||
2672 | static int scd_read_audio(struct cdrom_device_info *cdi, | ||
2673 | unsigned int cmd, unsigned long arg) | ||
2674 | { | ||
2675 | void __user *argp = (void __user *)arg; | ||
2676 | int retval; | ||
2677 | |||
2678 | if (down_interruptible(&sony_sem)) | ||
2679 | return -ERESTARTSYS; | ||
2680 | switch (cmd) { | ||
2681 | case CDROMREADAUDIO: /* Read 2352 byte audio tracks and 2340 byte | ||
2682 | raw data tracks. */ | ||
2683 | { | ||
2684 | struct cdrom_read_audio ra; | ||
2685 | |||
2686 | |||
2687 | sony_get_toc(); | ||
2688 | if (!sony_toc_read) { | ||
2689 | retval = -EIO; | ||
2690 | break; | ||
2691 | } | ||
2692 | |||
2693 | if (copy_from_user(&ra, argp, sizeof(ra))) { | ||
2694 | retval = -EFAULT; | ||
2695 | break; | ||
2696 | } | ||
2697 | |||
2698 | if (ra.nframes == 0) { | ||
2699 | retval = 0; | ||
2700 | break; | ||
2701 | } | ||
2702 | |||
2703 | if (!access_ok(VERIFY_WRITE, ra.buf, | ||
2704 | CD_FRAMESIZE_RAW * ra.nframes)) | ||
2705 | return -EFAULT; | ||
2706 | |||
2707 | if (ra.addr_format == CDROM_LBA) { | ||
2708 | if ((ra.addr.lba >= | ||
2709 | sony_toc.lead_out_start_lba) | ||
2710 | || (ra.addr.lba + ra.nframes >= | ||
2711 | sony_toc.lead_out_start_lba)) { | ||
2712 | retval = -EINVAL; | ||
2713 | break; | ||
2714 | } | ||
2715 | } else if (ra.addr_format == CDROM_MSF) { | ||
2716 | if ((ra.addr.msf.minute >= 75) | ||
2717 | || (ra.addr.msf.second >= 60) | ||
2718 | || (ra.addr.msf.frame >= 75)) { | ||
2719 | retval = -EINVAL; | ||
2720 | break; | ||
2721 | } | ||
2722 | |||
2723 | ra.addr.lba = ((ra.addr.msf.minute * 4500) | ||
2724 | + (ra.addr.msf.second * 75) | ||
2725 | + ra.addr.msf.frame); | ||
2726 | if ((ra.addr.lba >= | ||
2727 | sony_toc.lead_out_start_lba) | ||
2728 | || (ra.addr.lba + ra.nframes >= | ||
2729 | sony_toc.lead_out_start_lba)) { | ||
2730 | retval = -EINVAL; | ||
2731 | break; | ||
2732 | } | ||
2733 | |||
2734 | /* I know, this can go negative on an unsigned. However, | ||
2735 | the first thing done to the data is to add this value, | ||
2736 | so this should compensate and allow direct msf access. */ | ||
2737 | ra.addr.lba -= LOG_START_OFFSET; | ||
2738 | } else { | ||
2739 | retval = -EINVAL; | ||
2740 | break; | ||
2741 | } | ||
2742 | |||
2743 | retval = read_audio(&ra); | ||
2744 | break; | ||
2745 | } | ||
2746 | retval = 0; | ||
2747 | break; | ||
2748 | |||
2749 | default: | ||
2750 | retval = -EINVAL; | ||
2751 | } | ||
2752 | up(&sony_sem); | ||
2753 | return retval; | ||
2754 | } | ||
2755 | |||
2756 | static int scd_spinup(void) | ||
2757 | { | ||
2758 | unsigned char res_reg[12]; | ||
2759 | unsigned int res_size; | ||
2760 | int num_spin_ups; | ||
2761 | |||
2762 | num_spin_ups = 0; | ||
2763 | |||
2764 | respinup_on_open: | ||
2765 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); | ||
2766 | |||
2767 | /* The drive sometimes returns error 0. I don't know why, but ignore | ||
2768 | it. It seems to mean the drive has already done the operation. */ | ||
2769 | if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) { | ||
2770 | printk(KERN_ERR PFX "%s error (scd_open, spin up)\n", | ||
2771 | translate_error(res_reg[1])); | ||
2772 | return 1; | ||
2773 | } | ||
2774 | |||
2775 | do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size); | ||
2776 | |||
2777 | /* The drive sometimes returns error 0. I don't know why, but ignore | ||
2778 | it. It seems to mean the drive has already done the operation. */ | ||
2779 | if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) { | ||
2780 | /* If the drive is already playing, it's ok. */ | ||
2781 | if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) | ||
2782 | || (res_reg[1] == 0)) { | ||
2783 | return 0; | ||
2784 | } | ||
2785 | |||
2786 | /* If the drive says it is not spun up (even though we just did it!) | ||
2787 | then retry the operation at least a few times. */ | ||
2788 | if ((res_reg[1] == SONY_NOT_SPIN_ERR) | ||
2789 | && (num_spin_ups < MAX_CDU31A_RETRIES)) { | ||
2790 | num_spin_ups++; | ||
2791 | goto respinup_on_open; | ||
2792 | } | ||
2793 | |||
2794 | printk(KERN_ERR PFX "Error %s (scd_open, read toc)\n", | ||
2795 | translate_error(res_reg[1])); | ||
2796 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, | ||
2797 | &res_size); | ||
2798 | return 1; | ||
2799 | } | ||
2800 | return 0; | ||
2801 | } | ||
2802 | |||
2803 | /* | ||
2804 | * Open the drive for operations. Spin the drive up and read the table of | ||
2805 | * contents if these have not already been done. | ||
2806 | */ | ||
2807 | static int scd_open(struct cdrom_device_info *cdi, int purpose) | ||
2808 | { | ||
2809 | unsigned char res_reg[12]; | ||
2810 | unsigned int res_size; | ||
2811 | unsigned char params[2]; | ||
2812 | |||
2813 | if (purpose == 1) { | ||
2814 | /* Open for IOCTLs only - no media check */ | ||
2815 | sony_usage++; | ||
2816 | return 0; | ||
2817 | } | ||
2818 | |||
2819 | if (sony_usage == 0) { | ||
2820 | if (scd_spinup() != 0) | ||
2821 | return -EIO; | ||
2822 | sony_get_toc(); | ||
2823 | if (!sony_toc_read) { | ||
2824 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, | ||
2825 | res_reg, &res_size); | ||
2826 | return -EIO; | ||
2827 | } | ||
2828 | |||
2829 | /* For XA on the CDU31A only, we have to do special reads. | ||
2830 | The CDU33A handles XA automagically. */ | ||
2831 | /* if ( (sony_toc.disk_type == SONY_XA_DISK_TYPE) */ | ||
2832 | if ((sony_toc.disk_type != 0x00) | ||
2833 | && (!is_double_speed)) { | ||
2834 | params[0] = SONY_SD_DECODE_PARAM; | ||
2835 | params[1] = 0x07; | ||
2836 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2837 | params, 2, res_reg, &res_size); | ||
2838 | if ((res_size < 2) | ||
2839 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2840 | printk(KERN_WARNING PFX "Unable to set " | ||
2841 | "XA params: 0x%2.2x\n", res_reg[1]); | ||
2842 | } | ||
2843 | sony_xa_mode = 1; | ||
2844 | } | ||
2845 | /* A non-XA disk. Set the parms back if necessary. */ | ||
2846 | else if (sony_xa_mode) { | ||
2847 | params[0] = SONY_SD_DECODE_PARAM; | ||
2848 | params[1] = 0x0f; | ||
2849 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2850 | params, 2, res_reg, &res_size); | ||
2851 | if ((res_size < 2) | ||
2852 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2853 | printk(KERN_WARNING PFX "Unable to reset " | ||
2854 | "XA params: 0x%2.2x\n", res_reg[1]); | ||
2855 | } | ||
2856 | sony_xa_mode = 0; | ||
2857 | } | ||
2858 | |||
2859 | sony_spun_up = 1; | ||
2860 | } | ||
2861 | |||
2862 | sony_usage++; | ||
2863 | |||
2864 | return 0; | ||
2865 | } | ||
2866 | |||
2867 | |||
2868 | /* | ||
2869 | * Close the drive. Spin it down if no task is using it. The spin | ||
2870 | * down will fail if playing audio, so audio play is OK. | ||
2871 | */ | ||
2872 | static void scd_release(struct cdrom_device_info *cdi) | ||
2873 | { | ||
2874 | if (sony_usage == 1) { | ||
2875 | unsigned char res_reg[12]; | ||
2876 | unsigned int res_size; | ||
2877 | |||
2878 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, | ||
2879 | &res_size); | ||
2880 | |||
2881 | sony_spun_up = 0; | ||
2882 | } | ||
2883 | sony_usage--; | ||
2884 | } | ||
2885 | |||
2886 | static struct cdrom_device_ops scd_dops = { | ||
2887 | .open = scd_open, | ||
2888 | .release = scd_release, | ||
2889 | .drive_status = scd_drive_status, | ||
2890 | .media_changed = scd_media_changed, | ||
2891 | .tray_move = scd_tray_move, | ||
2892 | .lock_door = scd_lock_door, | ||
2893 | .select_speed = scd_select_speed, | ||
2894 | .get_last_session = scd_get_last_session, | ||
2895 | .get_mcn = scd_get_mcn, | ||
2896 | .reset = scd_reset, | ||
2897 | .audio_ioctl = scd_audio_ioctl, | ||
2898 | .capability = CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK | | ||
2899 | CDC_SELECT_SPEED | CDC_MULTI_SESSION | | ||
2900 | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | | ||
2901 | CDC_RESET | CDC_DRIVE_STATUS, | ||
2902 | .n_minors = 1, | ||
2903 | }; | ||
2904 | |||
2905 | static struct cdrom_device_info scd_info = { | ||
2906 | .ops = &scd_dops, | ||
2907 | .speed = 2, | ||
2908 | .capacity = 1, | ||
2909 | .name = "cdu31a" | ||
2910 | }; | ||
2911 | |||
2912 | static int scd_block_open(struct inode *inode, struct file *file) | ||
2913 | { | ||
2914 | return cdrom_open(&scd_info, inode, file); | ||
2915 | } | ||
2916 | |||
2917 | static int scd_block_release(struct inode *inode, struct file *file) | ||
2918 | { | ||
2919 | return cdrom_release(&scd_info, file); | ||
2920 | } | ||
2921 | |||
2922 | static int scd_block_ioctl(struct inode *inode, struct file *file, | ||
2923 | unsigned cmd, unsigned long arg) | ||
2924 | { | ||
2925 | int retval; | ||
2926 | |||
2927 | /* The eject and close commands should be handled by Uniform CD-ROM | ||
2928 | * driver - but I always got hard lockup instead of eject | ||
2929 | * until I put this here. | ||
2930 | */ | ||
2931 | switch (cmd) { | ||
2932 | case CDROMEJECT: | ||
2933 | scd_lock_door(&scd_info, 0); | ||
2934 | retval = scd_tray_move(&scd_info, 1); | ||
2935 | break; | ||
2936 | case CDROMCLOSETRAY: | ||
2937 | retval = scd_tray_move(&scd_info, 0); | ||
2938 | break; | ||
2939 | case CDROMREADAUDIO: | ||
2940 | retval = scd_read_audio(&scd_info, CDROMREADAUDIO, arg); | ||
2941 | break; | ||
2942 | default: | ||
2943 | retval = cdrom_ioctl(file, &scd_info, inode, cmd, arg); | ||
2944 | } | ||
2945 | return retval; | ||
2946 | } | ||
2947 | |||
2948 | static int scd_block_media_changed(struct gendisk *disk) | ||
2949 | { | ||
2950 | return cdrom_media_changed(&scd_info); | ||
2951 | } | ||
2952 | |||
2953 | static struct block_device_operations scd_bdops = | ||
2954 | { | ||
2955 | .owner = THIS_MODULE, | ||
2956 | .open = scd_block_open, | ||
2957 | .release = scd_block_release, | ||
2958 | .ioctl = scd_block_ioctl, | ||
2959 | .media_changed = scd_block_media_changed, | ||
2960 | }; | ||
2961 | |||
2962 | static struct gendisk *scd_gendisk; | ||
2963 | |||
2964 | /* The different types of disc loading mechanisms supported */ | ||
2965 | static char *load_mech[] __initdata = | ||
2966 | { "caddy", "tray", "pop-up", "unknown" }; | ||
2967 | |||
2968 | static int __init | ||
2969 | get_drive_configuration(unsigned short base_io, | ||
2970 | unsigned char res_reg[], unsigned int *res_size) | ||
2971 | { | ||
2972 | unsigned long retry_count; | ||
2973 | |||
2974 | |||
2975 | if (!request_region(base_io, 4, "cdu31a")) | ||
2976 | return 0; | ||
2977 | |||
2978 | /* Set the base address */ | ||
2979 | cdu31a_port = base_io; | ||
2980 | |||
2981 | /* Set up all the register locations */ | ||
2982 | sony_cd_cmd_reg = cdu31a_port + SONY_CMD_REG_OFFSET; | ||
2983 | sony_cd_param_reg = cdu31a_port + SONY_PARAM_REG_OFFSET; | ||
2984 | sony_cd_write_reg = cdu31a_port + SONY_WRITE_REG_OFFSET; | ||
2985 | sony_cd_control_reg = cdu31a_port + SONY_CONTROL_REG_OFFSET; | ||
2986 | sony_cd_status_reg = cdu31a_port + SONY_STATUS_REG_OFFSET; | ||
2987 | sony_cd_result_reg = cdu31a_port + SONY_RESULT_REG_OFFSET; | ||
2988 | sony_cd_read_reg = cdu31a_port + SONY_READ_REG_OFFSET; | ||
2989 | sony_cd_fifost_reg = cdu31a_port + SONY_FIFOST_REG_OFFSET; | ||
2990 | |||
2991 | /* | ||
2992 | * Check to see if anything exists at the status register location. | ||
2993 | * I don't know if this is a good way to check, but it seems to work | ||
2994 | * ok for me. | ||
2995 | */ | ||
2996 | if (read_status_register() != 0xff) { | ||
2997 | /* | ||
2998 | * Reset the drive and wait for attention from it (to say it's reset). | ||
2999 | * If you don't wait, the next operation will probably fail. | ||
3000 | */ | ||
3001 | reset_drive(); | ||
3002 | retry_count = jiffies + SONY_RESET_TIMEOUT; | ||
3003 | while (time_before(jiffies, retry_count) | ||
3004 | && (!is_attention())) { | ||
3005 | sony_sleep(); | ||
3006 | } | ||
3007 | |||
3008 | #if 0 | ||
3009 | /* If attention is never seen probably not a CDU31a present */ | ||
3010 | if (!is_attention()) { | ||
3011 | res_reg[0] = 0x20; | ||
3012 | goto out_err; | ||
3013 | } | ||
3014 | #endif | ||
3015 | |||
3016 | /* | ||
3017 | * Get the drive configuration. | ||
3018 | */ | ||
3019 | do_sony_cd_cmd(SONY_REQ_DRIVE_CONFIG_CMD, | ||
3020 | NULL, | ||
3021 | 0, (unsigned char *) res_reg, res_size); | ||
3022 | if (*res_size <= 2 || (res_reg[0] & 0xf0) != 0) | ||
3023 | goto out_err; | ||
3024 | return 1; | ||
3025 | } | ||
3026 | |||
3027 | /* Return an error */ | ||
3028 | res_reg[0] = 0x20; | ||
3029 | out_err: | ||
3030 | release_region(cdu31a_port, 4); | ||
3031 | cdu31a_port = 0; | ||
3032 | return 0; | ||
3033 | } | ||
3034 | |||
3035 | #ifndef MODULE | ||
3036 | /* | ||
3037 | * Set up base I/O and interrupts, called from main.c. | ||
3038 | */ | ||
3039 | |||
3040 | static int __init cdu31a_setup(char *strings) | ||
3041 | { | ||
3042 | int ints[4]; | ||
3043 | |||
3044 | (void) get_options(strings, ARRAY_SIZE(ints), ints); | ||
3045 | |||
3046 | if (ints[0] > 0) { | ||
3047 | cdu31a_port = ints[1]; | ||
3048 | } | ||
3049 | if (ints[0] > 1) { | ||
3050 | cdu31a_irq = ints[2]; | ||
3051 | } | ||
3052 | if ((strings != NULL) && (*strings != '\0')) { | ||
3053 | if (strcmp(strings, "PAS") == 0) { | ||
3054 | sony_pas_init = 1; | ||
3055 | } else { | ||
3056 | printk(KERN_NOTICE PFX "Unknown interface type: %s\n", | ||
3057 | strings); | ||
3058 | } | ||
3059 | } | ||
3060 | |||
3061 | return 1; | ||
3062 | } | ||
3063 | |||
3064 | __setup("cdu31a=", cdu31a_setup); | ||
3065 | |||
3066 | #endif | ||
3067 | |||
3068 | /* | ||
3069 | * Initialize the driver. | ||
3070 | */ | ||
3071 | int __init cdu31a_init(void) | ||
3072 | { | ||
3073 | struct s_sony_drive_config drive_config; | ||
3074 | struct gendisk *disk; | ||
3075 | int deficiency = 0; | ||
3076 | unsigned int res_size; | ||
3077 | char msg[255]; | ||
3078 | char buf[40]; | ||
3079 | int i; | ||
3080 | int tmp_irq; | ||
3081 | |||
3082 | /* | ||
3083 | * According to Alex Freed (freed@europa.orion.adobe.com), this is | ||
3084 | * required for the Fusion CD-16 package. If the sound driver is | ||
3085 | * loaded, it should work fine, but just in case... | ||
3086 | * | ||
3087 | * The following turn on the CD-ROM interface for a Fusion CD-16. | ||
3088 | */ | ||
3089 | if (sony_pas_init) { | ||
3090 | outb(0xbc, 0x9a01); | ||
3091 | outb(0xe2, 0x9a01); | ||
3092 | } | ||
3093 | |||
3094 | /* Setting the base I/O address to 0xffff will disable it. */ | ||
3095 | if (cdu31a_port == 0xffff) | ||
3096 | goto errout3; | ||
3097 | |||
3098 | if (cdu31a_port != 0) { | ||
3099 | /* Need IRQ 0 because we can't sleep here. */ | ||
3100 | tmp_irq = cdu31a_irq; | ||
3101 | cdu31a_irq = 0; | ||
3102 | if (!get_drive_configuration(cdu31a_port, | ||
3103 | drive_config.exec_status, | ||
3104 | &res_size)) | ||
3105 | goto errout3; | ||
3106 | cdu31a_irq = tmp_irq; | ||
3107 | } else { | ||
3108 | cdu31a_irq = 0; | ||
3109 | for (i = 0; cdu31a_addresses[i].base; i++) { | ||
3110 | if (get_drive_configuration(cdu31a_addresses[i].base, | ||
3111 | drive_config.exec_status, | ||
3112 | &res_size)) { | ||
3113 | cdu31a_irq = cdu31a_addresses[i].int_num; | ||
3114 | break; | ||
3115 | } | ||
3116 | } | ||
3117 | if (!cdu31a_port) | ||
3118 | goto errout3; | ||
3119 | } | ||
3120 | |||
3121 | if (register_blkdev(MAJOR_NR, "cdu31a")) | ||
3122 | goto errout2; | ||
3123 | |||
3124 | disk = alloc_disk(1); | ||
3125 | if (!disk) | ||
3126 | goto errout1; | ||
3127 | disk->major = MAJOR_NR; | ||
3128 | disk->first_minor = 0; | ||
3129 | sprintf(disk->disk_name, "cdu31a"); | ||
3130 | disk->fops = &scd_bdops; | ||
3131 | disk->flags = GENHD_FL_CD; | ||
3132 | |||
3133 | if (SONY_HWC_DOUBLE_SPEED(drive_config)) | ||
3134 | is_double_speed = 1; | ||
3135 | |||
3136 | tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */ | ||
3137 | cdu31a_irq = 0; | ||
3138 | |||
3139 | sony_speed = is_double_speed; /* Set 2X drives to 2X by default */ | ||
3140 | set_drive_params(sony_speed); | ||
3141 | |||
3142 | cdu31a_irq = tmp_irq; | ||
3143 | |||
3144 | if (cdu31a_irq > 0) { | ||
3145 | if (request_irq | ||
3146 | (cdu31a_irq, cdu31a_interrupt, IRQF_DISABLED, | ||
3147 | "cdu31a", NULL)) { | ||
3148 | printk(KERN_WARNING PFX "Unable to grab IRQ%d for " | ||
3149 | "the CDU31A driver\n", cdu31a_irq); | ||
3150 | cdu31a_irq = 0; | ||
3151 | } | ||
3152 | } | ||
3153 | |||
3154 | sprintf(msg, "Sony I/F CDROM : %8.8s %16.16s %8.8s\n", | ||
3155 | drive_config.vendor_id, | ||
3156 | drive_config.product_id, | ||
3157 | drive_config.product_rev_level); | ||
3158 | sprintf(buf, " Capabilities: %s", | ||
3159 | load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]); | ||
3160 | strcat(msg, buf); | ||
3161 | if (SONY_HWC_AUDIO_PLAYBACK(drive_config)) | ||
3162 | strcat(msg, ", audio"); | ||
3163 | else | ||
3164 | deficiency |= CDC_PLAY_AUDIO; | ||
3165 | if (SONY_HWC_EJECT(drive_config)) | ||
3166 | strcat(msg, ", eject"); | ||
3167 | else | ||
3168 | deficiency |= CDC_OPEN_TRAY; | ||
3169 | if (SONY_HWC_LED_SUPPORT(drive_config)) | ||
3170 | strcat(msg, ", LED"); | ||
3171 | if (SONY_HWC_ELECTRIC_VOLUME(drive_config)) | ||
3172 | strcat(msg, ", elec. Vol"); | ||
3173 | if (SONY_HWC_ELECTRIC_VOLUME_CTL(drive_config)) | ||
3174 | strcat(msg, ", sep. Vol"); | ||
3175 | if (is_double_speed) | ||
3176 | strcat(msg, ", double speed"); | ||
3177 | else | ||
3178 | deficiency |= CDC_SELECT_SPEED; | ||
3179 | if (cdu31a_irq > 0) { | ||
3180 | sprintf(buf, ", irq %d", cdu31a_irq); | ||
3181 | strcat(msg, buf); | ||
3182 | } | ||
3183 | strcat(msg, "\n"); | ||
3184 | printk(KERN_INFO PFX "%s",msg); | ||
3185 | |||
3186 | cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock); | ||
3187 | if (!cdu31a_queue) | ||
3188 | goto errout0; | ||
3189 | blk_queue_hardsect_size(cdu31a_queue, 2048); | ||
3190 | |||
3191 | init_timer(&cdu31a_abort_timer); | ||
3192 | cdu31a_abort_timer.function = handle_abort_timeout; | ||
3193 | |||
3194 | scd_info.mask = deficiency; | ||
3195 | scd_gendisk = disk; | ||
3196 | if (register_cdrom(&scd_info)) | ||
3197 | goto err; | ||
3198 | disk->queue = cdu31a_queue; | ||
3199 | add_disk(disk); | ||
3200 | |||
3201 | disk_changed = 1; | ||
3202 | return 0; | ||
3203 | |||
3204 | err: | ||
3205 | blk_cleanup_queue(cdu31a_queue); | ||
3206 | errout0: | ||
3207 | if (cdu31a_irq) | ||
3208 | free_irq(cdu31a_irq, NULL); | ||
3209 | printk(KERN_ERR PFX "Unable to register with Uniform cdrom driver\n"); | ||
3210 | put_disk(disk); | ||
3211 | errout1: | ||
3212 | if (unregister_blkdev(MAJOR_NR, "cdu31a")) { | ||
3213 | printk(KERN_WARNING PFX "Can't unregister block device\n"); | ||
3214 | } | ||
3215 | errout2: | ||
3216 | release_region(cdu31a_port, 4); | ||
3217 | errout3: | ||
3218 | return -EIO; | ||
3219 | } | ||
3220 | |||
3221 | |||
3222 | static void __exit cdu31a_exit(void) | ||
3223 | { | ||
3224 | del_gendisk(scd_gendisk); | ||
3225 | put_disk(scd_gendisk); | ||
3226 | if (unregister_cdrom(&scd_info)) { | ||
3227 | printk(KERN_WARNING PFX "Can't unregister from Uniform " | ||
3228 | "cdrom driver\n"); | ||
3229 | return; | ||
3230 | } | ||
3231 | if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL)) { | ||
3232 | printk(KERN_WARNING PFX "Can't unregister\n"); | ||
3233 | return; | ||
3234 | } | ||
3235 | |||
3236 | blk_cleanup_queue(cdu31a_queue); | ||
3237 | |||
3238 | if (cdu31a_irq > 0) | ||
3239 | free_irq(cdu31a_irq, NULL); | ||
3240 | |||
3241 | release_region(cdu31a_port, 4); | ||
3242 | printk(KERN_INFO PFX "module released.\n"); | ||
3243 | } | ||
3244 | |||
3245 | #ifdef MODULE | ||
3246 | module_init(cdu31a_init); | ||
3247 | #endif | ||
3248 | module_exit(cdu31a_exit); | ||
3249 | |||
3250 | MODULE_LICENSE("GPL"); | ||
3251 | MODULE_ALIAS_BLOCKDEV_MAJOR(CDU31A_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/cdu31a.h b/drivers/cdrom/cdu31a.h deleted file mode 100644 index 61d4768c412e..000000000000 --- a/drivers/cdrom/cdu31a.h +++ /dev/null | |||
@@ -1,411 +0,0 @@ | |||
1 | /* | ||
2 | * Definitions for a Sony interface CDROM drive. | ||
3 | * | ||
4 | * Corey Minyard (minyard@wf-rch.cirr.com) | ||
5 | * | ||
6 | * Copyright (C) 1993 Corey Minyard | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * General defines. | ||
26 | */ | ||
27 | #define SONY_XA_DISK_TYPE 0x20 | ||
28 | |||
29 | /* | ||
30 | * Offsets (from the base address) and bits for the various write registers | ||
31 | * of the drive. | ||
32 | */ | ||
33 | #define SONY_CMD_REG_OFFSET 0 | ||
34 | #define SONY_PARAM_REG_OFFSET 1 | ||
35 | #define SONY_WRITE_REG_OFFSET 2 | ||
36 | #define SONY_CONTROL_REG_OFFSET 3 | ||
37 | # define SONY_ATTN_CLR_BIT 0x01 | ||
38 | # define SONY_RES_RDY_CLR_BIT 0x02 | ||
39 | # define SONY_DATA_RDY_CLR_BIT 0x04 | ||
40 | # define SONY_ATTN_INT_EN_BIT 0x08 | ||
41 | # define SONY_RES_RDY_INT_EN_BIT 0x10 | ||
42 | # define SONY_DATA_RDY_INT_EN_BIT 0x20 | ||
43 | # define SONY_PARAM_CLR_BIT 0x40 | ||
44 | # define SONY_DRIVE_RESET_BIT 0x80 | ||
45 | |||
46 | /* | ||
47 | * Offsets (from the base address) and bits for the various read registers | ||
48 | * of the drive. | ||
49 | */ | ||
50 | #define SONY_STATUS_REG_OFFSET 0 | ||
51 | # define SONY_ATTN_BIT 0x01 | ||
52 | # define SONY_RES_RDY_BIT 0x02 | ||
53 | # define SONY_DATA_RDY_BIT 0x04 | ||
54 | # define SONY_ATTN_INT_ST_BIT 0x08 | ||
55 | # define SONY_RES_RDY_INT_ST_BIT 0x10 | ||
56 | # define SONY_DATA_RDY_INT_ST_BIT 0x20 | ||
57 | # define SONY_DATA_REQUEST_BIT 0x40 | ||
58 | # define SONY_BUSY_BIT 0x80 | ||
59 | #define SONY_RESULT_REG_OFFSET 1 | ||
60 | #define SONY_READ_REG_OFFSET 2 | ||
61 | #define SONY_FIFOST_REG_OFFSET 3 | ||
62 | # define SONY_PARAM_WRITE_RDY_BIT 0x01 | ||
63 | # define SONY_PARAM_REG_EMPTY_BIT 0x02 | ||
64 | # define SONY_RES_REG_NOT_EMP_BIT 0x04 | ||
65 | # define SONY_RES_REG_FULL_BIT 0x08 | ||
66 | |||
67 | #define LOG_START_OFFSET 150 /* Offset of first logical sector */ | ||
68 | |||
69 | #define SONY_DETECT_TIMEOUT (8*HZ/10) /* Maximum amount of time | ||
70 | that drive detection code | ||
71 | will wait for response | ||
72 | from drive (in 1/100th's | ||
73 | of seconds). */ | ||
74 | |||
75 | #define SONY_JIFFIES_TIMEOUT (10*HZ) /* Maximum number of times the | ||
76 | drive will wait/try for an | ||
77 | operation */ | ||
78 | #define SONY_RESET_TIMEOUT HZ /* Maximum number of times the | ||
79 | drive will wait/try a reset | ||
80 | operation */ | ||
81 | #define SONY_READY_RETRIES 20000 /* How many times to retry a | ||
82 | spin waiting for a register | ||
83 | to come ready */ | ||
84 | |||
85 | #define MAX_CDU31A_RETRIES 3 /* How many times to retry an | ||
86 | operation */ | ||
87 | |||
88 | /* Commands to request or set drive control parameters and disc information */ | ||
89 | #define SONY_REQ_DRIVE_CONFIG_CMD 0x00 /* Returns s_sony_drive_config */ | ||
90 | #define SONY_REQ_DRIVE_MODE_CMD 0x01 | ||
91 | #define SONY_REQ_DRIVE_PARAM_CMD 0x02 | ||
92 | #define SONY_REQ_MECH_STATUS_CMD 0x03 | ||
93 | #define SONY_REQ_AUDIO_STATUS_CMD 0x04 | ||
94 | #define SONY_SET_DRIVE_PARAM_CMD 0x10 | ||
95 | #define SONY_REQ_TOC_DATA_CMD 0x20 /* Returns s_sony_toc */ | ||
96 | #define SONY_REQ_SUBCODE_ADDRESS_CMD 0x21 /* Returns s_sony_subcode */ | ||
97 | #define SONY_REQ_UPC_EAN_CMD 0x22 | ||
98 | #define SONY_REQ_ISRC_CMD 0x23 | ||
99 | #define SONY_REQ_TOC_DATA_SPEC_CMD 0x24 /* Returns s_sony_session_toc */ | ||
100 | |||
101 | /* Commands to request information from the drive */ | ||
102 | #define SONY_READ_TOC_CMD 0x30 /* let the drive firmware grab the TOC */ | ||
103 | #define SONY_SEEK_CMD 0x31 | ||
104 | #define SONY_READ_CMD 0x32 | ||
105 | #define SONY_READ_BLKERR_STAT_CMD 0x34 | ||
106 | #define SONY_ABORT_CMD 0x35 | ||
107 | #define SONY_READ_TOC_SPEC_CMD 0x36 | ||
108 | |||
109 | /* Commands to control audio */ | ||
110 | #define SONY_AUDIO_PLAYBACK_CMD 0x40 | ||
111 | #define SONY_AUDIO_STOP_CMD 0x41 | ||
112 | #define SONY_AUDIO_SCAN_CMD 0x42 | ||
113 | |||
114 | /* Miscellaneous control commands */ | ||
115 | #define SONY_EJECT_CMD 0x50 | ||
116 | #define SONY_SPIN_UP_CMD 0x51 | ||
117 | #define SONY_SPIN_DOWN_CMD 0x52 | ||
118 | |||
119 | /* Diagnostic commands */ | ||
120 | #define SONY_WRITE_BUFFER_CMD 0x60 | ||
121 | #define SONY_READ_BUFFER_CMD 0x61 | ||
122 | #define SONY_DIAGNOSTICS_CMD 0x62 | ||
123 | |||
124 | |||
125 | /* | ||
126 | * The following are command parameters for the set drive parameter command | ||
127 | */ | ||
128 | #define SONY_SD_DECODE_PARAM 0x00 | ||
129 | #define SONY_SD_INTERFACE_PARAM 0x01 | ||
130 | #define SONY_SD_BUFFERING_PARAM 0x02 | ||
131 | #define SONY_SD_AUDIO_PARAM 0x03 | ||
132 | #define SONY_SD_AUDIO_VOLUME 0x04 | ||
133 | #define SONY_SD_MECH_CONTROL 0x05 | ||
134 | #define SONY_SD_AUTO_SPIN_DOWN_TIME 0x06 | ||
135 | |||
136 | /* | ||
137 | * The following are parameter bits for the mechanical control command | ||
138 | */ | ||
139 | #define SONY_AUTO_SPIN_UP_BIT 0x01 | ||
140 | #define SONY_AUTO_EJECT_BIT 0x02 | ||
141 | #define SONY_DOUBLE_SPEED_BIT 0x04 | ||
142 | |||
143 | /* | ||
144 | * The following extract information from the drive configuration about | ||
145 | * the drive itself. | ||
146 | */ | ||
147 | #define SONY_HWC_GET_LOAD_MECH(c) (c.hw_config[0] & 0x03) | ||
148 | #define SONY_HWC_EJECT(c) (c.hw_config[0] & 0x04) | ||
149 | #define SONY_HWC_LED_SUPPORT(c) (c.hw_config[0] & 0x08) | ||
150 | #define SONY_HWC_DOUBLE_SPEED(c) (c.hw_config[0] & 0x10) | ||
151 | #define SONY_HWC_GET_BUF_MEM_SIZE(c) ((c.hw_config[0] & 0xc0) >> 6) | ||
152 | #define SONY_HWC_AUDIO_PLAYBACK(c) (c.hw_config[1] & 0x01) | ||
153 | #define SONY_HWC_ELECTRIC_VOLUME(c) (c.hw_config[1] & 0x02) | ||
154 | #define SONY_HWC_ELECTRIC_VOLUME_CTL(c) (c.hw_config[1] & 0x04) | ||
155 | |||
156 | #define SONY_HWC_CADDY_LOAD_MECH 0x00 | ||
157 | #define SONY_HWC_TRAY_LOAD_MECH 0x01 | ||
158 | #define SONY_HWC_POPUP_LOAD_MECH 0x02 | ||
159 | #define SONY_HWC_UNKWN_LOAD_MECH 0x03 | ||
160 | |||
161 | #define SONY_HWC_8KB_BUFFER 0x00 | ||
162 | #define SONY_HWC_32KB_BUFFER 0x01 | ||
163 | #define SONY_HWC_64KB_BUFFER 0x02 | ||
164 | #define SONY_HWC_UNKWN_BUFFER 0x03 | ||
165 | |||
166 | /* | ||
167 | * This is the complete status returned from the drive configuration request | ||
168 | * command. | ||
169 | */ | ||
170 | struct s_sony_drive_config | ||
171 | { | ||
172 | unsigned char exec_status[2]; | ||
173 | char vendor_id[8]; | ||
174 | char product_id[16]; | ||
175 | char product_rev_level[8]; | ||
176 | unsigned char hw_config[2]; | ||
177 | }; | ||
178 | |||
179 | /* The following is returned from the request subcode address command */ | ||
180 | struct s_sony_subcode | ||
181 | { | ||
182 | unsigned char exec_status[2]; | ||
183 | unsigned char address :4; | ||
184 | unsigned char control :4; | ||
185 | unsigned char track_num; | ||
186 | unsigned char index_num; | ||
187 | unsigned char rel_msf[3]; | ||
188 | unsigned char reserved1; | ||
189 | unsigned char abs_msf[3]; | ||
190 | }; | ||
191 | |||
192 | #define MAX_TRACKS 100 /* The maximum tracks a disk may have. */ | ||
193 | /* | ||
194 | * The following is returned from the request TOC (Table Of Contents) command. | ||
195 | * (last_track_num-first_track_num+1) values are valid in tracks. | ||
196 | */ | ||
197 | struct s_sony_toc | ||
198 | { | ||
199 | unsigned char exec_status[2]; | ||
200 | unsigned char address0 :4; | ||
201 | unsigned char control0 :4; | ||
202 | unsigned char point0; | ||
203 | unsigned char first_track_num; | ||
204 | unsigned char disk_type; | ||
205 | unsigned char dummy0; | ||
206 | unsigned char address1 :4; | ||
207 | unsigned char control1 :4; | ||
208 | unsigned char point1; | ||
209 | unsigned char last_track_num; | ||
210 | unsigned char dummy1; | ||
211 | unsigned char dummy2; | ||
212 | unsigned char address2 :4; | ||
213 | unsigned char control2 :4; | ||
214 | unsigned char point2; | ||
215 | unsigned char lead_out_start_msf[3]; | ||
216 | struct | ||
217 | { | ||
218 | unsigned char address :4; | ||
219 | unsigned char control :4; | ||
220 | unsigned char track; | ||
221 | unsigned char track_start_msf[3]; | ||
222 | } tracks[MAX_TRACKS]; | ||
223 | |||
224 | unsigned int lead_out_start_lba; | ||
225 | }; | ||
226 | |||
227 | struct s_sony_session_toc | ||
228 | { | ||
229 | unsigned char exec_status[2]; | ||
230 | unsigned char session_number; | ||
231 | unsigned char address0 :4; | ||
232 | unsigned char control0 :4; | ||
233 | unsigned char point0; | ||
234 | unsigned char first_track_num; | ||
235 | unsigned char disk_type; | ||
236 | unsigned char dummy0; | ||
237 | unsigned char address1 :4; | ||
238 | unsigned char control1 :4; | ||
239 | unsigned char point1; | ||
240 | unsigned char last_track_num; | ||
241 | unsigned char dummy1; | ||
242 | unsigned char dummy2; | ||
243 | unsigned char address2 :4; | ||
244 | unsigned char control2 :4; | ||
245 | unsigned char point2; | ||
246 | unsigned char lead_out_start_msf[3]; | ||
247 | unsigned char addressb0 :4; | ||
248 | unsigned char controlb0 :4; | ||
249 | unsigned char pointb0; | ||
250 | unsigned char next_poss_prog_area_msf[3]; | ||
251 | unsigned char num_mode_5_pointers; | ||
252 | unsigned char max_start_outer_leadout_msf[3]; | ||
253 | unsigned char addressb1 :4; | ||
254 | unsigned char controlb1 :4; | ||
255 | unsigned char pointb1; | ||
256 | unsigned char dummyb0_1[4]; | ||
257 | unsigned char num_skip_interval_pointers; | ||
258 | unsigned char num_skip_track_assignments; | ||
259 | unsigned char dummyb0_2; | ||
260 | unsigned char addressb2 :4; | ||
261 | unsigned char controlb2 :4; | ||
262 | unsigned char pointb2; | ||
263 | unsigned char tracksb2[7]; | ||
264 | unsigned char addressb3 :4; | ||
265 | unsigned char controlb3 :4; | ||
266 | unsigned char pointb3; | ||
267 | unsigned char tracksb3[7]; | ||
268 | unsigned char addressb4 :4; | ||
269 | unsigned char controlb4 :4; | ||
270 | unsigned char pointb4; | ||
271 | unsigned char tracksb4[7]; | ||
272 | unsigned char addressc0 :4; | ||
273 | unsigned char controlc0 :4; | ||
274 | unsigned char pointc0; | ||
275 | unsigned char dummyc0[7]; | ||
276 | struct | ||
277 | { | ||
278 | unsigned char address :4; | ||
279 | unsigned char control :4; | ||
280 | unsigned char track; | ||
281 | unsigned char track_start_msf[3]; | ||
282 | } tracks[MAX_TRACKS]; | ||
283 | |||
284 | unsigned int start_track_lba; | ||
285 | unsigned int lead_out_start_lba; | ||
286 | unsigned int mint; | ||
287 | unsigned int maxt; | ||
288 | }; | ||
289 | |||
290 | struct s_all_sessions_toc | ||
291 | { | ||
292 | unsigned char sessions; | ||
293 | unsigned int track_entries; | ||
294 | unsigned char first_track_num; | ||
295 | unsigned char last_track_num; | ||
296 | unsigned char disk_type; | ||
297 | unsigned char lead_out_start_msf[3]; | ||
298 | struct | ||
299 | { | ||
300 | unsigned char address :4; | ||
301 | unsigned char control :4; | ||
302 | unsigned char track; | ||
303 | unsigned char track_start_msf[3]; | ||
304 | } tracks[MAX_TRACKS]; | ||
305 | |||
306 | unsigned int start_track_lba; | ||
307 | unsigned int lead_out_start_lba; | ||
308 | }; | ||
309 | |||
310 | |||
311 | /* | ||
312 | * The following are errors returned from the drive. | ||
313 | */ | ||
314 | |||
315 | /* Command error group */ | ||
316 | #define SONY_ILL_CMD_ERR 0x10 | ||
317 | #define SONY_ILL_PARAM_ERR 0x11 | ||
318 | |||
319 | /* Mechanism group */ | ||
320 | #define SONY_NOT_LOAD_ERR 0x20 | ||
321 | #define SONY_NO_DISK_ERR 0x21 | ||
322 | #define SONY_NOT_SPIN_ERR 0x22 | ||
323 | #define SONY_SPIN_ERR 0x23 | ||
324 | #define SONY_SPINDLE_SERVO_ERR 0x25 | ||
325 | #define SONY_FOCUS_SERVO_ERR 0x26 | ||
326 | #define SONY_EJECT_MECH_ERR 0x29 | ||
327 | #define SONY_AUDIO_PLAYING_ERR 0x2a | ||
328 | #define SONY_EMERGENCY_EJECT_ERR 0x2c | ||
329 | |||
330 | /* Seek error group */ | ||
331 | #define SONY_FOCUS_ERR 0x30 | ||
332 | #define SONY_FRAME_SYNC_ERR 0x31 | ||
333 | #define SONY_SUBCODE_ADDR_ERR 0x32 | ||
334 | #define SONY_BLOCK_SYNC_ERR 0x33 | ||
335 | #define SONY_HEADER_ADDR_ERR 0x34 | ||
336 | |||
337 | /* Read error group */ | ||
338 | #define SONY_ILL_TRACK_R_ERR 0x40 | ||
339 | #define SONY_MODE_0_R_ERR 0x41 | ||
340 | #define SONY_ILL_MODE_R_ERR 0x42 | ||
341 | #define SONY_ILL_BLOCK_SIZE_R_ERR 0x43 | ||
342 | #define SONY_MODE_R_ERR 0x44 | ||
343 | #define SONY_FORM_R_ERR 0x45 | ||
344 | #define SONY_LEAD_OUT_R_ERR 0x46 | ||
345 | #define SONY_BUFFER_OVERRUN_R_ERR 0x47 | ||
346 | |||
347 | /* Data error group */ | ||
348 | #define SONY_UNREC_CIRC_ERR 0x53 | ||
349 | #define SONY_UNREC_LECC_ERR 0x57 | ||
350 | |||
351 | /* Subcode error group */ | ||
352 | #define SONY_NO_TOC_ERR 0x60 | ||
353 | #define SONY_SUBCODE_DATA_NVAL_ERR 0x61 | ||
354 | #define SONY_FOCUS_ON_TOC_READ_ERR 0x63 | ||
355 | #define SONY_FRAME_SYNC_ON_TOC_READ_ERR 0x64 | ||
356 | #define SONY_TOC_DATA_ERR 0x65 | ||
357 | |||
358 | /* Hardware failure group */ | ||
359 | #define SONY_HW_FAILURE_ERR 0x70 | ||
360 | #define SONY_LEAD_IN_A_ERR 0x91 | ||
361 | #define SONY_LEAD_OUT_A_ERR 0x92 | ||
362 | #define SONY_DATA_TRACK_A_ERR 0x93 | ||
363 | |||
364 | /* | ||
365 | * The following are returned from the Read With Block Error Status command. | ||
366 | * They are not errors but information (Errors from the 0x5x group above may | ||
367 | * also be returned | ||
368 | */ | ||
369 | #define SONY_NO_CIRC_ERR_BLK_STAT 0x50 | ||
370 | #define SONY_NO_LECC_ERR_BLK_STAT 0x54 | ||
371 | #define SONY_RECOV_LECC_ERR_BLK_STAT 0x55 | ||
372 | #define SONY_NO_ERR_DETECTION_STAT 0x59 | ||
373 | |||
374 | /* | ||
375 | * The following is not an error returned by the drive, but by the code | ||
376 | * that talks to the drive. It is returned because of a timeout. | ||
377 | */ | ||
378 | #define SONY_TIMEOUT_OP_ERR 0x01 | ||
379 | #define SONY_SIGNAL_OP_ERR 0x02 | ||
380 | #define SONY_BAD_DATA_ERR 0x03 | ||
381 | |||
382 | |||
383 | /* | ||
384 | * The following are attention code for asynchronous events from the drive. | ||
385 | */ | ||
386 | |||
387 | /* Standard attention group */ | ||
388 | #define SONY_EMER_EJECT_ATTN 0x2c | ||
389 | #define SONY_HW_FAILURE_ATTN 0x70 | ||
390 | #define SONY_MECH_LOADED_ATTN 0x80 | ||
391 | #define SONY_EJECT_PUSHED_ATTN 0x81 | ||
392 | |||
393 | /* Audio attention group */ | ||
394 | #define SONY_AUDIO_PLAY_DONE_ATTN 0x90 | ||
395 | #define SONY_LEAD_IN_ERR_ATTN 0x91 | ||
396 | #define SONY_LEAD_OUT_ERR_ATTN 0x92 | ||
397 | #define SONY_DATA_TRACK_ERR_ATTN 0x93 | ||
398 | #define SONY_AUDIO_PLAYBACK_ERR_ATTN 0x94 | ||
399 | |||
400 | /* Auto spin up group */ | ||
401 | #define SONY_SPIN_UP_COMPLETE_ATTN 0x24 | ||
402 | #define SONY_SPINDLE_SERVO_ERR_ATTN 0x25 | ||
403 | #define SONY_FOCUS_SERVO_ERR_ATTN 0x26 | ||
404 | #define SONY_TOC_READ_DONE_ATTN 0x62 | ||
405 | #define SONY_FOCUS_ON_TOC_READ_ERR_ATTN 0x63 | ||
406 | #define SONY_SYNC_ON_TOC_READ_ERR_ATTN 0x65 | ||
407 | |||
408 | /* Auto eject group */ | ||
409 | #define SONY_SPIN_DOWN_COMPLETE_ATTN 0x27 | ||
410 | #define SONY_EJECT_COMPLETE_ATTN 0x28 | ||
411 | #define SONY_EJECT_MECH_ERR_ATTN 0x29 | ||
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c deleted file mode 100644 index 230131163240..000000000000 --- a/drivers/cdrom/cm206.c +++ /dev/null | |||
@@ -1,1594 +0,0 @@ | |||
1 | /* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card. | ||
2 | Copyright (c) 1995--1997 David A. van Leeuwen. | ||
3 | $Id: cm206.c,v 1.5 1997/12/26 11:02:51 david Exp $ | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | History: | ||
20 | Started 25 jan 1994. Waiting for documentation... | ||
21 | 22 feb 1995: 0.1a first reasonably safe polling driver. | ||
22 | Two major bugs, one in read_sector and one in | ||
23 | do_cm206_request, happened to cancel! | ||
24 | 25 feb 1995: 0.2a first reasonable interrupt driven version of above. | ||
25 | uart writes are still done in polling mode. | ||
26 | 25 feb 1995: 0.21a writes also in interrupt mode, still some | ||
27 | small bugs to be found... Larger buffer. | ||
28 | 2 mrt 1995: 0.22 Bug found (cd-> nowhere, interrupt was called in | ||
29 | initialization), read_ahead of 16. Timeouts implemented. | ||
30 | unclear if they do something... | ||
31 | 7 mrt 1995: 0.23 Start of background read-ahead. | ||
32 | 18 mrt 1995: 0.24 Working background read-ahead. (still problems) | ||
33 | 26 mrt 1995: 0.25 Multi-session ioctl added (kernel v1.2). | ||
34 | Statistics implemented, though separate stats206.h. | ||
35 | Accessible through ioctl 0x1000 (just a number). | ||
36 | Hard to choose between v1.2 development and 1.1.75. | ||
37 | Bottom-half doesn't work with 1.2... | ||
38 | 0.25a: fixed... typo. Still problems... | ||
39 | 1 apr 1995: 0.26 Module support added. Most bugs found. Use kernel 1.2.n. | ||
40 | 5 apr 1995: 0.27 Auto-probe for the adapter card base address. | ||
41 | Auto-probe for the adaptor card irq line. | ||
42 | 7 apr 1995: 0.28 Added lilo setup support for base address and irq. | ||
43 | Use major number 32 (not in this source), officially | ||
44 | assigned to this driver. | ||
45 | 9 apr 1995: 0.29 Added very limited audio support. Toc_header, stop, pause, | ||
46 | resume, eject. Play_track ignores track info, because we can't | ||
47 | read a table-of-contents entry. Toc_entry is implemented | ||
48 | as a `placebo' function: always returns start of disc. | ||
49 | 3 may 1995: 0.30 Audio support completed. The get_toc_entry function | ||
50 | is implemented as a binary search. | ||
51 | 15 may 1995: 0.31 More work on audio stuff. Workman is not easy to | ||
52 | satisfy; changed binary search into linear search. | ||
53 | Auto-probe for base address somewhat relaxed. | ||
54 | 1 jun 1995: 0.32 Removed probe_irq_on/off for module version. | ||
55 | 10 jun 1995: 0.33 Workman still behaves funny, but you should be | ||
56 | able to eject and substitute another disc. | ||
57 | |||
58 | An adaptation of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg | ||
59 | |||
60 | 18 jul 1995: 0.34 Patch by Heiko Eissfeldt included, mainly considering | ||
61 | verify_area's in the ioctls. Some bugs introduced by | ||
62 | EM considering the base port and irq fixed. | ||
63 | |||
64 | 18 dec 1995: 0.35 Add some code for error checking... no luck... | ||
65 | |||
66 | We jump to reach our goal: version 1.0 in the next stable linux kernel. | ||
67 | |||
68 | 19 mar 1996: 0.95 Different implementation of CDROM_GET_UPC, on | ||
69 | request of Thomas Quinot. | ||
70 | 25 mar 1996: 0.96 Interpretation of opening with O_WRONLY or O_RDWR: | ||
71 | open only for ioctl operation, e.g., for operation of | ||
72 | tray etc. | ||
73 | 4 apr 1996: 0.97 First implementation of layer between VFS and cdrom | ||
74 | driver, a generic interface. Much of the functionality | ||
75 | of cm206_open() and cm206_ioctl() is transferred to a | ||
76 | new file cdrom.c and its header ucdrom.h. | ||
77 | |||
78 | Upgrade to Linux kernel 1.3.78. | ||
79 | |||
80 | 11 apr 1996 0.98 Upgrade to Linux kernel 1.3.85 | ||
81 | More code moved to cdrom.c | ||
82 | |||
83 | 0.99 Some more small changes to decrease number | ||
84 | of oopses at module load; | ||
85 | |||
86 | 27 jul 1996 0.100 Many hours of debugging, kernel change from 1.2.13 | ||
87 | to 2.0.7 seems to have introduced some weird behavior | ||
88 | in (interruptible_)sleep_on(&cd->data): the process | ||
89 | seems to be woken without any explicit wake_up in my own | ||
90 | code. Patch to try 100x in case such untriggered wake_up's | ||
91 | occur. | ||
92 | |||
93 | 28 jul 1996 0.101 Rewriting of the code that receives the command echo, | ||
94 | using a fifo to store echoed bytes. | ||
95 | |||
96 | Branch from 0.99: | ||
97 | |||
98 | 0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t | ||
99 | (emoenke) various typos found by others. extra | ||
100 | module-load oops protection. | ||
101 | |||
102 | 0.99.1.1 Initialization constant cdrom_dops.speed | ||
103 | changed from float (2.0) to int (2); Cli()-sti() pair | ||
104 | around cm260_reset() in module initialization code. | ||
105 | |||
106 | 0.99.1.2 Changes literally as proposed by Scott Snyder | ||
107 | <snyder@d0sgif.fnal.gov> for the 2.1 kernel line, which | ||
108 | have to do mainly with the poor minor support i had. The | ||
109 | major new concept is to change a cdrom driver's | ||
110 | operations struct from the capabilities struct. This | ||
111 | reflects the fact that there is one major for a driver, | ||
112 | whilst there can be many minors whith completely | ||
113 | different capabilities. | ||
114 | |||
115 | 0.99.1.3 More changes for operations/info separation. | ||
116 | |||
117 | 0.99.1.4 Added speed selection (someone had to do this | ||
118 | first). | ||
119 | |||
120 | 23 jan 1997 0.99.1.5 MODULE_PARMS call added. | ||
121 | |||
122 | 23 jan 1997 0.100.1.2--0.100.1.5 following similar lines as | ||
123 | 0.99.1.1--0.99.1.5. I get too many complaints about the | ||
124 | drive making read errors. What't wrong with the 2.0+ | ||
125 | kernel line? Why get i (and othe cm206 owners) weird | ||
126 | results? Why were things good in the good old 1.1--1.2 | ||
127 | era? Why don't i throw away the drive? | ||
128 | |||
129 | 2 feb 1997 0.102 Added `volatile' to values in cm206_struct. Seems to | ||
130 | reduce many of the problems. Rewrote polling routines | ||
131 | to use fixed delays between polls. | ||
132 | 0.103 Changed printk behavior. | ||
133 | 0.104 Added a 0.100 -> 0.100.1.1 change | ||
134 | |||
135 | 11 feb 1997 0.105 Allow auto_probe during module load, disable | ||
136 | with module option "auto_probe=0". Moved some debugging | ||
137 | statements to lower priority. Implemented select_speed() | ||
138 | function. | ||
139 | |||
140 | 13 feb 1997 1.0 Final version for 2.0 kernel line. | ||
141 | |||
142 | All following changes will be for the 2.1 kernel line. | ||
143 | |||
144 | 15 feb 1997 1.1 Keep up with kernel 2.1.26, merge in changes from | ||
145 | cdrom.c 0.100.1.1--1.0. Add some more MODULE_PARMS. | ||
146 | |||
147 | 14 sep 1997 1.2 Upgrade to Linux 2.1.55. Added blksize_size[], patch | ||
148 | sent by James Bottomley <James.Bottomley@columbiasc.ncr.com>. | ||
149 | |||
150 | 21 dec 1997 1.4 Upgrade to Linux 2.1.72. | ||
151 | |||
152 | 24 jan 1998 Removed the cm206_disc_status() function, as it was now dead | ||
153 | code. The Uniform CDROM driver now provides this functionality. | ||
154 | |||
155 | 9 Nov. 1999 Make kernel-parameter implementation work with 2.3.x | ||
156 | Removed init_module & cleanup_module in favor of | ||
157 | module_init & module_exit. | ||
158 | Torben Mathiasen <tmm@image.dk> | ||
159 | * | ||
160 | * Parts of the code are based upon lmscd.c written by Kai Petzke, | ||
161 | * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin | ||
162 | * Harriss, but any off-the-shelf dynamic programming algorithm won't | ||
163 | * be able to find them. | ||
164 | * | ||
165 | * The cm206 drive interface and the cm260 adapter card seem to be | ||
166 | * sufficiently different from their cm205/cm250 counterparts | ||
167 | * in order to write a complete new driver. | ||
168 | * | ||
169 | * I call all routines connected to the Linux kernel something | ||
170 | * with `cm206' in it, as this stuff is too series-dependent. | ||
171 | * | ||
172 | * Currently, my limited knowledge is based on: | ||
173 | * - The Linux Kernel Hacker's guide, v. 0.5, by Michael K. Johnson | ||
174 | * - Linux Kernel Programmierung, by Michael Beck and others | ||
175 | * - Philips/LMS cm206 and cm226 product specification | ||
176 | * - Philips/LMS cm260 product specification | ||
177 | * | ||
178 | * David van Leeuwen, david@tm.tno.nl. */ | ||
179 | #define REVISION "$Revision: 1.5 $" | ||
180 | |||
181 | #include <linux/module.h> | ||
182 | |||
183 | #include <linux/errno.h> /* These include what we really need */ | ||
184 | #include <linux/delay.h> | ||
185 | #include <linux/string.h> | ||
186 | #include <linux/interrupt.h> | ||
187 | #include <linux/timer.h> | ||
188 | #include <linux/cdrom.h> | ||
189 | #include <linux/ioport.h> | ||
190 | #include <linux/mm.h> | ||
191 | #include <linux/slab.h> | ||
192 | #include <linux/init.h> | ||
193 | |||
194 | /* #include <linux/ucdrom.h> */ | ||
195 | |||
196 | #include <asm/io.h> | ||
197 | |||
198 | #define MAJOR_NR CM206_CDROM_MAJOR | ||
199 | |||
200 | #include <linux/blkdev.h> | ||
201 | |||
202 | #undef DEBUG | ||
203 | #define STATISTICS /* record times and frequencies of events */ | ||
204 | #define AUTO_PROBE_MODULE | ||
205 | #define USE_INSW | ||
206 | |||
207 | #include "cm206.h" | ||
208 | |||
209 | /* This variable defines whether or not to probe for adapter base port | ||
210 | address and interrupt request. It can be overridden by the boot | ||
211 | parameter `auto'. | ||
212 | */ | ||
213 | static int auto_probe = 1; /* Yes, why not? */ | ||
214 | |||
215 | static int cm206_base = CM206_BASE; | ||
216 | static int cm206_irq = CM206_IRQ; | ||
217 | #ifdef MODULE | ||
218 | static int cm206[2] = { 0, 0 }; /* for compatible `insmod' parameter passing */ | ||
219 | module_param_array(cm206, int, NULL, 0); /* base,irq or irq,base */ | ||
220 | #endif | ||
221 | |||
222 | module_param(cm206_base, int, 0); /* base */ | ||
223 | module_param(cm206_irq, int, 0); /* irq */ | ||
224 | module_param(auto_probe, bool, 0); /* auto probe base and irq */ | ||
225 | MODULE_LICENSE("GPL"); | ||
226 | |||
227 | #define POLLOOP 100 /* milliseconds */ | ||
228 | #define READ_AHEAD 1 /* defines private buffer, waste! */ | ||
229 | #define BACK_AHEAD 1 /* defines adapter-read ahead */ | ||
230 | #define DATA_TIMEOUT (3*HZ) /* measured in jiffies (10 ms) */ | ||
231 | #define UART_TIMEOUT (5*HZ/100) | ||
232 | #define DSB_TIMEOUT (7*HZ) /* time for the slowest command to finish */ | ||
233 | #define UR_SIZE 4 /* uart receive buffer fifo size */ | ||
234 | |||
235 | #define LINUX_BLOCK_SIZE 512 /* WHERE is this defined? */ | ||
236 | #define RAW_SECTOR_SIZE 2352 /* ok, is also defined in cdrom.h */ | ||
237 | #define ISO_SECTOR_SIZE 2048 | ||
238 | #define BLOCKS_ISO (ISO_SECTOR_SIZE/LINUX_BLOCK_SIZE) /* 4 */ | ||
239 | #define CD_SYNC_HEAD 16 /* CD_SYNC + CD_HEAD */ | ||
240 | |||
241 | #ifdef STATISTICS /* keep track of errors in counters */ | ||
242 | #define stats(i) { ++cd->stats[st_ ## i]; \ | ||
243 | cd->last_stat[st_ ## i] = cd->stat_counter++; \ | ||
244 | } | ||
245 | #else | ||
246 | #define stats(i) (void) 0; | ||
247 | #endif | ||
248 | |||
249 | #define Debug(a) {printk (KERN_DEBUG); printk a;} | ||
250 | #ifdef DEBUG | ||
251 | #define debug(a) Debug(a) | ||
252 | #else | ||
253 | #define debug(a) (void) 0; | ||
254 | #endif | ||
255 | |||
256 | typedef unsigned char uch; /* 8-bits */ | ||
257 | typedef unsigned short ush; /* 16-bits */ | ||
258 | |||
259 | struct toc_struct { /* private copy of Table of Contents */ | ||
260 | uch track, fsm[3], q0; | ||
261 | }; | ||
262 | |||
263 | struct cm206_struct { | ||
264 | volatile ush intr_ds; /* data status read on last interrupt */ | ||
265 | volatile ush intr_ls; /* uart line status read on last interrupt */ | ||
266 | volatile uch ur[UR_SIZE]; /* uart receive buffer fifo */ | ||
267 | volatile uch ur_w, ur_r; /* write/read buffer index */ | ||
268 | volatile uch dsb, cc; /* drive status byte and condition (error) code */ | ||
269 | int command; /* command to be written to the uart */ | ||
270 | int openfiles; | ||
271 | ush sector[READ_AHEAD * RAW_SECTOR_SIZE / 2]; /* buffered cd-sector */ | ||
272 | int sector_first, sector_last; /* range of these sectors */ | ||
273 | wait_queue_head_t uart; /* wait queues for interrupt */ | ||
274 | wait_queue_head_t data; | ||
275 | struct timer_list timer; /* time-out */ | ||
276 | char timed_out; | ||
277 | signed char max_sectors; /* number of sectors that fit in adapter mem */ | ||
278 | char wait_back; /* we're waiting for a background-read */ | ||
279 | char background; /* is a read going on in the background? */ | ||
280 | int adapter_first; /* if so, that's the starting sector */ | ||
281 | int adapter_last; | ||
282 | char fifo_overflowed; | ||
283 | uch disc_status[7]; /* result of get_disc_status command */ | ||
284 | #ifdef STATISTICS | ||
285 | int stats[NR_STATS]; | ||
286 | int last_stat[NR_STATS]; /* `time' at which stat was stat */ | ||
287 | int stat_counter; | ||
288 | #endif | ||
289 | struct toc_struct toc[101]; /* The whole table of contents + lead-out */ | ||
290 | uch q[10]; /* Last read q-channel info */ | ||
291 | uch audio_status[5]; /* last read position on pause */ | ||
292 | uch media_changed; /* record if media changed */ | ||
293 | }; | ||
294 | |||
295 | #define DISC_STATUS cd->disc_status[0] | ||
296 | #define FIRST_TRACK cd->disc_status[1] | ||
297 | #define LAST_TRACK cd->disc_status[2] | ||
298 | #define PAUSED cd->audio_status[0] /* misuse this memory byte! */ | ||
299 | #define PLAY_TO cd->toc[0] /* toc[0] records end-time in play */ | ||
300 | |||
301 | static struct cm206_struct *cd; /* the main memory structure */ | ||
302 | static struct request_queue *cm206_queue; | ||
303 | static DEFINE_SPINLOCK(cm206_lock); | ||
304 | |||
305 | /* First, we define some polling functions. These are actually | ||
306 | only being used in the initialization. */ | ||
307 | |||
308 | static void send_command_polled(int command) | ||
309 | { | ||
310 | int loop = POLLOOP; | ||
311 | while (!(inw(r_line_status) & ls_transmitter_buffer_empty) | ||
312 | && loop > 0) { | ||
313 | mdelay(1); /* one millisec delay */ | ||
314 | --loop; | ||
315 | } | ||
316 | outw(command, r_uart_transmit); | ||
317 | } | ||
318 | |||
319 | static uch receive_echo_polled(void) | ||
320 | { | ||
321 | int loop = POLLOOP; | ||
322 | while (!(inw(r_line_status) & ls_receive_buffer_full) && loop > 0) { | ||
323 | mdelay(1); | ||
324 | --loop; | ||
325 | } | ||
326 | return ((uch) inw(r_uart_receive)); | ||
327 | } | ||
328 | |||
329 | static uch send_receive_polled(int command) | ||
330 | { | ||
331 | send_command_polled(command); | ||
332 | return receive_echo_polled(); | ||
333 | } | ||
334 | |||
335 | static inline void clear_ur(void) | ||
336 | { | ||
337 | if (cd->ur_r != cd->ur_w) { | ||
338 | debug(("Deleting bytes from fifo:")); | ||
339 | for (; cd->ur_r != cd->ur_w; | ||
340 | cd->ur_r++, cd->ur_r %= UR_SIZE) | ||
341 | debug((" 0x%x", cd->ur[cd->ur_r])); | ||
342 | debug(("\n")); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | static struct tasklet_struct cm206_tasklet; | ||
347 | |||
348 | /* The interrupt handler. When the cm260 generates an interrupt, very | ||
349 | much care has to be taken in reading out the registers in the right | ||
350 | order; in case of a receive_buffer_full interrupt, first the | ||
351 | uart_receive must be read, and then the line status again to | ||
352 | de-assert the interrupt line. It took me a couple of hours to find | ||
353 | this out:-( | ||
354 | |||
355 | The function reset_cm206 appears to cause an interrupt, because | ||
356 | pulling up the INIT line clears both the uart-write-buffer /and/ | ||
357 | the uart-write-buffer-empty mask. We call this a `lost interrupt,' | ||
358 | as there seems so reason for this to happen. | ||
359 | */ | ||
360 | |||
361 | static irqreturn_t cm206_interrupt(int sig, void *dev_id) | ||
362 | { | ||
363 | volatile ush fool; | ||
364 | cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error, | ||
365 | crc_error, sync_error, toc_ready | ||
366 | interrupts */ | ||
367 | cd->intr_ls = inw(r_line_status); /* resets overrun bit */ | ||
368 | debug(("Intr, 0x%x 0x%x, %d\n", cd->intr_ds, cd->intr_ls, | ||
369 | cd->background)); | ||
370 | if (cd->intr_ls & ls_attention) | ||
371 | stats(attention); | ||
372 | /* receive buffer full? */ | ||
373 | if (cd->intr_ls & ls_receive_buffer_full) { | ||
374 | cd->ur[cd->ur_w] = inb(r_uart_receive); /* get order right! */ | ||
375 | cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */ | ||
376 | debug(("receiving #%d: 0x%x\n", cd->ur_w, | ||
377 | cd->ur[cd->ur_w])); | ||
378 | cd->ur_w++; | ||
379 | cd->ur_w %= UR_SIZE; | ||
380 | if (cd->ur_w == cd->ur_r) | ||
381 | debug(("cd->ur overflow!\n")); | ||
382 | if (waitqueue_active(&cd->uart) && cd->background < 2) { | ||
383 | del_timer(&cd->timer); | ||
384 | wake_up_interruptible(&cd->uart); | ||
385 | } | ||
386 | } | ||
387 | /* data ready in fifo? */ | ||
388 | else if (cd->intr_ds & ds_data_ready) { | ||
389 | if (cd->background) | ||
390 | ++cd->adapter_last; | ||
391 | if (waitqueue_active(&cd->data) | ||
392 | && (cd->wait_back || !cd->background)) { | ||
393 | del_timer(&cd->timer); | ||
394 | wake_up_interruptible(&cd->data); | ||
395 | } | ||
396 | stats(data_ready); | ||
397 | } | ||
398 | /* ready to issue a write command? */ | ||
399 | else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) { | ||
400 | outw(dc_normal | (inw(r_data_status) & 0x7f), | ||
401 | r_data_control); | ||
402 | outw(cd->command, r_uart_transmit); | ||
403 | cd->command = 0; | ||
404 | if (!cd->background) | ||
405 | wake_up_interruptible(&cd->uart); | ||
406 | } | ||
407 | /* now treat errors (at least, identify them for debugging) */ | ||
408 | else if (cd->intr_ds & ds_fifo_overflow) { | ||
409 | debug(("Fifo overflow at sectors 0x%x\n", | ||
410 | cd->sector_first)); | ||
411 | fool = inw(r_fifo_output_buffer); /* de-assert the interrupt */ | ||
412 | cd->fifo_overflowed = 1; /* signal one word less should be read */ | ||
413 | stats(fifo_overflow); | ||
414 | } else if (cd->intr_ds & ds_data_error) { | ||
415 | debug(("Data error at sector 0x%x\n", cd->sector_first)); | ||
416 | stats(data_error); | ||
417 | } else if (cd->intr_ds & ds_crc_error) { | ||
418 | debug(("CRC error at sector 0x%x\n", cd->sector_first)); | ||
419 | stats(crc_error); | ||
420 | } else if (cd->intr_ds & ds_sync_error) { | ||
421 | debug(("Sync at sector 0x%x\n", cd->sector_first)); | ||
422 | stats(sync_error); | ||
423 | } else if (cd->intr_ds & ds_toc_ready) { | ||
424 | /* do something appropriate */ | ||
425 | } | ||
426 | /* couldn't see why this interrupt, maybe due to init */ | ||
427 | else { | ||
428 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
429 | stats(lost_intr); | ||
430 | } | ||
431 | if (cd->background | ||
432 | && (cd->adapter_last - cd->adapter_first == cd->max_sectors | ||
433 | || cd->fifo_overflowed)) | ||
434 | tasklet_schedule(&cm206_tasklet); /* issue a stop read command */ | ||
435 | stats(interrupt); | ||
436 | return IRQ_HANDLED; | ||
437 | } | ||
438 | |||
439 | /* we have put the address of the wait queue in who */ | ||
440 | static void cm206_timeout(unsigned long who) | ||
441 | { | ||
442 | cd->timed_out = 1; | ||
443 | debug(("Timing out\n")); | ||
444 | wake_up_interruptible((wait_queue_head_t *) who); | ||
445 | } | ||
446 | |||
447 | /* This function returns 1 if a timeout occurred, 0 if an interrupt | ||
448 | happened */ | ||
449 | static int sleep_or_timeout(wait_queue_head_t * wait, int timeout) | ||
450 | { | ||
451 | cd->timed_out = 0; | ||
452 | init_timer(&cd->timer); | ||
453 | cd->timer.data = (unsigned long) wait; | ||
454 | cd->timer.expires = jiffies + timeout; | ||
455 | add_timer(&cd->timer); | ||
456 | debug(("going to sleep\n")); | ||
457 | interruptible_sleep_on(wait); | ||
458 | del_timer(&cd->timer); | ||
459 | if (cd->timed_out) { | ||
460 | cd->timed_out = 0; | ||
461 | return 1; | ||
462 | } else | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static void send_command(int command) | ||
467 | { | ||
468 | debug(("Sending 0x%x\n", command)); | ||
469 | if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) { | ||
470 | cd->command = command; | ||
471 | cli(); /* don't interrupt before sleep */ | ||
472 | outw(dc_mask_sync_error | dc_no_stop_on_error | | ||
473 | (inw(r_data_status) & 0x7f), r_data_control); | ||
474 | /* interrupt routine sends command */ | ||
475 | if (sleep_or_timeout(&cd->uart, UART_TIMEOUT)) { | ||
476 | debug(("Time out on write-buffer\n")); | ||
477 | stats(write_timeout); | ||
478 | outw(command, r_uart_transmit); | ||
479 | } | ||
480 | debug(("Write commmand delayed\n")); | ||
481 | } else | ||
482 | outw(command, r_uart_transmit); | ||
483 | } | ||
484 | |||
485 | static uch receive_byte(int timeout) | ||
486 | { | ||
487 | uch ret; | ||
488 | cli(); | ||
489 | debug(("cli\n")); | ||
490 | ret = cd->ur[cd->ur_r]; | ||
491 | if (cd->ur_r != cd->ur_w) { | ||
492 | sti(); | ||
493 | debug(("returning #%d: 0x%x\n", cd->ur_r, | ||
494 | cd->ur[cd->ur_r])); | ||
495 | cd->ur_r++; | ||
496 | cd->ur_r %= UR_SIZE; | ||
497 | return ret; | ||
498 | } else if (sleep_or_timeout(&cd->uart, timeout)) { /* does sti() */ | ||
499 | debug(("Time out on receive-buffer\n")); | ||
500 | #ifdef STATISTICS | ||
501 | if (timeout == UART_TIMEOUT) | ||
502 | stats(receive_timeout) /* no `;'! */ | ||
503 | else | ||
504 | stats(dsb_timeout); | ||
505 | #endif | ||
506 | return 0xda; | ||
507 | } | ||
508 | ret = cd->ur[cd->ur_r]; | ||
509 | debug(("slept; returning #%d: 0x%x\n", cd->ur_r, | ||
510 | cd->ur[cd->ur_r])); | ||
511 | cd->ur_r++; | ||
512 | cd->ur_r %= UR_SIZE; | ||
513 | return ret; | ||
514 | } | ||
515 | |||
516 | static inline uch receive_echo(void) | ||
517 | { | ||
518 | return receive_byte(UART_TIMEOUT); | ||
519 | } | ||
520 | |||
521 | static inline uch send_receive(int command) | ||
522 | { | ||
523 | send_command(command); | ||
524 | return receive_echo(); | ||
525 | } | ||
526 | |||
527 | static inline uch wait_dsb(void) | ||
528 | { | ||
529 | return receive_byte(DSB_TIMEOUT); | ||
530 | } | ||
531 | |||
532 | static int type_0_command(int command, int expect_dsb) | ||
533 | { | ||
534 | int e; | ||
535 | clear_ur(); | ||
536 | if (command != (e = send_receive(command))) { | ||
537 | debug(("command 0x%x echoed as 0x%x\n", command, e)); | ||
538 | stats(echo); | ||
539 | return -1; | ||
540 | } | ||
541 | if (expect_dsb) { | ||
542 | cd->dsb = wait_dsb(); /* wait for command to finish */ | ||
543 | } | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int type_1_command(int command, int bytes, uch * status) | ||
548 | { /* returns info */ | ||
549 | int i; | ||
550 | if (type_0_command(command, 0)) | ||
551 | return -1; | ||
552 | for (i = 0; i < bytes; i++) | ||
553 | status[i] = send_receive(c_gimme); | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | /* This function resets the adapter card. We'd better not do this too | ||
558 | * often, because it tends to generate `lost interrupts.' */ | ||
559 | static void reset_cm260(void) | ||
560 | { | ||
561 | outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control); | ||
562 | udelay(10); /* 3.3 mu sec minimum */ | ||
563 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
564 | } | ||
565 | |||
566 | /* fsm: frame-sec-min from linear address; one of many */ | ||
567 | static void fsm(int lba, uch * fsm) | ||
568 | { | ||
569 | fsm[0] = lba % 75; | ||
570 | lba /= 75; | ||
571 | lba += 2; | ||
572 | fsm[1] = lba % 60; | ||
573 | fsm[2] = lba / 60; | ||
574 | } | ||
575 | |||
576 | static inline int fsm2lba(uch * fsm) | ||
577 | { | ||
578 | return fsm[0] + 75 * (fsm[1] - 2 + 60 * fsm[2]); | ||
579 | } | ||
580 | |||
581 | static inline int f_s_m2lba(uch f, uch s, uch m) | ||
582 | { | ||
583 | return f + 75 * (s - 2 + 60 * m); | ||
584 | } | ||
585 | |||
586 | static int start_read(int start) | ||
587 | { | ||
588 | uch read_sector[4] = { c_read_data, }; | ||
589 | int i, e; | ||
590 | |||
591 | fsm(start, &read_sector[1]); | ||
592 | clear_ur(); | ||
593 | for (i = 0; i < 4; i++) | ||
594 | if (read_sector[i] != (e = send_receive(read_sector[i]))) { | ||
595 | debug(("read_sector: %x echoes %x\n", | ||
596 | read_sector[i], e)); | ||
597 | stats(echo); | ||
598 | if (e == 0xff) { /* this seems to happen often */ | ||
599 | e = receive_echo(); | ||
600 | debug(("Second try %x\n", e)); | ||
601 | if (e != read_sector[i]) | ||
602 | return -1; | ||
603 | } | ||
604 | } | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int stop_read(void) | ||
609 | { | ||
610 | int e; | ||
611 | type_0_command(c_stop, 0); | ||
612 | if ((e = receive_echo()) != 0xff) { | ||
613 | debug(("c_stop didn't send 0xff, but 0x%x\n", e)); | ||
614 | stats(stop_0xff); | ||
615 | return -1; | ||
616 | } | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | /* This function starts to read sectors in adapter memory, the | ||
621 | interrupt routine should stop the read. In fact, the bottom_half | ||
622 | routine takes care of this. Set a flag `background' in the cd | ||
623 | struct to indicate the process. */ | ||
624 | |||
625 | static int read_background(int start, int reading) | ||
626 | { | ||
627 | if (cd->background) | ||
628 | return -1; /* can't do twice */ | ||
629 | outw(dc_normal | BACK_AHEAD, r_data_control); | ||
630 | if (!reading && start_read(start)) | ||
631 | return -2; | ||
632 | cd->adapter_first = cd->adapter_last = start; | ||
633 | cd->background = 1; /* flag a read is going on */ | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | #ifdef USE_INSW | ||
638 | #define transport_data insw | ||
639 | #else | ||
640 | /* this routine implements insw(,,). There was a time i had the | ||
641 | impression that there would be any difference in error-behaviour. */ | ||
642 | void transport_data(int port, ush * dest, int count) | ||
643 | { | ||
644 | int i; | ||
645 | ush *d; | ||
646 | for (i = 0, d = dest; i < count; i++, d++) | ||
647 | *d = inw(port); | ||
648 | } | ||
649 | #endif | ||
650 | |||
651 | |||
652 | #define MAX_TRIES 100 | ||
653 | static int read_sector(int start) | ||
654 | { | ||
655 | int tries = 0; | ||
656 | if (cd->background) { | ||
657 | cd->background = 0; | ||
658 | cd->adapter_last = -1; /* invalidate adapter memory */ | ||
659 | stop_read(); | ||
660 | } | ||
661 | cd->fifo_overflowed = 0; | ||
662 | reset_cm260(); /* empty fifo etc. */ | ||
663 | if (start_read(start)) | ||
664 | return -1; | ||
665 | do { | ||
666 | if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { | ||
667 | debug(("Read timed out sector 0x%x\n", start)); | ||
668 | stats(read_timeout); | ||
669 | stop_read(); | ||
670 | return -3; | ||
671 | } | ||
672 | tries++; | ||
673 | } while (cd->intr_ds & ds_fifo_empty && tries < MAX_TRIES); | ||
674 | if (tries > 1) | ||
675 | debug(("Took me some tries\n")) | ||
676 | else | ||
677 | if (tries == MAX_TRIES) | ||
678 | debug(("MAX_TRIES tries for read sector\n")); | ||
679 | transport_data(r_fifo_output_buffer, cd->sector, | ||
680 | READ_AHEAD * RAW_SECTOR_SIZE / 2); | ||
681 | if (read_background(start + READ_AHEAD, 1)) | ||
682 | stats(read_background); | ||
683 | cd->sector_first = start; | ||
684 | cd->sector_last = start + READ_AHEAD; | ||
685 | stats(read_restarted); | ||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | /* The function of bottom-half is to send a stop command to the drive | ||
690 | This isn't easy because the routine is not `owned' by any process; | ||
691 | we can't go to sleep! The variable cd->background gives the status: | ||
692 | 0 no read pending | ||
693 | 1 a read is pending | ||
694 | 2 c_stop waits for write_buffer_empty | ||
695 | 3 c_stop waits for receive_buffer_full: echo | ||
696 | 4 c_stop waits for receive_buffer_full: 0xff | ||
697 | */ | ||
698 | |||
699 | static void cm206_tasklet_func(unsigned long ignore) | ||
700 | { | ||
701 | debug(("bh: %d\n", cd->background)); | ||
702 | switch (cd->background) { | ||
703 | case 1: | ||
704 | stats(bh); | ||
705 | if (!(cd->intr_ls & ls_transmitter_buffer_empty)) { | ||
706 | cd->command = c_stop; | ||
707 | outw(dc_mask_sync_error | dc_no_stop_on_error | | ||
708 | (inw(r_data_status) & 0x7f), r_data_control); | ||
709 | cd->background = 2; | ||
710 | break; /* we'd better not time-out here! */ | ||
711 | } else | ||
712 | outw(c_stop, r_uart_transmit); | ||
713 | /* fall into case 2: */ | ||
714 | case 2: | ||
715 | /* the write has been satisfied by interrupt routine */ | ||
716 | cd->background = 3; | ||
717 | break; | ||
718 | case 3: | ||
719 | if (cd->ur_r != cd->ur_w) { | ||
720 | if (cd->ur[cd->ur_r] != c_stop) { | ||
721 | debug(("cm206_bh: c_stop echoed 0x%x\n", | ||
722 | cd->ur[cd->ur_r])); | ||
723 | stats(echo); | ||
724 | } | ||
725 | cd->ur_r++; | ||
726 | cd->ur_r %= UR_SIZE; | ||
727 | } | ||
728 | cd->background++; | ||
729 | break; | ||
730 | case 4: | ||
731 | if (cd->ur_r != cd->ur_w) { | ||
732 | if (cd->ur[cd->ur_r] != 0xff) { | ||
733 | debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->ur[cd->ur_r])); | ||
734 | stats(stop_0xff); | ||
735 | } | ||
736 | cd->ur_r++; | ||
737 | cd->ur_r %= UR_SIZE; | ||
738 | } | ||
739 | cd->background = 0; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | static DECLARE_TASKLET(cm206_tasklet, cm206_tasklet_func, 0); | ||
744 | |||
745 | /* This command clears the dsb_possible_media_change flag, so we must | ||
746 | * retain it. | ||
747 | */ | ||
748 | static void get_drive_status(void) | ||
749 | { | ||
750 | uch status[2]; | ||
751 | type_1_command(c_drive_status, 2, status); /* this might be done faster */ | ||
752 | cd->dsb = status[0]; | ||
753 | cd->cc = status[1]; | ||
754 | cd->media_changed |= | ||
755 | !!(cd->dsb & (dsb_possible_media_change | | ||
756 | dsb_drive_not_ready | dsb_tray_not_closed)); | ||
757 | } | ||
758 | |||
759 | static void get_disc_status(void) | ||
760 | { | ||
761 | if (type_1_command(c_disc_status, 7, cd->disc_status)) { | ||
762 | debug(("get_disc_status: error\n")); | ||
763 | } | ||
764 | } | ||
765 | |||
766 | /* The new open. The real opening strategy is defined in cdrom.c. */ | ||
767 | |||
768 | static int cm206_open(struct cdrom_device_info *cdi, int purpose) | ||
769 | { | ||
770 | if (!cd->openfiles) { /* reset only first time */ | ||
771 | cd->background = 0; | ||
772 | reset_cm260(); | ||
773 | cd->adapter_last = -1; /* invalidate adapter memory */ | ||
774 | cd->sector_last = -1; | ||
775 | } | ||
776 | ++cd->openfiles; | ||
777 | stats(open); | ||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static void cm206_release(struct cdrom_device_info *cdi) | ||
782 | { | ||
783 | if (cd->openfiles == 1) { | ||
784 | if (cd->background) { | ||
785 | cd->background = 0; | ||
786 | stop_read(); | ||
787 | } | ||
788 | cd->sector_last = -1; /* Make our internal buffer invalid */ | ||
789 | FIRST_TRACK = 0; /* No valid disc status */ | ||
790 | } | ||
791 | --cd->openfiles; | ||
792 | } | ||
793 | |||
794 | /* Empty buffer empties $sectors$ sectors of the adapter card buffer, | ||
795 | * and then reads a sector in kernel memory. */ | ||
796 | static void empty_buffer(int sectors) | ||
797 | { | ||
798 | while (sectors >= 0) { | ||
799 | transport_data(r_fifo_output_buffer, | ||
800 | cd->sector + cd->fifo_overflowed, | ||
801 | RAW_SECTOR_SIZE / 2 - cd->fifo_overflowed); | ||
802 | --sectors; | ||
803 | ++cd->adapter_first; /* update the current adapter sector */ | ||
804 | cd->fifo_overflowed = 0; /* reset overflow bit */ | ||
805 | stats(sector_transferred); | ||
806 | } | ||
807 | cd->sector_first = cd->adapter_first - 1; | ||
808 | cd->sector_last = cd->adapter_first; /* update the buffer sector */ | ||
809 | } | ||
810 | |||
811 | /* try_adapter. This function determines if the requested sector is | ||
812 | in adapter memory, or will appear there soon. Returns 0 upon | ||
813 | success */ | ||
814 | static int try_adapter(int sector) | ||
815 | { | ||
816 | if (cd->adapter_first <= sector && sector < cd->adapter_last) { | ||
817 | /* sector is in adapter memory */ | ||
818 | empty_buffer(sector - cd->adapter_first); | ||
819 | return 0; | ||
820 | } else if (cd->background == 1 && cd->adapter_first <= sector | ||
821 | && sector < cd->adapter_first + cd->max_sectors) { | ||
822 | /* a read is going on, we can wait for it */ | ||
823 | cd->wait_back = 1; | ||
824 | while (sector >= cd->adapter_last) { | ||
825 | if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { | ||
826 | debug(("Timed out during background wait: %d %d %d %d\n", sector, cd->adapter_last, cd->adapter_first, cd->background)); | ||
827 | stats(back_read_timeout); | ||
828 | cd->wait_back = 0; | ||
829 | return -1; | ||
830 | } | ||
831 | } | ||
832 | cd->wait_back = 0; | ||
833 | empty_buffer(sector - cd->adapter_first); | ||
834 | return 0; | ||
835 | } else | ||
836 | return -2; | ||
837 | } | ||
838 | |||
839 | /* This is not a very smart implementation. We could optimize for | ||
840 | consecutive block numbers. I'm not convinced this would really | ||
841 | bring down the processor load. */ | ||
842 | static void do_cm206_request(request_queue_t * q) | ||
843 | { | ||
844 | long int i, cd_sec_no; | ||
845 | int quarter, error; | ||
846 | uch *source, *dest; | ||
847 | struct request *req; | ||
848 | |||
849 | while (1) { /* repeat until all requests have been satisfied */ | ||
850 | req = elv_next_request(q); | ||
851 | if (!req) | ||
852 | return; | ||
853 | |||
854 | if (req->cmd != READ) { | ||
855 | debug(("Non-read command %d on cdrom\n", req->cmd)); | ||
856 | end_request(req, 0); | ||
857 | continue; | ||
858 | } | ||
859 | spin_unlock_irq(q->queue_lock); | ||
860 | error = 0; | ||
861 | for (i = 0; i < req->nr_sectors; i++) { | ||
862 | int e1, e2; | ||
863 | cd_sec_no = (req->sector + i) / BLOCKS_ISO; /* 4 times 512 bytes */ | ||
864 | quarter = (req->sector + i) % BLOCKS_ISO; | ||
865 | dest = req->buffer + i * LINUX_BLOCK_SIZE; | ||
866 | /* is already in buffer memory? */ | ||
867 | if (cd->sector_first <= cd_sec_no | ||
868 | && cd_sec_no < cd->sector_last) { | ||
869 | source = | ||
870 | ((uch *) cd->sector) + 16 + | ||
871 | quarter * LINUX_BLOCK_SIZE + | ||
872 | (cd_sec_no - | ||
873 | cd->sector_first) * RAW_SECTOR_SIZE; | ||
874 | memcpy(dest, source, LINUX_BLOCK_SIZE); | ||
875 | } else if (!(e1 = try_adapter(cd_sec_no)) || | ||
876 | !(e2 = read_sector(cd_sec_no))) { | ||
877 | source = | ||
878 | ((uch *) cd->sector) + 16 + | ||
879 | quarter * LINUX_BLOCK_SIZE; | ||
880 | memcpy(dest, source, LINUX_BLOCK_SIZE); | ||
881 | } else { | ||
882 | error = 1; | ||
883 | debug(("cm206_request: %d %d\n", e1, e2)); | ||
884 | } | ||
885 | } | ||
886 | spin_lock_irq(q->queue_lock); | ||
887 | end_request(req, !error); | ||
888 | } | ||
889 | } | ||
890 | |||
891 | /* Audio support. I've tried very hard, but the cm206 drive doesn't | ||
892 | seem to have a get_toc (table-of-contents) function, while i'm | ||
893 | pretty sure it must read the toc upon disc insertion. Therefore | ||
894 | this function has been implemented through a binary search | ||
895 | strategy. All track starts that happen to be found are stored in | ||
896 | cd->toc[], for future use. | ||
897 | |||
898 | I've spent a whole day on a bug that only shows under Workman--- | ||
899 | I don't get it. Tried everything, nothing works. If workman asks | ||
900 | for track# 0xaa, it'll get the wrong time back. Any other program | ||
901 | receives the correct value. I'm stymied. | ||
902 | */ | ||
903 | |||
904 | /* seek seeks to address lba. It does wait to arrive there. */ | ||
905 | static void seek(int lba) | ||
906 | { | ||
907 | int i; | ||
908 | uch seek_command[4] = { c_seek, }; | ||
909 | |||
910 | fsm(lba, &seek_command[1]); | ||
911 | for (i = 0; i < 4; i++) | ||
912 | type_0_command(seek_command[i], 0); | ||
913 | cd->dsb = wait_dsb(); | ||
914 | } | ||
915 | |||
916 | static uch bcdbin(unsigned char bcd) | ||
917 | { /* stolen from mcd.c! */ | ||
918 | return (bcd >> 4) * 10 + (bcd & 0xf); | ||
919 | } | ||
920 | |||
921 | static inline uch normalize_track(uch track) | ||
922 | { | ||
923 | if (track < 1) | ||
924 | return 1; | ||
925 | if (track > LAST_TRACK) | ||
926 | return LAST_TRACK + 1; | ||
927 | return track; | ||
928 | } | ||
929 | |||
930 | /* This function does a binary search for track start. It records all | ||
931 | * tracks seen in the process. Input $track$ must be between 1 and | ||
932 | * #-of-tracks+1. Note that the start of the disc must be in toc[1].fsm. | ||
933 | */ | ||
934 | static int get_toc_lba(uch track) | ||
935 | { | ||
936 | int max = 74 * 60 * 75 - 150, min = fsm2lba(cd->toc[1].fsm); | ||
937 | int i, lba, l, old_lba = 0; | ||
938 | uch *q = cd->q; | ||
939 | uch ct; /* current track */ | ||
940 | int binary = 0; | ||
941 | const int skip = 3 * 60 * 75; /* 3 minutes */ | ||
942 | |||
943 | for (i = track; i > 0; i--) | ||
944 | if (cd->toc[i].track) { | ||
945 | min = fsm2lba(cd->toc[i].fsm); | ||
946 | break; | ||
947 | } | ||
948 | lba = min + skip; | ||
949 | do { | ||
950 | seek(lba); | ||
951 | type_1_command(c_read_current_q, 10, q); | ||
952 | ct = normalize_track(q[1]); | ||
953 | if (!cd->toc[ct].track) { | ||
954 | l = q[9] - bcdbin(q[5]) + 75 * (q[8] - | ||
955 | bcdbin(q[4]) - 2 + | ||
956 | 60 * (q[7] - | ||
957 | bcdbin(q | ||
958 | [3]))); | ||
959 | cd->toc[ct].track = q[1]; /* lead out still 0xaa */ | ||
960 | fsm(l, cd->toc[ct].fsm); | ||
961 | cd->toc[ct].q0 = q[0]; /* contains adr and ctrl info */ | ||
962 | if (ct == track) | ||
963 | return l; | ||
964 | } | ||
965 | old_lba = lba; | ||
966 | if (binary) { | ||
967 | if (ct < track) | ||
968 | min = lba; | ||
969 | else | ||
970 | max = lba; | ||
971 | lba = (min + max) / 2; | ||
972 | } else { | ||
973 | if (ct < track) | ||
974 | lba += skip; | ||
975 | else { | ||
976 | binary = 1; | ||
977 | max = lba; | ||
978 | min = lba - skip; | ||
979 | lba = (min + max) / 2; | ||
980 | } | ||
981 | } | ||
982 | } while (lba != old_lba); | ||
983 | return lba; | ||
984 | } | ||
985 | |||
986 | static void update_toc_entry(uch track) | ||
987 | { | ||
988 | track = normalize_track(track); | ||
989 | if (!cd->toc[track].track) | ||
990 | get_toc_lba(track); | ||
991 | } | ||
992 | |||
993 | /* return 0 upon success */ | ||
994 | static int read_toc_header(struct cdrom_tochdr *hp) | ||
995 | { | ||
996 | if (!FIRST_TRACK) | ||
997 | get_disc_status(); | ||
998 | if (hp) { | ||
999 | int i; | ||
1000 | hp->cdth_trk0 = FIRST_TRACK; | ||
1001 | hp->cdth_trk1 = LAST_TRACK; | ||
1002 | /* fill in first track position */ | ||
1003 | for (i = 0; i < 3; i++) | ||
1004 | cd->toc[1].fsm[i] = cd->disc_status[3 + i]; | ||
1005 | update_toc_entry(LAST_TRACK + 1); /* find most entries */ | ||
1006 | return 0; | ||
1007 | } | ||
1008 | return -1; | ||
1009 | } | ||
1010 | |||
1011 | static void play_from_to_msf(struct cdrom_msf *msfp) | ||
1012 | { | ||
1013 | uch play_command[] = { c_play, | ||
1014 | msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0, | ||
1015 | msfp->cdmsf_frame1, msfp->cdmsf_sec1, msfp->cdmsf_min1, 2, | ||
1016 | 2 | ||
1017 | }; | ||
1018 | int i; | ||
1019 | for (i = 0; i < 9; i++) | ||
1020 | type_0_command(play_command[i], 0); | ||
1021 | for (i = 0; i < 3; i++) | ||
1022 | PLAY_TO.fsm[i] = play_command[i + 4]; | ||
1023 | PLAY_TO.track = 0; /* say no track end */ | ||
1024 | cd->dsb = wait_dsb(); | ||
1025 | } | ||
1026 | |||
1027 | static void play_from_to_track(int from, int to) | ||
1028 | { | ||
1029 | uch play_command[8] = { c_play, }; | ||
1030 | int i; | ||
1031 | |||
1032 | if (from == 0) { /* continue paused play */ | ||
1033 | for (i = 0; i < 3; i++) { | ||
1034 | play_command[i + 1] = cd->audio_status[i + 2]; | ||
1035 | play_command[i + 4] = PLAY_TO.fsm[i]; | ||
1036 | } | ||
1037 | } else { | ||
1038 | update_toc_entry(from); | ||
1039 | update_toc_entry(to + 1); | ||
1040 | for (i = 0; i < 3; i++) { | ||
1041 | play_command[i + 1] = cd->toc[from].fsm[i]; | ||
1042 | PLAY_TO.fsm[i] = play_command[i + 4] = | ||
1043 | cd->toc[to + 1].fsm[i]; | ||
1044 | } | ||
1045 | PLAY_TO.track = to; | ||
1046 | } | ||
1047 | for (i = 0; i < 7; i++) | ||
1048 | type_0_command(play_command[i], 0); | ||
1049 | for (i = 0; i < 2; i++) | ||
1050 | type_0_command(0x2, 0); /* volume */ | ||
1051 | cd->dsb = wait_dsb(); | ||
1052 | } | ||
1053 | |||
1054 | static int get_current_q(struct cdrom_subchnl *qp) | ||
1055 | { | ||
1056 | int i; | ||
1057 | uch *q = cd->q; | ||
1058 | if (type_1_command(c_read_current_q, 10, q)) | ||
1059 | return 0; | ||
1060 | /* q[0] = bcdbin(q[0]); Don't think so! */ | ||
1061 | for (i = 2; i < 6; i++) | ||
1062 | q[i] = bcdbin(q[i]); | ||
1063 | qp->cdsc_adr = q[0] & 0xf; | ||
1064 | qp->cdsc_ctrl = q[0] >> 4; /* from mcd.c */ | ||
1065 | qp->cdsc_trk = q[1]; | ||
1066 | qp->cdsc_ind = q[2]; | ||
1067 | if (qp->cdsc_format == CDROM_MSF) { | ||
1068 | qp->cdsc_reladdr.msf.minute = q[3]; | ||
1069 | qp->cdsc_reladdr.msf.second = q[4]; | ||
1070 | qp->cdsc_reladdr.msf.frame = q[5]; | ||
1071 | qp->cdsc_absaddr.msf.minute = q[7]; | ||
1072 | qp->cdsc_absaddr.msf.second = q[8]; | ||
1073 | qp->cdsc_absaddr.msf.frame = q[9]; | ||
1074 | } else { | ||
1075 | qp->cdsc_reladdr.lba = f_s_m2lba(q[5], q[4], q[3]); | ||
1076 | qp->cdsc_absaddr.lba = f_s_m2lba(q[9], q[8], q[7]); | ||
1077 | } | ||
1078 | get_drive_status(); | ||
1079 | if (cd->dsb & dsb_play_in_progress) | ||
1080 | qp->cdsc_audiostatus = CDROM_AUDIO_PLAY; | ||
1081 | else if (PAUSED) | ||
1082 | qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED; | ||
1083 | else | ||
1084 | qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS; | ||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static void invalidate_toc(void) | ||
1089 | { | ||
1090 | memset(cd->toc, 0, sizeof(cd->toc)); | ||
1091 | memset(cd->disc_status, 0, sizeof(cd->disc_status)); | ||
1092 | } | ||
1093 | |||
1094 | /* cdrom.c guarantees that cdte_format == CDROM_MSF */ | ||
1095 | static void get_toc_entry(struct cdrom_tocentry *ep) | ||
1096 | { | ||
1097 | uch track = normalize_track(ep->cdte_track); | ||
1098 | update_toc_entry(track); | ||
1099 | ep->cdte_addr.msf.frame = cd->toc[track].fsm[0]; | ||
1100 | ep->cdte_addr.msf.second = cd->toc[track].fsm[1]; | ||
1101 | ep->cdte_addr.msf.minute = cd->toc[track].fsm[2]; | ||
1102 | ep->cdte_adr = cd->toc[track].q0 & 0xf; | ||
1103 | ep->cdte_ctrl = cd->toc[track].q0 >> 4; | ||
1104 | ep->cdte_datamode = 0; | ||
1105 | } | ||
1106 | |||
1107 | /* Audio ioctl. Ioctl commands connected to audio are in such an | ||
1108 | * idiosyncratic i/o format, that we leave these untouched. Return 0 | ||
1109 | * upon success. Memory checking has been done by cdrom_ioctl(), the | ||
1110 | * calling function, as well as LBA/MSF sanitization. | ||
1111 | */ | ||
1112 | static int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, | ||
1113 | void *arg) | ||
1114 | { | ||
1115 | switch (cmd) { | ||
1116 | case CDROMREADTOCHDR: | ||
1117 | return read_toc_header((struct cdrom_tochdr *) arg); | ||
1118 | case CDROMREADTOCENTRY: | ||
1119 | get_toc_entry((struct cdrom_tocentry *) arg); | ||
1120 | return 0; | ||
1121 | case CDROMPLAYMSF: | ||
1122 | play_from_to_msf((struct cdrom_msf *) arg); | ||
1123 | return 0; | ||
1124 | case CDROMPLAYTRKIND: /* admittedly, not particularly beautiful */ | ||
1125 | play_from_to_track(((struct cdrom_ti *) arg)->cdti_trk0, | ||
1126 | ((struct cdrom_ti *) arg)->cdti_trk1); | ||
1127 | return 0; | ||
1128 | case CDROMSTOP: | ||
1129 | PAUSED = 0; | ||
1130 | if (cd->dsb & dsb_play_in_progress) | ||
1131 | return type_0_command(c_stop, 1); | ||
1132 | else | ||
1133 | return 0; | ||
1134 | case CDROMPAUSE: | ||
1135 | get_drive_status(); | ||
1136 | if (cd->dsb & dsb_play_in_progress) { | ||
1137 | type_0_command(c_stop, 1); | ||
1138 | type_1_command(c_audio_status, 5, | ||
1139 | cd->audio_status); | ||
1140 | PAUSED = 1; /* say we're paused */ | ||
1141 | } | ||
1142 | return 0; | ||
1143 | case CDROMRESUME: | ||
1144 | if (PAUSED) | ||
1145 | play_from_to_track(0, 0); | ||
1146 | PAUSED = 0; | ||
1147 | return 0; | ||
1148 | case CDROMSTART: | ||
1149 | case CDROMVOLCTRL: | ||
1150 | return 0; | ||
1151 | case CDROMSUBCHNL: | ||
1152 | return get_current_q((struct cdrom_subchnl *) arg); | ||
1153 | default: | ||
1154 | return -EINVAL; | ||
1155 | } | ||
1156 | } | ||
1157 | |||
1158 | static int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
1159 | { | ||
1160 | if (cd != NULL) { | ||
1161 | int r; | ||
1162 | get_drive_status(); /* ensure cd->media_changed OK */ | ||
1163 | r = cd->media_changed; | ||
1164 | cd->media_changed = 0; /* clear bit */ | ||
1165 | return r; | ||
1166 | } else | ||
1167 | return -EIO; | ||
1168 | } | ||
1169 | |||
1170 | /* The new generic cdrom support. Routines should be concise, most of | ||
1171 | the logic should be in cdrom.c */ | ||
1172 | |||
1173 | |||
1174 | /* controls tray movement */ | ||
1175 | static int cm206_tray_move(struct cdrom_device_info *cdi, int position) | ||
1176 | { | ||
1177 | if (position) { /* 1: eject */ | ||
1178 | type_0_command(c_open_tray, 1); | ||
1179 | invalidate_toc(); | ||
1180 | } else | ||
1181 | type_0_command(c_close_tray, 1); /* 0: close */ | ||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | /* gives current state of the drive */ | ||
1186 | static int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr) | ||
1187 | { | ||
1188 | get_drive_status(); | ||
1189 | if (cd->dsb & dsb_tray_not_closed) | ||
1190 | return CDS_TRAY_OPEN; | ||
1191 | if (!(cd->dsb & dsb_disc_present)) | ||
1192 | return CDS_NO_DISC; | ||
1193 | if (cd->dsb & dsb_drive_not_ready) | ||
1194 | return CDS_DRIVE_NOT_READY; | ||
1195 | return CDS_DISC_OK; | ||
1196 | } | ||
1197 | |||
1198 | /* locks or unlocks door lock==1: lock; return 0 upon success */ | ||
1199 | static int cm206_lock_door(struct cdrom_device_info *cdi, int lock) | ||
1200 | { | ||
1201 | uch command = (lock) ? c_lock_tray : c_unlock_tray; | ||
1202 | type_0_command(command, 1); /* wait and get dsb */ | ||
1203 | /* the logic calculates the success, 0 means successful */ | ||
1204 | return lock ^ ((cd->dsb & dsb_tray_locked) != 0); | ||
1205 | } | ||
1206 | |||
1207 | /* Although a session start should be in LBA format, we return it in | ||
1208 | MSF format because it is slightly easier, and the new generic ioctl | ||
1209 | will take care of the necessary conversion. */ | ||
1210 | static int cm206_get_last_session(struct cdrom_device_info *cdi, | ||
1211 | struct cdrom_multisession *mssp) | ||
1212 | { | ||
1213 | if (!FIRST_TRACK) | ||
1214 | get_disc_status(); | ||
1215 | if (mssp != NULL) { | ||
1216 | if (DISC_STATUS & cds_multi_session) { /* multi-session */ | ||
1217 | mssp->addr.msf.frame = cd->disc_status[3]; | ||
1218 | mssp->addr.msf.second = cd->disc_status[4]; | ||
1219 | mssp->addr.msf.minute = cd->disc_status[5]; | ||
1220 | mssp->addr_format = CDROM_MSF; | ||
1221 | mssp->xa_flag = 1; | ||
1222 | } else { | ||
1223 | mssp->xa_flag = 0; | ||
1224 | } | ||
1225 | return 1; | ||
1226 | } | ||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) | ||
1231 | { | ||
1232 | uch upc[10]; | ||
1233 | char *ret = mcn->medium_catalog_number; | ||
1234 | int i; | ||
1235 | |||
1236 | if (type_1_command(c_read_upc, 10, upc)) | ||
1237 | return -EIO; | ||
1238 | for (i = 0; i < 13; i++) { | ||
1239 | int w = i / 2 + 1, r = i % 2; | ||
1240 | if (r) | ||
1241 | ret[i] = 0x30 | (upc[w] & 0x0f); | ||
1242 | else | ||
1243 | ret[i] = 0x30 | ((upc[w] >> 4) & 0x0f); | ||
1244 | } | ||
1245 | ret[13] = '\0'; | ||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | static int cm206_reset(struct cdrom_device_info *cdi) | ||
1250 | { | ||
1251 | stop_read(); | ||
1252 | reset_cm260(); | ||
1253 | outw(dc_normal | dc_break | READ_AHEAD, r_data_control); | ||
1254 | mdelay(1); /* 750 musec minimum */ | ||
1255 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
1256 | cd->sector_last = -1; /* flag no data buffered */ | ||
1257 | cd->adapter_last = -1; | ||
1258 | invalidate_toc(); | ||
1259 | return 0; | ||
1260 | } | ||
1261 | |||
1262 | static int cm206_select_speed(struct cdrom_device_info *cdi, int speed) | ||
1263 | { | ||
1264 | int r; | ||
1265 | switch (speed) { | ||
1266 | case 0: | ||
1267 | r = type_0_command(c_auto_mode, 1); | ||
1268 | break; | ||
1269 | case 1: | ||
1270 | r = type_0_command(c_force_1x, 1); | ||
1271 | break; | ||
1272 | case 2: | ||
1273 | r = type_0_command(c_force_2x, 1); | ||
1274 | break; | ||
1275 | default: | ||
1276 | return -1; | ||
1277 | } | ||
1278 | if (r < 0) | ||
1279 | return r; | ||
1280 | else | ||
1281 | return 1; | ||
1282 | } | ||
1283 | |||
1284 | static struct cdrom_device_ops cm206_dops = { | ||
1285 | .open = cm206_open, | ||
1286 | .release = cm206_release, | ||
1287 | .drive_status = cm206_drive_status, | ||
1288 | .media_changed = cm206_media_changed, | ||
1289 | .tray_move = cm206_tray_move, | ||
1290 | .lock_door = cm206_lock_door, | ||
1291 | .select_speed = cm206_select_speed, | ||
1292 | .get_last_session = cm206_get_last_session, | ||
1293 | .get_mcn = cm206_get_upc, | ||
1294 | .reset = cm206_reset, | ||
1295 | .audio_ioctl = cm206_audio_ioctl, | ||
1296 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | | ||
1297 | CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | | ||
1298 | CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED | | ||
1299 | CDC_DRIVE_STATUS, | ||
1300 | .n_minors = 1, | ||
1301 | }; | ||
1302 | |||
1303 | |||
1304 | static struct cdrom_device_info cm206_info = { | ||
1305 | .ops = &cm206_dops, | ||
1306 | .speed = 2, | ||
1307 | .capacity = 1, | ||
1308 | .name = "cm206", | ||
1309 | }; | ||
1310 | |||
1311 | static int cm206_block_open(struct inode *inode, struct file *file) | ||
1312 | { | ||
1313 | return cdrom_open(&cm206_info, inode, file); | ||
1314 | } | ||
1315 | |||
1316 | static int cm206_block_release(struct inode *inode, struct file *file) | ||
1317 | { | ||
1318 | return cdrom_release(&cm206_info, file); | ||
1319 | } | ||
1320 | |||
1321 | static int cm206_block_ioctl(struct inode *inode, struct file *file, | ||
1322 | unsigned cmd, unsigned long arg) | ||
1323 | { | ||
1324 | switch (cmd) { | ||
1325 | #ifdef STATISTICS | ||
1326 | case CM206CTL_GET_STAT: | ||
1327 | if (arg >= NR_STATS) | ||
1328 | return -EINVAL; | ||
1329 | return cd->stats[arg]; | ||
1330 | case CM206CTL_GET_LAST_STAT: | ||
1331 | if (arg >= NR_STATS) | ||
1332 | return -EINVAL; | ||
1333 | return cd->last_stat[arg]; | ||
1334 | #endif | ||
1335 | default: | ||
1336 | break; | ||
1337 | } | ||
1338 | |||
1339 | return cdrom_ioctl(file, &cm206_info, inode, cmd, arg); | ||
1340 | } | ||
1341 | |||
1342 | static int cm206_block_media_changed(struct gendisk *disk) | ||
1343 | { | ||
1344 | return cdrom_media_changed(&cm206_info); | ||
1345 | } | ||
1346 | |||
1347 | static struct block_device_operations cm206_bdops = | ||
1348 | { | ||
1349 | .owner = THIS_MODULE, | ||
1350 | .open = cm206_block_open, | ||
1351 | .release = cm206_block_release, | ||
1352 | .ioctl = cm206_block_ioctl, | ||
1353 | .media_changed = cm206_block_media_changed, | ||
1354 | }; | ||
1355 | |||
1356 | static struct gendisk *cm206_gendisk; | ||
1357 | |||
1358 | /* This function probes for the adapter card. It returns the base | ||
1359 | address if it has found the adapter card. One can specify a base | ||
1360 | port to probe specifically, or 0 which means span all possible | ||
1361 | bases. | ||
1362 | |||
1363 | Linus says it is too dangerous to use writes for probing, so we | ||
1364 | stick with pure reads for a while. Hope that 8 possible ranges, | ||
1365 | request_region, 15 bits of one port and 6 of another make things | ||
1366 | likely enough to accept the region on the first hit... | ||
1367 | */ | ||
1368 | static int __init probe_base_port(int base) | ||
1369 | { | ||
1370 | int b = 0x300, e = 0x370; /* this is the range of start addresses */ | ||
1371 | volatile int fool, i; | ||
1372 | |||
1373 | if (base) | ||
1374 | b = e = base; | ||
1375 | for (base = b; base <= e; base += 0x10) { | ||
1376 | if (!request_region(base, 0x10,"cm206")) | ||
1377 | continue; | ||
1378 | for (i = 0; i < 3; i++) | ||
1379 | fool = inw(base + 2); /* empty possibly uart_receive_buffer */ | ||
1380 | if ((inw(base + 6) & 0xffef) != 0x0001 || /* line_status */ | ||
1381 | (inw(base) & 0xad00) != 0) { /* data status */ | ||
1382 | release_region(base,0x10); | ||
1383 | continue; | ||
1384 | } | ||
1385 | return (base); | ||
1386 | } | ||
1387 | return 0; | ||
1388 | } | ||
1389 | |||
1390 | #if !defined(MODULE) || defined(AUTO_PROBE_MODULE) | ||
1391 | /* Probe for irq# nr. If nr==0, probe for all possible irq's. */ | ||
1392 | static int __init probe_irq(int nr) | ||
1393 | { | ||
1394 | int irqs, irq; | ||
1395 | outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ | ||
1396 | sti(); | ||
1397 | irqs = probe_irq_on(); | ||
1398 | reset_cm260(); /* causes interrupt */ | ||
1399 | udelay(100); /* wait for it */ | ||
1400 | irq = probe_irq_off(irqs); | ||
1401 | outw(dc_normal | READ_AHEAD, r_data_control); /* services interrupt */ | ||
1402 | if (nr && irq != nr && irq > 0) | ||
1403 | return 0; /* wrong interrupt happened */ | ||
1404 | else | ||
1405 | return irq; | ||
1406 | } | ||
1407 | #endif | ||
1408 | |||
1409 | int __init cm206_init(void) | ||
1410 | { | ||
1411 | uch e = 0; | ||
1412 | long int size = sizeof(struct cm206_struct); | ||
1413 | struct gendisk *disk; | ||
1414 | |||
1415 | printk(KERN_INFO "cm206 cdrom driver " REVISION); | ||
1416 | cm206_base = probe_base_port(auto_probe ? 0 : cm206_base); | ||
1417 | if (!cm206_base) { | ||
1418 | printk(" can't find adapter!\n"); | ||
1419 | return -EIO; | ||
1420 | } | ||
1421 | printk(" adapter at 0x%x", cm206_base); | ||
1422 | cd = kmalloc(size, GFP_KERNEL); | ||
1423 | if (!cd) | ||
1424 | goto out_base; | ||
1425 | /* Now we have found the adaptor card, try to reset it. As we have | ||
1426 | * found out earlier, this process generates an interrupt as well, | ||
1427 | * so we might just exploit that fact for irq probing! */ | ||
1428 | #if !defined(MODULE) || defined(AUTO_PROBE_MODULE) | ||
1429 | cm206_irq = probe_irq(auto_probe ? 0 : cm206_irq); | ||
1430 | if (cm206_irq <= 0) { | ||
1431 | printk("can't find IRQ!\n"); | ||
1432 | goto out_probe; | ||
1433 | } else | ||
1434 | printk(" IRQ %d found\n", cm206_irq); | ||
1435 | #else | ||
1436 | cli(); | ||
1437 | reset_cm260(); | ||
1438 | /* Now, the problem here is that reset_cm260 can generate an | ||
1439 | interrupt. It seems that this can cause a kernel oops some time | ||
1440 | later. So we wait a while and `service' this interrupt. */ | ||
1441 | mdelay(1); | ||
1442 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
1443 | sti(); | ||
1444 | printk(" using IRQ %d\n", cm206_irq); | ||
1445 | #endif | ||
1446 | if (send_receive_polled(c_drive_configuration) != | ||
1447 | c_drive_configuration) { | ||
1448 | printk(KERN_INFO " drive not there\n"); | ||
1449 | goto out_probe; | ||
1450 | } | ||
1451 | e = send_receive_polled(c_gimme); | ||
1452 | printk(KERN_INFO "Firmware revision %d", e & dcf_revision_code); | ||
1453 | if (e & dcf_transfer_rate) | ||
1454 | printk(" double"); | ||
1455 | else | ||
1456 | printk(" single"); | ||
1457 | printk(" speed drive"); | ||
1458 | if (e & dcf_motorized_tray) | ||
1459 | printk(", motorized tray"); | ||
1460 | if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206", NULL)) { | ||
1461 | printk("\nUnable to reserve IRQ---aborted\n"); | ||
1462 | goto out_probe; | ||
1463 | } | ||
1464 | printk(".\n"); | ||
1465 | |||
1466 | if (register_blkdev(MAJOR_NR, "cm206")) | ||
1467 | goto out_blkdev; | ||
1468 | |||
1469 | disk = alloc_disk(1); | ||
1470 | if (!disk) | ||
1471 | goto out_disk; | ||
1472 | disk->major = MAJOR_NR; | ||
1473 | disk->first_minor = 0; | ||
1474 | sprintf(disk->disk_name, "cm206cd"); | ||
1475 | disk->fops = &cm206_bdops; | ||
1476 | disk->flags = GENHD_FL_CD; | ||
1477 | cm206_gendisk = disk; | ||
1478 | if (register_cdrom(&cm206_info) != 0) { | ||
1479 | printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); | ||
1480 | goto out_cdrom; | ||
1481 | } | ||
1482 | cm206_queue = blk_init_queue(do_cm206_request, &cm206_lock); | ||
1483 | if (!cm206_queue) | ||
1484 | goto out_queue; | ||
1485 | |||
1486 | blk_queue_hardsect_size(cm206_queue, 2048); | ||
1487 | disk->queue = cm206_queue; | ||
1488 | add_disk(disk); | ||
1489 | |||
1490 | memset(cd, 0, sizeof(*cd)); /* give'm some reasonable value */ | ||
1491 | cd->sector_last = -1; /* flag no data buffered */ | ||
1492 | cd->adapter_last = -1; | ||
1493 | init_timer(&cd->timer); | ||
1494 | cd->timer.function = cm206_timeout; | ||
1495 | cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97; | ||
1496 | printk(KERN_INFO "%d kB adapter memory available, " | ||
1497 | " %ld bytes kernel memory used.\n", cd->max_sectors * 2, | ||
1498 | size); | ||
1499 | return 0; | ||
1500 | |||
1501 | out_queue: | ||
1502 | unregister_cdrom(&cm206_info); | ||
1503 | out_cdrom: | ||
1504 | put_disk(disk); | ||
1505 | out_disk: | ||
1506 | unregister_blkdev(MAJOR_NR, "cm206"); | ||
1507 | out_blkdev: | ||
1508 | free_irq(cm206_irq, NULL); | ||
1509 | out_probe: | ||
1510 | kfree(cd); | ||
1511 | out_base: | ||
1512 | release_region(cm206_base, 16); | ||
1513 | return -EIO; | ||
1514 | } | ||
1515 | |||
1516 | #ifdef MODULE | ||
1517 | |||
1518 | |||
1519 | static void __init parse_options(void) | ||
1520 | { | ||
1521 | int i; | ||
1522 | for (i = 0; i < 2; i++) { | ||
1523 | if (0x300 <= cm206[i] && i <= 0x370 | ||
1524 | && cm206[i] % 0x10 == 0) { | ||
1525 | cm206_base = cm206[i]; | ||
1526 | auto_probe = 0; | ||
1527 | } else if (3 <= cm206[i] && cm206[i] <= 15) { | ||
1528 | cm206_irq = cm206[i]; | ||
1529 | auto_probe = 0; | ||
1530 | } | ||
1531 | } | ||
1532 | } | ||
1533 | |||
1534 | static int __init __cm206_init(void) | ||
1535 | { | ||
1536 | parse_options(); | ||
1537 | #if !defined(AUTO_PROBE_MODULE) | ||
1538 | auto_probe = 0; | ||
1539 | #endif | ||
1540 | return cm206_init(); | ||
1541 | } | ||
1542 | |||
1543 | static void __exit cm206_exit(void) | ||
1544 | { | ||
1545 | del_gendisk(cm206_gendisk); | ||
1546 | put_disk(cm206_gendisk); | ||
1547 | if (unregister_cdrom(&cm206_info)) { | ||
1548 | printk("Can't unregister cdrom cm206\n"); | ||
1549 | return; | ||
1550 | } | ||
1551 | if (unregister_blkdev(MAJOR_NR, "cm206")) { | ||
1552 | printk("Can't unregister major cm206\n"); | ||
1553 | return; | ||
1554 | } | ||
1555 | blk_cleanup_queue(cm206_queue); | ||
1556 | free_irq(cm206_irq, NULL); | ||
1557 | kfree(cd); | ||
1558 | release_region(cm206_base, 16); | ||
1559 | printk(KERN_INFO "cm206 removed\n"); | ||
1560 | } | ||
1561 | |||
1562 | module_init(__cm206_init); | ||
1563 | module_exit(cm206_exit); | ||
1564 | |||
1565 | #else /* !MODULE */ | ||
1566 | |||
1567 | /* This setup function accepts either `auto' or numbers in the range | ||
1568 | * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */ | ||
1569 | |||
1570 | static int __init cm206_setup(char *s) | ||
1571 | { | ||
1572 | int i, p[4]; | ||
1573 | |||
1574 | (void) get_options(s, ARRAY_SIZE(p), p); | ||
1575 | |||
1576 | if (!strcmp(s, "auto")) | ||
1577 | auto_probe = 1; | ||
1578 | for (i = 1; i <= p[0]; i++) { | ||
1579 | if (0x300 <= p[i] && i <= 0x370 && p[i] % 0x10 == 0) { | ||
1580 | cm206_base = p[i]; | ||
1581 | auto_probe = 0; | ||
1582 | } else if (3 <= p[i] && p[i] <= 15) { | ||
1583 | cm206_irq = p[i]; | ||
1584 | auto_probe = 0; | ||
1585 | } | ||
1586 | } | ||
1587 | return 1; | ||
1588 | } | ||
1589 | |||
1590 | __setup("cm206=", cm206_setup); | ||
1591 | |||
1592 | #endif /* !MODULE */ | ||
1593 | MODULE_ALIAS_BLOCKDEV_MAJOR(CM206_CDROM_MAJOR); | ||
1594 | |||
diff --git a/drivers/cdrom/cm206.h b/drivers/cdrom/cm206.h deleted file mode 100644 index 0ae51c1a0dac..000000000000 --- a/drivers/cdrom/cm206.h +++ /dev/null | |||
@@ -1,171 +0,0 @@ | |||
1 | /* cm206.h Header file for cm206.c. | ||
2 | Copyright (c) 1995 David van Leeuwen | ||
3 | */ | ||
4 | |||
5 | #ifndef LINUX_CM206_H | ||
6 | #define LINUX_CM206_H | ||
7 | |||
8 | #include <linux/ioctl.h> | ||
9 | |||
10 | /* First, the cm260 stuff */ | ||
11 | /* The ports and irq used. Although CM206_BASE and CM206_IRQ are defined | ||
12 | below, the values are not used unless autoprobing is turned off and | ||
13 | no LILO boot options or module command line options are given. Change | ||
14 | these values to your own as last resort if autoprobing and options | ||
15 | don't work. */ | ||
16 | |||
17 | #define CM206_BASE 0x340 | ||
18 | #define CM206_IRQ 11 | ||
19 | |||
20 | #define r_data_status (cm206_base) | ||
21 | #define r_uart_receive (cm206_base+0x2) | ||
22 | #define r_fifo_output_buffer (cm206_base+0x4) | ||
23 | #define r_line_status (cm206_base+0x6) | ||
24 | #define r_data_control (cm206_base+0x8) | ||
25 | #define r_uart_transmit (cm206_base+0xa) | ||
26 | #define r_test_clock (cm206_base+0xc) | ||
27 | #define r_test_control (cm206_base+0xe) | ||
28 | |||
29 | /* the data_status flags */ | ||
30 | #define ds_ram_size 0x4000 | ||
31 | #define ds_toc_ready 0x2000 | ||
32 | #define ds_fifo_empty 0x1000 | ||
33 | #define ds_sync_error 0x800 | ||
34 | #define ds_crc_error 0x400 | ||
35 | #define ds_data_error 0x200 | ||
36 | #define ds_fifo_overflow 0x100 | ||
37 | #define ds_data_ready 0x80 | ||
38 | |||
39 | /* the line_status flags */ | ||
40 | #define ls_attention 0x10 | ||
41 | #define ls_parity_error 0x8 | ||
42 | #define ls_overrun 0x4 | ||
43 | #define ls_receive_buffer_full 0x2 | ||
44 | #define ls_transmitter_buffer_empty 0x1 | ||
45 | |||
46 | /* the data control register flags */ | ||
47 | #define dc_read_q_channel 0x4000 | ||
48 | #define dc_mask_sync_error 0x2000 | ||
49 | #define dc_toc_enable 0x1000 | ||
50 | #define dc_no_stop_on_error 0x800 | ||
51 | #define dc_break 0x400 | ||
52 | #define dc_initialize 0x200 | ||
53 | #define dc_mask_transmit_ready 0x100 | ||
54 | #define dc_flag_enable 0x80 | ||
55 | |||
56 | /* Define the default data control register flags here */ | ||
57 | #define dc_normal (dc_mask_sync_error | dc_no_stop_on_error | \ | ||
58 | dc_mask_transmit_ready) | ||
59 | |||
60 | /* now some constants related to the cm206 */ | ||
61 | /* another drive status byte, echoed by the cm206 on most commands */ | ||
62 | |||
63 | #define dsb_error_condition 0x1 | ||
64 | #define dsb_play_in_progress 0x4 | ||
65 | #define dsb_possible_media_change 0x8 | ||
66 | #define dsb_disc_present 0x10 | ||
67 | #define dsb_drive_not_ready 0x20 | ||
68 | #define dsb_tray_locked 0x40 | ||
69 | #define dsb_tray_not_closed 0x80 | ||
70 | |||
71 | #define dsb_not_useful (dsb_drive_not_ready | dsb_tray_not_closed) | ||
72 | |||
73 | /* the cm206 command set */ | ||
74 | |||
75 | #define c_close_tray 0 | ||
76 | #define c_lock_tray 0x01 | ||
77 | #define c_unlock_tray 0x04 | ||
78 | #define c_open_tray 0x05 | ||
79 | #define c_seek 0x10 | ||
80 | #define c_read_data 0x20 | ||
81 | #define c_force_1x 0x21 | ||
82 | #define c_force_2x 0x22 | ||
83 | #define c_auto_mode 0x23 | ||
84 | #define c_play 0x30 | ||
85 | #define c_set_audio_mode 0x31 | ||
86 | #define c_read_current_q 0x41 | ||
87 | #define c_stream_q 0x42 | ||
88 | #define c_drive_status 0x50 | ||
89 | #define c_disc_status 0x51 | ||
90 | #define c_audio_status 0x52 | ||
91 | #define c_drive_configuration 0x53 | ||
92 | #define c_read_upc 0x60 | ||
93 | #define c_stop 0x70 | ||
94 | #define c_calc_checksum 0xe5 | ||
95 | |||
96 | #define c_gimme 0xf8 | ||
97 | |||
98 | /* finally, the (error) condition that the drive can be in * | ||
99 | * OK, this is not always an error, but let's prefix it with e_ */ | ||
100 | |||
101 | #define e_none 0 | ||
102 | #define e_illegal_command 0x01 | ||
103 | #define e_sync 0x02 | ||
104 | #define e_seek 0x03 | ||
105 | #define e_parity 0x04 | ||
106 | #define e_focus 0x05 | ||
107 | #define e_header_sync 0x06 | ||
108 | #define e_code_incompatibility 0x07 | ||
109 | #define e_reset_done 0x08 | ||
110 | #define e_bad_parameter 0x09 | ||
111 | #define e_radial 0x0a | ||
112 | #define e_sub_code 0x0b | ||
113 | #define e_no_data_track 0x0c | ||
114 | #define e_scan 0x0d | ||
115 | #define e_tray_open 0x0f | ||
116 | #define e_no_disc 0x10 | ||
117 | #define e_tray stalled 0x11 | ||
118 | |||
119 | /* drive configuration masks */ | ||
120 | |||
121 | #define dcf_revision_code 0x7 | ||
122 | #define dcf_transfer_rate 0x60 | ||
123 | #define dcf_motorized_tray 0x80 | ||
124 | |||
125 | /* disc status byte */ | ||
126 | |||
127 | #define cds_multi_session 0x2 | ||
128 | #define cds_all_audio 0x8 | ||
129 | #define cds_xa_mode 0xf0 | ||
130 | |||
131 | /* finally some ioctls for the driver */ | ||
132 | |||
133 | #define CM206CTL_GET_STAT _IO( 0x20, 0 ) | ||
134 | #define CM206CTL_GET_LAST_STAT _IO( 0x20, 1 ) | ||
135 | |||
136 | #ifdef STATISTICS | ||
137 | |||
138 | /* This is an ugly way to guarantee that the names of the statistics | ||
139 | * are the same in the code and in the diagnostics program. */ | ||
140 | |||
141 | #ifdef __KERNEL__ | ||
142 | #define x(a) st_ ## a | ||
143 | #define y enum | ||
144 | #else | ||
145 | #define x(a) #a | ||
146 | #define y char * stats_name[] = | ||
147 | #endif | ||
148 | |||
149 | y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error), | ||
150 | x(crc_error), x(sync_error), x(lost_intr), x(echo), | ||
151 | x(write_timeout), x(receive_timeout), x(read_timeout), | ||
152 | x(dsb_timeout), x(stop_0xff), x(back_read_timeout), | ||
153 | x(sector_transferred), x(read_restarted), x(read_background), | ||
154 | x(bh), x(open), x(ioctl_multisession), x(attention) | ||
155 | #ifdef __KERNEL__ | ||
156 | , x(last_entry) | ||
157 | #endif | ||
158 | }; | ||
159 | |||
160 | #ifdef __KERNEL__ | ||
161 | #define NR_STATS st_last_entry | ||
162 | #else | ||
163 | #define NR_STATS (sizeof(stats_name)/sizeof(char*)) | ||
164 | #endif | ||
165 | |||
166 | #undef y | ||
167 | #undef x | ||
168 | |||
169 | #endif /* STATISTICS */ | ||
170 | |||
171 | #endif /* LINUX_CM206_H */ | ||
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c deleted file mode 100644 index b3ab6e9b8df1..000000000000 --- a/drivers/cdrom/gscd.c +++ /dev/null | |||
@@ -1,1029 +0,0 @@ | |||
1 | #define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>" | ||
2 | |||
3 | /* | ||
4 | linux/drivers/block/gscd.c - GoldStar R420 CDROM driver | ||
5 | |||
6 | Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de> | ||
7 | based upon pre-works by Eberhard Moenkeberg <emoenke@gwdg.de> | ||
8 | |||
9 | |||
10 | For all kind of other information about the GoldStar CDROM | ||
11 | and this Linux device driver I installed a WWW-URL: | ||
12 | http://linux.rz.fh-hannover.de/~raupach | ||
13 | |||
14 | |||
15 | If you are the editor of a Linux CD, you should | ||
16 | enable gscd.c within your boot floppy kernel and | ||
17 | send me one of your CDs for free. | ||
18 | |||
19 | |||
20 | -------------------------------------------------------------------- | ||
21 | This program is free software; you can redistribute it and/or modify | ||
22 | it under the terms of the GNU General Public License as published by | ||
23 | the Free Software Foundation; either version 2, or (at your option) | ||
24 | any later version. | ||
25 | |||
26 | This program is distributed in the hope that it will be useful, | ||
27 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | GNU General Public License for more details. | ||
30 | |||
31 | You should have received a copy of the GNU General Public License | ||
32 | along with this program; if not, write to the Free Software | ||
33 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
34 | |||
35 | -------------------------------------------------------------------- | ||
36 | |||
37 | 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
38 | Removed init_module & cleanup_module in favor of | ||
39 | module_init & module_exit. | ||
40 | Torben Mathiasen <tmm@image.dk> | ||
41 | |||
42 | */ | ||
43 | |||
44 | /* These settings are for various debug-level. Leave they untouched ... */ | ||
45 | #define NO_GSCD_DEBUG | ||
46 | #define NO_IOCTL_DEBUG | ||
47 | #define NO_MODULE_DEBUG | ||
48 | #define NO_FUTURE_WORK | ||
49 | /*------------------------*/ | ||
50 | |||
51 | #include <linux/module.h> | ||
52 | |||
53 | #include <linux/slab.h> | ||
54 | #include <linux/errno.h> | ||
55 | #include <linux/signal.h> | ||
56 | #include <linux/timer.h> | ||
57 | #include <linux/fs.h> | ||
58 | #include <linux/mm.h> | ||
59 | #include <linux/kernel.h> | ||
60 | #include <linux/cdrom.h> | ||
61 | #include <linux/ioport.h> | ||
62 | #include <linux/major.h> | ||
63 | #include <linux/string.h> | ||
64 | #include <linux/init.h> | ||
65 | |||
66 | #include <asm/system.h> | ||
67 | #include <asm/io.h> | ||
68 | #include <asm/uaccess.h> | ||
69 | |||
70 | #define MAJOR_NR GOLDSTAR_CDROM_MAJOR | ||
71 | #include <linux/blkdev.h> | ||
72 | #include "gscd.h" | ||
73 | |||
74 | static int gscdPresent = 0; | ||
75 | |||
76 | static unsigned char gscd_buf[2048]; /* buffer for block size conversion */ | ||
77 | static int gscd_bn = -1; | ||
78 | static short gscd_port = GSCD_BASE_ADDR; | ||
79 | module_param_named(gscd, gscd_port, short, 0); | ||
80 | |||
81 | /* Kommt spaeter vielleicht noch mal dran ... | ||
82 | * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); | ||
83 | */ | ||
84 | |||
85 | static void gscd_read_cmd(struct request *req); | ||
86 | static void gscd_hsg2msf(long hsg, struct msf *msf); | ||
87 | static void gscd_bin2bcd(unsigned char *p); | ||
88 | |||
89 | /* Schnittstellen zum Kern/FS */ | ||
90 | |||
91 | static void __do_gscd_request(unsigned long dummy); | ||
92 | static int gscd_ioctl(struct inode *, struct file *, unsigned int, | ||
93 | unsigned long); | ||
94 | static int gscd_open(struct inode *, struct file *); | ||
95 | static int gscd_release(struct inode *, struct file *); | ||
96 | static int check_gscd_med_chg(struct gendisk *disk); | ||
97 | |||
98 | /* GoldStar Funktionen */ | ||
99 | |||
100 | static void cmd_out(int, char *, char *, int); | ||
101 | static void cmd_status(void); | ||
102 | static void init_cd_drive(int); | ||
103 | |||
104 | static int get_status(void); | ||
105 | static void clear_Audio(void); | ||
106 | static void cc_invalidate(void); | ||
107 | |||
108 | /* some things for the next version */ | ||
109 | #ifdef FUTURE_WORK | ||
110 | static void update_state(void); | ||
111 | static long gscd_msf2hsg(struct msf *mp); | ||
112 | static int gscd_bcd2bin(unsigned char bcd); | ||
113 | #endif | ||
114 | |||
115 | |||
116 | /* lo-level cmd-Funktionen */ | ||
117 | |||
118 | static void cmd_info_in(char *, int); | ||
119 | static void cmd_end(void); | ||
120 | static void cmd_read_b(char *, int, int); | ||
121 | static void cmd_read_w(char *, int, int); | ||
122 | static int cmd_unit_alive(void); | ||
123 | static void cmd_write_cmd(char *); | ||
124 | |||
125 | |||
126 | /* GoldStar Variablen */ | ||
127 | |||
128 | static int curr_drv_state; | ||
129 | static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
130 | static int drv_mode; | ||
131 | static int disk_state; | ||
132 | static int speed; | ||
133 | static int ndrives; | ||
134 | |||
135 | static unsigned char drv_num_read; | ||
136 | static unsigned char f_dsk_valid; | ||
137 | static unsigned char current_drive; | ||
138 | static unsigned char f_drv_ok; | ||
139 | |||
140 | |||
141 | static char f_AudioPlay; | ||
142 | static char f_AudioPause; | ||
143 | static int AudioStart_m; | ||
144 | static int AudioStart_f; | ||
145 | static int AudioEnd_m; | ||
146 | static int AudioEnd_f; | ||
147 | |||
148 | static DEFINE_TIMER(gscd_timer, NULL, 0, 0); | ||
149 | static DEFINE_SPINLOCK(gscd_lock); | ||
150 | static struct request_queue *gscd_queue; | ||
151 | |||
152 | static struct block_device_operations gscd_fops = { | ||
153 | .owner = THIS_MODULE, | ||
154 | .open = gscd_open, | ||
155 | .release = gscd_release, | ||
156 | .ioctl = gscd_ioctl, | ||
157 | .media_changed = check_gscd_med_chg, | ||
158 | }; | ||
159 | |||
160 | /* | ||
161 | * Checking if the media has been changed | ||
162 | * (not yet implemented) | ||
163 | */ | ||
164 | static int check_gscd_med_chg(struct gendisk *disk) | ||
165 | { | ||
166 | #ifdef GSCD_DEBUG | ||
167 | printk("gscd: check_med_change\n"); | ||
168 | #endif | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | |||
173 | #ifndef MODULE | ||
174 | /* Using new interface for kernel-parameters */ | ||
175 | |||
176 | static int __init gscd_setup(char *str) | ||
177 | { | ||
178 | int ints[2]; | ||
179 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
180 | |||
181 | if (ints[0] > 0) { | ||
182 | gscd_port = ints[1]; | ||
183 | } | ||
184 | return 1; | ||
185 | } | ||
186 | |||
187 | __setup("gscd=", gscd_setup); | ||
188 | |||
189 | #endif | ||
190 | |||
191 | static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | ||
192 | unsigned long arg) | ||
193 | { | ||
194 | unsigned char to_do[10]; | ||
195 | unsigned char dummy; | ||
196 | |||
197 | |||
198 | switch (cmd) { | ||
199 | case CDROMSTART: /* Spin up the drive */ | ||
200 | /* Don't think we can do this. Even if we could, | ||
201 | * I think the drive times out and stops after a while | ||
202 | * anyway. For now, ignore it. | ||
203 | */ | ||
204 | return 0; | ||
205 | |||
206 | case CDROMRESUME: /* keine Ahnung was das ist */ | ||
207 | return 0; | ||
208 | |||
209 | |||
210 | case CDROMEJECT: | ||
211 | cmd_status(); | ||
212 | to_do[0] = CMD_TRAY_CTL; | ||
213 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
214 | |||
215 | return 0; | ||
216 | |||
217 | default: | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | } | ||
222 | |||
223 | |||
224 | /* | ||
225 | * Take care of the different block sizes between cdrom and Linux. | ||
226 | * When Linux gets variable block sizes this will probably go away. | ||
227 | */ | ||
228 | |||
229 | static void gscd_transfer(struct request *req) | ||
230 | { | ||
231 | while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) { | ||
232 | long offs = (req->sector & 3) * 512; | ||
233 | memcpy(req->buffer, gscd_buf + offs, 512); | ||
234 | req->nr_sectors--; | ||
235 | req->sector++; | ||
236 | req->buffer += 512; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | |||
241 | /* | ||
242 | * I/O request routine called from Linux kernel. | ||
243 | */ | ||
244 | |||
245 | static void do_gscd_request(request_queue_t * q) | ||
246 | { | ||
247 | __do_gscd_request(0); | ||
248 | } | ||
249 | |||
250 | static void __do_gscd_request(unsigned long dummy) | ||
251 | { | ||
252 | struct request *req; | ||
253 | unsigned int block; | ||
254 | unsigned int nsect; | ||
255 | |||
256 | repeat: | ||
257 | req = elv_next_request(gscd_queue); | ||
258 | if (!req) | ||
259 | return; | ||
260 | |||
261 | block = req->sector; | ||
262 | nsect = req->nr_sectors; | ||
263 | |||
264 | if (req->sector == -1) | ||
265 | goto out; | ||
266 | |||
267 | if (req->cmd != READ) { | ||
268 | printk("GSCD: bad cmd %u\n", rq_data_dir(req)); | ||
269 | end_request(req, 0); | ||
270 | goto repeat; | ||
271 | } | ||
272 | |||
273 | gscd_transfer(req); | ||
274 | |||
275 | /* if we satisfied the request from the buffer, we're done. */ | ||
276 | |||
277 | if (req->nr_sectors == 0) { | ||
278 | end_request(req, 1); | ||
279 | goto repeat; | ||
280 | } | ||
281 | #ifdef GSCD_DEBUG | ||
282 | printk("GSCD: block %d, nsect %d\n", block, nsect); | ||
283 | #endif | ||
284 | gscd_read_cmd(req); | ||
285 | out: | ||
286 | return; | ||
287 | } | ||
288 | |||
289 | |||
290 | |||
291 | /* | ||
292 | * Check the result of the set-mode command. On success, send the | ||
293 | * read-data command. | ||
294 | */ | ||
295 | |||
296 | static void gscd_read_cmd(struct request *req) | ||
297 | { | ||
298 | long block; | ||
299 | struct gscd_Play_msf gscdcmd; | ||
300 | char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */ | ||
301 | |||
302 | cmd_status(); | ||
303 | if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) { | ||
304 | printk("GSCD: no disk or door open\n"); | ||
305 | end_request(req, 0); | ||
306 | } else { | ||
307 | if (disk_state & ST_INVALID) { | ||
308 | printk("GSCD: disk invalid\n"); | ||
309 | end_request(req, 0); | ||
310 | } else { | ||
311 | gscd_bn = -1; /* purge our buffer */ | ||
312 | block = req->sector / 4; | ||
313 | gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */ | ||
314 | |||
315 | cmd[2] = gscdcmd.start.min; | ||
316 | cmd[3] = gscdcmd.start.sec; | ||
317 | cmd[4] = gscdcmd.start.frame; | ||
318 | |||
319 | #ifdef GSCD_DEBUG | ||
320 | printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], | ||
321 | cmd[4]); | ||
322 | #endif | ||
323 | cmd_out(TYPE_DATA, (char *) &cmd, | ||
324 | (char *) &gscd_buf[0], 1); | ||
325 | |||
326 | gscd_bn = req->sector / 4; | ||
327 | gscd_transfer(req); | ||
328 | end_request(req, 1); | ||
329 | } | ||
330 | } | ||
331 | SET_TIMER(__do_gscd_request, 1); | ||
332 | } | ||
333 | |||
334 | |||
335 | /* | ||
336 | * Open the device special file. Check that a disk is in. | ||
337 | */ | ||
338 | |||
339 | static int gscd_open(struct inode *ip, struct file *fp) | ||
340 | { | ||
341 | int st; | ||
342 | |||
343 | #ifdef GSCD_DEBUG | ||
344 | printk("GSCD: open\n"); | ||
345 | #endif | ||
346 | |||
347 | if (gscdPresent == 0) | ||
348 | return -ENXIO; /* no hardware */ | ||
349 | |||
350 | get_status(); | ||
351 | st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN); | ||
352 | if (st) { | ||
353 | printk("GSCD: no disk or door open\n"); | ||
354 | return -ENXIO; | ||
355 | } | ||
356 | |||
357 | /* if (updateToc() < 0) | ||
358 | return -EIO; | ||
359 | */ | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | |||
365 | /* | ||
366 | * On close, we flush all gscd blocks from the buffer cache. | ||
367 | */ | ||
368 | |||
369 | static int gscd_release(struct inode *inode, struct file *file) | ||
370 | { | ||
371 | |||
372 | #ifdef GSCD_DEBUG | ||
373 | printk("GSCD: release\n"); | ||
374 | #endif | ||
375 | |||
376 | gscd_bn = -1; | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | |||
382 | static int get_status(void) | ||
383 | { | ||
384 | int status; | ||
385 | |||
386 | cmd_status(); | ||
387 | status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01); | ||
388 | |||
389 | if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) { | ||
390 | cc_invalidate(); | ||
391 | return 1; | ||
392 | } else { | ||
393 | return 0; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | |||
398 | static void cc_invalidate(void) | ||
399 | { | ||
400 | drv_num_read = 0xFF; | ||
401 | f_dsk_valid = 0xFF; | ||
402 | current_drive = 0xFF; | ||
403 | f_drv_ok = 0xFF; | ||
404 | |||
405 | clear_Audio(); | ||
406 | |||
407 | } | ||
408 | |||
409 | static void clear_Audio(void) | ||
410 | { | ||
411 | |||
412 | f_AudioPlay = 0; | ||
413 | f_AudioPause = 0; | ||
414 | AudioStart_m = 0; | ||
415 | AudioStart_f = 0; | ||
416 | AudioEnd_m = 0; | ||
417 | AudioEnd_f = 0; | ||
418 | |||
419 | } | ||
420 | |||
421 | /* | ||
422 | * waiting ? | ||
423 | */ | ||
424 | |||
425 | static int wait_drv_ready(void) | ||
426 | { | ||
427 | int found, read; | ||
428 | |||
429 | do { | ||
430 | found = inb(GSCDPORT(0)); | ||
431 | found &= 0x0f; | ||
432 | read = inb(GSCDPORT(0)); | ||
433 | read &= 0x0f; | ||
434 | } while (read != found); | ||
435 | |||
436 | #ifdef GSCD_DEBUG | ||
437 | printk("Wait for: %d\n", read); | ||
438 | #endif | ||
439 | |||
440 | return read; | ||
441 | } | ||
442 | |||
443 | static void cc_Ident(char *respons) | ||
444 | { | ||
445 | char to_do[] = { CMD_IDENT, 0, 0 }; | ||
446 | |||
447 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E); | ||
448 | |||
449 | } | ||
450 | |||
451 | static void cc_SetSpeed(void) | ||
452 | { | ||
453 | char to_do[] = { CMD_SETSPEED, 0, 0 }; | ||
454 | char dummy; | ||
455 | |||
456 | if (speed > 0) { | ||
457 | to_do[1] = speed & 0x0F; | ||
458 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | static void cc_Reset(void) | ||
463 | { | ||
464 | char to_do[] = { CMD_RESET, 0 }; | ||
465 | char dummy; | ||
466 | |||
467 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
468 | } | ||
469 | |||
470 | static void cmd_status(void) | ||
471 | { | ||
472 | char to_do[] = { CMD_STATUS, 0 }; | ||
473 | char dummy; | ||
474 | |||
475 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
476 | |||
477 | #ifdef GSCD_DEBUG | ||
478 | printk("GSCD: Status: %d\n", disk_state); | ||
479 | #endif | ||
480 | |||
481 | } | ||
482 | |||
483 | static void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count) | ||
484 | { | ||
485 | int result; | ||
486 | |||
487 | |||
488 | result = wait_drv_ready(); | ||
489 | if (result != drv_mode) { | ||
490 | unsigned long test_loops = 0xFFFF; | ||
491 | int i, dummy; | ||
492 | |||
493 | outb(curr_drv_state, GSCDPORT(0)); | ||
494 | |||
495 | /* LOCLOOP_170 */ | ||
496 | do { | ||
497 | result = wait_drv_ready(); | ||
498 | test_loops--; | ||
499 | } while ((result != drv_mode) && (test_loops > 0)); | ||
500 | |||
501 | if (result != drv_mode) { | ||
502 | disk_state = ST_x08 | ST_x04 | ST_INVALID; | ||
503 | return; | ||
504 | } | ||
505 | |||
506 | /* ...and waiting */ | ||
507 | for (i = 1, dummy = 1; i < 0xFFFF; i++) { | ||
508 | dummy *= i; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | /* LOC_172 */ | ||
513 | /* check the unit */ | ||
514 | /* and wake it up */ | ||
515 | if (cmd_unit_alive() != 0x08) { | ||
516 | /* LOC_174 */ | ||
517 | /* game over for this unit */ | ||
518 | disk_state = ST_x08 | ST_x04 | ST_INVALID; | ||
519 | return; | ||
520 | } | ||
521 | |||
522 | /* LOC_176 */ | ||
523 | #ifdef GSCD_DEBUG | ||
524 | printk("LOC_176 "); | ||
525 | #endif | ||
526 | if (drv_mode == 0x09) { | ||
527 | /* magic... */ | ||
528 | printk("GSCD: magic ...\n"); | ||
529 | outb(result, GSCDPORT(2)); | ||
530 | } | ||
531 | |||
532 | /* write the command to the drive */ | ||
533 | cmd_write_cmd(cmd); | ||
534 | |||
535 | /* LOC_178 */ | ||
536 | for (;;) { | ||
537 | result = wait_drv_ready(); | ||
538 | if (result != drv_mode) { | ||
539 | /* LOC_179 */ | ||
540 | if (result == 0x04) { /* Mode 4 */ | ||
541 | /* LOC_205 */ | ||
542 | #ifdef GSCD_DEBUG | ||
543 | printk("LOC_205 "); | ||
544 | #endif | ||
545 | disk_state = inb(GSCDPORT(2)); | ||
546 | |||
547 | do { | ||
548 | result = wait_drv_ready(); | ||
549 | } while (result != drv_mode); | ||
550 | return; | ||
551 | |||
552 | } else { | ||
553 | if (result == 0x06) { /* Mode 6 */ | ||
554 | /* LOC_181 */ | ||
555 | #ifdef GSCD_DEBUG | ||
556 | printk("LOC_181 "); | ||
557 | #endif | ||
558 | |||
559 | if (cmd_type == TYPE_DATA) { | ||
560 | /* read data */ | ||
561 | /* LOC_184 */ | ||
562 | if (drv_mode == 9) { | ||
563 | /* read the data to the buffer (word) */ | ||
564 | |||
565 | /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */ | ||
566 | cmd_read_w | ||
567 | (respo_buf, | ||
568 | respo_count, | ||
569 | CD_FRAMESIZE / | ||
570 | 2); | ||
571 | return; | ||
572 | } else { | ||
573 | /* read the data to the buffer (byte) */ | ||
574 | |||
575 | /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */ | ||
576 | cmd_read_b | ||
577 | (respo_buf, | ||
578 | respo_count, | ||
579 | CD_FRAMESIZE); | ||
580 | return; | ||
581 | } | ||
582 | } else { | ||
583 | /* read the info to the buffer */ | ||
584 | cmd_info_in(respo_buf, | ||
585 | respo_count); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | return; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | } else { | ||
594 | disk_state = ST_x08 | ST_x04 | ST_INVALID; | ||
595 | return; | ||
596 | } | ||
597 | } /* for (;;) */ | ||
598 | |||
599 | |||
600 | #ifdef GSCD_DEBUG | ||
601 | printk("\n"); | ||
602 | #endif | ||
603 | } | ||
604 | |||
605 | |||
606 | static void cmd_write_cmd(char *pstr) | ||
607 | { | ||
608 | int i, j; | ||
609 | |||
610 | /* LOC_177 */ | ||
611 | #ifdef GSCD_DEBUG | ||
612 | printk("LOC_177 "); | ||
613 | #endif | ||
614 | |||
615 | /* calculate the number of parameter */ | ||
616 | j = *pstr & 0x0F; | ||
617 | |||
618 | /* shift it out */ | ||
619 | for (i = 0; i < j; i++) { | ||
620 | outb(*pstr, GSCDPORT(2)); | ||
621 | pstr++; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | |||
626 | static int cmd_unit_alive(void) | ||
627 | { | ||
628 | int result; | ||
629 | unsigned long max_test_loops; | ||
630 | |||
631 | |||
632 | /* LOC_172 */ | ||
633 | #ifdef GSCD_DEBUG | ||
634 | printk("LOC_172 "); | ||
635 | #endif | ||
636 | |||
637 | outb(curr_drv_state, GSCDPORT(0)); | ||
638 | max_test_loops = 0xFFFF; | ||
639 | |||
640 | do { | ||
641 | result = wait_drv_ready(); | ||
642 | max_test_loops--; | ||
643 | } while ((result != 0x08) && (max_test_loops > 0)); | ||
644 | |||
645 | return result; | ||
646 | } | ||
647 | |||
648 | |||
649 | static void cmd_info_in(char *pb, int count) | ||
650 | { | ||
651 | int result; | ||
652 | char read; | ||
653 | |||
654 | |||
655 | /* read info */ | ||
656 | /* LOC_182 */ | ||
657 | #ifdef GSCD_DEBUG | ||
658 | printk("LOC_182 "); | ||
659 | #endif | ||
660 | |||
661 | do { | ||
662 | read = inb(GSCDPORT(2)); | ||
663 | if (count > 0) { | ||
664 | *pb = read; | ||
665 | pb++; | ||
666 | count--; | ||
667 | } | ||
668 | |||
669 | /* LOC_183 */ | ||
670 | do { | ||
671 | result = wait_drv_ready(); | ||
672 | } while (result == 0x0E); | ||
673 | } while (result == 6); | ||
674 | |||
675 | cmd_end(); | ||
676 | return; | ||
677 | } | ||
678 | |||
679 | |||
680 | static void cmd_read_b(char *pb, int count, int size) | ||
681 | { | ||
682 | int result; | ||
683 | int i; | ||
684 | |||
685 | |||
686 | /* LOC_188 */ | ||
687 | /* LOC_189 */ | ||
688 | #ifdef GSCD_DEBUG | ||
689 | printk("LOC_189 "); | ||
690 | #endif | ||
691 | |||
692 | do { | ||
693 | do { | ||
694 | result = wait_drv_ready(); | ||
695 | } while (result != 6 || result == 0x0E); | ||
696 | |||
697 | if (result != 6) { | ||
698 | cmd_end(); | ||
699 | return; | ||
700 | } | ||
701 | #ifdef GSCD_DEBUG | ||
702 | printk("LOC_191 "); | ||
703 | #endif | ||
704 | |||
705 | for (i = 0; i < size; i++) { | ||
706 | *pb = inb(GSCDPORT(2)); | ||
707 | pb++; | ||
708 | } | ||
709 | count--; | ||
710 | } while (count > 0); | ||
711 | |||
712 | cmd_end(); | ||
713 | return; | ||
714 | } | ||
715 | |||
716 | |||
717 | static void cmd_end(void) | ||
718 | { | ||
719 | int result; | ||
720 | |||
721 | |||
722 | /* LOC_204 */ | ||
723 | #ifdef GSCD_DEBUG | ||
724 | printk("LOC_204 "); | ||
725 | #endif | ||
726 | |||
727 | do { | ||
728 | result = wait_drv_ready(); | ||
729 | if (result == drv_mode) { | ||
730 | return; | ||
731 | } | ||
732 | } while (result != 4); | ||
733 | |||
734 | /* LOC_205 */ | ||
735 | #ifdef GSCD_DEBUG | ||
736 | printk("LOC_205 "); | ||
737 | #endif | ||
738 | |||
739 | disk_state = inb(GSCDPORT(2)); | ||
740 | |||
741 | do { | ||
742 | result = wait_drv_ready(); | ||
743 | } while (result != drv_mode); | ||
744 | return; | ||
745 | |||
746 | } | ||
747 | |||
748 | |||
749 | static void cmd_read_w(char *pb, int count, int size) | ||
750 | { | ||
751 | int result; | ||
752 | int i; | ||
753 | |||
754 | |||
755 | #ifdef GSCD_DEBUG | ||
756 | printk("LOC_185 "); | ||
757 | #endif | ||
758 | |||
759 | do { | ||
760 | /* LOC_185 */ | ||
761 | do { | ||
762 | result = wait_drv_ready(); | ||
763 | } while (result != 6 || result == 0x0E); | ||
764 | |||
765 | if (result != 6) { | ||
766 | cmd_end(); | ||
767 | return; | ||
768 | } | ||
769 | |||
770 | for (i = 0; i < size; i++) { | ||
771 | /* na, hier muss ich noch mal drueber nachdenken */ | ||
772 | *pb = inw(GSCDPORT(2)); | ||
773 | pb++; | ||
774 | } | ||
775 | count--; | ||
776 | } while (count > 0); | ||
777 | |||
778 | cmd_end(); | ||
779 | return; | ||
780 | } | ||
781 | |||
782 | static int __init find_drives(void) | ||
783 | { | ||
784 | int *pdrv; | ||
785 | int drvnum; | ||
786 | int subdrv; | ||
787 | int i; | ||
788 | |||
789 | speed = 0; | ||
790 | pdrv = (int *) &drv_states; | ||
791 | curr_drv_state = 0xFE; | ||
792 | subdrv = 0; | ||
793 | drvnum = 0; | ||
794 | |||
795 | for (i = 0; i < 8; i++) { | ||
796 | subdrv++; | ||
797 | cmd_status(); | ||
798 | disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01; | ||
799 | if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) { | ||
800 | /* LOC_240 */ | ||
801 | *pdrv = curr_drv_state; | ||
802 | init_cd_drive(drvnum); | ||
803 | pdrv++; | ||
804 | drvnum++; | ||
805 | } else { | ||
806 | if (subdrv < 2) { | ||
807 | continue; | ||
808 | } else { | ||
809 | subdrv = 0; | ||
810 | } | ||
811 | } | ||
812 | |||
813 | /* curr_drv_state<<1; <-- das geht irgendwie nicht */ | ||
814 | /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */ | ||
815 | curr_drv_state *= 2; | ||
816 | curr_drv_state |= 1; | ||
817 | #ifdef GSCD_DEBUG | ||
818 | printk("DriveState: %d\n", curr_drv_state); | ||
819 | #endif | ||
820 | } | ||
821 | |||
822 | ndrives = drvnum; | ||
823 | return drvnum; | ||
824 | } | ||
825 | |||
826 | static void __init init_cd_drive(int num) | ||
827 | { | ||
828 | char resp[50]; | ||
829 | int i; | ||
830 | |||
831 | printk("GSCD: init unit %d\n", num); | ||
832 | cc_Ident((char *) &resp); | ||
833 | |||
834 | printk("GSCD: identification: "); | ||
835 | for (i = 0; i < 0x1E; i++) { | ||
836 | printk("%c", resp[i]); | ||
837 | } | ||
838 | printk("\n"); | ||
839 | |||
840 | cc_SetSpeed(); | ||
841 | |||
842 | } | ||
843 | |||
844 | #ifdef FUTURE_WORK | ||
845 | /* return_done */ | ||
846 | static void update_state(void) | ||
847 | { | ||
848 | unsigned int AX; | ||
849 | |||
850 | |||
851 | if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) { | ||
852 | if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) { | ||
853 | AX = ST_INVALID; | ||
854 | } | ||
855 | |||
856 | if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) | ||
857 | == 0) { | ||
858 | invalidate(); | ||
859 | f_drv_ok = 0; | ||
860 | } | ||
861 | |||
862 | AX |= 0x8000; | ||
863 | } | ||
864 | |||
865 | if (disk_state & ST_PLAYING) { | ||
866 | AX |= 0x200; | ||
867 | } | ||
868 | |||
869 | AX |= 0x100; | ||
870 | /* pkt_esbx = AX; */ | ||
871 | |||
872 | disk_state = 0; | ||
873 | |||
874 | } | ||
875 | #endif | ||
876 | |||
877 | static struct gendisk *gscd_disk; | ||
878 | |||
879 | static void __exit gscd_exit(void) | ||
880 | { | ||
881 | CLEAR_TIMER; | ||
882 | |||
883 | del_gendisk(gscd_disk); | ||
884 | put_disk(gscd_disk); | ||
885 | if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) { | ||
886 | printk("What's that: can't unregister GoldStar-module\n"); | ||
887 | return; | ||
888 | } | ||
889 | blk_cleanup_queue(gscd_queue); | ||
890 | release_region(gscd_port, GSCD_IO_EXTENT); | ||
891 | printk(KERN_INFO "GoldStar-module released.\n"); | ||
892 | } | ||
893 | |||
894 | /* This is the common initialisation for the GoldStar drive. */ | ||
895 | /* It is called at boot time AND for module init. */ | ||
896 | static int __init gscd_init(void) | ||
897 | { | ||
898 | int i; | ||
899 | int result; | ||
900 | int ret=0; | ||
901 | |||
902 | printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION); | ||
903 | printk(KERN_INFO | ||
904 | "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", | ||
905 | gscd_port); | ||
906 | |||
907 | if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) { | ||
908 | printk(KERN_WARNING "GSCD: Init failed, I/O port (%X) already" | ||
909 | " in use.\n", gscd_port); | ||
910 | return -EIO; | ||
911 | } | ||
912 | |||
913 | |||
914 | /* check for card */ | ||
915 | result = wait_drv_ready(); | ||
916 | if (result == 0x09) { | ||
917 | printk(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n"); | ||
918 | ret = -EIO; | ||
919 | goto err_out1; | ||
920 | } | ||
921 | |||
922 | if (result == 0x0b) { | ||
923 | drv_mode = result; | ||
924 | i = find_drives(); | ||
925 | if (i == 0) { | ||
926 | printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is" | ||
927 | " not found.\n"); | ||
928 | ret = -EIO; | ||
929 | goto err_out1; | ||
930 | } | ||
931 | } | ||
932 | |||
933 | if ((result != 0x0b) && (result != 0x09)) { | ||
934 | printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not " | ||
935 | "exist or H/W error\n"); | ||
936 | ret = -EIO; | ||
937 | goto err_out1; | ||
938 | } | ||
939 | |||
940 | /* reset all drives */ | ||
941 | i = 0; | ||
942 | while (drv_states[i] != 0) { | ||
943 | curr_drv_state = drv_states[i]; | ||
944 | printk(KERN_INFO "GSCD: Reset unit %d ... ", i); | ||
945 | cc_Reset(); | ||
946 | printk("done\n"); | ||
947 | i++; | ||
948 | } | ||
949 | |||
950 | gscd_disk = alloc_disk(1); | ||
951 | if (!gscd_disk) | ||
952 | goto err_out1; | ||
953 | gscd_disk->major = MAJOR_NR; | ||
954 | gscd_disk->first_minor = 0; | ||
955 | gscd_disk->fops = &gscd_fops; | ||
956 | sprintf(gscd_disk->disk_name, "gscd"); | ||
957 | |||
958 | if (register_blkdev(MAJOR_NR, "gscd")) { | ||
959 | ret = -EIO; | ||
960 | goto err_out2; | ||
961 | } | ||
962 | |||
963 | gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock); | ||
964 | if (!gscd_queue) { | ||
965 | ret = -ENOMEM; | ||
966 | goto err_out3; | ||
967 | } | ||
968 | |||
969 | disk_state = 0; | ||
970 | gscdPresent = 1; | ||
971 | |||
972 | gscd_disk->queue = gscd_queue; | ||
973 | add_disk(gscd_disk); | ||
974 | |||
975 | printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n"); | ||
976 | return 0; | ||
977 | |||
978 | err_out3: | ||
979 | unregister_blkdev(MAJOR_NR, "gscd"); | ||
980 | err_out2: | ||
981 | put_disk(gscd_disk); | ||
982 | err_out1: | ||
983 | release_region(gscd_port, GSCD_IO_EXTENT); | ||
984 | return ret; | ||
985 | } | ||
986 | |||
987 | static void gscd_hsg2msf(long hsg, struct msf *msf) | ||
988 | { | ||
989 | hsg += CD_MSF_OFFSET; | ||
990 | msf->min = hsg / (CD_FRAMES * CD_SECS); | ||
991 | hsg %= CD_FRAMES * CD_SECS; | ||
992 | msf->sec = hsg / CD_FRAMES; | ||
993 | msf->frame = hsg % CD_FRAMES; | ||
994 | |||
995 | gscd_bin2bcd(&msf->min); /* convert to BCD */ | ||
996 | gscd_bin2bcd(&msf->sec); | ||
997 | gscd_bin2bcd(&msf->frame); | ||
998 | } | ||
999 | |||
1000 | |||
1001 | static void gscd_bin2bcd(unsigned char *p) | ||
1002 | { | ||
1003 | int u, t; | ||
1004 | |||
1005 | u = *p % 10; | ||
1006 | t = *p / 10; | ||
1007 | *p = u | (t << 4); | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | #ifdef FUTURE_WORK | ||
1012 | static long gscd_msf2hsg(struct msf *mp) | ||
1013 | { | ||
1014 | return gscd_bcd2bin(mp->frame) | ||
1015 | + gscd_bcd2bin(mp->sec) * CD_FRAMES | ||
1016 | + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET; | ||
1017 | } | ||
1018 | |||
1019 | static int gscd_bcd2bin(unsigned char bcd) | ||
1020 | { | ||
1021 | return (bcd >> 4) * 10 + (bcd & 0xF); | ||
1022 | } | ||
1023 | #endif | ||
1024 | |||
1025 | MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"); | ||
1026 | MODULE_LICENSE("GPL"); | ||
1027 | module_init(gscd_init); | ||
1028 | module_exit(gscd_exit); | ||
1029 | MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/gscd.h b/drivers/cdrom/gscd.h deleted file mode 100644 index a41e64bfc061..000000000000 --- a/drivers/cdrom/gscd.h +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
1 | /* | ||
2 | * Definitions for a GoldStar R420 CD-ROM interface | ||
3 | * | ||
4 | * Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de> | ||
5 | * Eberhard Moenkeberg <emoenke@gwdg.de> | ||
6 | * | ||
7 | * Published under the GPL. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | |||
12 | /* The Interface Card default address is 0x340. This will work for most | ||
13 | applications. Address selection is accomplished by jumpers PN801-1 to | ||
14 | PN801-4 on the GoldStar Interface Card. | ||
15 | Appropriate settings are: 0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360 | ||
16 | 0x370, 0x380, 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0 */ | ||
17 | |||
18 | /* insert here the I/O port address and extent */ | ||
19 | #define GSCD_BASE_ADDR 0x340 | ||
20 | #define GSCD_IO_EXTENT 4 | ||
21 | |||
22 | |||
23 | /************** nothing to set up below here *********************/ | ||
24 | |||
25 | /* port access macro */ | ||
26 | #define GSCDPORT(x) (gscd_port + (x)) | ||
27 | |||
28 | /* | ||
29 | * commands | ||
30 | * the lower nibble holds the command length | ||
31 | */ | ||
32 | #define CMD_STATUS 0x01 | ||
33 | #define CMD_READSUBQ 0x02 /* 1: ?, 2: UPC, 5: ? */ | ||
34 | #define CMD_SEEK 0x05 /* read_mode M-S-F */ | ||
35 | #define CMD_READ 0x07 /* read_mode M-S-F nsec_h nsec_l */ | ||
36 | #define CMD_RESET 0x11 | ||
37 | #define CMD_SETMODE 0x15 | ||
38 | #define CMD_PLAY 0x17 /* M-S-F M-S-F */ | ||
39 | #define CMD_LOCK_CTL 0x22 /* 0: unlock, 1: lock */ | ||
40 | #define CMD_IDENT 0x31 | ||
41 | #define CMD_SETSPEED 0x32 /* 0: auto */ /* ??? */ | ||
42 | #define CMD_GETMODE 0x41 | ||
43 | #define CMD_PAUSE 0x51 | ||
44 | #define CMD_READTOC 0x61 | ||
45 | #define CMD_DISKINFO 0x71 | ||
46 | #define CMD_TRAY_CTL 0x81 | ||
47 | |||
48 | /* | ||
49 | * disk_state: | ||
50 | */ | ||
51 | #define ST_PLAYING 0x80 | ||
52 | #define ST_UNLOCKED 0x40 | ||
53 | #define ST_NO_DISK 0x20 | ||
54 | #define ST_DOOR_OPEN 0x10 | ||
55 | #define ST_x08 0x08 | ||
56 | #define ST_x04 0x04 | ||
57 | #define ST_INVALID 0x02 | ||
58 | #define ST_x01 0x01 | ||
59 | |||
60 | /* | ||
61 | * cmd_type: | ||
62 | */ | ||
63 | #define TYPE_INFO 0x01 | ||
64 | #define TYPE_DATA 0x02 | ||
65 | |||
66 | /* | ||
67 | * read_mode: | ||
68 | */ | ||
69 | #define MOD_POLLED 0x80 | ||
70 | #define MOD_x08 0x08 | ||
71 | #define MOD_RAW 0x04 | ||
72 | |||
73 | #define READ_DATA(port, buf, nr) insb(port, buf, nr) | ||
74 | |||
75 | #define SET_TIMER(func, jifs) \ | ||
76 | ((mod_timer(&gscd_timer, jiffies + jifs)), \ | ||
77 | (gscd_timer.function = func)) | ||
78 | |||
79 | #define CLEAR_TIMER del_timer_sync(&gscd_timer) | ||
80 | |||
81 | #define MAX_TRACKS 104 | ||
82 | |||
83 | struct msf { | ||
84 | unsigned char min; | ||
85 | unsigned char sec; | ||
86 | unsigned char frame; | ||
87 | }; | ||
88 | |||
89 | struct gscd_Play_msf { | ||
90 | struct msf start; | ||
91 | struct msf end; | ||
92 | }; | ||
93 | |||
94 | struct gscd_DiskInfo { | ||
95 | unsigned char first; | ||
96 | unsigned char last; | ||
97 | struct msf diskLength; | ||
98 | struct msf firstTrack; | ||
99 | }; | ||
100 | |||
101 | struct gscd_Toc { | ||
102 | unsigned char ctrl_addr; | ||
103 | unsigned char track; | ||
104 | unsigned char pointIndex; | ||
105 | struct msf trackTime; | ||
106 | struct msf diskTime; | ||
107 | }; | ||
108 | |||
diff --git a/drivers/cdrom/isp16.c b/drivers/cdrom/isp16.c deleted file mode 100644 index db0fd9a240e3..000000000000 --- a/drivers/cdrom/isp16.c +++ /dev/null | |||
@@ -1,374 +0,0 @@ | |||
1 | /* -- ISP16 cdrom detection and configuration | ||
2 | * | ||
3 | * Copyright (c) 1995,1996 Eric van der Maarel <H.T.M.v.d.Maarel@marin.nl> | ||
4 | * | ||
5 | * Version 0.6 | ||
6 | * | ||
7 | * History: | ||
8 | * 0.5 First release. | ||
9 | * Was included in the sjcd and optcd cdrom drivers. | ||
10 | * 0.6 First "stand-alone" version. | ||
11 | * Removed sound configuration. | ||
12 | * Added "module" support. | ||
13 | * | ||
14 | * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
15 | * Removed init_module & cleanup_module in favor of | ||
16 | * module_init & module_exit. | ||
17 | * Torben Mathiasen <tmm@image.dk> | ||
18 | * | ||
19 | * 19 June 2004 -- check_region() converted to request_region() | ||
20 | * and return statement cleanups. | ||
21 | * - Jesper Juhl | ||
22 | * | ||
23 | * Detect cdrom interface on ISP16 sound card. | ||
24 | * Configure cdrom interface. | ||
25 | * | ||
26 | * Algorithm for the card with OPTi 82C928 taken | ||
27 | * from the CDSETUP.SYS driver for MSDOS, | ||
28 | * by OPTi Computers, version 2.03. | ||
29 | * Algorithm for the card with OPTi 82C929 as communicated | ||
30 | * to me by Vadim Model and Leo Spiekman. | ||
31 | * | ||
32 | * This program is free software; you can redistribute it and/or modify | ||
33 | * it under the terms of the GNU General Public License as published by | ||
34 | * the Free Software Foundation; either version 2 of the License, or | ||
35 | * (at your option) any later version. | ||
36 | * | ||
37 | * This program is distributed in the hope that it will be useful, | ||
38 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
40 | * GNU General Public License for more details. | ||
41 | * | ||
42 | * You should have received a copy of the GNU General Public License | ||
43 | * along with this program; if not, write to the Free Software | ||
44 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
45 | * | ||
46 | */ | ||
47 | |||
48 | #define ISP16_VERSION_MAJOR 0 | ||
49 | #define ISP16_VERSION_MINOR 6 | ||
50 | |||
51 | #include <linux/module.h> | ||
52 | |||
53 | #include <linux/fs.h> | ||
54 | #include <linux/kernel.h> | ||
55 | #include <linux/string.h> | ||
56 | #include <linux/ioport.h> | ||
57 | #include <linux/init.h> | ||
58 | #include <asm/io.h> | ||
59 | #include "isp16.h" | ||
60 | |||
61 | static short isp16_detect(void); | ||
62 | static short isp16_c928__detect(void); | ||
63 | static short isp16_c929__detect(void); | ||
64 | static short isp16_cdi_config(int base, u_char drive_type, int irq, | ||
65 | int dma); | ||
66 | static short isp16_type; /* dependent on type of interface card */ | ||
67 | static u_char isp16_ctrl; | ||
68 | static u_short isp16_enable_port; | ||
69 | |||
70 | static int isp16_cdrom_base = ISP16_CDROM_IO_BASE; | ||
71 | static int isp16_cdrom_irq = ISP16_CDROM_IRQ; | ||
72 | static int isp16_cdrom_dma = ISP16_CDROM_DMA; | ||
73 | static char *isp16_cdrom_type = ISP16_CDROM_TYPE; | ||
74 | |||
75 | module_param(isp16_cdrom_base, int, 0); | ||
76 | module_param(isp16_cdrom_irq, int, 0); | ||
77 | module_param(isp16_cdrom_dma, int, 0); | ||
78 | module_param(isp16_cdrom_type, charp, 0); | ||
79 | |||
80 | #define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p)) | ||
81 | #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) | ||
82 | |||
83 | #ifndef MODULE | ||
84 | |||
85 | static int | ||
86 | __init isp16_setup(char *str) | ||
87 | { | ||
88 | int ints[4]; | ||
89 | |||
90 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
91 | if (ints[0] > 0) | ||
92 | isp16_cdrom_base = ints[1]; | ||
93 | if (ints[0] > 1) | ||
94 | isp16_cdrom_irq = ints[2]; | ||
95 | if (ints[0] > 2) | ||
96 | isp16_cdrom_dma = ints[3]; | ||
97 | if (str) | ||
98 | isp16_cdrom_type = str; | ||
99 | |||
100 | return 1; | ||
101 | } | ||
102 | |||
103 | __setup("isp16=", isp16_setup); | ||
104 | |||
105 | #endif /* MODULE */ | ||
106 | |||
107 | /* | ||
108 | * ISP16 initialisation. | ||
109 | * | ||
110 | */ | ||
111 | static int __init isp16_init(void) | ||
112 | { | ||
113 | u_char expected_drive; | ||
114 | |||
115 | printk(KERN_INFO | ||
116 | "ISP16: configuration cdrom interface, version %d.%d.\n", | ||
117 | ISP16_VERSION_MAJOR, ISP16_VERSION_MINOR); | ||
118 | |||
119 | if (!strcmp(isp16_cdrom_type, "noisp16")) { | ||
120 | printk("ISP16: no cdrom interface configured.\n"); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | if (!request_region(ISP16_IO_BASE, ISP16_IO_SIZE, "isp16")) { | ||
125 | printk("ISP16: i/o ports already in use.\n"); | ||
126 | goto out; | ||
127 | } | ||
128 | |||
129 | if ((isp16_type = isp16_detect()) < 0) { | ||
130 | printk("ISP16: no cdrom interface found.\n"); | ||
131 | goto cleanup_out; | ||
132 | } | ||
133 | |||
134 | printk(KERN_INFO | ||
135 | "ISP16: cdrom interface (with OPTi 82C92%d chip) detected.\n", | ||
136 | (isp16_type == 2) ? 9 : 8); | ||
137 | |||
138 | if (!strcmp(isp16_cdrom_type, "Sanyo")) | ||
139 | expected_drive = | ||
140 | (isp16_type ? ISP16_SANYO1 : ISP16_SANYO0); | ||
141 | else if (!strcmp(isp16_cdrom_type, "Sony")) | ||
142 | expected_drive = ISP16_SONY; | ||
143 | else if (!strcmp(isp16_cdrom_type, "Panasonic")) | ||
144 | expected_drive = | ||
145 | (isp16_type ? ISP16_PANASONIC1 : ISP16_PANASONIC0); | ||
146 | else if (!strcmp(isp16_cdrom_type, "Mitsumi")) | ||
147 | expected_drive = ISP16_MITSUMI; | ||
148 | else { | ||
149 | printk("ISP16: %s not supported by cdrom interface.\n", | ||
150 | isp16_cdrom_type); | ||
151 | goto cleanup_out; | ||
152 | } | ||
153 | |||
154 | if (isp16_cdi_config(isp16_cdrom_base, expected_drive, | ||
155 | isp16_cdrom_irq, isp16_cdrom_dma) < 0) { | ||
156 | printk | ||
157 | ("ISP16: cdrom interface has not been properly configured.\n"); | ||
158 | goto cleanup_out; | ||
159 | } | ||
160 | printk(KERN_INFO | ||
161 | "ISP16: cdrom interface set up with io base 0x%03X, irq %d, dma %d," | ||
162 | " type %s.\n", isp16_cdrom_base, isp16_cdrom_irq, | ||
163 | isp16_cdrom_dma, isp16_cdrom_type); | ||
164 | return 0; | ||
165 | |||
166 | cleanup_out: | ||
167 | release_region(ISP16_IO_BASE, ISP16_IO_SIZE); | ||
168 | out: | ||
169 | return -EIO; | ||
170 | } | ||
171 | |||
172 | static short __init isp16_detect(void) | ||
173 | { | ||
174 | |||
175 | if (isp16_c929__detect() >= 0) | ||
176 | return 2; | ||
177 | else | ||
178 | return (isp16_c928__detect()); | ||
179 | } | ||
180 | |||
181 | static short __init isp16_c928__detect(void) | ||
182 | { | ||
183 | u_char ctrl; | ||
184 | u_char enable_cdrom; | ||
185 | u_char io; | ||
186 | short i = -1; | ||
187 | |||
188 | isp16_ctrl = ISP16_C928__CTRL; | ||
189 | isp16_enable_port = ISP16_C928__ENABLE_PORT; | ||
190 | |||
191 | /* read' and write' are a special read and write, respectively */ | ||
192 | |||
193 | /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */ | ||
194 | ctrl = ISP16_IN(ISP16_CTRL_PORT) & 0xFC; | ||
195 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
196 | |||
197 | /* read' 3,4 and 5-bit from the cdrom enable port */ | ||
198 | enable_cdrom = ISP16_IN(ISP16_C928__ENABLE_PORT) & 0x38; | ||
199 | |||
200 | if (!(enable_cdrom & 0x20)) { /* 5-bit not set */ | ||
201 | /* read' last 2 bits of ISP16_IO_SET_PORT */ | ||
202 | io = ISP16_IN(ISP16_IO_SET_PORT) & 0x03; | ||
203 | if (((io & 0x01) << 1) == (io & 0x02)) { /* bits are the same */ | ||
204 | if (io == 0) { /* ...the same and 0 */ | ||
205 | i = 0; | ||
206 | enable_cdrom |= 0x20; | ||
207 | } else { /* ...the same and 1 *//* my card, first time 'round */ | ||
208 | i = 1; | ||
209 | enable_cdrom |= 0x28; | ||
210 | } | ||
211 | ISP16_OUT(ISP16_C928__ENABLE_PORT, enable_cdrom); | ||
212 | } else { /* bits are not the same */ | ||
213 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
214 | return i; /* -> not detected: possibly incorrect conclusion */ | ||
215 | } | ||
216 | } else if (enable_cdrom == 0x20) | ||
217 | i = 0; | ||
218 | else if (enable_cdrom == 0x28) /* my card, already initialised */ | ||
219 | i = 1; | ||
220 | |||
221 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
222 | |||
223 | return i; | ||
224 | } | ||
225 | |||
226 | static short __init isp16_c929__detect(void) | ||
227 | { | ||
228 | u_char ctrl; | ||
229 | u_char tmp; | ||
230 | |||
231 | isp16_ctrl = ISP16_C929__CTRL; | ||
232 | isp16_enable_port = ISP16_C929__ENABLE_PORT; | ||
233 | |||
234 | /* read' and write' are a special read and write, respectively */ | ||
235 | |||
236 | /* read' ISP16_CTRL_PORT and save */ | ||
237 | ctrl = ISP16_IN(ISP16_CTRL_PORT); | ||
238 | |||
239 | /* write' zero to the ctrl port and get response */ | ||
240 | ISP16_OUT(ISP16_CTRL_PORT, 0); | ||
241 | tmp = ISP16_IN(ISP16_CTRL_PORT); | ||
242 | |||
243 | if (tmp != 2) /* isp16 with 82C929 not detected */ | ||
244 | return -1; | ||
245 | |||
246 | /* restore ctrl port value */ | ||
247 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
248 | |||
249 | return 2; | ||
250 | } | ||
251 | |||
252 | static short __init | ||
253 | isp16_cdi_config(int base, u_char drive_type, int irq, int dma) | ||
254 | { | ||
255 | u_char base_code; | ||
256 | u_char irq_code; | ||
257 | u_char dma_code; | ||
258 | u_char i; | ||
259 | |||
260 | if ((drive_type == ISP16_MITSUMI) && (dma != 0)) | ||
261 | printk("ISP16: Mitsumi cdrom drive has no dma support.\n"); | ||
262 | |||
263 | switch (base) { | ||
264 | case 0x340: | ||
265 | base_code = ISP16_BASE_340; | ||
266 | break; | ||
267 | case 0x330: | ||
268 | base_code = ISP16_BASE_330; | ||
269 | break; | ||
270 | case 0x360: | ||
271 | base_code = ISP16_BASE_360; | ||
272 | break; | ||
273 | case 0x320: | ||
274 | base_code = ISP16_BASE_320; | ||
275 | break; | ||
276 | default: | ||
277 | printk | ||
278 | ("ISP16: base address 0x%03X not supported by cdrom interface.\n", | ||
279 | base); | ||
280 | return -1; | ||
281 | } | ||
282 | switch (irq) { | ||
283 | case 0: | ||
284 | irq_code = ISP16_IRQ_X; | ||
285 | break; /* disable irq */ | ||
286 | case 5: | ||
287 | irq_code = ISP16_IRQ_5; | ||
288 | printk("ISP16: irq 5 shouldn't be used by cdrom interface," | ||
289 | " due to possible conflicts with the sound card.\n"); | ||
290 | break; | ||
291 | case 7: | ||
292 | irq_code = ISP16_IRQ_7; | ||
293 | printk("ISP16: irq 7 shouldn't be used by cdrom interface," | ||
294 | " due to possible conflicts with the sound card.\n"); | ||
295 | break; | ||
296 | case 3: | ||
297 | irq_code = ISP16_IRQ_3; | ||
298 | break; | ||
299 | case 9: | ||
300 | irq_code = ISP16_IRQ_9; | ||
301 | break; | ||
302 | case 10: | ||
303 | irq_code = ISP16_IRQ_10; | ||
304 | break; | ||
305 | case 11: | ||
306 | irq_code = ISP16_IRQ_11; | ||
307 | break; | ||
308 | default: | ||
309 | printk("ISP16: irq %d not supported by cdrom interface.\n", | ||
310 | irq); | ||
311 | return -1; | ||
312 | } | ||
313 | switch (dma) { | ||
314 | case 0: | ||
315 | dma_code = ISP16_DMA_X; | ||
316 | break; /* disable dma */ | ||
317 | case 1: | ||
318 | printk("ISP16: dma 1 cannot be used by cdrom interface," | ||
319 | " due to conflict with the sound card.\n"); | ||
320 | return -1; | ||
321 | break; | ||
322 | case 3: | ||
323 | dma_code = ISP16_DMA_3; | ||
324 | break; | ||
325 | case 5: | ||
326 | dma_code = ISP16_DMA_5; | ||
327 | break; | ||
328 | case 6: | ||
329 | dma_code = ISP16_DMA_6; | ||
330 | break; | ||
331 | case 7: | ||
332 | dma_code = ISP16_DMA_7; | ||
333 | break; | ||
334 | default: | ||
335 | printk("ISP16: dma %d not supported by cdrom interface.\n", | ||
336 | dma); | ||
337 | return -1; | ||
338 | } | ||
339 | |||
340 | if (drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 && | ||
341 | drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 && | ||
342 | drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI && | ||
343 | drive_type != ISP16_DRIVE_X) { | ||
344 | printk | ||
345 | ("ISP16: drive type (code 0x%02X) not supported by cdrom" | ||
346 | " interface.\n", drive_type); | ||
347 | return -1; | ||
348 | } | ||
349 | |||
350 | /* set type of interface */ | ||
351 | i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */ | ||
352 | ISP16_OUT(ISP16_DRIVE_SET_PORT, i | drive_type); | ||
353 | |||
354 | /* enable cdrom on interface with 82C929 chip */ | ||
355 | if (isp16_type > 1) | ||
356 | ISP16_OUT(isp16_enable_port, ISP16_ENABLE_CDROM); | ||
357 | |||
358 | /* set base address, irq and dma */ | ||
359 | i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */ | ||
360 | ISP16_OUT(ISP16_IO_SET_PORT, i | base_code | irq_code | dma_code); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static void __exit isp16_exit(void) | ||
366 | { | ||
367 | release_region(ISP16_IO_BASE, ISP16_IO_SIZE); | ||
368 | printk(KERN_INFO "ISP16: module released.\n"); | ||
369 | } | ||
370 | |||
371 | module_init(isp16_init); | ||
372 | module_exit(isp16_exit); | ||
373 | |||
374 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/cdrom/isp16.h b/drivers/cdrom/isp16.h deleted file mode 100644 index 5bd22c8f7a96..000000000000 --- a/drivers/cdrom/isp16.h +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | /* -- isp16.h | ||
2 | * | ||
3 | * Header for detection and initialisation of cdrom interface (only) on | ||
4 | * ISP16 (MAD16, Mozart) sound card. | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | /* These are the default values */ | ||
23 | #define ISP16_CDROM_TYPE "Sanyo" | ||
24 | #define ISP16_CDROM_IO_BASE 0x340 | ||
25 | #define ISP16_CDROM_IRQ 0 | ||
26 | #define ISP16_CDROM_DMA 0 | ||
27 | |||
28 | /* Some (Media)Magic */ | ||
29 | /* define types of drive the interface on an ISP16 card may be looking at */ | ||
30 | #define ISP16_DRIVE_X 0x00 | ||
31 | #define ISP16_SONY 0x02 | ||
32 | #define ISP16_PANASONIC0 0x02 | ||
33 | #define ISP16_SANYO0 0x02 | ||
34 | #define ISP16_MITSUMI 0x04 | ||
35 | #define ISP16_PANASONIC1 0x06 | ||
36 | #define ISP16_SANYO1 0x06 | ||
37 | #define ISP16_DRIVE_NOT_USED 0x08 /* not used */ | ||
38 | #define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/ | ||
39 | /* ...for port */ | ||
40 | #define ISP16_DRIVE_SET_PORT 0xF8D | ||
41 | /* set io parameters */ | ||
42 | #define ISP16_BASE_340 0x00 | ||
43 | #define ISP16_BASE_330 0x40 | ||
44 | #define ISP16_BASE_360 0x80 | ||
45 | #define ISP16_BASE_320 0xC0 | ||
46 | #define ISP16_IRQ_X 0x00 | ||
47 | #define ISP16_IRQ_5 0x04 /* shouldn't be used to avoid sound card conflicts */ | ||
48 | #define ISP16_IRQ_7 0x08 /* shouldn't be used to avoid sound card conflicts */ | ||
49 | #define ISP16_IRQ_3 0x0C | ||
50 | #define ISP16_IRQ_9 0x10 | ||
51 | #define ISP16_IRQ_10 0x14 | ||
52 | #define ISP16_IRQ_11 0x18 | ||
53 | #define ISP16_DMA_X 0x03 | ||
54 | #define ISP16_DMA_3 0x00 | ||
55 | #define ISP16_DMA_5 0x00 | ||
56 | #define ISP16_DMA_6 0x01 | ||
57 | #define ISP16_DMA_7 0x02 | ||
58 | #define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */ | ||
59 | /* ...for port */ | ||
60 | #define ISP16_IO_SET_PORT 0xF8E | ||
61 | /* enable the card */ | ||
62 | #define ISP16_C928__ENABLE_PORT 0xF90 /* ISP16 with OPTi 82C928 chip */ | ||
63 | #define ISP16_C929__ENABLE_PORT 0xF91 /* ISP16 with OPTi 82C929 chip */ | ||
64 | #define ISP16_ENABLE_CDROM 0x80 /* seven bit */ | ||
65 | |||
66 | /* the magic stuff */ | ||
67 | #define ISP16_CTRL_PORT 0xF8F | ||
68 | #define ISP16_C928__CTRL 0xE2 /* ISP16 with OPTi 82C928 chip */ | ||
69 | #define ISP16_C929__CTRL 0xE3 /* ISP16 with OPTi 82C929 chip */ | ||
70 | |||
71 | #define ISP16_IO_BASE 0xF8D | ||
72 | #define ISP16_IO_SIZE 5 /* ports used from 0xF8D up to 0xF91 */ | ||
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c deleted file mode 100644 index 4310cc84dfed..000000000000 --- a/drivers/cdrom/mcdx.c +++ /dev/null | |||
@@ -1,1943 +0,0 @@ | |||
1 | /* | ||
2 | * The Mitsumi CDROM interface | ||
3 | * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de> | ||
4 | * VERSION: 2.14(hs) | ||
5 | * | ||
6 | * ... anyway, I'm back again, thanks to Marcin, he adopted | ||
7 | * large portions of my code (at least the parts containing | ||
8 | * my main thoughts ...) | ||
9 | * | ||
10 | ****************** H E L P ********************************* | ||
11 | * If you ever plan to update your CD ROM drive and perhaps | ||
12 | * want to sell or simply give away your Mitsumi FX-001[DS] | ||
13 | * -- Please -- | ||
14 | * mail me (heiko@lotte.sax.de). When my last drive goes | ||
15 | * ballistic no more driver support will be available from me! | ||
16 | ************************************************************* | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation; either version 2, or (at your option) | ||
21 | * any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; see the file COPYING. If not, write to | ||
30 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | * | ||
32 | * Thanks to | ||
33 | * The Linux Community at all and ... | ||
34 | * Martin Harriss (he wrote the first Mitsumi Driver) | ||
35 | * Eberhard Moenkeberg (he gave me much support and the initial kick) | ||
36 | * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they | ||
37 | * improved the original driver) | ||
38 | * Jon Tombs, Bjorn Ekwall (module support) | ||
39 | * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) | ||
40 | * Gerd Knorr (he lent me his PhotoCD) | ||
41 | * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) | ||
42 | * Andreas Kies (testing the mysterious hang-ups) | ||
43 | * Heiko Eissfeldt (VERIFY_READ/WRITE) | ||
44 | * Marcin Dalecki (improved performance, shortened code) | ||
45 | * ... somebody forgotten? | ||
46 | * | ||
47 | * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
48 | * Removed init_module & cleanup_module in favor of | ||
49 | * module_init & module_exit. | ||
50 | * Torben Mathiasen <tmm@image.dk> | ||
51 | */ | ||
52 | |||
53 | |||
54 | #ifdef RCS | ||
55 | static const char *mcdx_c_version | ||
56 | = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $"; | ||
57 | #endif | ||
58 | |||
59 | #include <linux/module.h> | ||
60 | |||
61 | #include <linux/errno.h> | ||
62 | #include <linux/interrupt.h> | ||
63 | #include <linux/fs.h> | ||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/cdrom.h> | ||
66 | #include <linux/ioport.h> | ||
67 | #include <linux/mm.h> | ||
68 | #include <linux/slab.h> | ||
69 | #include <linux/init.h> | ||
70 | #include <asm/io.h> | ||
71 | #include <asm/current.h> | ||
72 | #include <asm/uaccess.h> | ||
73 | |||
74 | #include <linux/major.h> | ||
75 | #define MAJOR_NR MITSUMI_X_CDROM_MAJOR | ||
76 | #include <linux/blkdev.h> | ||
77 | |||
78 | #include "mcdx.h" | ||
79 | |||
80 | #ifndef HZ | ||
81 | #error HZ not defined | ||
82 | #endif | ||
83 | |||
84 | #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args) | ||
85 | |||
86 | #if !MCDX_QUIET | ||
87 | #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args) | ||
88 | #else | ||
89 | #define xinfo(fmt, args...) { ; } | ||
90 | #endif | ||
91 | |||
92 | #if MCDX_DEBUG | ||
93 | #define xtrace(lvl, fmt, args...) \ | ||
94 | { if (lvl > 0) \ | ||
95 | { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } } | ||
96 | #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args) | ||
97 | #else | ||
98 | #define xtrace(lvl, fmt, args...) { ; } | ||
99 | #define xdebug(fmt, args...) { ; } | ||
100 | #endif | ||
101 | |||
102 | /* CONSTANTS *******************************************************/ | ||
103 | |||
104 | /* Following are the number of sectors we _request_ from the drive | ||
105 | every time an access outside the already requested range is done. | ||
106 | The _direct_ size is the number of sectors we're allowed to skip | ||
107 | directly (performing a read instead of requesting the new sector | ||
108 | needed */ | ||
109 | static const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */ | ||
110 | static const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */ | ||
111 | |||
112 | enum drivemodes { TOC, DATA, RAW, COOKED }; | ||
113 | enum datamodes { MODE0, MODE1, MODE2 }; | ||
114 | enum resetmodes { SOFT, HARD }; | ||
115 | |||
116 | static const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */ | ||
117 | static const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */ | ||
118 | static const int DOOR = 0x04; /* door locking capability */ | ||
119 | static const int MULTI = 0x08; /* multi session capability */ | ||
120 | |||
121 | static const unsigned char READ1X = 0xc0; | ||
122 | static const unsigned char READ2X = 0xc1; | ||
123 | |||
124 | |||
125 | /* DECLARATIONS ****************************************************/ | ||
126 | struct s_subqcode { | ||
127 | unsigned char control; | ||
128 | unsigned char tno; | ||
129 | unsigned char index; | ||
130 | struct cdrom_msf0 tt; | ||
131 | struct cdrom_msf0 dt; | ||
132 | }; | ||
133 | |||
134 | struct s_diskinfo { | ||
135 | unsigned int n_first; | ||
136 | unsigned int n_last; | ||
137 | struct cdrom_msf0 msf_leadout; | ||
138 | struct cdrom_msf0 msf_first; | ||
139 | }; | ||
140 | |||
141 | struct s_multi { | ||
142 | unsigned char multi; | ||
143 | struct cdrom_msf0 msf_last; | ||
144 | }; | ||
145 | |||
146 | struct s_version { | ||
147 | unsigned char code; | ||
148 | unsigned char ver; | ||
149 | }; | ||
150 | |||
151 | /* Per drive/controller stuff **************************************/ | ||
152 | |||
153 | struct s_drive_stuff { | ||
154 | /* waitqueues */ | ||
155 | wait_queue_head_t busyq; | ||
156 | wait_queue_head_t lockq; | ||
157 | wait_queue_head_t sleepq; | ||
158 | |||
159 | /* flags */ | ||
160 | volatile int introk; /* status of last irq operation */ | ||
161 | volatile int busy; /* drive performs an operation */ | ||
162 | volatile int lock; /* exclusive usage */ | ||
163 | |||
164 | /* cd infos */ | ||
165 | struct s_diskinfo di; | ||
166 | struct s_multi multi; | ||
167 | struct s_subqcode *toc; /* first entry of the toc array */ | ||
168 | struct s_subqcode start; | ||
169 | struct s_subqcode stop; | ||
170 | int xa; /* 1 if xa disk */ | ||
171 | int audio; /* 1 if audio disk */ | ||
172 | int audiostatus; | ||
173 | |||
174 | /* `buffer' control */ | ||
175 | volatile int valid; /* pending, ..., values are valid */ | ||
176 | volatile int pending; /* next sector to be read */ | ||
177 | volatile int low_border; /* first sector not to be skipped direct */ | ||
178 | volatile int high_border; /* first sector `out of area' */ | ||
179 | #ifdef AK2 | ||
180 | volatile int int_err; | ||
181 | #endif /* AK2 */ | ||
182 | |||
183 | /* adds and odds */ | ||
184 | unsigned wreg_data; /* w data */ | ||
185 | unsigned wreg_reset; /* w hardware reset */ | ||
186 | unsigned wreg_hcon; /* w hardware conf */ | ||
187 | unsigned wreg_chn; /* w channel */ | ||
188 | unsigned rreg_data; /* r data */ | ||
189 | unsigned rreg_status; /* r status */ | ||
190 | |||
191 | int irq; /* irq used by this drive */ | ||
192 | int present; /* drive present and its capabilities */ | ||
193 | unsigned char readcmd; /* read cmd depends on single/double speed */ | ||
194 | unsigned char playcmd; /* play should always be single speed */ | ||
195 | unsigned int xxx; /* set if changed, reset while open */ | ||
196 | unsigned int yyy; /* set if changed, reset by media_changed */ | ||
197 | int users; /* keeps track of open/close */ | ||
198 | int lastsector; /* last block accessible */ | ||
199 | int status; /* last operation's error / status */ | ||
200 | int readerrs; /* # of blocks read w/o error */ | ||
201 | struct cdrom_device_info info; | ||
202 | struct gendisk *disk; | ||
203 | }; | ||
204 | |||
205 | |||
206 | /* Prototypes ******************************************************/ | ||
207 | |||
208 | /* The following prototypes are already declared elsewhere. They are | ||
209 | repeated here to show what's going on. And to sense, if they're | ||
210 | changed elsewhere. */ | ||
211 | |||
212 | static int mcdx_init(void); | ||
213 | |||
214 | static int mcdx_block_open(struct inode *inode, struct file *file) | ||
215 | { | ||
216 | struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; | ||
217 | return cdrom_open(&p->info, inode, file); | ||
218 | } | ||
219 | |||
220 | static int mcdx_block_release(struct inode *inode, struct file *file) | ||
221 | { | ||
222 | struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; | ||
223 | return cdrom_release(&p->info, file); | ||
224 | } | ||
225 | |||
226 | static int mcdx_block_ioctl(struct inode *inode, struct file *file, | ||
227 | unsigned cmd, unsigned long arg) | ||
228 | { | ||
229 | struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; | ||
230 | return cdrom_ioctl(file, &p->info, inode, cmd, arg); | ||
231 | } | ||
232 | |||
233 | static int mcdx_block_media_changed(struct gendisk *disk) | ||
234 | { | ||
235 | struct s_drive_stuff *p = disk->private_data; | ||
236 | return cdrom_media_changed(&p->info); | ||
237 | } | ||
238 | |||
239 | static struct block_device_operations mcdx_bdops = | ||
240 | { | ||
241 | .owner = THIS_MODULE, | ||
242 | .open = mcdx_block_open, | ||
243 | .release = mcdx_block_release, | ||
244 | .ioctl = mcdx_block_ioctl, | ||
245 | .media_changed = mcdx_block_media_changed, | ||
246 | }; | ||
247 | |||
248 | |||
249 | /* Indirect exported functions. These functions are exported by their | ||
250 | addresses, such as mcdx_open and mcdx_close in the | ||
251 | structure mcdx_dops. */ | ||
252 | |||
253 | /* exported by file_ops */ | ||
254 | static int mcdx_open(struct cdrom_device_info *cdi, int purpose); | ||
255 | static void mcdx_close(struct cdrom_device_info *cdi); | ||
256 | static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr); | ||
257 | static int mcdx_tray_move(struct cdrom_device_info *cdi, int position); | ||
258 | static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock); | ||
259 | static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, | ||
260 | unsigned int cmd, void *arg); | ||
261 | |||
262 | /* misc internal support functions */ | ||
263 | static void log2msf(unsigned int, struct cdrom_msf0 *); | ||
264 | static unsigned int msf2log(const struct cdrom_msf0 *); | ||
265 | static unsigned int uint2bcd(unsigned int); | ||
266 | static unsigned int bcd2uint(unsigned char); | ||
267 | static unsigned port(int *); | ||
268 | static int irq(int *); | ||
269 | static void mcdx_delay(struct s_drive_stuff *, long jifs); | ||
270 | static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector, | ||
271 | int nr_sectors); | ||
272 | static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector, | ||
273 | int nr_sectors); | ||
274 | |||
275 | static int mcdx_config(struct s_drive_stuff *, int); | ||
276 | static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *, | ||
277 | int); | ||
278 | static int mcdx_stop(struct s_drive_stuff *, int); | ||
279 | static int mcdx_hold(struct s_drive_stuff *, int); | ||
280 | static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int); | ||
281 | static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int); | ||
282 | static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int); | ||
283 | static int mcdx_requestsubqcode(struct s_drive_stuff *, | ||
284 | struct s_subqcode *, int); | ||
285 | static int mcdx_requestmultidiskinfo(struct s_drive_stuff *, | ||
286 | struct s_multi *, int); | ||
287 | static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *, | ||
288 | int); | ||
289 | static int mcdx_getstatus(struct s_drive_stuff *, int); | ||
290 | static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *); | ||
291 | static int mcdx_talk(struct s_drive_stuff *, | ||
292 | const unsigned char *cmd, size_t, | ||
293 | void *buffer, size_t size, unsigned int timeout, int); | ||
294 | static int mcdx_readtoc(struct s_drive_stuff *); | ||
295 | static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *); | ||
296 | static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *); | ||
297 | static int mcdx_setattentuator(struct s_drive_stuff *, | ||
298 | struct cdrom_volctrl *, int); | ||
299 | |||
300 | /* static variables ************************************************/ | ||
301 | |||
302 | static int mcdx_drive_map[][2] = MCDX_DRIVEMAP; | ||
303 | static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES]; | ||
304 | static DEFINE_SPINLOCK(mcdx_lock); | ||
305 | static struct request_queue *mcdx_queue; | ||
306 | |||
307 | /* You can only set the first two pairs, from old MODULE_PARM code. */ | ||
308 | static int mcdx_set(const char *val, struct kernel_param *kp) | ||
309 | { | ||
310 | get_options((char *)val, 4, (int *)mcdx_drive_map); | ||
311 | return 0; | ||
312 | } | ||
313 | module_param_call(mcdx, mcdx_set, NULL, NULL, 0); | ||
314 | |||
315 | static struct cdrom_device_ops mcdx_dops = { | ||
316 | .open = mcdx_open, | ||
317 | .release = mcdx_close, | ||
318 | .media_changed = mcdx_media_changed, | ||
319 | .tray_move = mcdx_tray_move, | ||
320 | .lock_door = mcdx_lockdoor, | ||
321 | .audio_ioctl = mcdx_audio_ioctl, | ||
322 | .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | | ||
323 | CDC_PLAY_AUDIO | CDC_DRIVE_STATUS, | ||
324 | }; | ||
325 | |||
326 | /* KERNEL INTERFACE FUNCTIONS **************************************/ | ||
327 | |||
328 | |||
329 | static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, | ||
330 | unsigned int cmd, void *arg) | ||
331 | { | ||
332 | struct s_drive_stuff *stuffp = cdi->handle; | ||
333 | |||
334 | if (!stuffp->present) | ||
335 | return -ENXIO; | ||
336 | |||
337 | if (stuffp->xxx) { | ||
338 | if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { | ||
339 | stuffp->lastsector = -1; | ||
340 | } else { | ||
341 | stuffp->lastsector = (CD_FRAMESIZE / 512) | ||
342 | * msf2log(&stuffp->di.msf_leadout) - 1; | ||
343 | } | ||
344 | |||
345 | if (stuffp->toc) { | ||
346 | kfree(stuffp->toc); | ||
347 | stuffp->toc = NULL; | ||
348 | if (-1 == mcdx_readtoc(stuffp)) | ||
349 | return -1; | ||
350 | } | ||
351 | |||
352 | stuffp->xxx = 0; | ||
353 | } | ||
354 | |||
355 | switch (cmd) { | ||
356 | case CDROMSTART:{ | ||
357 | xtrace(IOCTL, "ioctl() START\n"); | ||
358 | /* Spin up the drive. Don't think we can do this. | ||
359 | * For now, ignore it. | ||
360 | */ | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | case CDROMSTOP:{ | ||
365 | xtrace(IOCTL, "ioctl() STOP\n"); | ||
366 | stuffp->audiostatus = CDROM_AUDIO_INVALID; | ||
367 | if (-1 == mcdx_stop(stuffp, 1)) | ||
368 | return -EIO; | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | case CDROMPLAYTRKIND:{ | ||
373 | struct cdrom_ti *ti = (struct cdrom_ti *) arg; | ||
374 | |||
375 | xtrace(IOCTL, "ioctl() PLAYTRKIND\n"); | ||
376 | if ((ti->cdti_trk0 < stuffp->di.n_first) | ||
377 | || (ti->cdti_trk0 > stuffp->di.n_last) | ||
378 | || (ti->cdti_trk1 < stuffp->di.n_first)) | ||
379 | return -EINVAL; | ||
380 | if (ti->cdti_trk1 > stuffp->di.n_last) | ||
381 | ti->cdti_trk1 = stuffp->di.n_last; | ||
382 | xtrace(PLAYTRK, "ioctl() track %d to %d\n", | ||
383 | ti->cdti_trk0, ti->cdti_trk1); | ||
384 | return mcdx_playtrk(stuffp, ti); | ||
385 | } | ||
386 | |||
387 | case CDROMPLAYMSF:{ | ||
388 | struct cdrom_msf *msf = (struct cdrom_msf *) arg; | ||
389 | |||
390 | xtrace(IOCTL, "ioctl() PLAYMSF\n"); | ||
391 | |||
392 | if ((stuffp->audiostatus == CDROM_AUDIO_PLAY) | ||
393 | && (-1 == mcdx_hold(stuffp, 1))) | ||
394 | return -EIO; | ||
395 | |||
396 | msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0); | ||
397 | msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0); | ||
398 | msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0); | ||
399 | |||
400 | msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1); | ||
401 | msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1); | ||
402 | msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1); | ||
403 | |||
404 | stuffp->stop.dt.minute = msf->cdmsf_min1; | ||
405 | stuffp->stop.dt.second = msf->cdmsf_sec1; | ||
406 | stuffp->stop.dt.frame = msf->cdmsf_frame1; | ||
407 | |||
408 | return mcdx_playmsf(stuffp, msf); | ||
409 | } | ||
410 | |||
411 | case CDROMRESUME:{ | ||
412 | xtrace(IOCTL, "ioctl() RESUME\n"); | ||
413 | return mcdx_playtrk(stuffp, NULL); | ||
414 | } | ||
415 | |||
416 | case CDROMREADTOCENTRY:{ | ||
417 | struct cdrom_tocentry *entry = | ||
418 | (struct cdrom_tocentry *) arg; | ||
419 | struct s_subqcode *tp = NULL; | ||
420 | xtrace(IOCTL, "ioctl() READTOCENTRY\n"); | ||
421 | |||
422 | if (-1 == mcdx_readtoc(stuffp)) | ||
423 | return -1; | ||
424 | if (entry->cdte_track == CDROM_LEADOUT) | ||
425 | tp = &stuffp->toc[stuffp->di.n_last - | ||
426 | stuffp->di.n_first + 1]; | ||
427 | else if (entry->cdte_track > stuffp->di.n_last | ||
428 | || entry->cdte_track < stuffp->di.n_first) | ||
429 | return -EINVAL; | ||
430 | else | ||
431 | tp = &stuffp->toc[entry->cdte_track - | ||
432 | stuffp->di.n_first]; | ||
433 | |||
434 | if (NULL == tp) | ||
435 | return -EIO; | ||
436 | entry->cdte_adr = tp->control; | ||
437 | entry->cdte_ctrl = tp->control >> 4; | ||
438 | /* Always return stuff in MSF, and let the Uniform cdrom driver | ||
439 | worry about what the user actually wants */ | ||
440 | entry->cdte_addr.msf.minute = | ||
441 | bcd2uint(tp->dt.minute); | ||
442 | entry->cdte_addr.msf.second = | ||
443 | bcd2uint(tp->dt.second); | ||
444 | entry->cdte_addr.msf.frame = | ||
445 | bcd2uint(tp->dt.frame); | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | case CDROMSUBCHNL:{ | ||
450 | struct cdrom_subchnl *sub = | ||
451 | (struct cdrom_subchnl *) arg; | ||
452 | struct s_subqcode q; | ||
453 | |||
454 | xtrace(IOCTL, "ioctl() SUBCHNL\n"); | ||
455 | |||
456 | if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) | ||
457 | return -EIO; | ||
458 | |||
459 | xtrace(SUBCHNL, "audiostatus: %x\n", | ||
460 | stuffp->audiostatus); | ||
461 | sub->cdsc_audiostatus = stuffp->audiostatus; | ||
462 | sub->cdsc_adr = q.control; | ||
463 | sub->cdsc_ctrl = q.control >> 4; | ||
464 | sub->cdsc_trk = bcd2uint(q.tno); | ||
465 | sub->cdsc_ind = bcd2uint(q.index); | ||
466 | |||
467 | xtrace(SUBCHNL, "trk %d, ind %d\n", | ||
468 | sub->cdsc_trk, sub->cdsc_ind); | ||
469 | /* Always return stuff in MSF, and let the Uniform cdrom driver | ||
470 | worry about what the user actually wants */ | ||
471 | sub->cdsc_absaddr.msf.minute = | ||
472 | bcd2uint(q.dt.minute); | ||
473 | sub->cdsc_absaddr.msf.second = | ||
474 | bcd2uint(q.dt.second); | ||
475 | sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame); | ||
476 | sub->cdsc_reladdr.msf.minute = | ||
477 | bcd2uint(q.tt.minute); | ||
478 | sub->cdsc_reladdr.msf.second = | ||
479 | bcd2uint(q.tt.second); | ||
480 | sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame); | ||
481 | xtrace(SUBCHNL, | ||
482 | "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n", | ||
483 | sub->cdsc_absaddr.msf.minute, | ||
484 | sub->cdsc_absaddr.msf.second, | ||
485 | sub->cdsc_absaddr.msf.frame, | ||
486 | sub->cdsc_reladdr.msf.minute, | ||
487 | sub->cdsc_reladdr.msf.second, | ||
488 | sub->cdsc_reladdr.msf.frame); | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | case CDROMREADTOCHDR:{ | ||
494 | struct cdrom_tochdr *toc = | ||
495 | (struct cdrom_tochdr *) arg; | ||
496 | |||
497 | xtrace(IOCTL, "ioctl() READTOCHDR\n"); | ||
498 | toc->cdth_trk0 = stuffp->di.n_first; | ||
499 | toc->cdth_trk1 = stuffp->di.n_last; | ||
500 | xtrace(TOCHDR, | ||
501 | "ioctl() track0 = %d, track1 = %d\n", | ||
502 | stuffp->di.n_first, stuffp->di.n_last); | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | case CDROMPAUSE:{ | ||
507 | xtrace(IOCTL, "ioctl() PAUSE\n"); | ||
508 | if (stuffp->audiostatus != CDROM_AUDIO_PLAY) | ||
509 | return -EINVAL; | ||
510 | if (-1 == mcdx_stop(stuffp, 1)) | ||
511 | return -EIO; | ||
512 | stuffp->audiostatus = CDROM_AUDIO_PAUSED; | ||
513 | if (-1 == | ||
514 | mcdx_requestsubqcode(stuffp, &stuffp->start, | ||
515 | 1)) | ||
516 | return -EIO; | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | case CDROMMULTISESSION:{ | ||
521 | struct cdrom_multisession *ms = | ||
522 | (struct cdrom_multisession *) arg; | ||
523 | xtrace(IOCTL, "ioctl() MULTISESSION\n"); | ||
524 | /* Always return stuff in LBA, and let the Uniform cdrom driver | ||
525 | worry about what the user actually wants */ | ||
526 | ms->addr.lba = msf2log(&stuffp->multi.msf_last); | ||
527 | ms->xa_flag = !!stuffp->multi.multi; | ||
528 | xtrace(MS, | ||
529 | "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", | ||
530 | ms->xa_flag, ms->addr.lba, | ||
531 | stuffp->multi.msf_last.minute, | ||
532 | stuffp->multi.msf_last.second, | ||
533 | stuffp->multi.msf_last.frame); | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | case CDROMEJECT:{ | ||
539 | xtrace(IOCTL, "ioctl() EJECT\n"); | ||
540 | if (stuffp->users > 1) | ||
541 | return -EBUSY; | ||
542 | return (mcdx_tray_move(cdi, 1)); | ||
543 | } | ||
544 | |||
545 | case CDROMCLOSETRAY:{ | ||
546 | xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n"); | ||
547 | return (mcdx_tray_move(cdi, 0)); | ||
548 | } | ||
549 | |||
550 | case CDROMVOLCTRL:{ | ||
551 | struct cdrom_volctrl *volctrl = | ||
552 | (struct cdrom_volctrl *) arg; | ||
553 | xtrace(IOCTL, "ioctl() VOLCTRL\n"); | ||
554 | |||
555 | #if 0 /* not tested! */ | ||
556 | /* adjust for the weirdness of workman (md) */ | ||
557 | /* can't test it (hs) */ | ||
558 | volctrl.channel2 = volctrl.channel1; | ||
559 | volctrl.channel1 = volctrl.channel3 = 0x00; | ||
560 | #endif | ||
561 | return mcdx_setattentuator(stuffp, volctrl, 2); | ||
562 | } | ||
563 | |||
564 | default: | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | static void do_mcdx_request(request_queue_t * q) | ||
570 | { | ||
571 | struct s_drive_stuff *stuffp; | ||
572 | struct request *req; | ||
573 | |||
574 | again: | ||
575 | |||
576 | req = elv_next_request(q); | ||
577 | if (!req) | ||
578 | return; | ||
579 | |||
580 | stuffp = req->rq_disk->private_data; | ||
581 | |||
582 | if (!stuffp->present) { | ||
583 | xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name); | ||
584 | xtrace(REQUEST, "end_request(0): bad device\n"); | ||
585 | end_request(req, 0); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | if (stuffp->audio) { | ||
590 | xwarn("do_request() attempt to read from audio cd\n"); | ||
591 | xtrace(REQUEST, "end_request(0): read from audio\n"); | ||
592 | end_request(req, 0); | ||
593 | return; | ||
594 | } | ||
595 | |||
596 | xtrace(REQUEST, "do_request() (%lu + %lu)\n", | ||
597 | req->sector, req->nr_sectors); | ||
598 | |||
599 | if (req->cmd != READ) { | ||
600 | xwarn("do_request(): non-read command to cd!!\n"); | ||
601 | xtrace(REQUEST, "end_request(0): write\n"); | ||
602 | end_request(req, 0); | ||
603 | return; | ||
604 | } | ||
605 | else { | ||
606 | stuffp->status = 0; | ||
607 | while (req->nr_sectors) { | ||
608 | int i; | ||
609 | |||
610 | i = mcdx_transfer(stuffp, | ||
611 | req->buffer, | ||
612 | req->sector, | ||
613 | req->nr_sectors); | ||
614 | |||
615 | if (i == -1) { | ||
616 | end_request(req, 0); | ||
617 | goto again; | ||
618 | } | ||
619 | req->sector += i; | ||
620 | req->nr_sectors -= i; | ||
621 | req->buffer += (i * 512); | ||
622 | } | ||
623 | end_request(req, 1); | ||
624 | goto again; | ||
625 | |||
626 | xtrace(REQUEST, "end_request(1)\n"); | ||
627 | end_request(req, 1); | ||
628 | } | ||
629 | |||
630 | goto again; | ||
631 | } | ||
632 | |||
633 | static int mcdx_open(struct cdrom_device_info *cdi, int purpose) | ||
634 | { | ||
635 | struct s_drive_stuff *stuffp; | ||
636 | xtrace(OPENCLOSE, "open()\n"); | ||
637 | stuffp = cdi->handle; | ||
638 | if (!stuffp->present) | ||
639 | return -ENXIO; | ||
640 | |||
641 | /* Make the modules looking used ... (thanx bjorn). | ||
642 | * But we shouldn't forget to decrement the module counter | ||
643 | * on error return */ | ||
644 | |||
645 | /* this is only done to test if the drive talks with us */ | ||
646 | if (-1 == mcdx_getstatus(stuffp, 1)) | ||
647 | return -EIO; | ||
648 | |||
649 | if (stuffp->xxx) { | ||
650 | |||
651 | xtrace(OPENCLOSE, "open() media changed\n"); | ||
652 | stuffp->audiostatus = CDROM_AUDIO_INVALID; | ||
653 | stuffp->readcmd = 0; | ||
654 | xtrace(OPENCLOSE, "open() Request multisession info\n"); | ||
655 | if (-1 == | ||
656 | mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6)) | ||
657 | xinfo("No multidiskinfo\n"); | ||
658 | } else { | ||
659 | /* multisession ? */ | ||
660 | if (!stuffp->multi.multi) | ||
661 | stuffp->multi.msf_last.second = 2; | ||
662 | |||
663 | xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n", | ||
664 | stuffp->multi.multi, | ||
665 | stuffp->multi.msf_last.minute, | ||
666 | stuffp->multi.msf_last.second, | ||
667 | stuffp->multi.msf_last.frame); | ||
668 | |||
669 | {; | ||
670 | } /* got multisession information */ | ||
671 | /* request the disks table of contents (aka diskinfo) */ | ||
672 | if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { | ||
673 | |||
674 | stuffp->lastsector = -1; | ||
675 | |||
676 | } else { | ||
677 | |||
678 | stuffp->lastsector = (CD_FRAMESIZE / 512) | ||
679 | * msf2log(&stuffp->di.msf_leadout) - 1; | ||
680 | |||
681 | xtrace(OPENCLOSE, | ||
682 | "open() start %d (%02x:%02x.%02x) %d\n", | ||
683 | stuffp->di.n_first, | ||
684 | stuffp->di.msf_first.minute, | ||
685 | stuffp->di.msf_first.second, | ||
686 | stuffp->di.msf_first.frame, | ||
687 | msf2log(&stuffp->di.msf_first)); | ||
688 | xtrace(OPENCLOSE, | ||
689 | "open() last %d (%02x:%02x.%02x) %d\n", | ||
690 | stuffp->di.n_last, | ||
691 | stuffp->di.msf_leadout.minute, | ||
692 | stuffp->di.msf_leadout.second, | ||
693 | stuffp->di.msf_leadout.frame, | ||
694 | msf2log(&stuffp->di.msf_leadout)); | ||
695 | } | ||
696 | |||
697 | if (stuffp->toc) { | ||
698 | xtrace(MALLOC, "open() free old toc @ %p\n", | ||
699 | stuffp->toc); | ||
700 | kfree(stuffp->toc); | ||
701 | |||
702 | stuffp->toc = NULL; | ||
703 | } | ||
704 | |||
705 | xtrace(OPENCLOSE, "open() init irq generation\n"); | ||
706 | if (-1 == mcdx_config(stuffp, 1)) | ||
707 | return -EIO; | ||
708 | #ifdef FALLBACK | ||
709 | /* Set the read speed */ | ||
710 | xwarn("AAA %x AAA\n", stuffp->readcmd); | ||
711 | if (stuffp->readerrs) | ||
712 | stuffp->readcmd = READ1X; | ||
713 | else | ||
714 | stuffp->readcmd = | ||
715 | stuffp->present | SINGLE ? READ1X : READ2X; | ||
716 | xwarn("XXX %x XXX\n", stuffp->readcmd); | ||
717 | #else | ||
718 | stuffp->readcmd = | ||
719 | stuffp->present | SINGLE ? READ1X : READ2X; | ||
720 | #endif | ||
721 | |||
722 | /* try to get the first sector, iff any ... */ | ||
723 | if (stuffp->lastsector >= 0) { | ||
724 | char buf[512]; | ||
725 | int ans; | ||
726 | int tries; | ||
727 | |||
728 | stuffp->xa = 0; | ||
729 | stuffp->audio = 0; | ||
730 | |||
731 | for (tries = 6; tries; tries--) { | ||
732 | |||
733 | stuffp->introk = 1; | ||
734 | |||
735 | xtrace(OPENCLOSE, "open() try as %s\n", | ||
736 | stuffp->xa ? "XA" : "normal"); | ||
737 | /* set data mode */ | ||
738 | if (-1 == (ans = mcdx_setdatamode(stuffp, | ||
739 | stuffp-> | ||
740 | xa ? | ||
741 | MODE2 : | ||
742 | MODE1, | ||
743 | 1))) { | ||
744 | /* return -EIO; */ | ||
745 | stuffp->xa = 0; | ||
746 | break; | ||
747 | } | ||
748 | |||
749 | if ((stuffp->audio = e_audio(ans))) | ||
750 | break; | ||
751 | |||
752 | while (0 == | ||
753 | (ans = | ||
754 | mcdx_transfer(stuffp, buf, 0, 1))); | ||
755 | |||
756 | if (ans == 1) | ||
757 | break; | ||
758 | stuffp->xa = !stuffp->xa; | ||
759 | } | ||
760 | } | ||
761 | /* xa disks will be read in raw mode, others not */ | ||
762 | if (-1 == mcdx_setdrivemode(stuffp, | ||
763 | stuffp->xa ? RAW : COOKED, | ||
764 | 1)) | ||
765 | return -EIO; | ||
766 | if (stuffp->audio) { | ||
767 | xinfo("open() audio disk found\n"); | ||
768 | } else if (stuffp->lastsector >= 0) { | ||
769 | xinfo("open() %s%s disk found\n", | ||
770 | stuffp->xa ? "XA / " : "", | ||
771 | stuffp->multi. | ||
772 | multi ? "Multi Session" : "Single Session"); | ||
773 | } | ||
774 | } | ||
775 | stuffp->xxx = 0; | ||
776 | stuffp->users++; | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | static void mcdx_close(struct cdrom_device_info *cdi) | ||
781 | { | ||
782 | struct s_drive_stuff *stuffp; | ||
783 | |||
784 | xtrace(OPENCLOSE, "close()\n"); | ||
785 | |||
786 | stuffp = cdi->handle; | ||
787 | |||
788 | --stuffp->users; | ||
789 | } | ||
790 | |||
791 | static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
792 | /* Return: 1 if media changed since last call to this function | ||
793 | 0 otherwise */ | ||
794 | { | ||
795 | struct s_drive_stuff *stuffp; | ||
796 | |||
797 | xinfo("mcdx_media_changed called for device %s\n", cdi->name); | ||
798 | |||
799 | stuffp = cdi->handle; | ||
800 | mcdx_getstatus(stuffp, 1); | ||
801 | |||
802 | if (stuffp->yyy == 0) | ||
803 | return 0; | ||
804 | |||
805 | stuffp->yyy = 0; | ||
806 | return 1; | ||
807 | } | ||
808 | |||
809 | #ifndef MODULE | ||
810 | static int __init mcdx_setup(char *str) | ||
811 | { | ||
812 | int pi[4]; | ||
813 | (void) get_options(str, ARRAY_SIZE(pi), pi); | ||
814 | |||
815 | if (pi[0] > 0) | ||
816 | mcdx_drive_map[0][0] = pi[1]; | ||
817 | if (pi[0] > 1) | ||
818 | mcdx_drive_map[0][1] = pi[2]; | ||
819 | return 1; | ||
820 | } | ||
821 | |||
822 | __setup("mcdx=", mcdx_setup); | ||
823 | |||
824 | #endif | ||
825 | |||
826 | /* DIRTY PART ******************************************************/ | ||
827 | |||
828 | static void mcdx_delay(struct s_drive_stuff *stuff, long jifs) | ||
829 | /* This routine is used for sleeping. | ||
830 | * A jifs value <0 means NO sleeping, | ||
831 | * =0 means minimal sleeping (let the kernel | ||
832 | * run for other processes) | ||
833 | * >0 means at least sleep for that amount. | ||
834 | * May be we could use a simple count loop w/ jumps to itself, but | ||
835 | * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */ | ||
836 | { | ||
837 | if (jifs < 0) | ||
838 | return; | ||
839 | |||
840 | xtrace(SLEEP, "*** delay: sleepq\n"); | ||
841 | interruptible_sleep_on_timeout(&stuff->sleepq, jifs); | ||
842 | xtrace(SLEEP, "delay awoken\n"); | ||
843 | if (signal_pending(current)) { | ||
844 | xtrace(SLEEP, "got signal\n"); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | static irqreturn_t mcdx_intr(int irq, void *dev_id) | ||
849 | { | ||
850 | struct s_drive_stuff *stuffp = dev_id; | ||
851 | unsigned char b; | ||
852 | |||
853 | #ifdef AK2 | ||
854 | if (!stuffp->busy && stuffp->pending) | ||
855 | stuffp->int_err = 1; | ||
856 | |||
857 | #endif /* AK2 */ | ||
858 | /* get the interrupt status */ | ||
859 | b = inb(stuffp->rreg_status); | ||
860 | stuffp->introk = ~b & MCDX_RBIT_DTEN; | ||
861 | |||
862 | /* NOTE: We only should get interrupts if the data we | ||
863 | * requested are ready to transfer. | ||
864 | * But the drive seems to generate ``asynchronous'' interrupts | ||
865 | * on several error conditions too. (Despite the err int enable | ||
866 | * setting during initialisation) */ | ||
867 | |||
868 | /* if not ok, read the next byte as the drives status */ | ||
869 | if (!stuffp->introk) { | ||
870 | xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b); | ||
871 | if (~b & MCDX_RBIT_STEN) { | ||
872 | xinfo("intr() irq %d status 0x%02x\n", | ||
873 | irq, inb(stuffp->rreg_data)); | ||
874 | } else { | ||
875 | xinfo("intr() irq %d ambiguous hw status\n", irq); | ||
876 | } | ||
877 | } else { | ||
878 | xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b); | ||
879 | } | ||
880 | |||
881 | stuffp->busy = 0; | ||
882 | wake_up_interruptible(&stuffp->busyq); | ||
883 | return IRQ_HANDLED; | ||
884 | } | ||
885 | |||
886 | |||
887 | static int mcdx_talk(struct s_drive_stuff *stuffp, | ||
888 | const unsigned char *cmd, size_t cmdlen, | ||
889 | void *buffer, size_t size, unsigned int timeout, int tries) | ||
890 | /* Send a command to the drive, wait for the result. | ||
891 | * returns -1 on timeout, drive status otherwise | ||
892 | * If buffer is not zero, the result (length size) is stored there. | ||
893 | * If buffer is zero the size should be the number of bytes to read | ||
894 | * from the drive. These bytes are discarded. | ||
895 | */ | ||
896 | { | ||
897 | int st; | ||
898 | char c; | ||
899 | int discard; | ||
900 | |||
901 | /* Somebody wants the data read? */ | ||
902 | if ((discard = (buffer == NULL))) | ||
903 | buffer = &c; | ||
904 | |||
905 | while (stuffp->lock) { | ||
906 | xtrace(SLEEP, "*** talk: lockq\n"); | ||
907 | interruptible_sleep_on(&stuffp->lockq); | ||
908 | xtrace(SLEEP, "talk: awoken\n"); | ||
909 | } | ||
910 | |||
911 | stuffp->lock = 1; | ||
912 | |||
913 | /* An operation other then reading data destroys the | ||
914 | * data already requested and remembered in stuffp->request, ... */ | ||
915 | stuffp->valid = 0; | ||
916 | |||
917 | #if MCDX_DEBUG & TALK | ||
918 | { | ||
919 | unsigned char i; | ||
920 | xtrace(TALK, | ||
921 | "talk() %d / %d tries, res.size %d, command 0x%02x", | ||
922 | tries, timeout, size, (unsigned char) cmd[0]); | ||
923 | for (i = 1; i < cmdlen; i++) | ||
924 | xtrace(TALK, " 0x%02x", cmd[i]); | ||
925 | xtrace(TALK, "\n"); | ||
926 | } | ||
927 | #endif | ||
928 | |||
929 | /* give up if all tries are done (bad) or if the status | ||
930 | * st != -1 (good) */ | ||
931 | for (st = -1; st == -1 && tries; tries--) { | ||
932 | |||
933 | char *bp = (char *) buffer; | ||
934 | size_t sz = size; | ||
935 | |||
936 | outsb(stuffp->wreg_data, cmd, cmdlen); | ||
937 | xtrace(TALK, "talk() command sent\n"); | ||
938 | |||
939 | /* get the status byte */ | ||
940 | if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { | ||
941 | xinfo("talk() %02x timed out (status), %d tr%s left\n", | ||
942 | cmd[0], tries - 1, tries == 2 ? "y" : "ies"); | ||
943 | continue; | ||
944 | } | ||
945 | st = *bp; | ||
946 | sz--; | ||
947 | if (!discard) | ||
948 | bp++; | ||
949 | |||
950 | xtrace(TALK, "talk() got status 0x%02x\n", st); | ||
951 | |||
952 | /* command error? */ | ||
953 | if (e_cmderr(st)) { | ||
954 | xwarn("command error cmd = %02x %s \n", | ||
955 | cmd[0], cmdlen > 1 ? "..." : ""); | ||
956 | st = -1; | ||
957 | continue; | ||
958 | } | ||
959 | |||
960 | /* audio status? */ | ||
961 | if (stuffp->audiostatus == CDROM_AUDIO_INVALID) | ||
962 | stuffp->audiostatus = | ||
963 | e_audiobusy(st) ? CDROM_AUDIO_PLAY : | ||
964 | CDROM_AUDIO_NO_STATUS; | ||
965 | else if (stuffp->audiostatus == CDROM_AUDIO_PLAY | ||
966 | && e_audiobusy(st) == 0) | ||
967 | stuffp->audiostatus = CDROM_AUDIO_COMPLETED; | ||
968 | |||
969 | /* media change? */ | ||
970 | if (e_changed(st)) { | ||
971 | xinfo("talk() media changed\n"); | ||
972 | stuffp->xxx = stuffp->yyy = 1; | ||
973 | } | ||
974 | |||
975 | /* now actually get the data */ | ||
976 | while (sz--) { | ||
977 | if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { | ||
978 | xinfo("talk() %02x timed out (data), %d tr%s left\n", | ||
979 | cmd[0], tries - 1, | ||
980 | tries == 2 ? "y" : "ies"); | ||
981 | st = -1; | ||
982 | break; | ||
983 | } | ||
984 | if (!discard) | ||
985 | bp++; | ||
986 | xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1)); | ||
987 | } | ||
988 | } | ||
989 | |||
990 | #if !MCDX_QUIET | ||
991 | if (!tries && st == -1) | ||
992 | xinfo("talk() giving up\n"); | ||
993 | #endif | ||
994 | |||
995 | stuffp->lock = 0; | ||
996 | wake_up_interruptible(&stuffp->lockq); | ||
997 | |||
998 | xtrace(TALK, "talk() done with 0x%02x\n", st); | ||
999 | return st; | ||
1000 | } | ||
1001 | |||
1002 | /* MODULE STUFF ***********************************************************/ | ||
1003 | |||
1004 | static int __init __mcdx_init(void) | ||
1005 | { | ||
1006 | int i; | ||
1007 | int drives = 0; | ||
1008 | |||
1009 | mcdx_init(); | ||
1010 | for (i = 0; i < MCDX_NDRIVES; i++) { | ||
1011 | if (mcdx_stuffp[i]) { | ||
1012 | xtrace(INIT, "init_module() drive %d stuff @ %p\n", | ||
1013 | i, mcdx_stuffp[i]); | ||
1014 | drives++; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | if (!drives) | ||
1019 | return -EIO; | ||
1020 | |||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | static void __exit mcdx_exit(void) | ||
1025 | { | ||
1026 | int i; | ||
1027 | |||
1028 | xinfo("cleanup_module called\n"); | ||
1029 | |||
1030 | for (i = 0; i < MCDX_NDRIVES; i++) { | ||
1031 | struct s_drive_stuff *stuffp = mcdx_stuffp[i]; | ||
1032 | if (!stuffp) | ||
1033 | continue; | ||
1034 | del_gendisk(stuffp->disk); | ||
1035 | if (unregister_cdrom(&stuffp->info)) { | ||
1036 | printk(KERN_WARNING "Can't unregister cdrom mcdx\n"); | ||
1037 | continue; | ||
1038 | } | ||
1039 | put_disk(stuffp->disk); | ||
1040 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1041 | free_irq(stuffp->irq, NULL); | ||
1042 | if (stuffp->toc) { | ||
1043 | xtrace(MALLOC, "cleanup_module() free toc @ %p\n", | ||
1044 | stuffp->toc); | ||
1045 | kfree(stuffp->toc); | ||
1046 | } | ||
1047 | xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", | ||
1048 | stuffp); | ||
1049 | mcdx_stuffp[i] = NULL; | ||
1050 | kfree(stuffp); | ||
1051 | } | ||
1052 | |||
1053 | if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) { | ||
1054 | xwarn("cleanup() unregister_blkdev() failed\n"); | ||
1055 | } | ||
1056 | #if !MCDX_QUIET | ||
1057 | else | ||
1058 | xinfo("cleanup() succeeded\n"); | ||
1059 | #endif | ||
1060 | blk_cleanup_queue(mcdx_queue); | ||
1061 | } | ||
1062 | |||
1063 | #ifdef MODULE | ||
1064 | module_init(__mcdx_init); | ||
1065 | #endif | ||
1066 | module_exit(mcdx_exit); | ||
1067 | |||
1068 | |||
1069 | /* Support functions ************************************************/ | ||
1070 | |||
1071 | static int __init mcdx_init_drive(int drive) | ||
1072 | { | ||
1073 | struct s_version version; | ||
1074 | struct gendisk *disk; | ||
1075 | struct s_drive_stuff *stuffp; | ||
1076 | int size = sizeof(*stuffp); | ||
1077 | char msg[80]; | ||
1078 | |||
1079 | xtrace(INIT, "init() try drive %d\n", drive); | ||
1080 | |||
1081 | xtrace(INIT, "kmalloc space for stuffpt's\n"); | ||
1082 | xtrace(MALLOC, "init() malloc %d bytes\n", size); | ||
1083 | if (!(stuffp = kzalloc(size, GFP_KERNEL))) { | ||
1084 | xwarn("init() malloc failed\n"); | ||
1085 | return 1; | ||
1086 | } | ||
1087 | |||
1088 | disk = alloc_disk(1); | ||
1089 | if (!disk) { | ||
1090 | xwarn("init() malloc failed\n"); | ||
1091 | kfree(stuffp); | ||
1092 | return 1; | ||
1093 | } | ||
1094 | |||
1095 | xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", | ||
1096 | sizeof(*stuffp), stuffp); | ||
1097 | |||
1098 | /* set default values */ | ||
1099 | stuffp->present = 0; /* this should be 0 already */ | ||
1100 | stuffp->toc = NULL; /* this should be NULL already */ | ||
1101 | |||
1102 | /* setup our irq and i/o addresses */ | ||
1103 | stuffp->irq = irq(mcdx_drive_map[drive]); | ||
1104 | stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); | ||
1105 | stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; | ||
1106 | stuffp->wreg_hcon = stuffp->wreg_reset + 1; | ||
1107 | stuffp->wreg_chn = stuffp->wreg_hcon + 1; | ||
1108 | |||
1109 | init_waitqueue_head(&stuffp->busyq); | ||
1110 | init_waitqueue_head(&stuffp->lockq); | ||
1111 | init_waitqueue_head(&stuffp->sleepq); | ||
1112 | |||
1113 | /* check if i/o addresses are available */ | ||
1114 | if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) { | ||
1115 | xwarn("0x%03x,%d: Init failed. " | ||
1116 | "I/O ports (0x%03x..0x%03x) already in use.\n", | ||
1117 | stuffp->wreg_data, stuffp->irq, | ||
1118 | stuffp->wreg_data, | ||
1119 | stuffp->wreg_data + MCDX_IO_SIZE - 1); | ||
1120 | xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); | ||
1121 | kfree(stuffp); | ||
1122 | put_disk(disk); | ||
1123 | xtrace(INIT, "init() continue at next drive\n"); | ||
1124 | return 0; /* next drive */ | ||
1125 | } | ||
1126 | |||
1127 | xtrace(INIT, "init() i/o port is available at 0x%03x\n" | ||
1128 | stuffp->wreg_data); | ||
1129 | xtrace(INIT, "init() hardware reset\n"); | ||
1130 | mcdx_reset(stuffp, HARD, 1); | ||
1131 | |||
1132 | xtrace(INIT, "init() get version\n"); | ||
1133 | if (-1 == mcdx_requestversion(stuffp, &version, 4)) { | ||
1134 | /* failed, next drive */ | ||
1135 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1136 | xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n", | ||
1137 | MCDX, stuffp->wreg_data, stuffp->irq); | ||
1138 | xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); | ||
1139 | kfree(stuffp); | ||
1140 | put_disk(disk); | ||
1141 | xtrace(INIT, "init() continue at next drive\n"); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | switch (version.code) { | ||
1146 | case 'D': | ||
1147 | stuffp->readcmd = READ2X; | ||
1148 | stuffp->present = DOUBLE | DOOR | MULTI; | ||
1149 | break; | ||
1150 | case 'F': | ||
1151 | stuffp->readcmd = READ1X; | ||
1152 | stuffp->present = SINGLE | DOOR | MULTI; | ||
1153 | break; | ||
1154 | case 'M': | ||
1155 | stuffp->readcmd = READ1X; | ||
1156 | stuffp->present = SINGLE; | ||
1157 | break; | ||
1158 | default: | ||
1159 | stuffp->present = 0; | ||
1160 | break; | ||
1161 | } | ||
1162 | |||
1163 | stuffp->playcmd = READ1X; | ||
1164 | |||
1165 | if (!stuffp->present) { | ||
1166 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1167 | xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n", | ||
1168 | MCDX, stuffp->wreg_data, stuffp->irq); | ||
1169 | kfree(stuffp); | ||
1170 | put_disk(disk); | ||
1171 | return 0; /* next drive */ | ||
1172 | } | ||
1173 | |||
1174 | xtrace(INIT, "init() register blkdev\n"); | ||
1175 | if (register_blkdev(MAJOR_NR, "mcdx")) { | ||
1176 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1177 | kfree(stuffp); | ||
1178 | put_disk(disk); | ||
1179 | return 1; | ||
1180 | } | ||
1181 | |||
1182 | mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock); | ||
1183 | if (!mcdx_queue) { | ||
1184 | unregister_blkdev(MAJOR_NR, "mcdx"); | ||
1185 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1186 | kfree(stuffp); | ||
1187 | put_disk(disk); | ||
1188 | return 1; | ||
1189 | } | ||
1190 | |||
1191 | xtrace(INIT, "init() subscribe irq and i/o\n"); | ||
1192 | if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) { | ||
1193 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1194 | xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n", | ||
1195 | MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq); | ||
1196 | stuffp->irq = 0; | ||
1197 | blk_cleanup_queue(mcdx_queue); | ||
1198 | kfree(stuffp); | ||
1199 | put_disk(disk); | ||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | xtrace(INIT, "init() get garbage\n"); | ||
1204 | { | ||
1205 | int i; | ||
1206 | mcdx_delay(stuffp, HZ / 2); | ||
1207 | for (i = 100; i; i--) | ||
1208 | (void) inb(stuffp->rreg_status); | ||
1209 | } | ||
1210 | |||
1211 | |||
1212 | #ifdef WE_KNOW_WHY | ||
1213 | /* irq 11 -> channel register */ | ||
1214 | outb(0x50, stuffp->wreg_chn); | ||
1215 | #endif | ||
1216 | |||
1217 | xtrace(INIT, "init() set non dma but irq mode\n"); | ||
1218 | mcdx_config(stuffp, 1); | ||
1219 | |||
1220 | stuffp->info.ops = &mcdx_dops; | ||
1221 | stuffp->info.speed = 2; | ||
1222 | stuffp->info.capacity = 1; | ||
1223 | stuffp->info.handle = stuffp; | ||
1224 | sprintf(stuffp->info.name, "mcdx%d", drive); | ||
1225 | disk->major = MAJOR_NR; | ||
1226 | disk->first_minor = drive; | ||
1227 | strcpy(disk->disk_name, stuffp->info.name); | ||
1228 | disk->fops = &mcdx_bdops; | ||
1229 | disk->flags = GENHD_FL_CD; | ||
1230 | stuffp->disk = disk; | ||
1231 | |||
1232 | sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d." | ||
1233 | " (Firmware version %c %x)\n", | ||
1234 | stuffp->wreg_data, stuffp->irq, version.code, version.ver); | ||
1235 | mcdx_stuffp[drive] = stuffp; | ||
1236 | xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); | ||
1237 | if (register_cdrom(&stuffp->info) != 0) { | ||
1238 | printk("Cannot register Mitsumi CD-ROM!\n"); | ||
1239 | free_irq(stuffp->irq, NULL); | ||
1240 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1241 | kfree(stuffp); | ||
1242 | put_disk(disk); | ||
1243 | if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) | ||
1244 | xwarn("cleanup() unregister_blkdev() failed\n"); | ||
1245 | blk_cleanup_queue(mcdx_queue); | ||
1246 | return 2; | ||
1247 | } | ||
1248 | disk->private_data = stuffp; | ||
1249 | disk->queue = mcdx_queue; | ||
1250 | add_disk(disk); | ||
1251 | printk(msg); | ||
1252 | return 0; | ||
1253 | } | ||
1254 | |||
1255 | static int __init mcdx_init(void) | ||
1256 | { | ||
1257 | int drive; | ||
1258 | xwarn("Version 2.14(hs) \n"); | ||
1259 | |||
1260 | xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); | ||
1261 | |||
1262 | /* zero the pointer array */ | ||
1263 | for (drive = 0; drive < MCDX_NDRIVES; drive++) | ||
1264 | mcdx_stuffp[drive] = NULL; | ||
1265 | |||
1266 | /* do the initialisation */ | ||
1267 | for (drive = 0; drive < MCDX_NDRIVES; drive++) { | ||
1268 | switch (mcdx_init_drive(drive)) { | ||
1269 | case 2: | ||
1270 | return -EIO; | ||
1271 | case 1: | ||
1272 | break; | ||
1273 | } | ||
1274 | } | ||
1275 | return 0; | ||
1276 | } | ||
1277 | |||
1278 | static int mcdx_transfer(struct s_drive_stuff *stuffp, | ||
1279 | char *p, int sector, int nr_sectors) | ||
1280 | /* This seems to do the actually transfer. But it does more. It | ||
1281 | keeps track of errors occurred and will (if possible) fall back | ||
1282 | to single speed on error. | ||
1283 | Return: -1 on timeout or other error | ||
1284 | else status byte (as in stuff->st) */ | ||
1285 | { | ||
1286 | int ans; | ||
1287 | |||
1288 | ans = mcdx_xfer(stuffp, p, sector, nr_sectors); | ||
1289 | return ans; | ||
1290 | #ifdef FALLBACK | ||
1291 | if (-1 == ans) | ||
1292 | stuffp->readerrs++; | ||
1293 | else | ||
1294 | return ans; | ||
1295 | |||
1296 | if (stuffp->readerrs && stuffp->readcmd == READ1X) { | ||
1297 | xwarn("XXX Already reading 1x -- no chance\n"); | ||
1298 | return -1; | ||
1299 | } | ||
1300 | |||
1301 | xwarn("XXX Fallback to 1x\n"); | ||
1302 | |||
1303 | stuffp->readcmd = READ1X; | ||
1304 | return mcdx_transfer(stuffp, p, sector, nr_sectors); | ||
1305 | #endif | ||
1306 | |||
1307 | } | ||
1308 | |||
1309 | |||
1310 | static int mcdx_xfer(struct s_drive_stuff *stuffp, | ||
1311 | char *p, int sector, int nr_sectors) | ||
1312 | /* This does actually the transfer from the drive. | ||
1313 | Return: -1 on timeout or other error | ||
1314 | else status byte (as in stuff->st) */ | ||
1315 | { | ||
1316 | int border; | ||
1317 | int done = 0; | ||
1318 | long timeout; | ||
1319 | |||
1320 | if (stuffp->audio) { | ||
1321 | xwarn("Attempt to read from audio CD.\n"); | ||
1322 | return -1; | ||
1323 | } | ||
1324 | |||
1325 | if (!stuffp->readcmd) { | ||
1326 | xinfo("Can't transfer from missing disk.\n"); | ||
1327 | return -1; | ||
1328 | } | ||
1329 | |||
1330 | while (stuffp->lock) { | ||
1331 | interruptible_sleep_on(&stuffp->lockq); | ||
1332 | } | ||
1333 | |||
1334 | if (stuffp->valid && (sector >= stuffp->pending) | ||
1335 | && (sector < stuffp->low_border)) { | ||
1336 | |||
1337 | /* All (or at least a part of the sectors requested) seems | ||
1338 | * to be already requested, so we don't need to bother the | ||
1339 | * drive with new requests ... | ||
1340 | * Wait for the drive become idle, but first | ||
1341 | * check for possible occurred errors --- the drive | ||
1342 | * seems to report them asynchronously */ | ||
1343 | |||
1344 | |||
1345 | border = stuffp->high_border < (border = | ||
1346 | sector + nr_sectors) | ||
1347 | ? stuffp->high_border : border; | ||
1348 | |||
1349 | stuffp->lock = current->pid; | ||
1350 | |||
1351 | do { | ||
1352 | |||
1353 | while (stuffp->busy) { | ||
1354 | |||
1355 | timeout = | ||
1356 | interruptible_sleep_on_timeout | ||
1357 | (&stuffp->busyq, 5 * HZ); | ||
1358 | |||
1359 | if (!stuffp->introk) { | ||
1360 | xtrace(XFER, | ||
1361 | "error via interrupt\n"); | ||
1362 | } else if (!timeout) { | ||
1363 | xtrace(XFER, "timeout\n"); | ||
1364 | } else if (signal_pending(current)) { | ||
1365 | xtrace(XFER, "signal\n"); | ||
1366 | } else | ||
1367 | continue; | ||
1368 | |||
1369 | stuffp->lock = 0; | ||
1370 | stuffp->busy = 0; | ||
1371 | stuffp->valid = 0; | ||
1372 | |||
1373 | wake_up_interruptible(&stuffp->lockq); | ||
1374 | xtrace(XFER, "transfer() done (-1)\n"); | ||
1375 | return -1; | ||
1376 | } | ||
1377 | |||
1378 | /* check if we need to set the busy flag (as we | ||
1379 | * expect an interrupt */ | ||
1380 | stuffp->busy = (3 == (stuffp->pending & 3)); | ||
1381 | |||
1382 | /* Test if it's the first sector of a block, | ||
1383 | * there we have to skip some bytes as we read raw data */ | ||
1384 | if (stuffp->xa && (0 == (stuffp->pending & 3))) { | ||
1385 | const int HEAD = | ||
1386 | CD_FRAMESIZE_RAW - CD_XA_TAIL - | ||
1387 | CD_FRAMESIZE; | ||
1388 | insb(stuffp->rreg_data, p, HEAD); | ||
1389 | } | ||
1390 | |||
1391 | /* now actually read the data */ | ||
1392 | insb(stuffp->rreg_data, p, 512); | ||
1393 | |||
1394 | /* test if it's the last sector of a block, | ||
1395 | * if so, we have to handle XA special */ | ||
1396 | if ((3 == (stuffp->pending & 3)) && stuffp->xa) { | ||
1397 | char dummy[CD_XA_TAIL]; | ||
1398 | insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL); | ||
1399 | } | ||
1400 | |||
1401 | if (stuffp->pending == sector) { | ||
1402 | p += 512; | ||
1403 | done++; | ||
1404 | sector++; | ||
1405 | } | ||
1406 | } while (++(stuffp->pending) < border); | ||
1407 | |||
1408 | stuffp->lock = 0; | ||
1409 | wake_up_interruptible(&stuffp->lockq); | ||
1410 | |||
1411 | } else { | ||
1412 | |||
1413 | /* The requested sector(s) is/are out of the | ||
1414 | * already requested range, so we have to bother the drive | ||
1415 | * with a new request. */ | ||
1416 | |||
1417 | static unsigned char cmd[] = { | ||
1418 | 0, | ||
1419 | 0, 0, 0, | ||
1420 | 0, 0, 0 | ||
1421 | }; | ||
1422 | |||
1423 | cmd[0] = stuffp->readcmd; | ||
1424 | |||
1425 | /* The numbers held in ->pending, ..., should be valid */ | ||
1426 | stuffp->valid = 1; | ||
1427 | stuffp->pending = sector & ~3; | ||
1428 | |||
1429 | /* do some sanity checks */ | ||
1430 | if (stuffp->pending > stuffp->lastsector) { | ||
1431 | xwarn | ||
1432 | ("transfer() sector %d from nirvana requested.\n", | ||
1433 | stuffp->pending); | ||
1434 | stuffp->status = MCDX_ST_EOM; | ||
1435 | stuffp->valid = 0; | ||
1436 | xtrace(XFER, "transfer() done (-1)\n"); | ||
1437 | return -1; | ||
1438 | } | ||
1439 | |||
1440 | if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE) | ||
1441 | > stuffp->lastsector + 1) { | ||
1442 | xtrace(XFER, "cut low_border\n"); | ||
1443 | stuffp->low_border = stuffp->lastsector + 1; | ||
1444 | } | ||
1445 | if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE) | ||
1446 | > stuffp->lastsector + 1) { | ||
1447 | xtrace(XFER, "cut high_border\n"); | ||
1448 | stuffp->high_border = stuffp->lastsector + 1; | ||
1449 | } | ||
1450 | |||
1451 | { /* Convert the sector to be requested to MSF format */ | ||
1452 | struct cdrom_msf0 pending; | ||
1453 | log2msf(stuffp->pending / 4, &pending); | ||
1454 | cmd[1] = pending.minute; | ||
1455 | cmd[2] = pending.second; | ||
1456 | cmd[3] = pending.frame; | ||
1457 | } | ||
1458 | |||
1459 | cmd[6] = | ||
1460 | (unsigned | ||
1461 | char) ((stuffp->high_border - stuffp->pending) / 4); | ||
1462 | xtrace(XFER, "[%2d]\n", cmd[6]); | ||
1463 | |||
1464 | stuffp->busy = 1; | ||
1465 | /* Now really issue the request command */ | ||
1466 | outsb(stuffp->wreg_data, cmd, sizeof cmd); | ||
1467 | |||
1468 | } | ||
1469 | #ifdef AK2 | ||
1470 | if (stuffp->int_err) { | ||
1471 | stuffp->valid = 0; | ||
1472 | stuffp->int_err = 0; | ||
1473 | return -1; | ||
1474 | } | ||
1475 | #endif /* AK2 */ | ||
1476 | |||
1477 | stuffp->low_border = (stuffp->low_border += | ||
1478 | done) < | ||
1479 | stuffp->high_border ? stuffp->low_border : stuffp->high_border; | ||
1480 | |||
1481 | return done; | ||
1482 | } | ||
1483 | |||
1484 | |||
1485 | /* Access to elements of the mcdx_drive_map members */ | ||
1486 | |||
1487 | static unsigned port(int *ip) | ||
1488 | { | ||
1489 | return ip[0]; | ||
1490 | } | ||
1491 | static int irq(int *ip) | ||
1492 | { | ||
1493 | return ip[1]; | ||
1494 | } | ||
1495 | |||
1496 | /* Misc number converters */ | ||
1497 | |||
1498 | static unsigned int bcd2uint(unsigned char c) | ||
1499 | { | ||
1500 | return (c >> 4) * 10 + (c & 0x0f); | ||
1501 | } | ||
1502 | |||
1503 | static unsigned int uint2bcd(unsigned int ival) | ||
1504 | { | ||
1505 | return ((ival / 10) << 4) | (ival % 10); | ||
1506 | } | ||
1507 | |||
1508 | static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf) | ||
1509 | { | ||
1510 | l += CD_MSF_OFFSET; | ||
1511 | pmsf->minute = uint2bcd(l / 4500), l %= 4500; | ||
1512 | pmsf->second = uint2bcd(l / 75); | ||
1513 | pmsf->frame = uint2bcd(l % 75); | ||
1514 | } | ||
1515 | |||
1516 | static unsigned int msf2log(const struct cdrom_msf0 *pmsf) | ||
1517 | { | ||
1518 | return bcd2uint(pmsf->frame) | ||
1519 | + bcd2uint(pmsf->second) * 75 | ||
1520 | + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET; | ||
1521 | } | ||
1522 | |||
1523 | int mcdx_readtoc(struct s_drive_stuff *stuffp) | ||
1524 | /* Read the toc entries from the CD, | ||
1525 | * Return: -1 on failure, else 0 */ | ||
1526 | { | ||
1527 | |||
1528 | if (stuffp->toc) { | ||
1529 | xtrace(READTOC, "ioctl() toc already read\n"); | ||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | xtrace(READTOC, "ioctl() readtoc for %d tracks\n", | ||
1534 | stuffp->di.n_last - stuffp->di.n_first + 1); | ||
1535 | |||
1536 | if (-1 == mcdx_hold(stuffp, 1)) | ||
1537 | return -1; | ||
1538 | |||
1539 | xtrace(READTOC, "ioctl() tocmode\n"); | ||
1540 | if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) | ||
1541 | return -EIO; | ||
1542 | |||
1543 | /* all seems to be ok so far ... malloc */ | ||
1544 | { | ||
1545 | int size; | ||
1546 | size = | ||
1547 | sizeof(struct s_subqcode) * (stuffp->di.n_last - | ||
1548 | stuffp->di.n_first + 2); | ||
1549 | |||
1550 | xtrace(MALLOC, "ioctl() malloc %d bytes\n", size); | ||
1551 | stuffp->toc = kmalloc(size, GFP_KERNEL); | ||
1552 | if (!stuffp->toc) { | ||
1553 | xwarn("Cannot malloc %d bytes for toc\n", size); | ||
1554 | mcdx_setdrivemode(stuffp, DATA, 1); | ||
1555 | return -EIO; | ||
1556 | } | ||
1557 | } | ||
1558 | |||
1559 | /* now read actually the index */ | ||
1560 | { | ||
1561 | int trk; | ||
1562 | int retries; | ||
1563 | |||
1564 | for (trk = 0; | ||
1565 | trk < (stuffp->di.n_last - stuffp->di.n_first + 1); | ||
1566 | trk++) | ||
1567 | stuffp->toc[trk].index = 0; | ||
1568 | |||
1569 | for (retries = 300; retries; retries--) { /* why 300? */ | ||
1570 | struct s_subqcode q; | ||
1571 | unsigned int idx; | ||
1572 | |||
1573 | if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) { | ||
1574 | mcdx_setdrivemode(stuffp, DATA, 1); | ||
1575 | return -EIO; | ||
1576 | } | ||
1577 | |||
1578 | idx = bcd2uint(q.index); | ||
1579 | |||
1580 | if ((idx > 0) | ||
1581 | && (idx <= stuffp->di.n_last) | ||
1582 | && (q.tno == 0) | ||
1583 | && (stuffp->toc[idx - stuffp->di.n_first]. | ||
1584 | index == 0)) { | ||
1585 | stuffp->toc[idx - stuffp->di.n_first] = q; | ||
1586 | xtrace(READTOC, | ||
1587 | "ioctl() toc idx %d (trk %d)\n", | ||
1588 | idx, trk); | ||
1589 | trk--; | ||
1590 | } | ||
1591 | if (trk == 0) | ||
1592 | break; | ||
1593 | } | ||
1594 | memset(&stuffp-> | ||
1595 | toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0, | ||
1596 | sizeof(stuffp->toc[0])); | ||
1597 | stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + | ||
1598 | 1].dt = stuffp->di.msf_leadout; | ||
1599 | } | ||
1600 | |||
1601 | /* unset toc mode */ | ||
1602 | xtrace(READTOC, "ioctl() undo toc mode\n"); | ||
1603 | if (-1 == mcdx_setdrivemode(stuffp, DATA, 2)) | ||
1604 | return -EIO; | ||
1605 | |||
1606 | #if MCDX_DEBUG && READTOC | ||
1607 | { | ||
1608 | int trk; | ||
1609 | for (trk = 0; | ||
1610 | trk < (stuffp->di.n_last - stuffp->di.n_first + 2); | ||
1611 | trk++) | ||
1612 | xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x" | ||
1613 | " %02x:%02x.%02x %02x:%02x.%02x\n", | ||
1614 | trk + stuffp->di.n_first, | ||
1615 | stuffp->toc[trk].control, | ||
1616 | stuffp->toc[trk].tno, | ||
1617 | stuffp->toc[trk].index, | ||
1618 | stuffp->toc[trk].tt.minute, | ||
1619 | stuffp->toc[trk].tt.second, | ||
1620 | stuffp->toc[trk].tt.frame, | ||
1621 | stuffp->toc[trk].dt.minute, | ||
1622 | stuffp->toc[trk].dt.second, | ||
1623 | stuffp->toc[trk].dt.frame); | ||
1624 | } | ||
1625 | #endif | ||
1626 | |||
1627 | return 0; | ||
1628 | } | ||
1629 | |||
1630 | static int | ||
1631 | mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf) | ||
1632 | { | ||
1633 | unsigned char cmd[7] = { | ||
1634 | 0, 0, 0, 0, 0, 0, 0 | ||
1635 | }; | ||
1636 | |||
1637 | if (!stuffp->readcmd) { | ||
1638 | xinfo("Can't play from missing disk.\n"); | ||
1639 | return -1; | ||
1640 | } | ||
1641 | |||
1642 | cmd[0] = stuffp->playcmd; | ||
1643 | |||
1644 | cmd[1] = msf->cdmsf_min0; | ||
1645 | cmd[2] = msf->cdmsf_sec0; | ||
1646 | cmd[3] = msf->cdmsf_frame0; | ||
1647 | cmd[4] = msf->cdmsf_min1; | ||
1648 | cmd[5] = msf->cdmsf_sec1; | ||
1649 | cmd[6] = msf->cdmsf_frame1; | ||
1650 | |||
1651 | xtrace(PLAYMSF, "ioctl(): play %x " | ||
1652 | "%02x:%02x:%02x -- %02x:%02x:%02x\n", | ||
1653 | cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]); | ||
1654 | |||
1655 | outsb(stuffp->wreg_data, cmd, sizeof cmd); | ||
1656 | |||
1657 | if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) { | ||
1658 | xwarn("playmsf() timeout\n"); | ||
1659 | return -1; | ||
1660 | } | ||
1661 | |||
1662 | stuffp->audiostatus = CDROM_AUDIO_PLAY; | ||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | static int | ||
1667 | mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti) | ||
1668 | { | ||
1669 | struct s_subqcode *p; | ||
1670 | struct cdrom_msf msf; | ||
1671 | |||
1672 | if (-1 == mcdx_readtoc(stuffp)) | ||
1673 | return -1; | ||
1674 | |||
1675 | if (ti) | ||
1676 | p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first]; | ||
1677 | else | ||
1678 | p = &stuffp->start; | ||
1679 | |||
1680 | msf.cdmsf_min0 = p->dt.minute; | ||
1681 | msf.cdmsf_sec0 = p->dt.second; | ||
1682 | msf.cdmsf_frame0 = p->dt.frame; | ||
1683 | |||
1684 | if (ti) { | ||
1685 | p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1]; | ||
1686 | stuffp->stop = *p; | ||
1687 | } else | ||
1688 | p = &stuffp->stop; | ||
1689 | |||
1690 | msf.cdmsf_min1 = p->dt.minute; | ||
1691 | msf.cdmsf_sec1 = p->dt.second; | ||
1692 | msf.cdmsf_frame1 = p->dt.frame; | ||
1693 | |||
1694 | return mcdx_playmsf(stuffp, &msf); | ||
1695 | } | ||
1696 | |||
1697 | |||
1698 | /* Drive functions ************************************************/ | ||
1699 | |||
1700 | static int mcdx_tray_move(struct cdrom_device_info *cdi, int position) | ||
1701 | { | ||
1702 | struct s_drive_stuff *stuffp = cdi->handle; | ||
1703 | |||
1704 | if (!stuffp->present) | ||
1705 | return -ENXIO; | ||
1706 | if (!(stuffp->present & DOOR)) | ||
1707 | return -ENOSYS; | ||
1708 | |||
1709 | if (position) /* 1: eject */ | ||
1710 | return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3); | ||
1711 | else /* 0: close */ | ||
1712 | return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3); | ||
1713 | return 1; | ||
1714 | } | ||
1715 | |||
1716 | static int mcdx_stop(struct s_drive_stuff *stuffp, int tries) | ||
1717 | { | ||
1718 | return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); | ||
1719 | } | ||
1720 | |||
1721 | static int mcdx_hold(struct s_drive_stuff *stuffp, int tries) | ||
1722 | { | ||
1723 | return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); | ||
1724 | } | ||
1725 | |||
1726 | static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp, | ||
1727 | struct s_subqcode *sub, int tries) | ||
1728 | { | ||
1729 | char buf[11]; | ||
1730 | int ans; | ||
1731 | |||
1732 | if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf), | ||
1733 | 2 * HZ, tries))) | ||
1734 | return -1; | ||
1735 | sub->control = buf[1]; | ||
1736 | sub->tno = buf[2]; | ||
1737 | sub->index = buf[3]; | ||
1738 | sub->tt.minute = buf[4]; | ||
1739 | sub->tt.second = buf[5]; | ||
1740 | sub->tt.frame = buf[6]; | ||
1741 | sub->dt.minute = buf[8]; | ||
1742 | sub->dt.second = buf[9]; | ||
1743 | sub->dt.frame = buf[10]; | ||
1744 | |||
1745 | return ans; | ||
1746 | } | ||
1747 | |||
1748 | static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, | ||
1749 | struct s_multi *multi, int tries) | ||
1750 | { | ||
1751 | char buf[5]; | ||
1752 | int ans; | ||
1753 | |||
1754 | if (stuffp->present & MULTI) { | ||
1755 | ans = | ||
1756 | mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, | ||
1757 | tries); | ||
1758 | multi->multi = buf[1]; | ||
1759 | multi->msf_last.minute = buf[2]; | ||
1760 | multi->msf_last.second = buf[3]; | ||
1761 | multi->msf_last.frame = buf[4]; | ||
1762 | return ans; | ||
1763 | } else { | ||
1764 | multi->multi = 0; | ||
1765 | return 0; | ||
1766 | } | ||
1767 | } | ||
1768 | |||
1769 | static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, | ||
1770 | int tries) | ||
1771 | { | ||
1772 | char buf[9]; | ||
1773 | int ans; | ||
1774 | ans = | ||
1775 | mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries); | ||
1776 | if (ans == -1) { | ||
1777 | info->n_first = 0; | ||
1778 | info->n_last = 0; | ||
1779 | } else { | ||
1780 | info->n_first = bcd2uint(buf[1]); | ||
1781 | info->n_last = bcd2uint(buf[2]); | ||
1782 | info->msf_leadout.minute = buf[3]; | ||
1783 | info->msf_leadout.second = buf[4]; | ||
1784 | info->msf_leadout.frame = buf[5]; | ||
1785 | info->msf_first.minute = buf[6]; | ||
1786 | info->msf_first.second = buf[7]; | ||
1787 | info->msf_first.frame = buf[8]; | ||
1788 | } | ||
1789 | return ans; | ||
1790 | } | ||
1791 | |||
1792 | static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, | ||
1793 | int tries) | ||
1794 | { | ||
1795 | char cmd[2]; | ||
1796 | int ans; | ||
1797 | |||
1798 | xtrace(HW, "setdrivemode() %d\n", mode); | ||
1799 | |||
1800 | if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries))) | ||
1801 | return -1; | ||
1802 | |||
1803 | switch (mode) { | ||
1804 | case TOC: | ||
1805 | cmd[1] |= 0x04; | ||
1806 | break; | ||
1807 | case DATA: | ||
1808 | cmd[1] &= ~0x04; | ||
1809 | break; | ||
1810 | case RAW: | ||
1811 | cmd[1] |= 0x40; | ||
1812 | break; | ||
1813 | case COOKED: | ||
1814 | cmd[1] &= ~0x40; | ||
1815 | break; | ||
1816 | default: | ||
1817 | break; | ||
1818 | } | ||
1819 | cmd[0] = 0x50; | ||
1820 | return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); | ||
1821 | } | ||
1822 | |||
1823 | static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, | ||
1824 | int tries) | ||
1825 | { | ||
1826 | unsigned char cmd[2] = { 0xa0 }; | ||
1827 | xtrace(HW, "setdatamode() %d\n", mode); | ||
1828 | switch (mode) { | ||
1829 | case MODE0: | ||
1830 | cmd[1] = 0x00; | ||
1831 | break; | ||
1832 | case MODE1: | ||
1833 | cmd[1] = 0x01; | ||
1834 | break; | ||
1835 | case MODE2: | ||
1836 | cmd[1] = 0x02; | ||
1837 | break; | ||
1838 | default: | ||
1839 | return -EINVAL; | ||
1840 | } | ||
1841 | return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); | ||
1842 | } | ||
1843 | |||
1844 | static int mcdx_config(struct s_drive_stuff *stuffp, int tries) | ||
1845 | { | ||
1846 | char cmd[4]; | ||
1847 | |||
1848 | xtrace(HW, "config()\n"); | ||
1849 | |||
1850 | cmd[0] = 0x90; | ||
1851 | |||
1852 | cmd[1] = 0x10; /* irq enable */ | ||
1853 | cmd[2] = 0x05; /* pre, err irq enable */ | ||
1854 | |||
1855 | if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries)) | ||
1856 | return -1; | ||
1857 | |||
1858 | cmd[1] = 0x02; /* dma select */ | ||
1859 | cmd[2] = 0x00; /* no dma */ | ||
1860 | |||
1861 | return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries); | ||
1862 | } | ||
1863 | |||
1864 | static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, | ||
1865 | int tries) | ||
1866 | { | ||
1867 | char buf[3]; | ||
1868 | int ans; | ||
1869 | |||
1870 | if (-1 == (ans = mcdx_talk(stuffp, "\xdc", | ||
1871 | 1, buf, sizeof(buf), 2 * HZ, tries))) | ||
1872 | return ans; | ||
1873 | |||
1874 | ver->code = buf[1]; | ||
1875 | ver->ver = buf[2]; | ||
1876 | |||
1877 | return ans; | ||
1878 | } | ||
1879 | |||
1880 | static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries) | ||
1881 | { | ||
1882 | if (mode == HARD) { | ||
1883 | outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */ | ||
1884 | outb(0, stuffp->wreg_reset); /* hw reset */ | ||
1885 | return 0; | ||
1886 | } else | ||
1887 | return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries); | ||
1888 | } | ||
1889 | |||
1890 | static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock) | ||
1891 | { | ||
1892 | struct s_drive_stuff *stuffp = cdi->handle; | ||
1893 | char cmd[2] = { 0xfe }; | ||
1894 | |||
1895 | if (!(stuffp->present & DOOR)) | ||
1896 | return -ENOSYS; | ||
1897 | if (stuffp->present & DOOR) { | ||
1898 | cmd[1] = lock ? 0x01 : 0x00; | ||
1899 | return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3); | ||
1900 | } else | ||
1901 | return 0; | ||
1902 | } | ||
1903 | |||
1904 | static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries) | ||
1905 | { | ||
1906 | return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); | ||
1907 | } | ||
1908 | |||
1909 | static int | ||
1910 | mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf) | ||
1911 | { | ||
1912 | unsigned long timeout = to + jiffies; | ||
1913 | char c; | ||
1914 | |||
1915 | if (!buf) | ||
1916 | buf = &c; | ||
1917 | |||
1918 | while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) { | ||
1919 | if (time_after(jiffies, timeout)) | ||
1920 | return -1; | ||
1921 | mcdx_delay(stuffp, delay); | ||
1922 | } | ||
1923 | |||
1924 | *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff; | ||
1925 | |||
1926 | return 0; | ||
1927 | } | ||
1928 | |||
1929 | static int mcdx_setattentuator(struct s_drive_stuff *stuffp, | ||
1930 | struct cdrom_volctrl *vol, int tries) | ||
1931 | { | ||
1932 | char cmd[5]; | ||
1933 | cmd[0] = 0xae; | ||
1934 | cmd[1] = vol->channel0; | ||
1935 | cmd[2] = 0; | ||
1936 | cmd[3] = vol->channel1; | ||
1937 | cmd[4] = 0; | ||
1938 | |||
1939 | return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries); | ||
1940 | } | ||
1941 | |||
1942 | MODULE_LICENSE("GPL"); | ||
1943 | MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/mcdx.h b/drivers/cdrom/mcdx.h deleted file mode 100644 index 83c364a74dc4..000000000000 --- a/drivers/cdrom/mcdx.h +++ /dev/null | |||
@@ -1,185 +0,0 @@ | |||
1 | /* | ||
2 | * Definitions for the Mitsumi CDROM interface | ||
3 | * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de> | ||
4 | * VERSION: @VERSION@ | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; see the file COPYING. If not, write to | ||
18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | * Thanks to | ||
21 | * The Linux Community at all and ... | ||
22 | * Martin Harris (he wrote the first Mitsumi Driver) | ||
23 | * Eberhard Moenkeberg (he gave me much support and the initial kick) | ||
24 | * Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they | ||
25 | * improved the original driver) | ||
26 | * Jon Tombs, Bjorn Ekwall (module support) | ||
27 | * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) | ||
28 | * Gerd Knorr (he lent me his PhotoCD) | ||
29 | * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) | ||
30 | * Andreas Kies (testing the mysterious hang up's) | ||
31 | * ... somebody forgotten? | ||
32 | * Marcin Dalecki | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | /* | ||
37 | * The following lines are for user configuration | ||
38 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
39 | * | ||
40 | * {0|1} -- 1 if you want the driver detect your drive, may crash and | ||
41 | * needs a long time to seek. The higher the address the longer the | ||
42 | * seek. | ||
43 | * | ||
44 | * WARNING: AUTOPROBE doesn't work. | ||
45 | */ | ||
46 | #define MCDX_AUTOPROBE 0 | ||
47 | |||
48 | /* | ||
49 | * Drive specific settings according to the jumpers on the controller | ||
50 | * board(s). | ||
51 | * o MCDX_NDRIVES : number of used entries of the following table | ||
52 | * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller | ||
53 | * | ||
54 | * NOTE: I didn't get a drive at irq 9(2) working. Not even alone. | ||
55 | */ | ||
56 | #if MCDX_AUTOPROBE == 0 | ||
57 | #define MCDX_NDRIVES 1 | ||
58 | #define MCDX_DRIVEMAP { \ | ||
59 | {0x300, 11}, \ | ||
60 | {0x304, 05}, \ | ||
61 | {0x000, 00}, \ | ||
62 | {0x000, 00}, \ | ||
63 | {0x000, 00}, \ | ||
64 | } | ||
65 | #else | ||
66 | #error Autoprobing is not implemented yet. | ||
67 | #endif | ||
68 | |||
69 | #ifndef MCDX_QUIET | ||
70 | #define MCDX_QUIET 1 | ||
71 | #endif | ||
72 | |||
73 | #ifndef MCDX_DEBUG | ||
74 | #define MCDX_DEBUG 0 | ||
75 | #endif | ||
76 | |||
77 | /* *** make the following line uncommented, if you're sure, | ||
78 | * *** all configuration is done */ | ||
79 | /* #define I_WAS_HERE */ | ||
80 | |||
81 | /* The name of the device */ | ||
82 | #define MCDX "mcdx" | ||
83 | |||
84 | /* Flags for DEBUGGING */ | ||
85 | #define INIT 0 | ||
86 | #define MALLOC 0 | ||
87 | #define IOCTL 0 | ||
88 | #define PLAYTRK 0 | ||
89 | #define SUBCHNL 0 | ||
90 | #define TOCHDR 0 | ||
91 | #define MS 0 | ||
92 | #define PLAYMSF 0 | ||
93 | #define READTOC 0 | ||
94 | #define OPENCLOSE 0 | ||
95 | #define HW 0 | ||
96 | #define TALK 0 | ||
97 | #define IRQ 0 | ||
98 | #define XFER 0 | ||
99 | #define REQUEST 0 | ||
100 | #define SLEEP 0 | ||
101 | |||
102 | /* The following addresses are taken from the Mitsumi Reference | ||
103 | * and describe the possible i/o range for the controller. | ||
104 | */ | ||
105 | #define MCDX_IO_BEGIN ((char*) 0x300) /* first base of i/o addr */ | ||
106 | #define MCDX_IO_END ((char*) 0x3fc) /* last base of i/o addr */ | ||
107 | |||
108 | /* Per controller 4 bytes i/o are needed. */ | ||
109 | #define MCDX_IO_SIZE 4 | ||
110 | |||
111 | /* | ||
112 | * Bits | ||
113 | */ | ||
114 | |||
115 | /* The status byte, returned from every command, set if | ||
116 | * the description is true */ | ||
117 | #define MCDX_RBIT_OPEN 0x80 /* door is open */ | ||
118 | #define MCDX_RBIT_DISKSET 0x40 /* disk set (recognised) */ | ||
119 | #define MCDX_RBIT_CHANGED 0x20 /* disk was changed */ | ||
120 | #define MCDX_RBIT_CHECK 0x10 /* disk rotates, servo is on */ | ||
121 | #define MCDX_RBIT_AUDIOTR 0x08 /* current track is audio */ | ||
122 | #define MCDX_RBIT_RDERR 0x04 /* read error, refer SENSE KEY */ | ||
123 | #define MCDX_RBIT_AUDIOBS 0x02 /* currently playing audio */ | ||
124 | #define MCDX_RBIT_CMDERR 0x01 /* command, param or format error */ | ||
125 | |||
126 | /* The I/O Register holding the h/w status of the drive, | ||
127 | * can be read at i/o base + 1 */ | ||
128 | #define MCDX_RBIT_DOOR 0x10 /* door is open */ | ||
129 | #define MCDX_RBIT_STEN 0x04 /* if 0, i/o base contains drive status */ | ||
130 | #define MCDX_RBIT_DTEN 0x02 /* if 0, i/o base contains data */ | ||
131 | |||
132 | /* | ||
133 | * The commands. | ||
134 | */ | ||
135 | |||
136 | #define OPCODE 1 /* offset of opcode */ | ||
137 | #define MCDX_CMD_REQUEST_TOC 1, 0x10 | ||
138 | #define MCDX_CMD_REQUEST_STATUS 1, 0x40 | ||
139 | #define MCDX_CMD_RESET 1, 0x60 | ||
140 | #define MCDX_CMD_REQUEST_DRIVE_MODE 1, 0xc2 | ||
141 | #define MCDX_CMD_SET_INTERLEAVE 2, 0xc8, 0 | ||
142 | #define MCDX_CMD_DATAMODE_SET 2, 0xa0, 0 | ||
143 | #define MCDX_DATAMODE1 0x01 | ||
144 | #define MCDX_DATAMODE2 0x02 | ||
145 | #define MCDX_CMD_LOCK_DOOR 2, 0xfe, 0 | ||
146 | |||
147 | #define READ_AHEAD 4 /* 8 Sectors (4K) */ | ||
148 | |||
149 | /* Useful macros */ | ||
150 | #define e_door(x) ((x) & MCDX_RBIT_OPEN) | ||
151 | #define e_check(x) (~(x) & MCDX_RBIT_CHECK) | ||
152 | #define e_notset(x) (~(x) & MCDX_RBIT_DISKSET) | ||
153 | #define e_changed(x) ((x) & MCDX_RBIT_CHANGED) | ||
154 | #define e_audio(x) ((x) & MCDX_RBIT_AUDIOTR) | ||
155 | #define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS) | ||
156 | #define e_cmderr(x) ((x) & MCDX_RBIT_CMDERR) | ||
157 | #define e_readerr(x) ((x) & MCDX_RBIT_RDERR) | ||
158 | |||
159 | /** no drive specific */ | ||
160 | #define MCDX_CDBLK 2048 /* 2048 cooked data each blk */ | ||
161 | |||
162 | #define MCDX_DATA_TIMEOUT (HZ/10) /* 0.1 second */ | ||
163 | |||
164 | /* | ||
165 | * Access to the msf array | ||
166 | */ | ||
167 | #define MSF_MIN 0 /* minute */ | ||
168 | #define MSF_SEC 1 /* second */ | ||
169 | #define MSF_FRM 2 /* frame */ | ||
170 | |||
171 | /* | ||
172 | * Errors | ||
173 | */ | ||
174 | #define MCDX_E 1 /* unspec error */ | ||
175 | #define MCDX_ST_EOM 0x0100 /* end of media */ | ||
176 | #define MCDX_ST_DRV 0x00ff /* mask to query the drive status */ | ||
177 | |||
178 | #ifndef I_WAS_HERE | ||
179 | #ifndef MODULE | ||
180 | #warning You have not edited mcdx.h | ||
181 | #warning Perhaps irq and i/o settings are wrong. | ||
182 | #endif | ||
183 | #endif | ||
184 | |||
185 | /* ex:set ts=4 sw=4: */ | ||
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c deleted file mode 100644 index 3541690a77d4..000000000000 --- a/drivers/cdrom/optcd.c +++ /dev/null | |||
@@ -1,2105 +0,0 @@ | |||
1 | /* linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver | ||
2 | $Id: optcd.c,v 1.11 1997/01/26 07:13:00 davem Exp $ | ||
3 | |||
4 | Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) | ||
5 | |||
6 | |||
7 | Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks | ||
8 | by Eberhard Moenkeberg (emoenke@gwdg.de). | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2, or (at your option) | ||
13 | any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | /* Revision history | ||
26 | |||
27 | |||
28 | 14-5-95 v0.0 Plays sound tracks. No reading of data CDs yet. | ||
29 | Detection of disk change doesn't work. | ||
30 | 21-5-95 v0.1 First ALPHA version. CD can be mounted. The | ||
31 | device major nr is borrowed from the Aztech | ||
32 | driver. Speed is around 240 kb/s, as measured | ||
33 | with "time dd if=/dev/cdrom of=/dev/null \ | ||
34 | bs=2048 count=4096". | ||
35 | 24-6-95 v0.2 Reworked the #defines for the command codes | ||
36 | and the like, as well as the structure of | ||
37 | the hardware communication protocol, to | ||
38 | reflect the "official" documentation, kindly | ||
39 | supplied by C.K. Tan, Optics Storage Pte. Ltd. | ||
40 | Also tidied up the state machine somewhat. | ||
41 | 28-6-95 v0.3 Removed the ISP-16 interface code, as this | ||
42 | should go into its own driver. The driver now | ||
43 | has its own major nr. | ||
44 | Disk change detection now seems to work, too. | ||
45 | This version became part of the standard | ||
46 | kernel as of version 1.3.7 | ||
47 | 24-9-95 v0.4 Re-inserted ISP-16 interface code which I | ||
48 | copied from sjcd.c, with a few changes. | ||
49 | Updated README.optcd. Submitted for | ||
50 | inclusion in 1.3.21 | ||
51 | 29-9-95 v0.4a Fixed bug that prevented compilation as module | ||
52 | 25-10-95 v0.5 Started multisession code. Implementation | ||
53 | copied from Werner Zimmermann, who copied it | ||
54 | from Heiko Schlittermann's mcdx. | ||
55 | 17-1-96 v0.6 Multisession works; some cleanup too. | ||
56 | 18-4-96 v0.7 Increased some timing constants; | ||
57 | thanks to Luke McFarlane. Also tidied up some | ||
58 | printk behaviour. ISP16 initialization | ||
59 | is now handled by a separate driver. | ||
60 | |||
61 | 09-11-99 Make kernel-parameter implementation work with 2.3.x | ||
62 | Removed init_module & cleanup_module in favor of | ||
63 | module_init & module_exit. | ||
64 | Torben Mathiasen <tmm@image.dk> | ||
65 | */ | ||
66 | |||
67 | /* Includes */ | ||
68 | |||
69 | |||
70 | #include <linux/module.h> | ||
71 | #include <linux/mm.h> | ||
72 | #include <linux/ioport.h> | ||
73 | #include <linux/init.h> | ||
74 | |||
75 | #include <asm/io.h> | ||
76 | #include <linux/blkdev.h> | ||
77 | |||
78 | #include <linux/cdrom.h> | ||
79 | #include "optcd.h" | ||
80 | |||
81 | #include <asm/uaccess.h> | ||
82 | |||
83 | #define MAJOR_NR OPTICS_CDROM_MAJOR | ||
84 | #define QUEUE (opt_queue) | ||
85 | #define CURRENT elv_next_request(opt_queue) | ||
86 | |||
87 | |||
88 | /* Debug support */ | ||
89 | |||
90 | |||
91 | /* Don't forget to add new debug flags here. */ | ||
92 | #if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \ | ||
93 | DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS | ||
94 | #define DEBUG(x) debug x | ||
95 | static void debug(int debug_this, const char* fmt, ...) | ||
96 | { | ||
97 | char s[1024]; | ||
98 | va_list args; | ||
99 | |||
100 | if (!debug_this) | ||
101 | return; | ||
102 | |||
103 | va_start(args, fmt); | ||
104 | vsnprintf(s, sizeof(s), fmt, args); | ||
105 | printk(KERN_DEBUG "optcd: %s\n", s); | ||
106 | va_end(args); | ||
107 | } | ||
108 | #else | ||
109 | #define DEBUG(x) | ||
110 | #endif | ||
111 | |||
112 | |||
113 | /* Drive hardware/firmware characteristics | ||
114 | Identifiers in accordance with Optics Storage documentation */ | ||
115 | |||
116 | |||
117 | #define optcd_port optcd /* Needed for the modutils. */ | ||
118 | static short optcd_port = OPTCD_PORTBASE; /* I/O base of drive. */ | ||
119 | module_param(optcd_port, short, 0); | ||
120 | /* Drive registers, read */ | ||
121 | #define DATA_PORT optcd_port /* Read data/status */ | ||
122 | #define STATUS_PORT optcd_port+1 /* Indicate data/status availability */ | ||
123 | |||
124 | /* Drive registers, write */ | ||
125 | #define COMIN_PORT optcd_port /* For passing command/parameter */ | ||
126 | #define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */ | ||
127 | #define HCON_PORT optcd_port+2 /* Host Xfer Configuration */ | ||
128 | |||
129 | |||
130 | /* Command completion/status read from DATA register */ | ||
131 | #define ST_DRVERR 0x80 | ||
132 | #define ST_DOOR_OPEN 0x40 | ||
133 | #define ST_MIXEDMODE_DISK 0x20 | ||
134 | #define ST_MODE_BITS 0x1c | ||
135 | #define ST_M_STOP 0x00 | ||
136 | #define ST_M_READ 0x04 | ||
137 | #define ST_M_AUDIO 0x04 | ||
138 | #define ST_M_PAUSE 0x08 | ||
139 | #define ST_M_INITIAL 0x0c | ||
140 | #define ST_M_ERROR 0x10 | ||
141 | #define ST_M_OTHERS 0x14 | ||
142 | #define ST_MODE2TRACK 0x02 | ||
143 | #define ST_DSK_CHG 0x01 | ||
144 | #define ST_L_LOCK 0x01 | ||
145 | #define ST_CMD_OK 0x00 | ||
146 | #define ST_OP_OK 0x01 | ||
147 | #define ST_PA_OK 0x02 | ||
148 | #define ST_OP_ERROR 0x05 | ||
149 | #define ST_PA_ERROR 0x06 | ||
150 | |||
151 | |||
152 | /* Error codes (appear as command completion code from DATA register) */ | ||
153 | /* Player related errors */ | ||
154 | #define ERR_ILLCMD 0x11 /* Illegal command to player module */ | ||
155 | #define ERR_ILLPARM 0x12 /* Illegal parameter to player module */ | ||
156 | #define ERR_SLEDGE 0x13 | ||
157 | #define ERR_FOCUS 0x14 | ||
158 | #define ERR_MOTOR 0x15 | ||
159 | #define ERR_RADIAL 0x16 | ||
160 | #define ERR_PLL 0x17 /* PLL lock error */ | ||
161 | #define ERR_SUB_TIM 0x18 /* Subcode timeout error */ | ||
162 | #define ERR_SUB_NF 0x19 /* Subcode not found error */ | ||
163 | #define ERR_TRAY 0x1a | ||
164 | #define ERR_TOC 0x1b /* Table of Contents read error */ | ||
165 | #define ERR_JUMP 0x1c | ||
166 | /* Data errors */ | ||
167 | #define ERR_MODE 0x21 | ||
168 | #define ERR_FORM 0x22 | ||
169 | #define ERR_HEADADDR 0x23 /* Header Address not found */ | ||
170 | #define ERR_CRC 0x24 | ||
171 | #define ERR_ECC 0x25 /* Uncorrectable ECC error */ | ||
172 | #define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */ | ||
173 | #define ERR_ILLBSYNC 0x27 /* Illegal block sync error */ | ||
174 | #define ERR_VDST 0x28 /* VDST not found */ | ||
175 | /* Timeout errors */ | ||
176 | #define ERR_READ_TIM 0x31 /* Read timeout error */ | ||
177 | #define ERR_DEC_STP 0x32 /* Decoder stopped */ | ||
178 | #define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */ | ||
179 | /* Function abort codes */ | ||
180 | #define ERR_KEY 0x41 /* Key -Detected abort */ | ||
181 | #define ERR_READ_FINISH 0x42 /* Read Finish */ | ||
182 | /* Second Byte diagnostic codes */ | ||
183 | #define ERR_NOBSYNC 0x01 /* No block sync */ | ||
184 | #define ERR_SHORTB 0x02 /* Short block */ | ||
185 | #define ERR_LONGB 0x03 /* Long block */ | ||
186 | #define ERR_SHORTDSP 0x04 /* Short DSP word */ | ||
187 | #define ERR_LONGDSP 0x05 /* Long DSP word */ | ||
188 | |||
189 | |||
190 | /* Status availability flags read from STATUS register */ | ||
191 | #define FL_EJECT 0x20 | ||
192 | #define FL_WAIT 0x10 /* active low */ | ||
193 | #define FL_EOP 0x08 /* active low */ | ||
194 | #define FL_STEN 0x04 /* Status available when low */ | ||
195 | #define FL_DTEN 0x02 /* Data available when low */ | ||
196 | #define FL_DRQ 0x01 /* active low */ | ||
197 | #define FL_RESET 0xde /* These bits are high after a reset */ | ||
198 | #define FL_STDT (FL_STEN|FL_DTEN) | ||
199 | |||
200 | |||
201 | /* Transfer mode, written to HCON register */ | ||
202 | #define HCON_DTS 0x08 | ||
203 | #define HCON_SDRQB 0x04 | ||
204 | #define HCON_LOHI 0x02 | ||
205 | #define HCON_DMA16 0x01 | ||
206 | |||
207 | |||
208 | /* Drive command set, written to COMIN register */ | ||
209 | /* Quick response commands */ | ||
210 | #define COMDRVST 0x20 /* Drive Status Read */ | ||
211 | #define COMERRST 0x21 /* Error Status Read */ | ||
212 | #define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */ | ||
213 | #define COMINITSINGLE 0x28 /* Initialize Single Speed */ | ||
214 | #define COMINITDOUBLE 0x29 /* Initialize Double Speed */ | ||
215 | #define COMUNLOCK 0x30 /* Unlock */ | ||
216 | #define COMLOCK 0x31 /* Lock */ | ||
217 | #define COMLOCKST 0x32 /* Lock/Unlock Status */ | ||
218 | #define COMVERSION 0x40 /* Get Firmware Revision */ | ||
219 | #define COMVOIDREADMODE 0x50 /* Void Data Read Mode */ | ||
220 | /* Read commands */ | ||
221 | #define COMFETCH 0x60 /* Prefetch Data */ | ||
222 | #define COMREAD 0x61 /* Read */ | ||
223 | #define COMREADRAW 0x62 /* Read Raw Data */ | ||
224 | #define COMREADALL 0x63 /* Read All 2646 Bytes */ | ||
225 | /* Player control commands */ | ||
226 | #define COMLEADIN 0x70 /* Seek To Lead-in */ | ||
227 | #define COMSEEK 0x71 /* Seek */ | ||
228 | #define COMPAUSEON 0x80 /* Pause On */ | ||
229 | #define COMPAUSEOFF 0x81 /* Pause Off */ | ||
230 | #define COMSTOP 0x82 /* Stop */ | ||
231 | #define COMOPEN 0x90 /* Open Tray Door */ | ||
232 | #define COMCLOSE 0x91 /* Close Tray Door */ | ||
233 | #define COMPLAY 0xa0 /* Audio Play */ | ||
234 | #define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */ | ||
235 | #define COMSUBQ 0xb0 /* Read Sub-q Code */ | ||
236 | #define COMLOCATION 0xb1 /* Read Head Position */ | ||
237 | /* Audio control commands */ | ||
238 | #define COMCHCTRL 0xc0 /* Audio Channel Control */ | ||
239 | /* Miscellaneous (test) commands */ | ||
240 | #define COMDRVTEST 0xd0 /* Write Test Bytes */ | ||
241 | #define COMTEST 0xd1 /* Diagnostic Test */ | ||
242 | |||
243 | /* Low level drive interface. Only here we do actual I/O | ||
244 | Waiting for status / data available */ | ||
245 | |||
246 | |||
247 | /* Busy wait until FLAG goes low. Return 0 on timeout. */ | ||
248 | static inline int flag_low(int flag, unsigned long timeout) | ||
249 | { | ||
250 | int flag_high; | ||
251 | unsigned long count = 0; | ||
252 | |||
253 | while ((flag_high = (inb(STATUS_PORT) & flag))) | ||
254 | if (++count >= timeout) | ||
255 | break; | ||
256 | |||
257 | DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s", | ||
258 | flag, count, flag_high ? " timeout" : "")); | ||
259 | return !flag_high; | ||
260 | } | ||
261 | |||
262 | |||
263 | /* Timed waiting for status or data */ | ||
264 | static int sleep_timeout; /* max # of ticks to sleep */ | ||
265 | static DECLARE_WAIT_QUEUE_HEAD(waitq); | ||
266 | static void sleep_timer(unsigned long data); | ||
267 | static DEFINE_TIMER(delay_timer, sleep_timer, 0, 0); | ||
268 | static DEFINE_SPINLOCK(optcd_lock); | ||
269 | static struct request_queue *opt_queue; | ||
270 | |||
271 | /* Timer routine: wake up when desired flag goes low, | ||
272 | or when timeout expires. */ | ||
273 | static void sleep_timer(unsigned long data) | ||
274 | { | ||
275 | int flags = inb(STATUS_PORT) & FL_STDT; | ||
276 | |||
277 | if (flags == FL_STDT && --sleep_timeout > 0) { | ||
278 | mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */ | ||
279 | } else | ||
280 | wake_up(&waitq); | ||
281 | } | ||
282 | |||
283 | |||
284 | /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */ | ||
285 | static int sleep_flag_low(int flag, unsigned long timeout) | ||
286 | { | ||
287 | int flag_high; | ||
288 | |||
289 | DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low")); | ||
290 | |||
291 | sleep_timeout = timeout; | ||
292 | flag_high = inb(STATUS_PORT) & flag; | ||
293 | if (flag_high && sleep_timeout > 0) { | ||
294 | mod_timer(&delay_timer, jiffies + HZ/100); | ||
295 | sleep_on(&waitq); | ||
296 | flag_high = inb(STATUS_PORT) & flag; | ||
297 | } | ||
298 | |||
299 | DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s", | ||
300 | flag, timeout, flag_high ? " timeout" : "")); | ||
301 | return !flag_high; | ||
302 | } | ||
303 | |||
304 | /* Low level drive interface. Only here we do actual I/O | ||
305 | Sending commands and parameters */ | ||
306 | |||
307 | |||
308 | /* Errors in the command protocol */ | ||
309 | #define ERR_IF_CMD_TIMEOUT 0x100 | ||
310 | #define ERR_IF_ERR_TIMEOUT 0x101 | ||
311 | #define ERR_IF_RESP_TIMEOUT 0x102 | ||
312 | #define ERR_IF_DATA_TIMEOUT 0x103 | ||
313 | #define ERR_IF_NOSTAT 0x104 | ||
314 | |||
315 | |||
316 | /* Send command code. Return <0 indicates error */ | ||
317 | static int send_cmd(int cmd) | ||
318 | { | ||
319 | unsigned char ack; | ||
320 | |||
321 | DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd)); | ||
322 | |||
323 | outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */ | ||
324 | outb(cmd, COMIN_PORT); /* Send command code */ | ||
325 | if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ | ||
326 | return -ERR_IF_CMD_TIMEOUT; | ||
327 | ack = inb(DATA_PORT); /* read command acknowledge */ | ||
328 | outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ | ||
329 | return ack==ST_OP_OK ? 0 : -ack; | ||
330 | } | ||
331 | |||
332 | |||
333 | /* Send command parameters. Return <0 indicates error */ | ||
334 | static int send_params(struct cdrom_msf *params) | ||
335 | { | ||
336 | unsigned char ack; | ||
337 | |||
338 | DEBUG((DEBUG_DRIVE_IF, "sending parameters" | ||
339 | " %02x:%02x:%02x" | ||
340 | " %02x:%02x:%02x", | ||
341 | params->cdmsf_min0, | ||
342 | params->cdmsf_sec0, | ||
343 | params->cdmsf_frame0, | ||
344 | params->cdmsf_min1, | ||
345 | params->cdmsf_sec1, | ||
346 | params->cdmsf_frame1)); | ||
347 | |||
348 | outb(params->cdmsf_min0, COMIN_PORT); | ||
349 | outb(params->cdmsf_sec0, COMIN_PORT); | ||
350 | outb(params->cdmsf_frame0, COMIN_PORT); | ||
351 | outb(params->cdmsf_min1, COMIN_PORT); | ||
352 | outb(params->cdmsf_sec1, COMIN_PORT); | ||
353 | outb(params->cdmsf_frame1, COMIN_PORT); | ||
354 | if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ | ||
355 | return -ERR_IF_CMD_TIMEOUT; | ||
356 | ack = inb(DATA_PORT); /* read command acknowledge */ | ||
357 | return ack==ST_PA_OK ? 0 : -ack; | ||
358 | } | ||
359 | |||
360 | |||
361 | /* Send parameters for SEEK command. Return <0 indicates error */ | ||
362 | static int send_seek_params(struct cdrom_msf *params) | ||
363 | { | ||
364 | unsigned char ack; | ||
365 | |||
366 | DEBUG((DEBUG_DRIVE_IF, "sending seek parameters" | ||
367 | " %02x:%02x:%02x", | ||
368 | params->cdmsf_min0, | ||
369 | params->cdmsf_sec0, | ||
370 | params->cdmsf_frame0)); | ||
371 | |||
372 | outb(params->cdmsf_min0, COMIN_PORT); | ||
373 | outb(params->cdmsf_sec0, COMIN_PORT); | ||
374 | outb(params->cdmsf_frame0, COMIN_PORT); | ||
375 | if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ | ||
376 | return -ERR_IF_CMD_TIMEOUT; | ||
377 | ack = inb(DATA_PORT); /* read command acknowledge */ | ||
378 | return ack==ST_PA_OK ? 0 : -ack; | ||
379 | } | ||
380 | |||
381 | |||
382 | /* Wait for command execution status. Choice between busy waiting | ||
383 | and sleeping. Return value <0 indicates timeout. */ | ||
384 | static inline int get_exec_status(int busy_waiting) | ||
385 | { | ||
386 | unsigned char exec_status; | ||
387 | |||
388 | if (busy_waiting | ||
389 | ? !flag_low(FL_STEN, BUSY_TIMEOUT) | ||
390 | : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT)) | ||
391 | return -ERR_IF_CMD_TIMEOUT; | ||
392 | |||
393 | exec_status = inb(DATA_PORT); | ||
394 | DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status)); | ||
395 | return exec_status; | ||
396 | } | ||
397 | |||
398 | |||
399 | /* Wait busy for extra byte of data that a command returns. | ||
400 | Return value <0 indicates timeout. */ | ||
401 | static inline int get_data(int short_timeout) | ||
402 | { | ||
403 | unsigned char data; | ||
404 | |||
405 | if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT)) | ||
406 | return -ERR_IF_DATA_TIMEOUT; | ||
407 | |||
408 | data = inb(DATA_PORT); | ||
409 | DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data)); | ||
410 | return data; | ||
411 | } | ||
412 | |||
413 | |||
414 | /* Returns 0 if failed */ | ||
415 | static int reset_drive(void) | ||
416 | { | ||
417 | unsigned long count = 0; | ||
418 | int flags; | ||
419 | |||
420 | DEBUG((DEBUG_DRIVE_IF, "reset drive")); | ||
421 | |||
422 | outb(0, RESET_PORT); | ||
423 | while (++count < RESET_WAIT) | ||
424 | inb(DATA_PORT); | ||
425 | |||
426 | count = 0; | ||
427 | while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET) | ||
428 | if (++count >= BUSY_TIMEOUT) | ||
429 | break; | ||
430 | |||
431 | DEBUG((DEBUG_DRIVE_IF, "reset %s", | ||
432 | flags == FL_RESET ? "succeeded" : "failed")); | ||
433 | |||
434 | if (flags != FL_RESET) | ||
435 | return 0; /* Reset failed */ | ||
436 | outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ | ||
437 | return 1; /* Reset succeeded */ | ||
438 | } | ||
439 | |||
440 | |||
441 | /* Facilities for asynchronous operation */ | ||
442 | |||
443 | /* Read status/data availability flags FL_STEN and FL_DTEN */ | ||
444 | static inline int stdt_flags(void) | ||
445 | { | ||
446 | return inb(STATUS_PORT) & FL_STDT; | ||
447 | } | ||
448 | |||
449 | |||
450 | /* Fetch status that has previously been waited for. <0 means not available */ | ||
451 | static inline int fetch_status(void) | ||
452 | { | ||
453 | unsigned char status; | ||
454 | |||
455 | if (inb(STATUS_PORT) & FL_STEN) | ||
456 | return -ERR_IF_NOSTAT; | ||
457 | |||
458 | status = inb(DATA_PORT); | ||
459 | DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status)); | ||
460 | return status; | ||
461 | } | ||
462 | |||
463 | |||
464 | /* Fetch data that has previously been waited for. */ | ||
465 | static inline void fetch_data(char *buf, int n) | ||
466 | { | ||
467 | insb(DATA_PORT, buf, n); | ||
468 | DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n)); | ||
469 | } | ||
470 | |||
471 | |||
472 | /* Flush status and data fifos */ | ||
473 | static inline void flush_data(void) | ||
474 | { | ||
475 | while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT) | ||
476 | inb(DATA_PORT); | ||
477 | DEBUG((DEBUG_DRIVE_IF, "flushed fifos")); | ||
478 | } | ||
479 | |||
480 | /* Command protocol */ | ||
481 | |||
482 | |||
483 | /* Send a simple command and wait for response. Command codes < COMFETCH | ||
484 | are quick response commands */ | ||
485 | static inline int exec_cmd(int cmd) | ||
486 | { | ||
487 | int ack = send_cmd(cmd); | ||
488 | if (ack < 0) | ||
489 | return ack; | ||
490 | return get_exec_status(cmd < COMFETCH); | ||
491 | } | ||
492 | |||
493 | |||
494 | /* Send a command with parameters. Don't wait for the response, | ||
495 | * which consists of data blocks read from the CD. */ | ||
496 | static inline int exec_read_cmd(int cmd, struct cdrom_msf *params) | ||
497 | { | ||
498 | int ack = send_cmd(cmd); | ||
499 | if (ack < 0) | ||
500 | return ack; | ||
501 | return send_params(params); | ||
502 | } | ||
503 | |||
504 | |||
505 | /* Send a seek command with parameters and wait for response */ | ||
506 | static inline int exec_seek_cmd(int cmd, struct cdrom_msf *params) | ||
507 | { | ||
508 | int ack = send_cmd(cmd); | ||
509 | if (ack < 0) | ||
510 | return ack; | ||
511 | ack = send_seek_params(params); | ||
512 | if (ack < 0) | ||
513 | return ack; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | |||
518 | /* Send a command with parameters and wait for response */ | ||
519 | static inline int exec_long_cmd(int cmd, struct cdrom_msf *params) | ||
520 | { | ||
521 | int ack = exec_read_cmd(cmd, params); | ||
522 | if (ack < 0) | ||
523 | return ack; | ||
524 | return get_exec_status(0); | ||
525 | } | ||
526 | |||
527 | /* Address conversion routines */ | ||
528 | |||
529 | |||
530 | /* Binary to BCD (2 digits) */ | ||
531 | static inline void single_bin2bcd(u_char *p) | ||
532 | { | ||
533 | DEBUG((DEBUG_CONV, "bin2bcd %02d", *p)); | ||
534 | *p = (*p % 10) | ((*p / 10) << 4); | ||
535 | } | ||
536 | |||
537 | |||
538 | /* Convert entire msf struct */ | ||
539 | static void bin2bcd(struct cdrom_msf *msf) | ||
540 | { | ||
541 | single_bin2bcd(&msf->cdmsf_min0); | ||
542 | single_bin2bcd(&msf->cdmsf_sec0); | ||
543 | single_bin2bcd(&msf->cdmsf_frame0); | ||
544 | single_bin2bcd(&msf->cdmsf_min1); | ||
545 | single_bin2bcd(&msf->cdmsf_sec1); | ||
546 | single_bin2bcd(&msf->cdmsf_frame1); | ||
547 | } | ||
548 | |||
549 | |||
550 | /* Linear block address to minute, second, frame form */ | ||
551 | #define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */ | ||
552 | |||
553 | static void lba2msf(int lba, struct cdrom_msf *msf) | ||
554 | { | ||
555 | DEBUG((DEBUG_CONV, "lba2msf %d", lba)); | ||
556 | lba += CD_MSF_OFFSET; | ||
557 | msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM; | ||
558 | msf->cdmsf_sec0 = lba / CD_FRAMES; | ||
559 | msf->cdmsf_frame0 = lba % CD_FRAMES; | ||
560 | msf->cdmsf_min1 = 0; | ||
561 | msf->cdmsf_sec1 = 0; | ||
562 | msf->cdmsf_frame1 = 0; | ||
563 | bin2bcd(msf); | ||
564 | } | ||
565 | |||
566 | |||
567 | /* Two BCD digits to binary */ | ||
568 | static inline u_char bcd2bin(u_char bcd) | ||
569 | { | ||
570 | DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd)); | ||
571 | return (bcd >> 4) * 10 + (bcd & 0x0f); | ||
572 | } | ||
573 | |||
574 | |||
575 | static void msf2lba(union cdrom_addr *addr) | ||
576 | { | ||
577 | addr->lba = addr->msf.minute * CD_FPM | ||
578 | + addr->msf.second * CD_FRAMES | ||
579 | + addr->msf.frame - CD_MSF_OFFSET; | ||
580 | } | ||
581 | |||
582 | |||
583 | /* Minute, second, frame address BCD to binary or to linear address, | ||
584 | depending on MODE */ | ||
585 | static void msf_bcd2bin(union cdrom_addr *addr) | ||
586 | { | ||
587 | addr->msf.minute = bcd2bin(addr->msf.minute); | ||
588 | addr->msf.second = bcd2bin(addr->msf.second); | ||
589 | addr->msf.frame = bcd2bin(addr->msf.frame); | ||
590 | } | ||
591 | |||
592 | /* High level drive commands */ | ||
593 | |||
594 | |||
595 | static int audio_status = CDROM_AUDIO_NO_STATUS; | ||
596 | static char toc_uptodate = 0; | ||
597 | static char disk_changed = 1; | ||
598 | |||
599 | /* Get drive status, flagging completion of audio play and disk changes. */ | ||
600 | static int drive_status(void) | ||
601 | { | ||
602 | int status; | ||
603 | |||
604 | status = exec_cmd(COMIOCTLISTAT); | ||
605 | DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status)); | ||
606 | if (status < 0) | ||
607 | return status; | ||
608 | if (status == 0xff) /* No status available */ | ||
609 | return -ERR_IF_NOSTAT; | ||
610 | |||
611 | if (((status & ST_MODE_BITS) != ST_M_AUDIO) && | ||
612 | (audio_status == CDROM_AUDIO_PLAY)) { | ||
613 | audio_status = CDROM_AUDIO_COMPLETED; | ||
614 | } | ||
615 | |||
616 | if (status & ST_DSK_CHG) { | ||
617 | toc_uptodate = 0; | ||
618 | disk_changed = 1; | ||
619 | audio_status = CDROM_AUDIO_NO_STATUS; | ||
620 | } | ||
621 | |||
622 | return status; | ||
623 | } | ||
624 | |||
625 | |||
626 | /* Read the current Q-channel info. Also used for reading the | ||
627 | table of contents. qp->cdsc_format must be set on entry to | ||
628 | indicate the desired address format */ | ||
629 | static int get_q_channel(struct cdrom_subchnl *qp) | ||
630 | { | ||
631 | int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10; | ||
632 | |||
633 | status = drive_status(); | ||
634 | if (status < 0) | ||
635 | return status; | ||
636 | qp->cdsc_audiostatus = audio_status; | ||
637 | |||
638 | status = exec_cmd(COMSUBQ); | ||
639 | if (status < 0) | ||
640 | return status; | ||
641 | |||
642 | d1 = get_data(0); | ||
643 | if (d1 < 0) | ||
644 | return d1; | ||
645 | qp->cdsc_adr = d1; | ||
646 | qp->cdsc_ctrl = d1 >> 4; | ||
647 | |||
648 | d2 = get_data(0); | ||
649 | if (d2 < 0) | ||
650 | return d2; | ||
651 | qp->cdsc_trk = bcd2bin(d2); | ||
652 | |||
653 | d3 = get_data(0); | ||
654 | if (d3 < 0) | ||
655 | return d3; | ||
656 | qp->cdsc_ind = bcd2bin(d3); | ||
657 | |||
658 | d4 = get_data(0); | ||
659 | if (d4 < 0) | ||
660 | return d4; | ||
661 | qp->cdsc_reladdr.msf.minute = d4; | ||
662 | |||
663 | d5 = get_data(0); | ||
664 | if (d5 < 0) | ||
665 | return d5; | ||
666 | qp->cdsc_reladdr.msf.second = d5; | ||
667 | |||
668 | d6 = get_data(0); | ||
669 | if (d6 < 0) | ||
670 | return d6; | ||
671 | qp->cdsc_reladdr.msf.frame = d6; | ||
672 | |||
673 | d7 = get_data(0); | ||
674 | if (d7 < 0) | ||
675 | return d7; | ||
676 | /* byte not used */ | ||
677 | |||
678 | d8 = get_data(0); | ||
679 | if (d8 < 0) | ||
680 | return d8; | ||
681 | qp->cdsc_absaddr.msf.minute = d8; | ||
682 | |||
683 | d9 = get_data(0); | ||
684 | if (d9 < 0) | ||
685 | return d9; | ||
686 | qp->cdsc_absaddr.msf.second = d9; | ||
687 | |||
688 | d10 = get_data(0); | ||
689 | if (d10 < 0) | ||
690 | return d10; | ||
691 | qp->cdsc_absaddr.msf.frame = d10; | ||
692 | |||
693 | DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", | ||
694 | d1, d2, d3, d4, d5, d6, d7, d8, d9, d10)); | ||
695 | |||
696 | msf_bcd2bin(&qp->cdsc_absaddr); | ||
697 | msf_bcd2bin(&qp->cdsc_reladdr); | ||
698 | if (qp->cdsc_format == CDROM_LBA) { | ||
699 | msf2lba(&qp->cdsc_absaddr); | ||
700 | msf2lba(&qp->cdsc_reladdr); | ||
701 | } | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | /* Table of contents handling */ | ||
707 | |||
708 | |||
709 | /* Errors in table of contents */ | ||
710 | #define ERR_TOC_MISSINGINFO 0x120 | ||
711 | #define ERR_TOC_MISSINGENTRY 0x121 | ||
712 | |||
713 | |||
714 | struct cdrom_disk_info { | ||
715 | unsigned char first; | ||
716 | unsigned char last; | ||
717 | struct cdrom_msf0 disk_length; | ||
718 | struct cdrom_msf0 first_track; | ||
719 | /* Multisession info: */ | ||
720 | unsigned char next; | ||
721 | struct cdrom_msf0 next_session; | ||
722 | struct cdrom_msf0 last_session; | ||
723 | unsigned char multi; | ||
724 | unsigned char xa; | ||
725 | unsigned char audio; | ||
726 | }; | ||
727 | static struct cdrom_disk_info disk_info; | ||
728 | |||
729 | #define MAX_TRACKS 111 | ||
730 | static struct cdrom_subchnl toc[MAX_TRACKS]; | ||
731 | |||
732 | #define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */ | ||
733 | #define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */ | ||
734 | #define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */ | ||
735 | #define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */ | ||
736 | |||
737 | #define I_FIRSTTRACK 0x01 | ||
738 | #define I_LASTTRACK 0x02 | ||
739 | #define I_DISKLENGTH 0x04 | ||
740 | #define I_NEXTSESSION 0x08 | ||
741 | #define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH) | ||
742 | |||
743 | |||
744 | #if DEBUG_TOC | ||
745 | static void toc_debug_info(int i) | ||
746 | { | ||
747 | printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d" | ||
748 | " %2d:%02d.%02d %2d:%02d.%02d\n", | ||
749 | i, toc[i].cdsc_ctrl, toc[i].cdsc_adr, | ||
750 | toc[i].cdsc_trk, toc[i].cdsc_ind, | ||
751 | toc[i].cdsc_reladdr.msf.minute, | ||
752 | toc[i].cdsc_reladdr.msf.second, | ||
753 | toc[i].cdsc_reladdr.msf.frame, | ||
754 | toc[i].cdsc_absaddr.msf.minute, | ||
755 | toc[i].cdsc_absaddr.msf.second, | ||
756 | toc[i].cdsc_absaddr.msf.frame); | ||
757 | } | ||
758 | #endif | ||
759 | |||
760 | |||
761 | static int read_toc(void) | ||
762 | { | ||
763 | int status, limit, count; | ||
764 | unsigned char got_info = 0; | ||
765 | struct cdrom_subchnl q_info; | ||
766 | #if DEBUG_TOC | ||
767 | int i; | ||
768 | #endif | ||
769 | |||
770 | DEBUG((DEBUG_TOC, "starting read_toc")); | ||
771 | |||
772 | count = 0; | ||
773 | for (limit = 60; limit > 0; limit--) { | ||
774 | int index; | ||
775 | |||
776 | q_info.cdsc_format = CDROM_MSF; | ||
777 | status = get_q_channel(&q_info); | ||
778 | if (status < 0) | ||
779 | return status; | ||
780 | |||
781 | index = q_info.cdsc_ind; | ||
782 | if (index > 0 && index < MAX_TRACKS | ||
783 | && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) { | ||
784 | toc[index] = q_info; | ||
785 | DEBUG((DEBUG_TOC, "got %d", index)); | ||
786 | if (index < 100) | ||
787 | count++; | ||
788 | |||
789 | switch (q_info.cdsc_ind) { | ||
790 | case QINFO_FIRSTTRACK: | ||
791 | got_info |= I_FIRSTTRACK; | ||
792 | break; | ||
793 | case QINFO_LASTTRACK: | ||
794 | got_info |= I_LASTTRACK; | ||
795 | break; | ||
796 | case QINFO_DISKLENGTH: | ||
797 | got_info |= I_DISKLENGTH; | ||
798 | break; | ||
799 | case QINFO_NEXTSESSION: | ||
800 | got_info |= I_NEXTSESSION; | ||
801 | break; | ||
802 | } | ||
803 | } | ||
804 | |||
805 | if ((got_info & I_ALL) == I_ALL | ||
806 | && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count | ||
807 | >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) | ||
808 | break; | ||
809 | } | ||
810 | |||
811 | /* Construct disk_info from TOC */ | ||
812 | if (disk_info.first == 0) { | ||
813 | disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; | ||
814 | disk_info.first_track.minute = | ||
815 | toc[disk_info.first].cdsc_absaddr.msf.minute; | ||
816 | disk_info.first_track.second = | ||
817 | toc[disk_info.first].cdsc_absaddr.msf.second; | ||
818 | disk_info.first_track.frame = | ||
819 | toc[disk_info.first].cdsc_absaddr.msf.frame; | ||
820 | } | ||
821 | disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute; | ||
822 | disk_info.disk_length.minute = | ||
823 | toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute; | ||
824 | disk_info.disk_length.second = | ||
825 | toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2; | ||
826 | disk_info.disk_length.frame = | ||
827 | toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame; | ||
828 | disk_info.next_session.minute = | ||
829 | toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute; | ||
830 | disk_info.next_session.second = | ||
831 | toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second; | ||
832 | disk_info.next_session.frame = | ||
833 | toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame; | ||
834 | disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; | ||
835 | disk_info.last_session.minute = | ||
836 | toc[disk_info.next].cdsc_absaddr.msf.minute; | ||
837 | disk_info.last_session.second = | ||
838 | toc[disk_info.next].cdsc_absaddr.msf.second; | ||
839 | disk_info.last_session.frame = | ||
840 | toc[disk_info.next].cdsc_absaddr.msf.frame; | ||
841 | toc[disk_info.last + 1].cdsc_absaddr.msf.minute = | ||
842 | disk_info.disk_length.minute; | ||
843 | toc[disk_info.last + 1].cdsc_absaddr.msf.second = | ||
844 | disk_info.disk_length.second; | ||
845 | toc[disk_info.last + 1].cdsc_absaddr.msf.frame = | ||
846 | disk_info.disk_length.frame; | ||
847 | #if DEBUG_TOC | ||
848 | for (i = 1; i <= disk_info.last + 1; i++) | ||
849 | toc_debug_info(i); | ||
850 | toc_debug_info(QINFO_FIRSTTRACK); | ||
851 | toc_debug_info(QINFO_LASTTRACK); | ||
852 | toc_debug_info(QINFO_DISKLENGTH); | ||
853 | toc_debug_info(QINFO_NEXTSESSION); | ||
854 | #endif | ||
855 | |||
856 | DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d", | ||
857 | got_info, count)); | ||
858 | if ((got_info & I_ALL) != I_ALL | ||
859 | || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count | ||
860 | < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) | ||
861 | return -ERR_TOC_MISSINGINFO; | ||
862 | return 0; | ||
863 | } | ||
864 | |||
865 | |||
866 | #ifdef MULTISESSION | ||
867 | static int get_multi_disk_info(void) | ||
868 | { | ||
869 | int sessions, status; | ||
870 | struct cdrom_msf multi_index; | ||
871 | |||
872 | |||
873 | for (sessions = 2; sessions < 10 /* %%for now */; sessions++) { | ||
874 | int count; | ||
875 | |||
876 | for (count = 100; count < MAX_TRACKS; count++) | ||
877 | toc[count].cdsc_ind = 0; | ||
878 | |||
879 | multi_index.cdmsf_min0 = disk_info.next_session.minute; | ||
880 | multi_index.cdmsf_sec0 = disk_info.next_session.second; | ||
881 | multi_index.cdmsf_frame0 = disk_info.next_session.frame; | ||
882 | if (multi_index.cdmsf_sec0 >= 20) | ||
883 | multi_index.cdmsf_sec0 -= 20; | ||
884 | else { | ||
885 | multi_index.cdmsf_sec0 += 40; | ||
886 | multi_index.cdmsf_min0--; | ||
887 | } | ||
888 | DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions, | ||
889 | multi_index.cdmsf_min0, | ||
890 | multi_index.cdmsf_sec0, | ||
891 | multi_index.cdmsf_frame0)); | ||
892 | bin2bcd(&multi_index); | ||
893 | multi_index.cdmsf_min1 = 0; | ||
894 | multi_index.cdmsf_sec1 = 0; | ||
895 | multi_index.cdmsf_frame1 = 1; | ||
896 | |||
897 | status = exec_read_cmd(COMREAD, &multi_index); | ||
898 | if (status < 0) { | ||
899 | DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x", | ||
900 | -status)); | ||
901 | break; | ||
902 | } | ||
903 | status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ? | ||
904 | 0 : -ERR_TOC_MISSINGINFO; | ||
905 | flush_data(); | ||
906 | if (status < 0) { | ||
907 | DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status)); | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | status = read_toc(); | ||
912 | if (status < 0) { | ||
913 | DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); | ||
914 | break; | ||
915 | } | ||
916 | |||
917 | disk_info.multi = 1; | ||
918 | } | ||
919 | |||
920 | exec_cmd(COMSTOP); | ||
921 | |||
922 | if (status < 0) | ||
923 | return -EIO; | ||
924 | return 0; | ||
925 | } | ||
926 | #endif /* MULTISESSION */ | ||
927 | |||
928 | |||
929 | static int update_toc(void) | ||
930 | { | ||
931 | int status, count; | ||
932 | |||
933 | if (toc_uptodate) | ||
934 | return 0; | ||
935 | |||
936 | DEBUG((DEBUG_TOC, "starting update_toc")); | ||
937 | |||
938 | disk_info.first = 0; | ||
939 | for (count = 0; count < MAX_TRACKS; count++) | ||
940 | toc[count].cdsc_ind = 0; | ||
941 | |||
942 | status = exec_cmd(COMLEADIN); | ||
943 | if (status < 0) | ||
944 | return -EIO; | ||
945 | |||
946 | status = read_toc(); | ||
947 | if (status < 0) { | ||
948 | DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); | ||
949 | return -EIO; | ||
950 | } | ||
951 | |||
952 | /* Audio disk detection. Look at first track. */ | ||
953 | disk_info.audio = | ||
954 | (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1; | ||
955 | |||
956 | /* XA detection */ | ||
957 | disk_info.xa = drive_status() & ST_MODE2TRACK; | ||
958 | |||
959 | /* Multisession detection: if we want this, define MULTISESSION */ | ||
960 | disk_info.multi = 0; | ||
961 | #ifdef MULTISESSION | ||
962 | if (disk_info.xa) | ||
963 | get_multi_disk_info(); /* Here disk_info.multi is set */ | ||
964 | #endif /* MULTISESSION */ | ||
965 | if (disk_info.multi) | ||
966 | printk(KERN_WARNING "optcd: Multisession support experimental, " | ||
967 | "see Documentation/cdrom/optcd\n"); | ||
968 | |||
969 | DEBUG((DEBUG_TOC, "exiting update_toc")); | ||
970 | |||
971 | toc_uptodate = 1; | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | /* Request handling */ | ||
976 | |||
977 | static int current_valid(void) | ||
978 | { | ||
979 | return CURRENT && | ||
980 | CURRENT->cmd == READ && | ||
981 | CURRENT->sector != -1; | ||
982 | } | ||
983 | |||
984 | /* Buffers for block size conversion. */ | ||
985 | #define NOBUF -1 | ||
986 | |||
987 | static char buf[CD_FRAMESIZE * N_BUFS]; | ||
988 | static volatile int buf_bn[N_BUFS], next_bn; | ||
989 | static volatile int buf_in = 0, buf_out = NOBUF; | ||
990 | |||
991 | static inline void opt_invalidate_buffers(void) | ||
992 | { | ||
993 | int i; | ||
994 | |||
995 | DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers")); | ||
996 | |||
997 | for (i = 0; i < N_BUFS; i++) | ||
998 | buf_bn[i] = NOBUF; | ||
999 | buf_out = NOBUF; | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | /* Take care of the different block sizes between cdrom and Linux. | ||
1004 | When Linux gets variable block sizes this will probably go away. */ | ||
1005 | static void transfer(void) | ||
1006 | { | ||
1007 | #if DEBUG_BUFFERS | DEBUG_REQUEST | ||
1008 | printk(KERN_DEBUG "optcd: executing transfer\n"); | ||
1009 | #endif | ||
1010 | |||
1011 | if (!current_valid()) | ||
1012 | return; | ||
1013 | while (CURRENT -> nr_sectors) { | ||
1014 | int bn = CURRENT -> sector / 4; | ||
1015 | int i, offs, nr_sectors; | ||
1016 | for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i); | ||
1017 | |||
1018 | DEBUG((DEBUG_REQUEST, "found %d", i)); | ||
1019 | |||
1020 | if (i >= N_BUFS) { | ||
1021 | buf_out = NOBUF; | ||
1022 | break; | ||
1023 | } | ||
1024 | |||
1025 | offs = (i * 4 + (CURRENT -> sector & 3)) * 512; | ||
1026 | nr_sectors = 4 - (CURRENT -> sector & 3); | ||
1027 | |||
1028 | if (buf_out != i) { | ||
1029 | buf_out = i; | ||
1030 | if (buf_bn[i] != bn) { | ||
1031 | buf_out = NOBUF; | ||
1032 | continue; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | if (nr_sectors > CURRENT -> nr_sectors) | ||
1037 | nr_sectors = CURRENT -> nr_sectors; | ||
1038 | memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512); | ||
1039 | CURRENT -> nr_sectors -= nr_sectors; | ||
1040 | CURRENT -> sector += nr_sectors; | ||
1041 | CURRENT -> buffer += nr_sectors * 512; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | |||
1046 | /* State machine for reading disk blocks */ | ||
1047 | |||
1048 | enum state_e { | ||
1049 | S_IDLE, /* 0 */ | ||
1050 | S_START, /* 1 */ | ||
1051 | S_READ, /* 2 */ | ||
1052 | S_DATA, /* 3 */ | ||
1053 | S_STOP, /* 4 */ | ||
1054 | S_STOPPING /* 5 */ | ||
1055 | }; | ||
1056 | |||
1057 | static volatile enum state_e state = S_IDLE; | ||
1058 | #if DEBUG_STATE | ||
1059 | static volatile enum state_e state_old = S_STOP; | ||
1060 | static volatile int flags_old = 0; | ||
1061 | static volatile long state_n = 0; | ||
1062 | #endif | ||
1063 | |||
1064 | |||
1065 | /* Used as mutex to keep do_optcd_request (and other processes calling | ||
1066 | ioctl) out while some process is inside a VFS call. | ||
1067 | Reverse is accomplished by checking if state = S_IDLE upon entry | ||
1068 | of opt_ioctl and opt_media_change. */ | ||
1069 | static int in_vfs = 0; | ||
1070 | |||
1071 | |||
1072 | static volatile int transfer_is_active = 0; | ||
1073 | static volatile int error = 0; /* %% do something with this?? */ | ||
1074 | static int tries; /* ibid?? */ | ||
1075 | static int timeout = 0; | ||
1076 | |||
1077 | static void poll(unsigned long data); | ||
1078 | static struct timer_list req_timer = {.function = poll}; | ||
1079 | |||
1080 | |||
1081 | static void poll(unsigned long data) | ||
1082 | { | ||
1083 | static volatile int read_count = 1; | ||
1084 | int flags; | ||
1085 | int loop_again = 1; | ||
1086 | int status = 0; | ||
1087 | int skip = 0; | ||
1088 | |||
1089 | if (error) { | ||
1090 | printk(KERN_ERR "optcd: I/O error 0x%02x\n", error); | ||
1091 | opt_invalidate_buffers(); | ||
1092 | if (!tries--) { | ||
1093 | printk(KERN_ERR "optcd: read block %d failed;" | ||
1094 | " Giving up\n", next_bn); | ||
1095 | if (transfer_is_active) | ||
1096 | loop_again = 0; | ||
1097 | if (current_valid()) | ||
1098 | end_request(CURRENT, 0); | ||
1099 | tries = 5; | ||
1100 | } | ||
1101 | error = 0; | ||
1102 | state = S_STOP; | ||
1103 | } | ||
1104 | |||
1105 | while (loop_again) | ||
1106 | { | ||
1107 | loop_again = 0; /* each case must flip this back to 1 if we want | ||
1108 | to come back up here */ | ||
1109 | |||
1110 | #if DEBUG_STATE | ||
1111 | if (state == state_old) | ||
1112 | state_n++; | ||
1113 | else { | ||
1114 | state_old = state; | ||
1115 | if (++state_n > 1) | ||
1116 | printk(KERN_DEBUG "optcd: %ld times " | ||
1117 | "in previous state\n", state_n); | ||
1118 | printk(KERN_DEBUG "optcd: state %d\n", state); | ||
1119 | state_n = 0; | ||
1120 | } | ||
1121 | #endif | ||
1122 | |||
1123 | switch (state) { | ||
1124 | case S_IDLE: | ||
1125 | return; | ||
1126 | case S_START: | ||
1127 | if (in_vfs) | ||
1128 | break; | ||
1129 | if (send_cmd(COMDRVST)) { | ||
1130 | state = S_IDLE; | ||
1131 | while (current_valid()) | ||
1132 | end_request(CURRENT, 0); | ||
1133 | return; | ||
1134 | } | ||
1135 | state = S_READ; | ||
1136 | timeout = READ_TIMEOUT; | ||
1137 | break; | ||
1138 | case S_READ: { | ||
1139 | struct cdrom_msf msf; | ||
1140 | if (!skip) { | ||
1141 | status = fetch_status(); | ||
1142 | if (status < 0) | ||
1143 | break; | ||
1144 | if (status & ST_DSK_CHG) { | ||
1145 | toc_uptodate = 0; | ||
1146 | opt_invalidate_buffers(); | ||
1147 | } | ||
1148 | } | ||
1149 | skip = 0; | ||
1150 | if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { | ||
1151 | toc_uptodate = 0; | ||
1152 | opt_invalidate_buffers(); | ||
1153 | printk(KERN_WARNING "optcd: %s\n", | ||
1154 | (status & ST_DOOR_OPEN) | ||
1155 | ? "door open" | ||
1156 | : "disk removed"); | ||
1157 | state = S_IDLE; | ||
1158 | while (current_valid()) | ||
1159 | end_request(CURRENT, 0); | ||
1160 | return; | ||
1161 | } | ||
1162 | if (!current_valid()) { | ||
1163 | state = S_STOP; | ||
1164 | loop_again = 1; | ||
1165 | break; | ||
1166 | } | ||
1167 | next_bn = CURRENT -> sector / 4; | ||
1168 | lba2msf(next_bn, &msf); | ||
1169 | read_count = N_BUFS; | ||
1170 | msf.cdmsf_frame1 = read_count; /* Not BCD! */ | ||
1171 | |||
1172 | DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x", | ||
1173 | msf.cdmsf_min0, | ||
1174 | msf.cdmsf_sec0, | ||
1175 | msf.cdmsf_frame0, | ||
1176 | msf.cdmsf_min1, | ||
1177 | msf.cdmsf_sec1, | ||
1178 | msf.cdmsf_frame1)); | ||
1179 | DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d" | ||
1180 | " buf_out:%d buf_bn:%d", | ||
1181 | next_bn, | ||
1182 | buf_in, | ||
1183 | buf_out, | ||
1184 | buf_bn[buf_in])); | ||
1185 | |||
1186 | exec_read_cmd(COMREAD, &msf); | ||
1187 | state = S_DATA; | ||
1188 | timeout = READ_TIMEOUT; | ||
1189 | break; | ||
1190 | } | ||
1191 | case S_DATA: | ||
1192 | flags = stdt_flags() & (FL_STEN|FL_DTEN); | ||
1193 | |||
1194 | #if DEBUG_STATE | ||
1195 | if (flags != flags_old) { | ||
1196 | flags_old = flags; | ||
1197 | printk(KERN_DEBUG "optcd: flags:%x\n", flags); | ||
1198 | } | ||
1199 | if (flags == FL_STEN) | ||
1200 | printk(KERN_DEBUG "timeout cnt: %d\n", timeout); | ||
1201 | #endif | ||
1202 | |||
1203 | switch (flags) { | ||
1204 | case FL_DTEN: /* only STEN low */ | ||
1205 | if (!tries--) { | ||
1206 | printk(KERN_ERR | ||
1207 | "optcd: read block %d failed; " | ||
1208 | "Giving up\n", next_bn); | ||
1209 | if (transfer_is_active) { | ||
1210 | tries = 0; | ||
1211 | break; | ||
1212 | } | ||
1213 | if (current_valid()) | ||
1214 | end_request(CURRENT, 0); | ||
1215 | tries = 5; | ||
1216 | } | ||
1217 | state = S_START; | ||
1218 | timeout = READ_TIMEOUT; | ||
1219 | loop_again = 1; | ||
1220 | case (FL_STEN|FL_DTEN): /* both high */ | ||
1221 | break; | ||
1222 | default: /* DTEN low */ | ||
1223 | tries = 5; | ||
1224 | if (!current_valid() && buf_in == buf_out) { | ||
1225 | state = S_STOP; | ||
1226 | loop_again = 1; | ||
1227 | break; | ||
1228 | } | ||
1229 | if (read_count<=0) | ||
1230 | printk(KERN_WARNING | ||
1231 | "optcd: warning - try to read" | ||
1232 | " 0 frames\n"); | ||
1233 | while (read_count) { | ||
1234 | buf_bn[buf_in] = NOBUF; | ||
1235 | if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) { | ||
1236 | /* should be no waiting here!?? */ | ||
1237 | printk(KERN_ERR | ||
1238 | "read_count:%d " | ||
1239 | "CURRENT->nr_sectors:%ld " | ||
1240 | "buf_in:%d\n", | ||
1241 | read_count, | ||
1242 | CURRENT->nr_sectors, | ||
1243 | buf_in); | ||
1244 | printk(KERN_ERR | ||
1245 | "transfer active: %x\n", | ||
1246 | transfer_is_active); | ||
1247 | read_count = 0; | ||
1248 | state = S_STOP; | ||
1249 | loop_again = 1; | ||
1250 | end_request(CURRENT, 0); | ||
1251 | break; | ||
1252 | } | ||
1253 | fetch_data(buf+ | ||
1254 | CD_FRAMESIZE*buf_in, | ||
1255 | CD_FRAMESIZE); | ||
1256 | read_count--; | ||
1257 | |||
1258 | DEBUG((DEBUG_REQUEST, | ||
1259 | "S_DATA; ---I've read data- " | ||
1260 | "read_count: %d", | ||
1261 | read_count)); | ||
1262 | DEBUG((DEBUG_REQUEST, | ||
1263 | "next_bn:%d buf_in:%d " | ||
1264 | "buf_out:%d buf_bn:%d", | ||
1265 | next_bn, | ||
1266 | buf_in, | ||
1267 | buf_out, | ||
1268 | buf_bn[buf_in])); | ||
1269 | |||
1270 | buf_bn[buf_in] = next_bn++; | ||
1271 | if (buf_out == NOBUF) | ||
1272 | buf_out = buf_in; | ||
1273 | buf_in = buf_in + 1 == | ||
1274 | N_BUFS ? 0 : buf_in + 1; | ||
1275 | } | ||
1276 | if (!transfer_is_active) { | ||
1277 | while (current_valid()) { | ||
1278 | transfer(); | ||
1279 | if (CURRENT -> nr_sectors == 0) | ||
1280 | end_request(CURRENT, 1); | ||
1281 | else | ||
1282 | break; | ||
1283 | } | ||
1284 | } | ||
1285 | |||
1286 | if (current_valid() | ||
1287 | && (CURRENT -> sector / 4 < next_bn || | ||
1288 | CURRENT -> sector / 4 > | ||
1289 | next_bn + N_BUFS)) { | ||
1290 | state = S_STOP; | ||
1291 | loop_again = 1; | ||
1292 | break; | ||
1293 | } | ||
1294 | timeout = READ_TIMEOUT; | ||
1295 | if (read_count == 0) { | ||
1296 | state = S_STOP; | ||
1297 | loop_again = 1; | ||
1298 | break; | ||
1299 | } | ||
1300 | } | ||
1301 | break; | ||
1302 | case S_STOP: | ||
1303 | if (read_count != 0) | ||
1304 | printk(KERN_ERR | ||
1305 | "optcd: discard data=%x frames\n", | ||
1306 | read_count); | ||
1307 | flush_data(); | ||
1308 | if (send_cmd(COMDRVST)) { | ||
1309 | state = S_IDLE; | ||
1310 | while (current_valid()) | ||
1311 | end_request(CURRENT, 0); | ||
1312 | return; | ||
1313 | } | ||
1314 | state = S_STOPPING; | ||
1315 | timeout = STOP_TIMEOUT; | ||
1316 | break; | ||
1317 | case S_STOPPING: | ||
1318 | status = fetch_status(); | ||
1319 | if (status < 0 && timeout) | ||
1320 | break; | ||
1321 | if ((status >= 0) && (status & ST_DSK_CHG)) { | ||
1322 | toc_uptodate = 0; | ||
1323 | opt_invalidate_buffers(); | ||
1324 | } | ||
1325 | if (current_valid()) { | ||
1326 | if (status >= 0) { | ||
1327 | state = S_READ; | ||
1328 | loop_again = 1; | ||
1329 | skip = 1; | ||
1330 | break; | ||
1331 | } else { | ||
1332 | state = S_START; | ||
1333 | timeout = 1; | ||
1334 | } | ||
1335 | } else { | ||
1336 | state = S_IDLE; | ||
1337 | return; | ||
1338 | } | ||
1339 | break; | ||
1340 | default: | ||
1341 | printk(KERN_ERR "optcd: invalid state %d\n", state); | ||
1342 | return; | ||
1343 | } /* case */ | ||
1344 | } /* while */ | ||
1345 | |||
1346 | if (!timeout--) { | ||
1347 | printk(KERN_ERR "optcd: timeout in state %d\n", state); | ||
1348 | state = S_STOP; | ||
1349 | if (exec_cmd(COMSTOP) < 0) { | ||
1350 | state = S_IDLE; | ||
1351 | while (current_valid()) | ||
1352 | end_request(CURRENT, 0); | ||
1353 | return; | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | mod_timer(&req_timer, jiffies + HZ/100); | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | static void do_optcd_request(request_queue_t * q) | ||
1362 | { | ||
1363 | DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)", | ||
1364 | CURRENT -> sector, CURRENT -> nr_sectors)); | ||
1365 | |||
1366 | if (disk_info.audio) { | ||
1367 | printk(KERN_WARNING "optcd: tried to mount an Audio CD\n"); | ||
1368 | end_request(CURRENT, 0); | ||
1369 | return; | ||
1370 | } | ||
1371 | |||
1372 | transfer_is_active = 1; | ||
1373 | while (current_valid()) { | ||
1374 | transfer(); /* First try to transfer block from buffers */ | ||
1375 | if (CURRENT -> nr_sectors == 0) { | ||
1376 | end_request(CURRENT, 1); | ||
1377 | } else { /* Want to read a block not in buffer */ | ||
1378 | buf_out = NOBUF; | ||
1379 | if (state == S_IDLE) { | ||
1380 | /* %% Should this block the request queue?? */ | ||
1381 | if (update_toc() < 0) { | ||
1382 | while (current_valid()) | ||
1383 | end_request(CURRENT, 0); | ||
1384 | break; | ||
1385 | } | ||
1386 | /* Start state machine */ | ||
1387 | state = S_START; | ||
1388 | timeout = READ_TIMEOUT; | ||
1389 | tries = 5; | ||
1390 | /* %% why not start right away?? */ | ||
1391 | mod_timer(&req_timer, jiffies + HZ/100); | ||
1392 | } | ||
1393 | break; | ||
1394 | } | ||
1395 | } | ||
1396 | transfer_is_active = 0; | ||
1397 | |||
1398 | DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d", | ||
1399 | next_bn, buf_in, buf_out, buf_bn[buf_in])); | ||
1400 | DEBUG((DEBUG_REQUEST, "do_optcd_request ends")); | ||
1401 | } | ||
1402 | |||
1403 | /* IOCTLs */ | ||
1404 | |||
1405 | |||
1406 | static char auto_eject = 0; | ||
1407 | |||
1408 | static int cdrompause(void) | ||
1409 | { | ||
1410 | int status; | ||
1411 | |||
1412 | if (audio_status != CDROM_AUDIO_PLAY) | ||
1413 | return -EINVAL; | ||
1414 | |||
1415 | status = exec_cmd(COMPAUSEON); | ||
1416 | if (status < 0) { | ||
1417 | DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status)); | ||
1418 | return -EIO; | ||
1419 | } | ||
1420 | audio_status = CDROM_AUDIO_PAUSED; | ||
1421 | return 0; | ||
1422 | } | ||
1423 | |||
1424 | |||
1425 | static int cdromresume(void) | ||
1426 | { | ||
1427 | int status; | ||
1428 | |||
1429 | if (audio_status != CDROM_AUDIO_PAUSED) | ||
1430 | return -EINVAL; | ||
1431 | |||
1432 | status = exec_cmd(COMPAUSEOFF); | ||
1433 | if (status < 0) { | ||
1434 | DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status)); | ||
1435 | audio_status = CDROM_AUDIO_ERROR; | ||
1436 | return -EIO; | ||
1437 | } | ||
1438 | audio_status = CDROM_AUDIO_PLAY; | ||
1439 | return 0; | ||
1440 | } | ||
1441 | |||
1442 | |||
1443 | static int cdromplaymsf(void __user *arg) | ||
1444 | { | ||
1445 | int status; | ||
1446 | struct cdrom_msf msf; | ||
1447 | |||
1448 | if (copy_from_user(&msf, arg, sizeof msf)) | ||
1449 | return -EFAULT; | ||
1450 | |||
1451 | bin2bcd(&msf); | ||
1452 | status = exec_long_cmd(COMPLAY, &msf); | ||
1453 | if (status < 0) { | ||
1454 | DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); | ||
1455 | audio_status = CDROM_AUDIO_ERROR; | ||
1456 | return -EIO; | ||
1457 | } | ||
1458 | |||
1459 | audio_status = CDROM_AUDIO_PLAY; | ||
1460 | return 0; | ||
1461 | } | ||
1462 | |||
1463 | |||
1464 | static int cdromplaytrkind(void __user *arg) | ||
1465 | { | ||
1466 | int status; | ||
1467 | struct cdrom_ti ti; | ||
1468 | struct cdrom_msf msf; | ||
1469 | |||
1470 | if (copy_from_user(&ti, arg, sizeof ti)) | ||
1471 | return -EFAULT; | ||
1472 | |||
1473 | if (ti.cdti_trk0 < disk_info.first | ||
1474 | || ti.cdti_trk0 > disk_info.last | ||
1475 | || ti.cdti_trk1 < ti.cdti_trk0) | ||
1476 | return -EINVAL; | ||
1477 | if (ti.cdti_trk1 > disk_info.last) | ||
1478 | ti.cdti_trk1 = disk_info.last; | ||
1479 | |||
1480 | msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute; | ||
1481 | msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second; | ||
1482 | msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame; | ||
1483 | msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute; | ||
1484 | msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second; | ||
1485 | msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame; | ||
1486 | |||
1487 | DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d", | ||
1488 | msf.cdmsf_min0, | ||
1489 | msf.cdmsf_sec0, | ||
1490 | msf.cdmsf_frame0, | ||
1491 | msf.cdmsf_min1, | ||
1492 | msf.cdmsf_sec1, | ||
1493 | msf.cdmsf_frame1)); | ||
1494 | |||
1495 | bin2bcd(&msf); | ||
1496 | status = exec_long_cmd(COMPLAY, &msf); | ||
1497 | if (status < 0) { | ||
1498 | DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); | ||
1499 | audio_status = CDROM_AUDIO_ERROR; | ||
1500 | return -EIO; | ||
1501 | } | ||
1502 | |||
1503 | audio_status = CDROM_AUDIO_PLAY; | ||
1504 | return 0; | ||
1505 | } | ||
1506 | |||
1507 | |||
1508 | static int cdromreadtochdr(void __user *arg) | ||
1509 | { | ||
1510 | struct cdrom_tochdr tochdr; | ||
1511 | |||
1512 | tochdr.cdth_trk0 = disk_info.first; | ||
1513 | tochdr.cdth_trk1 = disk_info.last; | ||
1514 | |||
1515 | return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0; | ||
1516 | } | ||
1517 | |||
1518 | |||
1519 | static int cdromreadtocentry(void __user *arg) | ||
1520 | { | ||
1521 | struct cdrom_tocentry entry; | ||
1522 | struct cdrom_subchnl *tocptr; | ||
1523 | |||
1524 | if (copy_from_user(&entry, arg, sizeof entry)) | ||
1525 | return -EFAULT; | ||
1526 | |||
1527 | if (entry.cdte_track == CDROM_LEADOUT) | ||
1528 | tocptr = &toc[disk_info.last + 1]; | ||
1529 | else if (entry.cdte_track > disk_info.last | ||
1530 | || entry.cdte_track < disk_info.first) | ||
1531 | return -EINVAL; | ||
1532 | else | ||
1533 | tocptr = &toc[entry.cdte_track]; | ||
1534 | |||
1535 | entry.cdte_adr = tocptr->cdsc_adr; | ||
1536 | entry.cdte_ctrl = tocptr->cdsc_ctrl; | ||
1537 | entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute; | ||
1538 | entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second; | ||
1539 | entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame; | ||
1540 | /* %% What should go into entry.cdte_datamode? */ | ||
1541 | |||
1542 | if (entry.cdte_format == CDROM_LBA) | ||
1543 | msf2lba(&entry.cdte_addr); | ||
1544 | else if (entry.cdte_format != CDROM_MSF) | ||
1545 | return -EINVAL; | ||
1546 | |||
1547 | return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0; | ||
1548 | } | ||
1549 | |||
1550 | |||
1551 | static int cdromvolctrl(void __user *arg) | ||
1552 | { | ||
1553 | int status; | ||
1554 | struct cdrom_volctrl volctrl; | ||
1555 | struct cdrom_msf msf; | ||
1556 | |||
1557 | if (copy_from_user(&volctrl, arg, sizeof volctrl)) | ||
1558 | return -EFAULT; | ||
1559 | |||
1560 | msf.cdmsf_min0 = 0x10; | ||
1561 | msf.cdmsf_sec0 = 0x32; | ||
1562 | msf.cdmsf_frame0 = volctrl.channel0; | ||
1563 | msf.cdmsf_min1 = volctrl.channel1; | ||
1564 | msf.cdmsf_sec1 = volctrl.channel2; | ||
1565 | msf.cdmsf_frame1 = volctrl.channel3; | ||
1566 | |||
1567 | status = exec_long_cmd(COMCHCTRL, &msf); | ||
1568 | if (status < 0) { | ||
1569 | DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status)); | ||
1570 | return -EIO; | ||
1571 | } | ||
1572 | return 0; | ||
1573 | } | ||
1574 | |||
1575 | |||
1576 | static int cdromsubchnl(void __user *arg) | ||
1577 | { | ||
1578 | int status; | ||
1579 | struct cdrom_subchnl subchnl; | ||
1580 | |||
1581 | if (copy_from_user(&subchnl, arg, sizeof subchnl)) | ||
1582 | return -EFAULT; | ||
1583 | |||
1584 | if (subchnl.cdsc_format != CDROM_LBA | ||
1585 | && subchnl.cdsc_format != CDROM_MSF) | ||
1586 | return -EINVAL; | ||
1587 | |||
1588 | status = get_q_channel(&subchnl); | ||
1589 | if (status < 0) { | ||
1590 | DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status)); | ||
1591 | return -EIO; | ||
1592 | } | ||
1593 | |||
1594 | if (copy_to_user(arg, &subchnl, sizeof subchnl)) | ||
1595 | return -EFAULT; | ||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | |||
1600 | static struct gendisk *optcd_disk; | ||
1601 | |||
1602 | |||
1603 | static int cdromread(void __user *arg, int blocksize, int cmd) | ||
1604 | { | ||
1605 | int status; | ||
1606 | struct cdrom_msf msf; | ||
1607 | |||
1608 | if (copy_from_user(&msf, arg, sizeof msf)) | ||
1609 | return -EFAULT; | ||
1610 | |||
1611 | bin2bcd(&msf); | ||
1612 | msf.cdmsf_min1 = 0; | ||
1613 | msf.cdmsf_sec1 = 0; | ||
1614 | msf.cdmsf_frame1 = 1; /* read only one frame */ | ||
1615 | status = exec_read_cmd(cmd, &msf); | ||
1616 | |||
1617 | DEBUG((DEBUG_VFS, "read cmd status 0x%x", status)); | ||
1618 | |||
1619 | if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT)) | ||
1620 | return -EIO; | ||
1621 | |||
1622 | fetch_data(optcd_disk->private_data, blocksize); | ||
1623 | |||
1624 | if (copy_to_user(arg, optcd_disk->private_data, blocksize)) | ||
1625 | return -EFAULT; | ||
1626 | |||
1627 | return 0; | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | static int cdromseek(void __user *arg) | ||
1632 | { | ||
1633 | int status; | ||
1634 | struct cdrom_msf msf; | ||
1635 | |||
1636 | if (copy_from_user(&msf, arg, sizeof msf)) | ||
1637 | return -EFAULT; | ||
1638 | |||
1639 | bin2bcd(&msf); | ||
1640 | status = exec_seek_cmd(COMSEEK, &msf); | ||
1641 | |||
1642 | DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status)); | ||
1643 | |||
1644 | if (status < 0) | ||
1645 | return -EIO; | ||
1646 | return 0; | ||
1647 | } | ||
1648 | |||
1649 | |||
1650 | #ifdef MULTISESSION | ||
1651 | static int cdrommultisession(void __user *arg) | ||
1652 | { | ||
1653 | struct cdrom_multisession ms; | ||
1654 | |||
1655 | if (copy_from_user(&ms, arg, sizeof ms)) | ||
1656 | return -EFAULT; | ||
1657 | |||
1658 | ms.addr.msf.minute = disk_info.last_session.minute; | ||
1659 | ms.addr.msf.second = disk_info.last_session.second; | ||
1660 | ms.addr.msf.frame = disk_info.last_session.frame; | ||
1661 | |||
1662 | if (ms.addr_format != CDROM_LBA | ||
1663 | && ms.addr_format != CDROM_MSF) | ||
1664 | return -EINVAL; | ||
1665 | if (ms.addr_format == CDROM_LBA) | ||
1666 | msf2lba(&ms.addr); | ||
1667 | |||
1668 | ms.xa_flag = disk_info.xa; | ||
1669 | |||
1670 | if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession))) | ||
1671 | return -EFAULT; | ||
1672 | |||
1673 | #if DEBUG_MULTIS | ||
1674 | if (ms.addr_format == CDROM_MSF) | ||
1675 | printk(KERN_DEBUG | ||
1676 | "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n", | ||
1677 | ms.xa_flag, | ||
1678 | ms.addr.msf.minute, | ||
1679 | ms.addr.msf.second, | ||
1680 | ms.addr.msf.frame); | ||
1681 | else | ||
1682 | printk(KERN_DEBUG | ||
1683 | "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n", | ||
1684 | ms.xa_flag, | ||
1685 | ms.addr.lba, | ||
1686 | disk_info.last_session.minute, | ||
1687 | disk_info.last_session.second, | ||
1688 | disk_info.last_session.frame); | ||
1689 | #endif /* DEBUG_MULTIS */ | ||
1690 | |||
1691 | return 0; | ||
1692 | } | ||
1693 | #endif /* MULTISESSION */ | ||
1694 | |||
1695 | |||
1696 | static int cdromreset(void) | ||
1697 | { | ||
1698 | if (state != S_IDLE) { | ||
1699 | error = 1; | ||
1700 | tries = 0; | ||
1701 | } | ||
1702 | |||
1703 | toc_uptodate = 0; | ||
1704 | disk_changed = 1; | ||
1705 | opt_invalidate_buffers(); | ||
1706 | audio_status = CDROM_AUDIO_NO_STATUS; | ||
1707 | |||
1708 | if (!reset_drive()) | ||
1709 | return -EIO; | ||
1710 | return 0; | ||
1711 | } | ||
1712 | |||
1713 | /* VFS calls */ | ||
1714 | |||
1715 | |||
1716 | static int opt_ioctl(struct inode *ip, struct file *fp, | ||
1717 | unsigned int cmd, unsigned long arg) | ||
1718 | { | ||
1719 | int status, err, retval = 0; | ||
1720 | void __user *argp = (void __user *)arg; | ||
1721 | |||
1722 | DEBUG((DEBUG_VFS, "starting opt_ioctl")); | ||
1723 | |||
1724 | if (!ip) | ||
1725 | return -EINVAL; | ||
1726 | |||
1727 | if (cmd == CDROMRESET) | ||
1728 | return cdromreset(); | ||
1729 | |||
1730 | /* is do_optcd_request or another ioctl busy? */ | ||
1731 | if (state != S_IDLE || in_vfs) | ||
1732 | return -EBUSY; | ||
1733 | |||
1734 | in_vfs = 1; | ||
1735 | |||
1736 | status = drive_status(); | ||
1737 | if (status < 0) { | ||
1738 | DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); | ||
1739 | in_vfs = 0; | ||
1740 | return -EIO; | ||
1741 | } | ||
1742 | |||
1743 | if (status & ST_DOOR_OPEN) | ||
1744 | switch (cmd) { /* Actions that can be taken with door open */ | ||
1745 | case CDROMCLOSETRAY: | ||
1746 | /* We do this before trying to read the toc. */ | ||
1747 | err = exec_cmd(COMCLOSE); | ||
1748 | if (err < 0) { | ||
1749 | DEBUG((DEBUG_VFS, | ||
1750 | "exec_cmd COMCLOSE: %02x", -err)); | ||
1751 | in_vfs = 0; | ||
1752 | return -EIO; | ||
1753 | } | ||
1754 | break; | ||
1755 | default: in_vfs = 0; | ||
1756 | return -EBUSY; | ||
1757 | } | ||
1758 | |||
1759 | err = update_toc(); | ||
1760 | if (err < 0) { | ||
1761 | DEBUG((DEBUG_VFS, "update_toc: %02x", -err)); | ||
1762 | in_vfs = 0; | ||
1763 | return -EIO; | ||
1764 | } | ||
1765 | |||
1766 | DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd)); | ||
1767 | |||
1768 | switch (cmd) { | ||
1769 | case CDROMPAUSE: retval = cdrompause(); break; | ||
1770 | case CDROMRESUME: retval = cdromresume(); break; | ||
1771 | case CDROMPLAYMSF: retval = cdromplaymsf(argp); break; | ||
1772 | case CDROMPLAYTRKIND: retval = cdromplaytrkind(argp); break; | ||
1773 | case CDROMREADTOCHDR: retval = cdromreadtochdr(argp); break; | ||
1774 | case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break; | ||
1775 | |||
1776 | case CDROMSTOP: err = exec_cmd(COMSTOP); | ||
1777 | if (err < 0) { | ||
1778 | DEBUG((DEBUG_VFS, | ||
1779 | "exec_cmd COMSTOP: %02x", | ||
1780 | -err)); | ||
1781 | retval = -EIO; | ||
1782 | } else | ||
1783 | audio_status = CDROM_AUDIO_NO_STATUS; | ||
1784 | break; | ||
1785 | case CDROMSTART: break; /* This is a no-op */ | ||
1786 | case CDROMEJECT: err = exec_cmd(COMUNLOCK); | ||
1787 | if (err < 0) { | ||
1788 | DEBUG((DEBUG_VFS, | ||
1789 | "exec_cmd COMUNLOCK: %02x", | ||
1790 | -err)); | ||
1791 | retval = -EIO; | ||
1792 | break; | ||
1793 | } | ||
1794 | err = exec_cmd(COMOPEN); | ||
1795 | if (err < 0) { | ||
1796 | DEBUG((DEBUG_VFS, | ||
1797 | "exec_cmd COMOPEN: %02x", | ||
1798 | -err)); | ||
1799 | retval = -EIO; | ||
1800 | } | ||
1801 | break; | ||
1802 | |||
1803 | case CDROMVOLCTRL: retval = cdromvolctrl(argp); break; | ||
1804 | case CDROMSUBCHNL: retval = cdromsubchnl(argp); break; | ||
1805 | |||
1806 | /* The drive detects the mode and automatically delivers the | ||
1807 | correct 2048 bytes, so we don't need these IOCTLs */ | ||
1808 | case CDROMREADMODE2: retval = -EINVAL; break; | ||
1809 | case CDROMREADMODE1: retval = -EINVAL; break; | ||
1810 | |||
1811 | /* Drive doesn't support reading audio */ | ||
1812 | case CDROMREADAUDIO: retval = -EINVAL; break; | ||
1813 | |||
1814 | case CDROMEJECT_SW: auto_eject = (char) arg; | ||
1815 | break; | ||
1816 | |||
1817 | #ifdef MULTISESSION | ||
1818 | case CDROMMULTISESSION: retval = cdrommultisession(argp); break; | ||
1819 | #endif | ||
1820 | |||
1821 | case CDROM_GET_MCN: retval = -EINVAL; break; /* not implemented */ | ||
1822 | case CDROMVOLREAD: retval = -EINVAL; break; /* not implemented */ | ||
1823 | |||
1824 | case CDROMREADRAW: | ||
1825 | /* this drive delivers 2340 bytes in raw mode */ | ||
1826 | retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW); | ||
1827 | break; | ||
1828 | case CDROMREADCOOKED: | ||
1829 | retval = cdromread(argp, CD_FRAMESIZE, COMREAD); | ||
1830 | break; | ||
1831 | case CDROMREADALL: | ||
1832 | retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL); | ||
1833 | break; | ||
1834 | |||
1835 | case CDROMSEEK: retval = cdromseek(argp); break; | ||
1836 | case CDROMPLAYBLK: retval = -EINVAL; break; /* not implemented */ | ||
1837 | case CDROMCLOSETRAY: break; /* The action was taken earlier */ | ||
1838 | default: retval = -EINVAL; | ||
1839 | } | ||
1840 | in_vfs = 0; | ||
1841 | return retval; | ||
1842 | } | ||
1843 | |||
1844 | |||
1845 | static int open_count = 0; | ||
1846 | |||
1847 | /* Open device special file; check that a disk is in. */ | ||
1848 | static int opt_open(struct inode *ip, struct file *fp) | ||
1849 | { | ||
1850 | DEBUG((DEBUG_VFS, "starting opt_open")); | ||
1851 | |||
1852 | if (!open_count && state == S_IDLE) { | ||
1853 | int status; | ||
1854 | char *buf; | ||
1855 | |||
1856 | buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL); | ||
1857 | if (!buf) { | ||
1858 | printk(KERN_INFO "optcd: cannot allocate read buffer\n"); | ||
1859 | return -ENOMEM; | ||
1860 | } | ||
1861 | optcd_disk->private_data = buf; /* save read buffer */ | ||
1862 | |||
1863 | toc_uptodate = 0; | ||
1864 | opt_invalidate_buffers(); | ||
1865 | |||
1866 | status = exec_cmd(COMCLOSE); /* close door */ | ||
1867 | if (status < 0) { | ||
1868 | DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status)); | ||
1869 | } | ||
1870 | |||
1871 | status = drive_status(); | ||
1872 | if (status < 0) { | ||
1873 | DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); | ||
1874 | goto err_out; | ||
1875 | } | ||
1876 | DEBUG((DEBUG_VFS, "status: %02x", status)); | ||
1877 | if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { | ||
1878 | printk(KERN_INFO "optcd: no disk or door open\n"); | ||
1879 | goto err_out; | ||
1880 | } | ||
1881 | status = exec_cmd(COMLOCK); /* Lock door */ | ||
1882 | if (status < 0) { | ||
1883 | DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status)); | ||
1884 | } | ||
1885 | status = update_toc(); /* Read table of contents */ | ||
1886 | if (status < 0) { | ||
1887 | DEBUG((DEBUG_VFS, "update_toc: %02x", -status)); | ||
1888 | status = exec_cmd(COMUNLOCK); /* Unlock door */ | ||
1889 | if (status < 0) { | ||
1890 | DEBUG((DEBUG_VFS, | ||
1891 | "exec_cmd COMUNLOCK: %02x", -status)); | ||
1892 | } | ||
1893 | goto err_out; | ||
1894 | } | ||
1895 | open_count++; | ||
1896 | } | ||
1897 | |||
1898 | DEBUG((DEBUG_VFS, "exiting opt_open")); | ||
1899 | |||
1900 | return 0; | ||
1901 | |||
1902 | err_out: | ||
1903 | return -EIO; | ||
1904 | } | ||
1905 | |||
1906 | |||
1907 | /* Release device special file; flush all blocks from the buffer cache */ | ||
1908 | static int opt_release(struct inode *ip, struct file *fp) | ||
1909 | { | ||
1910 | int status; | ||
1911 | |||
1912 | DEBUG((DEBUG_VFS, "executing opt_release")); | ||
1913 | DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n", | ||
1914 | ip, ip->i_bdev->bd_disk->disk_name, fp)); | ||
1915 | |||
1916 | if (!--open_count) { | ||
1917 | toc_uptodate = 0; | ||
1918 | opt_invalidate_buffers(); | ||
1919 | status = exec_cmd(COMUNLOCK); /* Unlock door */ | ||
1920 | if (status < 0) { | ||
1921 | DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status)); | ||
1922 | } | ||
1923 | if (auto_eject) { | ||
1924 | status = exec_cmd(COMOPEN); | ||
1925 | DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status)); | ||
1926 | } | ||
1927 | kfree(optcd_disk->private_data); | ||
1928 | del_timer(&delay_timer); | ||
1929 | del_timer(&req_timer); | ||
1930 | } | ||
1931 | return 0; | ||
1932 | } | ||
1933 | |||
1934 | |||
1935 | /* Check if disk has been changed */ | ||
1936 | static int opt_media_change(struct gendisk *disk) | ||
1937 | { | ||
1938 | DEBUG((DEBUG_VFS, "executing opt_media_change")); | ||
1939 | DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n", | ||
1940 | disk->disk_name, disk_changed)); | ||
1941 | |||
1942 | if (disk_changed) { | ||
1943 | disk_changed = 0; | ||
1944 | return 1; | ||
1945 | } | ||
1946 | return 0; | ||
1947 | } | ||
1948 | |||
1949 | /* Driver initialisation */ | ||
1950 | |||
1951 | |||
1952 | /* Returns 1 if a drive is detected with a version string | ||
1953 | starting with "DOLPHIN". Otherwise 0. */ | ||
1954 | static int __init version_ok(void) | ||
1955 | { | ||
1956 | char devname[100]; | ||
1957 | int count, i, ch, status; | ||
1958 | |||
1959 | status = exec_cmd(COMVERSION); | ||
1960 | if (status < 0) { | ||
1961 | DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status)); | ||
1962 | return 0; | ||
1963 | } | ||
1964 | if ((count = get_data(1)) < 0) { | ||
1965 | DEBUG((DEBUG_VFS, "get_data(1): %02x", -count)); | ||
1966 | return 0; | ||
1967 | } | ||
1968 | for (i = 0, ch = -1; count > 0; count--) { | ||
1969 | if ((ch = get_data(1)) < 0) { | ||
1970 | DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch)); | ||
1971 | break; | ||
1972 | } | ||
1973 | if (i < 99) | ||
1974 | devname[i++] = ch; | ||
1975 | } | ||
1976 | devname[i] = '\0'; | ||
1977 | if (ch < 0) | ||
1978 | return 0; | ||
1979 | |||
1980 | printk(KERN_INFO "optcd: Device %s detected\n", devname); | ||
1981 | return ((devname[0] == 'D') | ||
1982 | && (devname[1] == 'O') | ||
1983 | && (devname[2] == 'L') | ||
1984 | && (devname[3] == 'P') | ||
1985 | && (devname[4] == 'H') | ||
1986 | && (devname[5] == 'I') | ||
1987 | && (devname[6] == 'N')); | ||
1988 | } | ||
1989 | |||
1990 | |||
1991 | static struct block_device_operations opt_fops = { | ||
1992 | .owner = THIS_MODULE, | ||
1993 | .open = opt_open, | ||
1994 | .release = opt_release, | ||
1995 | .ioctl = opt_ioctl, | ||
1996 | .media_changed = opt_media_change, | ||
1997 | }; | ||
1998 | |||
1999 | #ifndef MODULE | ||
2000 | /* Get kernel parameter when used as a kernel driver */ | ||
2001 | static int optcd_setup(char *str) | ||
2002 | { | ||
2003 | int ints[4]; | ||
2004 | (void)get_options(str, ARRAY_SIZE(ints), ints); | ||
2005 | |||
2006 | if (ints[0] > 0) | ||
2007 | optcd_port = ints[1]; | ||
2008 | |||
2009 | return 1; | ||
2010 | } | ||
2011 | |||
2012 | __setup("optcd=", optcd_setup); | ||
2013 | |||
2014 | #endif /* MODULE */ | ||
2015 | |||
2016 | /* Test for presence of drive and initialize it. Called at boot time | ||
2017 | or during module initialisation. */ | ||
2018 | static int __init optcd_init(void) | ||
2019 | { | ||
2020 | int status; | ||
2021 | |||
2022 | if (optcd_port <= 0) { | ||
2023 | printk(KERN_INFO | ||
2024 | "optcd: no Optics Storage CDROM Initialization\n"); | ||
2025 | return -EIO; | ||
2026 | } | ||
2027 | optcd_disk = alloc_disk(1); | ||
2028 | if (!optcd_disk) { | ||
2029 | printk(KERN_ERR "optcd: can't allocate disk\n"); | ||
2030 | return -ENOMEM; | ||
2031 | } | ||
2032 | optcd_disk->major = MAJOR_NR; | ||
2033 | optcd_disk->first_minor = 0; | ||
2034 | optcd_disk->fops = &opt_fops; | ||
2035 | sprintf(optcd_disk->disk_name, "optcd"); | ||
2036 | |||
2037 | if (!request_region(optcd_port, 4, "optcd")) { | ||
2038 | printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n", | ||
2039 | optcd_port); | ||
2040 | put_disk(optcd_disk); | ||
2041 | return -EIO; | ||
2042 | } | ||
2043 | |||
2044 | if (!reset_drive()) { | ||
2045 | printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port); | ||
2046 | release_region(optcd_port, 4); | ||
2047 | put_disk(optcd_disk); | ||
2048 | return -EIO; | ||
2049 | } | ||
2050 | if (!version_ok()) { | ||
2051 | printk(KERN_ERR "optcd: unknown drive detected; aborting\n"); | ||
2052 | release_region(optcd_port, 4); | ||
2053 | put_disk(optcd_disk); | ||
2054 | return -EIO; | ||
2055 | } | ||
2056 | status = exec_cmd(COMINITDOUBLE); | ||
2057 | if (status < 0) { | ||
2058 | printk(KERN_ERR "optcd: cannot init double speed mode\n"); | ||
2059 | release_region(optcd_port, 4); | ||
2060 | DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status)); | ||
2061 | put_disk(optcd_disk); | ||
2062 | return -EIO; | ||
2063 | } | ||
2064 | if (register_blkdev(MAJOR_NR, "optcd")) { | ||
2065 | release_region(optcd_port, 4); | ||
2066 | put_disk(optcd_disk); | ||
2067 | return -EIO; | ||
2068 | } | ||
2069 | |||
2070 | |||
2071 | opt_queue = blk_init_queue(do_optcd_request, &optcd_lock); | ||
2072 | if (!opt_queue) { | ||
2073 | unregister_blkdev(MAJOR_NR, "optcd"); | ||
2074 | release_region(optcd_port, 4); | ||
2075 | put_disk(optcd_disk); | ||
2076 | return -ENOMEM; | ||
2077 | } | ||
2078 | |||
2079 | blk_queue_hardsect_size(opt_queue, 2048); | ||
2080 | optcd_disk->queue = opt_queue; | ||
2081 | add_disk(optcd_disk); | ||
2082 | |||
2083 | printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); | ||
2084 | return 0; | ||
2085 | } | ||
2086 | |||
2087 | |||
2088 | static void __exit optcd_exit(void) | ||
2089 | { | ||
2090 | del_gendisk(optcd_disk); | ||
2091 | put_disk(optcd_disk); | ||
2092 | if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) { | ||
2093 | printk(KERN_ERR "optcd: what's that: can't unregister\n"); | ||
2094 | return; | ||
2095 | } | ||
2096 | blk_cleanup_queue(opt_queue); | ||
2097 | release_region(optcd_port, 4); | ||
2098 | printk(KERN_INFO "optcd: module released.\n"); | ||
2099 | } | ||
2100 | |||
2101 | module_init(optcd_init); | ||
2102 | module_exit(optcd_exit); | ||
2103 | |||
2104 | MODULE_LICENSE("GPL"); | ||
2105 | MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/optcd.h b/drivers/cdrom/optcd.h deleted file mode 100644 index 1911bb92ee28..000000000000 --- a/drivers/cdrom/optcd.h +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | /* linux/include/linux/optcd.h - Optics Storage 8000 AT CDROM driver | ||
2 | $Id: optcd.h,v 1.2 1996/01/15 18:43:44 root Exp root $ | ||
3 | |||
4 | Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) | ||
5 | |||
6 | |||
7 | Configuration file for linux/drivers/cdrom/optcd.c | ||
8 | */ | ||
9 | |||
10 | #ifndef _LINUX_OPTCD_H | ||
11 | #define _LINUX_OPTCD_H | ||
12 | |||
13 | |||
14 | /* I/O base of drive. Drive uses base to base+2. | ||
15 | This setting can be overridden with the kernel or insmod command | ||
16 | line option 'optcd=<portbase>'. Use address of 0 to disable driver. */ | ||
17 | #define OPTCD_PORTBASE 0x340 | ||
18 | |||
19 | |||
20 | /* enable / disable parts of driver by define / undef */ | ||
21 | #define MULTISESSION /* multisession support (ALPHA) */ | ||
22 | |||
23 | |||
24 | /* Change 0 to 1 to debug various parts of the driver */ | ||
25 | #define DEBUG_DRIVE_IF 0 /* Low level drive interface */ | ||
26 | #define DEBUG_CONV 0 /* Address conversions */ | ||
27 | #define DEBUG_BUFFERS 0 /* Buffering and block size conversion */ | ||
28 | #define DEBUG_REQUEST 0 /* Request mechanism */ | ||
29 | #define DEBUG_STATE 0 /* State machine */ | ||
30 | #define DEBUG_TOC 0 /* Q-channel and Table of Contents */ | ||
31 | #define DEBUG_MULTIS 0 /* Multisession code */ | ||
32 | #define DEBUG_VFS 0 /* VFS interface */ | ||
33 | |||
34 | |||
35 | /* Don't touch these unless you know what you're doing. */ | ||
36 | |||
37 | /* Various timeout loop repetition counts. */ | ||
38 | #define BUSY_TIMEOUT 10000000 /* for busy wait */ | ||
39 | #define FAST_TIMEOUT 100000 /* ibid. for probing */ | ||
40 | #define SLEEP_TIMEOUT 6000 /* for timer wait */ | ||
41 | #define MULTI_SEEK_TIMEOUT 1000 /* for timer wait */ | ||
42 | #define READ_TIMEOUT 6000 /* for poll wait */ | ||
43 | #define STOP_TIMEOUT 2000 /* for poll wait */ | ||
44 | #define RESET_WAIT 5000 /* busy wait at drive reset */ | ||
45 | |||
46 | /* # of buffers for block size conversion. 6 is optimal for my setup (P75), | ||
47 | giving 280 kb/s, with 0.4% CPU usage. Experiment to find your optimal | ||
48 | setting */ | ||
49 | #define N_BUFS 6 | ||
50 | |||
51 | |||
52 | #endif /* _LINUX_OPTCD_H */ | ||
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c deleted file mode 100644 index a1283b1ef989..000000000000 --- a/drivers/cdrom/sbpcd.c +++ /dev/null | |||
@@ -1,5966 +0,0 @@ | |||
1 | /* | ||
2 | * sbpcd.c CD-ROM device driver for the whole family of traditional, | ||
3 | * non-ATAPI IDE-style Matsushita/Panasonic CR-5xx drives. | ||
4 | * Works with SoundBlaster compatible cards and with "no-sound" | ||
5 | * interface cards like Lasermate, Panasonic CI-101P, Teac, ... | ||
6 | * Also for the Longshine LCS-7260 drive. | ||
7 | * Also for the IBM "External ISA CD-Rom" drive. | ||
8 | * Also for the CreativeLabs CD200 drive. | ||
9 | * Also for the TEAC CD-55A drive. | ||
10 | * Also for the ECS-AT "Vertos 100" drive. | ||
11 | * Not for Sanyo drives (but for the H94A, sjcd is there...). | ||
12 | * Not for any other Funai drives than the CD200 types (sometimes | ||
13 | * labelled E2550UA or MK4015 or 2800F). | ||
14 | */ | ||
15 | |||
16 | #define VERSION "v4.63 Andrew J. Kroll <ag784@freenet.buffalo.edu> Wed Jul 26 04:24:10 EDT 2000" | ||
17 | |||
18 | /* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg <emoenke@gwdg.de> | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License as published by | ||
22 | * the Free Software Foundation; either version 2, or (at your option) | ||
23 | * any later version. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * (for example /usr/src/linux/COPYING); if not, write to the Free | ||
27 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
28 | * | ||
29 | * If you change this software, you should mail a .diff file with some | ||
30 | * description lines to emoenke@gwdg.de. I want to know about it. | ||
31 | * | ||
32 | * If you are the editor of a Linux CD, you should enable sbpcd.c within | ||
33 | * your boot floppy kernel and send me one of your CDs for free. | ||
34 | * | ||
35 | * If you would like to port the driver to an other operating system (f.e. | ||
36 | * FreeBSD or NetBSD) or use it as an information source, you shall not be | ||
37 | * restricted by the GPL under the following conditions: | ||
38 | * a) the source code of your work is freely available | ||
39 | * b) my part of the work gets mentioned at all places where your | ||
40 | * authorship gets mentioned | ||
41 | * c) I receive a copy of your code together with a full installation | ||
42 | * package of your operating system for free. | ||
43 | * | ||
44 | * | ||
45 | * VERSION HISTORY | ||
46 | * | ||
47 | * 0.1 initial release, April/May 93, after mcd.c (Martin Harriss) | ||
48 | * | ||
49 | * 0.2 thek "repeat:"-loop in do_sbpcd_request did not check for | ||
50 | * end-of-request_queue (resulting in kernel panic). | ||
51 | * Flow control seems stable, but throughput is not better. | ||
52 | * | ||
53 | * 0.3 interrupt locking totally eliminated (maybe "inb" and "outb" | ||
54 | * are still locking) - 0.2 made keyboard-type-ahead losses. | ||
55 | * check_sbpcd_media_change added (to use by isofs/inode.c) | ||
56 | * - but it detects almost nothing. | ||
57 | * | ||
58 | * 0.4 use MAJOR 25 definitely. | ||
59 | * Almost total re-design to support double-speed drives and | ||
60 | * "naked" (no sound) interface cards ("LaserMate" interface type). | ||
61 | * Flow control should be exact now. | ||
62 | * Don't occupy the SbPro IRQ line (not needed either); will | ||
63 | * live together with Hannu Savolainen's sndkit now. | ||
64 | * Speeded up data transfer to 150 kB/sec, with help from Kai | ||
65 | * Makisara, the "provider" of the "mt" tape utility. | ||
66 | * Give "SpinUp" command if necessary. | ||
67 | * First steps to support up to 4 drives (but currently only one). | ||
68 | * Implemented audio capabilities - workman should work, xcdplayer | ||
69 | * gives some problems. | ||
70 | * This version is still consuming too much CPU time, and | ||
71 | * sleeping still has to be worked on. | ||
72 | * During "long" implied seeks, it seems possible that a | ||
73 | * ReadStatus command gets ignored. That gives the message | ||
74 | * "ResponseStatus timed out" (happens about 6 times here during | ||
75 | * a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is | ||
76 | * handled without data error, but it should get done better. | ||
77 | * | ||
78 | * 0.5 Free CPU during waits (again with help from Kai Makisara). | ||
79 | * Made it work together with the LILO/kernel setup standard. | ||
80 | * Included auto-probing code, as suggested by YGGDRASIL. | ||
81 | * Formal redesign to add DDI debugging. | ||
82 | * There are still flaws in IOCTL (workman with double speed drive). | ||
83 | * | ||
84 | * 1.0 Added support for all drive IDs (0...3, no longer only 0) | ||
85 | * and up to 4 drives on one controller. | ||
86 | * Added "#define MANY_SESSION" for "old" multi session CDs. | ||
87 | * | ||
88 | * 1.1 Do SpinUp for new drives, too. | ||
89 | * Revised for clean compile under "old" kernels (0.99pl9). | ||
90 | * | ||
91 | * 1.2 Found the "workman with double-speed drive" bug: use the driver's | ||
92 | * audio_state, not what the drive is reporting with ReadSubQ. | ||
93 | * | ||
94 | * 1.3 Minor cleanups. | ||
95 | * Refinements regarding Workman. | ||
96 | * | ||
97 | * 1.4 Read XA disks (PhotoCDs) with "old" drives, too (but only the first | ||
98 | * session - no chance to fully access a "multi-session" CD). | ||
99 | * This currently still is too slow (50 kB/sec) - but possibly | ||
100 | * the old drives won't do it faster. | ||
101 | * Implemented "door (un)lock" for new drives (still does not work | ||
102 | * as wanted - no lock possible after an unlock). | ||
103 | * Added some debugging printout for the UPC/EAN code - but my drives | ||
104 | * return only zeroes. Is there no UPC/EAN code written? | ||
105 | * | ||
106 | * 1.5 Laborate with UPC/EAN code (not better yet). | ||
107 | * Adapt to kernel 1.1.8 change (have to explicitly include | ||
108 | * <linux/string.h> now). | ||
109 | * | ||
110 | * 1.6 Trying to read audio frames as data. Impossible with the current | ||
111 | * drive firmware levels, as it seems. Awaiting any hint. ;-) | ||
112 | * Changed "door unlock": repeat it until success. | ||
113 | * Changed CDROMSTOP routine (stop somewhat "softer" so that Workman | ||
114 | * won't get confused). | ||
115 | * Added a third interface type: Sequoia S-1000, as used with the SPEA | ||
116 | * Media FX sound card. This interface (usable for Sony and Mitsumi | ||
117 | * drives, too) needs a special configuration setup and behaves like a | ||
118 | * LaserMate type after that. Still experimental - I do not have such | ||
119 | * an interface. | ||
120 | * Use the "variable BLOCK_SIZE" feature (2048). But it does only work | ||
121 | * if you give the mount option "block=2048". | ||
122 | * The media_check routine is currently disabled; now that it gets | ||
123 | * called as it should I fear it must get synchronized for not to | ||
124 | * disturb the normal driver's activity. | ||
125 | * | ||
126 | * 2.0 Version number bumped - two reasons: | ||
127 | * - reading audio tracks as data works now with CR-562 and CR-563. We | ||
128 | * currently do it by an IOCTL (yet has to get standardized), one frame | ||
129 | * at a time; that is pretty slow. But it works. | ||
130 | * - we are maintaining now up to 4 interfaces (each up to 4 drives): | ||
131 | * did it the easy way - a different MAJOR (25, 26, ...) and a different | ||
132 | * copy of the driver (sbpcd.c, sbpcd2.c, sbpcd3.c, sbpcd4.c - only | ||
133 | * distinguished by the value of SBPCD_ISSUE and the driver's name), | ||
134 | * and a common sbpcd.h file. | ||
135 | * Bettered the "ReadCapacity error" problem with old CR-52x drives (the | ||
136 | * drives sometimes need a manual "eject/insert" before work): just | ||
137 | * reset the drive and do again. Needs lots of resets here and sometimes | ||
138 | * that does not cure, so this can't be the solution. | ||
139 | * | ||
140 | * 2.1 Found bug with multisession CDs (accessing frame 16). | ||
141 | * "read audio" works now with address type CDROM_MSF, too. | ||
142 | * Bigger audio frame buffer: allows reading max. 4 frames at time; this | ||
143 | * gives a significant speedup, but reading more than one frame at once | ||
144 | * gives missing chunks at each single frame boundary. | ||
145 | * | ||
146 | * 2.2 Kernel interface cleanups: timers, init, setup, media check. | ||
147 | * | ||
148 | * 2.3 Let "door lock" and "eject" live together. | ||
149 | * Implemented "close tray" (done automatically during open). | ||
150 | * | ||
151 | * 2.4 Use different names for device registering. | ||
152 | * | ||
153 | * 2.5 Added "#if EJECT" code (default: enabled) to automatically eject | ||
154 | * the tray during last call to "sbpcd_release". | ||
155 | * Added "#if JUKEBOX" code (default: disabled) to automatically eject | ||
156 | * the tray during call to "sbpcd_open" if no disk is in. | ||
157 | * Turn on the CD volume of "compatible" sound cards, too; just define | ||
158 | * SOUND_BASE (in sbpcd.h) accordingly (default: disabled). | ||
159 | * | ||
160 | * 2.6 Nothing new. | ||
161 | * | ||
162 | * 2.7 Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly: | ||
163 | * 0 disables, 1 enables auto-ejecting. Useful to keep the tray in | ||
164 | * during shutdown. | ||
165 | * | ||
166 | * 2.8 Added first support (still BETA, I need feedback or a drive) for | ||
167 | * the Longshine LCS-7260 drives. They appear as double-speed drives | ||
168 | * using the "old" command scheme, extended by tray control and door | ||
169 | * lock functions. | ||
170 | * Found (and fixed preliminary) a flaw with some multisession CDs: we | ||
171 | * have to re-direct not only the accesses to frame 16 (the isofs | ||
172 | * routines drive it up to max. 100), but also those to the continuation | ||
173 | * (repetition) frames (as far as they exist - currently set fix as | ||
174 | * 16..20). | ||
175 | * Changed default of the "JUKEBOX" define. If you use this default, | ||
176 | * your tray will eject if you try to mount without a disk in. Next | ||
177 | * mount command will insert the tray - so, just fill in a disk. ;-) | ||
178 | * | ||
179 | * 2.9 Fulfilled the Longshine LCS-7260 support; with great help and | ||
180 | * experiments by Serge Robyns. | ||
181 | * First attempts to support the TEAC CD-55A drives; but still not | ||
182 | * usable yet. | ||
183 | * Implemented the CDROMMULTISESSION ioctl; this is an attempt to handle | ||
184 | * multi session CDs more "transparent" (redirection handling has to be | ||
185 | * done within the isofs routines, and only for the special purpose of | ||
186 | * obtaining the "right" volume descriptor; accesses to the raw device | ||
187 | * should not get redirected). | ||
188 | * | ||
189 | * 3.0 Just a "normal" increment, with some provisions to do it better. ;-) | ||
190 | * Introduced "#define READ_AUDIO" to specify the maximum number of | ||
191 | * audio frames to grab with one request. This defines a buffer size | ||
192 | * within kernel space; a value of 0 will reserve no such space and | ||
193 | * disable the CDROMREADAUDIO ioctl. A value of 75 enables the reading | ||
194 | * of a whole second with one command, but will use a buffer of more | ||
195 | * than 172 kB. | ||
196 | * Started CD200 support. Drive detection should work, but nothing | ||
197 | * more. | ||
198 | * | ||
199 | * 3.1 Working to support the CD200 and the Teac CD-55A drives. | ||
200 | * AT-BUS style device numbering no longer used: use SCSI style now. | ||
201 | * So, the first "found" device has MINOR 0, regardless of the | ||
202 | * jumpered drive ID. This implies modifications to the /dev/sbpcd* | ||
203 | * entries for some people, but will help the DAU (german TLA, english: | ||
204 | * "newbie", maybe ;-) to install his "first" system from a CD. | ||
205 | * | ||
206 | * 3.2 Still testing with CD200 and CD-55A drives. | ||
207 | * | ||
208 | * 3.3 Working with CD200 support. | ||
209 | * | ||
210 | * 3.4 Auto-probing stops if an address of 0 is seen (to be entered with | ||
211 | * the kernel command line). | ||
212 | * Made the driver "loadable". If used as a module, "audio copy" is | ||
213 | * disabled, and the internal read ahead data buffer has a reduced size | ||
214 | * of 4 kB; so, throughput may be reduced a little bit with slow CPUs. | ||
215 | * | ||
216 | * 3.5 Provisions to handle weird photoCDs which have an interrupted | ||
217 | * "formatting" immediately after the last frames of some files: simply | ||
218 | * never "read ahead" with MultiSession CDs. By this, CPU usage may be | ||
219 | * increased with those CDs, and there may be a loss in speed. | ||
220 | * Re-structured the messaging system. | ||
221 | * The "loadable" version no longer has a limited READ_AUDIO buffer | ||
222 | * size. | ||
223 | * Removed "MANY_SESSION" handling for "old" multi session CDs. | ||
224 | * Added "private" IOCTLs CDROMRESET and CDROMVOLREAD. | ||
225 | * Started again to support the TEAC CD-55A drives, now that I found | ||
226 | * the money for "my own" drive. ;-) | ||
227 | * The TEAC CD-55A support is fairly working now. | ||
228 | * I have measured that the drive "delivers" at 600 kB/sec (even with | ||
229 | * bigger requests than the drive's 64 kB buffer can satisfy), but | ||
230 | * the "real" rate does not exceed 520 kB/sec at the moment. | ||
231 | * Caused by the various changes to build in TEAC support, the timed | ||
232 | * loops are de-optimized at the moment (less throughput with CR-52x | ||
233 | * drives, and the TEAC will give speed only with SBP_BUFFER_FRAMES 64). | ||
234 | * | ||
235 | * 3.6 Fixed TEAC data read problems with SbPro interfaces. | ||
236 | * Initial size of the READ_AUDIO buffer is 0. Can get set to any size | ||
237 | * during runtime. | ||
238 | * | ||
239 | * 3.7 Introduced MAX_DRIVES for some poor interface cards (seen with TEAC | ||
240 | * drives) which allow only one drive (ID 0); this avoids repetitive | ||
241 | * detection under IDs 1..3. | ||
242 | * Elongated cmd_out_T response waiting; necessary for photo CDs with | ||
243 | * a lot of sessions. | ||
244 | * Bettered the sbpcd_open() behavior with TEAC drives. | ||
245 | * | ||
246 | * 3.8 Elongated max_latency for CR-56x drives. | ||
247 | * | ||
248 | * 3.9 Finally fixed the long-known SoundScape/SPEA/Sequoia S-1000 interface | ||
249 | * configuration bug. | ||
250 | * Now Corey, Heiko, Ken, Leo, Vadim/Eric & Werner are invited to copy | ||
251 | * the config_spea() routine into their drivers. ;-) | ||
252 | * | ||
253 | * 4.0 No "big step" - normal version increment. | ||
254 | * Adapted the benefits from 1.3.33. | ||
255 | * Fiddled with CDROMREADAUDIO flaws. | ||
256 | * Avoid ReadCapacity command with CD200 drives (the MKE 1.01 version | ||
257 | * seems not to support it). | ||
258 | * Fulfilled "read audio" for CD200 drives, with help of Pete Heist | ||
259 | * (heistp@rpi.edu). | ||
260 | * | ||
261 | * 4.1 Use loglevel KERN_INFO with printk(). | ||
262 | * Added support for "Vertos 100" drive ("ECS-AT") - it is very similar | ||
263 | * to the Longshine LCS-7260. Give feedback if you can - I never saw | ||
264 | * such a drive, and I have no specs. | ||
265 | * | ||
266 | * 4.2 Support for Teac 16-bit interface cards. Can't get auto-detected, | ||
267 | * so you have to jumper your card to 0x2C0. Still not 100% - come | ||
268 | * in contact if you can give qualified feedback. | ||
269 | * Use loglevel KERN_NOTICE with printk(). If you get annoyed by a | ||
270 | * flood of unwanted messages and the accompanied delay, try to read | ||
271 | * my documentation. Especially the Linux CDROM drivers have to do an | ||
272 | * important job for the newcomers, so the "distributed" version has | ||
273 | * to fit some special needs. Since generations, the flood of messages | ||
274 | * is user-configurable (even at runtime), but to get aware of this, one | ||
275 | * needs a special mental quality: the ability to read. | ||
276 | * | ||
277 | * 4.3 CD200F does not like to receive a command while the drive is | ||
278 | * reading the ToC; still trying to solve it. | ||
279 | * Removed some redundant verify_area calls (yes, Heiko Eissfeldt | ||
280 | * is visiting all the Linux CDROM drivers ;-). | ||
281 | * | ||
282 | * 4.4 Adapted one idea from tiensivu@pilot.msu.edu's "stripping-down" | ||
283 | * experiments: "KLOGD_PAUSE". | ||
284 | * Inhibited "play audio" attempts with data CDs. Provisions for a | ||
285 | * "data-safe" handling of "mixed" (data plus audio) Cds. | ||
286 | * | ||
287 | * 4.5 Meanwhile Gonzalo Tornaria <tornaria@cmat.edu.uy> (GTL) built a | ||
288 | * special end_request routine: we seem to have to take care for not | ||
289 | * to have two processes working at the request list. My understanding | ||
290 | * was and is that ll_rw_blk should not call do_sbpcd_request as long | ||
291 | * as there is still one call active (the first call will care for all | ||
292 | * outstanding I/Os, and if a second call happens, that is a bug in | ||
293 | * ll_rw_blk.c). | ||
294 | * "Check media change" without touching any drive. | ||
295 | * | ||
296 | * 4.6 Use a semaphore to synchronize multi-activity; elaborated by Rob | ||
297 | * Riggs <rriggs@tesser.com>. At the moment, we simply block "read" | ||
298 | * against "ioctl" and vice versa. This could be refined further, but | ||
299 | * I guess with almost no performance increase. | ||
300 | * Experiments to speed up the CD-55A; again with help of Rob Riggs | ||
301 | * (to be true, he gave both, idea & code. ;-) | ||
302 | * | ||
303 | * 4.61 Ported to Uniform CD-ROM driver by | ||
304 | * Heiko Eissfeldt <heiko@colossus.escape.de> with additional | ||
305 | * changes by Erik Andersen <andersee@debian.org> | ||
306 | * | ||
307 | * 4.62 Fix a bug where playing audio left the drive in an unusable state. | ||
308 | * Heiko Eissfeldt <heiko@colossus.escape.de> | ||
309 | * | ||
310 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
311 | * Removed init_module & cleanup_module in favor of | ||
312 | * module_init & module_exit. | ||
313 | * Torben Mathiasen <tmm@image.dk> | ||
314 | * | ||
315 | * 4.63 Bug fixes for audio annoyances, new legacy CDROM maintainer. | ||
316 | * Annoying things fixed: | ||
317 | * TOC reread on automated disk changes | ||
318 | * TOC reread on manual cd changes | ||
319 | * Play IOCTL tries to play CD before it's actually ready... sometimes. | ||
320 | * CD_AUDIO_COMPLETED state so workman (and other playes) can repeat play. | ||
321 | * Andrew J. Kroll <ag784@freenet.buffalo.edu> Wed Jul 26 04:24:10 EDT 2000 | ||
322 | * | ||
323 | * 4.64 Fix module parameters - were being completely ignored. | ||
324 | * Can also specify max_drives=N as a setup int to get rid of | ||
325 | * "ghost" drives on crap hardware (aren't they all?) Paul Gortmaker | ||
326 | * | ||
327 | * TODO | ||
328 | * implement "read all subchannel data" (96 bytes per frame) | ||
329 | * remove alot of the virtual status bits and deal with hardware status | ||
330 | * move the change of cd for audio to a better place | ||
331 | * add debug levels to insmod parameters (trivial) | ||
332 | * | ||
333 | * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine | ||
334 | * elaborated speed-up experiments (and the fabulous results!), for | ||
335 | * the "push" towards load-free wait loops, and for the extensive mail | ||
336 | * thread which brought additional hints and bug fixes. | ||
337 | * | ||
338 | */ | ||
339 | |||
340 | /* | ||
341 | * Trying to merge requests breaks this driver horribly (as in it goes | ||
342 | * boom and apparently has done so since 2.3.41). As it is a legacy | ||
343 | * driver for a horribly slow double speed CD on a hideous interface | ||
344 | * designed for polled operation, I won't lose any sleep in simply | ||
345 | * disallowing merging. Paul G. 02/2001 | ||
346 | * | ||
347 | * Thu May 30 14:14:47 CEST 2002: | ||
348 | * | ||
349 | * I have presumably found the reson for the above - there was a bogous | ||
350 | * end_request substitute, which was manipulating the request queues | ||
351 | * incorrectly. If someone has access to the actual hardware, and it's | ||
352 | * still operations - well please free to test it. | ||
353 | * | ||
354 | * Marcin Dalecki | ||
355 | */ | ||
356 | |||
357 | /* | ||
358 | * Add bio/kdev_t changes for 2.5.x required to make it work again. | ||
359 | * Still room for improvement in the request handling here if anyone | ||
360 | * actually cares. Bring your own chainsaw. Paul G. 02/2002 | ||
361 | */ | ||
362 | |||
363 | |||
364 | #include <linux/module.h> | ||
365 | |||
366 | #include <linux/errno.h> | ||
367 | #include <linux/sched.h> | ||
368 | #include <linux/mm.h> | ||
369 | #include <linux/timer.h> | ||
370 | #include <linux/fs.h> | ||
371 | #include <linux/kernel.h> | ||
372 | #include <linux/cdrom.h> | ||
373 | #include <linux/ioport.h> | ||
374 | #include <linux/major.h> | ||
375 | #include <linux/string.h> | ||
376 | #include <linux/vmalloc.h> | ||
377 | #include <linux/init.h> | ||
378 | #include <linux/interrupt.h> | ||
379 | |||
380 | #include <asm/system.h> | ||
381 | #include <asm/io.h> | ||
382 | #include <asm/uaccess.h> | ||
383 | #include <stdarg.h> | ||
384 | #include "sbpcd.h" | ||
385 | |||
386 | #define MAJOR_NR MATSUSHITA_CDROM_MAJOR | ||
387 | #include <linux/blkdev.h> | ||
388 | |||
389 | /*==========================================================================*/ | ||
390 | #if SBPCD_DIS_IRQ | ||
391 | # define SBPCD_CLI cli() | ||
392 | # define SBPCD_STI sti() | ||
393 | #else | ||
394 | # define SBPCD_CLI | ||
395 | # define SBPCD_STI | ||
396 | #endif | ||
397 | |||
398 | /*==========================================================================*/ | ||
399 | /* | ||
400 | * auto-probing address list | ||
401 | * inspired by Adam J. Richter from Yggdrasil | ||
402 | * | ||
403 | * still not good enough - can cause a hang. | ||
404 | * example: a NE 2000 ethernet card at 300 will cause a hang probing 310. | ||
405 | * if that happens, reboot and use the LILO (kernel) command line. | ||
406 | * The possibly conflicting ethernet card addresses get NOT probed | ||
407 | * by default - to minimize the hang possibilities. | ||
408 | * | ||
409 | * The SB Pro addresses get "mirrored" at 0x6xx and some more locations - to | ||
410 | * avoid a type error, the 0x2xx-addresses must get checked before 0x6xx. | ||
411 | * | ||
412 | * send mail to emoenke@gwdg.de if your interface card is not FULLY | ||
413 | * represented here. | ||
414 | */ | ||
415 | static int sbpcd[] = | ||
416 | { | ||
417 | CDROM_PORT, SBPRO, /* probe with user's setup first */ | ||
418 | #if DISTRIBUTION | ||
419 | 0x230, 1, /* Soundblaster Pro and 16 (default) */ | ||
420 | #if 0 | ||
421 | 0x300, 0, /* CI-101P (default), WDH-7001C (default), | ||
422 | Galaxy (default), Reveal (one default) */ | ||
423 | 0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */ | ||
424 | 0x2C0, 3, /* Teac 16-bit cards */ | ||
425 | 0x260, 1, /* OmniCD */ | ||
426 | 0x320, 0, /* Lasermate, CI-101P, WDH-7001C, Galaxy, Reveal (other default), | ||
427 | Longshine LCS-6853 (default) */ | ||
428 | 0x338, 0, /* Reveal Sound Wave 32 card model #SC600 */ | ||
429 | 0x340, 0, /* Mozart sound card (default), Lasermate, CI-101P */ | ||
430 | 0x360, 0, /* Lasermate, CI-101P */ | ||
431 | 0x270, 1, /* Soundblaster 16 */ | ||
432 | 0x670, 0, /* "sound card #9" */ | ||
433 | 0x690, 0, /* "sound card #9" */ | ||
434 | 0x338, 2, /* SPEA Media FX, Ensonic SoundScape (default) */ | ||
435 | 0x328, 2, /* SPEA Media FX */ | ||
436 | 0x348, 2, /* SPEA Media FX */ | ||
437 | 0x634, 0, /* some newer sound cards */ | ||
438 | 0x638, 0, /* some newer sound cards */ | ||
439 | 0x230, 1, /* some newer sound cards */ | ||
440 | /* due to incomplete address decoding of the SbPro card, these must be last */ | ||
441 | 0x630, 0, /* "sound card #9" (default) */ | ||
442 | 0x650, 0, /* "sound card #9" */ | ||
443 | #ifdef MODULE | ||
444 | /* | ||
445 | * some "hazardous" locations (no harm with the loadable version) | ||
446 | * (will stop the bus if a NE2000 ethernet card resides at offset -0x10) | ||
447 | */ | ||
448 | 0x330, 0, /* Lasermate, CI-101P, WDH-7001C */ | ||
449 | 0x350, 0, /* Lasermate, CI-101P */ | ||
450 | 0x358, 2, /* SPEA Media FX */ | ||
451 | 0x370, 0, /* Lasermate, CI-101P */ | ||
452 | 0x290, 1, /* Soundblaster 16 */ | ||
453 | 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ | ||
454 | #endif /* MODULE */ | ||
455 | #endif | ||
456 | #endif /* DISTRIBUTION */ | ||
457 | }; | ||
458 | |||
459 | /* | ||
460 | * Protects access to global structures etc. | ||
461 | */ | ||
462 | static __cacheline_aligned DEFINE_SPINLOCK(sbpcd_lock); | ||
463 | static struct request_queue *sbpcd_queue; | ||
464 | |||
465 | /* You can only set the first pair, from old MODULE_PARM code. */ | ||
466 | static int sbpcd_set(const char *val, struct kernel_param *kp) | ||
467 | { | ||
468 | get_options((char *)val, 2, (int *)sbpcd); | ||
469 | return 0; | ||
470 | } | ||
471 | module_param_call(sbpcd, sbpcd_set, NULL, NULL, 0); | ||
472 | |||
473 | #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) | ||
474 | |||
475 | /*==========================================================================*/ | ||
476 | |||
477 | #define INLINE inline | ||
478 | |||
479 | /*==========================================================================*/ | ||
480 | /* | ||
481 | * the forward references: | ||
482 | */ | ||
483 | static void sbp_sleep(u_int); | ||
484 | static void mark_timeout_delay(u_long); | ||
485 | static void mark_timeout_data(u_long); | ||
486 | #if 0 | ||
487 | static void mark_timeout_audio(u_long); | ||
488 | #endif | ||
489 | static void sbp_read_cmd(struct request *req); | ||
490 | static int sbp_data(struct request *req); | ||
491 | static int cmd_out(void); | ||
492 | static int DiskInfo(void); | ||
493 | |||
494 | /*==========================================================================*/ | ||
495 | |||
496 | /* | ||
497 | * pattern for printk selection: | ||
498 | * | ||
499 | * (1<<DBG_INF) necessary information | ||
500 | * (1<<DBG_BSZ) BLOCK_SIZE trace | ||
501 | * (1<<DBG_REA) "read" status trace | ||
502 | * (1<<DBG_CHK) "media check" trace | ||
503 | * (1<<DBG_TIM) datarate timer test | ||
504 | * (1<<DBG_INI) initialization trace | ||
505 | * (1<<DBG_TOC) tell TocEntry values | ||
506 | * (1<<DBG_IOC) ioctl trace | ||
507 | * (1<<DBG_STA) "ResponseStatus" trace | ||
508 | * (1<<DBG_ERR) "cc_ReadError" trace | ||
509 | * (1<<DBG_CMD) "cmd_out" trace | ||
510 | * (1<<DBG_WRN) give explanation before auto-probing | ||
511 | * (1<<DBG_MUL) multi session code test | ||
512 | * (1<<DBG_IDX) "drive_id != 0" test code | ||
513 | * (1<<DBG_IOX) some special information | ||
514 | * (1<<DBG_DID) drive ID test | ||
515 | * (1<<DBG_RES) drive reset info | ||
516 | * (1<<DBG_SPI) SpinUp test info | ||
517 | * (1<<DBG_IOS) ioctl trace: "subchannel" | ||
518 | * (1<<DBG_IO2) ioctl trace: general | ||
519 | * (1<<DBG_UPC) show UPC info | ||
520 | * (1<<DBG_XA1) XA mode debugging | ||
521 | * (1<<DBG_LCK) door (un)lock info | ||
522 | * (1<<DBG_SQ1) dump SubQ frame | ||
523 | * (1<<DBG_AUD) "read audio" debugging | ||
524 | * (1<<DBG_SEQ) Sequoia interface configuration trace | ||
525 | * (1<<DBG_LCS) Longshine LCS-7260 debugging trace | ||
526 | * (1<<DBG_CD2) MKE/Funai CD200 debugging trace | ||
527 | * (1<<DBG_TEA) TEAC CD-55A debugging trace | ||
528 | * (1<<DBG_ECS) ECS-AT (Vertos-100) debugging trace | ||
529 | * (1<<DBG_000) unnecessary information | ||
530 | */ | ||
531 | #if DISTRIBUTION | ||
532 | static int sbpcd_debug = (1<<DBG_INF); | ||
533 | #else | ||
534 | static int sbpcd_debug = 0 & ((1<<DBG_INF) | | ||
535 | (1<<DBG_TOC) | | ||
536 | (1<<DBG_MUL) | | ||
537 | (1<<DBG_UPC)); | ||
538 | #endif /* DISTRIBUTION */ | ||
539 | |||
540 | static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */ | ||
541 | static int sbpro_type = SBPRO; | ||
542 | static unsigned char f_16bit; | ||
543 | static unsigned char do_16bit; | ||
544 | static int CDo_command, CDo_reset; | ||
545 | static int CDo_sel_i_d, CDo_enable; | ||
546 | static int CDi_info, CDi_status, CDi_data; | ||
547 | static struct cdrom_msf msf; | ||
548 | static struct cdrom_ti ti; | ||
549 | static struct cdrom_tochdr tochdr; | ||
550 | static struct cdrom_tocentry tocentry; | ||
551 | static struct cdrom_subchnl SC; | ||
552 | static struct cdrom_volctrl volctrl; | ||
553 | static struct cdrom_read_audio read_audio; | ||
554 | |||
555 | static unsigned char msgnum; | ||
556 | static char msgbuf[80]; | ||
557 | |||
558 | static int max_drives = MAX_DRIVES; | ||
559 | module_param(max_drives, int, 0); | ||
560 | #ifndef MODULE | ||
561 | static unsigned char setup_done; | ||
562 | static const char *str_sb_l = "soundblaster"; | ||
563 | static const char *str_sp_l = "spea"; | ||
564 | static const char *str_ss_l = "soundscape"; | ||
565 | static const char *str_t16_l = "teac16bit"; | ||
566 | static const char *str_ss = "SoundScape"; | ||
567 | #endif | ||
568 | static const char *str_sb = "SoundBlaster"; | ||
569 | static const char *str_lm = "LaserMate"; | ||
570 | static const char *str_sp = "SPEA"; | ||
571 | static const char *str_t16 = "Teac16bit"; | ||
572 | static const char *type; | ||
573 | static const char *major_name="sbpcd"; | ||
574 | |||
575 | /*==========================================================================*/ | ||
576 | |||
577 | #ifdef FUTURE | ||
578 | static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq); | ||
579 | #endif /* FUTURE */ | ||
580 | |||
581 | static int teac=SBP_TEAC_SPEED; | ||
582 | static int buffers=SBP_BUFFER_FRAMES; | ||
583 | |||
584 | static u_char family0[]="MATSHITA"; /* MKE CR-521, CR-522, CR-523 */ | ||
585 | static u_char family1[]="CR-56"; /* MKE CR-562, CR-563 */ | ||
586 | static u_char family2[]="CD200"; /* MKE CD200, Funai CD200F */ | ||
587 | static u_char familyL[]="LCS-7260"; /* Longshine LCS-7260 */ | ||
588 | static u_char familyT[]="CD-55"; /* TEAC CD-55A */ | ||
589 | static u_char familyV[]="ECS-AT"; /* ECS Vertos 100 */ | ||
590 | |||
591 | static u_int recursion; /* internal testing only */ | ||
592 | static u_int fatal_err; /* internal testing only */ | ||
593 | static u_int response_count; | ||
594 | static u_int flags_cmd_out; | ||
595 | static u_char cmd_type; | ||
596 | static u_char drvcmd[10]; | ||
597 | static u_char infobuf[20]; | ||
598 | static u_char xa_head_buf[CD_XA_HEAD]; | ||
599 | static u_char xa_tail_buf[CD_XA_TAIL]; | ||
600 | |||
601 | #if OLD_BUSY | ||
602 | static volatile u_char busy_data; | ||
603 | static volatile u_char busy_audio; /* true semaphores would be safer */ | ||
604 | #endif /* OLD_BUSY */ | ||
605 | static DECLARE_MUTEX(ioctl_read_sem); | ||
606 | static u_long timeout; | ||
607 | static volatile u_char timed_out_delay; | ||
608 | static volatile u_char timed_out_data; | ||
609 | #if 0 | ||
610 | static volatile u_char timed_out_audio; | ||
611 | #endif | ||
612 | static u_int datarate= 1000000; | ||
613 | static u_int maxtim16=16000000; | ||
614 | static u_int maxtim04= 4000000; | ||
615 | static u_int maxtim02= 2000000; | ||
616 | static u_int maxtim_8= 30000; | ||
617 | #if LONG_TIMING | ||
618 | static u_int maxtim_data= 9000; | ||
619 | #else | ||
620 | static u_int maxtim_data= 3000; | ||
621 | #endif /* LONG_TIMING */ | ||
622 | #if DISTRIBUTION | ||
623 | static int n_retries=6; | ||
624 | #else | ||
625 | static int n_retries=6; | ||
626 | #endif | ||
627 | /*==========================================================================*/ | ||
628 | |||
629 | static int ndrives; | ||
630 | static u_char drv_pattern[NR_SBPCD]={speed_auto,speed_auto,speed_auto,speed_auto}; | ||
631 | |||
632 | /*==========================================================================*/ | ||
633 | /* | ||
634 | * drive space begins here (needed separate for each unit) | ||
635 | */ | ||
636 | static struct sbpcd_drive { | ||
637 | char drv_id; /* "jumpered" drive ID or -1 */ | ||
638 | char drv_sel; /* drive select lines bits */ | ||
639 | |||
640 | char drive_model[9]; | ||
641 | u_char firmware_version[4]; | ||
642 | char f_eject; /* auto-eject flag: 0 or 1 */ | ||
643 | u_char *sbp_buf; /* Pointer to internal data buffer, | ||
644 | space allocated during sbpcd_init() */ | ||
645 | u_int sbp_bufsiz; /* size of sbp_buf (# of frames) */ | ||
646 | int sbp_first_frame; /* First frame in buffer */ | ||
647 | int sbp_last_frame; /* Last frame in buffer */ | ||
648 | int sbp_read_frames; /* Number of frames being read to buffer */ | ||
649 | int sbp_current; /* Frame being currently read */ | ||
650 | |||
651 | u_char mode; /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */ | ||
652 | u_char *aud_buf; /* Pointer to audio data buffer, | ||
653 | space allocated during sbpcd_init() */ | ||
654 | u_int sbp_audsiz; /* size of aud_buf (# of raw frames) */ | ||
655 | u_int drv_type; | ||
656 | u_char drv_options; | ||
657 | int status_bits; | ||
658 | u_char diskstate_flags; | ||
659 | u_char sense_byte; | ||
660 | |||
661 | u_char CD_changed; | ||
662 | char open_count; | ||
663 | u_char error_byte; | ||
664 | |||
665 | u_char f_multisession; | ||
666 | u_int lba_multi; | ||
667 | int first_session; | ||
668 | int last_session; | ||
669 | int track_of_last_session; | ||
670 | |||
671 | u_char audio_state; | ||
672 | u_int pos_audio_start; | ||
673 | u_int pos_audio_end; | ||
674 | char vol_chan0; | ||
675 | u_char vol_ctrl0; | ||
676 | char vol_chan1; | ||
677 | u_char vol_ctrl1; | ||
678 | #if 000 /* no supported drive has it */ | ||
679 | char vol_chan2; | ||
680 | u_char vol_ctrl2; | ||
681 | char vol_chan3; | ||
682 | u_char vol_ctrl3; | ||
683 | #endif /*000 */ | ||
684 | u_char volume_control; /* TEAC on/off bits */ | ||
685 | |||
686 | u_char SubQ_ctl_adr; | ||
687 | u_char SubQ_trk; | ||
688 | u_char SubQ_pnt_idx; | ||
689 | u_int SubQ_run_tot; | ||
690 | u_int SubQ_run_trk; | ||
691 | u_char SubQ_whatisthis; | ||
692 | |||
693 | u_char UPC_ctl_adr; | ||
694 | u_char UPC_buf[7]; | ||
695 | |||
696 | int frame_size; | ||
697 | int CDsize_frm; | ||
698 | |||
699 | u_char xa_byte; /* 0x20: XA capabilities */ | ||
700 | u_char n_first_track; /* binary */ | ||
701 | u_char n_last_track; /* binary (not bcd), 0x01...0x63 */ | ||
702 | u_int size_msf; /* time of whole CD, position of LeadOut track */ | ||
703 | u_int size_blk; | ||
704 | |||
705 | u_char TocEnt_nixbyte; /* em */ | ||
706 | u_char TocEnt_ctl_adr; | ||
707 | u_char TocEnt_number; | ||
708 | u_char TocEnt_format; /* em */ | ||
709 | u_int TocEnt_address; | ||
710 | #ifdef SAFE_MIXED | ||
711 | char has_data; | ||
712 | #endif /* SAFE_MIXED */ | ||
713 | u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */ | ||
714 | |||
715 | struct { | ||
716 | u_char nixbyte; /* em */ | ||
717 | u_char ctl_adr; /* 0x4x: data, 0x0x: audio */ | ||
718 | u_char number; | ||
719 | u_char format; /* em */ /* 0x00: lba, 0x01: msf */ | ||
720 | u_int address; | ||
721 | } TocBuffer[MAX_TRACKS+1]; /* last entry faked */ | ||
722 | |||
723 | int in_SpinUp; /* CR-52x test flag */ | ||
724 | int n_bytes; /* TEAC awaited response count */ | ||
725 | u_char error_state, b3, b4; /* TEAC command error state */ | ||
726 | u_char f_drv_error; /* TEAC command error flag */ | ||
727 | u_char speed_byte; | ||
728 | int frmsiz; | ||
729 | u_char f_XA; /* 1: XA */ | ||
730 | u_char type_byte; /* 0, 1, 3 */ | ||
731 | u_char mode_xb_6; | ||
732 | u_char mode_yb_7; | ||
733 | u_char mode_xb_8; | ||
734 | u_char delay; | ||
735 | struct cdrom_device_info *sbpcd_infop; | ||
736 | struct gendisk *disk; | ||
737 | } D_S[NR_SBPCD]; | ||
738 | |||
739 | static struct sbpcd_drive *current_drive = D_S; | ||
740 | |||
741 | /* | ||
742 | * drive space ends here (needed separate for each unit) | ||
743 | */ | ||
744 | /*==========================================================================*/ | ||
745 | #if 0 | ||
746 | unsigned long cli_sti; /* for saving the processor flags */ | ||
747 | #endif | ||
748 | /*==========================================================================*/ | ||
749 | static DEFINE_TIMER(delay_timer, mark_timeout_delay, 0, 0); | ||
750 | static DEFINE_TIMER(data_timer, mark_timeout_data, 0, 0); | ||
751 | #if 0 | ||
752 | static DEFINE_TIMER(audio_timer, mark_timeout_audio, 0, 0); | ||
753 | #endif | ||
754 | /*==========================================================================*/ | ||
755 | /* | ||
756 | * DDI interface | ||
757 | */ | ||
758 | static void msg(int level, const char *fmt, ...) | ||
759 | { | ||
760 | #if DISTRIBUTION | ||
761 | #define MSG_LEVEL KERN_NOTICE | ||
762 | #else | ||
763 | #define MSG_LEVEL KERN_INFO | ||
764 | #endif /* DISTRIBUTION */ | ||
765 | |||
766 | char buf[256]; | ||
767 | va_list args; | ||
768 | |||
769 | if (!(sbpcd_debug&(1<<level))) return; | ||
770 | |||
771 | msgnum++; | ||
772 | if (msgnum>99) msgnum=0; | ||
773 | va_start(args, fmt); | ||
774 | vsnprintf(buf, sizeof(buf), fmt, args); | ||
775 | va_end(args); | ||
776 | printk(MSG_LEVEL "%s-%d [%02d]: %s", major_name, current_drive - D_S, msgnum, buf); | ||
777 | #if KLOGD_PAUSE | ||
778 | sbp_sleep(KLOGD_PAUSE); /* else messages get lost */ | ||
779 | #endif /* KLOGD_PAUSE */ | ||
780 | return; | ||
781 | } | ||
782 | /*==========================================================================*/ | ||
783 | /* | ||
784 | * DDI interface: runtime trace bit pattern maintenance | ||
785 | */ | ||
786 | static int sbpcd_dbg_ioctl(unsigned long arg, int level) | ||
787 | { | ||
788 | switch(arg) | ||
789 | { | ||
790 | case 0: /* OFF */ | ||
791 | sbpcd_debug = DBG_INF; | ||
792 | break; | ||
793 | |||
794 | default: | ||
795 | if (arg>=128) sbpcd_debug &= ~(1<<(arg-128)); | ||
796 | else sbpcd_debug |= (1<<arg); | ||
797 | } | ||
798 | return (arg); | ||
799 | } | ||
800 | /*==========================================================================*/ | ||
801 | static void mark_timeout_delay(u_long i) | ||
802 | { | ||
803 | timed_out_delay=1; | ||
804 | #if 0 | ||
805 | msg(DBG_TIM,"delay timer expired.\n"); | ||
806 | #endif | ||
807 | } | ||
808 | /*==========================================================================*/ | ||
809 | static void mark_timeout_data(u_long i) | ||
810 | { | ||
811 | timed_out_data=1; | ||
812 | #if 0 | ||
813 | msg(DBG_TIM,"data timer expired.\n"); | ||
814 | #endif | ||
815 | } | ||
816 | /*==========================================================================*/ | ||
817 | #if 0 | ||
818 | static void mark_timeout_audio(u_long i) | ||
819 | { | ||
820 | timed_out_audio=1; | ||
821 | #if 0 | ||
822 | msg(DBG_TIM,"audio timer expired.\n"); | ||
823 | #endif | ||
824 | } | ||
825 | #endif | ||
826 | /*==========================================================================*/ | ||
827 | /* | ||
828 | * Wait a little while (used for polling the drive). | ||
829 | */ | ||
830 | static void sbp_sleep(u_int time) | ||
831 | { | ||
832 | sti(); | ||
833 | schedule_timeout_interruptible(time); | ||
834 | sti(); | ||
835 | } | ||
836 | /*==========================================================================*/ | ||
837 | #define RETURN_UP(rc) {up(&ioctl_read_sem); return(rc);} | ||
838 | /*==========================================================================*/ | ||
839 | /* | ||
840 | * convert logical_block_address to m-s-f_number (3 bytes only) | ||
841 | */ | ||
842 | static INLINE void lba2msf(int lba, u_char *msf) | ||
843 | { | ||
844 | lba += CD_MSF_OFFSET; | ||
845 | msf[0] = lba / (CD_SECS*CD_FRAMES); | ||
846 | lba %= CD_SECS*CD_FRAMES; | ||
847 | msf[1] = lba / CD_FRAMES; | ||
848 | msf[2] = lba % CD_FRAMES; | ||
849 | } | ||
850 | /*==========================================================================*/ | ||
851 | /*==========================================================================*/ | ||
852 | /* | ||
853 | * convert msf-bin to msf-bcd | ||
854 | */ | ||
855 | static INLINE void bin2bcdx(u_char *p) /* must work only up to 75 or 99 */ | ||
856 | { | ||
857 | *p=((*p/10)<<4)|(*p%10); | ||
858 | } | ||
859 | /*==========================================================================*/ | ||
860 | static INLINE u_int blk2msf(u_int blk) | ||
861 | { | ||
862 | MSF msf; | ||
863 | u_int mm; | ||
864 | |||
865 | msf.c[3] = 0; | ||
866 | msf.c[2] = (blk + CD_MSF_OFFSET) / (CD_SECS * CD_FRAMES); | ||
867 | mm = (blk + CD_MSF_OFFSET) % (CD_SECS * CD_FRAMES); | ||
868 | msf.c[1] = mm / CD_FRAMES; | ||
869 | msf.c[0] = mm % CD_FRAMES; | ||
870 | return (msf.n); | ||
871 | } | ||
872 | /*==========================================================================*/ | ||
873 | static INLINE u_int make16(u_char rh, u_char rl) | ||
874 | { | ||
875 | return ((rh<<8)|rl); | ||
876 | } | ||
877 | /*==========================================================================*/ | ||
878 | static INLINE u_int make32(u_int rh, u_int rl) | ||
879 | { | ||
880 | return ((rh<<16)|rl); | ||
881 | } | ||
882 | /*==========================================================================*/ | ||
883 | static INLINE u_char swap_nibbles(u_char i) | ||
884 | { | ||
885 | return ((i<<4)|(i>>4)); | ||
886 | } | ||
887 | /*==========================================================================*/ | ||
888 | static INLINE u_char byt2bcd(u_char i) | ||
889 | { | ||
890 | return (((i/10)<<4)+i%10); | ||
891 | } | ||
892 | /*==========================================================================*/ | ||
893 | static INLINE u_char bcd2bin(u_char bcd) | ||
894 | { | ||
895 | return ((bcd>>4)*10+(bcd&0x0F)); | ||
896 | } | ||
897 | /*==========================================================================*/ | ||
898 | static INLINE int msf2blk(int msfx) | ||
899 | { | ||
900 | MSF msf; | ||
901 | int i; | ||
902 | |||
903 | msf.n=msfx; | ||
904 | i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_MSF_OFFSET; | ||
905 | if (i<0) return (0); | ||
906 | return (i); | ||
907 | } | ||
908 | /*==========================================================================*/ | ||
909 | /* | ||
910 | * convert m-s-f_number (3 bytes only) to logical_block_address | ||
911 | */ | ||
912 | static INLINE int msf2lba(u_char *msf) | ||
913 | { | ||
914 | int i; | ||
915 | |||
916 | i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_MSF_OFFSET; | ||
917 | if (i<0) return (0); | ||
918 | return (i); | ||
919 | } | ||
920 | /*==========================================================================*/ | ||
921 | /* evaluate cc_ReadError code */ | ||
922 | static int sta2err(int sta) | ||
923 | { | ||
924 | if (famT_drive) | ||
925 | { | ||
926 | if (sta==0x00) return (0); | ||
927 | if (sta==0x01) return (-604); /* CRC error */ | ||
928 | if (sta==0x02) return (-602); /* drive not ready */ | ||
929 | if (sta==0x03) return (-607); /* unknown media */ | ||
930 | if (sta==0x04) return (-612); /* general failure */ | ||
931 | if (sta==0x05) return (0); | ||
932 | if (sta==0x06) return (-ERR_DISKCHANGE); /* disk change */ | ||
933 | if (sta==0x0b) return (-612); /* general failure */ | ||
934 | if (sta==0xff) return (-612); /* general failure */ | ||
935 | return (0); | ||
936 | } | ||
937 | else | ||
938 | { | ||
939 | if (sta<=2) return (sta); | ||
940 | if (sta==0x05) return (-604); /* CRC error */ | ||
941 | if (sta==0x06) return (-606); /* seek error */ | ||
942 | if (sta==0x0d) return (-606); /* seek error */ | ||
943 | if (sta==0x0e) return (-603); /* unknown command */ | ||
944 | if (sta==0x14) return (-603); /* unknown command */ | ||
945 | if (sta==0x0c) return (-611); /* read fault */ | ||
946 | if (sta==0x0f) return (-611); /* read fault */ | ||
947 | if (sta==0x10) return (-611); /* read fault */ | ||
948 | if (sta>=0x16) return (-612); /* general failure */ | ||
949 | if (sta==0x11) return (-ERR_DISKCHANGE); /* disk change (LCS: removed) */ | ||
950 | if (famL_drive) | ||
951 | if (sta==0x12) return (-ERR_DISKCHANGE); /* disk change (inserted) */ | ||
952 | return (-602); /* drive not ready */ | ||
953 | } | ||
954 | } | ||
955 | /*==========================================================================*/ | ||
956 | static INLINE void clr_cmdbuf(void) | ||
957 | { | ||
958 | int i; | ||
959 | |||
960 | for (i=0;i<10;i++) drvcmd[i]=0; | ||
961 | cmd_type=0; | ||
962 | } | ||
963 | /*==========================================================================*/ | ||
964 | static void flush_status(void) | ||
965 | { | ||
966 | int i; | ||
967 | |||
968 | sbp_sleep(15*HZ/10); | ||
969 | for (i=maxtim_data;i!=0;i--) inb(CDi_status); | ||
970 | } | ||
971 | /*====================================================================*/ | ||
972 | /* | ||
973 | * CDi status loop for Teac CD-55A (Rob Riggs) | ||
974 | * | ||
975 | * This is needed because for some strange reason | ||
976 | * the CD-55A can take a real long time to give a | ||
977 | * status response. This seems to happen after we | ||
978 | * issue a READ command where a long seek is involved. | ||
979 | * | ||
980 | * I tried to ensure that we get max throughput with | ||
981 | * minimal busy waiting. We busy wait at first, then | ||
982 | * "switch gears" and start sleeping. We sleep for | ||
983 | * longer periods of time the longer we wait. | ||
984 | * | ||
985 | */ | ||
986 | static int CDi_stat_loop_T(void) | ||
987 | { | ||
988 | int i, gear=1; | ||
989 | u_long timeout_1, timeout_2, timeout_3, timeout_4; | ||
990 | |||
991 | timeout_1 = jiffies + HZ / 50; /* sbp_sleep(0) for a short period */ | ||
992 | timeout_2 = jiffies + HZ / 5; /* nap for no more than 200ms */ | ||
993 | timeout_3 = jiffies + 5 * HZ; /* sleep for up to 5s */ | ||
994 | timeout_4 = jiffies + 45 * HZ; /* long sleep for up to 45s. */ | ||
995 | do | ||
996 | { | ||
997 | i = inb(CDi_status); | ||
998 | if (!(i&s_not_data_ready)) return (i); | ||
999 | if (!(i&s_not_result_ready)) return (i); | ||
1000 | switch(gear) | ||
1001 | { | ||
1002 | case 4: | ||
1003 | sbp_sleep(HZ); | ||
1004 | if (time_after(jiffies, timeout_4)) gear++; | ||
1005 | msg(DBG_TEA, "CDi_stat_loop_T: long sleep active.\n"); | ||
1006 | break; | ||
1007 | case 3: | ||
1008 | sbp_sleep(HZ/10); | ||
1009 | if (time_after(jiffies, timeout_3)) gear++; | ||
1010 | break; | ||
1011 | case 2: | ||
1012 | sbp_sleep(HZ/100); | ||
1013 | if (time_after(jiffies, timeout_2)) gear++; | ||
1014 | break; | ||
1015 | case 1: | ||
1016 | sbp_sleep(0); | ||
1017 | if (time_after(jiffies, timeout_1)) gear++; | ||
1018 | } | ||
1019 | } while (gear < 5); | ||
1020 | return -1; | ||
1021 | } | ||
1022 | /*==========================================================================*/ | ||
1023 | static int CDi_stat_loop(void) | ||
1024 | { | ||
1025 | int i,j; | ||
1026 | |||
1027 | for(timeout = jiffies + 10*HZ, i=maxtim_data; time_before(jiffies, timeout); ) | ||
1028 | { | ||
1029 | for ( ;i!=0;i--) | ||
1030 | { | ||
1031 | j=inb(CDi_status); | ||
1032 | if (!(j&s_not_data_ready)) return (j); | ||
1033 | if (!(j&s_not_result_ready)) return (j); | ||
1034 | if (fam0L_drive) if (j&s_attention) return (j); | ||
1035 | } | ||
1036 | sbp_sleep(1); | ||
1037 | i = 1; | ||
1038 | } | ||
1039 | msg(DBG_LCS,"CDi_stat_loop failed in line %d\n", __LINE__); | ||
1040 | return (-1); | ||
1041 | } | ||
1042 | /*==========================================================================*/ | ||
1043 | #if 00000 | ||
1044 | /*==========================================================================*/ | ||
1045 | static int tst_DataReady(void) | ||
1046 | { | ||
1047 | int i; | ||
1048 | |||
1049 | i=inb(CDi_status); | ||
1050 | if (i&s_not_data_ready) return (0); | ||
1051 | return (1); | ||
1052 | } | ||
1053 | /*==========================================================================*/ | ||
1054 | static int tst_ResultReady(void) | ||
1055 | { | ||
1056 | int i; | ||
1057 | |||
1058 | i=inb(CDi_status); | ||
1059 | if (i&s_not_result_ready) return (0); | ||
1060 | return (1); | ||
1061 | } | ||
1062 | /*==========================================================================*/ | ||
1063 | static int tst_Attention(void) | ||
1064 | { | ||
1065 | int i; | ||
1066 | |||
1067 | i=inb(CDi_status); | ||
1068 | if (i&s_attention) return (1); | ||
1069 | return (0); | ||
1070 | } | ||
1071 | /*==========================================================================*/ | ||
1072 | #endif | ||
1073 | /*==========================================================================*/ | ||
1074 | static int ResponseInfo(void) | ||
1075 | { | ||
1076 | int i,j,st=0; | ||
1077 | u_long timeout; | ||
1078 | |||
1079 | for (i=0,timeout=jiffies+HZ;i<response_count;i++) | ||
1080 | { | ||
1081 | for (j=maxtim_data; ; ) | ||
1082 | { | ||
1083 | for ( ;j!=0;j-- ) | ||
1084 | { | ||
1085 | st=inb(CDi_status); | ||
1086 | if (!(st&s_not_result_ready)) break; | ||
1087 | } | ||
1088 | if ((j!=0)||time_after_eq(jiffies, timeout)) break; | ||
1089 | sbp_sleep(1); | ||
1090 | j = 1; | ||
1091 | } | ||
1092 | if (time_after_eq(jiffies, timeout)) break; | ||
1093 | infobuf[i]=inb(CDi_info); | ||
1094 | } | ||
1095 | #if 000 | ||
1096 | while (!(inb(CDi_status)&s_not_result_ready)) | ||
1097 | { | ||
1098 | infobuf[i++]=inb(CDi_info); | ||
1099 | } | ||
1100 | j=i-response_count; | ||
1101 | if (j>0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j); | ||
1102 | #endif /* 000 */ | ||
1103 | for (j=0;j<i;j++) | ||
1104 | sprintf(&msgbuf[j*3]," %02X",infobuf[j]); | ||
1105 | msgbuf[j*3]=0; | ||
1106 | msg(DBG_CMD,"ResponseInfo:%s (%d,%d)\n",msgbuf,response_count,i); | ||
1107 | j=response_count-i; | ||
1108 | if (j>0) return (-j); | ||
1109 | else return (i); | ||
1110 | } | ||
1111 | /*==========================================================================*/ | ||
1112 | static void EvaluateStatus(int st) | ||
1113 | { | ||
1114 | current_drive->status_bits=0; | ||
1115 | if (fam1_drive) current_drive->status_bits=st|p_success; | ||
1116 | else if (fam0_drive) | ||
1117 | { | ||
1118 | if (st&p_caddin_old) current_drive->status_bits |= p_door_closed|p_caddy_in; | ||
1119 | if (st&p_spinning) current_drive->status_bits |= p_spinning; | ||
1120 | if (st&p_check) current_drive->status_bits |= p_check; | ||
1121 | if (st&p_success_old) current_drive->status_bits |= p_success; | ||
1122 | if (st&p_busy_old) current_drive->status_bits |= p_busy_new; | ||
1123 | if (st&p_disk_ok) current_drive->status_bits |= p_disk_ok; | ||
1124 | } | ||
1125 | else if (famLV_drive) | ||
1126 | { | ||
1127 | current_drive->status_bits |= p_success; | ||
1128 | if (st&p_caddin_old) current_drive->status_bits |= p_disk_ok|p_caddy_in; | ||
1129 | if (st&p_spinning) current_drive->status_bits |= p_spinning; | ||
1130 | if (st&p_check) current_drive->status_bits |= p_check; | ||
1131 | if (st&p_busy_old) current_drive->status_bits |= p_busy_new; | ||
1132 | if (st&p_lcs_door_closed) current_drive->status_bits |= p_door_closed; | ||
1133 | if (st&p_lcs_door_locked) current_drive->status_bits |= p_door_locked; | ||
1134 | } | ||
1135 | else if (fam2_drive) | ||
1136 | { | ||
1137 | current_drive->status_bits |= p_success; | ||
1138 | if (st&p2_check) current_drive->status_bits |= p1_check; | ||
1139 | if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; | ||
1140 | if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; | ||
1141 | if (st&p2_busy1) current_drive->status_bits |= p1_busy; | ||
1142 | if (st&p2_busy2) current_drive->status_bits |= p1_busy; | ||
1143 | if (st&p2_spinning) current_drive->status_bits |= p1_spinning; | ||
1144 | if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; | ||
1145 | if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; | ||
1146 | } | ||
1147 | else if (famT_drive) | ||
1148 | { | ||
1149 | return; /* still needs to get coded */ | ||
1150 | current_drive->status_bits |= p_success; | ||
1151 | if (st&p2_check) current_drive->status_bits |= p1_check; | ||
1152 | if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; | ||
1153 | if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; | ||
1154 | if (st&p2_busy1) current_drive->status_bits |= p1_busy; | ||
1155 | if (st&p2_busy2) current_drive->status_bits |= p1_busy; | ||
1156 | if (st&p2_spinning) current_drive->status_bits |= p1_spinning; | ||
1157 | if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; | ||
1158 | if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; | ||
1159 | } | ||
1160 | return; | ||
1161 | } | ||
1162 | /*==========================================================================*/ | ||
1163 | static int cmd_out_T(void); | ||
1164 | |||
1165 | static int get_state_T(void) | ||
1166 | { | ||
1167 | int i; | ||
1168 | |||
1169 | clr_cmdbuf(); | ||
1170 | current_drive->n_bytes=1; | ||
1171 | drvcmd[0]=CMDT_STATUS; | ||
1172 | i=cmd_out_T(); | ||
1173 | if (i>=0) i=infobuf[0]; | ||
1174 | else | ||
1175 | { | ||
1176 | msg(DBG_TEA,"get_state_T error %d\n", i); | ||
1177 | return (i); | ||
1178 | } | ||
1179 | if (i>=0) | ||
1180 | /* 2: closed, disk in */ | ||
1181 | current_drive->status_bits=p1_door_closed|p1_disk_in|p1_spinning|p1_disk_ok; | ||
1182 | else if (current_drive->error_state==6) | ||
1183 | { | ||
1184 | /* 3: closed, disk in, changed ("06 xx xx") */ | ||
1185 | current_drive->status_bits=p1_door_closed|p1_disk_in; | ||
1186 | current_drive->CD_changed=0xFF; | ||
1187 | current_drive->diskstate_flags &= ~toc_bit; | ||
1188 | } | ||
1189 | else if ((current_drive->error_state!=2)||(current_drive->b3!=0x3A)||(current_drive->b4==0x00)) | ||
1190 | { | ||
1191 | /* 1: closed, no disk ("xx yy zz"or "02 3A 00") */ | ||
1192 | current_drive->status_bits=p1_door_closed; | ||
1193 | current_drive->open_count=0; | ||
1194 | } | ||
1195 | else if (current_drive->b4==0x01) | ||
1196 | { | ||
1197 | /* 0: open ("02 3A 01") */ | ||
1198 | current_drive->status_bits=0; | ||
1199 | current_drive->open_count=0; | ||
1200 | } | ||
1201 | else | ||
1202 | { | ||
1203 | /* 1: closed, no disk ("02 3A xx") */ | ||
1204 | current_drive->status_bits=p1_door_closed; | ||
1205 | current_drive->open_count=0; | ||
1206 | } | ||
1207 | return (current_drive->status_bits); | ||
1208 | } | ||
1209 | /*==========================================================================*/ | ||
1210 | static int ResponseStatus(void) | ||
1211 | { | ||
1212 | int i,j; | ||
1213 | u_long timeout; | ||
1214 | |||
1215 | msg(DBG_STA,"doing ResponseStatus...\n"); | ||
1216 | if (famT_drive) return (get_state_T()); | ||
1217 | if (flags_cmd_out & f_respo3) timeout = jiffies; | ||
1218 | else if (flags_cmd_out & f_respo2) timeout = jiffies + 16*HZ; | ||
1219 | else timeout = jiffies + 4*HZ; | ||
1220 | j=maxtim_8; | ||
1221 | do | ||
1222 | { | ||
1223 | for ( ;j!=0;j--) | ||
1224 | { | ||
1225 | i=inb(CDi_status); | ||
1226 | if (!(i&s_not_result_ready)) break; | ||
1227 | } | ||
1228 | if ((j!=0)||time_after(jiffies, timeout)) break; | ||
1229 | sbp_sleep(1); | ||
1230 | j = 1; | ||
1231 | } | ||
1232 | while (1); | ||
1233 | if (j==0) | ||
1234 | { | ||
1235 | if ((flags_cmd_out & f_respo3) == 0) | ||
1236 | msg(DBG_STA,"ResponseStatus: timeout.\n"); | ||
1237 | current_drive->status_bits=0; | ||
1238 | return (-401); | ||
1239 | } | ||
1240 | i=inb(CDi_info); | ||
1241 | msg(DBG_STA,"ResponseStatus: response %02X.\n", i); | ||
1242 | EvaluateStatus(i); | ||
1243 | msg(DBG_STA,"status_bits=%02X, i=%02X\n",current_drive->status_bits,i); | ||
1244 | return (current_drive->status_bits); | ||
1245 | } | ||
1246 | /*==========================================================================*/ | ||
1247 | static void cc_ReadStatus(void) | ||
1248 | { | ||
1249 | int i; | ||
1250 | |||
1251 | msg(DBG_STA,"giving cc_ReadStatus command\n"); | ||
1252 | if (famT_drive) return; | ||
1253 | SBPCD_CLI; | ||
1254 | if (fam0LV_drive) OUT(CDo_command,CMD0_STATUS); | ||
1255 | else if (fam1_drive) OUT(CDo_command,CMD1_STATUS); | ||
1256 | else if (fam2_drive) OUT(CDo_command,CMD2_STATUS); | ||
1257 | if (!fam0LV_drive) for (i=0;i<6;i++) OUT(CDo_command,0); | ||
1258 | SBPCD_STI; | ||
1259 | } | ||
1260 | /*==========================================================================*/ | ||
1261 | static int cc_ReadError(void) | ||
1262 | { | ||
1263 | int i; | ||
1264 | |||
1265 | clr_cmdbuf(); | ||
1266 | msg(DBG_ERR,"giving cc_ReadError command.\n"); | ||
1267 | if (fam1_drive) | ||
1268 | { | ||
1269 | drvcmd[0]=CMD1_READ_ERR; | ||
1270 | response_count=8; | ||
1271 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1272 | } | ||
1273 | else if (fam0LV_drive) | ||
1274 | { | ||
1275 | drvcmd[0]=CMD0_READ_ERR; | ||
1276 | response_count=6; | ||
1277 | if (famLV_drive) | ||
1278 | flags_cmd_out=f_putcmd; | ||
1279 | else | ||
1280 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus; | ||
1281 | } | ||
1282 | else if (fam2_drive) | ||
1283 | { | ||
1284 | drvcmd[0]=CMD2_READ_ERR; | ||
1285 | response_count=6; | ||
1286 | flags_cmd_out=f_putcmd; | ||
1287 | } | ||
1288 | else if (famT_drive) | ||
1289 | { | ||
1290 | response_count=5; | ||
1291 | drvcmd[0]=CMDT_READ_ERR; | ||
1292 | } | ||
1293 | i=cmd_out(); | ||
1294 | current_drive->error_byte=0; | ||
1295 | msg(DBG_ERR,"cc_ReadError: cmd_out(CMDx_READ_ERR) returns %d (%02X)\n",i,i); | ||
1296 | if (i<0) return (i); | ||
1297 | if (fam0V_drive) i=1; | ||
1298 | else i=2; | ||
1299 | current_drive->error_byte=infobuf[i]; | ||
1300 | msg(DBG_ERR,"cc_ReadError: infobuf[%d] is %d (%02X)\n",i,current_drive->error_byte,current_drive->error_byte); | ||
1301 | i=sta2err(infobuf[i]); | ||
1302 | if (i==-ERR_DISKCHANGE) | ||
1303 | { | ||
1304 | current_drive->CD_changed=0xFF; | ||
1305 | current_drive->diskstate_flags &= ~toc_bit; | ||
1306 | } | ||
1307 | return (i); | ||
1308 | } | ||
1309 | /*==========================================================================*/ | ||
1310 | static int cc_DriveReset(void); | ||
1311 | |||
1312 | static int cmd_out_T(void) | ||
1313 | { | ||
1314 | #undef CMDT_TRIES | ||
1315 | #define CMDT_TRIES 1000 | ||
1316 | #define TEST_FALSE_FF 1 | ||
1317 | |||
1318 | int i, j, l=0, m, ntries; | ||
1319 | unsigned long flags; | ||
1320 | |||
1321 | current_drive->error_state=0; | ||
1322 | current_drive->b3=0; | ||
1323 | current_drive->b4=0; | ||
1324 | current_drive->f_drv_error=0; | ||
1325 | for (i=0;i<10;i++) sprintf(&msgbuf[i*3]," %02X",drvcmd[i]); | ||
1326 | msgbuf[i*3]=0; | ||
1327 | msg(DBG_CMD,"cmd_out_T:%s\n",msgbuf); | ||
1328 | |||
1329 | OUT(CDo_sel_i_d,0); | ||
1330 | OUT(CDo_enable,current_drive->drv_sel); | ||
1331 | i=inb(CDi_status); | ||
1332 | do_16bit=0; | ||
1333 | if ((f_16bit)&&(!(i&0x80))) | ||
1334 | { | ||
1335 | do_16bit=1; | ||
1336 | msg(DBG_TEA,"cmd_out_T: do_16bit set.\n"); | ||
1337 | } | ||
1338 | if (!(i&s_not_result_ready)) | ||
1339 | do | ||
1340 | { | ||
1341 | j=inb(CDi_info); | ||
1342 | i=inb(CDi_status); | ||
1343 | sbp_sleep(0); | ||
1344 | msg(DBG_TEA,"cmd_out_T: spurious !s_not_result_ready. (%02X)\n", j); | ||
1345 | } | ||
1346 | while (!(i&s_not_result_ready)); | ||
1347 | save_flags(flags); cli(); | ||
1348 | for (i=0;i<10;i++) OUT(CDo_command,drvcmd[i]); | ||
1349 | restore_flags(flags); | ||
1350 | for (ntries=CMDT_TRIES;ntries>0;ntries--) | ||
1351 | { | ||
1352 | if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */ | ||
1353 | #if 01 | ||
1354 | OUT(CDo_sel_i_d,1); | ||
1355 | #endif /* 01 */ | ||
1356 | if (teac==2) | ||
1357 | { | ||
1358 | if ((i=CDi_stat_loop_T()) == -1) break; | ||
1359 | } | ||
1360 | else | ||
1361 | { | ||
1362 | #if 0 | ||
1363 | OUT(CDo_sel_i_d,1); | ||
1364 | #endif /* 0 */ | ||
1365 | i=inb(CDi_status); | ||
1366 | } | ||
1367 | if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */ | ||
1368 | { | ||
1369 | OUT(CDo_sel_i_d,1); | ||
1370 | if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ | ||
1371 | if (drvcmd[0]==CMDT_DISKINFO) | ||
1372 | { | ||
1373 | l=0; | ||
1374 | do | ||
1375 | { | ||
1376 | if (do_16bit) | ||
1377 | { | ||
1378 | i=inw(CDi_data); | ||
1379 | infobuf[l++]=i&0x0ff; | ||
1380 | infobuf[l++]=i>>8; | ||
1381 | #if TEST_FALSE_FF | ||
1382 | if ((l==2)&&(infobuf[0]==0x0ff)) | ||
1383 | { | ||
1384 | infobuf[0]=infobuf[1]; | ||
1385 | l=1; | ||
1386 | msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n"); | ||
1387 | } | ||
1388 | #endif /* TEST_FALSE_FF */ | ||
1389 | } | ||
1390 | else infobuf[l++]=inb(CDi_data); | ||
1391 | i=inb(CDi_status); | ||
1392 | } | ||
1393 | while (!(i&s_not_data_ready)); | ||
1394 | for (j=0;j<l;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]); | ||
1395 | msgbuf[j*3]=0; | ||
1396 | msg(DBG_CMD,"cmd_out_T data response:%s\n", msgbuf); | ||
1397 | } | ||
1398 | else | ||
1399 | { | ||
1400 | msg(DBG_TEA,"cmd_out_T: data response with cmd_%02X!\n", | ||
1401 | drvcmd[0]); | ||
1402 | j=0; | ||
1403 | do | ||
1404 | { | ||
1405 | if (do_16bit) i=inw(CDi_data); | ||
1406 | else i=inb(CDi_data); | ||
1407 | j++; | ||
1408 | i=inb(CDi_status); | ||
1409 | } | ||
1410 | while (!(i&s_not_data_ready)); | ||
1411 | msg(DBG_TEA,"cmd_out_T: data response: discarded %d bytes/words.\n", j); | ||
1412 | fatal_err++; | ||
1413 | } | ||
1414 | } | ||
1415 | i=inb(CDi_status); | ||
1416 | if (!(i&s_not_result_ready)) | ||
1417 | { | ||
1418 | OUT(CDo_sel_i_d,0); | ||
1419 | if (drvcmd[0]==CMDT_DISKINFO) m=l; | ||
1420 | else m=0; | ||
1421 | do | ||
1422 | { | ||
1423 | infobuf[m++]=inb(CDi_info); | ||
1424 | i=inb(CDi_status); | ||
1425 | } | ||
1426 | while (!(i&s_not_result_ready)); | ||
1427 | for (j=0;j<m;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]); | ||
1428 | msgbuf[j*3]=0; | ||
1429 | msg(DBG_CMD,"cmd_out_T info response:%s\n", msgbuf); | ||
1430 | if (drvcmd[0]==CMDT_DISKINFO) | ||
1431 | { | ||
1432 | infobuf[0]=infobuf[l]; | ||
1433 | if (infobuf[0]!=0x02) return (l); /* data length */ | ||
1434 | } | ||
1435 | else if (infobuf[0]!=0x02) return (m); /* info length */ | ||
1436 | do | ||
1437 | { | ||
1438 | ++recursion; | ||
1439 | if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (%02X): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", drvcmd[0], recursion); | ||
1440 | clr_cmdbuf(); | ||
1441 | drvcmd[0]=CMDT_READ_ERR; | ||
1442 | j=cmd_out_T(); /* !!! recursive here !!! */ | ||
1443 | --recursion; | ||
1444 | sbp_sleep(1); | ||
1445 | } | ||
1446 | while (j<0); | ||
1447 | current_drive->error_state=infobuf[2]; | ||
1448 | current_drive->b3=infobuf[3]; | ||
1449 | current_drive->b4=infobuf[4]; | ||
1450 | if (current_drive->f_drv_error) | ||
1451 | { | ||
1452 | current_drive->f_drv_error=0; | ||
1453 | cc_DriveReset(); | ||
1454 | current_drive->error_state=2; | ||
1455 | } | ||
1456 | return (-current_drive->error_state-400); | ||
1457 | } | ||
1458 | if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ | ||
1459 | if ((teac==0)||(ntries<(CMDT_TRIES-5))) sbp_sleep(HZ/10); | ||
1460 | else sbp_sleep(HZ/100); | ||
1461 | if (ntries>(CMDT_TRIES-50)) continue; | ||
1462 | msg(DBG_TEA,"cmd_out_T: next CMDT_TRIES (%02X): %d.\n", drvcmd[0], ntries-1); | ||
1463 | } | ||
1464 | current_drive->f_drv_error=1; | ||
1465 | cc_DriveReset(); | ||
1466 | current_drive->error_state=2; | ||
1467 | return (-99); | ||
1468 | } | ||
1469 | /*==========================================================================*/ | ||
1470 | static int cmd_out(void) | ||
1471 | { | ||
1472 | int i=0; | ||
1473 | |||
1474 | if (famT_drive) return(cmd_out_T()); | ||
1475 | |||
1476 | if (flags_cmd_out&f_putcmd) | ||
1477 | { | ||
1478 | unsigned long flags; | ||
1479 | for (i=0;i<7;i++) | ||
1480 | sprintf(&msgbuf[i*3], " %02X", drvcmd[i]); | ||
1481 | msgbuf[i*3]=0; | ||
1482 | msg(DBG_CMD,"cmd_out:%s\n", msgbuf); | ||
1483 | save_flags(flags); cli(); | ||
1484 | for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]); | ||
1485 | restore_flags(flags); | ||
1486 | } | ||
1487 | if (response_count!=0) | ||
1488 | { | ||
1489 | if (cmd_type!=0) | ||
1490 | { | ||
1491 | if (sbpro_type==1) OUT(CDo_sel_i_d,1); | ||
1492 | msg(DBG_INF,"misleaded to try ResponseData.\n"); | ||
1493 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
1494 | return (-22); | ||
1495 | } | ||
1496 | else i=ResponseInfo(); | ||
1497 | if (i<0) return (i); | ||
1498 | } | ||
1499 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to CDi_stat_loop.\n"); | ||
1500 | if (flags_cmd_out&f_lopsta) | ||
1501 | { | ||
1502 | i=CDi_stat_loop(); | ||
1503 | if ((i<0)||!(i&s_attention)) return (-8); | ||
1504 | } | ||
1505 | if (!(flags_cmd_out&f_getsta)) goto LOC_229; | ||
1506 | |||
1507 | LOC_228: | ||
1508 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadStatus.\n"); | ||
1509 | cc_ReadStatus(); | ||
1510 | |||
1511 | LOC_229: | ||
1512 | if (flags_cmd_out&f_ResponseStatus) | ||
1513 | { | ||
1514 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to ResponseStatus.\n"); | ||
1515 | i=ResponseStatus(); | ||
1516 | /* builds status_bits, returns orig. status or p_busy_new */ | ||
1517 | if (i<0) return (i); | ||
1518 | if (flags_cmd_out&(f_bit1|f_wait_if_busy)) | ||
1519 | { | ||
1520 | if (!st_check) | ||
1521 | { | ||
1522 | if ((flags_cmd_out&f_bit1)&&(i&p_success)) goto LOC_232; | ||
1523 | if ((!(flags_cmd_out&f_wait_if_busy))||(!st_busy)) goto LOC_228; | ||
1524 | } | ||
1525 | } | ||
1526 | } | ||
1527 | LOC_232: | ||
1528 | if (!(flags_cmd_out&f_obey_p_check)) return (0); | ||
1529 | if (!st_check) return (0); | ||
1530 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadError.\n"); | ||
1531 | i=cc_ReadError(); | ||
1532 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cmd_out OK.\n"); | ||
1533 | msg(DBG_000,"cmd_out: cc_ReadError=%d\n", i); | ||
1534 | return (i); | ||
1535 | } | ||
1536 | /*==========================================================================*/ | ||
1537 | static int cc_Seek(u_int pos, char f_blk_msf) | ||
1538 | { | ||
1539 | int i; | ||
1540 | |||
1541 | clr_cmdbuf(); | ||
1542 | if (f_blk_msf>1) return (-3); | ||
1543 | if (fam0V_drive) | ||
1544 | { | ||
1545 | drvcmd[0]=CMD0_SEEK; | ||
1546 | if (f_blk_msf==1) pos=msf2blk(pos); | ||
1547 | drvcmd[2]=(pos>>16)&0x00FF; | ||
1548 | drvcmd[3]=(pos>>8)&0x00FF; | ||
1549 | drvcmd[4]=pos&0x00FF; | ||
1550 | if (fam0_drive) | ||
1551 | flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | | ||
1552 | f_ResponseStatus | f_obey_p_check | f_bit1; | ||
1553 | else | ||
1554 | flags_cmd_out = f_putcmd; | ||
1555 | } | ||
1556 | else if (fam1L_drive) | ||
1557 | { | ||
1558 | drvcmd[0]=CMD1_SEEK; /* same as CMD1_ and CMDL_ */ | ||
1559 | if (f_blk_msf==0) pos=blk2msf(pos); | ||
1560 | drvcmd[1]=(pos>>16)&0x00FF; | ||
1561 | drvcmd[2]=(pos>>8)&0x00FF; | ||
1562 | drvcmd[3]=pos&0x00FF; | ||
1563 | if (famL_drive) | ||
1564 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1565 | else | ||
1566 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1567 | } | ||
1568 | else if (fam2_drive) | ||
1569 | { | ||
1570 | drvcmd[0]=CMD2_SEEK; | ||
1571 | if (f_blk_msf==0) pos=blk2msf(pos); | ||
1572 | drvcmd[2]=(pos>>24)&0x00FF; | ||
1573 | drvcmd[3]=(pos>>16)&0x00FF; | ||
1574 | drvcmd[4]=(pos>>8)&0x00FF; | ||
1575 | drvcmd[5]=pos&0x00FF; | ||
1576 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1577 | } | ||
1578 | else if (famT_drive) | ||
1579 | { | ||
1580 | drvcmd[0]=CMDT_SEEK; | ||
1581 | if (f_blk_msf==1) pos=msf2blk(pos); | ||
1582 | drvcmd[2]=(pos>>24)&0x00FF; | ||
1583 | drvcmd[3]=(pos>>16)&0x00FF; | ||
1584 | drvcmd[4]=(pos>>8)&0x00FF; | ||
1585 | drvcmd[5]=pos&0x00FF; | ||
1586 | current_drive->n_bytes=1; | ||
1587 | } | ||
1588 | response_count=0; | ||
1589 | i=cmd_out(); | ||
1590 | return (i); | ||
1591 | } | ||
1592 | /*==========================================================================*/ | ||
1593 | static int cc_SpinUp(void) | ||
1594 | { | ||
1595 | int i; | ||
1596 | |||
1597 | msg(DBG_SPI,"SpinUp.\n"); | ||
1598 | current_drive->in_SpinUp = 1; | ||
1599 | clr_cmdbuf(); | ||
1600 | if (fam0LV_drive) | ||
1601 | { | ||
1602 | drvcmd[0]=CMD0_SPINUP; | ||
1603 | if (fam0L_drive) | ||
1604 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta| | ||
1605 | f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1606 | else | ||
1607 | flags_cmd_out=f_putcmd; | ||
1608 | } | ||
1609 | else if (fam1_drive) | ||
1610 | { | ||
1611 | drvcmd[0]=CMD1_SPINUP; | ||
1612 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1613 | } | ||
1614 | else if (fam2_drive) | ||
1615 | { | ||
1616 | drvcmd[0]=CMD2_TRAY_CTL; | ||
1617 | drvcmd[4]=0x01; /* "spinup" */ | ||
1618 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1619 | } | ||
1620 | else if (famT_drive) | ||
1621 | { | ||
1622 | drvcmd[0]=CMDT_TRAY_CTL; | ||
1623 | drvcmd[4]=0x03; /* "insert", it hopefully spins the drive up */ | ||
1624 | } | ||
1625 | response_count=0; | ||
1626 | i=cmd_out(); | ||
1627 | current_drive->in_SpinUp = 0; | ||
1628 | return (i); | ||
1629 | } | ||
1630 | /*==========================================================================*/ | ||
1631 | static int cc_SpinDown(void) | ||
1632 | { | ||
1633 | int i; | ||
1634 | |||
1635 | if (fam0_drive) return (0); | ||
1636 | clr_cmdbuf(); | ||
1637 | response_count=0; | ||
1638 | if (fam1_drive) | ||
1639 | { | ||
1640 | drvcmd[0]=CMD1_SPINDOWN; | ||
1641 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1642 | } | ||
1643 | else if (fam2_drive) | ||
1644 | { | ||
1645 | drvcmd[0]=CMD2_TRAY_CTL; | ||
1646 | drvcmd[4]=0x02; /* "eject" */ | ||
1647 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1648 | } | ||
1649 | else if (famL_drive) | ||
1650 | { | ||
1651 | drvcmd[0]=CMDL_SPINDOWN; | ||
1652 | drvcmd[1]=1; | ||
1653 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1654 | } | ||
1655 | else if (famV_drive) | ||
1656 | { | ||
1657 | drvcmd[0]=CMDV_SPINDOWN; | ||
1658 | flags_cmd_out=f_putcmd; | ||
1659 | } | ||
1660 | else if (famT_drive) | ||
1661 | { | ||
1662 | drvcmd[0]=CMDT_TRAY_CTL; | ||
1663 | drvcmd[4]=0x02; /* "eject" */ | ||
1664 | } | ||
1665 | i=cmd_out(); | ||
1666 | return (i); | ||
1667 | } | ||
1668 | /*==========================================================================*/ | ||
1669 | static int cc_get_mode_T(void) | ||
1670 | { | ||
1671 | int i; | ||
1672 | |||
1673 | clr_cmdbuf(); | ||
1674 | response_count=10; | ||
1675 | drvcmd[0]=CMDT_GETMODE; | ||
1676 | drvcmd[4]=response_count; | ||
1677 | i=cmd_out_T(); | ||
1678 | return (i); | ||
1679 | } | ||
1680 | /*==========================================================================*/ | ||
1681 | static int cc_set_mode_T(void) | ||
1682 | { | ||
1683 | int i; | ||
1684 | |||
1685 | clr_cmdbuf(); | ||
1686 | response_count=1; | ||
1687 | drvcmd[0]=CMDT_SETMODE; | ||
1688 | drvcmd[1]=current_drive->speed_byte; | ||
1689 | drvcmd[2]=current_drive->frmsiz>>8; | ||
1690 | drvcmd[3]=current_drive->frmsiz&0x0FF; | ||
1691 | drvcmd[4]=current_drive->f_XA; /* 1: XA */ | ||
1692 | drvcmd[5]=current_drive->type_byte; /* 0, 1, 3 */ | ||
1693 | drvcmd[6]=current_drive->mode_xb_6; | ||
1694 | drvcmd[7]=current_drive->mode_yb_7|current_drive->volume_control; | ||
1695 | drvcmd[8]=current_drive->mode_xb_8; | ||
1696 | drvcmd[9]=current_drive->delay; | ||
1697 | i=cmd_out_T(); | ||
1698 | return (i); | ||
1699 | } | ||
1700 | /*==========================================================================*/ | ||
1701 | static int cc_prep_mode_T(void) | ||
1702 | { | ||
1703 | int i, j; | ||
1704 | |||
1705 | i=cc_get_mode_T(); | ||
1706 | if (i<0) return (i); | ||
1707 | for (i=0;i<10;i++) | ||
1708 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
1709 | msgbuf[i*3]=0; | ||
1710 | msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); | ||
1711 | current_drive->speed_byte=0x02; /* 0x02: auto quad, 0x82: quad, 0x81: double, 0x80: single */ | ||
1712 | current_drive->frmsiz=make16(infobuf[2],infobuf[3]); | ||
1713 | current_drive->f_XA=infobuf[4]; | ||
1714 | if (current_drive->f_XA==0) current_drive->type_byte=0; | ||
1715 | else current_drive->type_byte=1; | ||
1716 | current_drive->mode_xb_6=infobuf[6]; | ||
1717 | current_drive->mode_yb_7=1; | ||
1718 | current_drive->mode_xb_8=infobuf[8]; | ||
1719 | current_drive->delay=0; /* 0, 1, 2, 3 */ | ||
1720 | j=cc_set_mode_T(); | ||
1721 | i=cc_get_mode_T(); | ||
1722 | for (i=0;i<10;i++) | ||
1723 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
1724 | msgbuf[i*3]=0; | ||
1725 | msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); | ||
1726 | return (j); | ||
1727 | } | ||
1728 | /*==========================================================================*/ | ||
1729 | static int cc_SetSpeed(u_char speed, u_char x1, u_char x2) | ||
1730 | { | ||
1731 | int i; | ||
1732 | |||
1733 | if (fam0LV_drive) return (0); | ||
1734 | clr_cmdbuf(); | ||
1735 | response_count=0; | ||
1736 | if (fam1_drive) | ||
1737 | { | ||
1738 | drvcmd[0]=CMD1_SETMODE; | ||
1739 | drvcmd[1]=0x03; | ||
1740 | drvcmd[2]=speed; | ||
1741 | drvcmd[3]=x1; | ||
1742 | drvcmd[4]=x2; | ||
1743 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
1744 | } | ||
1745 | else if (fam2_drive) | ||
1746 | { | ||
1747 | drvcmd[0]=CMD2_SETSPEED; | ||
1748 | if (speed&speed_auto) | ||
1749 | { | ||
1750 | drvcmd[2]=0xFF; | ||
1751 | drvcmd[3]=0xFF; | ||
1752 | } | ||
1753 | else | ||
1754 | { | ||
1755 | drvcmd[2]=0; | ||
1756 | drvcmd[3]=150; | ||
1757 | } | ||
1758 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
1759 | } | ||
1760 | else if (famT_drive) | ||
1761 | { | ||
1762 | return (0); | ||
1763 | } | ||
1764 | i=cmd_out(); | ||
1765 | return (i); | ||
1766 | } | ||
1767 | /*==========================================================================*/ | ||
1768 | static int cc_SetVolume(void) | ||
1769 | { | ||
1770 | int i; | ||
1771 | u_char channel0,channel1,volume0,volume1; | ||
1772 | u_char control0,value0,control1,value1; | ||
1773 | |||
1774 | current_drive->diskstate_flags &= ~volume_bit; | ||
1775 | clr_cmdbuf(); | ||
1776 | channel0=current_drive->vol_chan0; | ||
1777 | volume0=current_drive->vol_ctrl0; | ||
1778 | channel1=control1=current_drive->vol_chan1; | ||
1779 | volume1=value1=current_drive->vol_ctrl1; | ||
1780 | control0=value0=0; | ||
1781 | |||
1782 | if (famV_drive) return (0); | ||
1783 | |||
1784 | if (((current_drive->drv_options&audio_mono)!=0)&&(current_drive->drv_type>=drv_211)) | ||
1785 | { | ||
1786 | if ((volume0!=0)&&(volume1==0)) | ||
1787 | { | ||
1788 | volume1=volume0; | ||
1789 | channel1=channel0; | ||
1790 | } | ||
1791 | else if ((volume0==0)&&(volume1!=0)) | ||
1792 | { | ||
1793 | volume0=volume1; | ||
1794 | channel0=channel1; | ||
1795 | } | ||
1796 | } | ||
1797 | if (channel0>1) | ||
1798 | { | ||
1799 | channel0=0; | ||
1800 | volume0=0; | ||
1801 | } | ||
1802 | if (channel1>1) | ||
1803 | { | ||
1804 | channel1=1; | ||
1805 | volume1=0; | ||
1806 | } | ||
1807 | |||
1808 | if (fam1_drive) | ||
1809 | { | ||
1810 | control0=channel0+1; | ||
1811 | control1=channel1+1; | ||
1812 | value0=(volume0>volume1)?volume0:volume1; | ||
1813 | value1=value0; | ||
1814 | if (volume0==0) control0=0; | ||
1815 | if (volume1==0) control1=0; | ||
1816 | drvcmd[0]=CMD1_SETMODE; | ||
1817 | drvcmd[1]=0x05; | ||
1818 | drvcmd[3]=control0; | ||
1819 | drvcmd[4]=value0; | ||
1820 | drvcmd[5]=control1; | ||
1821 | drvcmd[6]=value1; | ||
1822 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
1823 | } | ||
1824 | else if (fam2_drive) | ||
1825 | { | ||
1826 | control0=channel0+1; | ||
1827 | control1=channel1+1; | ||
1828 | value0=(volume0>volume1)?volume0:volume1; | ||
1829 | value1=value0; | ||
1830 | if (volume0==0) control0=0; | ||
1831 | if (volume1==0) control1=0; | ||
1832 | drvcmd[0]=CMD2_SETMODE; | ||
1833 | drvcmd[1]=0x0E; | ||
1834 | drvcmd[3]=control0; | ||
1835 | drvcmd[4]=value0; | ||
1836 | drvcmd[5]=control1; | ||
1837 | drvcmd[6]=value1; | ||
1838 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1839 | } | ||
1840 | else if (famL_drive) | ||
1841 | { | ||
1842 | if ((volume0==0)||(channel0!=0)) control0 |= 0x80; | ||
1843 | if ((volume1==0)||(channel1!=1)) control0 |= 0x40; | ||
1844 | if (volume0|volume1) value0=0x80; | ||
1845 | drvcmd[0]=CMDL_SETMODE; | ||
1846 | drvcmd[1]=0x03; | ||
1847 | drvcmd[4]=control0; | ||
1848 | drvcmd[5]=value0; | ||
1849 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1850 | } | ||
1851 | else if (fam0_drive) /* different firmware levels */ | ||
1852 | { | ||
1853 | if (current_drive->drv_type>=drv_300) | ||
1854 | { | ||
1855 | control0=volume0&0xFC; | ||
1856 | value0=volume1&0xFC; | ||
1857 | if ((volume0!=0)&&(volume0<4)) control0 |= 0x04; | ||
1858 | if ((volume1!=0)&&(volume1<4)) value0 |= 0x04; | ||
1859 | if (channel0!=0) control0 |= 0x01; | ||
1860 | if (channel1==1) value0 |= 0x01; | ||
1861 | } | ||
1862 | else | ||
1863 | { | ||
1864 | value0=(volume0>volume1)?volume0:volume1; | ||
1865 | if (current_drive->drv_type<drv_211) | ||
1866 | { | ||
1867 | if (channel0!=0) | ||
1868 | { | ||
1869 | i=channel1; | ||
1870 | channel1=channel0; | ||
1871 | channel0=i; | ||
1872 | i=volume1; | ||
1873 | volume1=volume0; | ||
1874 | volume0=i; | ||
1875 | } | ||
1876 | if (channel0==channel1) | ||
1877 | { | ||
1878 | if (channel0==0) | ||
1879 | { | ||
1880 | channel1=1; | ||
1881 | volume1=0; | ||
1882 | volume0=value0; | ||
1883 | } | ||
1884 | else | ||
1885 | { | ||
1886 | channel0=0; | ||
1887 | volume0=0; | ||
1888 | volume1=value0; | ||
1889 | } | ||
1890 | } | ||
1891 | } | ||
1892 | |||
1893 | if ((volume0!=0)&&(volume1!=0)) | ||
1894 | { | ||
1895 | if (volume0==0xFF) volume1=0xFF; | ||
1896 | else if (volume1==0xFF) volume0=0xFF; | ||
1897 | } | ||
1898 | else if (current_drive->drv_type<drv_201) volume0=volume1=value0; | ||
1899 | |||
1900 | if (current_drive->drv_type>=drv_201) | ||
1901 | { | ||
1902 | if (volume0==0) control0 |= 0x80; | ||
1903 | if (volume1==0) control0 |= 0x40; | ||
1904 | } | ||
1905 | if (current_drive->drv_type>=drv_211) | ||
1906 | { | ||
1907 | if (channel0!=0) control0 |= 0x20; | ||
1908 | if (channel1!=1) control0 |= 0x10; | ||
1909 | } | ||
1910 | } | ||
1911 | drvcmd[0]=CMD0_SETMODE; | ||
1912 | drvcmd[1]=0x83; | ||
1913 | drvcmd[4]=control0; | ||
1914 | drvcmd[5]=value0; | ||
1915 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
1916 | } | ||
1917 | else if (famT_drive) | ||
1918 | { | ||
1919 | current_drive->volume_control=0; | ||
1920 | if (!volume0) current_drive->volume_control|=0x10; | ||
1921 | if (!volume1) current_drive->volume_control|=0x20; | ||
1922 | i=cc_prep_mode_T(); | ||
1923 | if (i<0) return (i); | ||
1924 | } | ||
1925 | if (!famT_drive) | ||
1926 | { | ||
1927 | response_count=0; | ||
1928 | i=cmd_out(); | ||
1929 | if (i<0) return (i); | ||
1930 | } | ||
1931 | current_drive->diskstate_flags |= volume_bit; | ||
1932 | return (0); | ||
1933 | } | ||
1934 | /*==========================================================================*/ | ||
1935 | static int GetStatus(void) | ||
1936 | { | ||
1937 | int i; | ||
1938 | |||
1939 | if (famT_drive) return (0); | ||
1940 | flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check; | ||
1941 | response_count=0; | ||
1942 | cmd_type=0; | ||
1943 | i=cmd_out(); | ||
1944 | return (i); | ||
1945 | } | ||
1946 | /*==========================================================================*/ | ||
1947 | static int cc_DriveReset(void) | ||
1948 | { | ||
1949 | int i; | ||
1950 | |||
1951 | msg(DBG_RES,"cc_DriveReset called.\n"); | ||
1952 | clr_cmdbuf(); | ||
1953 | response_count=0; | ||
1954 | if (fam0LV_drive) OUT(CDo_reset,0x00); | ||
1955 | else if (fam1_drive) | ||
1956 | { | ||
1957 | drvcmd[0]=CMD1_RESET; | ||
1958 | flags_cmd_out=f_putcmd; | ||
1959 | i=cmd_out(); | ||
1960 | } | ||
1961 | else if (fam2_drive) | ||
1962 | { | ||
1963 | drvcmd[0]=CMD2_RESET; | ||
1964 | flags_cmd_out=f_putcmd; | ||
1965 | i=cmd_out(); | ||
1966 | OUT(CDo_reset,0x00); | ||
1967 | } | ||
1968 | else if (famT_drive) | ||
1969 | { | ||
1970 | OUT(CDo_sel_i_d,0); | ||
1971 | OUT(CDo_enable,current_drive->drv_sel); | ||
1972 | OUT(CDo_command,CMDT_RESET); | ||
1973 | for (i=1;i<10;i++) OUT(CDo_command,0); | ||
1974 | } | ||
1975 | if (fam0LV_drive) sbp_sleep(5*HZ); /* wait 5 seconds */ | ||
1976 | else sbp_sleep(1*HZ); /* wait a second */ | ||
1977 | #if 1 | ||
1978 | if (famT_drive) | ||
1979 | { | ||
1980 | msg(DBG_TEA, "================CMDT_RESET given=================.\n"); | ||
1981 | sbp_sleep(3*HZ); | ||
1982 | } | ||
1983 | #endif /* 1 */ | ||
1984 | flush_status(); | ||
1985 | i=GetStatus(); | ||
1986 | if (i<0) return i; | ||
1987 | if (!famT_drive) | ||
1988 | if (current_drive->error_byte!=aud_12) return -501; | ||
1989 | return (0); | ||
1990 | } | ||
1991 | |||
1992 | /*==========================================================================*/ | ||
1993 | static int SetSpeed(void) | ||
1994 | { | ||
1995 | int i, speed; | ||
1996 | |||
1997 | if (!(current_drive->drv_options&(speed_auto|speed_300|speed_150))) return (0); | ||
1998 | speed=speed_auto; | ||
1999 | if (!(current_drive->drv_options&speed_auto)) | ||
2000 | { | ||
2001 | speed |= speed_300; | ||
2002 | if (!(current_drive->drv_options&speed_300)) speed=0; | ||
2003 | } | ||
2004 | i=cc_SetSpeed(speed,0,0); | ||
2005 | return (i); | ||
2006 | } | ||
2007 | |||
2008 | static void switch_drive(struct sbpcd_drive *); | ||
2009 | |||
2010 | static int sbpcd_select_speed(struct cdrom_device_info *cdi, int speed) | ||
2011 | { | ||
2012 | struct sbpcd_drive *p = cdi->handle; | ||
2013 | if (p != current_drive) | ||
2014 | switch_drive(p); | ||
2015 | |||
2016 | return cc_SetSpeed(speed == 2 ? speed_300 : speed_150, 0, 0); | ||
2017 | } | ||
2018 | |||
2019 | /*==========================================================================*/ | ||
2020 | static int DriveReset(void) | ||
2021 | { | ||
2022 | int i; | ||
2023 | |||
2024 | i=cc_DriveReset(); | ||
2025 | if (i<0) return (-22); | ||
2026 | do | ||
2027 | { | ||
2028 | i=GetStatus(); | ||
2029 | if ((i<0)&&(i!=-ERR_DISKCHANGE)) { | ||
2030 | return (-2); /* from sta2err */ | ||
2031 | } | ||
2032 | if (!st_caddy_in) break; | ||
2033 | sbp_sleep(1); | ||
2034 | } | ||
2035 | while (!st_diskok); | ||
2036 | #if 000 | ||
2037 | current_drive->CD_changed=1; | ||
2038 | #endif | ||
2039 | if ((st_door_closed) && (st_caddy_in)) | ||
2040 | { | ||
2041 | i=DiskInfo(); | ||
2042 | if (i<0) return (-23); | ||
2043 | } | ||
2044 | return (0); | ||
2045 | } | ||
2046 | |||
2047 | static int sbpcd_reset(struct cdrom_device_info *cdi) | ||
2048 | { | ||
2049 | struct sbpcd_drive *p = cdi->handle; | ||
2050 | if (p != current_drive) | ||
2051 | switch_drive(p); | ||
2052 | return DriveReset(); | ||
2053 | } | ||
2054 | |||
2055 | /*==========================================================================*/ | ||
2056 | static int cc_PlayAudio(int pos_audio_start,int pos_audio_end) | ||
2057 | { | ||
2058 | int i, j, n; | ||
2059 | |||
2060 | if (current_drive->audio_state==audio_playing) return (-EINVAL); | ||
2061 | clr_cmdbuf(); | ||
2062 | response_count=0; | ||
2063 | if (famLV_drive) | ||
2064 | { | ||
2065 | drvcmd[0]=CMDL_PLAY; | ||
2066 | i=msf2blk(pos_audio_start); | ||
2067 | n=msf2blk(pos_audio_end)+1-i; | ||
2068 | drvcmd[1]=(i>>16)&0x00FF; | ||
2069 | drvcmd[2]=(i>>8)&0x00FF; | ||
2070 | drvcmd[3]=i&0x00FF; | ||
2071 | drvcmd[4]=(n>>16)&0x00FF; | ||
2072 | drvcmd[5]=(n>>8)&0x00FF; | ||
2073 | drvcmd[6]=n&0x00FF; | ||
2074 | if (famL_drive) | ||
2075 | flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | | ||
2076 | f_ResponseStatus | f_obey_p_check | f_wait_if_busy; | ||
2077 | else | ||
2078 | flags_cmd_out = f_putcmd; | ||
2079 | } | ||
2080 | else | ||
2081 | { | ||
2082 | j=1; | ||
2083 | if (fam1_drive) | ||
2084 | { | ||
2085 | drvcmd[0]=CMD1_PLAY_MSF; | ||
2086 | flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | | ||
2087 | f_obey_p_check | f_wait_if_busy; | ||
2088 | } | ||
2089 | else if (fam2_drive) | ||
2090 | { | ||
2091 | drvcmd[0]=CMD2_PLAY_MSF; | ||
2092 | flags_cmd_out = f_putcmd | f_ResponseStatus | f_obey_p_check; | ||
2093 | } | ||
2094 | else if (famT_drive) | ||
2095 | { | ||
2096 | drvcmd[0]=CMDT_PLAY_MSF; | ||
2097 | j=3; | ||
2098 | response_count=1; | ||
2099 | } | ||
2100 | else if (fam0_drive) | ||
2101 | { | ||
2102 | drvcmd[0]=CMD0_PLAY_MSF; | ||
2103 | flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | | ||
2104 | f_ResponseStatus | f_obey_p_check | f_wait_if_busy; | ||
2105 | } | ||
2106 | drvcmd[j]=(pos_audio_start>>16)&0x00FF; | ||
2107 | drvcmd[j+1]=(pos_audio_start>>8)&0x00FF; | ||
2108 | drvcmd[j+2]=pos_audio_start&0x00FF; | ||
2109 | drvcmd[j+3]=(pos_audio_end>>16)&0x00FF; | ||
2110 | drvcmd[j+4]=(pos_audio_end>>8)&0x00FF; | ||
2111 | drvcmd[j+5]=pos_audio_end&0x00FF; | ||
2112 | } | ||
2113 | i=cmd_out(); | ||
2114 | return (i); | ||
2115 | } | ||
2116 | /*==========================================================================*/ | ||
2117 | static int cc_Pause_Resume(int pau_res) | ||
2118 | { | ||
2119 | int i; | ||
2120 | |||
2121 | clr_cmdbuf(); | ||
2122 | response_count=0; | ||
2123 | if (fam1_drive) | ||
2124 | { | ||
2125 | drvcmd[0]=CMD1_PAU_RES; | ||
2126 | if (pau_res!=1) drvcmd[1]=0x80; | ||
2127 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
2128 | } | ||
2129 | else if (fam2_drive) | ||
2130 | { | ||
2131 | drvcmd[0]=CMD2_PAU_RES; | ||
2132 | if (pau_res!=1) drvcmd[2]=0x01; | ||
2133 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
2134 | } | ||
2135 | else if (fam0LV_drive) | ||
2136 | { | ||
2137 | drvcmd[0]=CMD0_PAU_RES; | ||
2138 | if (pau_res!=1) drvcmd[1]=0x80; | ||
2139 | if (famL_drive) | ||
2140 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus| | ||
2141 | f_obey_p_check|f_bit1; | ||
2142 | else if (famV_drive) | ||
2143 | flags_cmd_out=f_putcmd; | ||
2144 | else | ||
2145 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus| | ||
2146 | f_obey_p_check; | ||
2147 | } | ||
2148 | else if (famT_drive) | ||
2149 | { | ||
2150 | if (pau_res==3) return (cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end)); | ||
2151 | else if (pau_res==1) drvcmd[0]=CMDT_PAUSE; | ||
2152 | else return (-56); | ||
2153 | } | ||
2154 | i=cmd_out(); | ||
2155 | return (i); | ||
2156 | } | ||
2157 | /*==========================================================================*/ | ||
2158 | static int cc_LockDoor(char lock) | ||
2159 | { | ||
2160 | int i; | ||
2161 | |||
2162 | if (fam0_drive) return (0); | ||
2163 | msg(DBG_LCK,"cc_LockDoor: %d (drive %d)\n", lock, current_drive - D_S); | ||
2164 | msg(DBG_LCS,"p_door_locked bit %d before\n", st_door_locked); | ||
2165 | clr_cmdbuf(); | ||
2166 | response_count=0; | ||
2167 | if (fam1_drive) | ||
2168 | { | ||
2169 | drvcmd[0]=CMD1_LOCK_CTL; | ||
2170 | if (lock==1) drvcmd[1]=0x01; | ||
2171 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2172 | } | ||
2173 | else if (fam2_drive) | ||
2174 | { | ||
2175 | drvcmd[0]=CMD2_LOCK_CTL; | ||
2176 | if (lock==1) drvcmd[4]=0x01; | ||
2177 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
2178 | } | ||
2179 | else if (famLV_drive) | ||
2180 | { | ||
2181 | drvcmd[0]=CMDL_LOCK_CTL; | ||
2182 | if (lock==1) drvcmd[1]=0x01; | ||
2183 | if (famL_drive) | ||
2184 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
2185 | else | ||
2186 | flags_cmd_out=f_putcmd; | ||
2187 | } | ||
2188 | else if (famT_drive) | ||
2189 | { | ||
2190 | drvcmd[0]=CMDT_LOCK_CTL; | ||
2191 | if (lock==1) drvcmd[4]=0x01; | ||
2192 | } | ||
2193 | i=cmd_out(); | ||
2194 | msg(DBG_LCS,"p_door_locked bit %d after\n", st_door_locked); | ||
2195 | return (i); | ||
2196 | } | ||
2197 | /*==========================================================================*/ | ||
2198 | /*==========================================================================*/ | ||
2199 | static int UnLockDoor(void) | ||
2200 | { | ||
2201 | int i,j; | ||
2202 | |||
2203 | j=20; | ||
2204 | do | ||
2205 | { | ||
2206 | i=cc_LockDoor(0); | ||
2207 | --j; | ||
2208 | sbp_sleep(1); | ||
2209 | } | ||
2210 | while ((i<0)&&(j)); | ||
2211 | if (i<0) | ||
2212 | { | ||
2213 | cc_DriveReset(); | ||
2214 | return -84; | ||
2215 | } | ||
2216 | return (0); | ||
2217 | } | ||
2218 | /*==========================================================================*/ | ||
2219 | static int LockDoor(void) | ||
2220 | { | ||
2221 | int i,j; | ||
2222 | |||
2223 | j=20; | ||
2224 | do | ||
2225 | { | ||
2226 | i=cc_LockDoor(1); | ||
2227 | --j; | ||
2228 | sbp_sleep(1); | ||
2229 | } | ||
2230 | while ((i<0)&&(j)); | ||
2231 | if (j==0) | ||
2232 | { | ||
2233 | cc_DriveReset(); | ||
2234 | j=20; | ||
2235 | do | ||
2236 | { | ||
2237 | i=cc_LockDoor(1); | ||
2238 | --j; | ||
2239 | sbp_sleep(1); | ||
2240 | } | ||
2241 | while ((i<0)&&(j)); | ||
2242 | } | ||
2243 | return (i); | ||
2244 | } | ||
2245 | |||
2246 | static int sbpcd_lock_door(struct cdrom_device_info *cdi, int lock) | ||
2247 | { | ||
2248 | return lock ? LockDoor() : UnLockDoor(); | ||
2249 | } | ||
2250 | |||
2251 | /*==========================================================================*/ | ||
2252 | static int cc_CloseTray(void) | ||
2253 | { | ||
2254 | int i; | ||
2255 | |||
2256 | if (fam0_drive) return (0); | ||
2257 | msg(DBG_LCK,"cc_CloseTray (drive %d)\n", current_drive - D_S); | ||
2258 | msg(DBG_LCS,"p_door_closed bit %d before\n", st_door_closed); | ||
2259 | |||
2260 | clr_cmdbuf(); | ||
2261 | response_count=0; | ||
2262 | if (fam1_drive) | ||
2263 | { | ||
2264 | drvcmd[0]=CMD1_TRAY_CTL; | ||
2265 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
2266 | } | ||
2267 | else if (fam2_drive) | ||
2268 | { | ||
2269 | drvcmd[0]=CMD2_TRAY_CTL; | ||
2270 | drvcmd[1]=0x01; | ||
2271 | drvcmd[4]=0x03; /* "insert" */ | ||
2272 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
2273 | } | ||
2274 | else if (famLV_drive) | ||
2275 | { | ||
2276 | drvcmd[0]=CMDL_TRAY_CTL; | ||
2277 | if (famLV_drive) | ||
2278 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta| | ||
2279 | f_ResponseStatus|f_obey_p_check|f_bit1; | ||
2280 | else | ||
2281 | flags_cmd_out=f_putcmd; | ||
2282 | } | ||
2283 | else if (famT_drive) | ||
2284 | { | ||
2285 | drvcmd[0]=CMDT_TRAY_CTL; | ||
2286 | drvcmd[4]=0x03; /* "insert" */ | ||
2287 | } | ||
2288 | i=cmd_out(); | ||
2289 | msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed); | ||
2290 | |||
2291 | i=cc_ReadError(); | ||
2292 | flags_cmd_out |= f_respo2; | ||
2293 | cc_ReadStatus(); /* command: give 1-byte status */ | ||
2294 | i=ResponseStatus(); | ||
2295 | if (famT_drive&&(i<0)) | ||
2296 | { | ||
2297 | cc_DriveReset(); | ||
2298 | i=ResponseStatus(); | ||
2299 | #if 0 | ||
2300 | sbp_sleep(HZ); | ||
2301 | #endif /* 0 */ | ||
2302 | i=ResponseStatus(); | ||
2303 | } | ||
2304 | if (i<0) | ||
2305 | { | ||
2306 | msg(DBG_INF,"sbpcd cc_CloseTray: ResponseStatus timed out (%d).\n",i); | ||
2307 | } | ||
2308 | if (!(famT_drive)) | ||
2309 | { | ||
2310 | if (!st_spinning) | ||
2311 | { | ||
2312 | cc_SpinUp(); | ||
2313 | if (st_check) i=cc_ReadError(); | ||
2314 | flags_cmd_out |= f_respo2; | ||
2315 | cc_ReadStatus(); | ||
2316 | i=ResponseStatus(); | ||
2317 | } else { | ||
2318 | } | ||
2319 | } | ||
2320 | i=DiskInfo(); | ||
2321 | return (i); | ||
2322 | } | ||
2323 | |||
2324 | static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position) | ||
2325 | { | ||
2326 | int retval=0; | ||
2327 | switch_drive(cdi->handle); | ||
2328 | /* DUH! --AJK */ | ||
2329 | if(current_drive->CD_changed != 0xFF) { | ||
2330 | current_drive->CD_changed=0xFF; | ||
2331 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
2332 | } | ||
2333 | if (position == 1) { | ||
2334 | cc_SpinDown(); | ||
2335 | } else { | ||
2336 | retval=cc_CloseTray(); | ||
2337 | } | ||
2338 | return retval; | ||
2339 | } | ||
2340 | |||
2341 | /*==========================================================================*/ | ||
2342 | static int cc_ReadSubQ(void) | ||
2343 | { | ||
2344 | int i,j; | ||
2345 | |||
2346 | current_drive->diskstate_flags &= ~subq_bit; | ||
2347 | for (j=255;j>0;j--) | ||
2348 | { | ||
2349 | clr_cmdbuf(); | ||
2350 | if (fam1_drive) | ||
2351 | { | ||
2352 | drvcmd[0]=CMD1_READSUBQ; | ||
2353 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2354 | response_count=11; | ||
2355 | } | ||
2356 | else if (fam2_drive) | ||
2357 | { | ||
2358 | drvcmd[0]=CMD2_READSUBQ; | ||
2359 | drvcmd[1]=0x02; | ||
2360 | drvcmd[3]=0x01; | ||
2361 | flags_cmd_out=f_putcmd; | ||
2362 | response_count=10; | ||
2363 | } | ||
2364 | else if (fam0LV_drive) | ||
2365 | { | ||
2366 | drvcmd[0]=CMD0_READSUBQ; | ||
2367 | drvcmd[1]=0x02; | ||
2368 | if (famLV_drive) | ||
2369 | flags_cmd_out=f_putcmd; | ||
2370 | else | ||
2371 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2372 | response_count=13; | ||
2373 | } | ||
2374 | else if (famT_drive) | ||
2375 | { | ||
2376 | response_count=12; | ||
2377 | drvcmd[0]=CMDT_READSUBQ; | ||
2378 | drvcmd[1]=0x02; | ||
2379 | drvcmd[2]=0x40; | ||
2380 | drvcmd[3]=0x01; | ||
2381 | drvcmd[8]=response_count; | ||
2382 | } | ||
2383 | i=cmd_out(); | ||
2384 | if (i<0) return (i); | ||
2385 | for (i=0;i<response_count;i++) | ||
2386 | { | ||
2387 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
2388 | msgbuf[i*3]=0; | ||
2389 | msg(DBG_SQ1,"cc_ReadSubQ:%s\n", msgbuf); | ||
2390 | } | ||
2391 | if (famT_drive) break; | ||
2392 | if (infobuf[0]!=0) break; | ||
2393 | if ((!st_spinning) || (j==1)) | ||
2394 | { | ||
2395 | current_drive->SubQ_ctl_adr=current_drive->SubQ_trk=current_drive->SubQ_pnt_idx=current_drive->SubQ_whatisthis=0; | ||
2396 | current_drive->SubQ_run_tot=current_drive->SubQ_run_trk=0; | ||
2397 | return (0); | ||
2398 | } | ||
2399 | } | ||
2400 | if (famT_drive) current_drive->SubQ_ctl_adr=infobuf[1]; | ||
2401 | else current_drive->SubQ_ctl_adr=swap_nibbles(infobuf[1]); | ||
2402 | current_drive->SubQ_trk=byt2bcd(infobuf[2]); | ||
2403 | current_drive->SubQ_pnt_idx=byt2bcd(infobuf[3]); | ||
2404 | if (fam0LV_drive) i=5; | ||
2405 | else if (fam12_drive) i=4; | ||
2406 | else if (famT_drive) i=8; | ||
2407 | current_drive->SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ | ||
2408 | i=7; | ||
2409 | if (fam0LV_drive) i=9; | ||
2410 | else if (fam12_drive) i=7; | ||
2411 | else if (famT_drive) i=4; | ||
2412 | current_drive->SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ | ||
2413 | current_drive->SubQ_whatisthis=infobuf[i+3]; | ||
2414 | current_drive->diskstate_flags |= subq_bit; | ||
2415 | return (0); | ||
2416 | } | ||
2417 | /*==========================================================================*/ | ||
2418 | static int cc_ModeSense(void) | ||
2419 | { | ||
2420 | int i; | ||
2421 | |||
2422 | if (fam2_drive) return (0); | ||
2423 | if (famV_drive) return (0); | ||
2424 | current_drive->diskstate_flags &= ~frame_size_bit; | ||
2425 | clr_cmdbuf(); | ||
2426 | if (fam1_drive) | ||
2427 | { | ||
2428 | response_count=5; | ||
2429 | drvcmd[0]=CMD1_GETMODE; | ||
2430 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2431 | } | ||
2432 | else if (fam0L_drive) | ||
2433 | { | ||
2434 | response_count=2; | ||
2435 | drvcmd[0]=CMD0_GETMODE; | ||
2436 | if (famL_drive) flags_cmd_out=f_putcmd; | ||
2437 | else flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2438 | } | ||
2439 | else if (famT_drive) | ||
2440 | { | ||
2441 | response_count=10; | ||
2442 | drvcmd[0]=CMDT_GETMODE; | ||
2443 | drvcmd[4]=response_count; | ||
2444 | } | ||
2445 | i=cmd_out(); | ||
2446 | if (i<0) return (i); | ||
2447 | i=0; | ||
2448 | current_drive->sense_byte=0; | ||
2449 | if (fam1_drive) current_drive->sense_byte=infobuf[i++]; | ||
2450 | else if (famT_drive) | ||
2451 | { | ||
2452 | if (infobuf[4]==0x01) current_drive->xa_byte=0x20; | ||
2453 | else current_drive->xa_byte=0; | ||
2454 | i=2; | ||
2455 | } | ||
2456 | current_drive->frame_size=make16(infobuf[i],infobuf[i+1]); | ||
2457 | for (i=0;i<response_count;i++) | ||
2458 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
2459 | msgbuf[i*3]=0; | ||
2460 | msg(DBG_XA1,"cc_ModeSense:%s\n", msgbuf); | ||
2461 | |||
2462 | current_drive->diskstate_flags |= frame_size_bit; | ||
2463 | return (0); | ||
2464 | } | ||
2465 | /*==========================================================================*/ | ||
2466 | /*==========================================================================*/ | ||
2467 | static int cc_ModeSelect(int framesize) | ||
2468 | { | ||
2469 | int i; | ||
2470 | |||
2471 | if (fam2_drive) return (0); | ||
2472 | if (famV_drive) return (0); | ||
2473 | current_drive->diskstate_flags &= ~frame_size_bit; | ||
2474 | clr_cmdbuf(); | ||
2475 | current_drive->frame_size=framesize; | ||
2476 | if (framesize==CD_FRAMESIZE_RAW) current_drive->sense_byte=0x82; | ||
2477 | else current_drive->sense_byte=0x00; | ||
2478 | |||
2479 | msg(DBG_XA1,"cc_ModeSelect: %02X %04X\n", | ||
2480 | current_drive->sense_byte, current_drive->frame_size); | ||
2481 | |||
2482 | if (fam1_drive) | ||
2483 | { | ||
2484 | drvcmd[0]=CMD1_SETMODE; | ||
2485 | drvcmd[1]=0x00; | ||
2486 | drvcmd[2]=current_drive->sense_byte; | ||
2487 | drvcmd[3]=(current_drive->frame_size>>8)&0xFF; | ||
2488 | drvcmd[4]=current_drive->frame_size&0xFF; | ||
2489 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2490 | } | ||
2491 | else if (fam0L_drive) | ||
2492 | { | ||
2493 | drvcmd[0]=CMD0_SETMODE; | ||
2494 | drvcmd[1]=0x00; | ||
2495 | drvcmd[2]=(current_drive->frame_size>>8)&0xFF; | ||
2496 | drvcmd[3]=current_drive->frame_size&0xFF; | ||
2497 | drvcmd[4]=0x00; | ||
2498 | if(famL_drive) | ||
2499 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2500 | else | ||
2501 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2502 | } | ||
2503 | else if (famT_drive) | ||
2504 | { | ||
2505 | return (-1); | ||
2506 | } | ||
2507 | response_count=0; | ||
2508 | i=cmd_out(); | ||
2509 | if (i<0) return (i); | ||
2510 | current_drive->diskstate_flags |= frame_size_bit; | ||
2511 | return (0); | ||
2512 | } | ||
2513 | /*==========================================================================*/ | ||
2514 | static int cc_GetVolume(void) | ||
2515 | { | ||
2516 | int i; | ||
2517 | u_char switches; | ||
2518 | u_char chan0=0; | ||
2519 | u_char vol0=0; | ||
2520 | u_char chan1=1; | ||
2521 | u_char vol1=0; | ||
2522 | |||
2523 | if (famV_drive) return (0); | ||
2524 | current_drive->diskstate_flags &= ~volume_bit; | ||
2525 | clr_cmdbuf(); | ||
2526 | if (fam1_drive) | ||
2527 | { | ||
2528 | drvcmd[0]=CMD1_GETMODE; | ||
2529 | drvcmd[1]=0x05; | ||
2530 | response_count=5; | ||
2531 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2532 | } | ||
2533 | else if (fam2_drive) | ||
2534 | { | ||
2535 | drvcmd[0]=CMD2_GETMODE; | ||
2536 | drvcmd[1]=0x0E; | ||
2537 | response_count=5; | ||
2538 | flags_cmd_out=f_putcmd; | ||
2539 | } | ||
2540 | else if (fam0L_drive) | ||
2541 | { | ||
2542 | drvcmd[0]=CMD0_GETMODE; | ||
2543 | drvcmd[1]=0x03; | ||
2544 | response_count=2; | ||
2545 | if(famL_drive) | ||
2546 | flags_cmd_out=f_putcmd; | ||
2547 | else | ||
2548 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2549 | } | ||
2550 | else if (famT_drive) | ||
2551 | { | ||
2552 | i=cc_get_mode_T(); | ||
2553 | if (i<0) return (i); | ||
2554 | } | ||
2555 | if (!famT_drive) | ||
2556 | { | ||
2557 | i=cmd_out(); | ||
2558 | if (i<0) return (i); | ||
2559 | } | ||
2560 | if (fam1_drive) | ||
2561 | { | ||
2562 | chan0=infobuf[1]&0x0F; | ||
2563 | vol0=infobuf[2]; | ||
2564 | chan1=infobuf[3]&0x0F; | ||
2565 | vol1=infobuf[4]; | ||
2566 | if (chan0==0) | ||
2567 | { | ||
2568 | chan0=1; | ||
2569 | vol0=0; | ||
2570 | } | ||
2571 | if (chan1==0) | ||
2572 | { | ||
2573 | chan1=2; | ||
2574 | vol1=0; | ||
2575 | } | ||
2576 | chan0 >>= 1; | ||
2577 | chan1 >>= 1; | ||
2578 | } | ||
2579 | else if (fam2_drive) | ||
2580 | { | ||
2581 | chan0=infobuf[1]; | ||
2582 | vol0=infobuf[2]; | ||
2583 | chan1=infobuf[3]; | ||
2584 | vol1=infobuf[4]; | ||
2585 | } | ||
2586 | else if (famL_drive) | ||
2587 | { | ||
2588 | chan0=0; | ||
2589 | chan1=1; | ||
2590 | vol0=vol1=infobuf[1]; | ||
2591 | switches=infobuf[0]; | ||
2592 | if ((switches&0x80)!=0) chan0=1; | ||
2593 | if ((switches&0x40)!=0) chan1=0; | ||
2594 | } | ||
2595 | else if (fam0_drive) /* different firmware levels */ | ||
2596 | { | ||
2597 | chan0=0; | ||
2598 | chan1=1; | ||
2599 | vol0=vol1=infobuf[1]; | ||
2600 | if (current_drive->drv_type>=drv_201) | ||
2601 | { | ||
2602 | if (current_drive->drv_type<drv_300) | ||
2603 | { | ||
2604 | switches=infobuf[0]; | ||
2605 | if ((switches&0x80)!=0) vol0=0; | ||
2606 | if ((switches&0x40)!=0) vol1=0; | ||
2607 | if (current_drive->drv_type>=drv_211) | ||
2608 | { | ||
2609 | if ((switches&0x20)!=0) chan0=1; | ||
2610 | if ((switches&0x10)!=0) chan1=0; | ||
2611 | } | ||
2612 | } | ||
2613 | else | ||
2614 | { | ||
2615 | vol0=infobuf[0]; | ||
2616 | if ((vol0&0x01)!=0) chan0=1; | ||
2617 | if ((vol1&0x01)==0) chan1=0; | ||
2618 | vol0 &= 0xFC; | ||
2619 | vol1 &= 0xFC; | ||
2620 | if (vol0!=0) vol0 += 3; | ||
2621 | if (vol1!=0) vol1 += 3; | ||
2622 | } | ||
2623 | } | ||
2624 | } | ||
2625 | else if (famT_drive) | ||
2626 | { | ||
2627 | current_drive->volume_control=infobuf[7]; | ||
2628 | chan0=0; | ||
2629 | chan1=1; | ||
2630 | if (current_drive->volume_control&0x10) vol0=0; | ||
2631 | else vol0=0xff; | ||
2632 | if (current_drive->volume_control&0x20) vol1=0; | ||
2633 | else vol1=0xff; | ||
2634 | } | ||
2635 | current_drive->vol_chan0=chan0; | ||
2636 | current_drive->vol_ctrl0=vol0; | ||
2637 | current_drive->vol_chan1=chan1; | ||
2638 | current_drive->vol_ctrl1=vol1; | ||
2639 | #if 000 | ||
2640 | current_drive->vol_chan2=2; | ||
2641 | current_drive->vol_ctrl2=0xFF; | ||
2642 | current_drive->vol_chan3=3; | ||
2643 | current_drive->vol_ctrl3=0xFF; | ||
2644 | #endif /* 000 */ | ||
2645 | current_drive->diskstate_flags |= volume_bit; | ||
2646 | return (0); | ||
2647 | } | ||
2648 | /*==========================================================================*/ | ||
2649 | static int cc_ReadCapacity(void) | ||
2650 | { | ||
2651 | int i, j; | ||
2652 | |||
2653 | if (fam2_drive) return (0); /* some firmware lacks this command */ | ||
2654 | if (famLV_drive) return (0); /* some firmware lacks this command */ | ||
2655 | if (famT_drive) return (0); /* done with cc_ReadTocDescr() */ | ||
2656 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
2657 | for (j=3;j>0;j--) | ||
2658 | { | ||
2659 | clr_cmdbuf(); | ||
2660 | if (fam1_drive) | ||
2661 | { | ||
2662 | drvcmd[0]=CMD1_CAPACITY; | ||
2663 | response_count=5; | ||
2664 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2665 | } | ||
2666 | #if 00 | ||
2667 | else if (fam2_drive) | ||
2668 | { | ||
2669 | drvcmd[0]=CMD2_CAPACITY; | ||
2670 | response_count=8; | ||
2671 | flags_cmd_out=f_putcmd; | ||
2672 | } | ||
2673 | #endif | ||
2674 | else if (fam0_drive) | ||
2675 | { | ||
2676 | drvcmd[0]=CMD0_CAPACITY; | ||
2677 | response_count=5; | ||
2678 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2679 | } | ||
2680 | i=cmd_out(); | ||
2681 | if (i>=0) break; | ||
2682 | msg(DBG_000,"cc_ReadCapacity: cmd_out: err %d\n", i); | ||
2683 | cc_ReadError(); | ||
2684 | } | ||
2685 | if (j==0) return (i); | ||
2686 | if (fam1_drive) current_drive->CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_MSF_OFFSET; | ||
2687 | else if (fam0_drive) current_drive->CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])); | ||
2688 | #if 00 | ||
2689 | else if (fam2_drive) current_drive->CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3])); | ||
2690 | #endif | ||
2691 | current_drive->diskstate_flags |= cd_size_bit; | ||
2692 | msg(DBG_000,"cc_ReadCapacity: %d frames.\n", current_drive->CDsize_frm); | ||
2693 | return (0); | ||
2694 | } | ||
2695 | /*==========================================================================*/ | ||
2696 | static int cc_ReadTocDescr(void) | ||
2697 | { | ||
2698 | int i; | ||
2699 | |||
2700 | current_drive->diskstate_flags &= ~toc_bit; | ||
2701 | clr_cmdbuf(); | ||
2702 | if (fam1_drive) | ||
2703 | { | ||
2704 | drvcmd[0]=CMD1_DISKINFO; | ||
2705 | response_count=6; | ||
2706 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2707 | } | ||
2708 | else if (fam0LV_drive) | ||
2709 | { | ||
2710 | drvcmd[0]=CMD0_DISKINFO; | ||
2711 | response_count=6; | ||
2712 | if(famLV_drive) | ||
2713 | flags_cmd_out=f_putcmd; | ||
2714 | else | ||
2715 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2716 | } | ||
2717 | else if (fam2_drive) | ||
2718 | { | ||
2719 | /* possibly longer timeout periods necessary */ | ||
2720 | current_drive->f_multisession=0; | ||
2721 | drvcmd[0]=CMD2_DISKINFO; | ||
2722 | drvcmd[1]=0x02; | ||
2723 | drvcmd[2]=0xAB; | ||
2724 | drvcmd[3]=0xFF; /* session */ | ||
2725 | response_count=8; | ||
2726 | flags_cmd_out=f_putcmd; | ||
2727 | } | ||
2728 | else if (famT_drive) | ||
2729 | { | ||
2730 | current_drive->f_multisession=0; | ||
2731 | response_count=12; | ||
2732 | drvcmd[0]=CMDT_DISKINFO; | ||
2733 | drvcmd[1]=0x02; | ||
2734 | drvcmd[6]=CDROM_LEADOUT; | ||
2735 | drvcmd[8]=response_count; | ||
2736 | drvcmd[9]=0x00; | ||
2737 | } | ||
2738 | i=cmd_out(); | ||
2739 | if (i<0) return (i); | ||
2740 | if ((famT_drive)&&(i<response_count)) return (-100-i); | ||
2741 | if ((fam1_drive)||(fam2_drive)||(fam0LV_drive)) | ||
2742 | current_drive->xa_byte=infobuf[0]; | ||
2743 | if (fam2_drive) | ||
2744 | { | ||
2745 | current_drive->first_session=infobuf[1]; | ||
2746 | current_drive->last_session=infobuf[2]; | ||
2747 | current_drive->n_first_track=infobuf[3]; | ||
2748 | current_drive->n_last_track=infobuf[4]; | ||
2749 | if (current_drive->first_session!=current_drive->last_session) | ||
2750 | { | ||
2751 | current_drive->f_multisession=1; | ||
2752 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7]))); | ||
2753 | } | ||
2754 | #if 0 | ||
2755 | if (current_drive->first_session!=current_drive->last_session) | ||
2756 | { | ||
2757 | if (current_drive->last_session<=20) | ||
2758 | zwanzig=current_drive->last_session+1; | ||
2759 | else zwanzig=20; | ||
2760 | for (count=current_drive->first_session;count<zwanzig;count++) | ||
2761 | { | ||
2762 | drvcmd[0]=CMD2_DISKINFO; | ||
2763 | drvcmd[1]=0x02; | ||
2764 | drvcmd[2]=0xAB; | ||
2765 | drvcmd[3]=count; | ||
2766 | response_count=8; | ||
2767 | flags_cmd_out=f_putcmd; | ||
2768 | i=cmd_out(); | ||
2769 | if (i<0) return (i); | ||
2770 | current_drive->msf_multi_n[count]=make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7])); | ||
2771 | } | ||
2772 | current_drive->diskstate_flags |= multisession_bit; | ||
2773 | } | ||
2774 | #endif | ||
2775 | drvcmd[0]=CMD2_DISKINFO; | ||
2776 | drvcmd[1]=0x02; | ||
2777 | drvcmd[2]=0xAA; | ||
2778 | drvcmd[3]=0xFF; | ||
2779 | response_count=5; | ||
2780 | flags_cmd_out=f_putcmd; | ||
2781 | i=cmd_out(); | ||
2782 | if (i<0) return (i); | ||
2783 | current_drive->size_msf=make32(make16(0,infobuf[2]),make16(infobuf[3],infobuf[4])); | ||
2784 | current_drive->size_blk=msf2blk(current_drive->size_msf); | ||
2785 | current_drive->CDsize_frm=current_drive->size_blk+1; | ||
2786 | } | ||
2787 | else if (famT_drive) | ||
2788 | { | ||
2789 | current_drive->size_msf=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11])); | ||
2790 | current_drive->size_blk=msf2blk(current_drive->size_msf); | ||
2791 | current_drive->CDsize_frm=current_drive->size_blk+1; | ||
2792 | current_drive->n_first_track=infobuf[2]; | ||
2793 | current_drive->n_last_track=infobuf[3]; | ||
2794 | } | ||
2795 | else | ||
2796 | { | ||
2797 | current_drive->n_first_track=infobuf[1]; | ||
2798 | current_drive->n_last_track=infobuf[2]; | ||
2799 | current_drive->size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5])); | ||
2800 | current_drive->size_blk=msf2blk(current_drive->size_msf); | ||
2801 | if (famLV_drive) current_drive->CDsize_frm=current_drive->size_blk+1; | ||
2802 | } | ||
2803 | current_drive->diskstate_flags |= toc_bit; | ||
2804 | msg(DBG_TOC,"TocDesc: xa %02X firstt %02X lastt %02X size %08X firstses %02X lastsess %02X\n", | ||
2805 | current_drive->xa_byte, | ||
2806 | current_drive->n_first_track, | ||
2807 | current_drive->n_last_track, | ||
2808 | current_drive->size_msf, | ||
2809 | current_drive->first_session, | ||
2810 | current_drive->last_session); | ||
2811 | return (0); | ||
2812 | } | ||
2813 | /*==========================================================================*/ | ||
2814 | static int cc_ReadTocEntry(int num) | ||
2815 | { | ||
2816 | int i; | ||
2817 | |||
2818 | clr_cmdbuf(); | ||
2819 | if (fam1_drive) | ||
2820 | { | ||
2821 | drvcmd[0]=CMD1_READTOC; | ||
2822 | drvcmd[2]=num; | ||
2823 | response_count=8; | ||
2824 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2825 | } | ||
2826 | else if (fam2_drive) | ||
2827 | { | ||
2828 | /* possibly longer timeout periods necessary */ | ||
2829 | drvcmd[0]=CMD2_DISKINFO; | ||
2830 | drvcmd[1]=0x02; | ||
2831 | drvcmd[2]=num; | ||
2832 | response_count=5; | ||
2833 | flags_cmd_out=f_putcmd; | ||
2834 | } | ||
2835 | else if (fam0LV_drive) | ||
2836 | { | ||
2837 | drvcmd[0]=CMD0_READTOC; | ||
2838 | drvcmd[1]=0x02; | ||
2839 | drvcmd[2]=num; | ||
2840 | response_count=8; | ||
2841 | if (famLV_drive) | ||
2842 | flags_cmd_out=f_putcmd; | ||
2843 | else | ||
2844 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2845 | } | ||
2846 | else if (famT_drive) | ||
2847 | { | ||
2848 | response_count=12; | ||
2849 | drvcmd[0]=CMDT_DISKINFO; | ||
2850 | drvcmd[1]=0x02; | ||
2851 | drvcmd[6]=num; | ||
2852 | drvcmd[8]=response_count; | ||
2853 | drvcmd[9]=0x00; | ||
2854 | } | ||
2855 | i=cmd_out(); | ||
2856 | if (i<0) return (i); | ||
2857 | if ((famT_drive)&&(i<response_count)) return (-100-i); | ||
2858 | if ((fam1_drive)||(fam0LV_drive)) | ||
2859 | { | ||
2860 | current_drive->TocEnt_nixbyte=infobuf[0]; | ||
2861 | i=1; | ||
2862 | } | ||
2863 | else if (fam2_drive) i=0; | ||
2864 | else if (famT_drive) i=5; | ||
2865 | current_drive->TocEnt_ctl_adr=swap_nibbles(infobuf[i++]); | ||
2866 | if ((fam1_drive)||(fam0L_drive)) | ||
2867 | { | ||
2868 | current_drive->TocEnt_number=infobuf[i++]; | ||
2869 | current_drive->TocEnt_format=infobuf[i]; | ||
2870 | } | ||
2871 | else | ||
2872 | { | ||
2873 | current_drive->TocEnt_number=num; | ||
2874 | current_drive->TocEnt_format=0; | ||
2875 | } | ||
2876 | if (fam1_drive) i=4; | ||
2877 | else if (fam0LV_drive) i=5; | ||
2878 | else if (fam2_drive) i=2; | ||
2879 | else if (famT_drive) i=9; | ||
2880 | current_drive->TocEnt_address=make32(make16(0,infobuf[i]), | ||
2881 | make16(infobuf[i+1],infobuf[i+2])); | ||
2882 | for (i=0;i<response_count;i++) | ||
2883 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
2884 | msgbuf[i*3]=0; | ||
2885 | msg(DBG_ECS,"TocEntry:%s\n", msgbuf); | ||
2886 | msg(DBG_TOC,"TocEntry: %02X %02X %02X %02X %08X\n", | ||
2887 | current_drive->TocEnt_nixbyte, current_drive->TocEnt_ctl_adr, | ||
2888 | current_drive->TocEnt_number, current_drive->TocEnt_format, | ||
2889 | current_drive->TocEnt_address); | ||
2890 | return (0); | ||
2891 | } | ||
2892 | /*==========================================================================*/ | ||
2893 | static int cc_ReadPacket(void) | ||
2894 | { | ||
2895 | int i; | ||
2896 | |||
2897 | clr_cmdbuf(); | ||
2898 | drvcmd[0]=CMD0_PACKET; | ||
2899 | drvcmd[1]=response_count; | ||
2900 | if(famL_drive) flags_cmd_out=f_putcmd; | ||
2901 | else if (fam01_drive) | ||
2902 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2903 | else if (fam2_drive) return (-1); /* not implemented yet */ | ||
2904 | else if (famT_drive) | ||
2905 | { | ||
2906 | return (-1); | ||
2907 | } | ||
2908 | i=cmd_out(); | ||
2909 | return (i); | ||
2910 | } | ||
2911 | /*==========================================================================*/ | ||
2912 | static int convert_UPC(u_char *p) | ||
2913 | { | ||
2914 | int i; | ||
2915 | |||
2916 | p++; | ||
2917 | if (fam0L_drive) p[13]=0; | ||
2918 | for (i=0;i<7;i++) | ||
2919 | { | ||
2920 | if (fam1_drive) current_drive->UPC_buf[i]=swap_nibbles(*p++); | ||
2921 | else if (fam0L_drive) | ||
2922 | { | ||
2923 | current_drive->UPC_buf[i]=((*p++)<<4)&0xFF; | ||
2924 | current_drive->UPC_buf[i] |= *p++; | ||
2925 | } | ||
2926 | else if (famT_drive) | ||
2927 | { | ||
2928 | return (-1); | ||
2929 | } | ||
2930 | else /* CD200 */ | ||
2931 | { | ||
2932 | return (-1); | ||
2933 | } | ||
2934 | } | ||
2935 | current_drive->UPC_buf[6] &= 0xF0; | ||
2936 | return (0); | ||
2937 | } | ||
2938 | /*==========================================================================*/ | ||
2939 | static int cc_ReadUPC(void) | ||
2940 | { | ||
2941 | int i; | ||
2942 | #if TEST_UPC | ||
2943 | int block, checksum; | ||
2944 | #endif /* TEST_UPC */ | ||
2945 | |||
2946 | if (fam2_drive) return (0); /* not implemented yet */ | ||
2947 | if (famT_drive) return (0); /* not implemented yet */ | ||
2948 | if (famV_drive) return (0); /* not implemented yet */ | ||
2949 | #if 1 | ||
2950 | if (fam0_drive) return (0); /* but it should work */ | ||
2951 | #endif | ||
2952 | |||
2953 | current_drive->diskstate_flags &= ~upc_bit; | ||
2954 | #if TEST_UPC | ||
2955 | for (block=CD_MSF_OFFSET+1;block<CD_MSF_OFFSET+200;block++) | ||
2956 | { | ||
2957 | #endif /* TEST_UPC */ | ||
2958 | clr_cmdbuf(); | ||
2959 | if (fam1_drive) | ||
2960 | { | ||
2961 | drvcmd[0]=CMD1_READ_UPC; | ||
2962 | #if TEST_UPC | ||
2963 | drvcmd[1]=(block>>16)&0xFF; | ||
2964 | drvcmd[2]=(block>>8)&0xFF; | ||
2965 | drvcmd[3]=block&0xFF; | ||
2966 | #endif /* TEST_UPC */ | ||
2967 | response_count=8; | ||
2968 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2969 | } | ||
2970 | else if (fam0L_drive) | ||
2971 | { | ||
2972 | drvcmd[0]=CMD0_READ_UPC; | ||
2973 | #if TEST_UPC | ||
2974 | drvcmd[2]=(block>>16)&0xFF; | ||
2975 | drvcmd[3]=(block>>8)&0xFF; | ||
2976 | drvcmd[4]=block&0xFF; | ||
2977 | #endif /* TEST_UPC */ | ||
2978 | response_count=0; | ||
2979 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
2980 | } | ||
2981 | else if (fam2_drive) | ||
2982 | { | ||
2983 | return (-1); | ||
2984 | } | ||
2985 | else if (famT_drive) | ||
2986 | { | ||
2987 | return (-1); | ||
2988 | } | ||
2989 | i=cmd_out(); | ||
2990 | if (i<0) | ||
2991 | { | ||
2992 | msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i); | ||
2993 | return (i); | ||
2994 | } | ||
2995 | if (fam0L_drive) | ||
2996 | { | ||
2997 | response_count=16; | ||
2998 | if (famL_drive) flags_cmd_out=f_putcmd; | ||
2999 | i=cc_ReadPacket(); | ||
3000 | if (i<0) | ||
3001 | { | ||
3002 | msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i); | ||
3003 | return (i); | ||
3004 | } | ||
3005 | } | ||
3006 | #if TEST_UPC | ||
3007 | checksum=0; | ||
3008 | #endif /* TEST_UPC */ | ||
3009 | for (i=0;i<(fam1_drive?8:16);i++) | ||
3010 | { | ||
3011 | #if TEST_UPC | ||
3012 | checksum |= infobuf[i]; | ||
3013 | #endif /* TEST_UPC */ | ||
3014 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3015 | } | ||
3016 | msgbuf[i*3]=0; | ||
3017 | msg(DBG_UPC,"UPC info:%s\n", msgbuf); | ||
3018 | #if TEST_UPC | ||
3019 | if ((checksum&0x7F)!=0) break; | ||
3020 | } | ||
3021 | #endif /* TEST_UPC */ | ||
3022 | current_drive->UPC_ctl_adr=0; | ||
3023 | if (fam1_drive) i=0; | ||
3024 | else i=2; | ||
3025 | if ((infobuf[i]&0x80)!=0) | ||
3026 | { | ||
3027 | convert_UPC(&infobuf[i]); | ||
3028 | current_drive->UPC_ctl_adr = (current_drive->TocEnt_ctl_adr & 0xF0) | 0x02; | ||
3029 | } | ||
3030 | for (i=0;i<7;i++) | ||
3031 | sprintf(&msgbuf[i*3], " %02X", current_drive->UPC_buf[i]); | ||
3032 | sprintf(&msgbuf[i*3], " (%02X)", current_drive->UPC_ctl_adr); | ||
3033 | msgbuf[i*3+5]=0; | ||
3034 | msg(DBG_UPC,"UPC code:%s\n", msgbuf); | ||
3035 | current_drive->diskstate_flags |= upc_bit; | ||
3036 | return (0); | ||
3037 | } | ||
3038 | |||
3039 | static int sbpcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) | ||
3040 | { | ||
3041 | int i; | ||
3042 | unsigned char *mcnp = mcn->medium_catalog_number; | ||
3043 | unsigned char *resp; | ||
3044 | |||
3045 | current_drive->diskstate_flags &= ~upc_bit; | ||
3046 | clr_cmdbuf(); | ||
3047 | if (fam1_drive) | ||
3048 | { | ||
3049 | drvcmd[0]=CMD1_READ_UPC; | ||
3050 | response_count=8; | ||
3051 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
3052 | } | ||
3053 | else if (fam0L_drive) | ||
3054 | { | ||
3055 | drvcmd[0]=CMD0_READ_UPC; | ||
3056 | response_count=0; | ||
3057 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
3058 | } | ||
3059 | else if (fam2_drive) | ||
3060 | { | ||
3061 | return (-1); | ||
3062 | } | ||
3063 | else if (famT_drive) | ||
3064 | { | ||
3065 | return (-1); | ||
3066 | } | ||
3067 | i=cmd_out(); | ||
3068 | if (i<0) | ||
3069 | { | ||
3070 | msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i); | ||
3071 | return (i); | ||
3072 | } | ||
3073 | if (fam0L_drive) | ||
3074 | { | ||
3075 | response_count=16; | ||
3076 | if (famL_drive) flags_cmd_out=f_putcmd; | ||
3077 | i=cc_ReadPacket(); | ||
3078 | if (i<0) | ||
3079 | { | ||
3080 | msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i); | ||
3081 | return (i); | ||
3082 | } | ||
3083 | } | ||
3084 | current_drive->UPC_ctl_adr=0; | ||
3085 | if (fam1_drive) i=0; | ||
3086 | else i=2; | ||
3087 | |||
3088 | resp = infobuf + i; | ||
3089 | if (*resp++ == 0x80) { | ||
3090 | /* packed bcd to single ASCII digits */ | ||
3091 | *mcnp++ = (*resp >> 4) + '0'; | ||
3092 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3093 | *mcnp++ = (*resp >> 4) + '0'; | ||
3094 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3095 | *mcnp++ = (*resp >> 4) + '0'; | ||
3096 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3097 | *mcnp++ = (*resp >> 4) + '0'; | ||
3098 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3099 | *mcnp++ = (*resp >> 4) + '0'; | ||
3100 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3101 | *mcnp++ = (*resp >> 4) + '0'; | ||
3102 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3103 | *mcnp++ = (*resp >> 4) + '0'; | ||
3104 | } | ||
3105 | *mcnp = '\0'; | ||
3106 | |||
3107 | current_drive->diskstate_flags |= upc_bit; | ||
3108 | return (0); | ||
3109 | } | ||
3110 | |||
3111 | /*==========================================================================*/ | ||
3112 | static int cc_CheckMultiSession(void) | ||
3113 | { | ||
3114 | int i; | ||
3115 | |||
3116 | if (fam2_drive) return (0); | ||
3117 | current_drive->f_multisession=0; | ||
3118 | current_drive->lba_multi=0; | ||
3119 | if (fam0_drive) return (0); | ||
3120 | clr_cmdbuf(); | ||
3121 | if (fam1_drive) | ||
3122 | { | ||
3123 | drvcmd[0]=CMD1_MULTISESS; | ||
3124 | response_count=6; | ||
3125 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
3126 | i=cmd_out(); | ||
3127 | if (i<0) return (i); | ||
3128 | if ((infobuf[0]&0x80)!=0) | ||
3129 | { | ||
3130 | current_drive->f_multisession=1; | ||
3131 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[1]), | ||
3132 | make16(infobuf[2],infobuf[3]))); | ||
3133 | } | ||
3134 | } | ||
3135 | else if (famLV_drive) | ||
3136 | { | ||
3137 | drvcmd[0]=CMDL_MULTISESS; | ||
3138 | drvcmd[1]=3; | ||
3139 | drvcmd[2]=1; | ||
3140 | response_count=8; | ||
3141 | flags_cmd_out=f_putcmd; | ||
3142 | i=cmd_out(); | ||
3143 | if (i<0) return (i); | ||
3144 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]), | ||
3145 | make16(infobuf[6],infobuf[7]))); | ||
3146 | } | ||
3147 | else if (famT_drive) | ||
3148 | { | ||
3149 | response_count=12; | ||
3150 | drvcmd[0]=CMDT_DISKINFO; | ||
3151 | drvcmd[1]=0x02; | ||
3152 | drvcmd[6]=0; | ||
3153 | drvcmd[8]=response_count; | ||
3154 | drvcmd[9]=0x40; | ||
3155 | i=cmd_out(); | ||
3156 | if (i<0) return (i); | ||
3157 | if (i<response_count) return (-100-i); | ||
3158 | current_drive->first_session=infobuf[2]; | ||
3159 | current_drive->last_session=infobuf[3]; | ||
3160 | current_drive->track_of_last_session=infobuf[6]; | ||
3161 | if (current_drive->first_session!=current_drive->last_session) | ||
3162 | { | ||
3163 | current_drive->f_multisession=1; | ||
3164 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[9]),make16(infobuf[10],infobuf[11]))); | ||
3165 | } | ||
3166 | } | ||
3167 | for (i=0;i<response_count;i++) | ||
3168 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3169 | msgbuf[i*3]=0; | ||
3170 | msg(DBG_MUL,"MultiSession Info:%s (%d)\n", msgbuf, current_drive->lba_multi); | ||
3171 | if (current_drive->lba_multi>200) | ||
3172 | { | ||
3173 | current_drive->f_multisession=1; | ||
3174 | msg(DBG_MUL,"MultiSession base: %06X\n", current_drive->lba_multi); | ||
3175 | } | ||
3176 | return (0); | ||
3177 | } | ||
3178 | /*==========================================================================*/ | ||
3179 | #ifdef FUTURE | ||
3180 | static int cc_SubChanInfo(int frame, int count, u_char *buffer) | ||
3181 | /* "frame" is a RED BOOK (msf-bin) address */ | ||
3182 | { | ||
3183 | int i; | ||
3184 | |||
3185 | if (fam0LV_drive) return (-ENOSYS); /* drive firmware lacks it */ | ||
3186 | if (famT_drive) | ||
3187 | { | ||
3188 | return (-1); | ||
3189 | } | ||
3190 | #if 0 | ||
3191 | if (current_drive->audio_state!=audio_playing) return (-ENODATA); | ||
3192 | #endif | ||
3193 | clr_cmdbuf(); | ||
3194 | drvcmd[0]=CMD1_SUBCHANINF; | ||
3195 | drvcmd[1]=(frame>>16)&0xFF; | ||
3196 | drvcmd[2]=(frame>>8)&0xFF; | ||
3197 | drvcmd[3]=frame&0xFF; | ||
3198 | drvcmd[5]=(count>>8)&0xFF; | ||
3199 | drvcmd[6]=count&0xFF; | ||
3200 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
3201 | cmd_type=READ_SC; | ||
3202 | current_drive->frame_size=CD_FRAMESIZE_SUB; | ||
3203 | i=cmd_out(); /* which buffer to use? */ | ||
3204 | return (i); | ||
3205 | } | ||
3206 | #endif /* FUTURE */ | ||
3207 | /*==========================================================================*/ | ||
3208 | static void __init check_datarate(void) | ||
3209 | { | ||
3210 | int i=0; | ||
3211 | |||
3212 | msg(DBG_IOX,"check_datarate entered.\n"); | ||
3213 | datarate=0; | ||
3214 | #if TEST_STI | ||
3215 | for (i=0;i<=1000;i++) printk("."); | ||
3216 | #endif | ||
3217 | /* set a timer to make (timed_out_delay!=0) after 1.1 seconds */ | ||
3218 | #if 1 | ||
3219 | del_timer(&delay_timer); | ||
3220 | #endif | ||
3221 | delay_timer.expires=jiffies+11*HZ/10; | ||
3222 | timed_out_delay=0; | ||
3223 | add_timer(&delay_timer); | ||
3224 | #if 0 | ||
3225 | msg(DBG_TIM,"delay timer started (11*HZ/10).\n"); | ||
3226 | #endif | ||
3227 | do | ||
3228 | { | ||
3229 | i=inb(CDi_status); | ||
3230 | datarate++; | ||
3231 | #if 1 | ||
3232 | if (datarate>0x6FFFFFFF) break; | ||
3233 | #endif | ||
3234 | } | ||
3235 | while (!timed_out_delay); | ||
3236 | del_timer(&delay_timer); | ||
3237 | #if 0 | ||
3238 | msg(DBG_TIM,"datarate: %04X\n", datarate); | ||
3239 | #endif | ||
3240 | if (datarate<65536) datarate=65536; | ||
3241 | maxtim16=datarate*16; | ||
3242 | maxtim04=datarate*4; | ||
3243 | maxtim02=datarate*2; | ||
3244 | maxtim_8=datarate/32; | ||
3245 | #if LONG_TIMING | ||
3246 | maxtim_data=datarate/100; | ||
3247 | #else | ||
3248 | maxtim_data=datarate/300; | ||
3249 | #endif /* LONG_TIMING */ | ||
3250 | #if 0 | ||
3251 | msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data); | ||
3252 | #endif | ||
3253 | } | ||
3254 | /*==========================================================================*/ | ||
3255 | #if 0 | ||
3256 | static int c2_ReadError(int fam) | ||
3257 | { | ||
3258 | int i; | ||
3259 | |||
3260 | clr_cmdbuf(); | ||
3261 | response_count=9; | ||
3262 | clr_respo_buf(9); | ||
3263 | if (fam==1) | ||
3264 | { | ||
3265 | drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */ | ||
3266 | i=do_cmd(f_putcmd|f_lopsta|f_getsta|f_ResponseStatus); | ||
3267 | } | ||
3268 | else if (fam==2) | ||
3269 | { | ||
3270 | drvcmd[0]=CMD2_READ_ERR; | ||
3271 | i=do_cmd(f_putcmd); | ||
3272 | } | ||
3273 | else return (-1); | ||
3274 | return (i); | ||
3275 | } | ||
3276 | #endif | ||
3277 | /*==========================================================================*/ | ||
3278 | static void __init ask_mail(void) | ||
3279 | { | ||
3280 | int i; | ||
3281 | |||
3282 | msg(DBG_INF, "please mail the following lines to emoenke@gwdg.de\n"); | ||
3283 | msg(DBG_INF, "(don't mail if you are not using the actual kernel):\n"); | ||
3284 | msg(DBG_INF, "%s\n", VERSION); | ||
3285 | msg(DBG_INF, "address %03X, type %s, drive %s (ID %d)\n", | ||
3286 | CDo_command, type, current_drive->drive_model, current_drive->drv_id); | ||
3287 | for (i=0;i<12;i++) | ||
3288 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3289 | msgbuf[i*3]=0; | ||
3290 | msg(DBG_INF,"infobuf =%s\n", msgbuf); | ||
3291 | for (i=0;i<12;i++) | ||
3292 | sprintf(&msgbuf[i*3], " %c ", infobuf[i]); | ||
3293 | msgbuf[i*3]=0; | ||
3294 | msg(DBG_INF,"infobuf =%s\n", msgbuf); | ||
3295 | } | ||
3296 | /*==========================================================================*/ | ||
3297 | static int __init check_version(void) | ||
3298 | { | ||
3299 | int i, j, l; | ||
3300 | int teac_possible=0; | ||
3301 | |||
3302 | msg(DBG_INI,"check_version: id=%d, d=%d.\n", current_drive->drv_id, current_drive - D_S); | ||
3303 | current_drive->drv_type=0; | ||
3304 | |||
3305 | /* check for CR-52x, CR-56x, LCS-7260 and ECS-AT */ | ||
3306 | /* clear any pending error state */ | ||
3307 | clr_cmdbuf(); | ||
3308 | drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */ | ||
3309 | response_count=9; | ||
3310 | flags_cmd_out=f_putcmd; | ||
3311 | i=cmd_out(); | ||
3312 | if (i<0) msg(DBG_INI,"CMD0_READ_ERR returns %d (ok anyway).\n",i); | ||
3313 | /* read drive version */ | ||
3314 | clr_cmdbuf(); | ||
3315 | for (i=0;i<12;i++) infobuf[i]=0; | ||
3316 | drvcmd[0]=CMD0_READ_VER; /* same as CMD1_ and CMDL_ */ | ||
3317 | response_count=12; /* fam1: only 11 */ | ||
3318 | flags_cmd_out=f_putcmd; | ||
3319 | i=cmd_out(); | ||
3320 | if (i<-1) msg(DBG_INI,"CMD0_READ_VER returns %d\n",i); | ||
3321 | if (i==-11) teac_possible++; | ||
3322 | j=0; | ||
3323 | for (i=0;i<12;i++) j+=infobuf[i]; | ||
3324 | if (j) | ||
3325 | { | ||
3326 | for (i=0;i<12;i++) | ||
3327 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3328 | msgbuf[i*3]=0; | ||
3329 | msg(DBG_ECS,"infobuf =%s\n", msgbuf); | ||
3330 | for (i=0;i<12;i++) | ||
3331 | sprintf(&msgbuf[i*3], " %c ", infobuf[i]); | ||
3332 | msgbuf[i*3]=0; | ||
3333 | msg(DBG_ECS,"infobuf =%s\n", msgbuf); | ||
3334 | } | ||
3335 | for (i=0;i<4;i++) if (infobuf[i]!=family1[i]) break; | ||
3336 | if (i==4) | ||
3337 | { | ||
3338 | current_drive->drive_model[0]='C'; | ||
3339 | current_drive->drive_model[1]='R'; | ||
3340 | current_drive->drive_model[2]='-'; | ||
3341 | current_drive->drive_model[3]='5'; | ||
3342 | current_drive->drive_model[4]=infobuf[i++]; | ||
3343 | current_drive->drive_model[5]=infobuf[i++]; | ||
3344 | current_drive->drive_model[6]=0; | ||
3345 | current_drive->drv_type=drv_fam1; | ||
3346 | } | ||
3347 | if (!current_drive->drv_type) | ||
3348 | { | ||
3349 | for (i=0;i<8;i++) if (infobuf[i]!=family0[i]) break; | ||
3350 | if (i==8) | ||
3351 | { | ||
3352 | current_drive->drive_model[0]='C'; | ||
3353 | current_drive->drive_model[1]='R'; | ||
3354 | current_drive->drive_model[2]='-'; | ||
3355 | current_drive->drive_model[3]='5'; | ||
3356 | current_drive->drive_model[4]='2'; | ||
3357 | current_drive->drive_model[5]='x'; | ||
3358 | current_drive->drive_model[6]=0; | ||
3359 | current_drive->drv_type=drv_fam0; | ||
3360 | } | ||
3361 | } | ||
3362 | if (!current_drive->drv_type) | ||
3363 | { | ||
3364 | for (i=0;i<8;i++) if (infobuf[i]!=familyL[i]) break; | ||
3365 | if (i==8) | ||
3366 | { | ||
3367 | for (j=0;j<8;j++) | ||
3368 | current_drive->drive_model[j]=infobuf[j]; | ||
3369 | current_drive->drive_model[8]=0; | ||
3370 | current_drive->drv_type=drv_famL; | ||
3371 | } | ||
3372 | } | ||
3373 | if (!current_drive->drv_type) | ||
3374 | { | ||
3375 | for (i=0;i<6;i++) if (infobuf[i]!=familyV[i]) break; | ||
3376 | if (i==6) | ||
3377 | { | ||
3378 | for (j=0;j<6;j++) | ||
3379 | current_drive->drive_model[j]=infobuf[j]; | ||
3380 | current_drive->drive_model[6]=0; | ||
3381 | current_drive->drv_type=drv_famV; | ||
3382 | i+=2; /* 2 blanks before version */ | ||
3383 | } | ||
3384 | } | ||
3385 | if (!current_drive->drv_type) | ||
3386 | { | ||
3387 | /* check for CD200 */ | ||
3388 | clr_cmdbuf(); | ||
3389 | drvcmd[0]=CMD2_READ_ERR; | ||
3390 | response_count=9; | ||
3391 | flags_cmd_out=f_putcmd; | ||
3392 | i=cmd_out(); | ||
3393 | if (i<0) msg(DBG_INI,"CMD2_READERR returns %d (ok anyway).\n",i); | ||
3394 | if (i<0) msg(DBG_000,"CMD2_READERR returns %d (ok anyway).\n",i); | ||
3395 | /* read drive version */ | ||
3396 | clr_cmdbuf(); | ||
3397 | for (i=0;i<12;i++) infobuf[i]=0; | ||
3398 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
3399 | #if 0 | ||
3400 | OUT(CDo_reset,0); | ||
3401 | sbp_sleep(6*HZ); | ||
3402 | OUT(CDo_enable,current_drive->drv_sel); | ||
3403 | #endif | ||
3404 | drvcmd[0]=CMD2_READ_VER; | ||
3405 | response_count=12; | ||
3406 | flags_cmd_out=f_putcmd; | ||
3407 | i=cmd_out(); | ||
3408 | if (i<0) msg(DBG_INI,"CMD2_READ_VER returns %d\n",i); | ||
3409 | if (i==-7) teac_possible++; | ||
3410 | j=0; | ||
3411 | for (i=0;i<12;i++) j+=infobuf[i]; | ||
3412 | if (j) | ||
3413 | { | ||
3414 | for (i=0;i<12;i++) | ||
3415 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3416 | msgbuf[i*3]=0; | ||
3417 | msg(DBG_IDX,"infobuf =%s\n", msgbuf); | ||
3418 | for (i=0;i<12;i++) | ||
3419 | sprintf(&msgbuf[i*3], " %c ", infobuf[i]); | ||
3420 | msgbuf[i*3]=0; | ||
3421 | msg(DBG_IDX,"infobuf =%s\n", msgbuf); | ||
3422 | } | ||
3423 | if (i>=0) | ||
3424 | { | ||
3425 | for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break; | ||
3426 | if (i==5) | ||
3427 | { | ||
3428 | current_drive->drive_model[0]='C'; | ||
3429 | current_drive->drive_model[1]='D'; | ||
3430 | current_drive->drive_model[2]='2'; | ||
3431 | current_drive->drive_model[3]='0'; | ||
3432 | current_drive->drive_model[4]='0'; | ||
3433 | current_drive->drive_model[5]=infobuf[i++]; | ||
3434 | current_drive->drive_model[6]=infobuf[i++]; | ||
3435 | current_drive->drive_model[7]=0; | ||
3436 | current_drive->drv_type=drv_fam2; | ||
3437 | } | ||
3438 | } | ||
3439 | } | ||
3440 | if (!current_drive->drv_type) | ||
3441 | { | ||
3442 | /* check for TEAC CD-55A */ | ||
3443 | msg(DBG_TEA,"teac_possible: %d\n",teac_possible); | ||
3444 | for (j=1;j<=((current_drive->drv_id==0)?3:1);j++) | ||
3445 | { | ||
3446 | for (l=1;l<=((current_drive->drv_id==0)?10:1);l++) | ||
3447 | { | ||
3448 | msg(DBG_TEA,"TEAC reset #%d-%d.\n", j, l); | ||
3449 | if (sbpro_type==1) OUT(CDo_reset,0); | ||
3450 | else | ||
3451 | { | ||
3452 | OUT(CDo_enable,current_drive->drv_sel); | ||
3453 | OUT(CDo_sel_i_d,0); | ||
3454 | OUT(CDo_command,CMDT_RESET); | ||
3455 | for (i=0;i<9;i++) OUT(CDo_command,0); | ||
3456 | } | ||
3457 | sbp_sleep(5*HZ/10); | ||
3458 | OUT(CDo_enable,current_drive->drv_sel); | ||
3459 | OUT(CDo_sel_i_d,0); | ||
3460 | i=inb(CDi_status); | ||
3461 | msg(DBG_TEA,"TEAC CDi_status: %02X.\n",i); | ||
3462 | #if 0 | ||
3463 | if (i&s_not_result_ready) continue; /* drive not present or ready */ | ||
3464 | #endif | ||
3465 | i=inb(CDi_info); | ||
3466 | msg(DBG_TEA,"TEAC CDi_info: %02X.\n",i); | ||
3467 | if (i==0x55) break; /* drive found */ | ||
3468 | } | ||
3469 | if (i==0x55) break; /* drive found */ | ||
3470 | } | ||
3471 | if (i==0x55) /* drive found */ | ||
3472 | { | ||
3473 | msg(DBG_TEA,"TEAC drive found.\n"); | ||
3474 | clr_cmdbuf(); | ||
3475 | flags_cmd_out=f_putcmd; | ||
3476 | response_count=12; | ||
3477 | drvcmd[0]=CMDT_READ_VER; | ||
3478 | drvcmd[4]=response_count; | ||
3479 | for (i=0;i<12;i++) infobuf[i]=0; | ||
3480 | i=cmd_out_T(); | ||
3481 | if (i!=0) msg(DBG_TEA,"cmd_out_T(CMDT_READ_VER) returns %d.\n",i); | ||
3482 | for (i=1;i<6;i++) if (infobuf[i]!=familyT[i-1]) break; | ||
3483 | if (i==6) | ||
3484 | { | ||
3485 | current_drive->drive_model[0]='C'; | ||
3486 | current_drive->drive_model[1]='D'; | ||
3487 | current_drive->drive_model[2]='-'; | ||
3488 | current_drive->drive_model[3]='5'; | ||
3489 | current_drive->drive_model[4]='5'; | ||
3490 | current_drive->drive_model[5]=0; | ||
3491 | current_drive->drv_type=drv_famT; | ||
3492 | } | ||
3493 | } | ||
3494 | } | ||
3495 | if (!current_drive->drv_type) | ||
3496 | { | ||
3497 | msg(DBG_TEA,"no drive found at address %03X under ID %d.\n",CDo_command,current_drive->drv_id); | ||
3498 | return (-522); | ||
3499 | } | ||
3500 | for (j=0;j<4;j++) current_drive->firmware_version[j]=infobuf[i+j]; | ||
3501 | if (famL_drive) | ||
3502 | { | ||
3503 | u_char lcs_firm_e1[]="A E1"; | ||
3504 | u_char lcs_firm_f4[]="A4F4"; | ||
3505 | |||
3506 | for (j=0;j<4;j++) | ||
3507 | if (current_drive->firmware_version[j]!=lcs_firm_e1[j]) break; | ||
3508 | if (j==4) current_drive->drv_type=drv_e1; | ||
3509 | |||
3510 | for (j=0;j<4;j++) | ||
3511 | if (current_drive->firmware_version[j]!=lcs_firm_f4[j]) break; | ||
3512 | if (j==4) current_drive->drv_type=drv_f4; | ||
3513 | |||
3514 | if (current_drive->drv_type==drv_famL) ask_mail(); | ||
3515 | } | ||
3516 | else if (famT_drive) | ||
3517 | { | ||
3518 | j=infobuf[4]; /* one-byte version??? - here: 0x15 */ | ||
3519 | if (j=='5') | ||
3520 | { | ||
3521 | current_drive->firmware_version[0]=infobuf[7]; | ||
3522 | current_drive->firmware_version[1]=infobuf[8]; | ||
3523 | current_drive->firmware_version[2]=infobuf[10]; | ||
3524 | current_drive->firmware_version[3]=infobuf[11]; | ||
3525 | } | ||
3526 | else | ||
3527 | { | ||
3528 | if (j!=0x15) ask_mail(); | ||
3529 | current_drive->firmware_version[0]='0'; | ||
3530 | current_drive->firmware_version[1]='.'; | ||
3531 | current_drive->firmware_version[2]='0'+(j>>4); | ||
3532 | current_drive->firmware_version[3]='0'+(j&0x0f); | ||
3533 | } | ||
3534 | } | ||
3535 | else /* CR-52x, CR-56x, CD200, ECS-AT */ | ||
3536 | { | ||
3537 | j = (current_drive->firmware_version[0] & 0x0F) * 100 + | ||
3538 | (current_drive->firmware_version[2] & 0x0F) *10 + | ||
3539 | (current_drive->firmware_version[3] & 0x0F); | ||
3540 | if (fam0_drive) | ||
3541 | { | ||
3542 | if (j<200) current_drive->drv_type=drv_199; | ||
3543 | else if (j<201) current_drive->drv_type=drv_200; | ||
3544 | else if (j<210) current_drive->drv_type=drv_201; | ||
3545 | else if (j<211) current_drive->drv_type=drv_210; | ||
3546 | else if (j<300) current_drive->drv_type=drv_211; | ||
3547 | else if (j>=300) current_drive->drv_type=drv_300; | ||
3548 | } | ||
3549 | else if (fam1_drive) | ||
3550 | { | ||
3551 | if (j<100) current_drive->drv_type=drv_099; | ||
3552 | else | ||
3553 | { | ||
3554 | current_drive->drv_type=drv_100; | ||
3555 | if ((j!=500)&&(j!=102)) ask_mail(); | ||
3556 | } | ||
3557 | } | ||
3558 | else if (fam2_drive) | ||
3559 | { | ||
3560 | if (current_drive->drive_model[5]=='F') | ||
3561 | { | ||
3562 | if ((j!=1)&&(j!=35)&&(j!=200)&&(j!=210)) | ||
3563 | ask_mail(); /* unknown version at time */ | ||
3564 | } | ||
3565 | else | ||
3566 | { | ||
3567 | msg(DBG_INF,"this CD200 drive is not fully supported yet - only audio will work.\n"); | ||
3568 | if ((j!=101)&&(j!=35)) | ||
3569 | ask_mail(); /* unknown version at time */ | ||
3570 | } | ||
3571 | } | ||
3572 | else if (famV_drive) | ||
3573 | { | ||
3574 | if ((j==100)||(j==150)) current_drive->drv_type=drv_at; | ||
3575 | ask_mail(); /* hopefully we get some feedback by this */ | ||
3576 | } | ||
3577 | } | ||
3578 | msg(DBG_LCS,"drive type %02X\n",current_drive->drv_type); | ||
3579 | msg(DBG_INI,"check_version done.\n"); | ||
3580 | return (0); | ||
3581 | } | ||
3582 | /*==========================================================================*/ | ||
3583 | static void switch_drive(struct sbpcd_drive *p) | ||
3584 | { | ||
3585 | current_drive = p; | ||
3586 | OUT(CDo_enable,current_drive->drv_sel); | ||
3587 | msg(DBG_DID,"drive %d (ID=%d) activated.\n", | ||
3588 | current_drive - D_S, current_drive->drv_id); | ||
3589 | return; | ||
3590 | } | ||
3591 | /*==========================================================================*/ | ||
3592 | #ifdef PATH_CHECK | ||
3593 | /* | ||
3594 | * probe for the presence of an interface card | ||
3595 | */ | ||
3596 | static int __init check_card(int port) | ||
3597 | { | ||
3598 | #undef N_RESPO | ||
3599 | #define N_RESPO 20 | ||
3600 | int i, j, k; | ||
3601 | u_char response[N_RESPO]; | ||
3602 | u_char save_port0; | ||
3603 | u_char save_port3; | ||
3604 | |||
3605 | msg(DBG_INI,"check_card entered.\n"); | ||
3606 | save_port0=inb(port+0); | ||
3607 | save_port3=inb(port+3); | ||
3608 | |||
3609 | for (j=0;j<NR_SBPCD;j++) | ||
3610 | { | ||
3611 | OUT(port+3,j) ; /* enable drive #j */ | ||
3612 | OUT(port+0,CMD0_PATH_CHECK); | ||
3613 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3614 | for (k=0;k<N_RESPO;k++) response[k]=0; | ||
3615 | for (k=0;k<N_RESPO;k++) | ||
3616 | { | ||
3617 | for (i=10000;i>0;i--) | ||
3618 | { | ||
3619 | if (inb(port+1)&s_not_result_ready) continue; | ||
3620 | response[k]=inb(port+0); | ||
3621 | break; | ||
3622 | } | ||
3623 | } | ||
3624 | for (i=0;i<N_RESPO;i++) | ||
3625 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3626 | msgbuf[i*3]=0; | ||
3627 | msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf); | ||
3628 | OUT(port+0,CMD0_PATH_CHECK); | ||
3629 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3630 | for (k=0;k<N_RESPO;k++) response[k]=0xFF; | ||
3631 | for (k=0;k<N_RESPO;k++) | ||
3632 | { | ||
3633 | for (i=10000;i>0;i--) | ||
3634 | { | ||
3635 | if (inb(port+1)&s_not_result_ready) continue; | ||
3636 | response[k]=inb(port+0); | ||
3637 | break; | ||
3638 | } | ||
3639 | } | ||
3640 | for (i=0;i<N_RESPO;i++) | ||
3641 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3642 | msgbuf[i*3]=0; | ||
3643 | msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf); | ||
3644 | |||
3645 | if (response[0]==0xAA) | ||
3646 | if (response[1]==0x55) | ||
3647 | return (0); | ||
3648 | } | ||
3649 | for (j=0;j<NR_SBPCD;j++) | ||
3650 | { | ||
3651 | OUT(port+3,j) ; /* enable drive #j */ | ||
3652 | OUT(port+0,CMD2_READ_VER); | ||
3653 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3654 | for (k=0;k<N_RESPO;k++) response[k]=0; | ||
3655 | for (k=0;k<N_RESPO;k++) | ||
3656 | { | ||
3657 | for (i=1000000;i>0;i--) | ||
3658 | { | ||
3659 | if (inb(port+1)&s_not_result_ready) continue; | ||
3660 | response[k]=inb(port+0); | ||
3661 | break; | ||
3662 | } | ||
3663 | } | ||
3664 | for (i=0;i<N_RESPO;i++) | ||
3665 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3666 | msgbuf[i*3]=0; | ||
3667 | msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf); | ||
3668 | |||
3669 | OUT(port+0,CMD2_READ_VER); | ||
3670 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3671 | for (k=0;k<N_RESPO;k++) response[k]=0xFF; | ||
3672 | for (k=0;k<N_RESPO;k++) | ||
3673 | { | ||
3674 | for (i=1000000;i>0;i--) | ||
3675 | { | ||
3676 | if (inb(port+1)&s_not_result_ready) continue; | ||
3677 | response[k]=inb(port+0); | ||
3678 | break; | ||
3679 | } | ||
3680 | } | ||
3681 | for (i=0;i<N_RESPO;i++) | ||
3682 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3683 | msgbuf[i*3]=0; | ||
3684 | msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf); | ||
3685 | |||
3686 | if (response[0]==0xAA) | ||
3687 | if (response[1]==0x55) | ||
3688 | return (0); | ||
3689 | } | ||
3690 | OUT(port+0,save_port0); | ||
3691 | OUT(port+3,save_port3); | ||
3692 | return (0); /* in any case - no real "function" at time */ | ||
3693 | } | ||
3694 | #endif /* PATH_CHECK */ | ||
3695 | /*==========================================================================*/ | ||
3696 | /*==========================================================================*/ | ||
3697 | /* | ||
3698 | * probe for the presence of drives on the selected controller | ||
3699 | */ | ||
3700 | static int __init check_drives(void) | ||
3701 | { | ||
3702 | int i, j; | ||
3703 | |||
3704 | msg(DBG_INI,"check_drives entered.\n"); | ||
3705 | ndrives=0; | ||
3706 | for (j=0;j<max_drives;j++) | ||
3707 | { | ||
3708 | struct sbpcd_drive *p = D_S + ndrives; | ||
3709 | p->drv_id=j; | ||
3710 | if (sbpro_type==1) p->drv_sel=(j&0x01)<<1|(j&0x02)>>1; | ||
3711 | else p->drv_sel=j; | ||
3712 | switch_drive(p); | ||
3713 | msg(DBG_INI,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j); | ||
3714 | msg(DBG_000,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j); | ||
3715 | i=check_version(); | ||
3716 | if (i<0) msg(DBG_INI,"check_version returns %d.\n",i); | ||
3717 | else | ||
3718 | { | ||
3719 | current_drive->drv_options=drv_pattern[j]; | ||
3720 | if (fam0L_drive) current_drive->drv_options&=~(speed_auto|speed_300|speed_150); | ||
3721 | msg(DBG_INF, "Drive %d (ID=%d): %.9s (%.4s) at 0x%03X (type %d)\n", | ||
3722 | current_drive - D_S, | ||
3723 | current_drive->drv_id, | ||
3724 | current_drive->drive_model, | ||
3725 | current_drive->firmware_version, | ||
3726 | CDo_command, | ||
3727 | sbpro_type); | ||
3728 | ndrives++; | ||
3729 | } | ||
3730 | } | ||
3731 | for (j=ndrives;j<NR_SBPCD;j++) D_S[j].drv_id=-1; | ||
3732 | if (ndrives==0) return (-1); | ||
3733 | return (0); | ||
3734 | } | ||
3735 | /*==========================================================================*/ | ||
3736 | #ifdef FUTURE | ||
3737 | /* | ||
3738 | * obtain if requested service disturbs current audio state | ||
3739 | */ | ||
3740 | static int obey_audio_state(u_char audio_state, u_char func,u_char subfunc) | ||
3741 | { | ||
3742 | switch (audio_state) /* audio status from controller */ | ||
3743 | { | ||
3744 | case aud_11: /* "audio play in progress" */ | ||
3745 | case audx11: | ||
3746 | switch (func) /* DOS command code */ | ||
3747 | { | ||
3748 | case cmd_07: /* input flush */ | ||
3749 | case cmd_0d: /* open device */ | ||
3750 | case cmd_0e: /* close device */ | ||
3751 | case cmd_0c: /* ioctl output */ | ||
3752 | return (1); | ||
3753 | case cmd_03: /* ioctl input */ | ||
3754 | switch (subfunc) | ||
3755 | /* DOS ioctl input subfunction */ | ||
3756 | { | ||
3757 | case cxi_00: | ||
3758 | case cxi_06: | ||
3759 | case cxi_09: | ||
3760 | return (1); | ||
3761 | default: | ||
3762 | return (ERROR15); | ||
3763 | } | ||
3764 | return (1); | ||
3765 | default: | ||
3766 | return (ERROR15); | ||
3767 | } | ||
3768 | return (1); | ||
3769 | case aud_12: /* "audio play paused" */ | ||
3770 | case audx12: | ||
3771 | return (1); | ||
3772 | default: | ||
3773 | return (2); | ||
3774 | } | ||
3775 | } | ||
3776 | /*==========================================================================*/ | ||
3777 | /* allowed is only | ||
3778 | * ioctl_o, flush_input, open_device, close_device, | ||
3779 | * tell_address, tell_volume, tell_capabiliti, | ||
3780 | * tell_framesize, tell_CD_changed, tell_audio_posi | ||
3781 | */ | ||
3782 | static int check_allowed1(u_char func1, u_char func2) | ||
3783 | { | ||
3784 | #if 000 | ||
3785 | if (func1==ioctl_o) return (0); | ||
3786 | if (func1==read_long) return (-1); | ||
3787 | if (func1==read_long_prefetch) return (-1); | ||
3788 | if (func1==seek) return (-1); | ||
3789 | if (func1==audio_play) return (-1); | ||
3790 | if (func1==audio_pause) return (-1); | ||
3791 | if (func1==audio_resume) return (-1); | ||
3792 | if (func1!=ioctl_i) return (0); | ||
3793 | if (func2==tell_SubQ_run_tot) return (-1); | ||
3794 | if (func2==tell_cdsize) return (-1); | ||
3795 | if (func2==tell_TocDescrip) return (-1); | ||
3796 | if (func2==tell_TocEntry) return (-1); | ||
3797 | if (func2==tell_subQ_info) return (-1); | ||
3798 | if (fam1_drive) if (func2==tell_SubChanInfo) return (-1); | ||
3799 | if (func2==tell_UPC) return (-1); | ||
3800 | #else | ||
3801 | return (0); | ||
3802 | #endif | ||
3803 | } | ||
3804 | /*==========================================================================*/ | ||
3805 | static int check_allowed2(u_char func1, u_char func2) | ||
3806 | { | ||
3807 | #if 000 | ||
3808 | if (func1==read_long) return (-1); | ||
3809 | if (func1==read_long_prefetch) return (-1); | ||
3810 | if (func1==seek) return (-1); | ||
3811 | if (func1==audio_play) return (-1); | ||
3812 | if (func1!=ioctl_o) return (0); | ||
3813 | if (fam1_drive) | ||
3814 | { | ||
3815 | if (func2==EjectDisk) return (-1); | ||
3816 | if (func2==CloseTray) return (-1); | ||
3817 | } | ||
3818 | #else | ||
3819 | return (0); | ||
3820 | #endif | ||
3821 | } | ||
3822 | /*==========================================================================*/ | ||
3823 | static int check_allowed3(u_char func1, u_char func2) | ||
3824 | { | ||
3825 | #if 000 | ||
3826 | if (func1==ioctl_i) | ||
3827 | { | ||
3828 | if (func2==tell_address) return (0); | ||
3829 | if (func2==tell_capabiliti) return (0); | ||
3830 | if (func2==tell_CD_changed) return (0); | ||
3831 | if (fam0L_drive) if (func2==tell_SubChanInfo) return (0); | ||
3832 | return (-1); | ||
3833 | } | ||
3834 | if (func1==ioctl_o) | ||
3835 | { | ||
3836 | if (func2==DriveReset) return (0); | ||
3837 | if (fam0L_drive) | ||
3838 | { | ||
3839 | if (func2==EjectDisk) return (0); | ||
3840 | if (func2==LockDoor) return (0); | ||
3841 | if (func2==CloseTray) return (0); | ||
3842 | } | ||
3843 | return (-1); | ||
3844 | } | ||
3845 | if (func1==flush_input) return (-1); | ||
3846 | if (func1==read_long) return (-1); | ||
3847 | if (func1==read_long_prefetch) return (-1); | ||
3848 | if (func1==seek) return (-1); | ||
3849 | if (func1==audio_play) return (-1); | ||
3850 | if (func1==audio_pause) return (-1); | ||
3851 | if (func1==audio_resume) return (-1); | ||
3852 | #else | ||
3853 | return (0); | ||
3854 | #endif | ||
3855 | } | ||
3856 | /*==========================================================================*/ | ||
3857 | static int seek_pos_audio_end(void) | ||
3858 | { | ||
3859 | int i; | ||
3860 | |||
3861 | i=msf2blk(current_drive->pos_audio_end)-1; | ||
3862 | if (i<0) return (-1); | ||
3863 | i=cc_Seek(i,0); | ||
3864 | return (i); | ||
3865 | } | ||
3866 | #endif /* FUTURE */ | ||
3867 | /*==========================================================================*/ | ||
3868 | static int ReadToC(void) | ||
3869 | { | ||
3870 | int i, j; | ||
3871 | current_drive->diskstate_flags &= ~toc_bit; | ||
3872 | current_drive->ored_ctl_adr=0; | ||
3873 | /* special handling of CD-I HE */ | ||
3874 | if ((current_drive->n_first_track == 2 && current_drive->n_last_track == 2) || | ||
3875 | current_drive->xa_byte == 0x10) | ||
3876 | { | ||
3877 | current_drive->TocBuffer[1].nixbyte=0; | ||
3878 | current_drive->TocBuffer[1].ctl_adr=0x40; | ||
3879 | current_drive->TocBuffer[1].number=1; | ||
3880 | current_drive->TocBuffer[1].format=0; | ||
3881 | current_drive->TocBuffer[1].address=blk2msf(0); | ||
3882 | current_drive->ored_ctl_adr |= 0x40; | ||
3883 | current_drive->n_first_track = 1; | ||
3884 | current_drive->n_last_track = 1; | ||
3885 | current_drive->xa_byte = 0x10; | ||
3886 | j = 2; | ||
3887 | } else | ||
3888 | for (j=current_drive->n_first_track;j<=current_drive->n_last_track;j++) | ||
3889 | { | ||
3890 | i=cc_ReadTocEntry(j); | ||
3891 | if (i<0) | ||
3892 | { | ||
3893 | msg(DBG_INF,"cc_ReadTocEntry(%d) returns %d.\n",j,i); | ||
3894 | return (i); | ||
3895 | } | ||
3896 | current_drive->TocBuffer[j].nixbyte=current_drive->TocEnt_nixbyte; | ||
3897 | current_drive->TocBuffer[j].ctl_adr=current_drive->TocEnt_ctl_adr; | ||
3898 | current_drive->TocBuffer[j].number=current_drive->TocEnt_number; | ||
3899 | current_drive->TocBuffer[j].format=current_drive->TocEnt_format; | ||
3900 | current_drive->TocBuffer[j].address=current_drive->TocEnt_address; | ||
3901 | current_drive->ored_ctl_adr |= current_drive->TocEnt_ctl_adr; | ||
3902 | } | ||
3903 | /* fake entry for LeadOut Track */ | ||
3904 | current_drive->TocBuffer[j].nixbyte=0; | ||
3905 | current_drive->TocBuffer[j].ctl_adr=0; | ||
3906 | current_drive->TocBuffer[j].number=CDROM_LEADOUT; | ||
3907 | current_drive->TocBuffer[j].format=0; | ||
3908 | current_drive->TocBuffer[j].address=current_drive->size_msf; | ||
3909 | |||
3910 | current_drive->diskstate_flags |= toc_bit; | ||
3911 | return (0); | ||
3912 | } | ||
3913 | /*==========================================================================*/ | ||
3914 | static int DiskInfo(void) | ||
3915 | { | ||
3916 | int i, j; | ||
3917 | |||
3918 | current_drive->mode=READ_M1; | ||
3919 | |||
3920 | #undef LOOP_COUNT | ||
3921 | #define LOOP_COUNT 10 /* needed for some "old" drives */ | ||
3922 | |||
3923 | msg(DBG_000,"DiskInfo entered.\n"); | ||
3924 | for (j=1;j<LOOP_COUNT;j++) | ||
3925 | { | ||
3926 | #if 0 | ||
3927 | i=SetSpeed(); | ||
3928 | if (i<0) | ||
3929 | { | ||
3930 | msg(DBG_INF,"DiskInfo: SetSpeed returns %d\n", i); | ||
3931 | continue; | ||
3932 | } | ||
3933 | i=cc_ModeSense(); | ||
3934 | if (i<0) | ||
3935 | { | ||
3936 | msg(DBG_INF,"DiskInfo: cc_ModeSense returns %d\n", i); | ||
3937 | continue; | ||
3938 | } | ||
3939 | #endif | ||
3940 | i=cc_ReadCapacity(); | ||
3941 | if (i>=0) break; | ||
3942 | msg(DBG_INF,"DiskInfo: ReadCapacity #%d returns %d\n", j, i); | ||
3943 | #if 0 | ||
3944 | i=cc_DriveReset(); | ||
3945 | #endif | ||
3946 | if (!fam0_drive && j == 2) break; | ||
3947 | } | ||
3948 | if (j==LOOP_COUNT) return (-33); /* give up */ | ||
3949 | |||
3950 | i=cc_ReadTocDescr(); | ||
3951 | if (i<0) | ||
3952 | { | ||
3953 | msg(DBG_INF,"DiskInfo: ReadTocDescr returns %d\n", i); | ||
3954 | return (i); | ||
3955 | } | ||
3956 | i=ReadToC(); | ||
3957 | if (i<0) | ||
3958 | { | ||
3959 | msg(DBG_INF,"DiskInfo: ReadToC returns %d\n", i); | ||
3960 | return (i); | ||
3961 | } | ||
3962 | i=cc_CheckMultiSession(); | ||
3963 | if (i<0) | ||
3964 | { | ||
3965 | msg(DBG_INF,"DiskInfo: cc_CheckMultiSession returns %d\n", i); | ||
3966 | return (i); | ||
3967 | } | ||
3968 | if (current_drive->f_multisession) current_drive->sbp_bufsiz=1; /* possibly a weird PhotoCD */ | ||
3969 | else current_drive->sbp_bufsiz=buffers; | ||
3970 | i=cc_ReadTocEntry(current_drive->n_first_track); | ||
3971 | if (i<0) | ||
3972 | { | ||
3973 | msg(DBG_INF,"DiskInfo: cc_ReadTocEntry(1) returns %d\n", i); | ||
3974 | return (i); | ||
3975 | } | ||
3976 | i=cc_ReadUPC(); | ||
3977 | if (i<0) msg(DBG_INF,"DiskInfo: cc_ReadUPC returns %d\n", i); | ||
3978 | if ((fam0L_drive) && (current_drive->xa_byte==0x20 || current_drive->xa_byte == 0x10)) | ||
3979 | { | ||
3980 | /* XA disk with old drive */ | ||
3981 | cc_ModeSelect(CD_FRAMESIZE_RAW1); | ||
3982 | cc_ModeSense(); | ||
3983 | } | ||
3984 | if (famT_drive) cc_prep_mode_T(); | ||
3985 | msg(DBG_000,"DiskInfo done.\n"); | ||
3986 | return (0); | ||
3987 | } | ||
3988 | |||
3989 | static int sbpcd_drive_status(struct cdrom_device_info *cdi, int slot_nr) | ||
3990 | { | ||
3991 | struct sbpcd_drive *p = cdi->handle; | ||
3992 | int st; | ||
3993 | |||
3994 | if (CDSL_CURRENT != slot_nr) { | ||
3995 | /* we have no changer support */ | ||
3996 | return -EINVAL; | ||
3997 | } | ||
3998 | |||
3999 | cc_ReadStatus(); | ||
4000 | st=ResponseStatus(); | ||
4001 | if (st<0) | ||
4002 | { | ||
4003 | msg(DBG_INF,"sbpcd_drive_status: timeout.\n"); | ||
4004 | return (0); | ||
4005 | } | ||
4006 | msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); | ||
4007 | msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); | ||
4008 | msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); | ||
4009 | msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); | ||
4010 | msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); | ||
4011 | msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); | ||
4012 | |||
4013 | #if 0 | ||
4014 | if (!(p->status_bits & p_door_closed)) return CDS_TRAY_OPEN; | ||
4015 | if (p->status_bits & p_disk_ok) return CDS_DISC_OK; | ||
4016 | if (p->status_bits & p_disk_in) return CDS_DRIVE_NOT_READY; | ||
4017 | |||
4018 | return CDS_NO_DISC; | ||
4019 | #else | ||
4020 | if (p->status_bits & p_spinning) return CDS_DISC_OK; | ||
4021 | /* return CDS_TRAY_OPEN; */ | ||
4022 | return CDS_NO_DISC; | ||
4023 | |||
4024 | #endif | ||
4025 | |||
4026 | } | ||
4027 | |||
4028 | |||
4029 | /*==========================================================================*/ | ||
4030 | #ifdef FUTURE | ||
4031 | /* | ||
4032 | * called always if driver gets entered | ||
4033 | * returns 0 or ERROR2 or ERROR15 | ||
4034 | */ | ||
4035 | static int prepare(u_char func, u_char subfunc) | ||
4036 | { | ||
4037 | int i; | ||
4038 | |||
4039 | if (fam0L_drive) | ||
4040 | { | ||
4041 | i=inb(CDi_status); | ||
4042 | if (i&s_attention) GetStatus(); | ||
4043 | } | ||
4044 | else if (fam1_drive) GetStatus(); | ||
4045 | else if (fam2_drive) GetStatus(); | ||
4046 | else if (famT_drive) GetStatus(); | ||
4047 | if (current_drive->CD_changed==0xFF) | ||
4048 | { | ||
4049 | current_drive->diskstate_flags=0; | ||
4050 | current_drive->audio_state=0; | ||
4051 | if (!st_diskok) | ||
4052 | { | ||
4053 | i=check_allowed1(func,subfunc); | ||
4054 | if (i<0) return (-2); | ||
4055 | } | ||
4056 | else | ||
4057 | { | ||
4058 | i=check_allowed3(func,subfunc); | ||
4059 | if (i<0) | ||
4060 | { | ||
4061 | current_drive->CD_changed=1; | ||
4062 | return (-15); | ||
4063 | } | ||
4064 | } | ||
4065 | } | ||
4066 | else | ||
4067 | { | ||
4068 | if (!st_diskok) | ||
4069 | { | ||
4070 | current_drive->diskstate_flags=0; | ||
4071 | current_drive->audio_state=0; | ||
4072 | i=check_allowed1(func,subfunc); | ||
4073 | if (i<0) return (-2); | ||
4074 | } | ||
4075 | else | ||
4076 | { | ||
4077 | if (st_busy) | ||
4078 | { | ||
4079 | if (current_drive->audio_state!=audio_pausing) | ||
4080 | { | ||
4081 | i=check_allowed2(func,subfunc); | ||
4082 | if (i<0) return (-2); | ||
4083 | } | ||
4084 | } | ||
4085 | else | ||
4086 | { | ||
4087 | if (current_drive->audio_state==audio_playing) seek_pos_audio_end(); | ||
4088 | current_drive->audio_state=0; | ||
4089 | } | ||
4090 | if (!frame_size_valid) | ||
4091 | { | ||
4092 | i=DiskInfo(); | ||
4093 | if (i<0) | ||
4094 | { | ||
4095 | current_drive->diskstate_flags=0; | ||
4096 | current_drive->audio_state=0; | ||
4097 | i=check_allowed1(func,subfunc); | ||
4098 | if (i<0) return (-2); | ||
4099 | } | ||
4100 | } | ||
4101 | } | ||
4102 | } | ||
4103 | return (0); | ||
4104 | } | ||
4105 | #endif /* FUTURE */ | ||
4106 | /*==========================================================================*/ | ||
4107 | /*==========================================================================*/ | ||
4108 | /* | ||
4109 | * Check the results of the "get status" command. | ||
4110 | */ | ||
4111 | static int sbp_status(void) | ||
4112 | { | ||
4113 | int st; | ||
4114 | |||
4115 | st=ResponseStatus(); | ||
4116 | if (st<0) | ||
4117 | { | ||
4118 | msg(DBG_INF,"sbp_status: timeout.\n"); | ||
4119 | return (0); | ||
4120 | } | ||
4121 | |||
4122 | if (!st_spinning) msg(DBG_SPI,"motor got off - ignoring.\n"); | ||
4123 | |||
4124 | if (st_check) | ||
4125 | { | ||
4126 | msg(DBG_INF,"st_check detected - retrying.\n"); | ||
4127 | return (0); | ||
4128 | } | ||
4129 | if (!st_door_closed) | ||
4130 | { | ||
4131 | msg(DBG_INF,"door is open - retrying.\n"); | ||
4132 | return (0); | ||
4133 | } | ||
4134 | if (!st_caddy_in) | ||
4135 | { | ||
4136 | msg(DBG_INF,"disk removed - retrying.\n"); | ||
4137 | return (0); | ||
4138 | } | ||
4139 | if (!st_diskok) | ||
4140 | { | ||
4141 | msg(DBG_INF,"!st_diskok detected - retrying.\n"); | ||
4142 | return (0); | ||
4143 | } | ||
4144 | if (st_busy) | ||
4145 | { | ||
4146 | msg(DBG_INF,"st_busy detected - retrying.\n"); | ||
4147 | return (0); | ||
4148 | } | ||
4149 | return (1); | ||
4150 | } | ||
4151 | /*==========================================================================*/ | ||
4152 | |||
4153 | static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp) | ||
4154 | { | ||
4155 | struct sbpcd_drive *p = cdi->handle; | ||
4156 | ms_infp->addr_format = CDROM_LBA; | ||
4157 | ms_infp->addr.lba = p->lba_multi; | ||
4158 | if (p->f_multisession) | ||
4159 | ms_infp->xa_flag=1; /* valid redirection address */ | ||
4160 | else | ||
4161 | ms_infp->xa_flag=0; /* invalid redirection address */ | ||
4162 | |||
4163 | return 0; | ||
4164 | } | ||
4165 | |||
4166 | static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd, | ||
4167 | void * arg) | ||
4168 | { | ||
4169 | struct sbpcd_drive *p = cdi->handle; | ||
4170 | int i, st, j; | ||
4171 | |||
4172 | msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08p)\n", cdi->name, cmd, arg); | ||
4173 | if (p->drv_id==-1) { | ||
4174 | msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name); | ||
4175 | return (-ENXIO); /* no such drive */ | ||
4176 | } | ||
4177 | down(&ioctl_read_sem); | ||
4178 | if (p != current_drive) | ||
4179 | switch_drive(p); | ||
4180 | |||
4181 | msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd); | ||
4182 | switch (cmd) /* Sun-compatible */ | ||
4183 | { | ||
4184 | |||
4185 | case CDROMPAUSE: /* Pause the drive */ | ||
4186 | msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n"); | ||
4187 | /* pause the drive unit when it is currently in PLAY mode, */ | ||
4188 | /* or reset the starting and ending locations when in PAUSED mode. */ | ||
4189 | /* If applicable, at the next stopping point it reaches */ | ||
4190 | /* the drive will discontinue playing. */ | ||
4191 | switch (current_drive->audio_state) | ||
4192 | { | ||
4193 | case audio_playing: | ||
4194 | if (famL_drive) i=cc_ReadSubQ(); | ||
4195 | else i=cc_Pause_Resume(1); | ||
4196 | if (i<0) RETURN_UP(-EIO); | ||
4197 | if (famL_drive) i=cc_Pause_Resume(1); | ||
4198 | else i=cc_ReadSubQ(); | ||
4199 | if (i<0) RETURN_UP(-EIO); | ||
4200 | current_drive->pos_audio_start=current_drive->SubQ_run_tot; | ||
4201 | current_drive->audio_state=audio_pausing; | ||
4202 | RETURN_UP(0); | ||
4203 | case audio_pausing: | ||
4204 | i=cc_Seek(current_drive->pos_audio_start,1); | ||
4205 | if (i<0) RETURN_UP(-EIO); | ||
4206 | RETURN_UP(0); | ||
4207 | default: | ||
4208 | RETURN_UP(-EINVAL); | ||
4209 | } | ||
4210 | |||
4211 | case CDROMRESUME: /* resume paused audio play */ | ||
4212 | msg(DBG_IOC,"ioctl: CDROMRESUME entered.\n"); | ||
4213 | /* resume playing audio tracks when a previous PLAY AUDIO call has */ | ||
4214 | /* been paused with a PAUSE command. */ | ||
4215 | /* It will resume playing from the location saved in SubQ_run_tot. */ | ||
4216 | if (current_drive->audio_state!=audio_pausing) RETURN_UP(-EINVAL); | ||
4217 | if (famL_drive) | ||
4218 | i=cc_PlayAudio(current_drive->pos_audio_start, | ||
4219 | current_drive->pos_audio_end); | ||
4220 | else i=cc_Pause_Resume(3); | ||
4221 | if (i<0) RETURN_UP(-EIO); | ||
4222 | current_drive->audio_state=audio_playing; | ||
4223 | RETURN_UP(0); | ||
4224 | |||
4225 | case CDROMPLAYMSF: | ||
4226 | msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n"); | ||
4227 | #ifdef SAFE_MIXED | ||
4228 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4229 | #endif /* SAFE_MIXED */ | ||
4230 | if (current_drive->audio_state==audio_playing) | ||
4231 | { | ||
4232 | i=cc_Pause_Resume(1); | ||
4233 | if (i<0) RETURN_UP(-EIO); | ||
4234 | i=cc_ReadSubQ(); | ||
4235 | if (i<0) RETURN_UP(-EIO); | ||
4236 | current_drive->pos_audio_start=current_drive->SubQ_run_tot; | ||
4237 | i=cc_Seek(current_drive->pos_audio_start,1); | ||
4238 | } | ||
4239 | memcpy(&msf, (void *) arg, sizeof(struct cdrom_msf)); | ||
4240 | /* values come as msf-bin */ | ||
4241 | current_drive->pos_audio_start = (msf.cdmsf_min0<<16) | | ||
4242 | (msf.cdmsf_sec0<<8) | | ||
4243 | msf.cdmsf_frame0; | ||
4244 | current_drive->pos_audio_end = (msf.cdmsf_min1<<16) | | ||
4245 | (msf.cdmsf_sec1<<8) | | ||
4246 | msf.cdmsf_frame1; | ||
4247 | msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n", | ||
4248 | current_drive->pos_audio_start,current_drive->pos_audio_end); | ||
4249 | i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end); | ||
4250 | if (i<0) | ||
4251 | { | ||
4252 | msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); | ||
4253 | DriveReset(); | ||
4254 | current_drive->audio_state=0; | ||
4255 | RETURN_UP(-EIO); | ||
4256 | } | ||
4257 | current_drive->audio_state=audio_playing; | ||
4258 | RETURN_UP(0); | ||
4259 | |||
4260 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
4261 | msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); | ||
4262 | #ifdef SAFE_MIXED | ||
4263 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4264 | #endif /* SAFE_MIXED */ | ||
4265 | if (current_drive->audio_state==audio_playing) | ||
4266 | { | ||
4267 | msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); | ||
4268 | #if 1 | ||
4269 | RETURN_UP(0); /* just let us play on */ | ||
4270 | #else | ||
4271 | RETURN_UP(-EINVAL); /* play on, but say "error" */ | ||
4272 | #endif | ||
4273 | } | ||
4274 | memcpy(&ti,(void *) arg,sizeof(struct cdrom_ti)); | ||
4275 | msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n", | ||
4276 | ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1); | ||
4277 | if (ti.cdti_trk0<current_drive->n_first_track) RETURN_UP(-EINVAL); | ||
4278 | if (ti.cdti_trk0>current_drive->n_last_track) RETURN_UP(-EINVAL); | ||
4279 | if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0; | ||
4280 | if (ti.cdti_trk1>current_drive->n_last_track) ti.cdti_trk1=current_drive->n_last_track; | ||
4281 | current_drive->pos_audio_start=current_drive->TocBuffer[ti.cdti_trk0].address; | ||
4282 | current_drive->pos_audio_end=current_drive->TocBuffer[ti.cdti_trk1+1].address; | ||
4283 | i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end); | ||
4284 | if (i<0) | ||
4285 | { | ||
4286 | msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); | ||
4287 | DriveReset(); | ||
4288 | current_drive->audio_state=0; | ||
4289 | RETURN_UP(-EIO); | ||
4290 | } | ||
4291 | current_drive->audio_state=audio_playing; | ||
4292 | RETURN_UP(0); | ||
4293 | |||
4294 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
4295 | msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n"); | ||
4296 | tochdr.cdth_trk0=current_drive->n_first_track; | ||
4297 | tochdr.cdth_trk1=current_drive->n_last_track; | ||
4298 | memcpy((void *) arg, &tochdr, sizeof(struct cdrom_tochdr)); | ||
4299 | RETURN_UP(0); | ||
4300 | |||
4301 | case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ | ||
4302 | msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n"); | ||
4303 | memcpy(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry)); | ||
4304 | i=tocentry.cdte_track; | ||
4305 | if (i==CDROM_LEADOUT) i=current_drive->n_last_track+1; | ||
4306 | else if (i<current_drive->n_first_track||i>current_drive->n_last_track) | ||
4307 | RETURN_UP(-EINVAL); | ||
4308 | tocentry.cdte_adr=current_drive->TocBuffer[i].ctl_adr&0x0F; | ||
4309 | tocentry.cdte_ctrl=(current_drive->TocBuffer[i].ctl_adr>>4)&0x0F; | ||
4310 | tocentry.cdte_datamode=current_drive->TocBuffer[i].format; | ||
4311 | if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */ | ||
4312 | { | ||
4313 | tocentry.cdte_addr.msf.minute=(current_drive->TocBuffer[i].address>>16)&0x00FF; | ||
4314 | tocentry.cdte_addr.msf.second=(current_drive->TocBuffer[i].address>>8)&0x00FF; | ||
4315 | tocentry.cdte_addr.msf.frame=current_drive->TocBuffer[i].address&0x00FF; | ||
4316 | } | ||
4317 | else if (tocentry.cdte_format==CDROM_LBA) /* blk required */ | ||
4318 | tocentry.cdte_addr.lba=msf2blk(current_drive->TocBuffer[i].address); | ||
4319 | else RETURN_UP(-EINVAL); | ||
4320 | memcpy((void *) arg, &tocentry, sizeof(struct cdrom_tocentry)); | ||
4321 | RETURN_UP(0); | ||
4322 | |||
4323 | case CDROMSTOP: /* Spin down the drive */ | ||
4324 | msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); | ||
4325 | #ifdef SAFE_MIXED | ||
4326 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4327 | #endif /* SAFE_MIXED */ | ||
4328 | i=cc_Pause_Resume(1); | ||
4329 | current_drive->audio_state=0; | ||
4330 | #if 0 | ||
4331 | cc_DriveReset(); | ||
4332 | #endif | ||
4333 | RETURN_UP(i); | ||
4334 | |||
4335 | case CDROMSTART: /* Spin up the drive */ | ||
4336 | msg(DBG_IOC,"ioctl: CDROMSTART entered.\n"); | ||
4337 | cc_SpinUp(); | ||
4338 | current_drive->audio_state=0; | ||
4339 | RETURN_UP(0); | ||
4340 | |||
4341 | case CDROMVOLCTRL: /* Volume control */ | ||
4342 | msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n"); | ||
4343 | memcpy(&volctrl,(char *) arg,sizeof(volctrl)); | ||
4344 | current_drive->vol_chan0=0; | ||
4345 | current_drive->vol_ctrl0=volctrl.channel0; | ||
4346 | current_drive->vol_chan1=1; | ||
4347 | current_drive->vol_ctrl1=volctrl.channel1; | ||
4348 | i=cc_SetVolume(); | ||
4349 | RETURN_UP(0); | ||
4350 | |||
4351 | case CDROMVOLREAD: /* read Volume settings from drive */ | ||
4352 | msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n"); | ||
4353 | st=cc_GetVolume(); | ||
4354 | if (st<0) RETURN_UP(st); | ||
4355 | volctrl.channel0=current_drive->vol_ctrl0; | ||
4356 | volctrl.channel1=current_drive->vol_ctrl1; | ||
4357 | volctrl.channel2=0; | ||
4358 | volctrl.channel2=0; | ||
4359 | memcpy((void *)arg,&volctrl,sizeof(volctrl)); | ||
4360 | RETURN_UP(0); | ||
4361 | |||
4362 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
4363 | msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n"); | ||
4364 | /* Bogus, I can do better than this! --AJK | ||
4365 | if ((st_spinning)||(!subq_valid)) { | ||
4366 | i=cc_ReadSubQ(); | ||
4367 | if (i<0) RETURN_UP(-EIO); | ||
4368 | } | ||
4369 | */ | ||
4370 | i=cc_ReadSubQ(); | ||
4371 | if (i<0) { | ||
4372 | j=cc_ReadError(); /* clear out error status from drive */ | ||
4373 | current_drive->audio_state=CDROM_AUDIO_NO_STATUS; | ||
4374 | /* get and set the disk state here, | ||
4375 | probably not the right place, but who cares! | ||
4376 | It makes it work properly! --AJK */ | ||
4377 | if (current_drive->CD_changed==0xFF) { | ||
4378 | msg(DBG_000,"Disk changed detect\n"); | ||
4379 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
4380 | } | ||
4381 | RETURN_UP(-EIO); | ||
4382 | } | ||
4383 | if (current_drive->CD_changed==0xFF) { | ||
4384 | /* reread the TOC because the disk has changed! --AJK */ | ||
4385 | msg(DBG_000,"Disk changed STILL detected, rereading TOC!\n"); | ||
4386 | i=DiskInfo(); | ||
4387 | if(i==0) { | ||
4388 | current_drive->CD_changed=0x00; /* cd has changed, procede, */ | ||
4389 | RETURN_UP(-EIO); /* and get TOC, etc on next try! --AJK */ | ||
4390 | } else { | ||
4391 | RETURN_UP(-EIO); /* we weren't ready yet! --AJK */ | ||
4392 | } | ||
4393 | } | ||
4394 | memcpy(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); | ||
4395 | /* | ||
4396 | This virtual crap is very bogus! | ||
4397 | It doesn't detect when the cd is done playing audio! | ||
4398 | Lets do this right with proper hardware register reading! | ||
4399 | */ | ||
4400 | cc_ReadStatus(); | ||
4401 | i=ResponseStatus(); | ||
4402 | msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); | ||
4403 | msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); | ||
4404 | msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); | ||
4405 | msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); | ||
4406 | msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); | ||
4407 | msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); | ||
4408 | /* st_busy indicates if it's _ACTUALLY_ playing audio */ | ||
4409 | switch (current_drive->audio_state) | ||
4410 | { | ||
4411 | case audio_playing: | ||
4412 | if(st_busy==0) { | ||
4413 | /* CD has stopped playing audio --AJK */ | ||
4414 | current_drive->audio_state=audio_completed; | ||
4415 | SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; | ||
4416 | } else { | ||
4417 | SC.cdsc_audiostatus=CDROM_AUDIO_PLAY; | ||
4418 | } | ||
4419 | break; | ||
4420 | case audio_pausing: | ||
4421 | SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED; | ||
4422 | break; | ||
4423 | case audio_completed: | ||
4424 | SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; | ||
4425 | break; | ||
4426 | default: | ||
4427 | SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS; | ||
4428 | break; | ||
4429 | } | ||
4430 | SC.cdsc_adr=current_drive->SubQ_ctl_adr; | ||
4431 | SC.cdsc_ctrl=current_drive->SubQ_ctl_adr>>4; | ||
4432 | SC.cdsc_trk=bcd2bin(current_drive->SubQ_trk); | ||
4433 | SC.cdsc_ind=bcd2bin(current_drive->SubQ_pnt_idx); | ||
4434 | if (SC.cdsc_format==CDROM_LBA) | ||
4435 | { | ||
4436 | SC.cdsc_absaddr.lba=msf2blk(current_drive->SubQ_run_tot); | ||
4437 | SC.cdsc_reladdr.lba=msf2blk(current_drive->SubQ_run_trk); | ||
4438 | } | ||
4439 | else /* not only if (SC.cdsc_format==CDROM_MSF) */ | ||
4440 | { | ||
4441 | SC.cdsc_absaddr.msf.minute=(current_drive->SubQ_run_tot>>16)&0x00FF; | ||
4442 | SC.cdsc_absaddr.msf.second=(current_drive->SubQ_run_tot>>8)&0x00FF; | ||
4443 | SC.cdsc_absaddr.msf.frame=current_drive->SubQ_run_tot&0x00FF; | ||
4444 | SC.cdsc_reladdr.msf.minute=(current_drive->SubQ_run_trk>>16)&0x00FF; | ||
4445 | SC.cdsc_reladdr.msf.second=(current_drive->SubQ_run_trk>>8)&0x00FF; | ||
4446 | SC.cdsc_reladdr.msf.frame=current_drive->SubQ_run_trk&0x00FF; | ||
4447 | } | ||
4448 | memcpy((void *) arg, &SC, sizeof(struct cdrom_subchnl)); | ||
4449 | msg(DBG_IOS,"CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n", | ||
4450 | SC.cdsc_format,SC.cdsc_audiostatus, | ||
4451 | SC.cdsc_adr,SC.cdsc_ctrl, | ||
4452 | SC.cdsc_trk,SC.cdsc_ind, | ||
4453 | SC.cdsc_absaddr,SC.cdsc_reladdr); | ||
4454 | RETURN_UP(0); | ||
4455 | |||
4456 | default: | ||
4457 | msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); | ||
4458 | RETURN_UP(-EINVAL); | ||
4459 | } /* end switch(cmd) */ | ||
4460 | } | ||
4461 | /*==========================================================================*/ | ||
4462 | /* | ||
4463 | * Take care of the different block sizes between cdrom and Linux. | ||
4464 | */ | ||
4465 | static void sbp_transfer(struct request *req) | ||
4466 | { | ||
4467 | long offs; | ||
4468 | |||
4469 | while ( (req->nr_sectors > 0) && | ||
4470 | (req->sector/4 >= current_drive->sbp_first_frame) && | ||
4471 | (req->sector/4 <= current_drive->sbp_last_frame) ) | ||
4472 | { | ||
4473 | offs = (req->sector - current_drive->sbp_first_frame * 4) * 512; | ||
4474 | memcpy(req->buffer, current_drive->sbp_buf + offs, 512); | ||
4475 | req->nr_sectors--; | ||
4476 | req->sector++; | ||
4477 | req->buffer += 512; | ||
4478 | } | ||
4479 | } | ||
4480 | /*==========================================================================*/ | ||
4481 | /* | ||
4482 | * special end_request for sbpcd to solve CURRENT==NULL bug. (GTL) | ||
4483 | * GTL = Gonzalo Tornaria <tornaria@cmat.edu.uy> | ||
4484 | * | ||
4485 | * This is a kludge so we don't need to modify end_request. | ||
4486 | * We put the req we take out after INIT_REQUEST in the requests list, | ||
4487 | * so that end_request will discard it. | ||
4488 | * | ||
4489 | * The bug could be present in other block devices, perhaps we | ||
4490 | * should modify INIT_REQUEST and end_request instead, and | ||
4491 | * change every block device.. | ||
4492 | * | ||
4493 | * Could be a race here?? Could e.g. a timer interrupt schedule() us? | ||
4494 | * If so, we should copy end_request here, and do it right.. (or | ||
4495 | * modify end_request and the block devices). | ||
4496 | * | ||
4497 | * In any case, the race here would be much small than it was, and | ||
4498 | * I couldn't reproduce.. | ||
4499 | * | ||
4500 | * The race could be: suppose CURRENT==NULL. We put our req in the list, | ||
4501 | * and we are scheduled. Other process takes over, and gets into | ||
4502 | * do_sbpcd_request. It sees CURRENT!=NULL (it is == to our req), so | ||
4503 | * proceeds. It ends, so CURRENT is now NULL.. Now we awake somewhere in | ||
4504 | * end_request, but now CURRENT==NULL... oops! | ||
4505 | * | ||
4506 | */ | ||
4507 | #undef DEBUG_GTL | ||
4508 | |||
4509 | /*==========================================================================*/ | ||
4510 | /* | ||
4511 | * I/O request routine, called from Linux kernel. | ||
4512 | */ | ||
4513 | static void do_sbpcd_request(request_queue_t * q) | ||
4514 | { | ||
4515 | u_int block; | ||
4516 | u_int nsect; | ||
4517 | int status_tries, data_tries; | ||
4518 | struct request *req; | ||
4519 | struct sbpcd_drive *p; | ||
4520 | #ifdef DEBUG_GTL | ||
4521 | static int xx_nr=0; | ||
4522 | int xnr; | ||
4523 | #endif | ||
4524 | |||
4525 | request_loop: | ||
4526 | #ifdef DEBUG_GTL | ||
4527 | xnr=++xx_nr; | ||
4528 | |||
4529 | req = elv_next_request(q); | ||
4530 | |||
4531 | if (!req) | ||
4532 | { | ||
4533 | printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n", | ||
4534 | xnr, current->pid, jiffies); | ||
4535 | printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n", | ||
4536 | xnr, jiffies); | ||
4537 | return; | ||
4538 | } | ||
4539 | |||
4540 | printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", | ||
4541 | xnr, req, req->sector, req->nr_sectors, current->pid, jiffies); | ||
4542 | #endif | ||
4543 | |||
4544 | req = elv_next_request(q); /* take out our request so no other */ | ||
4545 | if (!req) | ||
4546 | return; | ||
4547 | |||
4548 | if (req -> sector == -1) | ||
4549 | end_request(req, 0); | ||
4550 | spin_unlock_irq(q->queue_lock); | ||
4551 | |||
4552 | down(&ioctl_read_sem); | ||
4553 | if (rq_data_dir(elv_next_request(q)) != READ) | ||
4554 | { | ||
4555 | msg(DBG_INF, "bad cmd %d\n", req->cmd[0]); | ||
4556 | goto err_done; | ||
4557 | } | ||
4558 | p = req->rq_disk->private_data; | ||
4559 | #if OLD_BUSY | ||
4560 | while (busy_audio) sbp_sleep(HZ); /* wait a bit */ | ||
4561 | busy_data=1; | ||
4562 | #endif /* OLD_BUSY */ | ||
4563 | |||
4564 | if (p->audio_state==audio_playing) goto err_done; | ||
4565 | if (p != current_drive) | ||
4566 | switch_drive(p); | ||
4567 | |||
4568 | block = req->sector; /* always numbered as 512-byte-pieces */ | ||
4569 | nsect = req->nr_sectors; /* always counted as 512-byte-pieces */ | ||
4570 | |||
4571 | msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect); | ||
4572 | #if 0 | ||
4573 | msg(DBG_MUL,"read LBA %d\n", block/4); | ||
4574 | #endif | ||
4575 | |||
4576 | sbp_transfer(req); | ||
4577 | /* if we satisfied the request from the buffer, we're done. */ | ||
4578 | if (req->nr_sectors == 0) | ||
4579 | { | ||
4580 | #ifdef DEBUG_GTL | ||
4581 | printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n", | ||
4582 | xnr, req, req->sector, req->nr_sectors, jiffies); | ||
4583 | #endif | ||
4584 | up(&ioctl_read_sem); | ||
4585 | spin_lock_irq(q->queue_lock); | ||
4586 | end_request(req, 1); | ||
4587 | goto request_loop; | ||
4588 | } | ||
4589 | |||
4590 | #ifdef FUTURE | ||
4591 | i=prepare(0,0); /* at moment not really a hassle check, but ... */ | ||
4592 | if (i!=0) | ||
4593 | msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i); | ||
4594 | #endif /* FUTURE */ | ||
4595 | |||
4596 | if (!st_spinning) cc_SpinUp(); | ||
4597 | |||
4598 | for (data_tries=n_retries; data_tries > 0; data_tries--) | ||
4599 | { | ||
4600 | for (status_tries=3; status_tries > 0; status_tries--) | ||
4601 | { | ||
4602 | flags_cmd_out |= f_respo3; | ||
4603 | cc_ReadStatus(); | ||
4604 | if (sbp_status() != 0) break; | ||
4605 | if (st_check) cc_ReadError(); | ||
4606 | sbp_sleep(1); /* wait a bit, try again */ | ||
4607 | } | ||
4608 | if (status_tries == 0) | ||
4609 | { | ||
4610 | msg(DBG_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__); | ||
4611 | break; | ||
4612 | } | ||
4613 | |||
4614 | sbp_read_cmd(req); | ||
4615 | sbp_sleep(0); | ||
4616 | if (sbp_data(req) != 0) | ||
4617 | { | ||
4618 | #ifdef SAFE_MIXED | ||
4619 | current_drive->has_data=2; /* is really a data disk */ | ||
4620 | #endif /* SAFE_MIXED */ | ||
4621 | #ifdef DEBUG_GTL | ||
4622 | printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n", | ||
4623 | xnr, req, req->sector, req->nr_sectors, jiffies); | ||
4624 | #endif | ||
4625 | up(&ioctl_read_sem); | ||
4626 | spin_lock_irq(q->queue_lock); | ||
4627 | end_request(req, 1); | ||
4628 | goto request_loop; | ||
4629 | } | ||
4630 | } | ||
4631 | |||
4632 | err_done: | ||
4633 | #if OLD_BUSY | ||
4634 | busy_data=0; | ||
4635 | #endif /* OLD_BUSY */ | ||
4636 | #ifdef DEBUG_GTL | ||
4637 | printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", | ||
4638 | xnr, req, req->sector, req->nr_sectors, jiffies); | ||
4639 | #endif | ||
4640 | up(&ioctl_read_sem); | ||
4641 | sbp_sleep(0); /* wait a bit, try again */ | ||
4642 | spin_lock_irq(q->queue_lock); | ||
4643 | end_request(req, 0); | ||
4644 | goto request_loop; | ||
4645 | } | ||
4646 | /*==========================================================================*/ | ||
4647 | /* | ||
4648 | * build and send the READ command. | ||
4649 | */ | ||
4650 | static void sbp_read_cmd(struct request *req) | ||
4651 | { | ||
4652 | #undef OLD | ||
4653 | |||
4654 | int i; | ||
4655 | int block; | ||
4656 | |||
4657 | current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */ | ||
4658 | current_drive->sbp_current = 0; | ||
4659 | block=req->sector/4; | ||
4660 | if (block+current_drive->sbp_bufsiz <= current_drive->CDsize_frm) | ||
4661 | current_drive->sbp_read_frames = current_drive->sbp_bufsiz; | ||
4662 | else | ||
4663 | { | ||
4664 | current_drive->sbp_read_frames=current_drive->CDsize_frm-block; | ||
4665 | /* avoid reading past end of data */ | ||
4666 | if (current_drive->sbp_read_frames < 1) | ||
4667 | { | ||
4668 | msg(DBG_INF,"requested frame %d, CD size %d ???\n", | ||
4669 | block, current_drive->CDsize_frm); | ||
4670 | current_drive->sbp_read_frames=1; | ||
4671 | } | ||
4672 | } | ||
4673 | |||
4674 | flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check; | ||
4675 | clr_cmdbuf(); | ||
4676 | if (famV_drive) | ||
4677 | { | ||
4678 | drvcmd[0]=CMDV_READ; | ||
4679 | lba2msf(block,&drvcmd[1]); /* msf-bcd format required */ | ||
4680 | bin2bcdx(&drvcmd[1]); | ||
4681 | bin2bcdx(&drvcmd[2]); | ||
4682 | bin2bcdx(&drvcmd[3]); | ||
4683 | drvcmd[4]=current_drive->sbp_read_frames>>8; | ||
4684 | drvcmd[5]=current_drive->sbp_read_frames&0xff; | ||
4685 | drvcmd[6]=0x02; /* flag "msf-bcd" */ | ||
4686 | } | ||
4687 | else if (fam0L_drive) | ||
4688 | { | ||
4689 | flags_cmd_out |= f_lopsta | f_getsta | f_bit1; | ||
4690 | if (current_drive->xa_byte==0x20) | ||
4691 | { | ||
4692 | cmd_type=READ_M2; | ||
4693 | drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */ | ||
4694 | drvcmd[1]=(block>>16)&0x0ff; | ||
4695 | drvcmd[2]=(block>>8)&0x0ff; | ||
4696 | drvcmd[3]=block&0x0ff; | ||
4697 | drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
4698 | drvcmd[5]=current_drive->sbp_read_frames&0x0ff; | ||
4699 | } | ||
4700 | else | ||
4701 | { | ||
4702 | drvcmd[0]=CMD0_READ; /* "read frames", old drives */ | ||
4703 | if (current_drive->drv_type>=drv_201) | ||
4704 | { | ||
4705 | lba2msf(block,&drvcmd[1]); /* msf-bcd format required */ | ||
4706 | bin2bcdx(&drvcmd[1]); | ||
4707 | bin2bcdx(&drvcmd[2]); | ||
4708 | bin2bcdx(&drvcmd[3]); | ||
4709 | } | ||
4710 | else | ||
4711 | { | ||
4712 | drvcmd[1]=(block>>16)&0x0ff; | ||
4713 | drvcmd[2]=(block>>8)&0x0ff; | ||
4714 | drvcmd[3]=block&0x0ff; | ||
4715 | } | ||
4716 | drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
4717 | drvcmd[5]=current_drive->sbp_read_frames&0x0ff; | ||
4718 | drvcmd[6]=(current_drive->drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */ | ||
4719 | } | ||
4720 | } | ||
4721 | else if (fam1_drive) | ||
4722 | { | ||
4723 | drvcmd[0]=CMD1_READ; | ||
4724 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
4725 | drvcmd[5]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
4726 | drvcmd[6]=current_drive->sbp_read_frames&0x0ff; | ||
4727 | } | ||
4728 | else if (fam2_drive) | ||
4729 | { | ||
4730 | drvcmd[0]=CMD2_READ; | ||
4731 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
4732 | drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
4733 | drvcmd[5]=current_drive->sbp_read_frames&0x0ff; | ||
4734 | drvcmd[6]=0x02; | ||
4735 | } | ||
4736 | else if (famT_drive) | ||
4737 | { | ||
4738 | drvcmd[0]=CMDT_READ; | ||
4739 | drvcmd[2]=(block>>24)&0x0ff; | ||
4740 | drvcmd[3]=(block>>16)&0x0ff; | ||
4741 | drvcmd[4]=(block>>8)&0x0ff; | ||
4742 | drvcmd[5]=block&0x0ff; | ||
4743 | drvcmd[7]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
4744 | drvcmd[8]=current_drive->sbp_read_frames&0x0ff; | ||
4745 | } | ||
4746 | flags_cmd_out=f_putcmd; | ||
4747 | response_count=0; | ||
4748 | i=cmd_out(); | ||
4749 | if (i<0) msg(DBG_INF,"error giving READ command: %0d\n", i); | ||
4750 | return; | ||
4751 | } | ||
4752 | /*==========================================================================*/ | ||
4753 | /* | ||
4754 | * Check the completion of the read-data command. On success, read | ||
4755 | * the current_drive->sbp_bufsiz * 2048 bytes of data from the disk into buffer. | ||
4756 | */ | ||
4757 | static int sbp_data(struct request *req) | ||
4758 | { | ||
4759 | int i=0, j=0, l, frame; | ||
4760 | u_int try=0; | ||
4761 | u_long timeout; | ||
4762 | u_char *p; | ||
4763 | u_int data_tries = 0; | ||
4764 | u_int data_waits = 0; | ||
4765 | u_int data_retrying = 0; | ||
4766 | int error_flag; | ||
4767 | int xa_count; | ||
4768 | int max_latency; | ||
4769 | int success; | ||
4770 | int wait; | ||
4771 | int duration; | ||
4772 | |||
4773 | error_flag=0; | ||
4774 | success=0; | ||
4775 | #if LONG_TIMING | ||
4776 | max_latency=9*HZ; | ||
4777 | #else | ||
4778 | if (current_drive->f_multisession) max_latency=15*HZ; | ||
4779 | else max_latency=5*HZ; | ||
4780 | #endif | ||
4781 | duration=jiffies; | ||
4782 | for (frame=0;frame<current_drive->sbp_read_frames&&!error_flag; frame++) | ||
4783 | { | ||
4784 | SBPCD_CLI; | ||
4785 | |||
4786 | del_timer(&data_timer); | ||
4787 | data_timer.expires=jiffies+max_latency; | ||
4788 | timed_out_data=0; | ||
4789 | add_timer(&data_timer); | ||
4790 | while (!timed_out_data) | ||
4791 | { | ||
4792 | if (current_drive->f_multisession) try=maxtim_data*4; | ||
4793 | else try=maxtim_data; | ||
4794 | msg(DBG_000,"sbp_data: CDi_status loop: try=%d.\n",try); | ||
4795 | for ( ; try!=0;try--) | ||
4796 | { | ||
4797 | j=inb(CDi_status); | ||
4798 | if (!(j&s_not_data_ready)) break; | ||
4799 | if (!(j&s_not_result_ready)) break; | ||
4800 | if (fam0LV_drive) if (j&s_attention) break; | ||
4801 | } | ||
4802 | if (!(j&s_not_data_ready)) goto data_ready; | ||
4803 | if (try==0) | ||
4804 | { | ||
4805 | if (data_retrying == 0) data_waits++; | ||
4806 | data_retrying = 1; | ||
4807 | msg(DBG_000,"sbp_data: CDi_status loop: sleeping.\n"); | ||
4808 | sbp_sleep(1); | ||
4809 | try = 1; | ||
4810 | } | ||
4811 | } | ||
4812 | msg(DBG_INF,"sbp_data: CDi_status loop expired.\n"); | ||
4813 | data_ready: | ||
4814 | del_timer(&data_timer); | ||
4815 | |||
4816 | if (timed_out_data) | ||
4817 | { | ||
4818 | msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j); | ||
4819 | error_flag++; | ||
4820 | } | ||
4821 | if (try==0) | ||
4822 | { | ||
4823 | msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j); | ||
4824 | error_flag++; | ||
4825 | } | ||
4826 | if (!(j&s_not_result_ready)) | ||
4827 | { | ||
4828 | msg(DBG_INF, "sbp_data: RESULT_READY where DATA_READY awaited (%02X).\n", j); | ||
4829 | response_count=20; | ||
4830 | j=ResponseInfo(); | ||
4831 | j=inb(CDi_status); | ||
4832 | } | ||
4833 | if (j&s_not_data_ready) | ||
4834 | { | ||
4835 | if ((current_drive->ored_ctl_adr&0x40)==0) | ||
4836 | msg(DBG_INF, "CD contains no data tracks.\n"); | ||
4837 | else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j); | ||
4838 | error_flag++; | ||
4839 | } | ||
4840 | SBPCD_STI; | ||
4841 | if (error_flag) break; | ||
4842 | |||
4843 | msg(DBG_000, "sbp_data: beginning to read.\n"); | ||
4844 | p = current_drive->sbp_buf + frame * CD_FRAMESIZE; | ||
4845 | if (sbpro_type==1) OUT(CDo_sel_i_d,1); | ||
4846 | if (cmd_type==READ_M2) { | ||
4847 | if (do_16bit) insw(CDi_data, xa_head_buf, CD_XA_HEAD>>1); | ||
4848 | else insb(CDi_data, xa_head_buf, CD_XA_HEAD); | ||
4849 | } | ||
4850 | if (do_16bit) insw(CDi_data, p, CD_FRAMESIZE>>1); | ||
4851 | else insb(CDi_data, p, CD_FRAMESIZE); | ||
4852 | if (cmd_type==READ_M2) { | ||
4853 | if (do_16bit) insw(CDi_data, xa_tail_buf, CD_XA_TAIL>>1); | ||
4854 | else insb(CDi_data, xa_tail_buf, CD_XA_TAIL); | ||
4855 | } | ||
4856 | current_drive->sbp_current++; | ||
4857 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
4858 | if (cmd_type==READ_M2) | ||
4859 | { | ||
4860 | for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++) | ||
4861 | sprintf(&msgbuf[xa_count*3], " %02X", xa_head_buf[xa_count]); | ||
4862 | msgbuf[xa_count*3]=0; | ||
4863 | msg(DBG_XA1,"xa head:%s\n", msgbuf); | ||
4864 | } | ||
4865 | data_retrying = 0; | ||
4866 | data_tries++; | ||
4867 | if (data_tries >= 1000) | ||
4868 | { | ||
4869 | msg(DBG_INF,"sbp_data() statistics: %d waits in %d frames.\n", data_waits, data_tries); | ||
4870 | data_waits = data_tries = 0; | ||
4871 | } | ||
4872 | } | ||
4873 | duration=jiffies-duration; | ||
4874 | msg(DBG_TEA,"time to read %d frames: %d jiffies .\n",frame,duration); | ||
4875 | if (famT_drive) | ||
4876 | { | ||
4877 | wait=8; | ||
4878 | do | ||
4879 | { | ||
4880 | if (teac==2) | ||
4881 | { | ||
4882 | if ((i=CDi_stat_loop_T()) == -1) break; | ||
4883 | } | ||
4884 | else | ||
4885 | { | ||
4886 | sbp_sleep(1); | ||
4887 | OUT(CDo_sel_i_d,0); | ||
4888 | i=inb(CDi_status); | ||
4889 | } | ||
4890 | if (!(i&s_not_data_ready)) | ||
4891 | { | ||
4892 | OUT(CDo_sel_i_d,1); | ||
4893 | j=0; | ||
4894 | do | ||
4895 | { | ||
4896 | if (do_16bit) i=inw(CDi_data); | ||
4897 | else i=inb(CDi_data); | ||
4898 | j++; | ||
4899 | i=inb(CDi_status); | ||
4900 | } | ||
4901 | while (!(i&s_not_data_ready)); | ||
4902 | msg(DBG_TEA, "==========too much data (%d bytes/words)==============.\n", j); | ||
4903 | } | ||
4904 | if (!(i&s_not_result_ready)) | ||
4905 | { | ||
4906 | OUT(CDo_sel_i_d,0); | ||
4907 | l=0; | ||
4908 | do | ||
4909 | { | ||
4910 | infobuf[l++]=inb(CDi_info); | ||
4911 | i=inb(CDi_status); | ||
4912 | } | ||
4913 | while (!(i&s_not_result_ready)); | ||
4914 | if (infobuf[0]==0x00) success=1; | ||
4915 | #if 1 | ||
4916 | for (j=0;j<l;j++) sprintf(&msgbuf[j*3], " %02X", infobuf[j]); | ||
4917 | msgbuf[j*3]=0; | ||
4918 | msg(DBG_TEA,"sbp_data info response:%s\n", msgbuf); | ||
4919 | #endif | ||
4920 | if (infobuf[0]==0x02) | ||
4921 | { | ||
4922 | error_flag++; | ||
4923 | do | ||
4924 | { | ||
4925 | ++recursion; | ||
4926 | if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (sbp_data): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",recursion); | ||
4927 | else msg(DBG_TEA,"sbp_data: CMDT_READ_ERR necessary.\n"); | ||
4928 | clr_cmdbuf(); | ||
4929 | drvcmd[0]=CMDT_READ_ERR; | ||
4930 | j=cmd_out_T(); /* !!! recursive here !!! */ | ||
4931 | --recursion; | ||
4932 | sbp_sleep(1); | ||
4933 | } | ||
4934 | while (j<0); | ||
4935 | current_drive->error_state=infobuf[2]; | ||
4936 | current_drive->b3=infobuf[3]; | ||
4937 | current_drive->b4=infobuf[4]; | ||
4938 | } | ||
4939 | break; | ||
4940 | } | ||
4941 | else | ||
4942 | { | ||
4943 | #if 0 | ||
4944 | msg(DBG_TEA, "============= waiting for result=================.\n"); | ||
4945 | sbp_sleep(1); | ||
4946 | #endif | ||
4947 | } | ||
4948 | } | ||
4949 | while (wait--); | ||
4950 | } | ||
4951 | |||
4952 | if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ | ||
4953 | { | ||
4954 | msg(DBG_TEA, "================error flag: %d=================.\n", error_flag); | ||
4955 | msg(DBG_INF,"sbp_data: read aborted by drive.\n"); | ||
4956 | #if 1 | ||
4957 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
4958 | #else | ||
4959 | i=cc_ReadError(); | ||
4960 | #endif | ||
4961 | return (0); | ||
4962 | } | ||
4963 | |||
4964 | if (fam0LV_drive) | ||
4965 | { | ||
4966 | SBPCD_CLI; | ||
4967 | i=maxtim_data; | ||
4968 | for (timeout=jiffies+HZ; time_before(jiffies, timeout); timeout--) | ||
4969 | { | ||
4970 | for ( ;i!=0;i--) | ||
4971 | { | ||
4972 | j=inb(CDi_status); | ||
4973 | if (!(j&s_not_data_ready)) break; | ||
4974 | if (!(j&s_not_result_ready)) break; | ||
4975 | if (j&s_attention) break; | ||
4976 | } | ||
4977 | if (i != 0 || time_after_eq(jiffies, timeout)) break; | ||
4978 | sbp_sleep(0); | ||
4979 | i = 1; | ||
4980 | } | ||
4981 | if (i==0) msg(DBG_INF,"status timeout after READ.\n"); | ||
4982 | if (!(j&s_attention)) | ||
4983 | { | ||
4984 | msg(DBG_INF,"sbp_data: timeout waiting DRV_ATTN - retrying.\n"); | ||
4985 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
4986 | SBPCD_STI; | ||
4987 | return (0); | ||
4988 | } | ||
4989 | SBPCD_STI; | ||
4990 | } | ||
4991 | |||
4992 | #if 0 | ||
4993 | if (!success) | ||
4994 | #endif | ||
4995 | do | ||
4996 | { | ||
4997 | if (fam0LV_drive) cc_ReadStatus(); | ||
4998 | #if 1 | ||
4999 | if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i); | ||
5000 | #endif | ||
5001 | i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ | ||
5002 | #if 1 | ||
5003 | if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i); | ||
5004 | #endif | ||
5005 | if (i<0) | ||
5006 | { | ||
5007 | msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", current_drive->status_bits); | ||
5008 | return (0); | ||
5009 | } | ||
5010 | } | ||
5011 | while ((fam0LV_drive)&&(!st_check)&&(!(i&p_success))); | ||
5012 | if (st_check) | ||
5013 | { | ||
5014 | i=cc_ReadError(); | ||
5015 | msg(DBG_INF,"cc_ReadError was necessary after read: %d\n",i); | ||
5016 | return (0); | ||
5017 | } | ||
5018 | if (fatal_err) | ||
5019 | { | ||
5020 | fatal_err=0; | ||
5021 | current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */ | ||
5022 | current_drive->sbp_current = 0; | ||
5023 | msg(DBG_INF,"sbp_data: fatal_err - retrying.\n"); | ||
5024 | return (0); | ||
5025 | } | ||
5026 | |||
5027 | current_drive->sbp_first_frame = req -> sector / 4; | ||
5028 | current_drive->sbp_last_frame = current_drive->sbp_first_frame + current_drive->sbp_read_frames - 1; | ||
5029 | sbp_transfer(req); | ||
5030 | return (1); | ||
5031 | } | ||
5032 | /*==========================================================================*/ | ||
5033 | |||
5034 | static int sbpcd_block_open(struct inode *inode, struct file *file) | ||
5035 | { | ||
5036 | struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; | ||
5037 | return cdrom_open(p->sbpcd_infop, inode, file); | ||
5038 | } | ||
5039 | |||
5040 | static int sbpcd_block_release(struct inode *inode, struct file *file) | ||
5041 | { | ||
5042 | struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; | ||
5043 | return cdrom_release(p->sbpcd_infop, file); | ||
5044 | } | ||
5045 | |||
5046 | static int sbpcd_block_ioctl(struct inode *inode, struct file *file, | ||
5047 | unsigned cmd, unsigned long arg) | ||
5048 | { | ||
5049 | struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; | ||
5050 | struct cdrom_device_info *cdi = p->sbpcd_infop; | ||
5051 | int ret, i; | ||
5052 | |||
5053 | ret = cdrom_ioctl(file, p->sbpcd_infop, inode, cmd, arg); | ||
5054 | if (ret != -ENOSYS) | ||
5055 | return ret; | ||
5056 | |||
5057 | msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08lX)\n", cdi->name, cmd, arg); | ||
5058 | if (p->drv_id==-1) { | ||
5059 | msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name); | ||
5060 | return (-ENXIO); /* no such drive */ | ||
5061 | } | ||
5062 | down(&ioctl_read_sem); | ||
5063 | if (p != current_drive) | ||
5064 | switch_drive(p); | ||
5065 | |||
5066 | msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd); | ||
5067 | switch (cmd) /* Sun-compatible */ | ||
5068 | { | ||
5069 | case DDIOCSDBG: /* DDI Debug */ | ||
5070 | if (!capable(CAP_SYS_ADMIN)) RETURN_UP(-EPERM); | ||
5071 | i=sbpcd_dbg_ioctl(arg,1); | ||
5072 | RETURN_UP(i); | ||
5073 | case CDROMRESET: /* hard reset the drive */ | ||
5074 | msg(DBG_IOC,"ioctl: CDROMRESET entered.\n"); | ||
5075 | i=DriveReset(); | ||
5076 | current_drive->audio_state=0; | ||
5077 | RETURN_UP(i); | ||
5078 | |||
5079 | case CDROMREADMODE1: | ||
5080 | msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); | ||
5081 | #ifdef SAFE_MIXED | ||
5082 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
5083 | #endif /* SAFE_MIXED */ | ||
5084 | cc_ModeSelect(CD_FRAMESIZE); | ||
5085 | cc_ModeSense(); | ||
5086 | current_drive->mode=READ_M1; | ||
5087 | RETURN_UP(0); | ||
5088 | |||
5089 | case CDROMREADMODE2: /* not usable at the moment */ | ||
5090 | msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); | ||
5091 | #ifdef SAFE_MIXED | ||
5092 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
5093 | #endif /* SAFE_MIXED */ | ||
5094 | cc_ModeSelect(CD_FRAMESIZE_RAW1); | ||
5095 | cc_ModeSense(); | ||
5096 | current_drive->mode=READ_M2; | ||
5097 | RETURN_UP(0); | ||
5098 | |||
5099 | case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */ | ||
5100 | msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n"); | ||
5101 | if (current_drive->sbp_audsiz>0) | ||
5102 | vfree(current_drive->aud_buf); | ||
5103 | current_drive->aud_buf=NULL; | ||
5104 | current_drive->sbp_audsiz=arg; | ||
5105 | |||
5106 | if (current_drive->sbp_audsiz>16) | ||
5107 | { | ||
5108 | current_drive->sbp_audsiz = 0; | ||
5109 | RETURN_UP(current_drive->sbp_audsiz); | ||
5110 | } | ||
5111 | |||
5112 | if (current_drive->sbp_audsiz>0) | ||
5113 | { | ||
5114 | current_drive->aud_buf=(u_char *) vmalloc(current_drive->sbp_audsiz*CD_FRAMESIZE_RAW); | ||
5115 | if (current_drive->aud_buf==NULL) | ||
5116 | { | ||
5117 | msg(DBG_INF,"audio buffer (%d frames) not available.\n",current_drive->sbp_audsiz); | ||
5118 | current_drive->sbp_audsiz=0; | ||
5119 | } | ||
5120 | else msg(DBG_INF,"audio buffer size: %d frames.\n",current_drive->sbp_audsiz); | ||
5121 | } | ||
5122 | RETURN_UP(current_drive->sbp_audsiz); | ||
5123 | |||
5124 | case CDROMREADAUDIO: | ||
5125 | { /* start of CDROMREADAUDIO */ | ||
5126 | int i=0, j=0, frame, block=0; | ||
5127 | u_int try=0; | ||
5128 | u_long timeout; | ||
5129 | u_char *p; | ||
5130 | u_int data_tries = 0; | ||
5131 | u_int data_waits = 0; | ||
5132 | u_int data_retrying = 0; | ||
5133 | int status_tries; | ||
5134 | int error_flag; | ||
5135 | |||
5136 | msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n"); | ||
5137 | if (fam0_drive) RETURN_UP(-EINVAL); | ||
5138 | if (famL_drive) RETURN_UP(-EINVAL); | ||
5139 | if (famV_drive) RETURN_UP(-EINVAL); | ||
5140 | if (famT_drive) RETURN_UP(-EINVAL); | ||
5141 | #ifdef SAFE_MIXED | ||
5142 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
5143 | #endif /* SAFE_MIXED */ | ||
5144 | if (current_drive->aud_buf==NULL) RETURN_UP(-EINVAL); | ||
5145 | if (copy_from_user(&read_audio, (void __user *)arg, | ||
5146 | sizeof(struct cdrom_read_audio))) | ||
5147 | RETURN_UP(-EFAULT); | ||
5148 | if (read_audio.nframes < 0 || read_audio.nframes>current_drive->sbp_audsiz) RETURN_UP(-EINVAL); | ||
5149 | if (!access_ok(VERIFY_WRITE, read_audio.buf, | ||
5150 | read_audio.nframes*CD_FRAMESIZE_RAW)) | ||
5151 | RETURN_UP(-EFAULT); | ||
5152 | |||
5153 | if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */ | ||
5154 | block=msf2lba(&read_audio.addr.msf.minute); | ||
5155 | else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */ | ||
5156 | block=read_audio.addr.lba; | ||
5157 | else RETURN_UP(-EINVAL); | ||
5158 | #if 000 | ||
5159 | i=cc_SetSpeed(speed_150,0,0); | ||
5160 | if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i); | ||
5161 | #endif | ||
5162 | msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n", | ||
5163 | block, blk2msf(block)); | ||
5164 | msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n"); | ||
5165 | #if OLD_BUSY | ||
5166 | while (busy_data) sbp_sleep(HZ/10); /* wait a bit */ | ||
5167 | busy_audio=1; | ||
5168 | #endif /* OLD_BUSY */ | ||
5169 | error_flag=0; | ||
5170 | for (data_tries=5; data_tries>0; data_tries--) | ||
5171 | { | ||
5172 | msg(DBG_AUD,"data_tries=%d ...\n", data_tries); | ||
5173 | current_drive->mode=READ_AU; | ||
5174 | cc_ModeSelect(CD_FRAMESIZE_RAW); | ||
5175 | cc_ModeSense(); | ||
5176 | for (status_tries=3; status_tries > 0; status_tries--) | ||
5177 | { | ||
5178 | flags_cmd_out |= f_respo3; | ||
5179 | cc_ReadStatus(); | ||
5180 | if (sbp_status() != 0) break; | ||
5181 | if (st_check) cc_ReadError(); | ||
5182 | sbp_sleep(1); /* wait a bit, try again */ | ||
5183 | } | ||
5184 | if (status_tries == 0) | ||
5185 | { | ||
5186 | msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries in line %d.\n", __LINE__); | ||
5187 | continue; | ||
5188 | } | ||
5189 | msg(DBG_AUD,"read_audio: sbp_status: ok.\n"); | ||
5190 | |||
5191 | flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check; | ||
5192 | if (fam0L_drive) | ||
5193 | { | ||
5194 | flags_cmd_out |= f_lopsta | f_getsta | f_bit1; | ||
5195 | cmd_type=READ_M2; | ||
5196 | drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */ | ||
5197 | drvcmd[1]=(block>>16)&0x000000ff; | ||
5198 | drvcmd[2]=(block>>8)&0x000000ff; | ||
5199 | drvcmd[3]=block&0x000000ff; | ||
5200 | drvcmd[4]=0; | ||
5201 | drvcmd[5]=read_audio.nframes; /* # of frames */ | ||
5202 | drvcmd[6]=0; | ||
5203 | } | ||
5204 | else if (fam1_drive) | ||
5205 | { | ||
5206 | drvcmd[0]=CMD1_READ; /* "read frames", new drives */ | ||
5207 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
5208 | drvcmd[4]=0; | ||
5209 | drvcmd[5]=0; | ||
5210 | drvcmd[6]=read_audio.nframes; /* # of frames */ | ||
5211 | } | ||
5212 | else if (fam2_drive) | ||
5213 | { | ||
5214 | drvcmd[0]=CMD2_READ_XA2; | ||
5215 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
5216 | drvcmd[4]=0; | ||
5217 | drvcmd[5]=read_audio.nframes; /* # of frames */ | ||
5218 | drvcmd[6]=0x11; /* raw mode */ | ||
5219 | } | ||
5220 | else if (famT_drive) /* CD-55A: not tested yet */ | ||
5221 | { | ||
5222 | } | ||
5223 | msg(DBG_AUD,"read_audio: before giving \"read\" command.\n"); | ||
5224 | flags_cmd_out=f_putcmd; | ||
5225 | response_count=0; | ||
5226 | i=cmd_out(); | ||
5227 | if (i<0) msg(DBG_INF,"error giving READ AUDIO command: %0d\n", i); | ||
5228 | sbp_sleep(0); | ||
5229 | msg(DBG_AUD,"read_audio: after giving \"read\" command.\n"); | ||
5230 | for (frame=1;frame<2 && !error_flag; frame++) | ||
5231 | { | ||
5232 | try=maxtim_data; | ||
5233 | for (timeout=jiffies+9*HZ; ; ) | ||
5234 | { | ||
5235 | for ( ; try!=0;try--) | ||
5236 | { | ||
5237 | j=inb(CDi_status); | ||
5238 | if (!(j&s_not_data_ready)) break; | ||
5239 | if (!(j&s_not_result_ready)) break; | ||
5240 | if (fam0L_drive) if (j&s_attention) break; | ||
5241 | } | ||
5242 | if (try != 0 || time_after_eq(jiffies, timeout)) break; | ||
5243 | if (data_retrying == 0) data_waits++; | ||
5244 | data_retrying = 1; | ||
5245 | sbp_sleep(1); | ||
5246 | try = 1; | ||
5247 | } | ||
5248 | if (try==0) | ||
5249 | { | ||
5250 | msg(DBG_INF,"read_audio: sbp_data: CDi_status timeout.\n"); | ||
5251 | error_flag++; | ||
5252 | break; | ||
5253 | } | ||
5254 | msg(DBG_AUD,"read_audio: sbp_data: CDi_status ok.\n"); | ||
5255 | if (j&s_not_data_ready) | ||
5256 | { | ||
5257 | msg(DBG_INF, "read_audio: sbp_data: DATA_READY timeout.\n"); | ||
5258 | error_flag++; | ||
5259 | break; | ||
5260 | } | ||
5261 | msg(DBG_AUD,"read_audio: before reading data.\n"); | ||
5262 | error_flag=0; | ||
5263 | p = current_drive->aud_buf; | ||
5264 | if (sbpro_type==1) OUT(CDo_sel_i_d,1); | ||
5265 | if (do_16bit) | ||
5266 | { | ||
5267 | u_short *p2 = (u_short *) p; | ||
5268 | |||
5269 | for (; (u_char *) p2 < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) | ||
5270 | { | ||
5271 | if ((inb_p(CDi_status)&s_not_data_ready)) continue; | ||
5272 | |||
5273 | /* get one sample */ | ||
5274 | *p2++ = inw_p(CDi_data); | ||
5275 | *p2++ = inw_p(CDi_data); | ||
5276 | } | ||
5277 | } else { | ||
5278 | for (; p < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) | ||
5279 | { | ||
5280 | if ((inb_p(CDi_status)&s_not_data_ready)) continue; | ||
5281 | |||
5282 | /* get one sample */ | ||
5283 | *p++ = inb_p(CDi_data); | ||
5284 | *p++ = inb_p(CDi_data); | ||
5285 | *p++ = inb_p(CDi_data); | ||
5286 | *p++ = inb_p(CDi_data); | ||
5287 | } | ||
5288 | } | ||
5289 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
5290 | data_retrying = 0; | ||
5291 | } | ||
5292 | msg(DBG_AUD,"read_audio: after reading data.\n"); | ||
5293 | if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ | ||
5294 | { | ||
5295 | msg(DBG_AUD,"read_audio: read aborted by drive\n"); | ||
5296 | #if 0000 | ||
5297 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
5298 | #else | ||
5299 | i=cc_ReadError(); | ||
5300 | #endif | ||
5301 | continue; | ||
5302 | } | ||
5303 | if (fam0L_drive) | ||
5304 | { | ||
5305 | i=maxtim_data; | ||
5306 | for (timeout=jiffies+9*HZ; time_before(jiffies, timeout); timeout--) | ||
5307 | { | ||
5308 | for ( ;i!=0;i--) | ||
5309 | { | ||
5310 | j=inb(CDi_status); | ||
5311 | if (!(j&s_not_data_ready)) break; | ||
5312 | if (!(j&s_not_result_ready)) break; | ||
5313 | if (j&s_attention) break; | ||
5314 | } | ||
5315 | if (i != 0 || time_after_eq(jiffies, timeout)) break; | ||
5316 | sbp_sleep(0); | ||
5317 | i = 1; | ||
5318 | } | ||
5319 | if (i==0) msg(DBG_AUD,"read_audio: STATUS TIMEOUT AFTER READ"); | ||
5320 | if (!(j&s_attention)) | ||
5321 | { | ||
5322 | msg(DBG_AUD,"read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"); | ||
5323 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
5324 | continue; | ||
5325 | } | ||
5326 | } | ||
5327 | do | ||
5328 | { | ||
5329 | if (fam0L_drive) cc_ReadStatus(); | ||
5330 | i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ | ||
5331 | if (i<0) { msg(DBG_AUD, | ||
5332 | "read_audio: cc_ReadStatus error after read: %02X\n", | ||
5333 | current_drive->status_bits); | ||
5334 | continue; /* FIXME */ | ||
5335 | } | ||
5336 | } | ||
5337 | while ((fam0L_drive)&&(!st_check)&&(!(i&p_success))); | ||
5338 | if (st_check) | ||
5339 | { | ||
5340 | i=cc_ReadError(); | ||
5341 | msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i); | ||
5342 | continue; | ||
5343 | } | ||
5344 | if (copy_to_user(read_audio.buf, | ||
5345 | current_drive->aud_buf, | ||
5346 | read_audio.nframes * CD_FRAMESIZE_RAW)) | ||
5347 | RETURN_UP(-EFAULT); | ||
5348 | msg(DBG_AUD,"read_audio: copy_to_user done.\n"); | ||
5349 | break; | ||
5350 | } | ||
5351 | cc_ModeSelect(CD_FRAMESIZE); | ||
5352 | cc_ModeSense(); | ||
5353 | current_drive->mode=READ_M1; | ||
5354 | #if OLD_BUSY | ||
5355 | busy_audio=0; | ||
5356 | #endif /* OLD_BUSY */ | ||
5357 | if (data_tries == 0) | ||
5358 | { | ||
5359 | msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__); | ||
5360 | RETURN_UP(-EIO); | ||
5361 | } | ||
5362 | msg(DBG_AUD,"read_audio: successful return.\n"); | ||
5363 | RETURN_UP(0); | ||
5364 | } /* end of CDROMREADAUDIO */ | ||
5365 | |||
5366 | default: | ||
5367 | msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); | ||
5368 | RETURN_UP(-EINVAL); | ||
5369 | } /* end switch(cmd) */ | ||
5370 | } | ||
5371 | |||
5372 | static int sbpcd_block_media_changed(struct gendisk *disk) | ||
5373 | { | ||
5374 | struct sbpcd_drive *p = disk->private_data; | ||
5375 | return cdrom_media_changed(p->sbpcd_infop); | ||
5376 | } | ||
5377 | |||
5378 | static struct block_device_operations sbpcd_bdops = | ||
5379 | { | ||
5380 | .owner = THIS_MODULE, | ||
5381 | .open = sbpcd_block_open, | ||
5382 | .release = sbpcd_block_release, | ||
5383 | .ioctl = sbpcd_block_ioctl, | ||
5384 | .media_changed = sbpcd_block_media_changed, | ||
5385 | }; | ||
5386 | /*==========================================================================*/ | ||
5387 | /* | ||
5388 | * Open the device special file. Check that a disk is in. Read TOC. | ||
5389 | */ | ||
5390 | static int sbpcd_open(struct cdrom_device_info *cdi, int purpose) | ||
5391 | { | ||
5392 | struct sbpcd_drive *p = cdi->handle; | ||
5393 | |||
5394 | down(&ioctl_read_sem); | ||
5395 | switch_drive(p); | ||
5396 | |||
5397 | /* | ||
5398 | * try to keep an "open" counter here and lock the door if 0->1. | ||
5399 | */ | ||
5400 | msg(DBG_LCK,"open_count: %d -> %d\n", | ||
5401 | current_drive->open_count,current_drive->open_count+1); | ||
5402 | if (++current_drive->open_count<=1) | ||
5403 | { | ||
5404 | int i; | ||
5405 | i=LockDoor(); | ||
5406 | current_drive->open_count=1; | ||
5407 | if (famT_drive) msg(DBG_TEA,"sbpcd_open: before i=DiskInfo();.\n"); | ||
5408 | i=DiskInfo(); | ||
5409 | if (famT_drive) msg(DBG_TEA,"sbpcd_open: after i=DiskInfo();.\n"); | ||
5410 | if ((current_drive->ored_ctl_adr&0x40)==0) | ||
5411 | { | ||
5412 | msg(DBG_INF,"CD contains no data tracks.\n"); | ||
5413 | #ifdef SAFE_MIXED | ||
5414 | current_drive->has_data=0; | ||
5415 | #endif /* SAFE_MIXED */ | ||
5416 | } | ||
5417 | #ifdef SAFE_MIXED | ||
5418 | else if (current_drive->has_data<1) current_drive->has_data=1; | ||
5419 | #endif /* SAFE_MIXED */ | ||
5420 | } | ||
5421 | if (!st_spinning) cc_SpinUp(); | ||
5422 | RETURN_UP(0); | ||
5423 | } | ||
5424 | /*==========================================================================*/ | ||
5425 | /* | ||
5426 | * On close, we flush all sbp blocks from the buffer cache. | ||
5427 | */ | ||
5428 | static void sbpcd_release(struct cdrom_device_info * cdi) | ||
5429 | { | ||
5430 | struct sbpcd_drive *p = cdi->handle; | ||
5431 | |||
5432 | if (p->drv_id==-1) { | ||
5433 | msg(DBG_INF, "release: bad device: %s\n", cdi->name); | ||
5434 | return; | ||
5435 | } | ||
5436 | down(&ioctl_read_sem); | ||
5437 | switch_drive(p); | ||
5438 | /* | ||
5439 | * try to keep an "open" counter here and unlock the door if 1->0. | ||
5440 | */ | ||
5441 | msg(DBG_LCK,"open_count: %d -> %d\n", | ||
5442 | p->open_count,p->open_count-1); | ||
5443 | if (p->open_count>-2) /* CDROMEJECT may have been done */ | ||
5444 | { | ||
5445 | if (--p->open_count<=0) | ||
5446 | { | ||
5447 | p->sbp_first_frame=p->sbp_last_frame=-1; | ||
5448 | if (p->audio_state!=audio_playing) | ||
5449 | if (p->f_eject) cc_SpinDown(); | ||
5450 | p->diskstate_flags &= ~cd_size_bit; | ||
5451 | p->open_count=0; | ||
5452 | #ifdef SAFE_MIXED | ||
5453 | p->has_data=0; | ||
5454 | #endif /* SAFE_MIXED */ | ||
5455 | } | ||
5456 | } | ||
5457 | up(&ioctl_read_sem); | ||
5458 | return ; | ||
5459 | } | ||
5460 | /*==========================================================================*/ | ||
5461 | /* | ||
5462 | * | ||
5463 | */ | ||
5464 | static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr); | ||
5465 | static struct cdrom_device_ops sbpcd_dops = { | ||
5466 | .open = sbpcd_open, | ||
5467 | .release = sbpcd_release, | ||
5468 | .drive_status = sbpcd_drive_status, | ||
5469 | .media_changed = sbpcd_media_changed, | ||
5470 | .tray_move = sbpcd_tray_move, | ||
5471 | .lock_door = sbpcd_lock_door, | ||
5472 | .select_speed = sbpcd_select_speed, | ||
5473 | .get_last_session = sbpcd_get_last_session, | ||
5474 | .get_mcn = sbpcd_get_mcn, | ||
5475 | .reset = sbpcd_reset, | ||
5476 | .audio_ioctl = sbpcd_audio_ioctl, | ||
5477 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | | ||
5478 | CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | | ||
5479 | CDC_MCN | CDC_PLAY_AUDIO, | ||
5480 | .n_minors = 1, | ||
5481 | }; | ||
5482 | |||
5483 | /*==========================================================================*/ | ||
5484 | /* | ||
5485 | * accept "kernel command line" parameters | ||
5486 | * (suggested by Peter MacDonald with SLS 1.03) | ||
5487 | * | ||
5488 | * This is only implemented for the first controller. Should be enough to | ||
5489 | * allow installing with a "strange" distribution kernel. | ||
5490 | * | ||
5491 | * use: tell LILO: | ||
5492 | * sbpcd=0x230,SoundBlaster | ||
5493 | * or | ||
5494 | * sbpcd=0x300,LaserMate | ||
5495 | * or | ||
5496 | * sbpcd=0x338,SoundScape | ||
5497 | * or | ||
5498 | * sbpcd=0x2C0,Teac16bit | ||
5499 | * | ||
5500 | * (upper/lower case sensitive here - but all-lowercase is ok!!!). | ||
5501 | * | ||
5502 | * the address value has to be the CDROM PORT ADDRESS - | ||
5503 | * not the soundcard base address. | ||
5504 | * For the SPEA/SoundScape setup, DO NOT specify the "configuration port" | ||
5505 | * address, but the address which is really used for the CDROM (usually 8 | ||
5506 | * bytes above). | ||
5507 | * | ||
5508 | */ | ||
5509 | |||
5510 | int sbpcd_setup(char *s) | ||
5511 | { | ||
5512 | #ifndef MODULE | ||
5513 | int p[4]; | ||
5514 | (void)get_options(s, ARRAY_SIZE(p), p); | ||
5515 | setup_done++; | ||
5516 | msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s); | ||
5517 | sbpro_type=0; /* default: "LaserMate" */ | ||
5518 | if (p[0]>1) sbpro_type=p[2]; | ||
5519 | else if (!strcmp(s,str_sb)) sbpro_type=1; | ||
5520 | else if (!strcmp(s,str_sb_l)) sbpro_type=1; | ||
5521 | else if (!strcmp(s,str_sp)) sbpro_type=2; | ||
5522 | else if (!strcmp(s,str_sp_l)) sbpro_type=2; | ||
5523 | else if (!strcmp(s,str_ss)) sbpro_type=2; | ||
5524 | else if (!strcmp(s,str_ss_l)) sbpro_type=2; | ||
5525 | else if (!strcmp(s,str_t16)) sbpro_type=3; | ||
5526 | else if (!strcmp(s,str_t16_l)) sbpro_type=3; | ||
5527 | if (p[0]>0) sbpcd_ioaddr=p[1]; | ||
5528 | if (p[0]>2) max_drives=p[3]; | ||
5529 | #else | ||
5530 | sbpcd_ioaddr = sbpcd[0]; | ||
5531 | sbpro_type = sbpcd[1]; | ||
5532 | #endif | ||
5533 | |||
5534 | CDo_command=sbpcd_ioaddr; | ||
5535 | CDi_info=sbpcd_ioaddr; | ||
5536 | CDi_status=sbpcd_ioaddr+1; | ||
5537 | CDo_sel_i_d=sbpcd_ioaddr+1; | ||
5538 | CDo_reset=sbpcd_ioaddr+2; | ||
5539 | CDo_enable=sbpcd_ioaddr+3; | ||
5540 | f_16bit=0; | ||
5541 | if ((sbpro_type==1)||(sbpro_type==3)) | ||
5542 | { | ||
5543 | CDi_data=sbpcd_ioaddr; | ||
5544 | if (sbpro_type==3) | ||
5545 | { | ||
5546 | f_16bit=1; | ||
5547 | sbpro_type=1; | ||
5548 | } | ||
5549 | } | ||
5550 | else CDi_data=sbpcd_ioaddr+2; | ||
5551 | |||
5552 | return 1; | ||
5553 | } | ||
5554 | |||
5555 | __setup("sbpcd=", sbpcd_setup); | ||
5556 | |||
5557 | |||
5558 | /*==========================================================================*/ | ||
5559 | /* | ||
5560 | * Sequoia S-1000 CD-ROM Interface Configuration | ||
5561 | * as used within SPEA Media FX, Ensonic SoundScape and some Reveal cards | ||
5562 | * The soundcard has to get jumpered for the interface type "Panasonic" | ||
5563 | * (not Sony or Mitsumi) and to get soft-configured for | ||
5564 | * -> configuration port address | ||
5565 | * -> CDROM port offset (num_ports): has to be 8 here. Possibly this | ||
5566 | * offset value determines the interface type (none, Panasonic, | ||
5567 | * Mitsumi, Sony). | ||
5568 | * The interface uses a configuration port (0x320, 0x330, 0x340, 0x350) | ||
5569 | * some bytes below the real CDROM address. | ||
5570 | * | ||
5571 | * For the Panasonic style (LaserMate) interface and the configuration | ||
5572 | * port 0x330, we have to use an offset of 8; so, the real CDROM port | ||
5573 | * address is 0x338. | ||
5574 | */ | ||
5575 | static int __init config_spea(void) | ||
5576 | { | ||
5577 | /* | ||
5578 | * base address offset between configuration port and CDROM port, | ||
5579 | * this probably defines the interface type | ||
5580 | * 2 (type=??): 0x00 | ||
5581 | * 8 (type=LaserMate):0x10 | ||
5582 | * 16 (type=??):0x20 | ||
5583 | * 32 (type=??):0x30 | ||
5584 | */ | ||
5585 | int n_ports=0x10; | ||
5586 | |||
5587 | int irq_number=0; /* off:0x00, 2/9:0x01, 7:0x03, 12:0x05, 15:0x07 */ | ||
5588 | int dma_channel=0; /* off: 0x00, 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68 */ | ||
5589 | int dack_polarity=0; /* L:0x00, H:0x80 */ | ||
5590 | int drq_polarity=0x40; /* L:0x00, H:0x40 */ | ||
5591 | int i; | ||
5592 | |||
5593 | #define SPEA_REG_1 sbpcd_ioaddr-0x08+4 | ||
5594 | #define SPEA_REG_2 sbpcd_ioaddr-0x08+5 | ||
5595 | |||
5596 | OUT(SPEA_REG_1,0xFF); | ||
5597 | i=inb(SPEA_REG_1); | ||
5598 | if (i!=0x0F) | ||
5599 | { | ||
5600 | msg(DBG_SEQ,"no SPEA interface at %04X present.\n", sbpcd_ioaddr); | ||
5601 | return (-1); /* no interface found */ | ||
5602 | } | ||
5603 | OUT(SPEA_REG_1,0x04); | ||
5604 | OUT(SPEA_REG_2,0xC0); | ||
5605 | |||
5606 | OUT(SPEA_REG_1,0x05); | ||
5607 | OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity); | ||
5608 | |||
5609 | #if 1 | ||
5610 | #define SPEA_PATTERN 0x80 | ||
5611 | #else | ||
5612 | #define SPEA_PATTERN 0x00 | ||
5613 | #endif | ||
5614 | OUT(SPEA_REG_1,0x06); | ||
5615 | OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); | ||
5616 | OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); | ||
5617 | |||
5618 | OUT(SPEA_REG_1,0x09); | ||
5619 | i=(inb(SPEA_REG_2)&0xCF)|n_ports; | ||
5620 | OUT(SPEA_REG_2,i); | ||
5621 | |||
5622 | sbpro_type = 0; /* acts like a LaserMate interface now */ | ||
5623 | msg(DBG_SEQ,"found SoundScape interface at %04X.\n", sbpcd_ioaddr); | ||
5624 | return (0); | ||
5625 | } | ||
5626 | |||
5627 | /*==========================================================================*/ | ||
5628 | /* | ||
5629 | * Test for presence of drive and initialize it. | ||
5630 | * Called once at boot or load time. | ||
5631 | */ | ||
5632 | |||
5633 | /* FIXME: cleanups after failed allocations are too ugly for words */ | ||
5634 | #ifdef MODULE | ||
5635 | int __init __sbpcd_init(void) | ||
5636 | #else | ||
5637 | int __init sbpcd_init(void) | ||
5638 | #endif | ||
5639 | { | ||
5640 | int i=0, j=0; | ||
5641 | int addr[2]={1, CDROM_PORT}; | ||
5642 | int port_index; | ||
5643 | |||
5644 | sti(); | ||
5645 | |||
5646 | msg(DBG_INF,"sbpcd.c %s\n", VERSION); | ||
5647 | #ifndef MODULE | ||
5648 | #if DISTRIBUTION | ||
5649 | if (!setup_done) | ||
5650 | { | ||
5651 | msg(DBG_INF,"Looking for Matsushita/Panasonic, CreativeLabs, Longshine, TEAC CD-ROM drives\n"); | ||
5652 | msg(DBG_INF,"= = = = = = = = = = W A R N I N G = = = = = = = = = =\n"); | ||
5653 | msg(DBG_INF,"Auto-Probing can cause a hang (f.e. touching an NE2000 card).\n"); | ||
5654 | msg(DBG_INF,"If that happens, you have to reboot and use the\n"); | ||
5655 | msg(DBG_INF,"LILO (kernel) command line feature like:\n"); | ||
5656 | msg(DBG_INF," LILO boot: ... sbpcd=0x230,SoundBlaster\n"); | ||
5657 | msg(DBG_INF,"or like:\n"); | ||
5658 | msg(DBG_INF," LILO boot: ... sbpcd=0x300,LaserMate\n"); | ||
5659 | msg(DBG_INF,"or like:\n"); | ||
5660 | msg(DBG_INF," LILO boot: ... sbpcd=0x338,SoundScape\n"); | ||
5661 | msg(DBG_INF,"with your REAL address.\n"); | ||
5662 | msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n"); | ||
5663 | } | ||
5664 | #endif /* DISTRIBUTION */ | ||
5665 | sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */ | ||
5666 | sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */ | ||
5667 | #endif /* MODULE */ | ||
5668 | |||
5669 | for (port_index=0;port_index<NUM_PROBE;port_index+=2) | ||
5670 | { | ||
5671 | addr[1]=sbpcd[port_index]; | ||
5672 | if (addr[1]==0) break; | ||
5673 | if (check_region(addr[1],4)) | ||
5674 | { | ||
5675 | msg(DBG_INF,"check_region: %03X is not free.\n",addr[1]); | ||
5676 | continue; | ||
5677 | } | ||
5678 | if (sbpcd[port_index+1]==2) type=str_sp; | ||
5679 | else if (sbpcd[port_index+1]==1) type=str_sb; | ||
5680 | else if (sbpcd[port_index+1]==3) type=str_t16; | ||
5681 | else type=str_lm; | ||
5682 | sbpcd_setup((char *)type); | ||
5683 | #if DISTRIBUTION | ||
5684 | msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type); | ||
5685 | #endif /* DISTRIBUTION */ | ||
5686 | if (sbpcd[port_index+1]==2) | ||
5687 | { | ||
5688 | i=config_spea(); | ||
5689 | if (i<0) continue; | ||
5690 | } | ||
5691 | #ifdef PATH_CHECK | ||
5692 | if (check_card(addr[1])) continue; | ||
5693 | #endif /* PATH_CHECK */ | ||
5694 | i=check_drives(); | ||
5695 | msg(DBG_INI,"check_drives done.\n"); | ||
5696 | if (i>=0) break; /* drive found */ | ||
5697 | } /* end of cycling through the set of possible I/O port addresses */ | ||
5698 | |||
5699 | if (ndrives==0) | ||
5700 | { | ||
5701 | msg(DBG_INF, "No drive found.\n"); | ||
5702 | #ifdef MODULE | ||
5703 | return -EIO; | ||
5704 | #else | ||
5705 | goto init_done; | ||
5706 | #endif /* MODULE */ | ||
5707 | } | ||
5708 | |||
5709 | if (port_index>0) | ||
5710 | { | ||
5711 | msg(DBG_INF, "You should read Documentation/cdrom/sbpcd\n"); | ||
5712 | msg(DBG_INF, "and then configure sbpcd.h for your hardware.\n"); | ||
5713 | } | ||
5714 | check_datarate(); | ||
5715 | msg(DBG_INI,"check_datarate done.\n"); | ||
5716 | |||
5717 | for (j=0;j<NR_SBPCD;j++) | ||
5718 | { | ||
5719 | struct sbpcd_drive *p = D_S + j; | ||
5720 | if (p->drv_id==-1) | ||
5721 | continue; | ||
5722 | switch_drive(p); | ||
5723 | #if 1 | ||
5724 | if (!famL_drive) cc_DriveReset(); | ||
5725 | #endif | ||
5726 | if (!st_spinning) cc_SpinUp(); | ||
5727 | p->sbp_first_frame = -1; /* First frame in buffer */ | ||
5728 | p->sbp_last_frame = -1; /* Last frame in buffer */ | ||
5729 | p->sbp_read_frames = 0; /* Number of frames being read to buffer */ | ||
5730 | p->sbp_current = 0; /* Frame being currently read */ | ||
5731 | p->CD_changed=1; | ||
5732 | p->frame_size=CD_FRAMESIZE; | ||
5733 | p->f_eject=0; | ||
5734 | #if EJECT | ||
5735 | if (!fam0_drive) p->f_eject=1; | ||
5736 | #endif /* EJECT */ | ||
5737 | cc_ReadStatus(); | ||
5738 | i=ResponseStatus(); /* returns orig. status or p_busy_new */ | ||
5739 | if (famT_drive) i=ResponseStatus(); /* returns orig. status or p_busy_new */ | ||
5740 | if (i<0) | ||
5741 | { | ||
5742 | if (i!=-402) | ||
5743 | msg(DBG_INF,"init: ResponseStatus returns %d.\n",i); | ||
5744 | } | ||
5745 | else | ||
5746 | { | ||
5747 | if (st_check) | ||
5748 | { | ||
5749 | i=cc_ReadError(); | ||
5750 | msg(DBG_INI,"init: cc_ReadError returns %d\n",i); | ||
5751 | } | ||
5752 | } | ||
5753 | msg(DBG_INI,"init: first GetStatus: %d\n",i); | ||
5754 | msg(DBG_LCS,"init: first GetStatus: error_byte=%d\n", | ||
5755 | p->error_byte); | ||
5756 | if (p->error_byte==aud_12) | ||
5757 | { | ||
5758 | timeout=jiffies+2*HZ; | ||
5759 | do | ||
5760 | { | ||
5761 | i=GetStatus(); | ||
5762 | msg(DBG_INI,"init: second GetStatus: %02X\n",i); | ||
5763 | msg(DBG_LCS, | ||
5764 | "init: second GetStatus: error_byte=%d\n", | ||
5765 | p->error_byte); | ||
5766 | if (i<0) break; | ||
5767 | if (!st_caddy_in) break; | ||
5768 | } | ||
5769 | while ((!st_diskok)||time_after(jiffies, timeout)); | ||
5770 | } | ||
5771 | i=SetSpeed(); | ||
5772 | if (i>=0) p->CD_changed=1; | ||
5773 | } | ||
5774 | |||
5775 | if (!request_region(CDo_command,4,major_name)) | ||
5776 | { | ||
5777 | printk(KERN_WARNING "sbpcd: Unable to request region 0x%x\n", CDo_command); | ||
5778 | return -EIO; | ||
5779 | } | ||
5780 | |||
5781 | /* | ||
5782 | * Turn on the CD audio channels. | ||
5783 | * The addresses are obtained from SOUND_BASE (see sbpcd.h). | ||
5784 | */ | ||
5785 | #if SOUND_BASE | ||
5786 | OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */ | ||
5787 | OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */ | ||
5788 | #endif /* SOUND_BASE */ | ||
5789 | |||
5790 | if (register_blkdev(MAJOR_NR, major_name)) { | ||
5791 | #ifdef MODULE | ||
5792 | return -EIO; | ||
5793 | #else | ||
5794 | goto init_done; | ||
5795 | #endif /* MODULE */ | ||
5796 | } | ||
5797 | |||
5798 | /* | ||
5799 | * init error handling is broken beyond belief in this driver... | ||
5800 | */ | ||
5801 | sbpcd_queue = blk_init_queue(do_sbpcd_request, &sbpcd_lock); | ||
5802 | if (!sbpcd_queue) { | ||
5803 | release_region(CDo_command,4); | ||
5804 | unregister_blkdev(MAJOR_NR, major_name); | ||
5805 | return -ENOMEM; | ||
5806 | } | ||
5807 | |||
5808 | for (j=0;j<NR_SBPCD;j++) | ||
5809 | { | ||
5810 | struct cdrom_device_info * sbpcd_infop; | ||
5811 | struct gendisk *disk; | ||
5812 | struct sbpcd_drive *p = D_S + j; | ||
5813 | |||
5814 | if (p->drv_id==-1) continue; | ||
5815 | switch_drive(p); | ||
5816 | #ifdef SAFE_MIXED | ||
5817 | p->has_data=0; | ||
5818 | #endif /* SAFE_MIXED */ | ||
5819 | /* | ||
5820 | * allocate memory for the frame buffers | ||
5821 | */ | ||
5822 | p->aud_buf=NULL; | ||
5823 | p->sbp_audsiz=0; | ||
5824 | p->sbp_bufsiz=buffers; | ||
5825 | if (p->drv_type&drv_fam1) | ||
5826 | if (READ_AUDIO>0) | ||
5827 | p->sbp_audsiz = READ_AUDIO; | ||
5828 | p->sbp_buf=(u_char *) vmalloc(buffers*CD_FRAMESIZE); | ||
5829 | if (!p->sbp_buf) { | ||
5830 | msg(DBG_INF,"data buffer (%d frames) not available.\n", | ||
5831 | buffers); | ||
5832 | if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL)) | ||
5833 | { | ||
5834 | printk("Can't unregister %s\n", major_name); | ||
5835 | } | ||
5836 | release_region(CDo_command,4); | ||
5837 | blk_cleanup_queue(sbpcd_queue); | ||
5838 | return -EIO; | ||
5839 | } | ||
5840 | #ifdef MODULE | ||
5841 | msg(DBG_INF,"data buffer size: %d frames.\n",buffers); | ||
5842 | #endif /* MODULE */ | ||
5843 | if (p->sbp_audsiz>0) | ||
5844 | { | ||
5845 | p->aud_buf=(u_char *) vmalloc(p->sbp_audsiz*CD_FRAMESIZE_RAW); | ||
5846 | if (p->aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",p->sbp_audsiz); | ||
5847 | else msg(DBG_INF,"audio buffer size: %d frames.\n",p->sbp_audsiz); | ||
5848 | } | ||
5849 | sbpcd_infop = vmalloc(sizeof (struct cdrom_device_info)); | ||
5850 | if (sbpcd_infop == NULL) | ||
5851 | { | ||
5852 | release_region(CDo_command,4); | ||
5853 | blk_cleanup_queue(sbpcd_queue); | ||
5854 | return -ENOMEM; | ||
5855 | } | ||
5856 | memset(sbpcd_infop, 0, sizeof(struct cdrom_device_info)); | ||
5857 | sbpcd_infop->ops = &sbpcd_dops; | ||
5858 | sbpcd_infop->speed = 2; | ||
5859 | sbpcd_infop->capacity = 1; | ||
5860 | sprintf(sbpcd_infop->name, "sbpcd%d", j); | ||
5861 | sbpcd_infop->handle = p; | ||
5862 | p->sbpcd_infop = sbpcd_infop; | ||
5863 | disk = alloc_disk(1); | ||
5864 | disk->major = MAJOR_NR; | ||
5865 | disk->first_minor = j; | ||
5866 | disk->fops = &sbpcd_bdops; | ||
5867 | strcpy(disk->disk_name, sbpcd_infop->name); | ||
5868 | disk->flags = GENHD_FL_CD; | ||
5869 | p->disk = disk; | ||
5870 | if (register_cdrom(sbpcd_infop)) | ||
5871 | { | ||
5872 | printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n"); | ||
5873 | } | ||
5874 | disk->private_data = p; | ||
5875 | disk->queue = sbpcd_queue; | ||
5876 | add_disk(disk); | ||
5877 | } | ||
5878 | blk_queue_hardsect_size(sbpcd_queue, CD_FRAMESIZE); | ||
5879 | |||
5880 | #ifndef MODULE | ||
5881 | init_done: | ||
5882 | #endif | ||
5883 | return 0; | ||
5884 | } | ||
5885 | /*==========================================================================*/ | ||
5886 | #ifdef MODULE | ||
5887 | static void sbpcd_exit(void) | ||
5888 | { | ||
5889 | int j; | ||
5890 | |||
5891 | if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL)) | ||
5892 | { | ||
5893 | msg(DBG_INF, "What's that: can't unregister %s.\n", major_name); | ||
5894 | return; | ||
5895 | } | ||
5896 | release_region(CDo_command,4); | ||
5897 | blk_cleanup_queue(sbpcd_queue); | ||
5898 | for (j=0;j<NR_SBPCD;j++) | ||
5899 | { | ||
5900 | if (D_S[j].drv_id==-1) continue; | ||
5901 | del_gendisk(D_S[j].disk); | ||
5902 | put_disk(D_S[j].disk); | ||
5903 | vfree(D_S[j].sbp_buf); | ||
5904 | if (D_S[j].sbp_audsiz>0) | ||
5905 | vfree(D_S[j].aud_buf); | ||
5906 | if ((unregister_cdrom(D_S[j].sbpcd_infop) == -EINVAL)) | ||
5907 | { | ||
5908 | msg(DBG_INF, "What's that: can't unregister info %s.\n", major_name); | ||
5909 | return; | ||
5910 | } | ||
5911 | vfree(D_S[j].sbpcd_infop); | ||
5912 | } | ||
5913 | msg(DBG_INF, "%s module released.\n", major_name); | ||
5914 | } | ||
5915 | |||
5916 | |||
5917 | module_init(__sbpcd_init) /*HACK!*/; | ||
5918 | module_exit(sbpcd_exit); | ||
5919 | |||
5920 | |||
5921 | #endif /* MODULE */ | ||
5922 | static int sbpcd_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
5923 | { | ||
5924 | struct sbpcd_drive *p = cdi->handle; | ||
5925 | msg(DBG_CHK,"media_check (%s) called\n", cdi->name); | ||
5926 | |||
5927 | if (p->CD_changed==0xFF) | ||
5928 | { | ||
5929 | p->CD_changed=0; | ||
5930 | msg(DBG_CHK,"medium changed (drive %s)\n", cdi->name); | ||
5931 | current_drive->diskstate_flags &= ~toc_bit; | ||
5932 | /* we *don't* need invalidate here, it's done by caller */ | ||
5933 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
5934 | #ifdef SAFE_MIXED | ||
5935 | current_drive->has_data=0; | ||
5936 | #endif /* SAFE_MIXED */ | ||
5937 | |||
5938 | return (1); | ||
5939 | } | ||
5940 | else | ||
5941 | return (0); | ||
5942 | } | ||
5943 | |||
5944 | MODULE_LICENSE("GPL"); | ||
5945 | /* FIXME: Old modules.conf claims MATSUSHITA_CDROM2_MAJOR and CDROM3, but | ||
5946 | AFAICT this doesn't support those majors, so why? --RR 30 Jul 2003 */ | ||
5947 | MODULE_ALIAS_BLOCKDEV_MAJOR(MATSUSHITA_CDROM_MAJOR); | ||
5948 | |||
5949 | /*==========================================================================*/ | ||
5950 | /* | ||
5951 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
5952 | * Emacs will notice this stuff at the end of the file and automatically | ||
5953 | * adjust the settings for this buffer only. This must remain at the end | ||
5954 | * of the file. | ||
5955 | * --------------------------------------------------------------------------- | ||
5956 | * Local variables: | ||
5957 | * c-indent-level: 8 | ||
5958 | * c-brace-imaginary-offset: 0 | ||
5959 | * c-brace-offset: -8 | ||
5960 | * c-argdecl-indent: 8 | ||
5961 | * c-label-offset: -8 | ||
5962 | * c-continued-statement-offset: 8 | ||
5963 | * c-continued-brace-offset: 0 | ||
5964 | * End: | ||
5965 | */ | ||
5966 | |||
diff --git a/drivers/cdrom/sbpcd.h b/drivers/cdrom/sbpcd.h deleted file mode 100644 index 2f2225f13c6f..000000000000 --- a/drivers/cdrom/sbpcd.h +++ /dev/null | |||
@@ -1,839 +0,0 @@ | |||
1 | /* | ||
2 | * sbpcd.h Specify interface address and interface type here. | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * Attention! This file contains user-serviceable parts! | ||
7 | * I recommend to make use of it... | ||
8 | * If you feel helpless, look into Documentation/cdrom/sbpcd | ||
9 | * (good idea anyway, at least before mailing me). | ||
10 | * | ||
11 | * The definitions for the first controller can get overridden by | ||
12 | * the kernel command line ("lilo boot option"). | ||
13 | * Examples: | ||
14 | * sbpcd=0x300,LaserMate | ||
15 | * or | ||
16 | * sbpcd=0x230,SoundBlaster | ||
17 | * or | ||
18 | * sbpcd=0x338,SoundScape | ||
19 | * or | ||
20 | * sbpcd=0x2C0,Teac16bit | ||
21 | * | ||
22 | * If sbpcd gets used as a module, you can load it with | ||
23 | * insmod sbpcd.o sbpcd=0x300,0 | ||
24 | * or | ||
25 | * insmod sbpcd.o sbpcd=0x230,1 | ||
26 | * or | ||
27 | * insmod sbpcd.o sbpcd=0x338,2 | ||
28 | * or | ||
29 | * insmod sbpcd.o sbpcd=0x2C0,3 | ||
30 | * respective to override the configured address and type. | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | * define your CDROM port base address as CDROM_PORT | ||
35 | * and specify the type of your interface card as SBPRO. | ||
36 | * | ||
37 | * address: | ||
38 | * ======== | ||
39 | * SBPRO type addresses typically are 0x0230 (=0x220+0x10), 0x0250, ... | ||
40 | * LASERMATE type (CI-101P, WDH-7001C) addresses typically are 0x0300, ... | ||
41 | * SOUNDSCAPE addresses are from the LASERMATE type and range. You have to | ||
42 | * specify the REAL address here, not the configuration port address. Look | ||
43 | * at the CDROM driver's invoking line within your DOS CONFIG.SYS, or let | ||
44 | * sbpcd auto-probe, if you are not firm with the address. | ||
45 | * There are some soundcards on the market with 0x0630, 0x0650, ...; their | ||
46 | * type is not obvious (both types are possible). | ||
47 | * | ||
48 | * example: if your SBPRO audio address is 0x220, specify 0x230 and SBPRO 1. | ||
49 | * if your soundcard has its CDROM port above 0x300, specify | ||
50 | * that address and try SBPRO 0 first. | ||
51 | * if your SoundScape configuration port is at 0x330, specify | ||
52 | * 0x338 and SBPRO 2. | ||
53 | * | ||
54 | * interface type: | ||
55 | * =============== | ||
56 | * set SBPRO to 1 for "true" SoundBlaster card | ||
57 | * set SBPRO to 0 for "compatible" soundcards and | ||
58 | * for "poor" (no sound) interface cards. | ||
59 | * set SBPRO to 2 for Ensonic SoundScape or SPEA Media FX cards | ||
60 | * set SBPRO to 3 for Teac 16bit interface cards | ||
61 | * | ||
62 | * Almost all "compatible" sound boards need to set SBPRO to 0. | ||
63 | * If SBPRO is set wrong, the drives will get found - but any | ||
64 | * data access will give errors (audio access will work). | ||
65 | * The "OmniCD" no-sound interface card from CreativeLabs and most Teac | ||
66 | * interface cards need SBPRO 1. | ||
67 | * | ||
68 | * sound base: | ||
69 | * =========== | ||
70 | * The SOUND_BASE definition tells if we should try to turn the CD sound | ||
71 | * channels on. It will only be of use regarding soundcards with a SbPro | ||
72 | * compatible mixer. | ||
73 | * | ||
74 | * Example: #define SOUND_BASE 0x220 enables the sound card's CD channels | ||
75 | * #define SOUND_BASE 0 leaves the soundcard untouched | ||
76 | */ | ||
77 | #define CDROM_PORT 0x340 /* <-----------<< port address */ | ||
78 | #define SBPRO 0 /* <-----------<< interface type */ | ||
79 | #define MAX_DRIVES 4 /* set to 1 if the card does not use "drive select" */ | ||
80 | #define SOUND_BASE 0x220 /* <-----------<< sound address of this card or 0 */ | ||
81 | |||
82 | /* | ||
83 | * some more or less user dependent definitions - service them! | ||
84 | */ | ||
85 | |||
86 | /* Set this to 0 once you have configured your interface definitions right. */ | ||
87 | #define DISTRIBUTION 1 | ||
88 | |||
89 | /* | ||
90 | * Time to wait after giving a message. | ||
91 | * This gets important if you enable non-standard DBG_xxx flags. | ||
92 | * You will see what happens if you omit the pause or make it | ||
93 | * too short. Be warned! | ||
94 | */ | ||
95 | #define KLOGD_PAUSE 1 | ||
96 | |||
97 | /* tray control: eject tray if no disk is in */ | ||
98 | #if DISTRIBUTION | ||
99 | #define JUKEBOX 0 | ||
100 | #else | ||
101 | #define JUKEBOX 1 | ||
102 | #endif /* DISTRIBUTION */ | ||
103 | |||
104 | /* tray control: eject tray after last use */ | ||
105 | #if DISTRIBUTION | ||
106 | #define EJECT 0 | ||
107 | #else | ||
108 | #define EJECT 1 | ||
109 | #endif /* DISTRIBUTION */ | ||
110 | |||
111 | /* max. number of audio frames to read with one */ | ||
112 | /* request (allocates n* 2352 bytes kernel memory!) */ | ||
113 | /* may be freely adjusted, f.e. 75 (= 1 sec.), at */ | ||
114 | /* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ | ||
115 | #define READ_AUDIO 0 | ||
116 | |||
117 | /* Optimizations for the Teac CD-55A drive read performance. | ||
118 | * SBP_TEAC_SPEED can be changed here, or one can set the | ||
119 | * variable "teac" when loading as a module. | ||
120 | * Valid settings are: | ||
121 | * 0 - very slow - the recommended "DISTRIBUTION 1" setup. | ||
122 | * 1 - 2x performance with little overhead. No busy waiting. | ||
123 | * 2 - 4x performance with 5ms overhead per read. Busy wait. | ||
124 | * | ||
125 | * Setting SBP_TEAC_SPEED or the variable 'teac' to anything | ||
126 | * other than 0 may cause problems. If you run into them, first | ||
127 | * change SBP_TEAC_SPEED back to 0 and see if your drive responds | ||
128 | * normally. If yes, you are "allowed" to report your case - to help | ||
129 | * me with the driver, not to solve your hassle. Don´t mail if you | ||
130 | * simply are stuck into your own "tuning" experiments, you know? | ||
131 | */ | ||
132 | #define SBP_TEAC_SPEED 1 | ||
133 | |||
134 | /*==========================================================================*/ | ||
135 | /*==========================================================================*/ | ||
136 | /* | ||
137 | * nothing to change below here if you are not fully aware what you're doing | ||
138 | */ | ||
139 | #ifndef _LINUX_SBPCD_H | ||
140 | |||
141 | #define _LINUX_SBPCD_H | ||
142 | /*==========================================================================*/ | ||
143 | /*==========================================================================*/ | ||
144 | /* | ||
145 | * driver's own read_ahead, data mode | ||
146 | */ | ||
147 | #define SBP_BUFFER_FRAMES 8 | ||
148 | |||
149 | #define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ | ||
150 | #undef FUTURE | ||
151 | #undef SAFE_MIXED | ||
152 | |||
153 | #define TEST_UPC 0 | ||
154 | #define SPEA_TEST 0 | ||
155 | #define TEST_STI 0 | ||
156 | #define OLD_BUSY 0 | ||
157 | #undef PATH_CHECK | ||
158 | #ifndef SOUND_BASE | ||
159 | #define SOUND_BASE 0 | ||
160 | #endif | ||
161 | #if DISTRIBUTION | ||
162 | #undef SBP_TEAC_SPEED | ||
163 | #define SBP_TEAC_SPEED 0 | ||
164 | #endif | ||
165 | /*==========================================================================*/ | ||
166 | /* | ||
167 | * DDI interface definitions | ||
168 | * "invented" by Fred N. van Kempen.. | ||
169 | */ | ||
170 | #define DDIOCSDBG 0x9000 | ||
171 | |||
172 | /*==========================================================================*/ | ||
173 | /* | ||
174 | * "private" IOCTL functions | ||
175 | */ | ||
176 | #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ | ||
177 | |||
178 | /*==========================================================================*/ | ||
179 | /* | ||
180 | * Debug output levels | ||
181 | */ | ||
182 | #define DBG_INF 1 /* necessary information */ | ||
183 | #define DBG_BSZ 2 /* BLOCK_SIZE trace */ | ||
184 | #define DBG_REA 3 /* READ status trace */ | ||
185 | #define DBG_CHK 4 /* MEDIA CHECK trace */ | ||
186 | #define DBG_TIM 5 /* datarate timer test */ | ||
187 | #define DBG_INI 6 /* initialization trace */ | ||
188 | #define DBG_TOC 7 /* tell TocEntry values */ | ||
189 | #define DBG_IOC 8 /* ioctl trace */ | ||
190 | #define DBG_STA 9 /* ResponseStatus() trace */ | ||
191 | #define DBG_ERR 10 /* cc_ReadError() trace */ | ||
192 | #define DBG_CMD 11 /* cmd_out() trace */ | ||
193 | #define DBG_WRN 12 /* give explanation before auto-probing */ | ||
194 | #define DBG_MUL 13 /* multi session code test */ | ||
195 | #define DBG_IDX 14 /* test code for drive_id !=0 */ | ||
196 | #define DBG_IOX 15 /* some special information */ | ||
197 | #define DBG_DID 16 /* drive ID test */ | ||
198 | #define DBG_RES 17 /* drive reset info */ | ||
199 | #define DBG_SPI 18 /* SpinUp test */ | ||
200 | #define DBG_IOS 19 /* ioctl trace: subchannel functions */ | ||
201 | #define DBG_IO2 20 /* ioctl trace: general */ | ||
202 | #define DBG_UPC 21 /* show UPC information */ | ||
203 | #define DBG_XA1 22 /* XA mode debugging */ | ||
204 | #define DBG_LCK 23 /* door (un)lock info */ | ||
205 | #define DBG_SQ1 24 /* dump SubQ frame */ | ||
206 | #define DBG_AUD 25 /* READ AUDIO debugging */ | ||
207 | #define DBG_SEQ 26 /* Sequoia interface configuration trace */ | ||
208 | #define DBG_LCS 27 /* Longshine LCS-7260 debugging trace */ | ||
209 | #define DBG_CD2 28 /* MKE/Funai CD200 debugging trace */ | ||
210 | #define DBG_TEA 29 /* TEAC CD-55A debugging trace */ | ||
211 | #define DBG_ECS 30 /* ECS-AT (Vertos 100) debugging trace */ | ||
212 | #define DBG_000 31 /* unnecessary information */ | ||
213 | |||
214 | /*==========================================================================*/ | ||
215 | /*==========================================================================*/ | ||
216 | |||
217 | /* | ||
218 | * bits of flags_cmd_out: | ||
219 | */ | ||
220 | #define f_respo3 0x100 | ||
221 | #define f_putcmd 0x80 | ||
222 | #define f_respo2 0x40 | ||
223 | #define f_lopsta 0x20 | ||
224 | #define f_getsta 0x10 | ||
225 | #define f_ResponseStatus 0x08 | ||
226 | #define f_obey_p_check 0x04 | ||
227 | #define f_bit1 0x02 | ||
228 | #define f_wait_if_busy 0x01 | ||
229 | |||
230 | /* | ||
231 | * diskstate_flags: | ||
232 | */ | ||
233 | #define x80_bit 0x80 | ||
234 | #define upc_bit 0x40 | ||
235 | #define volume_bit 0x20 | ||
236 | #define toc_bit 0x10 | ||
237 | #define multisession_bit 0x08 | ||
238 | #define cd_size_bit 0x04 | ||
239 | #define subq_bit 0x02 | ||
240 | #define frame_size_bit 0x01 | ||
241 | |||
242 | /* | ||
243 | * disk states (bits of diskstate_flags): | ||
244 | */ | ||
245 | #define upc_valid (current_drive->diskstate_flags&upc_bit) | ||
246 | #define volume_valid (current_drive->diskstate_flags&volume_bit) | ||
247 | #define toc_valid (current_drive->diskstate_flags&toc_bit) | ||
248 | #define cd_size_valid (current_drive->diskstate_flags&cd_size_bit) | ||
249 | #define subq_valid (current_drive->diskstate_flags&subq_bit) | ||
250 | #define frame_size_valid (current_drive->diskstate_flags&frame_size_bit) | ||
251 | |||
252 | /* | ||
253 | * the status_bits variable | ||
254 | */ | ||
255 | #define p_success 0x100 | ||
256 | #define p_door_closed 0x80 | ||
257 | #define p_caddy_in 0x40 | ||
258 | #define p_spinning 0x20 | ||
259 | #define p_check 0x10 | ||
260 | #define p_busy_new 0x08 | ||
261 | #define p_door_locked 0x04 | ||
262 | #define p_disk_ok 0x01 | ||
263 | |||
264 | /* | ||
265 | * LCS-7260 special status result bits: | ||
266 | */ | ||
267 | #define p_lcs_door_locked 0x02 | ||
268 | #define p_lcs_door_closed 0x01 /* probably disk_in */ | ||
269 | |||
270 | /* | ||
271 | * CR-52x special status result bits: | ||
272 | */ | ||
273 | #define p_caddin_old 0x40 | ||
274 | #define p_success_old 0x08 | ||
275 | #define p_busy_old 0x04 | ||
276 | #define p_bit_1 0x02 /* hopefully unused now */ | ||
277 | |||
278 | /* | ||
279 | * "generation specific" defs of the status result bits: | ||
280 | */ | ||
281 | #define p0_door_closed 0x80 | ||
282 | #define p0_caddy_in 0x40 | ||
283 | #define p0_spinning 0x20 | ||
284 | #define p0_check 0x10 | ||
285 | #define p0_success 0x08 /* unused */ | ||
286 | #define p0_busy 0x04 | ||
287 | #define p0_bit_1 0x02 /* unused */ | ||
288 | #define p0_disk_ok 0x01 | ||
289 | |||
290 | #define pL_disk_in 0x40 | ||
291 | #define pL_spinning 0x20 | ||
292 | #define pL_check 0x10 | ||
293 | #define pL_success 0x08 /* unused ?? */ | ||
294 | #define pL_busy 0x04 | ||
295 | #define pL_door_locked 0x02 | ||
296 | #define pL_door_closed 0x01 | ||
297 | |||
298 | #define pV_door_closed 0x40 | ||
299 | #define pV_spinning 0x20 | ||
300 | #define pV_check 0x10 | ||
301 | #define pV_success 0x08 | ||
302 | #define pV_busy 0x04 | ||
303 | #define pV_door_locked 0x02 | ||
304 | #define pV_disk_ok 0x01 | ||
305 | |||
306 | #define p1_door_closed 0x80 | ||
307 | #define p1_disk_in 0x40 | ||
308 | #define p1_spinning 0x20 | ||
309 | #define p1_check 0x10 | ||
310 | #define p1_busy 0x08 | ||
311 | #define p1_door_locked 0x04 | ||
312 | #define p1_bit_1 0x02 /* unused */ | ||
313 | #define p1_disk_ok 0x01 | ||
314 | |||
315 | #define p2_disk_ok 0x80 | ||
316 | #define p2_door_locked 0x40 | ||
317 | #define p2_spinning 0x20 | ||
318 | #define p2_busy2 0x10 | ||
319 | #define p2_busy1 0x08 | ||
320 | #define p2_door_closed 0x04 | ||
321 | #define p2_disk_in 0x02 | ||
322 | #define p2_check 0x01 | ||
323 | |||
324 | /* | ||
325 | * used drive states: | ||
326 | */ | ||
327 | #define st_door_closed (current_drive->status_bits&p_door_closed) | ||
328 | #define st_caddy_in (current_drive->status_bits&p_caddy_in) | ||
329 | #define st_spinning (current_drive->status_bits&p_spinning) | ||
330 | #define st_check (current_drive->status_bits&p_check) | ||
331 | #define st_busy (current_drive->status_bits&p_busy_new) | ||
332 | #define st_door_locked (current_drive->status_bits&p_door_locked) | ||
333 | #define st_diskok (current_drive->status_bits&p_disk_ok) | ||
334 | |||
335 | /* | ||
336 | * bits of the CDi_status register: | ||
337 | */ | ||
338 | #define s_not_result_ready 0x04 /* 0: "result ready" */ | ||
339 | #define s_not_data_ready 0x02 /* 0: "data ready" */ | ||
340 | #define s_attention 0x01 /* 1: "attention required" */ | ||
341 | /* | ||
342 | * usable as: | ||
343 | */ | ||
344 | #define DRV_ATTN ((inb(CDi_status)&s_attention)!=0) | ||
345 | #define DATA_READY ((inb(CDi_status)&s_not_data_ready)==0) | ||
346 | #define RESULT_READY ((inb(CDi_status)&s_not_result_ready)==0) | ||
347 | |||
348 | /* | ||
349 | * drive families and types (firmware versions): | ||
350 | */ | ||
351 | #define drv_fam0 0x0100 /* CR-52x family */ | ||
352 | #define drv_199 (drv_fam0+0x01) /* <200 */ | ||
353 | #define drv_200 (drv_fam0+0x02) /* <201 */ | ||
354 | #define drv_201 (drv_fam0+0x03) /* <210 */ | ||
355 | #define drv_210 (drv_fam0+0x04) /* <211 */ | ||
356 | #define drv_211 (drv_fam0+0x05) /* <300 */ | ||
357 | #define drv_300 (drv_fam0+0x06) /* >=300 */ | ||
358 | |||
359 | #define drv_fam1 0x0200 /* CR-56x family */ | ||
360 | #define drv_099 (drv_fam1+0x01) /* <100 */ | ||
361 | #define drv_100 (drv_fam1+0x02) /* >=100, only 1.02 and 5.00 known */ | ||
362 | |||
363 | #define drv_fam2 0x0400 /* CD200 family */ | ||
364 | |||
365 | #define drv_famT 0x0800 /* TEAC CD-55A */ | ||
366 | |||
367 | #define drv_famL 0x1000 /* Longshine family */ | ||
368 | #define drv_260 (drv_famL+0x01) /* LCS-7260 */ | ||
369 | #define drv_e1 (drv_famL+0x01) /* LCS-7260, firmware "A E1" */ | ||
370 | #define drv_f4 (drv_famL+0x02) /* LCS-7260, firmware "A4F4" */ | ||
371 | |||
372 | #define drv_famV 0x2000 /* ECS-AT (vertos-100) family */ | ||
373 | #define drv_at (drv_famV+0x01) /* ECS-AT, firmware "1.00" */ | ||
374 | |||
375 | #define fam0_drive (current_drive->drv_type&drv_fam0) | ||
376 | #define famL_drive (current_drive->drv_type&drv_famL) | ||
377 | #define famV_drive (current_drive->drv_type&drv_famV) | ||
378 | #define fam1_drive (current_drive->drv_type&drv_fam1) | ||
379 | #define fam2_drive (current_drive->drv_type&drv_fam2) | ||
380 | #define famT_drive (current_drive->drv_type&drv_famT) | ||
381 | #define fam0L_drive (current_drive->drv_type&(drv_fam0|drv_famL)) | ||
382 | #define fam0V_drive (current_drive->drv_type&(drv_fam0|drv_famV)) | ||
383 | #define famLV_drive (current_drive->drv_type&(drv_famL|drv_famV)) | ||
384 | #define fam0LV_drive (current_drive->drv_type&(drv_fam0|drv_famL|drv_famV)) | ||
385 | #define fam1L_drive (current_drive->drv_type&(drv_fam1|drv_famL)) | ||
386 | #define fam1V_drive (current_drive->drv_type&(drv_fam1|drv_famV)) | ||
387 | #define fam1LV_drive (current_drive->drv_type&(drv_fam1|drv_famL|drv_famV)) | ||
388 | #define fam01_drive (current_drive->drv_type&(drv_fam0|drv_fam1)) | ||
389 | #define fam12_drive (current_drive->drv_type&(drv_fam1|drv_fam2)) | ||
390 | #define fam2T_drive (current_drive->drv_type&(drv_fam2|drv_famT)) | ||
391 | |||
392 | /* | ||
393 | * audio states: | ||
394 | */ | ||
395 | #define audio_completed 3 /* Forgot this one! --AJK */ | ||
396 | #define audio_playing 2 | ||
397 | #define audio_pausing 1 | ||
398 | |||
399 | /* | ||
400 | * drv_pattern, drv_options: | ||
401 | */ | ||
402 | #define speed_auto 0x80 | ||
403 | #define speed_300 0x40 | ||
404 | #define speed_150 0x20 | ||
405 | #define audio_mono 0x04 | ||
406 | |||
407 | /* | ||
408 | * values of cmd_type (0 else): | ||
409 | */ | ||
410 | #define READ_M1 0x01 /* "data mode 1": 2048 bytes per frame */ | ||
411 | #define READ_M2 0x02 /* "data mode 2": 12+2048+280 bytes per frame */ | ||
412 | #define READ_SC 0x04 /* "subchannel info": 96 bytes per frame */ | ||
413 | #define READ_AU 0x08 /* "audio frame": 2352 bytes per frame */ | ||
414 | |||
415 | /* | ||
416 | * sense_byte: | ||
417 | * | ||
418 | * values: 00 | ||
419 | * 01 | ||
420 | * 81 | ||
421 | * 82 "raw audio" mode | ||
422 | * xx from infobuf[0] after 85 00 00 00 00 00 00 | ||
423 | */ | ||
424 | |||
425 | /* audio status (bin) */ | ||
426 | #define aud_00 0x00 /* Audio status byte not supported or not valid */ | ||
427 | #define audx11 0x0b /* Audio play operation in progress */ | ||
428 | #define audx12 0x0c /* Audio play operation paused */ | ||
429 | #define audx13 0x0d /* Audio play operation successfully completed */ | ||
430 | #define audx14 0x0e /* Audio play operation stopped due to error */ | ||
431 | #define audx15 0x0f /* No current audio status to return */ | ||
432 | /* audio status (bcd) */ | ||
433 | #define aud_11 0x11 /* Audio play operation in progress */ | ||
434 | #define aud_12 0x12 /* Audio play operation paused */ | ||
435 | #define aud_13 0x13 /* Audio play operation successfully completed */ | ||
436 | #define aud_14 0x14 /* Audio play operation stopped due to error */ | ||
437 | #define aud_15 0x15 /* No current audio status to return */ | ||
438 | |||
439 | /* | ||
440 | * highest allowed drive number (MINOR+1) | ||
441 | */ | ||
442 | #define NR_SBPCD 4 | ||
443 | |||
444 | /* | ||
445 | * we try to never disable interrupts - seems to work | ||
446 | */ | ||
447 | #define SBPCD_DIS_IRQ 0 | ||
448 | |||
449 | /* | ||
450 | * "write byte to port" | ||
451 | */ | ||
452 | #define OUT(x,y) outb(y,x) | ||
453 | |||
454 | /*==========================================================================*/ | ||
455 | |||
456 | #define MIXER_addr SOUND_BASE+4 /* sound card's address register */ | ||
457 | #define MIXER_data SOUND_BASE+5 /* sound card's data register */ | ||
458 | #define MIXER_CD_Volume 0x28 /* internal SB Pro register address */ | ||
459 | |||
460 | /*==========================================================================*/ | ||
461 | |||
462 | #define MAX_TRACKS 99 | ||
463 | |||
464 | #define ERR_DISKCHANGE 615 | ||
465 | |||
466 | /*==========================================================================*/ | ||
467 | /* | ||
468 | * To make conversions easier (machine dependent!) | ||
469 | */ | ||
470 | typedef union _msf | ||
471 | { | ||
472 | u_int n; | ||
473 | u_char c[4]; | ||
474 | } MSF; | ||
475 | |||
476 | typedef union _blk | ||
477 | { | ||
478 | u_int n; | ||
479 | u_char c[4]; | ||
480 | } BLK; | ||
481 | |||
482 | /*==========================================================================*/ | ||
483 | |||
484 | /*============================================================================ | ||
485 | ============================================================================== | ||
486 | |||
487 | COMMAND SET of "old" drives like CR-521, CR-522 | ||
488 | (the CR-562 family is different): | ||
489 | |||
490 | No. Command Code | ||
491 | -------------------------------------------- | ||
492 | |||
493 | Drive Commands: | ||
494 | 1 Seek 01 | ||
495 | 2 Read Data 02 | ||
496 | 3 Read XA-Data 03 | ||
497 | 4 Read Header 04 | ||
498 | 5 Spin Up 05 | ||
499 | 6 Spin Down 06 | ||
500 | 7 Diagnostic 07 | ||
501 | 8 Read UPC 08 | ||
502 | 9 Read ISRC 09 | ||
503 | 10 Play Audio 0A | ||
504 | 11 Play Audio MSF 0B | ||
505 | 12 Play Audio Track/Index 0C | ||
506 | |||
507 | Status Commands: | ||
508 | 13 Read Status 81 | ||
509 | 14 Read Error 82 | ||
510 | 15 Read Drive Version 83 | ||
511 | 16 Mode Select 84 | ||
512 | 17 Mode Sense 85 | ||
513 | 18 Set XA Parameter 86 | ||
514 | 19 Read XA Parameter 87 | ||
515 | 20 Read Capacity 88 | ||
516 | 21 Read SUB_Q 89 | ||
517 | 22 Read Disc Code 8A | ||
518 | 23 Read Disc Information 8B | ||
519 | 24 Read TOC 8C | ||
520 | 25 Pause/Resume 8D | ||
521 | 26 Read Packet 8E | ||
522 | 27 Read Path Check 00 | ||
523 | |||
524 | |||
525 | all numbers (lba, msf-bin, msf-bcd, counts) to transfer high byte first | ||
526 | |||
527 | mnemo 7-byte command #bytes response (r0...rn) | ||
528 | ________ ____________________ ____ | ||
529 | |||
530 | Read Status: | ||
531 | status: 81. (1) one-byte command, gives the main | ||
532 | status byte | ||
533 | Read Error: | ||
534 | check1: 82 00 00 00 00 00 00. (6) r1: audio status | ||
535 | |||
536 | Read Packet: | ||
537 | check2: 8e xx 00 00 00 00 00. (xx) gets xx bytes response, relating | ||
538 | to commands 01 04 05 07 08 09 | ||
539 | |||
540 | Play Audio: | ||
541 | play: 0a ll-bb-aa nn-nn-nn. (0) play audio, ll-bb-aa: starting block (lba), | ||
542 | nn-nn-nn: #blocks | ||
543 | Play Audio MSF: | ||
544 | 0b mm-ss-ff mm-ss-ff (0) play audio from/to | ||
545 | |||
546 | Play Audio Track/Index: | ||
547 | 0c ... | ||
548 | |||
549 | Pause/Resume: | ||
550 | pause: 8d pr 00 00 00 00 00. (0) pause (pr=00) | ||
551 | resume (pr=80) audio playing | ||
552 | |||
553 | Mode Select: | ||
554 | 84 00 nn-nn ??.?? 00 (0) nn-nn: 2048 or 2340 | ||
555 | possibly defines transfer size | ||
556 | |||
557 | set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1) | ||
558 | le(vel): min=0, max=FF, else half | ||
559 | (firmware 2.11) | ||
560 | |||
561 | Mode Sense: | ||
562 | get_vol: 85 03 00 00 00 00 00. (2) tell current audio volume setting | ||
563 | |||
564 | Read Disc Information: | ||
565 | tocdesc: 8b 00 00 00 00 00 00. (6) read the toc descriptor ("msf-bin"-format) | ||
566 | |||
567 | Read TOC: | ||
568 | tocent: 8c fl nn 00 00 00 00. (8) read toc entry #nn | ||
569 | (fl=0:"lba"-, =2:"msf-bin"-format) | ||
570 | |||
571 | Read Capacity: | ||
572 | capacit: 88 00 00 00 00 00 00. (5) "read CD-ROM capacity" | ||
573 | |||
574 | |||
575 | Read Path Check: | ||
576 | ping: 00 00 00 00 00 00 00. (2) r0=AA, r1=55 | ||
577 | ("ping" if the drive is connected) | ||
578 | |||
579 | Read Drive Version: | ||
580 | ident: 83 00 00 00 00 00 00. (12) gives "MATSHITAn.nn" | ||
581 | (n.nn = 2.01, 2.11., 3.00, ...) | ||
582 | |||
583 | Seek: | ||
584 | seek: 01 00 ll-bb-aa 00 00. (0) | ||
585 | seek: 01 02 mm-ss-ff 00 00. (0) | ||
586 | |||
587 | Read Data: | ||
588 | read: 02 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2048 bytes, | ||
589 | starting at block xx-xx-xx | ||
590 | fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx | ||
591 | |||
592 | Read XA-Data: | ||
593 | read: 03 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2340 bytes, | ||
594 | starting at block xx-xx-xx | ||
595 | fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx | ||
596 | |||
597 | Read SUB_Q: | ||
598 | 89 fl 00 00 00 00 00. (13) r0: audio status, r4-r7: lba/msf, | ||
599 | fl=0: "lba", fl=2: "msf" | ||
600 | |||
601 | Read Disc Code: | ||
602 | 8a 00 00 00 00 00 00. (14) possibly extended "check condition"-info | ||
603 | |||
604 | Read Header: | ||
605 | 04 00 ll-bb-aa 00 00. (0) 4 bytes response with "check2" | ||
606 | 04 02 mm-ss-ff 00 00. (0) 4 bytes response with "check2" | ||
607 | |||
608 | Spin Up: | ||
609 | 05 00 ll-bb-aa 00 00. (0) possibly implies a "seek" | ||
610 | |||
611 | Spin Down: | ||
612 | 06 ... | ||
613 | |||
614 | Diagnostic: | ||
615 | 07 00 ll-bb-aa 00 00. (2) 2 bytes response with "check2" | ||
616 | 07 02 mm-ss-ff 00 00. (2) 2 bytes response with "check2" | ||
617 | |||
618 | Read UPC: | ||
619 | 08 00 ll-bb-aa 00 00. (16) | ||
620 | 08 02 mm-ss-ff 00 00. (16) | ||
621 | |||
622 | Read ISRC: | ||
623 | 09 00 ll-bb-aa 00 00. (15) 15 bytes response with "check2" | ||
624 | 09 02 mm-ss-ff 00 00. (15) 15 bytes response with "check2" | ||
625 | |||
626 | Set XA Parameter: | ||
627 | 86 ... | ||
628 | |||
629 | Read XA Parameter: | ||
630 | 87 ... | ||
631 | |||
632 | ============================================================================== | ||
633 | ============================================================================*/ | ||
634 | |||
635 | /* | ||
636 | * commands | ||
637 | * | ||
638 | * CR-52x: CMD0_ | ||
639 | * CR-56x: CMD1_ | ||
640 | * CD200: CMD2_ | ||
641 | * LCS-7260: CMDL_ | ||
642 | * TEAC CD-55A: CMDT_ | ||
643 | * ECS-AT: CMDV_ | ||
644 | */ | ||
645 | #define CMD1_RESET 0x0a | ||
646 | #define CMD2_RESET 0x01 | ||
647 | #define CMDT_RESET 0xc0 | ||
648 | |||
649 | #define CMD1_LOCK_CTL 0x0c | ||
650 | #define CMD2_LOCK_CTL 0x1e | ||
651 | #define CMDT_LOCK_CTL CMD2_LOCK_CTL | ||
652 | #define CMDL_LOCK_CTL 0x0e | ||
653 | #define CMDV_LOCK_CTL CMDL_LOCK_CTL | ||
654 | |||
655 | #define CMD1_TRAY_CTL 0x07 | ||
656 | #define CMD2_TRAY_CTL 0x1b | ||
657 | #define CMDT_TRAY_CTL CMD2_TRAY_CTL | ||
658 | #define CMDL_TRAY_CTL 0x0d | ||
659 | #define CMDV_TRAY_CTL CMDL_TRAY_CTL | ||
660 | |||
661 | #define CMD1_MULTISESS 0x8d | ||
662 | #define CMDL_MULTISESS 0x8c | ||
663 | #define CMDV_MULTISESS CMDL_MULTISESS | ||
664 | |||
665 | #define CMD1_SUBCHANINF 0x11 | ||
666 | #define CMD2_SUBCHANINF 0x?? | ||
667 | |||
668 | #define CMD1_ABORT 0x08 | ||
669 | #define CMD2_ABORT 0x08 | ||
670 | #define CMDT_ABORT 0x08 | ||
671 | |||
672 | #define CMD2_x02 0x02 | ||
673 | |||
674 | #define CMD2_SETSPEED 0xda | ||
675 | |||
676 | #define CMD0_PATH_CHECK 0x00 | ||
677 | #define CMD1_PATH_CHECK 0x??? | ||
678 | #define CMD2_PATH_CHECK 0x??? | ||
679 | #define CMDT_PATH_CHECK 0x??? | ||
680 | #define CMDL_PATH_CHECK CMD0_PATH_CHECK | ||
681 | #define CMDV_PATH_CHECK CMD0_PATH_CHECK | ||
682 | |||
683 | #define CMD0_SEEK 0x01 | ||
684 | #define CMD1_SEEK CMD0_SEEK | ||
685 | #define CMD2_SEEK 0x2b | ||
686 | #define CMDT_SEEK CMD2_SEEK | ||
687 | #define CMDL_SEEK CMD0_SEEK | ||
688 | #define CMDV_SEEK CMD0_SEEK | ||
689 | |||
690 | #define CMD0_READ 0x02 | ||
691 | #define CMD1_READ 0x10 | ||
692 | #define CMD2_READ 0x28 | ||
693 | #define CMDT_READ CMD2_READ | ||
694 | #define CMDL_READ CMD0_READ | ||
695 | #define CMDV_READ CMD0_READ | ||
696 | |||
697 | #define CMD0_READ_XA 0x03 | ||
698 | #define CMD2_READ_XA 0xd4 | ||
699 | #define CMD2_READ_XA2 0xd5 | ||
700 | #define CMDL_READ_XA CMD0_READ_XA /* really ?? */ | ||
701 | #define CMDV_READ_XA CMD0_READ_XA | ||
702 | |||
703 | #define CMD0_READ_HEAD 0x04 | ||
704 | |||
705 | #define CMD0_SPINUP 0x05 | ||
706 | #define CMD1_SPINUP 0x02 | ||
707 | #define CMD2_SPINUP CMD2_TRAY_CTL | ||
708 | #define CMDL_SPINUP CMD0_SPINUP | ||
709 | #define CMDV_SPINUP CMD0_SPINUP | ||
710 | |||
711 | #define CMD0_SPINDOWN 0x06 /* really??? */ | ||
712 | #define CMD1_SPINDOWN 0x06 | ||
713 | #define CMD2_SPINDOWN CMD2_TRAY_CTL | ||
714 | #define CMDL_SPINDOWN 0x0d | ||
715 | #define CMDV_SPINDOWN CMD0_SPINDOWN | ||
716 | |||
717 | #define CMD0_DIAG 0x07 | ||
718 | |||
719 | #define CMD0_READ_UPC 0x08 | ||
720 | #define CMD1_READ_UPC 0x88 | ||
721 | #define CMD2_READ_UPC 0x??? | ||
722 | #define CMDL_READ_UPC CMD0_READ_UPC | ||
723 | #define CMDV_READ_UPC 0x8f | ||
724 | |||
725 | #define CMD0_READ_ISRC 0x09 | ||
726 | |||
727 | #define CMD0_PLAY 0x0a | ||
728 | #define CMD1_PLAY 0x??? | ||
729 | #define CMD2_PLAY 0x??? | ||
730 | #define CMDL_PLAY CMD0_PLAY | ||
731 | #define CMDV_PLAY CMD0_PLAY | ||
732 | |||
733 | #define CMD0_PLAY_MSF 0x0b | ||
734 | #define CMD1_PLAY_MSF 0x0e | ||
735 | #define CMD2_PLAY_MSF 0x47 | ||
736 | #define CMDT_PLAY_MSF CMD2_PLAY_MSF | ||
737 | #define CMDL_PLAY_MSF 0x??? | ||
738 | |||
739 | #define CMD0_PLAY_TI 0x0c | ||
740 | #define CMD1_PLAY_TI 0x0f | ||
741 | |||
742 | #define CMD0_STATUS 0x81 | ||
743 | #define CMD1_STATUS 0x05 | ||
744 | #define CMD2_STATUS 0x00 | ||
745 | #define CMDT_STATUS CMD2_STATUS | ||
746 | #define CMDL_STATUS CMD0_STATUS | ||
747 | #define CMDV_STATUS CMD0_STATUS | ||
748 | #define CMD2_SEEK_LEADIN 0x00 | ||
749 | |||
750 | #define CMD0_READ_ERR 0x82 | ||
751 | #define CMD1_READ_ERR CMD0_READ_ERR | ||
752 | #define CMD2_READ_ERR 0x03 | ||
753 | #define CMDT_READ_ERR CMD2_READ_ERR /* get audio status */ | ||
754 | #define CMDL_READ_ERR CMD0_READ_ERR | ||
755 | #define CMDV_READ_ERR CMD0_READ_ERR | ||
756 | |||
757 | #define CMD0_READ_VER 0x83 | ||
758 | #define CMD1_READ_VER CMD0_READ_VER | ||
759 | #define CMD2_READ_VER 0x12 | ||
760 | #define CMDT_READ_VER CMD2_READ_VER /* really ?? */ | ||
761 | #define CMDL_READ_VER CMD0_READ_VER | ||
762 | #define CMDV_READ_VER CMD0_READ_VER | ||
763 | |||
764 | #define CMD0_SETMODE 0x84 | ||
765 | #define CMD1_SETMODE 0x09 | ||
766 | #define CMD2_SETMODE 0x55 | ||
767 | #define CMDT_SETMODE CMD2_SETMODE | ||
768 | #define CMDL_SETMODE CMD0_SETMODE | ||
769 | |||
770 | #define CMD0_GETMODE 0x85 | ||
771 | #define CMD1_GETMODE 0x84 | ||
772 | #define CMD2_GETMODE 0x5a | ||
773 | #define CMDT_GETMODE CMD2_GETMODE | ||
774 | #define CMDL_GETMODE CMD0_GETMODE | ||
775 | |||
776 | #define CMD0_SET_XA 0x86 | ||
777 | |||
778 | #define CMD0_GET_XA 0x87 | ||
779 | |||
780 | #define CMD0_CAPACITY 0x88 | ||
781 | #define CMD1_CAPACITY 0x85 | ||
782 | #define CMD2_CAPACITY 0x25 | ||
783 | #define CMDL_CAPACITY CMD0_CAPACITY /* missing in some firmware versions */ | ||
784 | |||
785 | #define CMD0_READSUBQ 0x89 | ||
786 | #define CMD1_READSUBQ 0x87 | ||
787 | #define CMD2_READSUBQ 0x42 | ||
788 | #define CMDT_READSUBQ CMD2_READSUBQ | ||
789 | #define CMDL_READSUBQ CMD0_READSUBQ | ||
790 | #define CMDV_READSUBQ CMD0_READSUBQ | ||
791 | |||
792 | #define CMD0_DISKCODE 0x8a | ||
793 | |||
794 | #define CMD0_DISKINFO 0x8b | ||
795 | #define CMD1_DISKINFO CMD0_DISKINFO | ||
796 | #define CMD2_DISKINFO 0x43 | ||
797 | #define CMDT_DISKINFO CMD2_DISKINFO | ||
798 | #define CMDL_DISKINFO CMD0_DISKINFO | ||
799 | #define CMDV_DISKINFO CMD0_DISKINFO | ||
800 | |||
801 | #define CMD0_READTOC 0x8c | ||
802 | #define CMD1_READTOC CMD0_READTOC | ||
803 | #define CMD2_READTOC 0x??? | ||
804 | #define CMDL_READTOC CMD0_READTOC | ||
805 | #define CMDV_READTOC CMD0_READTOC | ||
806 | |||
807 | #define CMD0_PAU_RES 0x8d | ||
808 | #define CMD1_PAU_RES 0x0d | ||
809 | #define CMD2_PAU_RES 0x4b | ||
810 | #define CMDT_PAUSE CMD2_PAU_RES | ||
811 | #define CMDL_PAU_RES CMD0_PAU_RES | ||
812 | #define CMDV_PAUSE CMD0_PAU_RES | ||
813 | |||
814 | #define CMD0_PACKET 0x8e | ||
815 | #define CMD1_PACKET CMD0_PACKET | ||
816 | #define CMD2_PACKET 0x??? | ||
817 | #define CMDL_PACKET CMD0_PACKET | ||
818 | #define CMDV_PACKET 0x??? | ||
819 | |||
820 | /*==========================================================================*/ | ||
821 | /*==========================================================================*/ | ||
822 | #endif /* _LINUX_SBPCD_H */ | ||
823 | /*==========================================================================*/ | ||
824 | /* | ||
825 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
826 | * Emacs will notice this stuff at the end of the file and automatically | ||
827 | * adjust the settings for this buffer only. This must remain at the end | ||
828 | * of the file. | ||
829 | * --------------------------------------------------------------------------- | ||
830 | * Local variables: | ||
831 | * c-indent-level: 8 | ||
832 | * c-brace-imaginary-offset: 0 | ||
833 | * c-brace-offset: -8 | ||
834 | * c-argdecl-indent: 8 | ||
835 | * c-label-offset: -8 | ||
836 | * c-continued-statement-offset: 8 | ||
837 | * c-continued-brace-offset: 0 | ||
838 | * End: | ||
839 | */ | ||
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c deleted file mode 100644 index 5409fca5bbfc..000000000000 --- a/drivers/cdrom/sjcd.c +++ /dev/null | |||
@@ -1,1815 +0,0 @@ | |||
1 | /* -- sjcd.c | ||
2 | * | ||
3 | * Sanyo CD-ROM device driver implementation, Version 1.6 | ||
4 | * Copyright (C) 1995 Vadim V. Model | ||
5 | * | ||
6 | * model@cecmow.enet.dec.com | ||
7 | * vadim@rbrf.ru | ||
8 | * vadim@ipsun.ras.ru | ||
9 | * | ||
10 | * | ||
11 | * This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de); | ||
12 | * it was developed under use of mcd.c from Martin Harriss, with help of | ||
13 | * Eric van der Maarel (H.T.M.v.d.Maarel@marin.nl). | ||
14 | * | ||
15 | * It is planned to include these routines into sbpcd.c later - to make | ||
16 | * a "mixed use" on one cable possible for all kinds of drives which use | ||
17 | * the SoundBlaster/Panasonic style CDROM interface. But today, the | ||
18 | * ability to install directly from CDROM is more important than flexibility. | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License as published by | ||
22 | * the Free Software Foundation; either version 2 of the License, or | ||
23 | * (at your option) any later version. | ||
24 | * | ||
25 | * This program is distributed in the hope that it will be useful, | ||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | * GNU General Public License for more details. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License | ||
31 | * along with this program; if not, write to the Free Software | ||
32 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
33 | * | ||
34 | * History: | ||
35 | * 1.1 First public release with kernel version 1.3.7. | ||
36 | * Written by Vadim Model. | ||
37 | * 1.2 Added detection and configuration of cdrom interface | ||
38 | * on ISP16 soundcard. | ||
39 | * Allow for command line options: sjcd=<io_base>,<irq>,<dma> | ||
40 | * 1.3 Some minor changes to README.sjcd. | ||
41 | * 1.4 MSS Sound support!! Listen to a CD through the speakers. | ||
42 | * 1.5 Module support and bugfixes. | ||
43 | * Tray locking. | ||
44 | * 1.6 Removed ISP16 code from this driver. | ||
45 | * Allow only to set io base address on command line: sjcd=<io_base> | ||
46 | * Changes to Documentation/cdrom/sjcd | ||
47 | * Added cleanup after any error in the initialisation. | ||
48 | * 1.7 Added code to set the sector size tables to prevent the bug present in | ||
49 | * the previous version of this driver. Coded added by Anthony Barbachan | ||
50 | * from bugfix tip originally suggested by Alan Cox. | ||
51 | * | ||
52 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
53 | * Removed init_module & cleanup_module in favor of | ||
54 | * module_init & module_exit. | ||
55 | * Torben Mathiasen <tmm@image.dk> | ||
56 | */ | ||
57 | |||
58 | #define SJCD_VERSION_MAJOR 1 | ||
59 | #define SJCD_VERSION_MINOR 7 | ||
60 | |||
61 | #include <linux/module.h> | ||
62 | #include <linux/errno.h> | ||
63 | #include <linux/mm.h> | ||
64 | #include <linux/timer.h> | ||
65 | #include <linux/fs.h> | ||
66 | #include <linux/kernel.h> | ||
67 | #include <linux/cdrom.h> | ||
68 | #include <linux/ioport.h> | ||
69 | #include <linux/string.h> | ||
70 | #include <linux/major.h> | ||
71 | #include <linux/init.h> | ||
72 | |||
73 | #include <asm/system.h> | ||
74 | #include <asm/io.h> | ||
75 | #include <asm/uaccess.h> | ||
76 | #include <linux/blkdev.h> | ||
77 | #include "sjcd.h" | ||
78 | |||
79 | static int sjcd_present = 0; | ||
80 | static struct request_queue *sjcd_queue; | ||
81 | |||
82 | #define MAJOR_NR SANYO_CDROM_MAJOR | ||
83 | #define QUEUE (sjcd_queue) | ||
84 | #define CURRENT elv_next_request(sjcd_queue) | ||
85 | |||
86 | #define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */ | ||
87 | |||
88 | /* | ||
89 | * buffer for block size conversion | ||
90 | */ | ||
91 | static char sjcd_buf[2048 * SJCD_BUF_SIZ]; | ||
92 | static volatile int sjcd_buf_bn[SJCD_BUF_SIZ], sjcd_next_bn; | ||
93 | static volatile int sjcd_buf_in, sjcd_buf_out = -1; | ||
94 | |||
95 | /* | ||
96 | * Status. | ||
97 | */ | ||
98 | static unsigned short sjcd_status_valid = 0; | ||
99 | static unsigned short sjcd_door_closed; | ||
100 | static unsigned short sjcd_door_was_open; | ||
101 | static unsigned short sjcd_media_is_available; | ||
102 | static unsigned short sjcd_media_is_changed; | ||
103 | static unsigned short sjcd_toc_uptodate = 0; | ||
104 | static unsigned short sjcd_command_failed; | ||
105 | static volatile unsigned char sjcd_completion_status = 0; | ||
106 | static volatile unsigned char sjcd_completion_error = 0; | ||
107 | static unsigned short sjcd_command_is_in_progress = 0; | ||
108 | static unsigned short sjcd_error_reported = 0; | ||
109 | static DEFINE_SPINLOCK(sjcd_lock); | ||
110 | |||
111 | static int sjcd_open_count; | ||
112 | |||
113 | static int sjcd_audio_status; | ||
114 | static struct sjcd_play_msf sjcd_playing; | ||
115 | |||
116 | static int sjcd_base = SJCD_BASE_ADDR; | ||
117 | |||
118 | module_param(sjcd_base, int, 0); | ||
119 | |||
120 | static DECLARE_WAIT_QUEUE_HEAD(sjcd_waitq); | ||
121 | |||
122 | /* | ||
123 | * Data transfer. | ||
124 | */ | ||
125 | static volatile unsigned short sjcd_transfer_is_active = 0; | ||
126 | |||
127 | enum sjcd_transfer_state { | ||
128 | SJCD_S_IDLE = 0, | ||
129 | SJCD_S_START = 1, | ||
130 | SJCD_S_MODE = 2, | ||
131 | SJCD_S_READ = 3, | ||
132 | SJCD_S_DATA = 4, | ||
133 | SJCD_S_STOP = 5, | ||
134 | SJCD_S_STOPPING = 6 | ||
135 | }; | ||
136 | static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE; | ||
137 | static long sjcd_transfer_timeout = 0; | ||
138 | static int sjcd_read_count = 0; | ||
139 | static unsigned char sjcd_mode = 0; | ||
140 | |||
141 | #define SJCD_READ_TIMEOUT 5000 | ||
142 | |||
143 | #if defined( SJCD_GATHER_STAT ) | ||
144 | /* | ||
145 | * Statistic. | ||
146 | */ | ||
147 | static struct sjcd_stat statistic; | ||
148 | #endif | ||
149 | |||
150 | /* | ||
151 | * Timer. | ||
152 | */ | ||
153 | static DEFINE_TIMER(sjcd_delay_timer, NULL, 0, 0); | ||
154 | |||
155 | #define SJCD_SET_TIMER( func, tmout ) \ | ||
156 | ( sjcd_delay_timer.expires = jiffies+tmout, \ | ||
157 | sjcd_delay_timer.function = ( void * )func, \ | ||
158 | add_timer( &sjcd_delay_timer ) ) | ||
159 | |||
160 | #define CLEAR_TIMER del_timer( &sjcd_delay_timer ) | ||
161 | |||
162 | /* | ||
163 | * Set up device, i.e., use command line data to set | ||
164 | * base address. | ||
165 | */ | ||
166 | #ifndef MODULE | ||
167 | static int __init sjcd_setup(char *str) | ||
168 | { | ||
169 | int ints[2]; | ||
170 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
171 | if (ints[0] > 0) | ||
172 | sjcd_base = ints[1]; | ||
173 | |||
174 | return 1; | ||
175 | } | ||
176 | |||
177 | __setup("sjcd=", sjcd_setup); | ||
178 | |||
179 | #endif | ||
180 | |||
181 | /* | ||
182 | * Special converters. | ||
183 | */ | ||
184 | static unsigned char bin2bcd(int bin) | ||
185 | { | ||
186 | int u, v; | ||
187 | |||
188 | u = bin % 10; | ||
189 | v = bin / 10; | ||
190 | return (u | (v << 4)); | ||
191 | } | ||
192 | |||
193 | static int bcd2bin(unsigned char bcd) | ||
194 | { | ||
195 | return ((bcd >> 4) * 10 + (bcd & 0x0F)); | ||
196 | } | ||
197 | |||
198 | static long msf2hsg(struct msf *mp) | ||
199 | { | ||
200 | return (bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 | ||
201 | + bcd2bin(mp->min) * 4500 - 150); | ||
202 | } | ||
203 | |||
204 | static void hsg2msf(long hsg, struct msf *msf) | ||
205 | { | ||
206 | hsg += 150; | ||
207 | msf->min = hsg / 4500; | ||
208 | hsg %= 4500; | ||
209 | msf->sec = hsg / 75; | ||
210 | msf->frame = hsg % 75; | ||
211 | msf->min = bin2bcd(msf->min); /* convert to BCD */ | ||
212 | msf->sec = bin2bcd(msf->sec); | ||
213 | msf->frame = bin2bcd(msf->frame); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Send a command to cdrom. Invalidate status. | ||
218 | */ | ||
219 | static void sjcd_send_cmd(unsigned char cmd) | ||
220 | { | ||
221 | #if defined( SJCD_TRACE ) | ||
222 | printk("SJCD: send_cmd( 0x%x )\n", cmd); | ||
223 | #endif | ||
224 | outb(cmd, SJCDPORT(0)); | ||
225 | sjcd_command_is_in_progress = 1; | ||
226 | sjcd_status_valid = 0; | ||
227 | sjcd_command_failed = 0; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Send a command with one arg to cdrom. Invalidate status. | ||
232 | */ | ||
233 | static void sjcd_send_1_cmd(unsigned char cmd, unsigned char a) | ||
234 | { | ||
235 | #if defined( SJCD_TRACE ) | ||
236 | printk("SJCD: send_1_cmd( 0x%x, 0x%x )\n", cmd, a); | ||
237 | #endif | ||
238 | outb(cmd, SJCDPORT(0)); | ||
239 | outb(a, SJCDPORT(0)); | ||
240 | sjcd_command_is_in_progress = 1; | ||
241 | sjcd_status_valid = 0; | ||
242 | sjcd_command_failed = 0; | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * Send a command with four args to cdrom. Invalidate status. | ||
247 | */ | ||
248 | static void sjcd_send_4_cmd(unsigned char cmd, unsigned char a, | ||
249 | unsigned char b, unsigned char c, | ||
250 | unsigned char d) | ||
251 | { | ||
252 | #if defined( SJCD_TRACE ) | ||
253 | printk("SJCD: send_4_cmd( 0x%x )\n", cmd); | ||
254 | #endif | ||
255 | outb(cmd, SJCDPORT(0)); | ||
256 | outb(a, SJCDPORT(0)); | ||
257 | outb(b, SJCDPORT(0)); | ||
258 | outb(c, SJCDPORT(0)); | ||
259 | outb(d, SJCDPORT(0)); | ||
260 | sjcd_command_is_in_progress = 1; | ||
261 | sjcd_status_valid = 0; | ||
262 | sjcd_command_failed = 0; | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Send a play or read command to cdrom. Invalidate Status. | ||
267 | */ | ||
268 | static void sjcd_send_6_cmd(unsigned char cmd, struct sjcd_play_msf *pms) | ||
269 | { | ||
270 | #if defined( SJCD_TRACE ) | ||
271 | printk("SJCD: send_long_cmd( 0x%x )\n", cmd); | ||
272 | #endif | ||
273 | outb(cmd, SJCDPORT(0)); | ||
274 | outb(pms->start.min, SJCDPORT(0)); | ||
275 | outb(pms->start.sec, SJCDPORT(0)); | ||
276 | outb(pms->start.frame, SJCDPORT(0)); | ||
277 | outb(pms->end.min, SJCDPORT(0)); | ||
278 | outb(pms->end.sec, SJCDPORT(0)); | ||
279 | outb(pms->end.frame, SJCDPORT(0)); | ||
280 | sjcd_command_is_in_progress = 1; | ||
281 | sjcd_status_valid = 0; | ||
282 | sjcd_command_failed = 0; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * Get a value from the data port. Should not block, so we use a little | ||
287 | * wait for a while. Returns 0 if OK. | ||
288 | */ | ||
289 | static int sjcd_load_response(void *buf, int len) | ||
290 | { | ||
291 | unsigned char *resp = (unsigned char *) buf; | ||
292 | |||
293 | for (; len; --len) { | ||
294 | int i; | ||
295 | for (i = 200; | ||
296 | i-- && !SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)));); | ||
297 | if (i > 0) | ||
298 | *resp++ = (unsigned char) inb(SJCDPORT(0)); | ||
299 | else | ||
300 | break; | ||
301 | } | ||
302 | return (len); | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Load and parse command completion status (drive info byte and maybe error). | ||
307 | * Sorry, no error classification yet. | ||
308 | */ | ||
309 | static void sjcd_load_status(void) | ||
310 | { | ||
311 | sjcd_media_is_changed = 0; | ||
312 | sjcd_completion_error = 0; | ||
313 | sjcd_completion_status = inb(SJCDPORT(0)); | ||
314 | if (sjcd_completion_status & SST_DOOR_OPENED) { | ||
315 | sjcd_door_closed = sjcd_media_is_available = 0; | ||
316 | } else { | ||
317 | sjcd_door_closed = 1; | ||
318 | if (sjcd_completion_status & SST_MEDIA_CHANGED) | ||
319 | sjcd_media_is_available = sjcd_media_is_changed = | ||
320 | 1; | ||
321 | else if (sjcd_completion_status & 0x0F) { | ||
322 | /* | ||
323 | * OK, we seem to catch an error ... | ||
324 | */ | ||
325 | while (!SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))); | ||
326 | sjcd_completion_error = inb(SJCDPORT(0)); | ||
327 | if ((sjcd_completion_status & 0x08) && | ||
328 | (sjcd_completion_error & 0x40)) | ||
329 | sjcd_media_is_available = 0; | ||
330 | else | ||
331 | sjcd_command_failed = 1; | ||
332 | } else | ||
333 | sjcd_media_is_available = 1; | ||
334 | } | ||
335 | /* | ||
336 | * Ok, status loaded successfully. | ||
337 | */ | ||
338 | sjcd_status_valid = 1, sjcd_error_reported = 0; | ||
339 | sjcd_command_is_in_progress = 0; | ||
340 | |||
341 | /* | ||
342 | * If the disk is changed, the TOC is not valid. | ||
343 | */ | ||
344 | if (sjcd_media_is_changed) | ||
345 | sjcd_toc_uptodate = 0; | ||
346 | #if defined( SJCD_TRACE ) | ||
347 | printk("SJCD: status %02x.%02x loaded.\n", | ||
348 | (int) sjcd_completion_status, (int) sjcd_completion_error); | ||
349 | #endif | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Read status from cdrom. Check to see if the status is available. | ||
354 | */ | ||
355 | static int sjcd_check_status(void) | ||
356 | { | ||
357 | /* | ||
358 | * Try to load the response from cdrom into buffer. | ||
359 | */ | ||
360 | if (SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))) { | ||
361 | sjcd_load_status(); | ||
362 | return (1); | ||
363 | } else { | ||
364 | /* | ||
365 | * No status is available. | ||
366 | */ | ||
367 | return (0); | ||
368 | } | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * This is just timeout counter, and nothing more. Surprised ? :-) | ||
373 | */ | ||
374 | static volatile long sjcd_status_timeout; | ||
375 | |||
376 | /* | ||
377 | * We need about 10 seconds to wait. The longest command takes about 5 seconds | ||
378 | * to probe the disk (usually after tray closed or drive reset). Other values | ||
379 | * should be thought of for other commands. | ||
380 | */ | ||
381 | #define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000 | ||
382 | |||
383 | static void sjcd_status_timer(void) | ||
384 | { | ||
385 | if (sjcd_check_status()) { | ||
386 | /* | ||
387 | * The command completed and status is loaded, stop waiting. | ||
388 | */ | ||
389 | wake_up(&sjcd_waitq); | ||
390 | } else if (--sjcd_status_timeout <= 0) { | ||
391 | /* | ||
392 | * We are timed out. | ||
393 | */ | ||
394 | wake_up(&sjcd_waitq); | ||
395 | } else { | ||
396 | /* | ||
397 | * We have still some time to wait. Try again. | ||
398 | */ | ||
399 | SJCD_SET_TIMER(sjcd_status_timer, 1); | ||
400 | } | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Wait for status for 10 sec approx. Returns non-positive when timed out. | ||
405 | * Should not be used while reading data CDs. | ||
406 | */ | ||
407 | static int sjcd_wait_for_status(void) | ||
408 | { | ||
409 | sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT; | ||
410 | SJCD_SET_TIMER(sjcd_status_timer, 1); | ||
411 | sleep_on(&sjcd_waitq); | ||
412 | #if defined( SJCD_DIAGNOSTIC ) || defined ( SJCD_TRACE ) | ||
413 | if (sjcd_status_timeout <= 0) | ||
414 | printk("SJCD: Error Wait For Status.\n"); | ||
415 | #endif | ||
416 | return (sjcd_status_timeout); | ||
417 | } | ||
418 | |||
419 | static int sjcd_receive_status(void) | ||
420 | { | ||
421 | int i; | ||
422 | #if defined( SJCD_TRACE ) | ||
423 | printk("SJCD: receive_status\n"); | ||
424 | #endif | ||
425 | /* | ||
426 | * Wait a bit for status available. | ||
427 | */ | ||
428 | for (i = 200; i-- && (sjcd_check_status() == 0);); | ||
429 | if (i < 0) { | ||
430 | #if defined( SJCD_TRACE ) | ||
431 | printk("SJCD: long wait for status\n"); | ||
432 | #endif | ||
433 | if (sjcd_wait_for_status() <= 0) | ||
434 | printk("SJCD: Timeout when read status.\n"); | ||
435 | else | ||
436 | i = 0; | ||
437 | } | ||
438 | return (i); | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * Load the status. Issue get status command and wait for status available. | ||
443 | */ | ||
444 | static void sjcd_get_status(void) | ||
445 | { | ||
446 | #if defined( SJCD_TRACE ) | ||
447 | printk("SJCD: get_status\n"); | ||
448 | #endif | ||
449 | sjcd_send_cmd(SCMD_GET_STATUS); | ||
450 | sjcd_receive_status(); | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * Check the drive if the disk is changed. Should be revised. | ||
455 | */ | ||
456 | static int sjcd_disk_change(struct gendisk *disk) | ||
457 | { | ||
458 | #if 0 | ||
459 | printk("SJCD: sjcd_disk_change(%s)\n", disk->disk_name); | ||
460 | #endif | ||
461 | if (!sjcd_command_is_in_progress) | ||
462 | sjcd_get_status(); | ||
463 | return (sjcd_status_valid ? sjcd_media_is_changed : 0); | ||
464 | } | ||
465 | |||
466 | /* | ||
467 | * Read the table of contents (TOC) and TOC header if necessary. | ||
468 | * We assume that the drive contains no more than 99 toc entries. | ||
469 | */ | ||
470 | static struct sjcd_hw_disk_info sjcd_table_of_contents[SJCD_MAX_TRACKS]; | ||
471 | static unsigned char sjcd_first_track_no, sjcd_last_track_no; | ||
472 | #define sjcd_disk_length sjcd_table_of_contents[0].un.track_msf | ||
473 | |||
474 | static int sjcd_update_toc(void) | ||
475 | { | ||
476 | struct sjcd_hw_disk_info info; | ||
477 | int i; | ||
478 | #if defined( SJCD_TRACE ) | ||
479 | printk("SJCD: update toc:\n"); | ||
480 | #endif | ||
481 | /* | ||
482 | * check to see if we need to do anything | ||
483 | */ | ||
484 | if (sjcd_toc_uptodate) | ||
485 | return (0); | ||
486 | |||
487 | /* | ||
488 | * Get the TOC start information. | ||
489 | */ | ||
490 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_1_TRACK); | ||
491 | sjcd_receive_status(); | ||
492 | |||
493 | if (!sjcd_status_valid) { | ||
494 | printk("SJCD: cannot load status.\n"); | ||
495 | return (-1); | ||
496 | } | ||
497 | |||
498 | if (!sjcd_media_is_available) { | ||
499 | printk("SJCD: no disk in drive\n"); | ||
500 | return (-1); | ||
501 | } | ||
502 | |||
503 | if (!sjcd_command_failed) { | ||
504 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | ||
505 | printk | ||
506 | ("SJCD: cannot load response about TOC start.\n"); | ||
507 | return (-1); | ||
508 | } | ||
509 | sjcd_first_track_no = bcd2bin(info.un.track_no); | ||
510 | } else { | ||
511 | printk("SJCD: get first failed\n"); | ||
512 | return (-1); | ||
513 | } | ||
514 | #if defined( SJCD_TRACE ) | ||
515 | printk("SJCD: TOC start 0x%02x ", sjcd_first_track_no); | ||
516 | #endif | ||
517 | /* | ||
518 | * Get the TOC finish information. | ||
519 | */ | ||
520 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_L_TRACK); | ||
521 | sjcd_receive_status(); | ||
522 | |||
523 | if (!sjcd_status_valid) { | ||
524 | printk("SJCD: cannot load status.\n"); | ||
525 | return (-1); | ||
526 | } | ||
527 | |||
528 | if (!sjcd_media_is_available) { | ||
529 | printk("SJCD: no disk in drive\n"); | ||
530 | return (-1); | ||
531 | } | ||
532 | |||
533 | if (!sjcd_command_failed) { | ||
534 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | ||
535 | printk | ||
536 | ("SJCD: cannot load response about TOC finish.\n"); | ||
537 | return (-1); | ||
538 | } | ||
539 | sjcd_last_track_no = bcd2bin(info.un.track_no); | ||
540 | } else { | ||
541 | printk("SJCD: get last failed\n"); | ||
542 | return (-1); | ||
543 | } | ||
544 | #if defined( SJCD_TRACE ) | ||
545 | printk("SJCD: TOC finish 0x%02x ", sjcd_last_track_no); | ||
546 | #endif | ||
547 | for (i = sjcd_first_track_no; i <= sjcd_last_track_no; i++) { | ||
548 | /* | ||
549 | * Get the first track information. | ||
550 | */ | ||
551 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, bin2bcd(i)); | ||
552 | sjcd_receive_status(); | ||
553 | |||
554 | if (!sjcd_status_valid) { | ||
555 | printk("SJCD: cannot load status.\n"); | ||
556 | return (-1); | ||
557 | } | ||
558 | |||
559 | if (!sjcd_media_is_available) { | ||
560 | printk("SJCD: no disk in drive\n"); | ||
561 | return (-1); | ||
562 | } | ||
563 | |||
564 | if (!sjcd_command_failed) { | ||
565 | if (sjcd_load_response(&sjcd_table_of_contents[i], | ||
566 | sizeof(struct | ||
567 | sjcd_hw_disk_info)) | ||
568 | != 0) { | ||
569 | printk | ||
570 | ("SJCD: cannot load info for %d track\n", | ||
571 | i); | ||
572 | return (-1); | ||
573 | } | ||
574 | } else { | ||
575 | printk("SJCD: get info %d failed\n", i); | ||
576 | return (-1); | ||
577 | } | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * Get the disk length info. | ||
582 | */ | ||
583 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE); | ||
584 | sjcd_receive_status(); | ||
585 | |||
586 | if (!sjcd_status_valid) { | ||
587 | printk("SJCD: cannot load status.\n"); | ||
588 | return (-1); | ||
589 | } | ||
590 | |||
591 | if (!sjcd_media_is_available) { | ||
592 | printk("SJCD: no disk in drive\n"); | ||
593 | return (-1); | ||
594 | } | ||
595 | |||
596 | if (!sjcd_command_failed) { | ||
597 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | ||
598 | printk | ||
599 | ("SJCD: cannot load response about disk size.\n"); | ||
600 | return (-1); | ||
601 | } | ||
602 | sjcd_disk_length.min = info.un.track_msf.min; | ||
603 | sjcd_disk_length.sec = info.un.track_msf.sec; | ||
604 | sjcd_disk_length.frame = info.un.track_msf.frame; | ||
605 | } else { | ||
606 | printk("SJCD: get size failed\n"); | ||
607 | return (1); | ||
608 | } | ||
609 | #if defined( SJCD_TRACE ) | ||
610 | printk("SJCD: (%02x:%02x.%02x)\n", sjcd_disk_length.min, | ||
611 | sjcd_disk_length.sec, sjcd_disk_length.frame); | ||
612 | #endif | ||
613 | return (0); | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * Load subchannel information. | ||
618 | */ | ||
619 | static int sjcd_get_q_info(struct sjcd_hw_qinfo *qp) | ||
620 | { | ||
621 | int s; | ||
622 | #if defined( SJCD_TRACE ) | ||
623 | printk("SJCD: load sub q\n"); | ||
624 | #endif | ||
625 | sjcd_send_cmd(SCMD_GET_QINFO); | ||
626 | s = sjcd_receive_status(); | ||
627 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) { | ||
628 | sjcd_send_cmd(0xF2); | ||
629 | s = sjcd_receive_status(); | ||
630 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) | ||
631 | return (-1); | ||
632 | sjcd_send_cmd(SCMD_GET_QINFO); | ||
633 | s = sjcd_receive_status(); | ||
634 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) | ||
635 | return (-1); | ||
636 | } | ||
637 | if (sjcd_media_is_available) | ||
638 | if (sjcd_load_response(qp, sizeof(*qp)) == 0) | ||
639 | return (0); | ||
640 | return (-1); | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * Start playing from the specified position. | ||
645 | */ | ||
646 | static int sjcd_play(struct sjcd_play_msf *mp) | ||
647 | { | ||
648 | struct sjcd_play_msf msf; | ||
649 | |||
650 | /* | ||
651 | * Turn the device to play mode. | ||
652 | */ | ||
653 | sjcd_send_1_cmd(SCMD_SET_MODE, SCMD_MODE_PLAY); | ||
654 | if (sjcd_receive_status() < 0) | ||
655 | return (-1); | ||
656 | |||
657 | /* | ||
658 | * Seek to the starting point. | ||
659 | */ | ||
660 | msf.start = mp->start; | ||
661 | msf.end.min = msf.end.sec = msf.end.frame = 0x00; | ||
662 | sjcd_send_6_cmd(SCMD_SEEK, &msf); | ||
663 | if (sjcd_receive_status() < 0) | ||
664 | return (-1); | ||
665 | |||
666 | /* | ||
667 | * Start playing. | ||
668 | */ | ||
669 | sjcd_send_6_cmd(SCMD_PLAY, mp); | ||
670 | return (sjcd_receive_status()); | ||
671 | } | ||
672 | |||
673 | /* | ||
674 | * Tray control functions. | ||
675 | */ | ||
676 | static int sjcd_tray_close(void) | ||
677 | { | ||
678 | #if defined( SJCD_TRACE ) | ||
679 | printk("SJCD: tray_close\n"); | ||
680 | #endif | ||
681 | sjcd_send_cmd(SCMD_CLOSE_TRAY); | ||
682 | return (sjcd_receive_status()); | ||
683 | } | ||
684 | |||
685 | static int sjcd_tray_lock(void) | ||
686 | { | ||
687 | #if defined( SJCD_TRACE ) | ||
688 | printk("SJCD: tray_lock\n"); | ||
689 | #endif | ||
690 | sjcd_send_cmd(SCMD_LOCK_TRAY); | ||
691 | return (sjcd_receive_status()); | ||
692 | } | ||
693 | |||
694 | static int sjcd_tray_unlock(void) | ||
695 | { | ||
696 | #if defined( SJCD_TRACE ) | ||
697 | printk("SJCD: tray_unlock\n"); | ||
698 | #endif | ||
699 | sjcd_send_cmd(SCMD_UNLOCK_TRAY); | ||
700 | return (sjcd_receive_status()); | ||
701 | } | ||
702 | |||
703 | static int sjcd_tray_open(void) | ||
704 | { | ||
705 | #if defined( SJCD_TRACE ) | ||
706 | printk("SJCD: tray_open\n"); | ||
707 | #endif | ||
708 | sjcd_send_cmd(SCMD_EJECT_TRAY); | ||
709 | return (sjcd_receive_status()); | ||
710 | } | ||
711 | |||
712 | /* | ||
713 | * Do some user commands. | ||
714 | */ | ||
715 | static int sjcd_ioctl(struct inode *ip, struct file *fp, | ||
716 | unsigned int cmd, unsigned long arg) | ||
717 | { | ||
718 | void __user *argp = (void __user *)arg; | ||
719 | #if defined( SJCD_TRACE ) | ||
720 | printk("SJCD:ioctl\n"); | ||
721 | #endif | ||
722 | |||
723 | sjcd_get_status(); | ||
724 | if (!sjcd_status_valid) | ||
725 | return (-EIO); | ||
726 | if (sjcd_update_toc() < 0) | ||
727 | return (-EIO); | ||
728 | |||
729 | switch (cmd) { | ||
730 | case CDROMSTART:{ | ||
731 | #if defined( SJCD_TRACE ) | ||
732 | printk("SJCD: ioctl: start\n"); | ||
733 | #endif | ||
734 | return (0); | ||
735 | } | ||
736 | |||
737 | case CDROMSTOP:{ | ||
738 | #if defined( SJCD_TRACE ) | ||
739 | printk("SJCD: ioctl: stop\n"); | ||
740 | #endif | ||
741 | sjcd_send_cmd(SCMD_PAUSE); | ||
742 | (void) sjcd_receive_status(); | ||
743 | sjcd_audio_status = CDROM_AUDIO_NO_STATUS; | ||
744 | return (0); | ||
745 | } | ||
746 | |||
747 | case CDROMPAUSE:{ | ||
748 | struct sjcd_hw_qinfo q_info; | ||
749 | #if defined( SJCD_TRACE ) | ||
750 | printk("SJCD: ioctl: pause\n"); | ||
751 | #endif | ||
752 | if (sjcd_audio_status == CDROM_AUDIO_PLAY) { | ||
753 | sjcd_send_cmd(SCMD_PAUSE); | ||
754 | (void) sjcd_receive_status(); | ||
755 | if (sjcd_get_q_info(&q_info) < 0) { | ||
756 | sjcd_audio_status = | ||
757 | CDROM_AUDIO_NO_STATUS; | ||
758 | } else { | ||
759 | sjcd_audio_status = | ||
760 | CDROM_AUDIO_PAUSED; | ||
761 | sjcd_playing.start = q_info.abs; | ||
762 | } | ||
763 | return (0); | ||
764 | } else | ||
765 | return (-EINVAL); | ||
766 | } | ||
767 | |||
768 | case CDROMRESUME:{ | ||
769 | #if defined( SJCD_TRACE ) | ||
770 | printk("SJCD: ioctl: resume\n"); | ||
771 | #endif | ||
772 | if (sjcd_audio_status == CDROM_AUDIO_PAUSED) { | ||
773 | /* | ||
774 | * continue play starting at saved location | ||
775 | */ | ||
776 | if (sjcd_play(&sjcd_playing) < 0) { | ||
777 | sjcd_audio_status = | ||
778 | CDROM_AUDIO_ERROR; | ||
779 | return (-EIO); | ||
780 | } else { | ||
781 | sjcd_audio_status = | ||
782 | CDROM_AUDIO_PLAY; | ||
783 | return (0); | ||
784 | } | ||
785 | } else | ||
786 | return (-EINVAL); | ||
787 | } | ||
788 | |||
789 | case CDROMPLAYTRKIND:{ | ||
790 | struct cdrom_ti ti; | ||
791 | int s = -EFAULT; | ||
792 | #if defined( SJCD_TRACE ) | ||
793 | printk("SJCD: ioctl: playtrkind\n"); | ||
794 | #endif | ||
795 | if (!copy_from_user(&ti, argp, sizeof(ti))) { | ||
796 | s = 0; | ||
797 | if (ti.cdti_trk0 < sjcd_first_track_no) | ||
798 | return (-EINVAL); | ||
799 | if (ti.cdti_trk1 > sjcd_last_track_no) | ||
800 | ti.cdti_trk1 = sjcd_last_track_no; | ||
801 | if (ti.cdti_trk0 > ti.cdti_trk1) | ||
802 | return (-EINVAL); | ||
803 | |||
804 | sjcd_playing.start = | ||
805 | sjcd_table_of_contents[ti.cdti_trk0]. | ||
806 | un.track_msf; | ||
807 | sjcd_playing.end = | ||
808 | (ti.cdti_trk1 < | ||
809 | sjcd_last_track_no) ? | ||
810 | sjcd_table_of_contents[ti.cdti_trk1 + | ||
811 | 1].un. | ||
812 | track_msf : sjcd_table_of_contents[0]. | ||
813 | un.track_msf; | ||
814 | |||
815 | if (sjcd_play(&sjcd_playing) < 0) { | ||
816 | sjcd_audio_status = | ||
817 | CDROM_AUDIO_ERROR; | ||
818 | return (-EIO); | ||
819 | } else | ||
820 | sjcd_audio_status = | ||
821 | CDROM_AUDIO_PLAY; | ||
822 | } | ||
823 | return (s); | ||
824 | } | ||
825 | |||
826 | case CDROMPLAYMSF:{ | ||
827 | struct cdrom_msf sjcd_msf; | ||
828 | int s; | ||
829 | #if defined( SJCD_TRACE ) | ||
830 | printk("SJCD: ioctl: playmsf\n"); | ||
831 | #endif | ||
832 | if ((s = | ||
833 | access_ok(VERIFY_READ, argp, sizeof(sjcd_msf)) | ||
834 | ? 0 : -EFAULT) == 0) { | ||
835 | if (sjcd_audio_status == CDROM_AUDIO_PLAY) { | ||
836 | sjcd_send_cmd(SCMD_PAUSE); | ||
837 | (void) sjcd_receive_status(); | ||
838 | sjcd_audio_status = | ||
839 | CDROM_AUDIO_NO_STATUS; | ||
840 | } | ||
841 | |||
842 | if (copy_from_user(&sjcd_msf, argp, | ||
843 | sizeof(sjcd_msf))) | ||
844 | return (-EFAULT); | ||
845 | |||
846 | sjcd_playing.start.min = | ||
847 | bin2bcd(sjcd_msf.cdmsf_min0); | ||
848 | sjcd_playing.start.sec = | ||
849 | bin2bcd(sjcd_msf.cdmsf_sec0); | ||
850 | sjcd_playing.start.frame = | ||
851 | bin2bcd(sjcd_msf.cdmsf_frame0); | ||
852 | sjcd_playing.end.min = | ||
853 | bin2bcd(sjcd_msf.cdmsf_min1); | ||
854 | sjcd_playing.end.sec = | ||
855 | bin2bcd(sjcd_msf.cdmsf_sec1); | ||
856 | sjcd_playing.end.frame = | ||
857 | bin2bcd(sjcd_msf.cdmsf_frame1); | ||
858 | |||
859 | if (sjcd_play(&sjcd_playing) < 0) { | ||
860 | sjcd_audio_status = | ||
861 | CDROM_AUDIO_ERROR; | ||
862 | return (-EIO); | ||
863 | } else | ||
864 | sjcd_audio_status = | ||
865 | CDROM_AUDIO_PLAY; | ||
866 | } | ||
867 | return (s); | ||
868 | } | ||
869 | |||
870 | case CDROMREADTOCHDR:{ | ||
871 | struct cdrom_tochdr toc_header; | ||
872 | #if defined (SJCD_TRACE ) | ||
873 | printk("SJCD: ioctl: readtocheader\n"); | ||
874 | #endif | ||
875 | toc_header.cdth_trk0 = sjcd_first_track_no; | ||
876 | toc_header.cdth_trk1 = sjcd_last_track_no; | ||
877 | if (copy_to_user(argp, &toc_header, | ||
878 | sizeof(toc_header))) | ||
879 | return -EFAULT; | ||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | case CDROMREADTOCENTRY:{ | ||
884 | struct cdrom_tocentry toc_entry; | ||
885 | int s; | ||
886 | #if defined( SJCD_TRACE ) | ||
887 | printk("SJCD: ioctl: readtocentry\n"); | ||
888 | #endif | ||
889 | if ((s = | ||
890 | access_ok(VERIFY_WRITE, argp, sizeof(toc_entry)) | ||
891 | ? 0 : -EFAULT) == 0) { | ||
892 | struct sjcd_hw_disk_info *tp; | ||
893 | |||
894 | if (copy_from_user(&toc_entry, argp, | ||
895 | sizeof(toc_entry))) | ||
896 | return (-EFAULT); | ||
897 | if (toc_entry.cdte_track == CDROM_LEADOUT) | ||
898 | tp = &sjcd_table_of_contents[0]; | ||
899 | else if (toc_entry.cdte_track < | ||
900 | sjcd_first_track_no) | ||
901 | return (-EINVAL); | ||
902 | else if (toc_entry.cdte_track > | ||
903 | sjcd_last_track_no) | ||
904 | return (-EINVAL); | ||
905 | else | ||
906 | tp = &sjcd_table_of_contents | ||
907 | [toc_entry.cdte_track]; | ||
908 | |||
909 | toc_entry.cdte_adr = | ||
910 | tp->track_control & 0x0F; | ||
911 | toc_entry.cdte_ctrl = | ||
912 | tp->track_control >> 4; | ||
913 | |||
914 | switch (toc_entry.cdte_format) { | ||
915 | case CDROM_LBA: | ||
916 | toc_entry.cdte_addr.lba = | ||
917 | msf2hsg(&(tp->un.track_msf)); | ||
918 | break; | ||
919 | case CDROM_MSF: | ||
920 | toc_entry.cdte_addr.msf.minute = | ||
921 | bcd2bin(tp->un.track_msf.min); | ||
922 | toc_entry.cdte_addr.msf.second = | ||
923 | bcd2bin(tp->un.track_msf.sec); | ||
924 | toc_entry.cdte_addr.msf.frame = | ||
925 | bcd2bin(tp->un.track_msf. | ||
926 | frame); | ||
927 | break; | ||
928 | default: | ||
929 | return (-EINVAL); | ||
930 | } | ||
931 | if (copy_to_user(argp, &toc_entry, | ||
932 | sizeof(toc_entry))) | ||
933 | s = -EFAULT; | ||
934 | } | ||
935 | return (s); | ||
936 | } | ||
937 | |||
938 | case CDROMSUBCHNL:{ | ||
939 | struct cdrom_subchnl subchnl; | ||
940 | int s; | ||
941 | #if defined( SJCD_TRACE ) | ||
942 | printk("SJCD: ioctl: subchnl\n"); | ||
943 | #endif | ||
944 | if ((s = | ||
945 | access_ok(VERIFY_WRITE, argp, sizeof(subchnl)) | ||
946 | ? 0 : -EFAULT) == 0) { | ||
947 | struct sjcd_hw_qinfo q_info; | ||
948 | |||
949 | if (copy_from_user(&subchnl, argp, | ||
950 | sizeof(subchnl))) | ||
951 | return (-EFAULT); | ||
952 | |||
953 | if (sjcd_get_q_info(&q_info) < 0) | ||
954 | return (-EIO); | ||
955 | |||
956 | subchnl.cdsc_audiostatus = | ||
957 | sjcd_audio_status; | ||
958 | subchnl.cdsc_adr = | ||
959 | q_info.track_control & 0x0F; | ||
960 | subchnl.cdsc_ctrl = | ||
961 | q_info.track_control >> 4; | ||
962 | subchnl.cdsc_trk = | ||
963 | bcd2bin(q_info.track_no); | ||
964 | subchnl.cdsc_ind = bcd2bin(q_info.x); | ||
965 | |||
966 | switch (subchnl.cdsc_format) { | ||
967 | case CDROM_LBA: | ||
968 | subchnl.cdsc_absaddr.lba = | ||
969 | msf2hsg(&(q_info.abs)); | ||
970 | subchnl.cdsc_reladdr.lba = | ||
971 | msf2hsg(&(q_info.rel)); | ||
972 | break; | ||
973 | case CDROM_MSF: | ||
974 | subchnl.cdsc_absaddr.msf.minute = | ||
975 | bcd2bin(q_info.abs.min); | ||
976 | subchnl.cdsc_absaddr.msf.second = | ||
977 | bcd2bin(q_info.abs.sec); | ||
978 | subchnl.cdsc_absaddr.msf.frame = | ||
979 | bcd2bin(q_info.abs.frame); | ||
980 | subchnl.cdsc_reladdr.msf.minute = | ||
981 | bcd2bin(q_info.rel.min); | ||
982 | subchnl.cdsc_reladdr.msf.second = | ||
983 | bcd2bin(q_info.rel.sec); | ||
984 | subchnl.cdsc_reladdr.msf.frame = | ||
985 | bcd2bin(q_info.rel.frame); | ||
986 | break; | ||
987 | default: | ||
988 | return (-EINVAL); | ||
989 | } | ||
990 | if (copy_to_user(argp, &subchnl, | ||
991 | sizeof(subchnl))) | ||
992 | s = -EFAULT; | ||
993 | } | ||
994 | return (s); | ||
995 | } | ||
996 | |||
997 | case CDROMVOLCTRL:{ | ||
998 | struct cdrom_volctrl vol_ctrl; | ||
999 | int s; | ||
1000 | #if defined( SJCD_TRACE ) | ||
1001 | printk("SJCD: ioctl: volctrl\n"); | ||
1002 | #endif | ||
1003 | if ((s = | ||
1004 | access_ok(VERIFY_READ, argp, sizeof(vol_ctrl)) | ||
1005 | ? 0 : -EFAULT) == 0) { | ||
1006 | unsigned char dummy[4]; | ||
1007 | |||
1008 | if (copy_from_user(&vol_ctrl, argp, | ||
1009 | sizeof(vol_ctrl))) | ||
1010 | return (-EFAULT); | ||
1011 | sjcd_send_4_cmd(SCMD_SET_VOLUME, | ||
1012 | vol_ctrl.channel0, 0xFF, | ||
1013 | vol_ctrl.channel1, 0xFF); | ||
1014 | if (sjcd_receive_status() < 0) | ||
1015 | return (-EIO); | ||
1016 | (void) sjcd_load_response(dummy, 4); | ||
1017 | } | ||
1018 | return (s); | ||
1019 | } | ||
1020 | |||
1021 | case CDROMEJECT:{ | ||
1022 | #if defined( SJCD_TRACE ) | ||
1023 | printk("SJCD: ioctl: eject\n"); | ||
1024 | #endif | ||
1025 | if (!sjcd_command_is_in_progress) { | ||
1026 | sjcd_tray_unlock(); | ||
1027 | sjcd_send_cmd(SCMD_EJECT_TRAY); | ||
1028 | (void) sjcd_receive_status(); | ||
1029 | } | ||
1030 | return (0); | ||
1031 | } | ||
1032 | |||
1033 | #if defined( SJCD_GATHER_STAT ) | ||
1034 | case 0xABCD:{ | ||
1035 | #if defined( SJCD_TRACE ) | ||
1036 | printk("SJCD: ioctl: statistic\n"); | ||
1037 | #endif | ||
1038 | if (copy_to_user(argp, &statistic, sizeof(statistic))) | ||
1039 | return -EFAULT; | ||
1040 | return 0; | ||
1041 | } | ||
1042 | #endif | ||
1043 | |||
1044 | default: | ||
1045 | return (-EINVAL); | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | /* | ||
1050 | * Invalidate internal buffers of the driver. | ||
1051 | */ | ||
1052 | static void sjcd_invalidate_buffers(void) | ||
1053 | { | ||
1054 | int i; | ||
1055 | for (i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[i++] = -1); | ||
1056 | sjcd_buf_out = -1; | ||
1057 | } | ||
1058 | |||
1059 | /* | ||
1060 | * Take care of the different block sizes between cdrom and Linux. | ||
1061 | * When Linux gets variable block sizes this will probably go away. | ||
1062 | */ | ||
1063 | |||
1064 | static int current_valid(void) | ||
1065 | { | ||
1066 | return CURRENT && | ||
1067 | CURRENT->cmd == READ && | ||
1068 | CURRENT->sector != -1; | ||
1069 | } | ||
1070 | |||
1071 | static void sjcd_transfer(void) | ||
1072 | { | ||
1073 | #if defined( SJCD_TRACE ) | ||
1074 | printk("SJCD: transfer:\n"); | ||
1075 | #endif | ||
1076 | if (current_valid()) { | ||
1077 | while (CURRENT->nr_sectors) { | ||
1078 | int i, bn = CURRENT->sector / 4; | ||
1079 | for (i = 0; | ||
1080 | i < SJCD_BUF_SIZ && sjcd_buf_bn[i] != bn; | ||
1081 | i++); | ||
1082 | if (i < SJCD_BUF_SIZ) { | ||
1083 | int offs = | ||
1084 | (i * 4 + (CURRENT->sector & 3)) * 512; | ||
1085 | int nr_sectors = 4 - (CURRENT->sector & 3); | ||
1086 | if (sjcd_buf_out != i) { | ||
1087 | sjcd_buf_out = i; | ||
1088 | if (sjcd_buf_bn[i] != bn) { | ||
1089 | sjcd_buf_out = -1; | ||
1090 | continue; | ||
1091 | } | ||
1092 | } | ||
1093 | if (nr_sectors > CURRENT->nr_sectors) | ||
1094 | nr_sectors = CURRENT->nr_sectors; | ||
1095 | #if defined( SJCD_TRACE ) | ||
1096 | printk("SJCD: copy out\n"); | ||
1097 | #endif | ||
1098 | memcpy(CURRENT->buffer, sjcd_buf + offs, | ||
1099 | nr_sectors * 512); | ||
1100 | CURRENT->nr_sectors -= nr_sectors; | ||
1101 | CURRENT->sector += nr_sectors; | ||
1102 | CURRENT->buffer += nr_sectors * 512; | ||
1103 | } else { | ||
1104 | sjcd_buf_out = -1; | ||
1105 | break; | ||
1106 | } | ||
1107 | } | ||
1108 | } | ||
1109 | #if defined( SJCD_TRACE ) | ||
1110 | printk("SJCD: transfer: done\n"); | ||
1111 | #endif | ||
1112 | } | ||
1113 | |||
1114 | static void sjcd_poll(void) | ||
1115 | { | ||
1116 | #if defined( SJCD_GATHER_STAT ) | ||
1117 | /* | ||
1118 | * Update total number of ticks. | ||
1119 | */ | ||
1120 | statistic.ticks++; | ||
1121 | statistic.tticks[sjcd_transfer_state]++; | ||
1122 | #endif | ||
1123 | |||
1124 | ReSwitch:switch (sjcd_transfer_state) { | ||
1125 | |||
1126 | case SJCD_S_IDLE:{ | ||
1127 | #if defined( SJCD_GATHER_STAT ) | ||
1128 | statistic.idle_ticks++; | ||
1129 | #endif | ||
1130 | #if defined( SJCD_TRACE ) | ||
1131 | printk("SJCD_S_IDLE\n"); | ||
1132 | #endif | ||
1133 | return; | ||
1134 | } | ||
1135 | |||
1136 | case SJCD_S_START:{ | ||
1137 | #if defined( SJCD_GATHER_STAT ) | ||
1138 | statistic.start_ticks++; | ||
1139 | #endif | ||
1140 | sjcd_send_cmd(SCMD_GET_STATUS); | ||
1141 | sjcd_transfer_state = | ||
1142 | sjcd_mode == | ||
1143 | SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE; | ||
1144 | sjcd_transfer_timeout = 500; | ||
1145 | #if defined( SJCD_TRACE ) | ||
1146 | printk("SJCD_S_START: goto SJCD_S_%s mode\n", | ||
1147 | sjcd_transfer_state == | ||
1148 | SJCD_S_READ ? "READ" : "MODE"); | ||
1149 | #endif | ||
1150 | break; | ||
1151 | } | ||
1152 | |||
1153 | case SJCD_S_MODE:{ | ||
1154 | if (sjcd_check_status()) { | ||
1155 | /* | ||
1156 | * Previous command is completed. | ||
1157 | */ | ||
1158 | if (!sjcd_status_valid | ||
1159 | || sjcd_command_failed) { | ||
1160 | #if defined( SJCD_TRACE ) | ||
1161 | printk | ||
1162 | ("SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n"); | ||
1163 | #endif | ||
1164 | sjcd_transfer_state = SJCD_S_STOP; | ||
1165 | goto ReSwitch; | ||
1166 | } | ||
1167 | |||
1168 | sjcd_mode = 0; /* unknown mode; should not be valid when failed */ | ||
1169 | sjcd_send_1_cmd(SCMD_SET_MODE, | ||
1170 | SCMD_MODE_COOKED); | ||
1171 | sjcd_transfer_state = SJCD_S_READ; | ||
1172 | sjcd_transfer_timeout = 1000; | ||
1173 | #if defined( SJCD_TRACE ) | ||
1174 | printk | ||
1175 | ("SJCD_S_MODE: goto SJCD_S_READ mode\n"); | ||
1176 | #endif | ||
1177 | } | ||
1178 | #if defined( SJCD_GATHER_STAT ) | ||
1179 | else | ||
1180 | statistic.mode_ticks++; | ||
1181 | #endif | ||
1182 | break; | ||
1183 | } | ||
1184 | |||
1185 | case SJCD_S_READ:{ | ||
1186 | if (sjcd_status_valid ? 1 : sjcd_check_status()) { | ||
1187 | /* | ||
1188 | * Previous command is completed. | ||
1189 | */ | ||
1190 | if (!sjcd_status_valid | ||
1191 | || sjcd_command_failed) { | ||
1192 | #if defined( SJCD_TRACE ) | ||
1193 | printk | ||
1194 | ("SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n"); | ||
1195 | #endif | ||
1196 | sjcd_transfer_state = SJCD_S_STOP; | ||
1197 | goto ReSwitch; | ||
1198 | } | ||
1199 | if (!sjcd_media_is_available) { | ||
1200 | #if defined( SJCD_TRACE ) | ||
1201 | printk | ||
1202 | ("SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n"); | ||
1203 | #endif | ||
1204 | sjcd_transfer_state = SJCD_S_STOP; | ||
1205 | goto ReSwitch; | ||
1206 | } | ||
1207 | if (sjcd_mode != SCMD_MODE_COOKED) { | ||
1208 | /* | ||
1209 | * We seem to come from set mode. So discard one byte of result. | ||
1210 | */ | ||
1211 | if (sjcd_load_response | ||
1212 | (&sjcd_mode, 1) != 0) { | ||
1213 | #if defined( SJCD_TRACE ) | ||
1214 | printk | ||
1215 | ("SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n"); | ||
1216 | #endif | ||
1217 | sjcd_transfer_state = | ||
1218 | SJCD_S_STOP; | ||
1219 | goto ReSwitch; | ||
1220 | } | ||
1221 | if (sjcd_mode != SCMD_MODE_COOKED) { | ||
1222 | #if defined( SJCD_TRACE ) | ||
1223 | printk | ||
1224 | ("SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n"); | ||
1225 | #endif | ||
1226 | sjcd_transfer_state = | ||
1227 | SJCD_S_STOP; | ||
1228 | goto ReSwitch; | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | if (current_valid()) { | ||
1233 | struct sjcd_play_msf msf; | ||
1234 | |||
1235 | sjcd_next_bn = CURRENT->sector / 4; | ||
1236 | hsg2msf(sjcd_next_bn, &msf.start); | ||
1237 | msf.end.min = 0; | ||
1238 | msf.end.sec = 0; | ||
1239 | msf.end.frame = sjcd_read_count = | ||
1240 | SJCD_BUF_SIZ; | ||
1241 | #if defined( SJCD_TRACE ) | ||
1242 | printk | ||
1243 | ("SJCD: ---reading msf-address %x:%x:%x %x:%x:%x\n", | ||
1244 | msf.start.min, msf.start.sec, | ||
1245 | msf.start.frame, msf.end.min, | ||
1246 | msf.end.sec, msf.end.frame); | ||
1247 | printk | ||
1248 | ("sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n", | ||
1249 | sjcd_next_bn, sjcd_buf_in, | ||
1250 | sjcd_buf_out, | ||
1251 | sjcd_buf_bn[sjcd_buf_in]); | ||
1252 | #endif | ||
1253 | sjcd_send_6_cmd(SCMD_DATA_READ, | ||
1254 | &msf); | ||
1255 | sjcd_transfer_state = SJCD_S_DATA; | ||
1256 | sjcd_transfer_timeout = 500; | ||
1257 | #if defined( SJCD_TRACE ) | ||
1258 | printk | ||
1259 | ("SJCD_S_READ: go to SJCD_S_DATA mode\n"); | ||
1260 | #endif | ||
1261 | } else { | ||
1262 | #if defined( SJCD_TRACE ) | ||
1263 | printk | ||
1264 | ("SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n"); | ||
1265 | #endif | ||
1266 | sjcd_transfer_state = SJCD_S_STOP; | ||
1267 | goto ReSwitch; | ||
1268 | } | ||
1269 | } | ||
1270 | #if defined( SJCD_GATHER_STAT ) | ||
1271 | else | ||
1272 | statistic.read_ticks++; | ||
1273 | #endif | ||
1274 | break; | ||
1275 | } | ||
1276 | |||
1277 | case SJCD_S_DATA:{ | ||
1278 | unsigned char stat; | ||
1279 | |||
1280 | sjcd_s_data:stat = | ||
1281 | inb(SJCDPORT | ||
1282 | (1)); | ||
1283 | #if defined( SJCD_TRACE ) | ||
1284 | printk("SJCD_S_DATA: status = 0x%02x\n", stat); | ||
1285 | #endif | ||
1286 | if (SJCD_STATUS_AVAILABLE(stat)) { | ||
1287 | /* | ||
1288 | * No data is waiting for us in the drive buffer. Status of operation | ||
1289 | * completion is available. Read and parse it. | ||
1290 | */ | ||
1291 | sjcd_load_status(); | ||
1292 | |||
1293 | if (!sjcd_status_valid | ||
1294 | || sjcd_command_failed) { | ||
1295 | #if defined( SJCD_TRACE ) | ||
1296 | printk | ||
1297 | ("SJCD: read block %d failed, maybe audio disk? Giving up\n", | ||
1298 | sjcd_next_bn); | ||
1299 | #endif | ||
1300 | if (current_valid()) | ||
1301 | end_request(CURRENT, 0); | ||
1302 | #if defined( SJCD_TRACE ) | ||
1303 | printk | ||
1304 | ("SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n"); | ||
1305 | #endif | ||
1306 | sjcd_transfer_state = SJCD_S_STOP; | ||
1307 | goto ReSwitch; | ||
1308 | } | ||
1309 | |||
1310 | if (!sjcd_media_is_available) { | ||
1311 | printk | ||
1312 | ("SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n"); | ||
1313 | sjcd_transfer_state = SJCD_S_STOP; | ||
1314 | goto ReSwitch; | ||
1315 | } | ||
1316 | |||
1317 | sjcd_transfer_state = SJCD_S_READ; | ||
1318 | goto ReSwitch; | ||
1319 | } else if (SJCD_DATA_AVAILABLE(stat)) { | ||
1320 | /* | ||
1321 | * One frame is read into device buffer. We must copy it to our memory. | ||
1322 | * Otherwise cdrom hangs up. Check to see if we have something to copy | ||
1323 | * to. | ||
1324 | */ | ||
1325 | if (!current_valid() | ||
1326 | && sjcd_buf_in == sjcd_buf_out) { | ||
1327 | #if defined( SJCD_TRACE ) | ||
1328 | printk | ||
1329 | ("SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n"); | ||
1330 | printk | ||
1331 | (" ... all the date would be discarded\n"); | ||
1332 | #endif | ||
1333 | sjcd_transfer_state = SJCD_S_STOP; | ||
1334 | goto ReSwitch; | ||
1335 | } | ||
1336 | |||
1337 | /* | ||
1338 | * Everything seems to be OK. Just read the frame and recalculate | ||
1339 | * indices. | ||
1340 | */ | ||
1341 | sjcd_buf_bn[sjcd_buf_in] = -1; /* ??? */ | ||
1342 | insb(SJCDPORT(2), | ||
1343 | sjcd_buf + 2048 * sjcd_buf_in, 2048); | ||
1344 | #if defined( SJCD_TRACE ) | ||
1345 | printk | ||
1346 | ("SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n", | ||
1347 | sjcd_next_bn, sjcd_buf_in, | ||
1348 | sjcd_buf_out, | ||
1349 | sjcd_buf_bn[sjcd_buf_in]); | ||
1350 | #endif | ||
1351 | sjcd_buf_bn[sjcd_buf_in] = sjcd_next_bn++; | ||
1352 | if (sjcd_buf_out == -1) | ||
1353 | sjcd_buf_out = sjcd_buf_in; | ||
1354 | if (++sjcd_buf_in == SJCD_BUF_SIZ) | ||
1355 | sjcd_buf_in = 0; | ||
1356 | |||
1357 | /* | ||
1358 | * Only one frame is ready at time. So we should turn over to wait for | ||
1359 | * another frame. If we need that, of course. | ||
1360 | */ | ||
1361 | if (--sjcd_read_count == 0) { | ||
1362 | /* | ||
1363 | * OK, request seems to be precessed. Continue transferring... | ||
1364 | */ | ||
1365 | if (!sjcd_transfer_is_active) { | ||
1366 | while (current_valid()) { | ||
1367 | /* | ||
1368 | * Continue transferring. | ||
1369 | */ | ||
1370 | sjcd_transfer(); | ||
1371 | if (CURRENT-> | ||
1372 | nr_sectors == | ||
1373 | 0) | ||
1374 | end_request | ||
1375 | (CURRENT, 1); | ||
1376 | else | ||
1377 | break; | ||
1378 | } | ||
1379 | } | ||
1380 | if (current_valid() && | ||
1381 | (CURRENT->sector / 4 < | ||
1382 | sjcd_next_bn | ||
1383 | || CURRENT->sector / 4 > | ||
1384 | sjcd_next_bn + | ||
1385 | SJCD_BUF_SIZ)) { | ||
1386 | #if defined( SJCD_TRACE ) | ||
1387 | printk | ||
1388 | ("SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n"); | ||
1389 | #endif | ||
1390 | sjcd_transfer_state = | ||
1391 | SJCD_S_STOP; | ||
1392 | goto ReSwitch; | ||
1393 | } | ||
1394 | } | ||
1395 | /* | ||
1396 | * Now we should turn around rather than wait for while. | ||
1397 | */ | ||
1398 | goto sjcd_s_data; | ||
1399 | } | ||
1400 | #if defined( SJCD_GATHER_STAT ) | ||
1401 | else | ||
1402 | statistic.data_ticks++; | ||
1403 | #endif | ||
1404 | break; | ||
1405 | } | ||
1406 | |||
1407 | case SJCD_S_STOP:{ | ||
1408 | sjcd_read_count = 0; | ||
1409 | sjcd_send_cmd(SCMD_STOP); | ||
1410 | sjcd_transfer_state = SJCD_S_STOPPING; | ||
1411 | sjcd_transfer_timeout = 500; | ||
1412 | #if defined( SJCD_GATHER_STAT ) | ||
1413 | statistic.stop_ticks++; | ||
1414 | #endif | ||
1415 | break; | ||
1416 | } | ||
1417 | |||
1418 | case SJCD_S_STOPPING:{ | ||
1419 | unsigned char stat; | ||
1420 | |||
1421 | stat = inb(SJCDPORT(1)); | ||
1422 | #if defined( SJCD_TRACE ) | ||
1423 | printk("SJCD_S_STOP: status = 0x%02x\n", stat); | ||
1424 | #endif | ||
1425 | if (SJCD_DATA_AVAILABLE(stat)) { | ||
1426 | int i; | ||
1427 | #if defined( SJCD_TRACE ) | ||
1428 | printk("SJCD_S_STOP: discard data\n"); | ||
1429 | #endif | ||
1430 | /* | ||
1431 | * Discard all the data from the pipe. Foolish method. | ||
1432 | */ | ||
1433 | for (i = 2048; i--; | ||
1434 | (void) inb(SJCDPORT(2))); | ||
1435 | sjcd_transfer_timeout = 500; | ||
1436 | } else if (SJCD_STATUS_AVAILABLE(stat)) { | ||
1437 | sjcd_load_status(); | ||
1438 | if (sjcd_status_valid | ||
1439 | && sjcd_media_is_changed) { | ||
1440 | sjcd_toc_uptodate = 0; | ||
1441 | sjcd_invalidate_buffers(); | ||
1442 | } | ||
1443 | if (current_valid()) { | ||
1444 | if (sjcd_status_valid) | ||
1445 | sjcd_transfer_state = | ||
1446 | SJCD_S_READ; | ||
1447 | else | ||
1448 | sjcd_transfer_state = | ||
1449 | SJCD_S_START; | ||
1450 | } else | ||
1451 | sjcd_transfer_state = SJCD_S_IDLE; | ||
1452 | goto ReSwitch; | ||
1453 | } | ||
1454 | #if defined( SJCD_GATHER_STAT ) | ||
1455 | else | ||
1456 | statistic.stopping_ticks++; | ||
1457 | #endif | ||
1458 | break; | ||
1459 | } | ||
1460 | |||
1461 | default: | ||
1462 | printk("SJCD: poll: invalid state %d\n", | ||
1463 | sjcd_transfer_state); | ||
1464 | return; | ||
1465 | } | ||
1466 | |||
1467 | if (--sjcd_transfer_timeout == 0) { | ||
1468 | printk("SJCD: timeout in state %d\n", sjcd_transfer_state); | ||
1469 | while (current_valid()) | ||
1470 | end_request(CURRENT, 0); | ||
1471 | sjcd_send_cmd(SCMD_STOP); | ||
1472 | sjcd_transfer_state = SJCD_S_IDLE; | ||
1473 | goto ReSwitch; | ||
1474 | } | ||
1475 | |||
1476 | /* | ||
1477 | * Get back in some time. 1 should be replaced with count variable to | ||
1478 | * avoid unnecessary testings. | ||
1479 | */ | ||
1480 | SJCD_SET_TIMER(sjcd_poll, 1); | ||
1481 | } | ||
1482 | |||
1483 | static void do_sjcd_request(request_queue_t * q) | ||
1484 | { | ||
1485 | #if defined( SJCD_TRACE ) | ||
1486 | printk("SJCD: do_sjcd_request(%ld+%ld)\n", | ||
1487 | CURRENT->sector, CURRENT->nr_sectors); | ||
1488 | #endif | ||
1489 | sjcd_transfer_is_active = 1; | ||
1490 | while (current_valid()) { | ||
1491 | sjcd_transfer(); | ||
1492 | if (CURRENT->nr_sectors == 0) | ||
1493 | end_request(CURRENT, 1); | ||
1494 | else { | ||
1495 | sjcd_buf_out = -1; /* Want to read a block not in buffer */ | ||
1496 | if (sjcd_transfer_state == SJCD_S_IDLE) { | ||
1497 | if (!sjcd_toc_uptodate) { | ||
1498 | if (sjcd_update_toc() < 0) { | ||
1499 | printk | ||
1500 | ("SJCD: transfer: discard\n"); | ||
1501 | while (current_valid()) | ||
1502 | end_request(CURRENT, 0); | ||
1503 | break; | ||
1504 | } | ||
1505 | } | ||
1506 | sjcd_transfer_state = SJCD_S_START; | ||
1507 | SJCD_SET_TIMER(sjcd_poll, HZ / 100); | ||
1508 | } | ||
1509 | break; | ||
1510 | } | ||
1511 | } | ||
1512 | sjcd_transfer_is_active = 0; | ||
1513 | #if defined( SJCD_TRACE ) | ||
1514 | printk | ||
1515 | ("sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n", | ||
1516 | sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, | ||
1517 | sjcd_buf_bn[sjcd_buf_in]); | ||
1518 | printk("do_sjcd_request ends\n"); | ||
1519 | #endif | ||
1520 | } | ||
1521 | |||
1522 | /* | ||
1523 | * Open the device special file. Check disk is in. | ||
1524 | */ | ||
1525 | static int sjcd_open(struct inode *ip, struct file *fp) | ||
1526 | { | ||
1527 | /* | ||
1528 | * Check the presence of device. | ||
1529 | */ | ||
1530 | if (!sjcd_present) | ||
1531 | return (-ENXIO); | ||
1532 | |||
1533 | /* | ||
1534 | * Only read operations are allowed. Really? (:-) | ||
1535 | */ | ||
1536 | if (fp->f_mode & 2) | ||
1537 | return (-EROFS); | ||
1538 | |||
1539 | if (sjcd_open_count == 0) { | ||
1540 | int s, sjcd_open_tries; | ||
1541 | /* We don't know that, do we? */ | ||
1542 | /* | ||
1543 | sjcd_audio_status = CDROM_AUDIO_NO_STATUS; | ||
1544 | */ | ||
1545 | sjcd_mode = 0; | ||
1546 | sjcd_door_was_open = 0; | ||
1547 | sjcd_transfer_state = SJCD_S_IDLE; | ||
1548 | sjcd_invalidate_buffers(); | ||
1549 | sjcd_status_valid = 0; | ||
1550 | |||
1551 | /* | ||
1552 | * Strict status checking. | ||
1553 | */ | ||
1554 | for (sjcd_open_tries = 4; --sjcd_open_tries;) { | ||
1555 | if (!sjcd_status_valid) | ||
1556 | sjcd_get_status(); | ||
1557 | if (!sjcd_status_valid) { | ||
1558 | #if defined( SJCD_DIAGNOSTIC ) | ||
1559 | printk | ||
1560 | ("SJCD: open: timed out when check status.\n"); | ||
1561 | #endif | ||
1562 | goto err_out; | ||
1563 | } else if (!sjcd_media_is_available) { | ||
1564 | #if defined( SJCD_DIAGNOSTIC ) | ||
1565 | printk("SJCD: open: no disk in drive\n"); | ||
1566 | #endif | ||
1567 | if (!sjcd_door_closed) { | ||
1568 | sjcd_door_was_open = 1; | ||
1569 | #if defined( SJCD_TRACE ) | ||
1570 | printk | ||
1571 | ("SJCD: open: close the tray\n"); | ||
1572 | #endif | ||
1573 | s = sjcd_tray_close(); | ||
1574 | if (s < 0 || !sjcd_status_valid | ||
1575 | || sjcd_command_failed) { | ||
1576 | #if defined( SJCD_DIAGNOSTIC ) | ||
1577 | printk | ||
1578 | ("SJCD: open: tray close attempt failed\n"); | ||
1579 | #endif | ||
1580 | goto err_out; | ||
1581 | } | ||
1582 | continue; | ||
1583 | } else | ||
1584 | goto err_out; | ||
1585 | } | ||
1586 | break; | ||
1587 | } | ||
1588 | s = sjcd_tray_lock(); | ||
1589 | if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { | ||
1590 | #if defined( SJCD_DIAGNOSTIC ) | ||
1591 | printk("SJCD: open: tray lock attempt failed\n"); | ||
1592 | #endif | ||
1593 | goto err_out; | ||
1594 | } | ||
1595 | #if defined( SJCD_TRACE ) | ||
1596 | printk("SJCD: open: done\n"); | ||
1597 | #endif | ||
1598 | } | ||
1599 | |||
1600 | ++sjcd_open_count; | ||
1601 | return (0); | ||
1602 | |||
1603 | err_out: | ||
1604 | return (-EIO); | ||
1605 | } | ||
1606 | |||
1607 | /* | ||
1608 | * On close, we flush all sjcd blocks from the buffer cache. | ||
1609 | */ | ||
1610 | static int sjcd_release(struct inode *inode, struct file *file) | ||
1611 | { | ||
1612 | int s; | ||
1613 | |||
1614 | #if defined( SJCD_TRACE ) | ||
1615 | printk("SJCD: release\n"); | ||
1616 | #endif | ||
1617 | if (--sjcd_open_count == 0) { | ||
1618 | sjcd_invalidate_buffers(); | ||
1619 | s = sjcd_tray_unlock(); | ||
1620 | if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { | ||
1621 | #if defined( SJCD_DIAGNOSTIC ) | ||
1622 | printk | ||
1623 | ("SJCD: release: tray unlock attempt failed.\n"); | ||
1624 | #endif | ||
1625 | } | ||
1626 | if (sjcd_door_was_open) { | ||
1627 | s = sjcd_tray_open(); | ||
1628 | if (s < 0 || !sjcd_status_valid | ||
1629 | || sjcd_command_failed) { | ||
1630 | #if defined( SJCD_DIAGNOSTIC ) | ||
1631 | printk | ||
1632 | ("SJCD: release: tray unload attempt failed.\n"); | ||
1633 | #endif | ||
1634 | } | ||
1635 | } | ||
1636 | } | ||
1637 | return 0; | ||
1638 | } | ||
1639 | |||
1640 | /* | ||
1641 | * A list of file operations allowed for this cdrom. | ||
1642 | */ | ||
1643 | static struct block_device_operations sjcd_fops = { | ||
1644 | .owner = THIS_MODULE, | ||
1645 | .open = sjcd_open, | ||
1646 | .release = sjcd_release, | ||
1647 | .ioctl = sjcd_ioctl, | ||
1648 | .media_changed = sjcd_disk_change, | ||
1649 | }; | ||
1650 | |||
1651 | /* | ||
1652 | * Following stuff is intended for initialization of the cdrom. It | ||
1653 | * first looks for presence of device. If the device is present, it | ||
1654 | * will be reset. Then read the version of the drive and load status. | ||
1655 | * The version is two BCD-coded bytes. | ||
1656 | */ | ||
1657 | static struct { | ||
1658 | unsigned char major, minor; | ||
1659 | } sjcd_version; | ||
1660 | |||
1661 | static struct gendisk *sjcd_disk; | ||
1662 | |||
1663 | /* | ||
1664 | * Test for presence of drive and initialize it. Called at boot time. | ||
1665 | * Probe cdrom, find out version and status. | ||
1666 | */ | ||
1667 | static int __init sjcd_init(void) | ||
1668 | { | ||
1669 | int i; | ||
1670 | |||
1671 | printk(KERN_INFO | ||
1672 | "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", | ||
1673 | SJCD_VERSION_MAJOR, SJCD_VERSION_MINOR); | ||
1674 | |||
1675 | #if defined( SJCD_TRACE ) | ||
1676 | printk("SJCD: sjcd=0x%x: ", sjcd_base); | ||
1677 | #endif | ||
1678 | |||
1679 | if (register_blkdev(MAJOR_NR, "sjcd")) | ||
1680 | return -EIO; | ||
1681 | |||
1682 | sjcd_queue = blk_init_queue(do_sjcd_request, &sjcd_lock); | ||
1683 | if (!sjcd_queue) | ||
1684 | goto out0; | ||
1685 | |||
1686 | blk_queue_hardsect_size(sjcd_queue, 2048); | ||
1687 | |||
1688 | sjcd_disk = alloc_disk(1); | ||
1689 | if (!sjcd_disk) { | ||
1690 | printk(KERN_ERR "SJCD: can't allocate disk"); | ||
1691 | goto out1; | ||
1692 | } | ||
1693 | sjcd_disk->major = MAJOR_NR, | ||
1694 | sjcd_disk->first_minor = 0, | ||
1695 | sjcd_disk->fops = &sjcd_fops, | ||
1696 | sprintf(sjcd_disk->disk_name, "sjcd"); | ||
1697 | |||
1698 | if (!request_region(sjcd_base, 4,"sjcd")) { | ||
1699 | printk | ||
1700 | ("SJCD: Init failed, I/O port (%X) is already in use\n", | ||
1701 | sjcd_base); | ||
1702 | goto out2; | ||
1703 | } | ||
1704 | |||
1705 | /* | ||
1706 | * Check for card. Since we are booting now, we can't use standard | ||
1707 | * wait algorithm. | ||
1708 | */ | ||
1709 | printk(KERN_INFO "SJCD: Resetting: "); | ||
1710 | sjcd_send_cmd(SCMD_RESET); | ||
1711 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1712 | unsigned long timer; | ||
1713 | |||
1714 | /* | ||
1715 | * Wait 10ms approx. | ||
1716 | */ | ||
1717 | for (timer = jiffies; time_before_eq(jiffies, timer);); | ||
1718 | if ((i % 100) == 0) | ||
1719 | printk("."); | ||
1720 | (void) sjcd_check_status(); | ||
1721 | } | ||
1722 | if (i == 0 || sjcd_command_failed) { | ||
1723 | printk(" reset failed, no drive found.\n"); | ||
1724 | goto out3; | ||
1725 | } else | ||
1726 | printk("\n"); | ||
1727 | |||
1728 | /* | ||
1729 | * Get and print out cdrom version. | ||
1730 | */ | ||
1731 | printk(KERN_INFO "SJCD: Getting version: "); | ||
1732 | sjcd_send_cmd(SCMD_GET_VERSION); | ||
1733 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1734 | unsigned long timer; | ||
1735 | |||
1736 | /* | ||
1737 | * Wait 10ms approx. | ||
1738 | */ | ||
1739 | for (timer = jiffies; time_before_eq(jiffies, timer);); | ||
1740 | if ((i % 100) == 0) | ||
1741 | printk("."); | ||
1742 | (void) sjcd_check_status(); | ||
1743 | } | ||
1744 | if (i == 0 || sjcd_command_failed) { | ||
1745 | printk(" get version failed, no drive found.\n"); | ||
1746 | goto out3; | ||
1747 | } | ||
1748 | |||
1749 | if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) { | ||
1750 | printk(" %1x.%02x\n", (int) sjcd_version.major, | ||
1751 | (int) sjcd_version.minor); | ||
1752 | } else { | ||
1753 | printk(" read version failed, no drive found.\n"); | ||
1754 | goto out3; | ||
1755 | } | ||
1756 | |||
1757 | /* | ||
1758 | * Check and print out the tray state. (if it is needed?). | ||
1759 | */ | ||
1760 | if (!sjcd_status_valid) { | ||
1761 | printk(KERN_INFO "SJCD: Getting status: "); | ||
1762 | sjcd_send_cmd(SCMD_GET_STATUS); | ||
1763 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1764 | unsigned long timer; | ||
1765 | |||
1766 | /* | ||
1767 | * Wait 10ms approx. | ||
1768 | */ | ||
1769 | for (timer = jiffies; | ||
1770 | time_before_eq(jiffies, timer);); | ||
1771 | if ((i % 100) == 0) | ||
1772 | printk("."); | ||
1773 | (void) sjcd_check_status(); | ||
1774 | } | ||
1775 | if (i == 0 || sjcd_command_failed) { | ||
1776 | printk(" get status failed, no drive found.\n"); | ||
1777 | goto out3; | ||
1778 | } else | ||
1779 | printk("\n"); | ||
1780 | } | ||
1781 | |||
1782 | printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); | ||
1783 | sjcd_disk->queue = sjcd_queue; | ||
1784 | add_disk(sjcd_disk); | ||
1785 | |||
1786 | sjcd_present++; | ||
1787 | return (0); | ||
1788 | out3: | ||
1789 | release_region(sjcd_base, 4); | ||
1790 | out2: | ||
1791 | put_disk(sjcd_disk); | ||
1792 | out1: | ||
1793 | blk_cleanup_queue(sjcd_queue); | ||
1794 | out0: | ||
1795 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | ||
1796 | printk("SJCD: cannot unregister device.\n"); | ||
1797 | return (-EIO); | ||
1798 | } | ||
1799 | |||
1800 | static void __exit sjcd_exit(void) | ||
1801 | { | ||
1802 | del_gendisk(sjcd_disk); | ||
1803 | put_disk(sjcd_disk); | ||
1804 | release_region(sjcd_base, 4); | ||
1805 | blk_cleanup_queue(sjcd_queue); | ||
1806 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | ||
1807 | printk("SJCD: cannot unregister device.\n"); | ||
1808 | printk(KERN_INFO "SJCD: module: removed.\n"); | ||
1809 | } | ||
1810 | |||
1811 | module_init(sjcd_init); | ||
1812 | module_exit(sjcd_exit); | ||
1813 | |||
1814 | MODULE_LICENSE("GPL"); | ||
1815 | MODULE_ALIAS_BLOCKDEV_MAJOR(SANYO_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/sjcd.h b/drivers/cdrom/sjcd.h deleted file mode 100644 index 0aa5e714659d..000000000000 --- a/drivers/cdrom/sjcd.h +++ /dev/null | |||
@@ -1,181 +0,0 @@ | |||
1 | /* | ||
2 | * Definitions for a Sanyo CD-ROM interface. | ||
3 | * | ||
4 | * Copyright (C) 1995 Vadim V. Model | ||
5 | * model@cecmow.enet.dec.com | ||
6 | * vadim@rbrf.msk.su | ||
7 | * vadim@ipsun.ras.ru | ||
8 | * Eric van der Maarel | ||
9 | * H.T.M.v.d.Maarel@marin.nl | ||
10 | * | ||
11 | * This information is based on mcd.c from M. Harriss and sjcd102.lst from | ||
12 | * E. Moenkeberg. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | |||
29 | #ifndef __SJCD_H__ | ||
30 | #define __SJCD_H__ | ||
31 | |||
32 | /* | ||
33 | * Change this to set the I/O port address as default. More flexibility | ||
34 | * come with setup implementation. | ||
35 | */ | ||
36 | #define SJCD_BASE_ADDR 0x340 | ||
37 | |||
38 | /* | ||
39 | * Change this to set the irq as default. Really SANYO do not use interrupts | ||
40 | * at all. | ||
41 | */ | ||
42 | #define SJCD_INTR_NR 0 | ||
43 | |||
44 | /* | ||
45 | * Change this to set the dma as default value. really SANYO does not use | ||
46 | * direct memory access at all. | ||
47 | */ | ||
48 | #define SJCD_DMA_NR 0 | ||
49 | |||
50 | /* | ||
51 | * Macros which allow us to find out the status of the drive. | ||
52 | */ | ||
53 | #define SJCD_STATUS_AVAILABLE( x ) (((x)&0x02)==0) | ||
54 | #define SJCD_DATA_AVAILABLE( x ) (((x)&0x01)==0) | ||
55 | |||
56 | /* | ||
57 | * Port access macro. Three ports are available: S-data port (command port), | ||
58 | * status port (read only) and D-data port (read only). | ||
59 | */ | ||
60 | #define SJCDPORT( x ) ( sjcd_base + ( x ) ) | ||
61 | #define SJCD_STATUS_PORT SJCDPORT( 1 ) | ||
62 | #define SJCD_S_DATA_PORT SJCDPORT( 0 ) | ||
63 | #define SJCD_COMMAND_PORT SJCDPORT( 0 ) | ||
64 | #define SJCD_D_DATA_PORT SJCDPORT( 2 ) | ||
65 | |||
66 | /* | ||
67 | * Drive info bits. Drive info available as first (mandatory) byte of | ||
68 | * command completion status. | ||
69 | */ | ||
70 | #define SST_NOT_READY 0x10 /* no disk in the drive (???) */ | ||
71 | #define SST_MEDIA_CHANGED 0x20 /* disk is changed */ | ||
72 | #define SST_DOOR_OPENED 0x40 /* door is open */ | ||
73 | |||
74 | /* commands */ | ||
75 | |||
76 | #define SCMD_EJECT_TRAY 0xD0 /* eject tray if not locked */ | ||
77 | #define SCMD_LOCK_TRAY 0xD2 /* lock tray when in */ | ||
78 | #define SCMD_UNLOCK_TRAY 0xD4 /* unlock tray when in */ | ||
79 | #define SCMD_CLOSE_TRAY 0xD6 /* load tray in */ | ||
80 | |||
81 | #define SCMD_RESET 0xFA /* soft reset */ | ||
82 | #define SCMD_GET_STATUS 0x80 | ||
83 | #define SCMD_GET_VERSION 0xCC | ||
84 | |||
85 | #define SCMD_DATA_READ 0xA0 /* are the same, depend on mode&args */ | ||
86 | #define SCMD_SEEK 0xA0 | ||
87 | #define SCMD_PLAY 0xA0 | ||
88 | |||
89 | #define SCMD_GET_QINFO 0xA8 | ||
90 | |||
91 | #define SCMD_SET_MODE 0xC4 | ||
92 | #define SCMD_MODE_PLAY 0xE0 | ||
93 | #define SCMD_MODE_COOKED (0xF8 & ~0x20) | ||
94 | #define SCMD_MODE_RAW 0xF9 | ||
95 | #define SCMD_MODE_x20_BIT 0x20 /* What is it for ? */ | ||
96 | |||
97 | #define SCMD_SET_VOLUME 0xAE | ||
98 | #define SCMD_PAUSE 0xE0 | ||
99 | #define SCMD_STOP 0xE0 | ||
100 | |||
101 | #define SCMD_GET_DISK_INFO 0xAA | ||
102 | |||
103 | /* | ||
104 | * Some standard arguments for SCMD_GET_DISK_INFO. | ||
105 | */ | ||
106 | #define SCMD_GET_1_TRACK 0xA0 /* get the first track information */ | ||
107 | #define SCMD_GET_L_TRACK 0xA1 /* get the last track information */ | ||
108 | #define SCMD_GET_D_SIZE 0xA2 /* get the whole disk information */ | ||
109 | |||
110 | /* | ||
111 | * Borrowed from hd.c. Allows to optimize multiple port read commands. | ||
112 | */ | ||
113 | #define S_READ_DATA( port, buf, nr ) insb( port, buf, nr ) | ||
114 | |||
115 | /* | ||
116 | * We assume that there are no audio disks with TOC length more than this | ||
117 | * number (I personally have never seen disks with more than 20 fragments). | ||
118 | */ | ||
119 | #define SJCD_MAX_TRACKS 100 | ||
120 | |||
121 | struct msf { | ||
122 | unsigned char min; | ||
123 | unsigned char sec; | ||
124 | unsigned char frame; | ||
125 | }; | ||
126 | |||
127 | struct sjcd_hw_disk_info { | ||
128 | unsigned char track_control; | ||
129 | unsigned char track_no; | ||
130 | unsigned char x, y, z; | ||
131 | union { | ||
132 | unsigned char track_no; | ||
133 | struct msf track_msf; | ||
134 | } un; | ||
135 | }; | ||
136 | |||
137 | struct sjcd_hw_qinfo { | ||
138 | unsigned char track_control; | ||
139 | unsigned char track_no; | ||
140 | unsigned char x; | ||
141 | struct msf rel; | ||
142 | struct msf abs; | ||
143 | }; | ||
144 | |||
145 | struct sjcd_play_msf { | ||
146 | struct msf start; | ||
147 | struct msf end; | ||
148 | }; | ||
149 | |||
150 | struct sjcd_disk_info { | ||
151 | unsigned char first; | ||
152 | unsigned char last; | ||
153 | struct msf disk_length; | ||
154 | struct msf first_track; | ||
155 | }; | ||
156 | |||
157 | struct sjcd_toc { | ||
158 | unsigned char ctrl_addr; | ||
159 | unsigned char track; | ||
160 | unsigned char point_index; | ||
161 | struct msf track_time; | ||
162 | struct msf disk_time; | ||
163 | }; | ||
164 | |||
165 | #if defined( SJCD_GATHER_STAT ) | ||
166 | |||
167 | struct sjcd_stat { | ||
168 | int ticks; | ||
169 | int tticks[ 8 ]; | ||
170 | int idle_ticks; | ||
171 | int start_ticks; | ||
172 | int mode_ticks; | ||
173 | int read_ticks; | ||
174 | int data_ticks; | ||
175 | int stop_ticks; | ||
176 | int stopping_ticks; | ||
177 | }; | ||
178 | |||
179 | #endif | ||
180 | |||
181 | #endif | ||
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c deleted file mode 100644 index f77ada933ea0..000000000000 --- a/drivers/cdrom/sonycd535.c +++ /dev/null | |||
@@ -1,1689 +0,0 @@ | |||
1 | /* | ||
2 | * Sony CDU-535 interface device driver | ||
3 | * | ||
4 | * This is a modified version of the CDU-31A device driver (see below). | ||
5 | * Changes were made using documentation for the CDU-531 (which Sony | ||
6 | * assures me is very similar to the 535) and partial disassembly of the | ||
7 | * DOS driver. I used Minyard's driver and replaced the CDU-31A | ||
8 | * commands with the CDU-531 commands. This was complicated by a different | ||
9 | * interface protocol with the drive. The driver is still polled. | ||
10 | * | ||
11 | * Data transfer rate is about 110 Kb/sec, theoretical maximum is 150 Kb/sec. | ||
12 | * I tried polling without the sony_sleep during the data transfers but | ||
13 | * it did not speed things up any. | ||
14 | * | ||
15 | * 1993-05-23 (rgj) changed the major number to 21 to get rid of conflict | ||
16 | * with CDU-31A driver. This is the also the number from the Linux | ||
17 | * Device Driver Registry for the Sony Drive. Hope nobody else is using it. | ||
18 | * | ||
19 | * 1993-08-29 (rgj) remove the configuring of the interface board address | ||
20 | * from the top level configuration, you have to modify it in this file. | ||
21 | * | ||
22 | * 1995-01-26 Made module-capable (Joel Katz <Stimpson@Panix.COM>) | ||
23 | * | ||
24 | * 1995-05-20 | ||
25 | * Modified to support CDU-510/515 series | ||
26 | * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) | ||
27 | * Fixed to report verify_area() failures | ||
28 | * (Heiko Eissfeldt <heiko@colossus.escape.de>) | ||
29 | * | ||
30 | * 1995-06-01 | ||
31 | * More changes to support CDU-510/515 series | ||
32 | * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) | ||
33 | * | ||
34 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
35 | * Removed init_module & cleanup_module in favor of | ||
36 | * module_init & module_exit. | ||
37 | * Torben Mathiasen <tmm@image.dk> | ||
38 | * | ||
39 | * September 2003 - Fix SMP support by removing cli/sti calls. | ||
40 | * Using spinlocks with a wait_queue instead. | ||
41 | * Felipe Damasio <felipewd@terra.com.br> | ||
42 | * | ||
43 | * Things to do: | ||
44 | * - handle errors and status better, put everything into a single word | ||
45 | * - use interrupts (code mostly there, but a big hole still missing) | ||
46 | * - handle multi-session CDs? | ||
47 | * - use DMA? | ||
48 | * | ||
49 | * Known Bugs: | ||
50 | * - | ||
51 | * | ||
52 | * Ken Pizzini (ken@halcyon.com) | ||
53 | * | ||
54 | * Original by: | ||
55 | * Ron Jeppesen (ronj.an@site007.saic.com) | ||
56 | * | ||
57 | * | ||
58 | *------------------------------------------------------------------------ | ||
59 | * Sony CDROM interface device driver. | ||
60 | * | ||
61 | * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above) | ||
62 | * | ||
63 | * Colossians 3:17 | ||
64 | * | ||
65 | * The Sony interface device driver handles Sony interface CDROM | ||
66 | * drives and provides a complete block-level interface as well as an | ||
67 | * ioctl() interface compatible with the Sun (as specified in | ||
68 | * include/linux/cdrom.h). With this interface, CDROMs can be | ||
69 | * accessed and standard audio CDs can be played back normally. | ||
70 | * | ||
71 | * This interface is (unfortunately) a polled interface. This is | ||
72 | * because most Sony interfaces are set up with DMA and interrupts | ||
73 | * disables. Some (like mine) do not even have the capability to | ||
74 | * handle interrupts or DMA. For this reason you will see a bit of | ||
75 | * the following: | ||
76 | * | ||
77 | * snap = jiffies; | ||
78 | * while (jiffies-snap < SONY_JIFFIES_TIMEOUT) | ||
79 | * { | ||
80 | * if (some_condition()) | ||
81 | * break; | ||
82 | * sony_sleep(); | ||
83 | * } | ||
84 | * if (some_condition not met) | ||
85 | * { | ||
86 | * return an_error; | ||
87 | * } | ||
88 | * | ||
89 | * This ugly hack waits for something to happen, sleeping a little | ||
90 | * between every try. (The conditional is written so that jiffies | ||
91 | * wrap-around is handled properly.) | ||
92 | * | ||
93 | * One thing about these drives: They talk in MSF (Minute Second Frame) format. | ||
94 | * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a | ||
95 | * disk. The funny thing is that these are sent to the drive in BCD, but the | ||
96 | * interface wants to see them in decimal. A lot of conversion goes on. | ||
97 | * | ||
98 | * Copyright (C) 1993 Corey Minyard | ||
99 | * | ||
100 | * This program is free software; you can redistribute it and/or modify | ||
101 | * it under the terms of the GNU General Public License as published by | ||
102 | * the Free Software Foundation; either version 2 of the License, or | ||
103 | * (at your option) any later version. | ||
104 | * | ||
105 | * This program is distributed in the hope that it will be useful, | ||
106 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
107 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
108 | * GNU General Public License for more details. | ||
109 | * | ||
110 | * You should have received a copy of the GNU General Public License | ||
111 | * along with this program; if not, write to the Free Software | ||
112 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
113 | * | ||
114 | */ | ||
115 | |||
116 | |||
117 | # include <linux/module.h> | ||
118 | |||
119 | #include <linux/errno.h> | ||
120 | #include <linux/signal.h> | ||
121 | #include <linux/sched.h> | ||
122 | #include <linux/timer.h> | ||
123 | #include <linux/fs.h> | ||
124 | #include <linux/kernel.h> | ||
125 | #include <linux/interrupt.h> | ||
126 | #include <linux/ioport.h> | ||
127 | #include <linux/hdreg.h> | ||
128 | #include <linux/genhd.h> | ||
129 | #include <linux/mm.h> | ||
130 | #include <linux/slab.h> | ||
131 | #include <linux/init.h> | ||
132 | |||
133 | #define REALLY_SLOW_IO | ||
134 | #include <asm/system.h> | ||
135 | #include <asm/io.h> | ||
136 | #include <asm/uaccess.h> | ||
137 | |||
138 | #include <linux/cdrom.h> | ||
139 | |||
140 | #define MAJOR_NR CDU535_CDROM_MAJOR | ||
141 | #include <linux/blkdev.h> | ||
142 | |||
143 | #define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ | ||
144 | #include "sonycd535.h" | ||
145 | |||
146 | /* | ||
147 | * this is the base address of the interface card for the Sony CDU-535 | ||
148 | * CDROM drive. If your jumpers are set for an address other than | ||
149 | * this one (the default), change the following line to the | ||
150 | * proper address. | ||
151 | */ | ||
152 | #ifndef CDU535_ADDRESS | ||
153 | # define CDU535_ADDRESS 0x340 | ||
154 | #endif | ||
155 | #ifndef CDU535_INTERRUPT | ||
156 | # define CDU535_INTERRUPT 0 | ||
157 | #endif | ||
158 | #ifndef CDU535_HANDLE | ||
159 | # define CDU535_HANDLE "cdu535" | ||
160 | #endif | ||
161 | #ifndef CDU535_MESSAGE_NAME | ||
162 | # define CDU535_MESSAGE_NAME "Sony CDU-535" | ||
163 | #endif | ||
164 | |||
165 | #define CDU535_BLOCK_SIZE 2048 | ||
166 | |||
167 | #ifndef MAX_SPINUP_RETRY | ||
168 | # define MAX_SPINUP_RETRY 3 /* 1 is sufficient for most drives... */ | ||
169 | #endif | ||
170 | #ifndef RETRY_FOR_BAD_STATUS | ||
171 | # define RETRY_FOR_BAD_STATUS 100 /* in 10th of second */ | ||
172 | #endif | ||
173 | |||
174 | #ifndef DEBUG | ||
175 | # define DEBUG 1 | ||
176 | #endif | ||
177 | |||
178 | /* | ||
179 | * SONY535_BUFFER_SIZE determines the size of internal buffer used | ||
180 | * by the drive. It must be at least 2K and the larger the buffer | ||
181 | * the better the transfer rate. It does however take system memory. | ||
182 | * On my system I get the following transfer rates using dd to read | ||
183 | * 10 Mb off /dev/cdrom. | ||
184 | * | ||
185 | * 8K buffer 43 Kb/sec | ||
186 | * 16K buffer 66 Kb/sec | ||
187 | * 32K buffer 91 Kb/sec | ||
188 | * 64K buffer 111 Kb/sec | ||
189 | * 128K buffer 123 Kb/sec | ||
190 | * 512K buffer 123 Kb/sec | ||
191 | */ | ||
192 | #define SONY535_BUFFER_SIZE (64*1024) | ||
193 | |||
194 | /* | ||
195 | * if LOCK_DOORS is defined then the eject button is disabled while | ||
196 | * the device is open. | ||
197 | */ | ||
198 | #ifndef NO_LOCK_DOORS | ||
199 | # define LOCK_DOORS | ||
200 | #endif | ||
201 | |||
202 | static int read_subcode(void); | ||
203 | static void sony_get_toc(void); | ||
204 | static int cdu_open(struct inode *inode, struct file *filp); | ||
205 | static inline unsigned int int_to_bcd(unsigned int val); | ||
206 | static unsigned int bcd_to_int(unsigned int bcd); | ||
207 | static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2], | ||
208 | Byte * response, int n_response, int ignoreStatusBit7); | ||
209 | |||
210 | /* The base I/O address of the Sony Interface. This is a variable (not a | ||
211 | #define) so it can be easily changed via some future ioctl() */ | ||
212 | static unsigned int sony535_cd_base_io = CDU535_ADDRESS; | ||
213 | module_param(sony535_cd_base_io, int, 0); | ||
214 | |||
215 | /* | ||
216 | * The following are I/O addresses of the various registers for the drive. The | ||
217 | * comment for the base address also applies here. | ||
218 | */ | ||
219 | static unsigned short select_unit_reg; | ||
220 | static unsigned short result_reg; | ||
221 | static unsigned short command_reg; | ||
222 | static unsigned short read_status_reg; | ||
223 | static unsigned short data_reg; | ||
224 | |||
225 | static DEFINE_SPINLOCK(sonycd535_lock); /* queue lock */ | ||
226 | static struct request_queue *sonycd535_queue; | ||
227 | |||
228 | static int initialized; /* Has the drive been initialized? */ | ||
229 | static int sony_disc_changed = 1; /* Has the disk been changed | ||
230 | since the last check? */ | ||
231 | static int sony_toc_read; /* Has the table of contents been | ||
232 | read? */ | ||
233 | static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead | ||
234 | buffer. */ | ||
235 | static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of | ||
236 | the read-ahead buffer. */ | ||
237 | static unsigned int sony_usage; /* How many processes have the | ||
238 | drive open. */ | ||
239 | |||
240 | static int sony_first_block = -1; /* First OS block (512 byte) in | ||
241 | the read-ahead buffer */ | ||
242 | static int sony_last_block = -1; /* Last OS block (512 byte) in | ||
243 | the read-ahead buffer */ | ||
244 | |||
245 | static struct s535_sony_toc *sony_toc; /* Points to the table of | ||
246 | contents. */ | ||
247 | |||
248 | static struct s535_sony_subcode *last_sony_subcode; /* Points to the last | ||
249 | subcode address read */ | ||
250 | static Byte **sony_buffer; /* Points to the pointers | ||
251 | to the sector buffers */ | ||
252 | |||
253 | static int sony_inuse; /* is the drive in use? Only one | ||
254 | open at a time allowed */ | ||
255 | |||
256 | /* | ||
257 | * The audio status uses the values from read subchannel data as specified | ||
258 | * in include/linux/cdrom.h. | ||
259 | */ | ||
260 | static int sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
261 | |||
262 | /* | ||
263 | * The following are a hack for pausing and resuming audio play. The drive | ||
264 | * does not work as I would expect it, if you stop it then start it again, | ||
265 | * the drive seeks back to the beginning and starts over. This holds the | ||
266 | * position during a pause so a resume can restart it. It uses the | ||
267 | * audio status variable above to tell if it is paused. | ||
268 | * I just kept the CDU-31A driver behavior rather than using the PAUSE | ||
269 | * command on the CDU-535. | ||
270 | */ | ||
271 | static Byte cur_pos_msf[3]; | ||
272 | static Byte final_pos_msf[3]; | ||
273 | |||
274 | /* What IRQ is the drive using? 0 if none. */ | ||
275 | static int sony535_irq_used = CDU535_INTERRUPT; | ||
276 | |||
277 | /* The interrupt handler will wake this queue up when it gets an interrupt. */ | ||
278 | static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait); | ||
279 | |||
280 | |||
281 | /* | ||
282 | * This routine returns 1 if the disk has been changed since the last | ||
283 | * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. | ||
284 | */ | ||
285 | static int | ||
286 | cdu535_check_media_change(struct gendisk *disk) | ||
287 | { | ||
288 | /* if driver is not initialized, always return 0 */ | ||
289 | int retval = initialized ? sony_disc_changed : 0; | ||
290 | sony_disc_changed = 0; | ||
291 | return retval; | ||
292 | } | ||
293 | |||
294 | static inline void | ||
295 | enable_interrupts(void) | ||
296 | { | ||
297 | #ifdef USE_IRQ | ||
298 | /* | ||
299 | * This code was taken from cdu31a.c; it will not | ||
300 | * directly work for the cdu535 as written... | ||
301 | */ | ||
302 | curr_control_reg |= ( SONY_ATTN_INT_EN_BIT | ||
303 | | SONY_RES_RDY_INT_EN_BIT | ||
304 | | SONY_DATA_RDY_INT_EN_BIT); | ||
305 | outb(curr_control_reg, sony_cd_control_reg); | ||
306 | #endif | ||
307 | } | ||
308 | |||
309 | static inline void | ||
310 | disable_interrupts(void) | ||
311 | { | ||
312 | #ifdef USE_IRQ | ||
313 | /* | ||
314 | * This code was taken from cdu31a.c; it will not | ||
315 | * directly work for the cdu535 as written... | ||
316 | */ | ||
317 | curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT | ||
318 | | SONY_RES_RDY_INT_EN_BIT | ||
319 | | SONY_DATA_RDY_INT_EN_BIT); | ||
320 | outb(curr_control_reg, sony_cd_control_reg); | ||
321 | #endif | ||
322 | } | ||
323 | |||
324 | static irqreturn_t | ||
325 | cdu535_interrupt(int irq, void *dev_id) | ||
326 | { | ||
327 | disable_interrupts(); | ||
328 | if (waitqueue_active(&cdu535_irq_wait)) { | ||
329 | wake_up(&cdu535_irq_wait); | ||
330 | return IRQ_HANDLED; | ||
331 | } | ||
332 | printk(CDU535_MESSAGE_NAME | ||
333 | ": Got an interrupt but nothing was waiting\n"); | ||
334 | return IRQ_NONE; | ||
335 | } | ||
336 | |||
337 | |||
338 | /* | ||
339 | * Wait a little while. | ||
340 | */ | ||
341 | static inline void | ||
342 | sony_sleep(void) | ||
343 | { | ||
344 | if (sony535_irq_used <= 0) { /* poll */ | ||
345 | yield(); | ||
346 | } else { /* Interrupt driven */ | ||
347 | DEFINE_WAIT(wait); | ||
348 | |||
349 | spin_lock_irq(&sonycd535_lock); | ||
350 | enable_interrupts(); | ||
351 | prepare_to_wait(&cdu535_irq_wait, &wait, TASK_INTERRUPTIBLE); | ||
352 | spin_unlock_irq(&sonycd535_lock); | ||
353 | schedule(); | ||
354 | finish_wait(&cdu535_irq_wait, &wait); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | /*------------------start of SONY CDU535 very specific ---------------------*/ | ||
359 | |||
360 | /**************************************************************************** | ||
361 | * void select_unit( int unit_no ) | ||
362 | * | ||
363 | * Select the specified unit (0-3) so that subsequent commands reference it | ||
364 | ****************************************************************************/ | ||
365 | static void | ||
366 | select_unit(int unit_no) | ||
367 | { | ||
368 | unsigned int select_mask = ~(1 << unit_no); | ||
369 | outb(select_mask, select_unit_reg); | ||
370 | } | ||
371 | |||
372 | /*************************************************************************** | ||
373 | * int read_result_reg( Byte *data_ptr ) | ||
374 | * | ||
375 | * Read a result byte from the Sony CDU controller, store in location pointed | ||
376 | * to by data_ptr. Return zero on success, TIME_OUT if we did not receive | ||
377 | * data. | ||
378 | ***************************************************************************/ | ||
379 | static int | ||
380 | read_result_reg(Byte *data_ptr) | ||
381 | { | ||
382 | unsigned long snap; | ||
383 | int read_status; | ||
384 | |||
385 | snap = jiffies; | ||
386 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | ||
387 | read_status = inb(read_status_reg); | ||
388 | if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { | ||
389 | #if DEBUG > 1 | ||
390 | printk(CDU535_MESSAGE_NAME | ||
391 | ": read_result_reg(): readStatReg = 0x%x\n", read_status); | ||
392 | #endif | ||
393 | *data_ptr = inb(result_reg); | ||
394 | return 0; | ||
395 | } else { | ||
396 | sony_sleep(); | ||
397 | } | ||
398 | } | ||
399 | printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n"); | ||
400 | return TIME_OUT; | ||
401 | } | ||
402 | |||
403 | /**************************************************************************** | ||
404 | * int read_exec_status( Byte status[2] ) | ||
405 | * | ||
406 | * Read the execution status of the last command and put into status. | ||
407 | * Handles reading second status word if available. Returns 0 on success, | ||
408 | * TIME_OUT on failure. | ||
409 | ****************************************************************************/ | ||
410 | static int | ||
411 | read_exec_status(Byte status[2]) | ||
412 | { | ||
413 | status[1] = 0; | ||
414 | if (read_result_reg(&(status[0])) != 0) | ||
415 | return TIME_OUT; | ||
416 | if ((status[0] & 0x80) != 0) { /* byte two follows */ | ||
417 | if (read_result_reg(&(status[1])) != 0) | ||
418 | return TIME_OUT; | ||
419 | } | ||
420 | #if DEBUG > 1 | ||
421 | printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n", | ||
422 | status[0], status[1]); | ||
423 | #endif | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | /**************************************************************************** | ||
428 | * int check_drive_status( void ) | ||
429 | * | ||
430 | * Check the current drive status. Using this before executing a command | ||
431 | * takes care of the problem of unsolicited drive status-2 messages. | ||
432 | * Add a check of the audio status if we think the disk is playing. | ||
433 | ****************************************************************************/ | ||
434 | static int | ||
435 | check_drive_status(void) | ||
436 | { | ||
437 | Byte status, e_status[2]; | ||
438 | int CDD, ATN; | ||
439 | Byte cmd; | ||
440 | |||
441 | select_unit(0); | ||
442 | if (sony_audio_status == CDROM_AUDIO_PLAY) { /* check status */ | ||
443 | outb(SONY535_REQUEST_AUDIO_STATUS, command_reg); | ||
444 | if (read_result_reg(&status) == 0) { | ||
445 | switch (status) { | ||
446 | case 0x0: | ||
447 | break; /* play in progress */ | ||
448 | case 0x1: | ||
449 | break; /* paused */ | ||
450 | case 0x3: /* audio play completed */ | ||
451 | case 0x5: /* play not requested */ | ||
452 | sony_audio_status = CDROM_AUDIO_COMPLETED; | ||
453 | read_subcode(); | ||
454 | break; | ||
455 | case 0x4: /* error during play */ | ||
456 | sony_audio_status = CDROM_AUDIO_ERROR; | ||
457 | break; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | /* now check drive status */ | ||
462 | outb(SONY535_REQUEST_DRIVE_STATUS_2, command_reg); | ||
463 | if (read_result_reg(&status) != 0) | ||
464 | return TIME_OUT; | ||
465 | |||
466 | #if DEBUG > 1 | ||
467 | printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status); | ||
468 | #endif | ||
469 | |||
470 | if (status == 0) | ||
471 | return 0; | ||
472 | |||
473 | ATN = status & 0xf; | ||
474 | CDD = (status >> 4) & 0xf; | ||
475 | |||
476 | switch (ATN) { | ||
477 | case 0x0: | ||
478 | break; /* go on to CDD stuff */ | ||
479 | case SONY535_ATN_BUSY: | ||
480 | if (initialized) | ||
481 | printk(CDU535_MESSAGE_NAME " error: drive busy\n"); | ||
482 | return CD_BUSY; | ||
483 | case SONY535_ATN_EJECT_IN_PROGRESS: | ||
484 | printk(CDU535_MESSAGE_NAME " error: eject in progress\n"); | ||
485 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
486 | return CD_BUSY; | ||
487 | case SONY535_ATN_RESET_OCCURRED: | ||
488 | case SONY535_ATN_DISC_CHANGED: | ||
489 | case SONY535_ATN_RESET_AND_DISC_CHANGED: | ||
490 | #if DEBUG > 0 | ||
491 | printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n"); | ||
492 | #endif | ||
493 | sony_disc_changed = 1; | ||
494 | sony_toc_read = 0; | ||
495 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
496 | sony_first_block = -1; | ||
497 | sony_last_block = -1; | ||
498 | if (initialized) { | ||
499 | cmd = SONY535_SPIN_UP; | ||
500 | do_sony_cmd(&cmd, 1, e_status, NULL, 0, 0); | ||
501 | sony_get_toc(); | ||
502 | } | ||
503 | return 0; | ||
504 | default: | ||
505 | printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN); | ||
506 | return CD_BUSY; | ||
507 | } | ||
508 | switch (CDD) { /* the 531 docs are not helpful in decoding this */ | ||
509 | case 0x0: /* just use the values from the DOS driver */ | ||
510 | case 0x2: | ||
511 | case 0xa: | ||
512 | break; /* no error */ | ||
513 | case 0xc: | ||
514 | printk(CDU535_MESSAGE_NAME | ||
515 | ": check_drive_status(): CDD = 0xc! Not properly handled!\n"); | ||
516 | return CD_BUSY; /* ? */ | ||
517 | default: | ||
518 | return CD_BUSY; | ||
519 | } | ||
520 | return 0; | ||
521 | } /* check_drive_status() */ | ||
522 | |||
523 | /***************************************************************************** | ||
524 | * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2], | ||
525 | * Byte *response, int n_response, int ignore_status_bit7 ) | ||
526 | * | ||
527 | * Generic routine for executing commands. The command and its parameters | ||
528 | * should be placed in the cmd[] array, number of bytes in the command is | ||
529 | * stored in nCmd. The response from the command will be stored in the | ||
530 | * response array. The number of bytes you expect back (excluding status) | ||
531 | * should be passed in n_response. Finally, some | ||
532 | * commands set bit 7 of the return status even when there is no second | ||
533 | * status byte, on these commands set ignoreStatusBit7 TRUE. | ||
534 | * If the command was sent and data received back, then we return 0, | ||
535 | * else we return TIME_OUT. You still have to check the status yourself. | ||
536 | * You should call check_drive_status() before calling this routine | ||
537 | * so that you do not lose notifications of disk changes, etc. | ||
538 | ****************************************************************************/ | ||
539 | static int | ||
540 | do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2], | ||
541 | Byte * response, int n_response, int ignore_status_bit7) | ||
542 | { | ||
543 | int i; | ||
544 | |||
545 | /* write out the command */ | ||
546 | for (i = 0; i < n_cmd; i++) | ||
547 | outb(cmd[i], command_reg); | ||
548 | |||
549 | /* read back the status */ | ||
550 | if (read_result_reg(status) != 0) | ||
551 | return TIME_OUT; | ||
552 | if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) { | ||
553 | /* get second status byte */ | ||
554 | if (read_result_reg(status + 1) != 0) | ||
555 | return TIME_OUT; | ||
556 | } else { | ||
557 | status[1] = 0; | ||
558 | } | ||
559 | #if DEBUG > 2 | ||
560 | printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n", | ||
561 | *cmd, status[0], status[1]); | ||
562 | #endif | ||
563 | |||
564 | /* do not know about when I should read set of data and when not to */ | ||
565 | if ((status[0] & ((ignore_status_bit7 ? 0x7f : 0xff) & 0x8f)) != 0) | ||
566 | return 0; | ||
567 | |||
568 | /* else, read in rest of data */ | ||
569 | for (i = 0; 0 < n_response; n_response--, i++) | ||
570 | if (read_result_reg(response + i) != 0) | ||
571 | return TIME_OUT; | ||
572 | return 0; | ||
573 | } /* do_sony_cmd() */ | ||
574 | |||
575 | /************************************************************************** | ||
576 | * int set_drive_mode( int mode, Byte status[2] ) | ||
577 | * | ||
578 | * Set the drive mode to the specified value (mode=0 is audio, mode=e0 | ||
579 | * is mode-1 CDROM | ||
580 | **************************************************************************/ | ||
581 | static int | ||
582 | set_drive_mode(int mode, Byte status[2]) | ||
583 | { | ||
584 | Byte cmd_buff[2]; | ||
585 | Byte ret_buff[1]; | ||
586 | |||
587 | cmd_buff[0] = SONY535_SET_DRIVE_MODE; | ||
588 | cmd_buff[1] = mode; | ||
589 | return do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1); | ||
590 | } | ||
591 | |||
592 | /*************************************************************************** | ||
593 | * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2], | ||
594 | * Byte *data_buff, int buff_size ) | ||
595 | * | ||
596 | * Read n_blocks of data from the CDROM starting at position params[0:2], | ||
597 | * number of blocks in stored in params[3:5] -- both these are already | ||
598 | * int bcd format. | ||
599 | * Transfer the data into the buffer pointed at by data_buff. buff_size | ||
600 | * gives the number of bytes available in the buffer. | ||
601 | * The routine returns number of bytes read in if successful, otherwise | ||
602 | * it returns one of the standard error returns. | ||
603 | ***************************************************************************/ | ||
604 | static int | ||
605 | seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2], | ||
606 | Byte **buff, int buf_size) | ||
607 | { | ||
608 | Byte cmd_buff[7]; | ||
609 | int i; | ||
610 | int read_status; | ||
611 | unsigned long snap; | ||
612 | Byte *data_buff; | ||
613 | int sector_count = 0; | ||
614 | |||
615 | if (buf_size < CDU535_BLOCK_SIZE * n_blocks) | ||
616 | return NO_ROOM; | ||
617 | |||
618 | set_drive_mode(SONY535_CDROM_DRIVE_MODE, status); | ||
619 | |||
620 | /* send command to read the data */ | ||
621 | cmd_buff[0] = SONY535_SEEK_AND_READ_N_BLOCKS_1; | ||
622 | for (i = 0; i < 6; i++) | ||
623 | cmd_buff[i + 1] = params[i]; | ||
624 | for (i = 0; i < 7; i++) | ||
625 | outb(cmd_buff[i], command_reg); | ||
626 | |||
627 | /* read back the data one block at a time */ | ||
628 | while (0 < n_blocks--) { | ||
629 | /* wait for data to be ready */ | ||
630 | int data_valid = 0; | ||
631 | snap = jiffies; | ||
632 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | ||
633 | read_status = inb(read_status_reg); | ||
634 | if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { | ||
635 | read_exec_status(status); | ||
636 | return BAD_STATUS; | ||
637 | } | ||
638 | if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) { | ||
639 | /* data is ready, read it */ | ||
640 | data_buff = buff[sector_count++]; | ||
641 | for (i = 0; i < CDU535_BLOCK_SIZE; i++) | ||
642 | *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ | ||
643 | data_valid = 1; | ||
644 | break; /* exit the timeout loop */ | ||
645 | } | ||
646 | sony_sleep(); /* data not ready, sleep a while */ | ||
647 | } | ||
648 | if (!data_valid) | ||
649 | return TIME_OUT; /* if we reach this stage */ | ||
650 | } | ||
651 | |||
652 | /* read all the data, now read the status */ | ||
653 | if ((i = read_exec_status(status)) != 0) | ||
654 | return i; | ||
655 | return CDU535_BLOCK_SIZE * sector_count; | ||
656 | } /* seek_and_read_N_blocks() */ | ||
657 | |||
658 | /**************************************************************************** | ||
659 | * int request_toc_data( Byte status[2], struct s535_sony_toc *toc ) | ||
660 | * | ||
661 | * Read in the table of contents data. Converts all the bcd data | ||
662 | * into integers in the toc structure. | ||
663 | ****************************************************************************/ | ||
664 | static int | ||
665 | request_toc_data(Byte status[2], struct s535_sony_toc *toc) | ||
666 | { | ||
667 | int to_status; | ||
668 | int i, j, n_tracks, track_no; | ||
669 | int first_track_num, last_track_num; | ||
670 | Byte cmd_no = 0xb2; | ||
671 | Byte track_address_buffer[5]; | ||
672 | |||
673 | /* read the fixed portion of the table of contents */ | ||
674 | if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0) | ||
675 | return to_status; | ||
676 | |||
677 | /* convert the data into integers so we can use them */ | ||
678 | first_track_num = bcd_to_int(toc->first_track_num); | ||
679 | last_track_num = bcd_to_int(toc->last_track_num); | ||
680 | n_tracks = last_track_num - first_track_num + 1; | ||
681 | |||
682 | /* read each of the track address descriptors */ | ||
683 | for (i = 0; i < n_tracks; i++) { | ||
684 | /* read the descriptor into a temporary buffer */ | ||
685 | for (j = 0; j < 5; j++) { | ||
686 | if (read_result_reg(track_address_buffer + j) != 0) | ||
687 | return TIME_OUT; | ||
688 | if (j == 1) /* need to convert from bcd */ | ||
689 | track_no = bcd_to_int(track_address_buffer[j]); | ||
690 | } | ||
691 | /* copy the descriptor to proper location - sonycd.c just fills */ | ||
692 | memcpy(toc->tracks + i, track_address_buffer, 5); | ||
693 | } | ||
694 | return 0; | ||
695 | } /* request_toc_data() */ | ||
696 | |||
697 | /*************************************************************************** | ||
698 | * int spin_up_drive( Byte status[2] ) | ||
699 | * | ||
700 | * Spin up the drive (unless it is already spinning). | ||
701 | ***************************************************************************/ | ||
702 | static int | ||
703 | spin_up_drive(Byte status[2]) | ||
704 | { | ||
705 | Byte cmd; | ||
706 | |||
707 | /* first see if the drive is already spinning */ | ||
708 | cmd = SONY535_REQUEST_DRIVE_STATUS_1; | ||
709 | if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0) | ||
710 | return TIME_OUT; | ||
711 | if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0) | ||
712 | return 0; /* it's already spinning */ | ||
713 | |||
714 | /* otherwise, give the spin-up command */ | ||
715 | cmd = SONY535_SPIN_UP; | ||
716 | return do_sony_cmd(&cmd, 1, status, NULL, 0, 0); | ||
717 | } | ||
718 | |||
719 | /*--------------------end of SONY CDU535 very specific ---------------------*/ | ||
720 | |||
721 | /* Convert from an integer 0-99 to BCD */ | ||
722 | static inline unsigned int | ||
723 | int_to_bcd(unsigned int val) | ||
724 | { | ||
725 | int retval; | ||
726 | |||
727 | retval = (val / 10) << 4; | ||
728 | retval = retval | val % 10; | ||
729 | return retval; | ||
730 | } | ||
731 | |||
732 | |||
733 | /* Convert from BCD to an integer from 0-99 */ | ||
734 | static unsigned int | ||
735 | bcd_to_int(unsigned int bcd) | ||
736 | { | ||
737 | return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); | ||
738 | } | ||
739 | |||
740 | |||
741 | /* | ||
742 | * Convert a logical sector value (like the OS would want to use for | ||
743 | * a block device) to an MSF format. | ||
744 | */ | ||
745 | static void | ||
746 | log_to_msf(unsigned int log, Byte *msf) | ||
747 | { | ||
748 | log = log + LOG_START_OFFSET; | ||
749 | msf[0] = int_to_bcd(log / 4500); | ||
750 | log = log % 4500; | ||
751 | msf[1] = int_to_bcd(log / 75); | ||
752 | msf[2] = int_to_bcd(log % 75); | ||
753 | } | ||
754 | |||
755 | |||
756 | /* | ||
757 | * Convert an MSF format to a logical sector. | ||
758 | */ | ||
759 | static unsigned int | ||
760 | msf_to_log(Byte *msf) | ||
761 | { | ||
762 | unsigned int log; | ||
763 | |||
764 | |||
765 | log = bcd_to_int(msf[2]); | ||
766 | log += bcd_to_int(msf[1]) * 75; | ||
767 | log += bcd_to_int(msf[0]) * 4500; | ||
768 | log = log - LOG_START_OFFSET; | ||
769 | |||
770 | return log; | ||
771 | } | ||
772 | |||
773 | |||
774 | /* | ||
775 | * Take in integer size value and put it into a buffer like | ||
776 | * the drive would want to see a number-of-sector value. | ||
777 | */ | ||
778 | static void | ||
779 | size_to_buf(unsigned int size, Byte *buf) | ||
780 | { | ||
781 | buf[0] = size / 65536; | ||
782 | size = size % 65536; | ||
783 | buf[1] = size / 256; | ||
784 | buf[2] = size % 256; | ||
785 | } | ||
786 | |||
787 | |||
788 | /* | ||
789 | * The OS calls this to perform a read or write operation to the drive. | ||
790 | * Write obviously fail. Reads to a read ahead of sony_buffer_size | ||
791 | * bytes to help speed operations. This especially helps since the OS | ||
792 | * may use 1024 byte blocks and the drive uses 2048 byte blocks. Since most | ||
793 | * data access on a CD is done sequentially, this saves a lot of operations. | ||
794 | */ | ||
795 | static void | ||
796 | do_cdu535_request(request_queue_t * q) | ||
797 | { | ||
798 | struct request *req; | ||
799 | unsigned int read_size; | ||
800 | int block; | ||
801 | int nsect; | ||
802 | int copyoff; | ||
803 | int spin_up_retry; | ||
804 | Byte params[10]; | ||
805 | Byte status[2]; | ||
806 | Byte cmd[2]; | ||
807 | |||
808 | while (1) { | ||
809 | req = elv_next_request(q); | ||
810 | if (!req) | ||
811 | return; | ||
812 | |||
813 | block = req->sector; | ||
814 | nsect = req->nr_sectors; | ||
815 | if (!blk_fs_request(req)) { | ||
816 | end_request(req, 0); | ||
817 | continue; | ||
818 | } | ||
819 | if (rq_data_dir(req) == WRITE) { | ||
820 | end_request(req, 0); | ||
821 | continue; | ||
822 | } | ||
823 | /* | ||
824 | * If the block address is invalid or the request goes beyond | ||
825 | * the end of the media, return an error. | ||
826 | */ | ||
827 | if (sony_toc->lead_out_start_lba <= (block/4)) { | ||
828 | end_request(req, 0); | ||
829 | return; | ||
830 | } | ||
831 | if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { | ||
832 | end_request(req, 0); | ||
833 | return; | ||
834 | } | ||
835 | while (0 < nsect) { | ||
836 | /* | ||
837 | * If the requested sector is not currently in | ||
838 | * the read-ahead buffer, it must be read in. | ||
839 | */ | ||
840 | if ((block < sony_first_block) || (sony_last_block < block)) { | ||
841 | sony_first_block = (block / 4) * 4; | ||
842 | log_to_msf(block / 4, params); | ||
843 | |||
844 | /* | ||
845 | * If the full read-ahead would go beyond the end of the media, trim | ||
846 | * it back to read just till the end of the media. | ||
847 | */ | ||
848 | if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { | ||
849 | sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; | ||
850 | read_size = sony_toc->lead_out_start_lba - (block / 4); | ||
851 | } else { | ||
852 | sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; | ||
853 | read_size = sony_buffer_sectors; | ||
854 | } | ||
855 | size_to_buf(read_size, ¶ms[3]); | ||
856 | |||
857 | /* | ||
858 | * Read the data. If the drive was not spinning, | ||
859 | * spin it up and try some more. | ||
860 | */ | ||
861 | for (spin_up_retry=0 ;; ++spin_up_retry) { | ||
862 | /* This loop has been modified to support the Sony | ||
863 | * CDU-510/515 series, thanks to Claudio Porfiri | ||
864 | * <C.Porfiri@nisms.tei.ericsson.se>. | ||
865 | */ | ||
866 | /* | ||
867 | * This part is to deal with very slow hardware. We | ||
868 | * try at most MAX_SPINUP_RETRY times to read the same | ||
869 | * block. A check for seek_and_read_N_blocks' result is | ||
870 | * performed; if the result is wrong, the CDROM's engine | ||
871 | * is restarted and the operation is tried again. | ||
872 | */ | ||
873 | /* | ||
874 | * 1995-06-01: The system got problems when downloading | ||
875 | * from Slackware CDROM, the problem seems to be: | ||
876 | * seek_and_read_N_blocks returns BAD_STATUS and we | ||
877 | * should wait for a while before retrying, so a new | ||
878 | * part was added to discriminate the return value from | ||
879 | * seek_and_read_N_blocks for the various cases. | ||
880 | */ | ||
881 | int readStatus = seek_and_read_N_blocks(params, read_size, | ||
882 | status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); | ||
883 | if (0 <= readStatus) /* Good data; common case, placed first */ | ||
884 | break; | ||
885 | if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { | ||
886 | /* give up */ | ||
887 | if (readStatus == NO_ROOM) | ||
888 | printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); | ||
889 | else | ||
890 | printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", | ||
891 | status[0]); | ||
892 | sony_first_block = -1; | ||
893 | sony_last_block = -1; | ||
894 | end_request(req, 0); | ||
895 | return; | ||
896 | } | ||
897 | if (readStatus == BAD_STATUS) { | ||
898 | /* Sleep for a while, then retry */ | ||
899 | set_current_state(TASK_INTERRUPTIBLE); | ||
900 | spin_unlock_irq(&sonycd535_lock); | ||
901 | schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); | ||
902 | spin_lock_irq(&sonycd535_lock); | ||
903 | } | ||
904 | #if DEBUG > 0 | ||
905 | printk(CDU535_MESSAGE_NAME | ||
906 | " debug: calling spin up when reading data!\n"); | ||
907 | #endif | ||
908 | cmd[0] = SONY535_SPIN_UP; | ||
909 | do_sony_cmd(cmd, 1, status, NULL, 0, 0); | ||
910 | } | ||
911 | } | ||
912 | /* | ||
913 | * The data is in memory now, copy it to the buffer and advance to the | ||
914 | * next block to read. | ||
915 | */ | ||
916 | copyoff = block - sony_first_block; | ||
917 | memcpy(req->buffer, | ||
918 | sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); | ||
919 | |||
920 | block += 1; | ||
921 | nsect -= 1; | ||
922 | req->buffer += 512; | ||
923 | } | ||
924 | |||
925 | end_request(req, 1); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * Read the table of contents from the drive and set sony_toc_read if | ||
931 | * successful. | ||
932 | */ | ||
933 | static void | ||
934 | sony_get_toc(void) | ||
935 | { | ||
936 | Byte status[2]; | ||
937 | if (!sony_toc_read) { | ||
938 | /* do not call check_drive_status() from here since it can call this routine */ | ||
939 | if (request_toc_data(status, sony_toc) < 0) | ||
940 | return; | ||
941 | sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf); | ||
942 | sony_toc_read = 1; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | |||
947 | /* | ||
948 | * Search for a specific track in the table of contents. track is | ||
949 | * passed in bcd format | ||
950 | */ | ||
951 | static int | ||
952 | find_track(int track) | ||
953 | { | ||
954 | int i; | ||
955 | int num_tracks; | ||
956 | |||
957 | |||
958 | num_tracks = bcd_to_int(sony_toc->last_track_num) - | ||
959 | bcd_to_int(sony_toc->first_track_num) + 1; | ||
960 | for (i = 0; i < num_tracks; i++) { | ||
961 | if (sony_toc->tracks[i].track == track) { | ||
962 | return i; | ||
963 | } | ||
964 | } | ||
965 | |||
966 | return -1; | ||
967 | } | ||
968 | |||
969 | /* | ||
970 | * Read the subcode and put it int last_sony_subcode for future use. | ||
971 | */ | ||
972 | static int | ||
973 | read_subcode(void) | ||
974 | { | ||
975 | Byte cmd = SONY535_REQUEST_SUB_Q_DATA; | ||
976 | Byte status[2]; | ||
977 | int dsc_status; | ||
978 | |||
979 | if (check_drive_status() != 0) | ||
980 | return -EIO; | ||
981 | |||
982 | if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode, | ||
983 | sizeof(struct s535_sony_subcode), 1)) != 0) { | ||
984 | printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n", | ||
985 | status[0], dsc_status); | ||
986 | return -EIO; | ||
987 | } | ||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | |||
992 | /* | ||
993 | * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If | ||
994 | * the drive is playing, the subchannel needs to be read (since it would be | ||
995 | * changing). If the drive is paused or completed, the subcode information has | ||
996 | * already been stored, just use that. The ioctl call wants things in decimal | ||
997 | * (not BCD), so all the conversions are done. | ||
998 | */ | ||
999 | static int | ||
1000 | sony_get_subchnl_info(void __user *arg) | ||
1001 | { | ||
1002 | struct cdrom_subchnl schi; | ||
1003 | |||
1004 | /* Get attention stuff */ | ||
1005 | if (check_drive_status() != 0) | ||
1006 | return -EIO; | ||
1007 | |||
1008 | sony_get_toc(); | ||
1009 | if (!sony_toc_read) { | ||
1010 | return -EIO; | ||
1011 | } | ||
1012 | if (copy_from_user(&schi, arg, sizeof schi)) | ||
1013 | return -EFAULT; | ||
1014 | |||
1015 | switch (sony_audio_status) { | ||
1016 | case CDROM_AUDIO_PLAY: | ||
1017 | if (read_subcode() < 0) { | ||
1018 | return -EIO; | ||
1019 | } | ||
1020 | break; | ||
1021 | |||
1022 | case CDROM_AUDIO_PAUSED: | ||
1023 | case CDROM_AUDIO_COMPLETED: | ||
1024 | break; | ||
1025 | |||
1026 | case CDROM_AUDIO_NO_STATUS: | ||
1027 | schi.cdsc_audiostatus = sony_audio_status; | ||
1028 | if (copy_to_user(arg, &schi, sizeof schi)) | ||
1029 | return -EFAULT; | ||
1030 | return 0; | ||
1031 | break; | ||
1032 | |||
1033 | case CDROM_AUDIO_INVALID: | ||
1034 | case CDROM_AUDIO_ERROR: | ||
1035 | default: | ||
1036 | return -EIO; | ||
1037 | } | ||
1038 | |||
1039 | schi.cdsc_audiostatus = sony_audio_status; | ||
1040 | schi.cdsc_adr = last_sony_subcode->address; | ||
1041 | schi.cdsc_ctrl = last_sony_subcode->control; | ||
1042 | schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num); | ||
1043 | schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num); | ||
1044 | if (schi.cdsc_format == CDROM_MSF) { | ||
1045 | schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]); | ||
1046 | schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]); | ||
1047 | schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]); | ||
1048 | |||
1049 | schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]); | ||
1050 | schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]); | ||
1051 | schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]); | ||
1052 | } else if (schi.cdsc_format == CDROM_LBA) { | ||
1053 | schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); | ||
1054 | schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); | ||
1055 | } | ||
1056 | return copy_to_user(arg, &schi, sizeof schi) ? -EFAULT : 0; | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | /* | ||
1061 | * The big ugly ioctl handler. | ||
1062 | */ | ||
1063 | static int | ||
1064 | cdu_ioctl(struct inode *inode, | ||
1065 | struct file *file, | ||
1066 | unsigned int cmd, | ||
1067 | unsigned long arg) | ||
1068 | { | ||
1069 | Byte status[2]; | ||
1070 | Byte cmd_buff[10], params[10]; | ||
1071 | int i; | ||
1072 | int dsc_status; | ||
1073 | void __user *argp = (void __user *)arg; | ||
1074 | |||
1075 | if (check_drive_status() != 0) | ||
1076 | return -EIO; | ||
1077 | |||
1078 | switch (cmd) { | ||
1079 | case CDROMSTART: /* Spin up the drive */ | ||
1080 | if (spin_up_drive(status) < 0) { | ||
1081 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n", | ||
1082 | status[0]); | ||
1083 | return -EIO; | ||
1084 | } | ||
1085 | return 0; | ||
1086 | break; | ||
1087 | |||
1088 | case CDROMSTOP: /* Spin down the drive */ | ||
1089 | cmd_buff[0] = SONY535_HOLD; | ||
1090 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1091 | |||
1092 | /* | ||
1093 | * Spin the drive down, ignoring the error if the disk was | ||
1094 | * already not spinning. | ||
1095 | */ | ||
1096 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
1097 | cmd_buff[0] = SONY535_SPIN_DOWN; | ||
1098 | dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1099 | if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) || | ||
1100 | ((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) { | ||
1101 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n", | ||
1102 | status[0]); | ||
1103 | return -EIO; | ||
1104 | } | ||
1105 | return 0; | ||
1106 | break; | ||
1107 | |||
1108 | case CDROMPAUSE: /* Pause the drive */ | ||
1109 | cmd_buff[0] = SONY535_HOLD; /* CDU-31 driver uses AUDIO_STOP, not pause */ | ||
1110 | if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { | ||
1111 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n", | ||
1112 | status[0]); | ||
1113 | return -EIO; | ||
1114 | } | ||
1115 | /* Get the current position and save it for resuming */ | ||
1116 | if (read_subcode() < 0) { | ||
1117 | return -EIO; | ||
1118 | } | ||
1119 | cur_pos_msf[0] = last_sony_subcode->abs_msf[0]; | ||
1120 | cur_pos_msf[1] = last_sony_subcode->abs_msf[1]; | ||
1121 | cur_pos_msf[2] = last_sony_subcode->abs_msf[2]; | ||
1122 | sony_audio_status = CDROM_AUDIO_PAUSED; | ||
1123 | return 0; | ||
1124 | break; | ||
1125 | |||
1126 | case CDROMRESUME: /* Start the drive after being paused */ | ||
1127 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | ||
1128 | |||
1129 | if (sony_audio_status != CDROM_AUDIO_PAUSED) { | ||
1130 | return -EINVAL; | ||
1131 | } | ||
1132 | spin_up_drive(status); | ||
1133 | |||
1134 | /* Start the drive at the saved position. */ | ||
1135 | cmd_buff[0] = SONY535_PLAY_AUDIO; | ||
1136 | cmd_buff[1] = 0; /* play back starting at this address */ | ||
1137 | cmd_buff[2] = cur_pos_msf[0]; | ||
1138 | cmd_buff[3] = cur_pos_msf[1]; | ||
1139 | cmd_buff[4] = cur_pos_msf[2]; | ||
1140 | cmd_buff[5] = SONY535_PLAY_AUDIO; | ||
1141 | cmd_buff[6] = 2; /* set ending address */ | ||
1142 | cmd_buff[7] = final_pos_msf[0]; | ||
1143 | cmd_buff[8] = final_pos_msf[1]; | ||
1144 | cmd_buff[9] = final_pos_msf[2]; | ||
1145 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | ||
1146 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | ||
1147 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n", | ||
1148 | status[0]); | ||
1149 | return -EIO; | ||
1150 | } | ||
1151 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
1152 | return 0; | ||
1153 | break; | ||
1154 | |||
1155 | case CDROMPLAYMSF: /* Play starting at the given MSF address. */ | ||
1156 | if (copy_from_user(params, argp, 6)) | ||
1157 | return -EFAULT; | ||
1158 | spin_up_drive(status); | ||
1159 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | ||
1160 | |||
1161 | /* The parameters are given in int, must be converted */ | ||
1162 | for (i = 0; i < 3; i++) { | ||
1163 | cmd_buff[2 + i] = int_to_bcd(params[i]); | ||
1164 | cmd_buff[7 + i] = int_to_bcd(params[i + 3]); | ||
1165 | } | ||
1166 | cmd_buff[0] = SONY535_PLAY_AUDIO; | ||
1167 | cmd_buff[1] = 0; /* play back starting at this address */ | ||
1168 | /* cmd_buff[2-4] are filled in for loop above */ | ||
1169 | cmd_buff[5] = SONY535_PLAY_AUDIO; | ||
1170 | cmd_buff[6] = 2; /* set ending address */ | ||
1171 | /* cmd_buff[7-9] are filled in for loop above */ | ||
1172 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | ||
1173 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | ||
1174 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n", | ||
1175 | status[0]); | ||
1176 | return -EIO; | ||
1177 | } | ||
1178 | /* Save the final position for pauses and resumes */ | ||
1179 | final_pos_msf[0] = cmd_buff[7]; | ||
1180 | final_pos_msf[1] = cmd_buff[8]; | ||
1181 | final_pos_msf[2] = cmd_buff[9]; | ||
1182 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
1183 | return 0; | ||
1184 | break; | ||
1185 | |||
1186 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
1187 | { | ||
1188 | struct cdrom_tochdr __user *hdr = argp; | ||
1189 | struct cdrom_tochdr loc_hdr; | ||
1190 | |||
1191 | sony_get_toc(); | ||
1192 | if (!sony_toc_read) | ||
1193 | return -EIO; | ||
1194 | loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); | ||
1195 | loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); | ||
1196 | if (copy_to_user(hdr, &loc_hdr, sizeof *hdr)) | ||
1197 | return -EFAULT; | ||
1198 | } | ||
1199 | return 0; | ||
1200 | break; | ||
1201 | |||
1202 | case CDROMREADTOCENTRY: /* Read a given table of contents entry */ | ||
1203 | { | ||
1204 | struct cdrom_tocentry __user *entry = argp; | ||
1205 | struct cdrom_tocentry loc_entry; | ||
1206 | int track_idx; | ||
1207 | Byte *msf_val = NULL; | ||
1208 | |||
1209 | sony_get_toc(); | ||
1210 | if (!sony_toc_read) { | ||
1211 | return -EIO; | ||
1212 | } | ||
1213 | |||
1214 | if (copy_from_user(&loc_entry, entry, sizeof loc_entry)) | ||
1215 | return -EFAULT; | ||
1216 | |||
1217 | /* Lead out is handled separately since it is special. */ | ||
1218 | if (loc_entry.cdte_track == CDROM_LEADOUT) { | ||
1219 | loc_entry.cdte_adr = 0 /*sony_toc->address2 */ ; | ||
1220 | loc_entry.cdte_ctrl = sony_toc->control2; | ||
1221 | msf_val = sony_toc->lead_out_start_msf; | ||
1222 | } else { | ||
1223 | track_idx = find_track(int_to_bcd(loc_entry.cdte_track)); | ||
1224 | if (track_idx < 0) | ||
1225 | return -EINVAL; | ||
1226 | loc_entry.cdte_adr = 0 /*sony_toc->tracks[track_idx].address */ ; | ||
1227 | loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control; | ||
1228 | msf_val = sony_toc->tracks[track_idx].track_start_msf; | ||
1229 | } | ||
1230 | |||
1231 | /* Logical buffer address or MSF format requested? */ | ||
1232 | if (loc_entry.cdte_format == CDROM_LBA) { | ||
1233 | loc_entry.cdte_addr.lba = msf_to_log(msf_val); | ||
1234 | } else if (loc_entry.cdte_format == CDROM_MSF) { | ||
1235 | loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val); | ||
1236 | loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1)); | ||
1237 | loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2)); | ||
1238 | } | ||
1239 | if (copy_to_user(entry, &loc_entry, sizeof *entry)) | ||
1240 | return -EFAULT; | ||
1241 | } | ||
1242 | return 0; | ||
1243 | break; | ||
1244 | |||
1245 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
1246 | { | ||
1247 | struct cdrom_ti ti; | ||
1248 | int track_idx; | ||
1249 | |||
1250 | sony_get_toc(); | ||
1251 | if (!sony_toc_read) | ||
1252 | return -EIO; | ||
1253 | |||
1254 | if (copy_from_user(&ti, argp, sizeof ti)) | ||
1255 | return -EFAULT; | ||
1256 | if ((ti.cdti_trk0 < sony_toc->first_track_num) | ||
1257 | || (sony_toc->last_track_num < ti.cdti_trk0) | ||
1258 | || (ti.cdti_trk1 < ti.cdti_trk0)) { | ||
1259 | return -EINVAL; | ||
1260 | } | ||
1261 | track_idx = find_track(int_to_bcd(ti.cdti_trk0)); | ||
1262 | if (track_idx < 0) | ||
1263 | return -EINVAL; | ||
1264 | params[1] = sony_toc->tracks[track_idx].track_start_msf[0]; | ||
1265 | params[2] = sony_toc->tracks[track_idx].track_start_msf[1]; | ||
1266 | params[3] = sony_toc->tracks[track_idx].track_start_msf[2]; | ||
1267 | /* | ||
1268 | * If we want to stop after the last track, use the lead-out | ||
1269 | * MSF to do that. | ||
1270 | */ | ||
1271 | if (bcd_to_int(sony_toc->last_track_num) <= ti.cdti_trk1) { | ||
1272 | log_to_msf(msf_to_log(sony_toc->lead_out_start_msf) - 1, | ||
1273 | &(params[4])); | ||
1274 | } else { | ||
1275 | track_idx = find_track(int_to_bcd(ti.cdti_trk1 + 1)); | ||
1276 | if (track_idx < 0) | ||
1277 | return -EINVAL; | ||
1278 | log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf) - 1, | ||
1279 | &(params[4])); | ||
1280 | } | ||
1281 | params[0] = 0x03; | ||
1282 | |||
1283 | spin_up_drive(status); | ||
1284 | |||
1285 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | ||
1286 | |||
1287 | /* Start the drive at the saved position. */ | ||
1288 | cmd_buff[0] = SONY535_PLAY_AUDIO; | ||
1289 | cmd_buff[1] = 0; /* play back starting at this address */ | ||
1290 | cmd_buff[2] = params[1]; | ||
1291 | cmd_buff[3] = params[2]; | ||
1292 | cmd_buff[4] = params[3]; | ||
1293 | cmd_buff[5] = SONY535_PLAY_AUDIO; | ||
1294 | cmd_buff[6] = 2; /* set ending address */ | ||
1295 | cmd_buff[7] = params[4]; | ||
1296 | cmd_buff[8] = params[5]; | ||
1297 | cmd_buff[9] = params[6]; | ||
1298 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | ||
1299 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | ||
1300 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n", | ||
1301 | status[0]); | ||
1302 | printk("... Params: %x %x %x %x %x %x %x\n", | ||
1303 | params[0], params[1], params[2], | ||
1304 | params[3], params[4], params[5], params[6]); | ||
1305 | return -EIO; | ||
1306 | } | ||
1307 | /* Save the final position for pauses and resumes */ | ||
1308 | final_pos_msf[0] = params[4]; | ||
1309 | final_pos_msf[1] = params[5]; | ||
1310 | final_pos_msf[2] = params[6]; | ||
1311 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
1316 | return sony_get_subchnl_info(argp); | ||
1317 | |||
1318 | case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ | ||
1319 | { | ||
1320 | struct cdrom_volctrl volctrl; | ||
1321 | |||
1322 | if (copy_from_user(&volctrl, argp, sizeof volctrl)) | ||
1323 | return -EFAULT; | ||
1324 | cmd_buff[0] = SONY535_SET_VOLUME; | ||
1325 | cmd_buff[1] = volctrl.channel0; | ||
1326 | cmd_buff[2] = volctrl.channel1; | ||
1327 | if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) { | ||
1328 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n", | ||
1329 | status[0]); | ||
1330 | return -EIO; | ||
1331 | } | ||
1332 | } | ||
1333 | return 0; | ||
1334 | |||
1335 | case CDROMEJECT: /* Eject the drive */ | ||
1336 | cmd_buff[0] = SONY535_STOP; | ||
1337 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1338 | cmd_buff[0] = SONY535_SPIN_DOWN; | ||
1339 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1340 | |||
1341 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
1342 | cmd_buff[0] = SONY535_EJECT_CADDY; | ||
1343 | if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { | ||
1344 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n", | ||
1345 | status[0]); | ||
1346 | return -EIO; | ||
1347 | } | ||
1348 | return 0; | ||
1349 | break; | ||
1350 | |||
1351 | default: | ||
1352 | return -EINVAL; | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | |||
1357 | /* | ||
1358 | * Open the drive for operations. Spin the drive up and read the table of | ||
1359 | * contents if these have not already been done. | ||
1360 | */ | ||
1361 | static int | ||
1362 | cdu_open(struct inode *inode, | ||
1363 | struct file *filp) | ||
1364 | { | ||
1365 | Byte status[2], cmd_buff[2]; | ||
1366 | |||
1367 | if (sony_inuse) | ||
1368 | return -EBUSY; | ||
1369 | if (check_drive_status() != 0) | ||
1370 | return -EIO; | ||
1371 | sony_inuse = 1; | ||
1372 | |||
1373 | if (spin_up_drive(status) != 0) { | ||
1374 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n", | ||
1375 | status[0]); | ||
1376 | sony_inuse = 0; | ||
1377 | return -EIO; | ||
1378 | } | ||
1379 | sony_get_toc(); | ||
1380 | if (!sony_toc_read) { | ||
1381 | cmd_buff[0] = SONY535_SPIN_DOWN; | ||
1382 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1383 | sony_inuse = 0; | ||
1384 | return -EIO; | ||
1385 | } | ||
1386 | check_disk_change(inode->i_bdev); | ||
1387 | sony_usage++; | ||
1388 | |||
1389 | #ifdef LOCK_DOORS | ||
1390 | /* disable the eject button while mounted */ | ||
1391 | cmd_buff[0] = SONY535_DISABLE_EJECT_BUTTON; | ||
1392 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1393 | #endif | ||
1394 | |||
1395 | return 0; | ||
1396 | } | ||
1397 | |||
1398 | |||
1399 | /* | ||
1400 | * Close the drive. Spin it down if no task is using it. The spin | ||
1401 | * down will fail if playing audio, so audio play is OK. | ||
1402 | */ | ||
1403 | static int | ||
1404 | cdu_release(struct inode *inode, | ||
1405 | struct file *filp) | ||
1406 | { | ||
1407 | Byte status[2], cmd_no; | ||
1408 | |||
1409 | sony_inuse = 0; | ||
1410 | |||
1411 | if (0 < sony_usage) { | ||
1412 | sony_usage--; | ||
1413 | } | ||
1414 | if (sony_usage == 0) { | ||
1415 | check_drive_status(); | ||
1416 | |||
1417 | if (sony_audio_status != CDROM_AUDIO_PLAY) { | ||
1418 | cmd_no = SONY535_SPIN_DOWN; | ||
1419 | do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); | ||
1420 | } | ||
1421 | #ifdef LOCK_DOORS | ||
1422 | /* enable the eject button after umount */ | ||
1423 | cmd_no = SONY535_ENABLE_EJECT_BUTTON; | ||
1424 | do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); | ||
1425 | #endif | ||
1426 | } | ||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | static struct block_device_operations cdu_fops = | ||
1431 | { | ||
1432 | .owner = THIS_MODULE, | ||
1433 | .open = cdu_open, | ||
1434 | .release = cdu_release, | ||
1435 | .ioctl = cdu_ioctl, | ||
1436 | .media_changed = cdu535_check_media_change, | ||
1437 | }; | ||
1438 | |||
1439 | static struct gendisk *cdu_disk; | ||
1440 | |||
1441 | /* | ||
1442 | * Initialize the driver. | ||
1443 | */ | ||
1444 | static int __init sony535_init(void) | ||
1445 | { | ||
1446 | struct s535_sony_drive_config drive_config; | ||
1447 | Byte cmd_buff[3]; | ||
1448 | Byte ret_buff[2]; | ||
1449 | Byte status[2]; | ||
1450 | unsigned long snap; | ||
1451 | int got_result = 0; | ||
1452 | int tmp_irq; | ||
1453 | int i; | ||
1454 | int err; | ||
1455 | |||
1456 | /* Setting the base I/O address to 0 will disable it. */ | ||
1457 | if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0)) | ||
1458 | return 0; | ||
1459 | |||
1460 | /* Set up all the register locations */ | ||
1461 | result_reg = sony535_cd_base_io; | ||
1462 | command_reg = sony535_cd_base_io; | ||
1463 | data_reg = sony535_cd_base_io + 1; | ||
1464 | read_status_reg = sony535_cd_base_io + 2; | ||
1465 | select_unit_reg = sony535_cd_base_io + 3; | ||
1466 | |||
1467 | #ifndef USE_IRQ | ||
1468 | sony535_irq_used = 0; /* polling only until this is ready... */ | ||
1469 | #endif | ||
1470 | /* we need to poll until things get initialized */ | ||
1471 | tmp_irq = sony535_irq_used; | ||
1472 | sony535_irq_used = 0; | ||
1473 | |||
1474 | #if DEBUG > 0 | ||
1475 | printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n", | ||
1476 | sony535_cd_base_io); | ||
1477 | #endif | ||
1478 | /* look for the CD-ROM, follows the procedure in the DOS driver */ | ||
1479 | inb(select_unit_reg); | ||
1480 | /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ | ||
1481 | schedule_timeout_interruptible((HZ+17)*40/18); | ||
1482 | inb(result_reg); | ||
1483 | |||
1484 | outb(0, read_status_reg); /* does a reset? */ | ||
1485 | snap = jiffies; | ||
1486 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | ||
1487 | select_unit(0); | ||
1488 | if (inb(result_reg) != 0xff) { | ||
1489 | got_result = 1; | ||
1490 | break; | ||
1491 | } | ||
1492 | sony_sleep(); | ||
1493 | } | ||
1494 | |||
1495 | if (!got_result || check_drive_status() == TIME_OUT) | ||
1496 | goto Enodev; | ||
1497 | |||
1498 | /* CD-ROM drive responded -- get the drive configuration */ | ||
1499 | cmd_buff[0] = SONY535_INQUIRY; | ||
1500 | if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0) | ||
1501 | goto Enodev; | ||
1502 | |||
1503 | /* was able to get the configuration, | ||
1504 | * set drive mode as rest of init | ||
1505 | */ | ||
1506 | #if DEBUG > 0 | ||
1507 | /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */ | ||
1508 | if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 ) | ||
1509 | printk(CDU535_MESSAGE_NAME | ||
1510 | "Inquiry command returned status = 0x%x\n", status[0]); | ||
1511 | #endif | ||
1512 | /* now ready to use interrupts, if available */ | ||
1513 | sony535_irq_used = tmp_irq; | ||
1514 | |||
1515 | /* A negative sony535_irq_used will attempt an autoirq. */ | ||
1516 | if (sony535_irq_used < 0) { | ||
1517 | unsigned long irq_mask, delay; | ||
1518 | |||
1519 | irq_mask = probe_irq_on(); | ||
1520 | enable_interrupts(); | ||
1521 | outb(0, read_status_reg); /* does a reset? */ | ||
1522 | delay = jiffies + HZ/10; | ||
1523 | while (time_before(jiffies, delay)) ; | ||
1524 | |||
1525 | sony535_irq_used = probe_irq_off(irq_mask); | ||
1526 | disable_interrupts(); | ||
1527 | } | ||
1528 | if (sony535_irq_used > 0) { | ||
1529 | if (request_irq(sony535_irq_used, cdu535_interrupt, | ||
1530 | IRQF_DISABLED, CDU535_HANDLE, NULL)) { | ||
1531 | printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME | ||
1532 | " driver; polling instead.\n", sony535_irq_used); | ||
1533 | sony535_irq_used = 0; | ||
1534 | } | ||
1535 | } | ||
1536 | cmd_buff[0] = SONY535_SET_DRIVE_MODE; | ||
1537 | cmd_buff[1] = 0x0; /* default audio */ | ||
1538 | if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0) | ||
1539 | goto Enodev_irq; | ||
1540 | |||
1541 | /* set the drive mode successful, we are set! */ | ||
1542 | sony_buffer_size = SONY535_BUFFER_SIZE; | ||
1543 | sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE; | ||
1544 | |||
1545 | printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s", | ||
1546 | drive_config.vendor_id, | ||
1547 | drive_config.product_id, | ||
1548 | drive_config.product_rev_level); | ||
1549 | printk(" base address %03X, ", sony535_cd_base_io); | ||
1550 | if (tmp_irq > 0) | ||
1551 | printk("IRQ%d, ", tmp_irq); | ||
1552 | printk("using %d byte buffer\n", sony_buffer_size); | ||
1553 | |||
1554 | if (register_blkdev(MAJOR_NR, CDU535_HANDLE)) { | ||
1555 | err = -EIO; | ||
1556 | goto out1; | ||
1557 | } | ||
1558 | sonycd535_queue = blk_init_queue(do_cdu535_request, &sonycd535_lock); | ||
1559 | if (!sonycd535_queue) { | ||
1560 | err = -ENOMEM; | ||
1561 | goto out1a; | ||
1562 | } | ||
1563 | |||
1564 | blk_queue_hardsect_size(sonycd535_queue, CDU535_BLOCK_SIZE); | ||
1565 | sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL); | ||
1566 | err = -ENOMEM; | ||
1567 | if (!sony_toc) | ||
1568 | goto out2; | ||
1569 | last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL); | ||
1570 | if (!last_sony_subcode) | ||
1571 | goto out3; | ||
1572 | sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL); | ||
1573 | if (!sony_buffer) | ||
1574 | goto out4; | ||
1575 | for (i = 0; i < sony_buffer_sectors; i++) { | ||
1576 | sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL); | ||
1577 | if (!sony_buffer[i]) { | ||
1578 | while (--i>=0) | ||
1579 | kfree(sony_buffer[i]); | ||
1580 | goto out5; | ||
1581 | } | ||
1582 | } | ||
1583 | initialized = 1; | ||
1584 | |||
1585 | cdu_disk = alloc_disk(1); | ||
1586 | if (!cdu_disk) | ||
1587 | goto out6; | ||
1588 | cdu_disk->major = MAJOR_NR; | ||
1589 | cdu_disk->first_minor = 0; | ||
1590 | cdu_disk->fops = &cdu_fops; | ||
1591 | sprintf(cdu_disk->disk_name, "cdu"); | ||
1592 | |||
1593 | if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { | ||
1594 | printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", | ||
1595 | sony535_cd_base_io); | ||
1596 | goto out7; | ||
1597 | } | ||
1598 | cdu_disk->queue = sonycd535_queue; | ||
1599 | add_disk(cdu_disk); | ||
1600 | return 0; | ||
1601 | |||
1602 | out7: | ||
1603 | put_disk(cdu_disk); | ||
1604 | out6: | ||
1605 | for (i = 0; i < sony_buffer_sectors; i++) | ||
1606 | kfree(sony_buffer[i]); | ||
1607 | out5: | ||
1608 | kfree(sony_buffer); | ||
1609 | out4: | ||
1610 | kfree(last_sony_subcode); | ||
1611 | out3: | ||
1612 | kfree(sony_toc); | ||
1613 | out2: | ||
1614 | blk_cleanup_queue(sonycd535_queue); | ||
1615 | out1a: | ||
1616 | unregister_blkdev(MAJOR_NR, CDU535_HANDLE); | ||
1617 | out1: | ||
1618 | if (sony535_irq_used) | ||
1619 | free_irq(sony535_irq_used, NULL); | ||
1620 | return err; | ||
1621 | Enodev_irq: | ||
1622 | if (sony535_irq_used) | ||
1623 | free_irq(sony535_irq_used, NULL); | ||
1624 | Enodev: | ||
1625 | printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); | ||
1626 | return -EIO; | ||
1627 | } | ||
1628 | |||
1629 | #ifndef MODULE | ||
1630 | |||
1631 | /* | ||
1632 | * accept "kernel command line" parameters | ||
1633 | * (added by emoenke@gwdg.de) | ||
1634 | * | ||
1635 | * use: tell LILO: | ||
1636 | * sonycd535=0x320 | ||
1637 | * | ||
1638 | * the address value has to be the existing CDROM port address. | ||
1639 | */ | ||
1640 | static int __init | ||
1641 | sonycd535_setup(char *strings) | ||
1642 | { | ||
1643 | int ints[3]; | ||
1644 | (void)get_options(strings, ARRAY_SIZE(ints), ints); | ||
1645 | /* if IRQ change and default io base desired, | ||
1646 | * then call with io base of 0 | ||
1647 | */ | ||
1648 | if (ints[0] > 0) | ||
1649 | if (ints[1] != 0) | ||
1650 | sony535_cd_base_io = ints[1]; | ||
1651 | if (ints[0] > 1) | ||
1652 | sony535_irq_used = ints[2]; | ||
1653 | if ((strings != NULL) && (*strings != '\0')) | ||
1654 | printk(CDU535_MESSAGE_NAME | ||
1655 | ": Warning: Unknown interface type: %s\n", strings); | ||
1656 | |||
1657 | return 1; | ||
1658 | } | ||
1659 | |||
1660 | __setup("sonycd535=", sonycd535_setup); | ||
1661 | |||
1662 | #endif /* MODULE */ | ||
1663 | |||
1664 | static void __exit | ||
1665 | sony535_exit(void) | ||
1666 | { | ||
1667 | int i; | ||
1668 | |||
1669 | release_region(sony535_cd_base_io, 4); | ||
1670 | for (i = 0; i < sony_buffer_sectors; i++) | ||
1671 | kfree(sony_buffer[i]); | ||
1672 | kfree(sony_buffer); | ||
1673 | kfree(last_sony_subcode); | ||
1674 | kfree(sony_toc); | ||
1675 | del_gendisk(cdu_disk); | ||
1676 | put_disk(cdu_disk); | ||
1677 | blk_cleanup_queue(sonycd535_queue); | ||
1678 | if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) | ||
1679 | printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); | ||
1680 | else | ||
1681 | printk(KERN_INFO CDU535_HANDLE " module released\n"); | ||
1682 | } | ||
1683 | |||
1684 | module_init(sony535_init); | ||
1685 | module_exit(sony535_exit); | ||
1686 | |||
1687 | |||
1688 | MODULE_LICENSE("GPL"); | ||
1689 | MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/sonycd535.h b/drivers/cdrom/sonycd535.h deleted file mode 100644 index 5dea1ef168d6..000000000000 --- a/drivers/cdrom/sonycd535.h +++ /dev/null | |||
@@ -1,183 +0,0 @@ | |||
1 | #ifndef SONYCD535_H | ||
2 | #define SONYCD535_H | ||
3 | |||
4 | /* | ||
5 | * define all the commands recognized by the CDU-531/5 | ||
6 | */ | ||
7 | #define SONY535_REQUEST_DRIVE_STATUS_1 (0x80) | ||
8 | #define SONY535_REQUEST_SENSE (0x82) | ||
9 | #define SONY535_REQUEST_DRIVE_STATUS_2 (0x84) | ||
10 | #define SONY535_REQUEST_ERROR_STATUS (0x86) | ||
11 | #define SONY535_REQUEST_AUDIO_STATUS (0x88) | ||
12 | #define SONY535_INQUIRY (0x8a) | ||
13 | |||
14 | #define SONY535_SET_INACTIVITY_TIME (0x90) | ||
15 | |||
16 | #define SONY535_SEEK_AND_READ_N_BLOCKS_1 (0xa0) | ||
17 | #define SONY535_SEEK_AND_READ_N_BLOCKS_2 (0xa4) | ||
18 | #define SONY535_PLAY_AUDIO (0xa6) | ||
19 | |||
20 | #define SONY535_REQUEST_DISC_CAPACITY (0xb0) | ||
21 | #define SONY535_REQUEST_TOC_DATA (0xb2) | ||
22 | #define SONY535_REQUEST_SUB_Q_DATA (0xb4) | ||
23 | #define SONY535_REQUEST_ISRC (0xb6) | ||
24 | #define SONY535_REQUEST_UPC_EAN (0xb8) | ||
25 | |||
26 | #define SONY535_SET_DRIVE_MODE (0xc0) | ||
27 | #define SONY535_REQUEST_DRIVE_MODE (0xc2) | ||
28 | #define SONY535_SET_RETRY_COUNT (0xc4) | ||
29 | |||
30 | #define SONY535_DIAGNOSTIC_1 (0xc6) | ||
31 | #define SONY535_DIAGNOSTIC_4 (0xcc) | ||
32 | #define SONY535_DIAGNOSTIC_5 (0xce) | ||
33 | |||
34 | #define SONY535_EJECT_CADDY (0xd0) | ||
35 | #define SONY535_DISABLE_EJECT_BUTTON (0xd2) | ||
36 | #define SONY535_ENABLE_EJECT_BUTTON (0xd4) | ||
37 | |||
38 | #define SONY535_HOLD (0xe0) | ||
39 | #define SONY535_AUDIO_PAUSE_ON_OFF (0xe2) | ||
40 | #define SONY535_SET_VOLUME (0xe8) | ||
41 | |||
42 | #define SONY535_STOP (0xf0) | ||
43 | #define SONY535_SPIN_UP (0xf2) | ||
44 | #define SONY535_SPIN_DOWN (0xf4) | ||
45 | |||
46 | #define SONY535_CLEAR_PARAMETERS (0xf6) | ||
47 | #define SONY535_CLEAR_ENDING_ADDRESS (0xf8) | ||
48 | |||
49 | /* | ||
50 | * define some masks | ||
51 | */ | ||
52 | #define SONY535_DATA_NOT_READY_BIT (0x1) | ||
53 | #define SONY535_RESULT_NOT_READY_BIT (0x2) | ||
54 | |||
55 | /* | ||
56 | * drive status 1 | ||
57 | */ | ||
58 | #define SONY535_STATUS1_COMMAND_ERROR (0x1) | ||
59 | #define SONY535_STATUS1_DATA_ERROR (0x2) | ||
60 | #define SONY535_STATUS1_SEEK_ERROR (0x4) | ||
61 | #define SONY535_STATUS1_DISC_TYPE_ERROR (0x8) | ||
62 | #define SONY535_STATUS1_NOT_SPINNING (0x10) | ||
63 | #define SONY535_STATUS1_EJECT_BUTTON_PRESSED (0x20) | ||
64 | #define SONY535_STATUS1_CADDY_NOT_INSERTED (0x40) | ||
65 | #define SONY535_STATUS1_BYTE_TWO_FOLLOWS (0x80) | ||
66 | |||
67 | /* | ||
68 | * drive status 2 | ||
69 | */ | ||
70 | #define SONY535_CDD_LOADING_ERROR (0x7) | ||
71 | #define SONY535_CDD_NO_DISC (0x8) | ||
72 | #define SONY535_CDD_UNLOADING_ERROR (0x9) | ||
73 | #define SONY535_CDD_CADDY_NOT_INSERTED (0xd) | ||
74 | #define SONY535_ATN_RESET_OCCURRED (0x2) | ||
75 | #define SONY535_ATN_DISC_CHANGED (0x4) | ||
76 | #define SONY535_ATN_RESET_AND_DISC_CHANGED (0x6) | ||
77 | #define SONY535_ATN_EJECT_IN_PROGRESS (0xe) | ||
78 | #define SONY535_ATN_BUSY (0xf) | ||
79 | |||
80 | /* | ||
81 | * define some parameters | ||
82 | */ | ||
83 | #define SONY535_AUDIO_DRIVE_MODE (0) | ||
84 | #define SONY535_CDROM_DRIVE_MODE (0xe0) | ||
85 | |||
86 | #define SONY535_PLAY_OP_PLAYBACK (0) | ||
87 | #define SONY535_PLAY_OP_ENTER_HOLD (1) | ||
88 | #define SONY535_PLAY_OP_SET_AUDIO_ENDING_ADDR (2) | ||
89 | #define SONY535_PLAY_OP_SCAN_FORWARD (3) | ||
90 | #define SONY535_PLAY_OP_SCAN_BACKWARD (4) | ||
91 | |||
92 | /* | ||
93 | * convert from msf format to block number | ||
94 | */ | ||
95 | #define SONY_BLOCK_NUMBER(m,s,f) (((m)*60L+(s))*75L+(f)) | ||
96 | #define SONY_BLOCK_NUMBER_MSF(x) (((x)[0]*60L+(x)[1])*75L+(x)[2]) | ||
97 | |||
98 | /* | ||
99 | * error return values from the doSonyCmd() routines | ||
100 | */ | ||
101 | #define TIME_OUT (-1) | ||
102 | #define NO_CDROM (-2) | ||
103 | #define BAD_STATUS (-3) | ||
104 | #define CD_BUSY (-4) | ||
105 | #define NOT_DATA_CD (-5) | ||
106 | #define NO_ROOM (-6) | ||
107 | |||
108 | #define LOG_START_OFFSET 150 /* Offset of first logical sector */ | ||
109 | |||
110 | #define SONY_JIFFIES_TIMEOUT (5*HZ) /* Maximum time | ||
111 | the drive will wait/try for an | ||
112 | operation */ | ||
113 | #define SONY_READY_RETRIES (50000) /* How many times to retry a | ||
114 | spin waiting for a register | ||
115 | to come ready */ | ||
116 | #define SONY535_FAST_POLLS (10000) /* how many times recheck | ||
117 | status waiting for a data | ||
118 | to become ready */ | ||
119 | |||
120 | typedef unsigned char Byte; | ||
121 | |||
122 | /* | ||
123 | * This is the complete status returned from the drive configuration request | ||
124 | * command. | ||
125 | */ | ||
126 | struct s535_sony_drive_config | ||
127 | { | ||
128 | char vendor_id[8]; | ||
129 | char product_id[16]; | ||
130 | char product_rev_level[4]; | ||
131 | }; | ||
132 | |||
133 | /* The following is returned from the request sub-q data command */ | ||
134 | struct s535_sony_subcode | ||
135 | { | ||
136 | unsigned char address :4; | ||
137 | unsigned char control :4; | ||
138 | unsigned char track_num; | ||
139 | unsigned char index_num; | ||
140 | unsigned char rel_msf[3]; | ||
141 | unsigned char abs_msf[3]; | ||
142 | }; | ||
143 | |||
144 | struct s535_sony_disc_capacity | ||
145 | { | ||
146 | Byte mFirstTrack, sFirstTrack, fFirstTrack; | ||
147 | Byte mLeadOut, sLeadOut, fLeadOut; | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * The following is returned from the request TOC (Table Of Contents) command. | ||
152 | * (last_track_num-first_track_num+1) values are valid in tracks. | ||
153 | */ | ||
154 | struct s535_sony_toc | ||
155 | { | ||
156 | unsigned char reserved0 :4; | ||
157 | unsigned char control0 :4; | ||
158 | unsigned char point0; | ||
159 | unsigned char first_track_num; | ||
160 | unsigned char reserved0a; | ||
161 | unsigned char reserved0b; | ||
162 | unsigned char reserved1 :4; | ||
163 | unsigned char control1 :4; | ||
164 | unsigned char point1; | ||
165 | unsigned char last_track_num; | ||
166 | unsigned char dummy1; | ||
167 | unsigned char dummy2; | ||
168 | unsigned char reserved2 :4; | ||
169 | unsigned char control2 :4; | ||
170 | unsigned char point2; | ||
171 | unsigned char lead_out_start_msf[3]; | ||
172 | struct | ||
173 | { | ||
174 | unsigned char reserved :4; | ||
175 | unsigned char control :4; | ||
176 | unsigned char track; | ||
177 | unsigned char track_start_msf[3]; | ||
178 | } tracks[100]; | ||
179 | |||
180 | unsigned int lead_out_start_lba; | ||
181 | }; | ||
182 | |||
183 | #endif /* SONYCD535_H */ | ||
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 1b094509b1d2..90965b4def5c 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -1005,8 +1005,8 @@ static const unsigned short x86_keycodes[256] = | |||
1005 | 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, | 1005 | 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, |
1006 | 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, | 1006 | 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, |
1007 | 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, | 1007 | 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, |
1008 | 103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361, | 1008 | 103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361, |
1009 | 291,108,381,281,290,272,292,305,280, 99,112,257,258,359,113,114, | 1009 | 291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114, |
1010 | 264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116, | 1010 | 264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116, |
1011 | 377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307, | 1011 | 377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307, |
1012 | 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330, | 1012 | 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330, |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index cc9a9d0df979..bbee97ff355f 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/crash_dump.h> | 24 | #include <linux/crash_dump.h> |
25 | #include <linux/backing-dev.h> | 25 | #include <linux/backing-dev.h> |
26 | #include <linux/bootmem.h> | 26 | #include <linux/bootmem.h> |
27 | #include <linux/pipe_fs_i.h> | 27 | #include <linux/splice.h> |
28 | #include <linux/pfn.h> | 28 | #include <linux/pfn.h> |
29 | 29 | ||
30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
@@ -75,6 +75,13 @@ static inline int uncached_access(struct file *file, unsigned long addr) | |||
75 | * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. | 75 | * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. |
76 | */ | 76 | */ |
77 | return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); | 77 | return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); |
78 | #elif defined(CONFIG_MIPS) | ||
79 | { | ||
80 | extern int __uncached_access(struct file *file, | ||
81 | unsigned long addr); | ||
82 | |||
83 | return __uncached_access(file, addr); | ||
84 | } | ||
78 | #else | 85 | #else |
79 | /* | 86 | /* |
80 | * Accessing memory above the top the kernel knows about or through a file pointer | 87 | * Accessing memory above the top the kernel knows about or through a file pointer |
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index 661c12f6dda6..7f4c0a5050a1 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c | |||
@@ -623,7 +623,8 @@ repeat: | |||
623 | cyl = track / disk->head; | 623 | cyl = track / disk->head; |
624 | #ifdef DEBUG | 624 | #ifdef DEBUG |
625 | printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", | 625 | printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", |
626 | req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ", | 626 | req->rq_disk->disk_name, |
627 | req_data_dir(req) == READ ? "read" : "writ", | ||
627 | cyl, head, sec, nsect, req->buffer); | 628 | cyl, head, sec, nsect, req->buffer); |
628 | #endif | 629 | #endif |
629 | if (blk_fs_request(req)) { | 630 | if (blk_fs_request(req)) { |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index be6b93c20f60..ab4b2d9b5327 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -30,6 +30,7 @@ struct evdev { | |||
30 | wait_queue_head_t wait; | 30 | wait_queue_head_t wait; |
31 | struct evdev_client *grab; | 31 | struct evdev_client *grab; |
32 | struct list_head client_list; | 32 | struct list_head client_list; |
33 | struct device dev; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct evdev_client { | 36 | struct evdev_client { |
@@ -94,8 +95,10 @@ static int evdev_flush(struct file *file, fl_owner_t id) | |||
94 | return input_flush_device(&evdev->handle, file); | 95 | return input_flush_device(&evdev->handle, file); |
95 | } | 96 | } |
96 | 97 | ||
97 | static void evdev_free(struct evdev *evdev) | 98 | static void evdev_free(struct device *dev) |
98 | { | 99 | { |
100 | struct evdev *evdev = container_of(dev, struct evdev, dev); | ||
101 | |||
99 | evdev_table[evdev->minor] = NULL; | 102 | evdev_table[evdev->minor] = NULL; |
100 | kfree(evdev); | 103 | kfree(evdev); |
101 | } | 104 | } |
@@ -114,12 +117,10 @@ static int evdev_release(struct inode *inode, struct file *file) | |||
114 | list_del(&client->node); | 117 | list_del(&client->node); |
115 | kfree(client); | 118 | kfree(client); |
116 | 119 | ||
117 | if (!--evdev->open) { | 120 | if (!--evdev->open && evdev->exist) |
118 | if (evdev->exist) | 121 | input_close_device(&evdev->handle); |
119 | input_close_device(&evdev->handle); | 122 | |
120 | else | 123 | put_device(&evdev->dev); |
121 | evdev_free(evdev); | ||
122 | } | ||
123 | 124 | ||
124 | return 0; | 125 | return 0; |
125 | } | 126 | } |
@@ -139,24 +140,32 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
139 | if (!evdev || !evdev->exist) | 140 | if (!evdev || !evdev->exist) |
140 | return -ENODEV; | 141 | return -ENODEV; |
141 | 142 | ||
143 | get_device(&evdev->dev); | ||
144 | |||
142 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); | 145 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); |
143 | if (!client) | 146 | if (!client) { |
144 | return -ENOMEM; | 147 | error = -ENOMEM; |
148 | goto err_put_evdev; | ||
149 | } | ||
145 | 150 | ||
146 | client->evdev = evdev; | 151 | client->evdev = evdev; |
147 | list_add_tail(&client->node, &evdev->client_list); | 152 | list_add_tail(&client->node, &evdev->client_list); |
148 | 153 | ||
149 | if (!evdev->open++ && evdev->exist) { | 154 | if (!evdev->open++ && evdev->exist) { |
150 | error = input_open_device(&evdev->handle); | 155 | error = input_open_device(&evdev->handle); |
151 | if (error) { | 156 | if (error) |
152 | list_del(&client->node); | 157 | goto err_free_client; |
153 | kfree(client); | ||
154 | return error; | ||
155 | } | ||
156 | } | 158 | } |
157 | 159 | ||
158 | file->private_data = client; | 160 | file->private_data = client; |
159 | return 0; | 161 | return 0; |
162 | |||
163 | err_free_client: | ||
164 | list_del(&client->node); | ||
165 | kfree(client); | ||
166 | err_put_evdev: | ||
167 | put_device(&evdev->dev); | ||
168 | return error; | ||
160 | } | 169 | } |
161 | 170 | ||
162 | #ifdef CONFIG_COMPAT | 171 | #ifdef CONFIG_COMPAT |
@@ -625,8 +634,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
625 | const struct input_device_id *id) | 634 | const struct input_device_id *id) |
626 | { | 635 | { |
627 | struct evdev *evdev; | 636 | struct evdev *evdev; |
628 | struct class_device *cdev; | ||
629 | dev_t devt; | ||
630 | int minor; | 637 | int minor; |
631 | int error; | 638 | int error; |
632 | 639 | ||
@@ -649,38 +656,32 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
649 | evdev->handle.name = evdev->name; | 656 | evdev->handle.name = evdev->name; |
650 | evdev->handle.handler = handler; | 657 | evdev->handle.handler = handler; |
651 | evdev->handle.private = evdev; | 658 | evdev->handle.private = evdev; |
652 | sprintf(evdev->name, "event%d", minor); | 659 | snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); |
653 | |||
654 | evdev_table[minor] = evdev; | ||
655 | 660 | ||
656 | devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), | 661 | snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id), |
662 | "event%d", minor); | ||
663 | evdev->dev.class = &input_class; | ||
664 | evdev->dev.parent = &dev->dev; | ||
665 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); | ||
666 | evdev->dev.release = evdev_free; | ||
667 | device_initialize(&evdev->dev); | ||
657 | 668 | ||
658 | cdev = class_device_create(&input_class, &dev->cdev, devt, | 669 | evdev_table[minor] = evdev; |
659 | dev->cdev.dev, evdev->name); | ||
660 | if (IS_ERR(cdev)) { | ||
661 | error = PTR_ERR(cdev); | ||
662 | goto err_free_evdev; | ||
663 | } | ||
664 | 670 | ||
665 | /* temporary symlink to keep userspace happy */ | 671 | error = device_add(&evdev->dev); |
666 | error = sysfs_create_link(&input_class.subsys.kobj, | ||
667 | &cdev->kobj, evdev->name); | ||
668 | if (error) | 672 | if (error) |
669 | goto err_cdev_destroy; | 673 | goto err_free_evdev; |
670 | 674 | ||
671 | error = input_register_handle(&evdev->handle); | 675 | error = input_register_handle(&evdev->handle); |
672 | if (error) | 676 | if (error) |
673 | goto err_remove_link; | 677 | goto err_delete_evdev; |
674 | 678 | ||
675 | return 0; | 679 | return 0; |
676 | 680 | ||
677 | err_remove_link: | 681 | err_delete_evdev: |
678 | sysfs_remove_link(&input_class.subsys.kobj, evdev->name); | 682 | device_del(&evdev->dev); |
679 | err_cdev_destroy: | ||
680 | class_device_destroy(&input_class, devt); | ||
681 | err_free_evdev: | 683 | err_free_evdev: |
682 | kfree(evdev); | 684 | put_device(&evdev->dev); |
683 | evdev_table[minor] = NULL; | ||
684 | return error; | 685 | return error; |
685 | } | 686 | } |
686 | 687 | ||
@@ -690,10 +691,8 @@ static void evdev_disconnect(struct input_handle *handle) | |||
690 | struct evdev_client *client; | 691 | struct evdev_client *client; |
691 | 692 | ||
692 | input_unregister_handle(handle); | 693 | input_unregister_handle(handle); |
694 | device_del(&evdev->dev); | ||
693 | 695 | ||
694 | sysfs_remove_link(&input_class.subsys.kobj, evdev->name); | ||
695 | class_device_destroy(&input_class, | ||
696 | MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); | ||
697 | evdev->exist = 0; | 696 | evdev->exist = 0; |
698 | 697 | ||
699 | if (evdev->open) { | 698 | if (evdev->open) { |
@@ -702,8 +701,9 @@ static void evdev_disconnect(struct input_handle *handle) | |||
702 | list_for_each_entry(client, &evdev->client_list, node) | 701 | list_for_each_entry(client, &evdev->client_list, node) |
703 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 702 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
704 | wake_up_interruptible(&evdev->wait); | 703 | wake_up_interruptible(&evdev->wait); |
705 | } else | 704 | } |
706 | evdev_free(evdev); | 705 | |
706 | put_device(&evdev->dev); | ||
707 | } | 707 | } |
708 | 708 | ||
709 | static const struct input_device_id evdev_ids[] = { | 709 | static const struct input_device_id evdev_ids[] = { |
diff --git a/drivers/input/input.c b/drivers/input/input.c index ccd8abafcb70..75b4d2a83dd9 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -442,7 +442,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han | |||
442 | printk(KERN_ERR | 442 | printk(KERN_ERR |
443 | "input: failed to attach handler %s to device %s, " | 443 | "input: failed to attach handler %s to device %s, " |
444 | "error: %d\n", | 444 | "error: %d\n", |
445 | handler->name, kobject_name(&dev->cdev.kobj), error); | 445 | handler->name, kobject_name(&dev->dev.kobj), error); |
446 | 446 | ||
447 | return error; | 447 | return error; |
448 | } | 448 | } |
@@ -527,7 +527,7 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name, | |||
527 | static int input_devices_seq_show(struct seq_file *seq, void *v) | 527 | static int input_devices_seq_show(struct seq_file *seq, void *v) |
528 | { | 528 | { |
529 | struct input_dev *dev = container_of(v, struct input_dev, node); | 529 | struct input_dev *dev = container_of(v, struct input_dev, node); |
530 | const char *path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); | 530 | const char *path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); |
531 | struct input_handle *handle; | 531 | struct input_handle *handle; |
532 | 532 | ||
533 | seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", | 533 | seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", |
@@ -682,15 +682,17 @@ static inline int input_proc_init(void) { return 0; } | |||
682 | static inline void input_proc_exit(void) { } | 682 | static inline void input_proc_exit(void) { } |
683 | #endif | 683 | #endif |
684 | 684 | ||
685 | #define INPUT_DEV_STRING_ATTR_SHOW(name) \ | 685 | #define INPUT_DEV_STRING_ATTR_SHOW(name) \ |
686 | static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \ | 686 | static ssize_t input_dev_show_##name(struct device *dev, \ |
687 | { \ | 687 | struct device_attribute *attr, \ |
688 | struct input_dev *input_dev = to_input_dev(dev); \ | 688 | char *buf) \ |
689 | \ | 689 | { \ |
690 | return scnprintf(buf, PAGE_SIZE, "%s\n", \ | 690 | struct input_dev *input_dev = to_input_dev(dev); \ |
691 | input_dev->name ? input_dev->name : ""); \ | 691 | \ |
692 | } \ | 692 | return scnprintf(buf, PAGE_SIZE, "%s\n", \ |
693 | static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL); | 693 | input_dev->name ? input_dev->name : ""); \ |
694 | } \ | ||
695 | static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL) | ||
694 | 696 | ||
695 | INPUT_DEV_STRING_ATTR_SHOW(name); | 697 | INPUT_DEV_STRING_ATTR_SHOW(name); |
696 | INPUT_DEV_STRING_ATTR_SHOW(phys); | 698 | INPUT_DEV_STRING_ATTR_SHOW(phys); |
@@ -744,7 +746,9 @@ static int input_print_modalias(char *buf, int size, struct input_dev *id, | |||
744 | return len; | 746 | return len; |
745 | } | 747 | } |
746 | 748 | ||
747 | static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf) | 749 | static ssize_t input_dev_show_modalias(struct device *dev, |
750 | struct device_attribute *attr, | ||
751 | char *buf) | ||
748 | { | 752 | { |
749 | struct input_dev *id = to_input_dev(dev); | 753 | struct input_dev *id = to_input_dev(dev); |
750 | ssize_t len; | 754 | ssize_t len; |
@@ -753,13 +757,13 @@ static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf) | |||
753 | 757 | ||
754 | return min_t(int, len, PAGE_SIZE); | 758 | return min_t(int, len, PAGE_SIZE); |
755 | } | 759 | } |
756 | static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); | 760 | static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); |
757 | 761 | ||
758 | static struct attribute *input_dev_attrs[] = { | 762 | static struct attribute *input_dev_attrs[] = { |
759 | &class_device_attr_name.attr, | 763 | &dev_attr_name.attr, |
760 | &class_device_attr_phys.attr, | 764 | &dev_attr_phys.attr, |
761 | &class_device_attr_uniq.attr, | 765 | &dev_attr_uniq.attr, |
762 | &class_device_attr_modalias.attr, | 766 | &dev_attr_modalias.attr, |
763 | NULL | 767 | NULL |
764 | }; | 768 | }; |
765 | 769 | ||
@@ -767,13 +771,15 @@ static struct attribute_group input_dev_attr_group = { | |||
767 | .attrs = input_dev_attrs, | 771 | .attrs = input_dev_attrs, |
768 | }; | 772 | }; |
769 | 773 | ||
770 | #define INPUT_DEV_ID_ATTR(name) \ | 774 | #define INPUT_DEV_ID_ATTR(name) \ |
771 | static ssize_t input_dev_show_id_##name(struct class_device *dev, char *buf) \ | 775 | static ssize_t input_dev_show_id_##name(struct device *dev, \ |
772 | { \ | 776 | struct device_attribute *attr, \ |
773 | struct input_dev *input_dev = to_input_dev(dev); \ | 777 | char *buf) \ |
774 | return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name); \ | 778 | { \ |
775 | } \ | 779 | struct input_dev *input_dev = to_input_dev(dev); \ |
776 | static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL); | 780 | return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name); \ |
781 | } \ | ||
782 | static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL) | ||
777 | 783 | ||
778 | INPUT_DEV_ID_ATTR(bustype); | 784 | INPUT_DEV_ID_ATTR(bustype); |
779 | INPUT_DEV_ID_ATTR(vendor); | 785 | INPUT_DEV_ID_ATTR(vendor); |
@@ -781,10 +787,10 @@ INPUT_DEV_ID_ATTR(product); | |||
781 | INPUT_DEV_ID_ATTR(version); | 787 | INPUT_DEV_ID_ATTR(version); |
782 | 788 | ||
783 | static struct attribute *input_dev_id_attrs[] = { | 789 | static struct attribute *input_dev_id_attrs[] = { |
784 | &class_device_attr_bustype.attr, | 790 | &dev_attr_bustype.attr, |
785 | &class_device_attr_vendor.attr, | 791 | &dev_attr_vendor.attr, |
786 | &class_device_attr_product.attr, | 792 | &dev_attr_product.attr, |
787 | &class_device_attr_version.attr, | 793 | &dev_attr_version.attr, |
788 | NULL | 794 | NULL |
789 | }; | 795 | }; |
790 | 796 | ||
@@ -813,15 +819,17 @@ static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, | |||
813 | return len; | 819 | return len; |
814 | } | 820 | } |
815 | 821 | ||
816 | #define INPUT_DEV_CAP_ATTR(ev, bm) \ | 822 | #define INPUT_DEV_CAP_ATTR(ev, bm) \ |
817 | static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ | 823 | static ssize_t input_dev_show_cap_##bm(struct device *dev, \ |
818 | { \ | 824 | struct device_attribute *attr, \ |
819 | struct input_dev *input_dev = to_input_dev(dev); \ | 825 | char *buf) \ |
820 | int len = input_print_bitmap(buf, PAGE_SIZE, \ | 826 | { \ |
821 | input_dev->bm##bit, ev##_MAX, 1); \ | 827 | struct input_dev *input_dev = to_input_dev(dev); \ |
822 | return min_t(int, len, PAGE_SIZE); \ | 828 | int len = input_print_bitmap(buf, PAGE_SIZE, \ |
823 | } \ | 829 | input_dev->bm##bit, ev##_MAX, 1); \ |
824 | static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); | 830 | return min_t(int, len, PAGE_SIZE); \ |
831 | } \ | ||
832 | static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL) | ||
825 | 833 | ||
826 | INPUT_DEV_CAP_ATTR(EV, ev); | 834 | INPUT_DEV_CAP_ATTR(EV, ev); |
827 | INPUT_DEV_CAP_ATTR(KEY, key); | 835 | INPUT_DEV_CAP_ATTR(KEY, key); |
@@ -834,15 +842,15 @@ INPUT_DEV_CAP_ATTR(FF, ff); | |||
834 | INPUT_DEV_CAP_ATTR(SW, sw); | 842 | INPUT_DEV_CAP_ATTR(SW, sw); |
835 | 843 | ||
836 | static struct attribute *input_dev_caps_attrs[] = { | 844 | static struct attribute *input_dev_caps_attrs[] = { |
837 | &class_device_attr_ev.attr, | 845 | &dev_attr_ev.attr, |
838 | &class_device_attr_key.attr, | 846 | &dev_attr_key.attr, |
839 | &class_device_attr_rel.attr, | 847 | &dev_attr_rel.attr, |
840 | &class_device_attr_abs.attr, | 848 | &dev_attr_abs.attr, |
841 | &class_device_attr_msc.attr, | 849 | &dev_attr_msc.attr, |
842 | &class_device_attr_led.attr, | 850 | &dev_attr_led.attr, |
843 | &class_device_attr_snd.attr, | 851 | &dev_attr_snd.attr, |
844 | &class_device_attr_ff.attr, | 852 | &dev_attr_ff.attr, |
845 | &class_device_attr_sw.attr, | 853 | &dev_attr_sw.attr, |
846 | NULL | 854 | NULL |
847 | }; | 855 | }; |
848 | 856 | ||
@@ -858,9 +866,9 @@ static struct attribute_group *input_dev_attr_groups[] = { | |||
858 | NULL | 866 | NULL |
859 | }; | 867 | }; |
860 | 868 | ||
861 | static void input_dev_release(struct class_device *class_dev) | 869 | static void input_dev_release(struct device *device) |
862 | { | 870 | { |
863 | struct input_dev *dev = to_input_dev(class_dev); | 871 | struct input_dev *dev = to_input_dev(device); |
864 | 872 | ||
865 | input_ff_destroy(dev); | 873 | input_ff_destroy(dev); |
866 | kfree(dev); | 874 | kfree(dev); |
@@ -947,10 +955,10 @@ static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_ind | |||
947 | return err; \ | 955 | return err; \ |
948 | } while (0) | 956 | } while (0) |
949 | 957 | ||
950 | static int input_dev_uevent(struct class_device *cdev, char **envp, | 958 | static int input_dev_uevent(struct device *device, char **envp, |
951 | int num_envp, char *buffer, int buffer_size) | 959 | int num_envp, char *buffer, int buffer_size) |
952 | { | 960 | { |
953 | struct input_dev *dev = to_input_dev(cdev); | 961 | struct input_dev *dev = to_input_dev(device); |
954 | int i = 0; | 962 | int i = 0; |
955 | int len = 0; | 963 | int len = 0; |
956 | 964 | ||
@@ -988,10 +996,14 @@ static int input_dev_uevent(struct class_device *cdev, char **envp, | |||
988 | return 0; | 996 | return 0; |
989 | } | 997 | } |
990 | 998 | ||
999 | static struct device_type input_dev_type = { | ||
1000 | .groups = input_dev_attr_groups, | ||
1001 | .release = input_dev_release, | ||
1002 | .uevent = input_dev_uevent, | ||
1003 | }; | ||
1004 | |||
991 | struct class input_class = { | 1005 | struct class input_class = { |
992 | .name = "input", | 1006 | .name = "input", |
993 | .release = input_dev_release, | ||
994 | .uevent = input_dev_uevent, | ||
995 | }; | 1007 | }; |
996 | EXPORT_SYMBOL_GPL(input_class); | 1008 | EXPORT_SYMBOL_GPL(input_class); |
997 | 1009 | ||
@@ -1010,9 +1022,9 @@ struct input_dev *input_allocate_device(void) | |||
1010 | 1022 | ||
1011 | dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); | 1023 | dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); |
1012 | if (dev) { | 1024 | if (dev) { |
1013 | dev->cdev.class = &input_class; | 1025 | dev->dev.type = &input_dev_type; |
1014 | dev->cdev.groups = input_dev_attr_groups; | 1026 | dev->dev.class = &input_class; |
1015 | class_device_initialize(&dev->cdev); | 1027 | device_initialize(&dev->dev); |
1016 | mutex_init(&dev->mutex); | 1028 | mutex_init(&dev->mutex); |
1017 | INIT_LIST_HEAD(&dev->h_list); | 1029 | INIT_LIST_HEAD(&dev->h_list); |
1018 | INIT_LIST_HEAD(&dev->node); | 1030 | INIT_LIST_HEAD(&dev->node); |
@@ -1131,17 +1143,17 @@ int input_register_device(struct input_dev *dev) | |||
1131 | 1143 | ||
1132 | list_add_tail(&dev->node, &input_dev_list); | 1144 | list_add_tail(&dev->node, &input_dev_list); |
1133 | 1145 | ||
1134 | snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), | 1146 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), |
1135 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); | 1147 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); |
1136 | 1148 | ||
1137 | if (!dev->cdev.dev) | 1149 | if (dev->cdev.dev) |
1138 | dev->cdev.dev = dev->dev.parent; | 1150 | dev->dev.parent = dev->cdev.dev; |
1139 | 1151 | ||
1140 | error = class_device_add(&dev->cdev); | 1152 | error = device_add(&dev->dev); |
1141 | if (error) | 1153 | if (error) |
1142 | return error; | 1154 | return error; |
1143 | 1155 | ||
1144 | path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); | 1156 | path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); |
1145 | printk(KERN_INFO "input: %s as %s\n", | 1157 | printk(KERN_INFO "input: %s as %s\n", |
1146 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); | 1158 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); |
1147 | kfree(path); | 1159 | kfree(path); |
@@ -1173,7 +1185,7 @@ void input_unregister_device(struct input_dev *dev) | |||
1173 | 1185 | ||
1174 | list_del_init(&dev->node); | 1186 | list_del_init(&dev->node); |
1175 | 1187 | ||
1176 | class_device_unregister(&dev->cdev); | 1188 | device_unregister(&dev->dev); |
1177 | 1189 | ||
1178 | input_wakeup_procfs_readers(); | 1190 | input_wakeup_procfs_readers(); |
1179 | } | 1191 | } |
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 10e3b7bc925f..a9a0180bfd46 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
@@ -43,6 +43,8 @@ struct joydev { | |||
43 | struct input_handle handle; | 43 | struct input_handle handle; |
44 | wait_queue_head_t wait; | 44 | wait_queue_head_t wait; |
45 | struct list_head client_list; | 45 | struct list_head client_list; |
46 | struct device dev; | ||
47 | |||
46 | struct js_corr corr[ABS_MAX + 1]; | 48 | struct js_corr corr[ABS_MAX + 1]; |
47 | struct JS_DATA_SAVE_TYPE glue; | 49 | struct JS_DATA_SAVE_TYPE glue; |
48 | int nabs; | 50 | int nabs; |
@@ -138,8 +140,10 @@ static int joydev_fasync(int fd, struct file *file, int on) | |||
138 | return retval < 0 ? retval : 0; | 140 | return retval < 0 ? retval : 0; |
139 | } | 141 | } |
140 | 142 | ||
141 | static void joydev_free(struct joydev *joydev) | 143 | static void joydev_free(struct device *dev) |
142 | { | 144 | { |
145 | struct joydev *joydev = container_of(dev, struct joydev, dev); | ||
146 | |||
143 | joydev_table[joydev->minor] = NULL; | 147 | joydev_table[joydev->minor] = NULL; |
144 | kfree(joydev); | 148 | kfree(joydev); |
145 | } | 149 | } |
@@ -154,12 +158,10 @@ static int joydev_release(struct inode *inode, struct file *file) | |||
154 | list_del(&client->node); | 158 | list_del(&client->node); |
155 | kfree(client); | 159 | kfree(client); |
156 | 160 | ||
157 | if (!--joydev->open) { | 161 | if (!--joydev->open && joydev->exist) |
158 | if (joydev->exist) | 162 | input_close_device(&joydev->handle); |
159 | input_close_device(&joydev->handle); | 163 | |
160 | else | 164 | put_device(&joydev->dev); |
161 | joydev_free(joydev); | ||
162 | } | ||
163 | 165 | ||
164 | return 0; | 166 | return 0; |
165 | } | 167 | } |
@@ -178,24 +180,32 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
178 | if (!joydev || !joydev->exist) | 180 | if (!joydev || !joydev->exist) |
179 | return -ENODEV; | 181 | return -ENODEV; |
180 | 182 | ||
183 | get_device(&joydev->dev); | ||
184 | |||
181 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); | 185 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
182 | if (!client) | 186 | if (!client) { |
183 | return -ENOMEM; | 187 | error = -ENOMEM; |
188 | goto err_put_joydev; | ||
189 | } | ||
184 | 190 | ||
185 | client->joydev = joydev; | 191 | client->joydev = joydev; |
186 | list_add_tail(&client->node, &joydev->client_list); | 192 | list_add_tail(&client->node, &joydev->client_list); |
187 | 193 | ||
188 | if (!joydev->open++ && joydev->exist) { | 194 | if (!joydev->open++ && joydev->exist) { |
189 | error = input_open_device(&joydev->handle); | 195 | error = input_open_device(&joydev->handle); |
190 | if (error) { | 196 | if (error) |
191 | list_del(&client->node); | 197 | goto err_free_client; |
192 | kfree(client); | ||
193 | return error; | ||
194 | } | ||
195 | } | 198 | } |
196 | 199 | ||
197 | file->private_data = client; | 200 | file->private_data = client; |
198 | return 0; | 201 | return 0; |
202 | |||
203 | err_free_client: | ||
204 | list_del(&client->node); | ||
205 | kfree(client); | ||
206 | err_put_joydev: | ||
207 | put_device(&joydev->dev); | ||
208 | return error; | ||
199 | } | 209 | } |
200 | 210 | ||
201 | static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 211 | static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
@@ -481,8 +491,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
481 | const struct input_device_id *id) | 491 | const struct input_device_id *id) |
482 | { | 492 | { |
483 | struct joydev *joydev; | 493 | struct joydev *joydev; |
484 | struct class_device *cdev; | ||
485 | dev_t devt; | ||
486 | int i, j, t, minor; | 494 | int i, j, t, minor; |
487 | int error; | 495 | int error; |
488 | 496 | ||
@@ -505,7 +513,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
505 | joydev->handle.name = joydev->name; | 513 | joydev->handle.name = joydev->name; |
506 | joydev->handle.handler = handler; | 514 | joydev->handle.handler = handler; |
507 | joydev->handle.private = joydev; | 515 | joydev->handle.private = joydev; |
508 | sprintf(joydev->name, "js%d", minor); | 516 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); |
509 | 517 | ||
510 | for (i = 0; i < ABS_MAX + 1; i++) | 518 | for (i = 0; i < ABS_MAX + 1; i++) |
511 | if (test_bit(i, dev->absbit)) { | 519 | if (test_bit(i, dev->absbit)) { |
@@ -547,36 +555,30 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
547 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | 555 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); |
548 | } | 556 | } |
549 | 557 | ||
550 | joydev_table[minor] = joydev; | 558 | snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id), |
551 | 559 | "js%d", minor); | |
552 | devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), | 560 | joydev->dev.class = &input_class; |
561 | joydev->dev.parent = &dev->dev; | ||
562 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); | ||
563 | joydev->dev.release = joydev_free; | ||
564 | device_initialize(&joydev->dev); | ||
553 | 565 | ||
554 | cdev = class_device_create(&input_class, &dev->cdev, devt, | 566 | joydev_table[minor] = joydev; |
555 | dev->cdev.dev, joydev->name); | ||
556 | if (IS_ERR(cdev)) { | ||
557 | error = PTR_ERR(cdev); | ||
558 | goto err_free_joydev; | ||
559 | } | ||
560 | 567 | ||
561 | /* temporary symlink to keep userspace happy */ | 568 | error = device_add(&joydev->dev); |
562 | error = sysfs_create_link(&input_class.subsys.kobj, | ||
563 | &cdev->kobj, joydev->name); | ||
564 | if (error) | 569 | if (error) |
565 | goto err_cdev_destroy; | 570 | goto err_free_joydev; |
566 | 571 | ||
567 | error = input_register_handle(&joydev->handle); | 572 | error = input_register_handle(&joydev->handle); |
568 | if (error) | 573 | if (error) |
569 | goto err_remove_link; | 574 | goto err_delete_joydev; |
570 | 575 | ||
571 | return 0; | 576 | return 0; |
572 | 577 | ||
573 | err_remove_link: | 578 | err_delete_joydev: |
574 | sysfs_remove_link(&input_class.subsys.kobj, joydev->name); | 579 | device_del(&joydev->dev); |
575 | err_cdev_destroy: | ||
576 | class_device_destroy(&input_class, devt); | ||
577 | err_free_joydev: | 580 | err_free_joydev: |
578 | joydev_table[minor] = NULL; | 581 | put_device(&joydev->dev); |
579 | kfree(joydev); | ||
580 | return error; | 582 | return error; |
581 | } | 583 | } |
582 | 584 | ||
@@ -587,9 +589,8 @@ static void joydev_disconnect(struct input_handle *handle) | |||
587 | struct joydev_client *client; | 589 | struct joydev_client *client; |
588 | 590 | ||
589 | input_unregister_handle(handle); | 591 | input_unregister_handle(handle); |
592 | device_del(&joydev->dev); | ||
590 | 593 | ||
591 | sysfs_remove_link(&input_class.subsys.kobj, joydev->name); | ||
592 | class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); | ||
593 | joydev->exist = 0; | 594 | joydev->exist = 0; |
594 | 595 | ||
595 | if (joydev->open) { | 596 | if (joydev->open) { |
@@ -597,8 +598,9 @@ static void joydev_disconnect(struct input_handle *handle) | |||
597 | list_for_each_entry(client, &joydev->client_list, node) | 598 | list_for_each_entry(client, &joydev->client_list, node) |
598 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 599 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
599 | wake_up_interruptible(&joydev->wait); | 600 | wake_up_interruptible(&joydev->wait); |
600 | } else | 601 | } |
601 | joydev_free(joydev); | 602 | |
603 | put_device(&joydev->dev); | ||
602 | } | 604 | } |
603 | 605 | ||
604 | static const struct input_device_id joydev_blacklist[] = { | 606 | static const struct input_device_id joydev_blacklist[] = { |
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index b0023452ec90..12db72d83ea0 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig | |||
@@ -268,4 +268,11 @@ config JOYSTICK_XPAD | |||
268 | To compile this driver as a module, choose M here: the | 268 | To compile this driver as a module, choose M here: the |
269 | module will be called xpad. | 269 | module will be called xpad. |
270 | 270 | ||
271 | config JOYSTICK_XPAD_FF | ||
272 | bool "X-Box gamepad rumble support" | ||
273 | depends on JOYSTICK_XPAD && INPUT | ||
274 | select INPUT_FF_MEMLESS | ||
275 | ---help--- | ||
276 | Say Y here if you want to take advantage of xbox 360 rumble features. | ||
277 | |||
271 | endif | 278 | endif |
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index 555319e6378c..4ed3a3eadf19 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c | |||
@@ -320,10 +320,10 @@ static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, | |||
320 | 320 | ||
321 | static int dig_mode_start(struct gameport *gameport, u32 *packet) | 321 | static int dig_mode_start(struct gameport *gameport, u32 *packet) |
322 | { | 322 | { |
323 | int i, seq_len = sizeof(init_seq)/sizeof(int); | 323 | int i; |
324 | int flags, tries = 0, bads = 0; | 324 | int flags, tries = 0, bads = 0; |
325 | 325 | ||
326 | for (i = 0; i < seq_len; i++) { /* Send magic sequence */ | 326 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { /* Send magic sequence */ |
327 | if (init_seq[i]) | 327 | if (init_seq[i]) |
328 | gameport_trigger(gameport); | 328 | gameport_trigger(gameport); |
329 | udelay(GRIP_INIT_DELAY); | 329 | udelay(GRIP_INIT_DELAY); |
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 8c8cd95a6989..244089c52650 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * Ivan Hawkes <blackhawk@ivanhawkes.com> | 8 | * Ivan Hawkes <blackhawk@ivanhawkes.com> |
9 | * 2005 Dominic Cerquetti <binary1230@yahoo.com> | 9 | * 2005 Dominic Cerquetti <binary1230@yahoo.com> |
10 | * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> | 10 | * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> |
11 | * 2007 Jan Kratochvil <honza@jikos.cz> | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License as | 14 | * modify it under the terms of the GNU General Public License as |
@@ -28,6 +29,7 @@ | |||
28 | * - information from http://euc.jp/periphs/xbox-controller.ja.html | 29 | * - information from http://euc.jp/periphs/xbox-controller.ja.html |
29 | * - the iForce driver drivers/char/joystick/iforce.c | 30 | * - the iForce driver drivers/char/joystick/iforce.c |
30 | * - the skeleton-driver drivers/usb/usb-skeleton.c | 31 | * - the skeleton-driver drivers/usb/usb-skeleton.c |
32 | * - Xbox 360 information http://www.free60.org/wiki/Gamepad | ||
31 | * | 33 | * |
32 | * Thanks to: | 34 | * Thanks to: |
33 | * - ITO Takayuki for providing essential xpad information on his website | 35 | * - ITO Takayuki for providing essential xpad information on his website |
@@ -88,6 +90,9 @@ | |||
88 | #define MAP_DPAD_TO_AXES 1 | 90 | #define MAP_DPAD_TO_AXES 1 |
89 | #define MAP_DPAD_UNKNOWN -1 | 91 | #define MAP_DPAD_UNKNOWN -1 |
90 | 92 | ||
93 | #define XTYPE_XBOX 0 | ||
94 | #define XTYPE_XBOX360 1 | ||
95 | |||
91 | static int dpad_to_buttons; | 96 | static int dpad_to_buttons; |
92 | module_param(dpad_to_buttons, bool, S_IRUGO); | 97 | module_param(dpad_to_buttons, bool, S_IRUGO); |
93 | MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); | 98 | MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); |
@@ -97,40 +102,42 @@ static const struct xpad_device { | |||
97 | u16 idProduct; | 102 | u16 idProduct; |
98 | char *name; | 103 | char *name; |
99 | u8 dpad_mapping; | 104 | u8 dpad_mapping; |
105 | u8 xtype; | ||
100 | } xpad_device[] = { | 106 | } xpad_device[] = { |
101 | { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES }, | 107 | { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
102 | { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES }, | 108 | { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
103 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES }, | 109 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
104 | { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES }, | 110 | { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
105 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS }, | 111 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
106 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES }, | 112 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
107 | { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES }, | 113 | { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
108 | { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES }, | 114 | { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
109 | { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES }, | 115 | { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
110 | { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES }, | 116 | { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
111 | { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES }, | 117 | { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
112 | { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES }, | 118 | { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
113 | { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES }, | 119 | { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
114 | { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES }, | 120 | { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
115 | { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS }, | 121 | { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
116 | { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES }, | 122 | { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
117 | { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS }, | 123 | { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
118 | { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, | 124 | { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
119 | { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, | 125 | { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
120 | { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES }, | 126 | { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
121 | { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES }, | 127 | { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
122 | { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES}, | 128 | { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
123 | { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES }, | 129 | { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
124 | { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES }, | 130 | { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
125 | { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES }, | 131 | { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
126 | { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES }, | 132 | { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
127 | { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES }, | 133 | { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
128 | { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES }, | 134 | { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
129 | { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES }, | 135 | { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
130 | { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS }, | 136 | { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
131 | { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS }, | 137 | { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
132 | { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES }, | 138 | { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, |
133 | { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN } | 139 | { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
140 | { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_XBOX } | ||
134 | }; | 141 | }; |
135 | 142 | ||
136 | static const signed short xpad_btn[] = { | 143 | static const signed short xpad_btn[] = { |
@@ -146,6 +153,12 @@ static const signed short xpad_btn_pad[] = { | |||
146 | -1 /* terminating entry */ | 153 | -1 /* terminating entry */ |
147 | }; | 154 | }; |
148 | 155 | ||
156 | static const signed short xpad360_btn[] = { /* buttons for x360 controller */ | ||
157 | BTN_TL, BTN_TR, /* Button LB/RB */ | ||
158 | BTN_MODE, /* The big X button */ | ||
159 | -1 | ||
160 | }; | ||
161 | |||
149 | static const signed short xpad_abs[] = { | 162 | static const signed short xpad_abs[] = { |
150 | ABS_X, ABS_Y, /* left stick */ | 163 | ABS_X, ABS_Y, /* left stick */ |
151 | ABS_RX, ABS_RY, /* right stick */ | 164 | ABS_RX, ABS_RY, /* right stick */ |
@@ -159,8 +172,12 @@ static const signed short xpad_abs_pad[] = { | |||
159 | -1 /* terminating entry */ | 172 | -1 /* terminating entry */ |
160 | }; | 173 | }; |
161 | 174 | ||
175 | /* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only | ||
176 | * USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols, | ||
177 | * but we need only one of them. */ | ||
162 | static struct usb_device_id xpad_table [] = { | 178 | static struct usb_device_id xpad_table [] = { |
163 | { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ | 179 | { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ |
180 | { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) }, /* X-Box 360 controller */ | ||
164 | { } | 181 | { } |
165 | }; | 182 | }; |
166 | 183 | ||
@@ -174,9 +191,16 @@ struct usb_xpad { | |||
174 | unsigned char *idata; /* input data */ | 191 | unsigned char *idata; /* input data */ |
175 | dma_addr_t idata_dma; | 192 | dma_addr_t idata_dma; |
176 | 193 | ||
194 | #ifdef CONFIG_JOYSTICK_XPAD_FF | ||
195 | struct urb *irq_out; /* urb for interrupt out report */ | ||
196 | unsigned char *odata; /* output data */ | ||
197 | dma_addr_t odata_dma; | ||
198 | #endif | ||
199 | |||
177 | char phys[65]; /* physical device path */ | 200 | char phys[65]; /* physical device path */ |
178 | 201 | ||
179 | int dpad_mapping; /* map d-pad to buttons or to axes */ | 202 | int dpad_mapping; /* map d-pad to buttons or to axes */ |
203 | int xtype; /* type of xbox device */ | ||
180 | }; | 204 | }; |
181 | 205 | ||
182 | /* | 206 | /* |
@@ -212,8 +236,8 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d | |||
212 | } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { | 236 | } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { |
213 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); | 237 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); |
214 | input_report_key(dev, BTN_RIGHT, data[2] & 0x08); | 238 | input_report_key(dev, BTN_RIGHT, data[2] & 0x08); |
215 | input_report_key(dev, BTN_0, data[2] & 0x01); // up | 239 | input_report_key(dev, BTN_0, data[2] & 0x01); /* up */ |
216 | input_report_key(dev, BTN_1, data[2] & 0x02); // down | 240 | input_report_key(dev, BTN_1, data[2] & 0x02); /* down */ |
217 | } | 241 | } |
218 | 242 | ||
219 | /* start/back buttons and stick press left/right */ | 243 | /* start/back buttons and stick press left/right */ |
@@ -235,6 +259,64 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d | |||
235 | input_sync(dev); | 259 | input_sync(dev); |
236 | } | 260 | } |
237 | 261 | ||
262 | /* | ||
263 | * xpad360_process_packet | ||
264 | * | ||
265 | * Completes a request by converting the data into events for the | ||
266 | * input subsystem. It is version for xbox 360 controller | ||
267 | * | ||
268 | * The used report descriptor was taken from: | ||
269 | * http://www.free60.org/wiki/Gamepad | ||
270 | */ | ||
271 | |||
272 | static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) | ||
273 | { | ||
274 | struct input_dev *dev = xpad->dev; | ||
275 | |||
276 | /* digital pad */ | ||
277 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { | ||
278 | input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); | ||
279 | input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); | ||
280 | } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) { | ||
281 | /* dpad as buttons (right, left, down, up) */ | ||
282 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); | ||
283 | input_report_key(dev, BTN_RIGHT, data[2] & 0x08); | ||
284 | input_report_key(dev, BTN_0, data[2] & 0x01); /* up */ | ||
285 | input_report_key(dev, BTN_1, data[2] & 0x02); /* down */ | ||
286 | } | ||
287 | |||
288 | /* start/back buttons */ | ||
289 | input_report_key(dev, BTN_START, data[2] & 0x10); | ||
290 | input_report_key(dev, BTN_BACK, data[2] & 0x20); | ||
291 | |||
292 | /* stick press left/right */ | ||
293 | input_report_key(dev, BTN_THUMBL, data[2] & 0x40); | ||
294 | input_report_key(dev, BTN_THUMBR, data[2] & 0x80); | ||
295 | |||
296 | /* buttons A,B,X,Y,TL,TR and MODE */ | ||
297 | input_report_key(dev, BTN_A, data[3] & 0x10); | ||
298 | input_report_key(dev, BTN_B, data[3] & 0x20); | ||
299 | input_report_key(dev, BTN_X, data[3] & 0x40); | ||
300 | input_report_key(dev, BTN_Y, data[3] & 0x80); | ||
301 | input_report_key(dev, BTN_TL, data[3] & 0x01); | ||
302 | input_report_key(dev, BTN_TR, data[3] & 0x02); | ||
303 | input_report_key(dev, BTN_MODE, data[3] & 0x04); | ||
304 | |||
305 | /* left stick */ | ||
306 | input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6])); | ||
307 | input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[9] << 8) | (__s16)data[8])); | ||
308 | |||
309 | /* right stick */ | ||
310 | input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10])); | ||
311 | input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[13] << 8) | (__s16)data[12])); | ||
312 | |||
313 | /* triggers left/right */ | ||
314 | input_report_abs(dev, ABS_Z, data[4]); | ||
315 | input_report_abs(dev, ABS_RZ, data[5]); | ||
316 | |||
317 | input_sync(dev); | ||
318 | } | ||
319 | |||
238 | static void xpad_irq_in(struct urb *urb) | 320 | static void xpad_irq_in(struct urb *urb) |
239 | { | 321 | { |
240 | struct usb_xpad *xpad = urb->context; | 322 | struct usb_xpad *xpad = urb->context; |
@@ -255,7 +337,10 @@ static void xpad_irq_in(struct urb *urb) | |||
255 | goto exit; | 337 | goto exit; |
256 | } | 338 | } |
257 | 339 | ||
258 | xpad_process_packet(xpad, 0, xpad->idata); | 340 | if (xpad->xtype == XTYPE_XBOX360) |
341 | xpad360_process_packet(xpad, 0, xpad->idata); | ||
342 | else | ||
343 | xpad_process_packet(xpad, 0, xpad->idata); | ||
259 | 344 | ||
260 | exit: | 345 | exit: |
261 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 346 | retval = usb_submit_urb (urb, GFP_ATOMIC); |
@@ -264,7 +349,114 @@ exit: | |||
264 | __FUNCTION__, retval); | 349 | __FUNCTION__, retval); |
265 | } | 350 | } |
266 | 351 | ||
267 | static int xpad_open (struct input_dev *dev) | 352 | #ifdef CONFIG_JOYSTICK_XPAD_FF |
353 | static void xpad_irq_out(struct urb *urb) | ||
354 | { | ||
355 | int retval; | ||
356 | |||
357 | switch (urb->status) { | ||
358 | case 0: | ||
359 | /* success */ | ||
360 | break; | ||
361 | case -ECONNRESET: | ||
362 | case -ENOENT: | ||
363 | case -ESHUTDOWN: | ||
364 | /* this urb is terminated, clean up */ | ||
365 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | ||
366 | return; | ||
367 | default: | ||
368 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | ||
369 | goto exit; | ||
370 | } | ||
371 | |||
372 | exit: | ||
373 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
374 | if (retval) | ||
375 | err("%s - usb_submit_urb failed with result %d", | ||
376 | __FUNCTION__, retval); | ||
377 | } | ||
378 | |||
379 | static int xpad_play_effect(struct input_dev *dev, void *data, | ||
380 | struct ff_effect *effect) | ||
381 | { | ||
382 | struct usb_xpad *xpad = input_get_drvdata(dev); | ||
383 | |||
384 | if (effect->type == FF_RUMBLE) { | ||
385 | __u16 strong = effect->u.rumble.strong_magnitude; | ||
386 | __u16 weak = effect->u.rumble.weak_magnitude; | ||
387 | xpad->odata[0] = 0x00; | ||
388 | xpad->odata[1] = 0x08; | ||
389 | xpad->odata[2] = 0x00; | ||
390 | xpad->odata[3] = strong / 256; | ||
391 | xpad->odata[4] = weak / 256; | ||
392 | xpad->odata[5] = 0x00; | ||
393 | xpad->odata[6] = 0x00; | ||
394 | xpad->odata[7] = 0x00; | ||
395 | usb_submit_urb(xpad->irq_out, GFP_KERNEL); | ||
396 | } | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) | ||
402 | { | ||
403 | struct usb_endpoint_descriptor *ep_irq_out; | ||
404 | int error = -ENOMEM; | ||
405 | |||
406 | if (xpad->xtype != XTYPE_XBOX360) | ||
407 | return 0; | ||
408 | |||
409 | xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN, | ||
410 | GFP_ATOMIC, &xpad->odata_dma ); | ||
411 | if (!xpad->odata) | ||
412 | goto fail1; | ||
413 | |||
414 | xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); | ||
415 | if (!xpad->irq_out) | ||
416 | goto fail2; | ||
417 | |||
418 | ep_irq_out = &intf->cur_altsetting->endpoint[1].desc; | ||
419 | usb_fill_int_urb(xpad->irq_out, xpad->udev, | ||
420 | usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress), | ||
421 | xpad->odata, XPAD_PKT_LEN, | ||
422 | xpad_irq_out, xpad, ep_irq_out->bInterval); | ||
423 | xpad->irq_out->transfer_dma = xpad->odata_dma; | ||
424 | xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
425 | |||
426 | input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); | ||
427 | |||
428 | error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect); | ||
429 | if (error) | ||
430 | goto fail2; | ||
431 | |||
432 | return 0; | ||
433 | |||
434 | fail2: usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); | ||
435 | fail1: return error; | ||
436 | } | ||
437 | |||
438 | static void xpad_stop_ff(struct usb_xpad *xpad) | ||
439 | { | ||
440 | if (xpad->xtype == XTYPE_XBOX360) | ||
441 | usb_kill_urb(xpad->irq_out); | ||
442 | } | ||
443 | |||
444 | static void xpad_deinit_ff(struct usb_xpad *xpad) | ||
445 | { | ||
446 | if (xpad->xtype == XTYPE_XBOX360) { | ||
447 | usb_free_urb(xpad->irq_out); | ||
448 | usb_buffer_free(xpad->udev, XPAD_PKT_LEN, | ||
449 | xpad->odata, xpad->odata_dma); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | #else | ||
454 | static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; } | ||
455 | static void xpad_stop_ff(struct usb_xpad *xpad) { } | ||
456 | static void xpad_deinit_ff(struct usb_xpad *xpad) { } | ||
457 | #endif | ||
458 | |||
459 | static int xpad_open(struct input_dev *dev) | ||
268 | { | 460 | { |
269 | struct usb_xpad *xpad = input_get_drvdata(dev); | 461 | struct usb_xpad *xpad = input_get_drvdata(dev); |
270 | 462 | ||
@@ -275,11 +467,12 @@ static int xpad_open (struct input_dev *dev) | |||
275 | return 0; | 467 | return 0; |
276 | } | 468 | } |
277 | 469 | ||
278 | static void xpad_close (struct input_dev *dev) | 470 | static void xpad_close(struct input_dev *dev) |
279 | { | 471 | { |
280 | struct usb_xpad *xpad = input_get_drvdata(dev); | 472 | struct usb_xpad *xpad = input_get_drvdata(dev); |
281 | 473 | ||
282 | usb_kill_urb(xpad->irq_in); | 474 | usb_kill_urb(xpad->irq_in); |
475 | xpad_stop_ff(xpad); | ||
283 | } | 476 | } |
284 | 477 | ||
285 | static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) | 478 | static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) |
@@ -335,6 +528,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
335 | 528 | ||
336 | xpad->udev = udev; | 529 | xpad->udev = udev; |
337 | xpad->dpad_mapping = xpad_device[i].dpad_mapping; | 530 | xpad->dpad_mapping = xpad_device[i].dpad_mapping; |
531 | xpad->xtype = xpad_device[i].xtype; | ||
338 | if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) | 532 | if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) |
339 | xpad->dpad_mapping = dpad_to_buttons; | 533 | xpad->dpad_mapping = dpad_to_buttons; |
340 | xpad->dev = input_dev; | 534 | xpad->dev = input_dev; |
@@ -356,6 +550,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
356 | /* set up buttons */ | 550 | /* set up buttons */ |
357 | for (i = 0; xpad_btn[i] >= 0; i++) | 551 | for (i = 0; xpad_btn[i] >= 0; i++) |
358 | set_bit(xpad_btn[i], input_dev->keybit); | 552 | set_bit(xpad_btn[i], input_dev->keybit); |
553 | if (xpad->xtype == XTYPE_XBOX360) | ||
554 | for (i = 0; xpad360_btn[i] >= 0; i++) | ||
555 | set_bit(xpad360_btn[i], input_dev->keybit); | ||
359 | if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) | 556 | if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) |
360 | for (i = 0; xpad_btn_pad[i] >= 0; i++) | 557 | for (i = 0; xpad_btn_pad[i] >= 0; i++) |
361 | set_bit(xpad_btn_pad[i], input_dev->keybit); | 558 | set_bit(xpad_btn_pad[i], input_dev->keybit); |
@@ -367,6 +564,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
367 | for (i = 0; xpad_abs_pad[i] >= 0; i++) | 564 | for (i = 0; xpad_abs_pad[i] >= 0; i++) |
368 | xpad_set_up_abs(input_dev, xpad_abs_pad[i]); | 565 | xpad_set_up_abs(input_dev, xpad_abs_pad[i]); |
369 | 566 | ||
567 | error = xpad_init_ff(intf, xpad); | ||
568 | if (error) | ||
569 | goto fail2; | ||
570 | |||
370 | ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; | 571 | ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; |
371 | usb_fill_int_urb(xpad->irq_in, udev, | 572 | usb_fill_int_urb(xpad->irq_in, udev, |
372 | usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), | 573 | usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), |
@@ -396,10 +597,10 @@ static void xpad_disconnect(struct usb_interface *intf) | |||
396 | 597 | ||
397 | usb_set_intfdata(intf, NULL); | 598 | usb_set_intfdata(intf, NULL); |
398 | if (xpad) { | 599 | if (xpad) { |
399 | usb_kill_urb(xpad->irq_in); | ||
400 | input_unregister_device(xpad->dev); | 600 | input_unregister_device(xpad->dev); |
601 | xpad_deinit_ff(xpad); | ||
401 | usb_free_urb(xpad->irq_in); | 602 | usb_free_urb(xpad->irq_in); |
402 | usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, | 603 | usb_buffer_free(xpad->udev, XPAD_PKT_LEN, |
403 | xpad->idata, xpad->idata_dma); | 604 | xpad->idata, xpad->idata_dma); |
404 | kfree(xpad); | 605 | kfree(xpad); |
405 | } | 606 | } |
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 9950fcb33650..41fc3d03b6eb 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -89,7 +89,7 @@ static unsigned char atkbd_set2_keycode[512] = { | |||
89 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 89 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
90 | 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, | 90 | 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, |
91 | 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, | 91 | 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, |
92 | 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142, | 92 | 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142, |
93 | 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, | 93 | 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, |
94 | 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, | 94 | 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, |
95 | 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, | 95 | 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, |
@@ -111,7 +111,7 @@ static unsigned char atkbd_set3_keycode[512] = { | |||
111 | 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183, | 111 | 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183, |
112 | 112 | ||
113 | 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0, | 113 | 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0, |
114 | 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168, | 114 | 0,139,172,163,165,115,152,172,166,140,160,154,113,114,167,168, |
115 | 148,149,147,140 | 115 | 148,149,147,140 |
116 | }; | 116 | }; |
117 | 117 | ||
diff --git a/drivers/input/keyboard/pxa27x_keyboard.c b/drivers/input/keyboard/pxa27x_keyboard.c index f9e82c9ca421..ebe5eacf2990 100644 --- a/drivers/input/keyboard/pxa27x_keyboard.c +++ b/drivers/input/keyboard/pxa27x_keyboard.c | |||
@@ -140,7 +140,7 @@ static int pxakbd_resume(struct platform_device *pdev) | |||
140 | KPREC = pdata->reg_kprec; | 140 | KPREC = pdata->reg_kprec; |
141 | 141 | ||
142 | /* Enable unit clock */ | 142 | /* Enable unit clock */ |
143 | pxa_set_cken(CKEN19_KEYPAD, 1); | 143 | pxa_set_cken(CKEN_KEYPAD, 1); |
144 | } | 144 | } |
145 | 145 | ||
146 | mutex_unlock(&input_dev->mutex); | 146 | mutex_unlock(&input_dev->mutex); |
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 88e29074ac90..9b26574f1466 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -65,9 +65,13 @@ config INPUT_COBALT_BTNS | |||
65 | config INPUT_WISTRON_BTNS | 65 | config INPUT_WISTRON_BTNS |
66 | tristate "x86 Wistron laptop button interface" | 66 | tristate "x86 Wistron laptop button interface" |
67 | depends on X86 && !X86_64 | 67 | depends on X86 && !X86_64 |
68 | select INPUT_POLLDEV | ||
69 | select NEW_LEDS | ||
70 | select LEDS_CLASS | ||
68 | help | 71 | help |
69 | Say Y here for support of Winstron laptop button interface, used on | 72 | Say Y here for support of Winstron laptop button interface, used on |
70 | laptops of various brands, including Acer and Fujitsu-Siemens. | 73 | laptops of various brands, including Acer and Fujitsu-Siemens. If |
74 | available, mail and wifi leds will be controlable via /sys/class/leds. | ||
71 | 75 | ||
72 | To compile this driver as a module, choose M here: the module will | 76 | To compile this driver as a module, choose M here: the module will |
73 | be called wistron_btns. | 77 | be called wistron_btns. |
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 961aad7a0476..60121f10f8d9 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c | |||
@@ -20,37 +20,31 @@ | |||
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/dmi.h> | 21 | #include <linux/dmi.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/input.h> | 23 | #include <linux/input-polldev.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/jiffies.h> | ||
25 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
26 | #include <linux/mc146818rtc.h> | 27 | #include <linux/mc146818rtc.h> |
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
28 | #include <linux/preempt.h> | 29 | #include <linux/preempt.h> |
29 | #include <linux/string.h> | 30 | #include <linux/string.h> |
30 | #include <linux/timer.h> | ||
31 | #include <linux/types.h> | 31 | #include <linux/types.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/leds.h> | ||
33 | 34 | ||
34 | /* | 35 | /* How often we poll keys - msecs */ |
35 | * Number of attempts to read data from queue per poll; | 36 | #define POLL_INTERVAL_DEFAULT 500 /* when idle */ |
36 | * the queue can hold up to 31 entries | 37 | #define POLL_INTERVAL_BURST 100 /* when a key was recently pressed */ |
37 | */ | ||
38 | #define MAX_POLL_ITERATIONS 64 | ||
39 | |||
40 | #define POLL_FREQUENCY 10 /* Number of polls per second */ | ||
41 | |||
42 | #if POLL_FREQUENCY > HZ | ||
43 | #error "POLL_FREQUENCY too high" | ||
44 | #endif | ||
45 | 38 | ||
46 | /* BIOS subsystem IDs */ | 39 | /* BIOS subsystem IDs */ |
47 | #define WIFI 0x35 | 40 | #define WIFI 0x35 |
48 | #define BLUETOOTH 0x34 | 41 | #define BLUETOOTH 0x34 |
42 | #define MAIL_LED 0x31 | ||
49 | 43 | ||
50 | MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>"); | 44 | MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>"); |
51 | MODULE_DESCRIPTION("Wistron laptop button driver"); | 45 | MODULE_DESCRIPTION("Wistron laptop button driver"); |
52 | MODULE_LICENSE("GPL v2"); | 46 | MODULE_LICENSE("GPL v2"); |
53 | MODULE_VERSION("0.2"); | 47 | MODULE_VERSION("0.3"); |
54 | 48 | ||
55 | static int force; /* = 0; */ | 49 | static int force; /* = 0; */ |
56 | module_param(force, bool, 0); | 50 | module_param(force, bool, 0); |
@@ -248,9 +242,10 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; | |||
248 | #define FE_WIFI_LED 0x02 | 242 | #define FE_WIFI_LED 0x02 |
249 | #define FE_UNTESTED 0x80 | 243 | #define FE_UNTESTED 0x80 |
250 | 244 | ||
251 | static const struct key_entry *keymap; /* = NULL; Current key map */ | 245 | static struct key_entry *keymap; /* = NULL; Current key map */ |
252 | static int have_wifi; | 246 | static int have_wifi; |
253 | static int have_bluetooth; | 247 | static int have_bluetooth; |
248 | static int have_leds; | ||
254 | 249 | ||
255 | static int __init dmi_matched(struct dmi_system_id *dmi) | 250 | static int __init dmi_matched(struct dmi_system_id *dmi) |
256 | { | 251 | { |
@@ -263,6 +258,8 @@ static int __init dmi_matched(struct dmi_system_id *dmi) | |||
263 | else if (key->type == KE_BLUETOOTH) | 258 | else if (key->type == KE_BLUETOOTH) |
264 | have_bluetooth = 1; | 259 | have_bluetooth = 1; |
265 | } | 260 | } |
261 | have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED); | ||
262 | |||
266 | return 1; | 263 | return 1; |
267 | } | 264 | } |
268 | 265 | ||
@@ -966,118 +963,163 @@ static int __init select_keymap(void) | |||
966 | 963 | ||
967 | /* Input layer interface */ | 964 | /* Input layer interface */ |
968 | 965 | ||
969 | static struct input_dev *input_dev; | 966 | static struct input_polled_dev *wistron_idev; |
967 | static unsigned long jiffies_last_press; | ||
968 | static int wifi_enabled; | ||
969 | static int bluetooth_enabled; | ||
970 | 970 | ||
971 | static int __devinit setup_input_dev(void) | 971 | static void report_key(struct input_dev *dev, unsigned int keycode) |
972 | { | 972 | { |
973 | const struct key_entry *key; | 973 | input_report_key(dev, keycode, 1); |
974 | int error; | 974 | input_sync(dev); |
975 | input_report_key(dev, keycode, 0); | ||
976 | input_sync(dev); | ||
977 | } | ||
975 | 978 | ||
976 | input_dev = input_allocate_device(); | 979 | static void report_switch(struct input_dev *dev, unsigned int code, int value) |
977 | if (!input_dev) | 980 | { |
978 | return -ENOMEM; | 981 | input_report_switch(dev, code, value); |
982 | input_sync(dev); | ||
983 | } | ||
979 | 984 | ||
980 | input_dev->name = "Wistron laptop buttons"; | ||
981 | input_dev->phys = "wistron/input0"; | ||
982 | input_dev->id.bustype = BUS_HOST; | ||
983 | input_dev->cdev.dev = &wistron_device->dev; | ||
984 | 985 | ||
985 | for (key = keymap; key->type != KE_END; key++) { | 986 | /* led management */ |
986 | switch (key->type) { | 987 | static void wistron_mail_led_set(struct led_classdev *led_cdev, |
987 | case KE_KEY: | 988 | enum led_brightness value) |
988 | set_bit(EV_KEY, input_dev->evbit); | 989 | { |
989 | set_bit(key->keycode, input_dev->keybit); | 990 | bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0); |
990 | break; | 991 | } |
991 | 992 | ||
992 | case KE_SW: | 993 | /* same as setting up wifi card, but for laptops on which the led is managed */ |
993 | set_bit(EV_SW, input_dev->evbit); | 994 | static void wistron_wifi_led_set(struct led_classdev *led_cdev, |
994 | set_bit(key->sw.code, input_dev->swbit); | 995 | enum led_brightness value) |
995 | break; | 996 | { |
997 | bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0); | ||
998 | } | ||
996 | 999 | ||
997 | default: | 1000 | static struct led_classdev wistron_mail_led = { |
998 | ; | 1001 | .name = "mail:green", |
999 | } | 1002 | .brightness_set = wistron_mail_led_set, |
1000 | } | 1003 | }; |
1001 | 1004 | ||
1002 | /* reads information flags on KE_END */ | 1005 | static struct led_classdev wistron_wifi_led = { |
1003 | if (key->code & FE_UNTESTED) | 1006 | .name = "wifi:red", |
1004 | printk(KERN_WARNING "Untested laptop multimedia keys, " | 1007 | .brightness_set = wistron_wifi_led_set, |
1005 | "please report success or failure to eric.piel" | 1008 | }; |
1006 | "@tremplin-utc.net\n"); | ||
1007 | 1009 | ||
1008 | error = input_register_device(input_dev); | 1010 | static void __devinit wistron_led_init(struct device *parent) |
1009 | if (error) { | 1011 | { |
1010 | input_free_device(input_dev); | 1012 | if (have_leds & FE_WIFI_LED) { |
1011 | return error; | 1013 | u16 wifi = bios_get_default_setting(WIFI); |
1014 | if (wifi & 1) { | ||
1015 | wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; | ||
1016 | if (led_classdev_register(parent, &wistron_wifi_led)) | ||
1017 | have_leds &= ~FE_WIFI_LED; | ||
1018 | else | ||
1019 | bios_set_state(WIFI, wistron_wifi_led.brightness); | ||
1020 | |||
1021 | } else | ||
1022 | have_leds &= ~FE_WIFI_LED; | ||
1012 | } | 1023 | } |
1013 | 1024 | ||
1014 | return 0; | 1025 | if (have_leds & FE_MAIL_LED) { |
1026 | /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ | ||
1027 | wistron_mail_led.brightness = LED_OFF; | ||
1028 | if (led_classdev_register(parent, &wistron_mail_led)) | ||
1029 | have_leds &= ~FE_MAIL_LED; | ||
1030 | else | ||
1031 | bios_set_state(MAIL_LED, wistron_mail_led.brightness); | ||
1032 | } | ||
1015 | } | 1033 | } |
1016 | 1034 | ||
1017 | static void report_key(unsigned keycode) | 1035 | static void __devexit wistron_led_remove(void) |
1018 | { | 1036 | { |
1019 | input_report_key(input_dev, keycode, 1); | 1037 | if (have_leds & FE_MAIL_LED) |
1020 | input_sync(input_dev); | 1038 | led_classdev_unregister(&wistron_mail_led); |
1021 | input_report_key(input_dev, keycode, 0); | 1039 | |
1022 | input_sync(input_dev); | 1040 | if (have_leds & FE_WIFI_LED) |
1041 | led_classdev_unregister(&wistron_wifi_led); | ||
1023 | } | 1042 | } |
1024 | 1043 | ||
1025 | static void report_switch(unsigned code, int value) | 1044 | static inline void wistron_led_suspend(void) |
1026 | { | 1045 | { |
1027 | input_report_switch(input_dev, code, value); | 1046 | if (have_leds & FE_MAIL_LED) |
1028 | input_sync(input_dev); | 1047 | led_classdev_suspend(&wistron_mail_led); |
1048 | |||
1049 | if (have_leds & FE_WIFI_LED) | ||
1050 | led_classdev_suspend(&wistron_wifi_led); | ||
1029 | } | 1051 | } |
1030 | 1052 | ||
1031 | /* Driver core */ | 1053 | static inline void wistron_led_resume(void) |
1054 | { | ||
1055 | if (have_leds & FE_MAIL_LED) | ||
1056 | led_classdev_resume(&wistron_mail_led); | ||
1032 | 1057 | ||
1033 | static int wifi_enabled; | 1058 | if (have_leds & FE_WIFI_LED) |
1034 | static int bluetooth_enabled; | 1059 | led_classdev_resume(&wistron_wifi_led); |
1060 | } | ||
1061 | |||
1062 | static struct key_entry *wistron_get_entry_by_scancode(int code) | ||
1063 | { | ||
1064 | struct key_entry *key; | ||
1035 | 1065 | ||
1036 | static void poll_bios(unsigned long); | 1066 | for (key = keymap; key->type != KE_END; key++) |
1067 | if (code == key->code) | ||
1068 | return key; | ||
1037 | 1069 | ||
1038 | static struct timer_list poll_timer = TIMER_INITIALIZER(poll_bios, 0, 0); | 1070 | return NULL; |
1071 | } | ||
1039 | 1072 | ||
1040 | static void handle_key(u8 code) | 1073 | static struct key_entry *wistron_get_entry_by_keycode(int keycode) |
1041 | { | 1074 | { |
1042 | const struct key_entry *key; | 1075 | struct key_entry *key; |
1043 | 1076 | ||
1044 | for (key = keymap; key->type != KE_END; key++) { | 1077 | for (key = keymap; key->type != KE_END; key++) |
1045 | if (code == key->code) { | 1078 | if (key->type == KE_KEY && keycode == key->keycode) |
1046 | switch (key->type) { | 1079 | return key; |
1047 | case KE_KEY: | ||
1048 | report_key(key->keycode); | ||
1049 | break; | ||
1050 | 1080 | ||
1051 | case KE_SW: | 1081 | return NULL; |
1052 | report_switch(key->sw.code, key->sw.value); | 1082 | } |
1053 | break; | ||
1054 | 1083 | ||
1055 | case KE_WIFI: | 1084 | static void handle_key(u8 code) |
1056 | if (have_wifi) { | 1085 | { |
1057 | wifi_enabled = !wifi_enabled; | 1086 | const struct key_entry *key = wistron_get_entry_by_scancode(code); |
1058 | bios_set_state(WIFI, wifi_enabled); | ||
1059 | } | ||
1060 | break; | ||
1061 | 1087 | ||
1062 | case KE_BLUETOOTH: | 1088 | if (key) { |
1063 | if (have_bluetooth) { | 1089 | switch (key->type) { |
1064 | bluetooth_enabled = !bluetooth_enabled; | 1090 | case KE_KEY: |
1065 | bios_set_state(BLUETOOTH, bluetooth_enabled); | 1091 | report_key(wistron_idev->input, key->keycode); |
1066 | } | 1092 | break; |
1067 | break; | ||
1068 | 1093 | ||
1069 | case KE_END: | 1094 | case KE_SW: |
1070 | break; | 1095 | report_switch(wistron_idev->input, |
1071 | default: | 1096 | key->sw.code, key->sw.value); |
1072 | BUG(); | 1097 | break; |
1098 | |||
1099 | case KE_WIFI: | ||
1100 | if (have_wifi) { | ||
1101 | wifi_enabled = !wifi_enabled; | ||
1102 | bios_set_state(WIFI, wifi_enabled); | ||
1103 | } | ||
1104 | break; | ||
1105 | |||
1106 | case KE_BLUETOOTH: | ||
1107 | if (have_bluetooth) { | ||
1108 | bluetooth_enabled = !bluetooth_enabled; | ||
1109 | bios_set_state(BLUETOOTH, bluetooth_enabled); | ||
1073 | } | 1110 | } |
1074 | return; | 1111 | break; |
1112 | |||
1113 | default: | ||
1114 | BUG(); | ||
1075 | } | 1115 | } |
1076 | } | 1116 | jiffies_last_press = jiffies; |
1077 | printk(KERN_NOTICE "wistron_btns: Unknown key code %02X\n", code); | 1117 | } else |
1118 | printk(KERN_NOTICE | ||
1119 | "wistron_btns: Unknown key code %02X\n", code); | ||
1078 | } | 1120 | } |
1079 | 1121 | ||
1080 | static void poll_bios(unsigned long discard) | 1122 | static void poll_bios(bool discard) |
1081 | { | 1123 | { |
1082 | u8 qlen; | 1124 | u8 qlen; |
1083 | u16 val; | 1125 | u16 val; |
@@ -1090,15 +1132,118 @@ static void poll_bios(unsigned long discard) | |||
1090 | if (val != 0 && !discard) | 1132 | if (val != 0 && !discard) |
1091 | handle_key((u8)val); | 1133 | handle_key((u8)val); |
1092 | } | 1134 | } |
1135 | } | ||
1136 | |||
1137 | static void wistron_flush(struct input_polled_dev *dev) | ||
1138 | { | ||
1139 | /* Flush stale event queue */ | ||
1140 | poll_bios(true); | ||
1141 | } | ||
1142 | |||
1143 | static void wistron_poll(struct input_polled_dev *dev) | ||
1144 | { | ||
1145 | poll_bios(false); | ||
1146 | |||
1147 | /* Increase poll frequency if user is currently pressing keys (< 2s ago) */ | ||
1148 | if (time_before(jiffies, jiffies_last_press + 2 * HZ)) | ||
1149 | dev->poll_interval = POLL_INTERVAL_BURST; | ||
1150 | else | ||
1151 | dev->poll_interval = POLL_INTERVAL_DEFAULT; | ||
1152 | } | ||
1153 | |||
1154 | static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode) | ||
1155 | { | ||
1156 | const struct key_entry *key = wistron_get_entry_by_scancode(scancode); | ||
1157 | |||
1158 | if (key && key->type == KE_KEY) { | ||
1159 | *keycode = key->keycode; | ||
1160 | return 0; | ||
1161 | } | ||
1162 | |||
1163 | return -EINVAL; | ||
1164 | } | ||
1165 | |||
1166 | static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode) | ||
1167 | { | ||
1168 | struct key_entry *key; | ||
1169 | int old_keycode; | ||
1170 | |||
1171 | if (keycode < 0 || keycode > KEY_MAX) | ||
1172 | return -EINVAL; | ||
1173 | |||
1174 | key = wistron_get_entry_by_scancode(scancode); | ||
1175 | if (key && key->type == KE_KEY) { | ||
1176 | old_keycode = key->keycode; | ||
1177 | key->keycode = keycode; | ||
1178 | set_bit(keycode, dev->keybit); | ||
1179 | if (!wistron_get_entry_by_keycode(old_keycode)) | ||
1180 | clear_bit(old_keycode, dev->keybit); | ||
1181 | return 0; | ||
1182 | } | ||
1093 | 1183 | ||
1094 | mod_timer(&poll_timer, jiffies + HZ / POLL_FREQUENCY); | 1184 | return -EINVAL; |
1095 | } | 1185 | } |
1096 | 1186 | ||
1187 | static int __devinit setup_input_dev(void) | ||
1188 | { | ||
1189 | const struct key_entry *key; | ||
1190 | struct input_dev *input_dev; | ||
1191 | int error; | ||
1192 | |||
1193 | wistron_idev = input_allocate_polled_device(); | ||
1194 | if (!wistron_idev) | ||
1195 | return -ENOMEM; | ||
1196 | |||
1197 | wistron_idev->flush = wistron_flush; | ||
1198 | wistron_idev->poll = wistron_poll; | ||
1199 | wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT; | ||
1200 | |||
1201 | input_dev = wistron_idev->input; | ||
1202 | input_dev->name = "Wistron laptop buttons"; | ||
1203 | input_dev->phys = "wistron/input0"; | ||
1204 | input_dev->id.bustype = BUS_HOST; | ||
1205 | input_dev->dev.parent = &wistron_device->dev; | ||
1206 | |||
1207 | input_dev->getkeycode = wistron_getkeycode; | ||
1208 | input_dev->setkeycode = wistron_setkeycode; | ||
1209 | |||
1210 | for (key = keymap; key->type != KE_END; key++) { | ||
1211 | switch (key->type) { | ||
1212 | case KE_KEY: | ||
1213 | set_bit(EV_KEY, input_dev->evbit); | ||
1214 | set_bit(key->keycode, input_dev->keybit); | ||
1215 | break; | ||
1216 | |||
1217 | case KE_SW: | ||
1218 | set_bit(EV_SW, input_dev->evbit); | ||
1219 | set_bit(key->sw.code, input_dev->swbit); | ||
1220 | break; | ||
1221 | |||
1222 | default: | ||
1223 | break; | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1227 | /* reads information flags on KE_END */ | ||
1228 | if (key->code & FE_UNTESTED) | ||
1229 | printk(KERN_WARNING "Untested laptop multimedia keys, " | ||
1230 | "please report success or failure to eric.piel" | ||
1231 | "@tremplin-utc.net\n"); | ||
1232 | |||
1233 | error = input_register_polled_device(wistron_idev); | ||
1234 | if (error) { | ||
1235 | input_free_polled_device(wistron_idev); | ||
1236 | return error; | ||
1237 | } | ||
1238 | |||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | /* Driver core */ | ||
1243 | |||
1097 | static int __devinit wistron_probe(struct platform_device *dev) | 1244 | static int __devinit wistron_probe(struct platform_device *dev) |
1098 | { | 1245 | { |
1099 | int err = setup_input_dev(); | 1246 | int err; |
1100 | if (err) | ||
1101 | return err; | ||
1102 | 1247 | ||
1103 | bios_attach(); | 1248 | bios_attach(); |
1104 | cmos_address = bios_get_cmos_address(); | 1249 | cmos_address = bios_get_cmos_address(); |
@@ -1125,15 +1270,21 @@ static int __devinit wistron_probe(struct platform_device *dev) | |||
1125 | bios_set_state(BLUETOOTH, bluetooth_enabled); | 1270 | bios_set_state(BLUETOOTH, bluetooth_enabled); |
1126 | } | 1271 | } |
1127 | 1272 | ||
1128 | poll_bios(1); /* Flush stale event queue and arm timer */ | 1273 | wistron_led_init(&dev->dev); |
1274 | err = setup_input_dev(); | ||
1275 | if (err) { | ||
1276 | bios_detach(); | ||
1277 | return err; | ||
1278 | } | ||
1129 | 1279 | ||
1130 | return 0; | 1280 | return 0; |
1131 | } | 1281 | } |
1132 | 1282 | ||
1133 | static int __devexit wistron_remove(struct platform_device *dev) | 1283 | static int __devexit wistron_remove(struct platform_device *dev) |
1134 | { | 1284 | { |
1135 | del_timer_sync(&poll_timer); | 1285 | wistron_led_remove(); |
1136 | input_unregister_device(input_dev); | 1286 | input_unregister_polled_device(wistron_idev); |
1287 | input_free_polled_device(wistron_idev); | ||
1137 | bios_detach(); | 1288 | bios_detach(); |
1138 | 1289 | ||
1139 | return 0; | 1290 | return 0; |
@@ -1142,14 +1293,13 @@ static int __devexit wistron_remove(struct platform_device *dev) | |||
1142 | #ifdef CONFIG_PM | 1293 | #ifdef CONFIG_PM |
1143 | static int wistron_suspend(struct platform_device *dev, pm_message_t state) | 1294 | static int wistron_suspend(struct platform_device *dev, pm_message_t state) |
1144 | { | 1295 | { |
1145 | del_timer_sync(&poll_timer); | ||
1146 | |||
1147 | if (have_wifi) | 1296 | if (have_wifi) |
1148 | bios_set_state(WIFI, 0); | 1297 | bios_set_state(WIFI, 0); |
1149 | 1298 | ||
1150 | if (have_bluetooth) | 1299 | if (have_bluetooth) |
1151 | bios_set_state(BLUETOOTH, 0); | 1300 | bios_set_state(BLUETOOTH, 0); |
1152 | 1301 | ||
1302 | wistron_led_suspend(); | ||
1153 | return 0; | 1303 | return 0; |
1154 | } | 1304 | } |
1155 | 1305 | ||
@@ -1161,7 +1311,8 @@ static int wistron_resume(struct platform_device *dev) | |||
1161 | if (have_bluetooth) | 1311 | if (have_bluetooth) |
1162 | bios_set_state(BLUETOOTH, bluetooth_enabled); | 1312 | bios_set_state(BLUETOOTH, bluetooth_enabled); |
1163 | 1313 | ||
1164 | poll_bios(1); | 1314 | wistron_led_resume(); |
1315 | poll_bios(true); | ||
1165 | 1316 | ||
1166 | return 0; | 1317 | return 0; |
1167 | } | 1318 | } |
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 50e06e8dd05d..7bbea097cda2 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
@@ -216,4 +216,20 @@ config MOUSE_HIL | |||
216 | help | 216 | help |
217 | Say Y here to support HIL pointers. | 217 | Say Y here to support HIL pointers. |
218 | 218 | ||
219 | config MOUSE_GPIO | ||
220 | tristate "GPIO mouse" | ||
221 | depends on GENERIC_GPIO | ||
222 | select INPUT_POLLDEV | ||
223 | help | ||
224 | This driver simulates a mouse on GPIO lines of various CPUs (and some | ||
225 | other chips). | ||
226 | |||
227 | Say Y here if your device has buttons or a simple joystick connected | ||
228 | directly to GPIO lines. Your board-specific setup logic must also | ||
229 | provide a platform device and platform data saying which GPIOs are | ||
230 | used. | ||
231 | |||
232 | To compile this driver as a module, choose M here: the | ||
233 | module will be called gpio_mouse. | ||
234 | |||
219 | endif | 235 | endif |
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index aa4ba878533f..9e6e36330820 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_MOUSE_PS2) += psmouse.o | |||
15 | obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o | 15 | obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o |
16 | obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o | 16 | obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o |
17 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o | 17 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o |
18 | obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o | ||
18 | 19 | ||
19 | psmouse-objs := psmouse-base.o synaptics.o | 20 | psmouse-objs := psmouse-base.o synaptics.o |
20 | 21 | ||
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c new file mode 100644 index 000000000000..0936d6ba015c --- /dev/null +++ b/drivers/input/mouse/gpio_mouse.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Driver for simulating a mouse on GPIO lines. | ||
3 | * | ||
4 | * Copyright (C) 2007 Atmel Corporation | ||
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 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/version.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/input-polldev.h> | ||
16 | #include <linux/gpio_mouse.h> | ||
17 | |||
18 | #include <asm/gpio.h> | ||
19 | |||
20 | /* | ||
21 | * Timer function which is run every scan_ms ms when the device is opened. | ||
22 | * The dev input varaible is set to the the input_dev pointer. | ||
23 | */ | ||
24 | static void gpio_mouse_scan(struct input_polled_dev *dev) | ||
25 | { | ||
26 | struct gpio_mouse_platform_data *gpio = dev->private; | ||
27 | struct input_dev *input = dev->input; | ||
28 | int x, y; | ||
29 | |||
30 | if (gpio->bleft >= 0) | ||
31 | input_report_key(input, BTN_LEFT, | ||
32 | gpio_get_value(gpio->bleft) ^ gpio->polarity); | ||
33 | if (gpio->bmiddle >= 0) | ||
34 | input_report_key(input, BTN_MIDDLE, | ||
35 | gpio_get_value(gpio->bmiddle) ^ gpio->polarity); | ||
36 | if (gpio->bright >= 0) | ||
37 | input_report_key(input, BTN_RIGHT, | ||
38 | gpio_get_value(gpio->bright) ^ gpio->polarity); | ||
39 | |||
40 | x = (gpio_get_value(gpio->right) ^ gpio->polarity) | ||
41 | - (gpio_get_value(gpio->left) ^ gpio->polarity); | ||
42 | y = (gpio_get_value(gpio->down) ^ gpio->polarity) | ||
43 | - (gpio_get_value(gpio->up) ^ gpio->polarity); | ||
44 | |||
45 | input_report_rel(input, REL_X, x); | ||
46 | input_report_rel(input, REL_Y, y); | ||
47 | input_sync(input); | ||
48 | } | ||
49 | |||
50 | static int __init gpio_mouse_probe(struct platform_device *pdev) | ||
51 | { | ||
52 | struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data; | ||
53 | struct input_polled_dev *input_poll; | ||
54 | struct input_dev *input; | ||
55 | int pin, i; | ||
56 | int error; | ||
57 | |||
58 | if (!pdata) { | ||
59 | dev_err(&pdev->dev, "no platform data\n"); | ||
60 | error = -ENXIO; | ||
61 | goto out; | ||
62 | } | ||
63 | |||
64 | if (pdata->scan_ms < 0) { | ||
65 | dev_err(&pdev->dev, "invalid scan time\n"); | ||
66 | error = -EINVAL; | ||
67 | goto out; | ||
68 | } | ||
69 | |||
70 | for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) { | ||
71 | pin = pdata->pins[i]; | ||
72 | |||
73 | if (pin < 0) { | ||
74 | |||
75 | if (i <= GPIO_MOUSE_PIN_RIGHT) { | ||
76 | /* Mouse direction is required. */ | ||
77 | dev_err(&pdev->dev, | ||
78 | "missing GPIO for directions\n"); | ||
79 | error = -EINVAL; | ||
80 | goto out_free_gpios; | ||
81 | } | ||
82 | |||
83 | if (i == GPIO_MOUSE_PIN_BLEFT) | ||
84 | dev_dbg(&pdev->dev, "no left button defined\n"); | ||
85 | |||
86 | } else { | ||
87 | error = gpio_request(pin, "gpio_mouse"); | ||
88 | if (error) { | ||
89 | dev_err(&pdev->dev, "fail %d pin (%d idx)\n", | ||
90 | pin, i); | ||
91 | goto out_free_gpios; | ||
92 | } | ||
93 | |||
94 | gpio_direction_input(pin); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | input_poll = input_allocate_polled_device(); | ||
99 | if (!input_poll) { | ||
100 | dev_err(&pdev->dev, "not enough memory for input device\n"); | ||
101 | error = -ENOMEM; | ||
102 | goto out_free_gpios; | ||
103 | } | ||
104 | |||
105 | platform_set_drvdata(pdev, input_poll); | ||
106 | |||
107 | /* set input-polldev handlers */ | ||
108 | input_poll->private = pdata; | ||
109 | input_poll->poll = gpio_mouse_scan; | ||
110 | input_poll->poll_interval = pdata->scan_ms; | ||
111 | |||
112 | input = input_poll->input; | ||
113 | input->name = pdev->name; | ||
114 | input->id.bustype = BUS_HOST; | ||
115 | input->dev.parent = &pdev->dev; | ||
116 | |||
117 | input_set_capability(input, EV_REL, REL_X); | ||
118 | input_set_capability(input, EV_REL, REL_Y); | ||
119 | if (pdata->bleft >= 0) | ||
120 | input_set_capability(input, EV_KEY, BTN_LEFT); | ||
121 | if (pdata->bmiddle >= 0) | ||
122 | input_set_capability(input, EV_KEY, BTN_MIDDLE); | ||
123 | if (pdata->bright >= 0) | ||
124 | input_set_capability(input, EV_KEY, BTN_RIGHT); | ||
125 | |||
126 | error = input_register_polled_device(input_poll); | ||
127 | if (error) { | ||
128 | dev_err(&pdev->dev, "could not register input device\n"); | ||
129 | goto out_free_polldev; | ||
130 | } | ||
131 | |||
132 | dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n", | ||
133 | pdata->scan_ms, | ||
134 | pdata->bleft < 0 ? "" : "left ", | ||
135 | pdata->bmiddle < 0 ? "" : "middle ", | ||
136 | pdata->bright < 0 ? "" : "right"); | ||
137 | |||
138 | return 0; | ||
139 | |||
140 | out_free_polldev: | ||
141 | input_free_polled_device(input_poll); | ||
142 | platform_set_drvdata(pdev, NULL); | ||
143 | |||
144 | out_free_gpios: | ||
145 | while (--i >= 0) { | ||
146 | pin = pdata->pins[i]; | ||
147 | if (pin) | ||
148 | gpio_free(pin); | ||
149 | } | ||
150 | out: | ||
151 | return error; | ||
152 | } | ||
153 | |||
154 | static int __devexit gpio_mouse_remove(struct platform_device *pdev) | ||
155 | { | ||
156 | struct input_polled_dev *input = platform_get_drvdata(pdev); | ||
157 | struct gpio_mouse_platform_data *pdata = input->private; | ||
158 | int pin, i; | ||
159 | |||
160 | input_unregister_polled_device(input); | ||
161 | input_free_polled_device(input); | ||
162 | |||
163 | for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) { | ||
164 | pin = pdata->pins[i]; | ||
165 | if (pin >= 0) | ||
166 | gpio_free(pin); | ||
167 | } | ||
168 | |||
169 | platform_set_drvdata(pdev, NULL); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | struct platform_driver gpio_mouse_device_driver = { | ||
175 | .remove = __devexit_p(gpio_mouse_remove), | ||
176 | .driver = { | ||
177 | .name = "gpio_mouse", | ||
178 | } | ||
179 | }; | ||
180 | |||
181 | static int __init gpio_mouse_init(void) | ||
182 | { | ||
183 | return platform_driver_probe(&gpio_mouse_device_driver, | ||
184 | gpio_mouse_probe); | ||
185 | } | ||
186 | module_init(gpio_mouse_init); | ||
187 | |||
188 | static void __exit gpio_mouse_exit(void) | ||
189 | { | ||
190 | platform_driver_unregister(&gpio_mouse_device_driver); | ||
191 | } | ||
192 | module_exit(gpio_mouse_exit); | ||
193 | |||
194 | MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); | ||
195 | MODULE_DESCRIPTION("GPIO mouse driver"); | ||
196 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index f15f695777f8..b9f0fb2530e2 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -178,6 +178,15 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) | |||
178 | } | 178 | } |
179 | 179 | ||
180 | /* | 180 | /* |
181 | * Cortron PS2 Trackball reports SIDE button on the 4th bit of the first | ||
182 | * byte. | ||
183 | */ | ||
184 | if (psmouse->type == PSMOUSE_CORTRON) { | ||
185 | input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1); | ||
186 | packet[0] |= 0x08; | ||
187 | } | ||
188 | |||
189 | /* | ||
181 | * Generic PS/2 Mouse | 190 | * Generic PS/2 Mouse |
182 | */ | 191 | */ |
183 | 192 | ||
@@ -539,6 +548,20 @@ static int ps2bare_detect(struct psmouse *psmouse, int set_properties) | |||
539 | return 0; | 548 | return 0; |
540 | } | 549 | } |
541 | 550 | ||
551 | /* | ||
552 | * Cortron PS/2 protocol detection. There's no special way to detect it, so it | ||
553 | * must be forced by sysfs protocol writing. | ||
554 | */ | ||
555 | static int cortron_detect(struct psmouse *psmouse, int set_properties) | ||
556 | { | ||
557 | if (set_properties) { | ||
558 | psmouse->vendor = "Cortron"; | ||
559 | psmouse->name = "PS/2 Trackball"; | ||
560 | set_bit(BTN_SIDE, psmouse->dev->keybit); | ||
561 | } | ||
562 | |||
563 | return 0; | ||
564 | } | ||
542 | 565 | ||
543 | /* | 566 | /* |
544 | * psmouse_extensions() probes for any extensions to the basic PS/2 protocol | 567 | * psmouse_extensions() probes for any extensions to the basic PS/2 protocol |
@@ -740,6 +763,12 @@ static const struct psmouse_protocol psmouse_protocols[] = { | |||
740 | }, | 763 | }, |
741 | #endif | 764 | #endif |
742 | { | 765 | { |
766 | .type = PSMOUSE_CORTRON, | ||
767 | .name = "CortronPS/2", | ||
768 | .alias = "cortps", | ||
769 | .detect = cortron_detect, | ||
770 | }, | ||
771 | { | ||
743 | .type = PSMOUSE_AUTO, | 772 | .type = PSMOUSE_AUTO, |
744 | .name = "auto", | 773 | .name = "auto", |
745 | .alias = "any", | 774 | .alias = "any", |
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 3964e8acbc54..27a68835b5ba 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
@@ -88,6 +88,7 @@ enum psmouse_type { | |||
88 | PSMOUSE_LIFEBOOK, | 88 | PSMOUSE_LIFEBOOK, |
89 | PSMOUSE_TRACKPOINT, | 89 | PSMOUSE_TRACKPOINT, |
90 | PSMOUSE_TOUCHKIT_PS2, | 90 | PSMOUSE_TOUCHKIT_PS2, |
91 | PSMOUSE_CORTRON, | ||
91 | PSMOUSE_AUTO /* This one should always be last */ | 92 | PSMOUSE_AUTO /* This one should always be last */ |
92 | }; | 93 | }; |
93 | 94 | ||
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 3f4866d8d18c..9173916b8be5 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
@@ -64,6 +64,7 @@ struct mousedev { | |||
64 | wait_queue_head_t wait; | 64 | wait_queue_head_t wait; |
65 | struct list_head client_list; | 65 | struct list_head client_list; |
66 | struct input_handle handle; | 66 | struct input_handle handle; |
67 | struct device dev; | ||
67 | 68 | ||
68 | struct list_head mixdev_node; | 69 | struct list_head mixdev_node; |
69 | int mixdev_open; | 70 | int mixdev_open; |
@@ -112,7 +113,7 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | |||
112 | static struct input_handler mousedev_handler; | 113 | static struct input_handler mousedev_handler; |
113 | 114 | ||
114 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | 115 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; |
115 | static struct mousedev mousedev_mix; | 116 | static struct mousedev *mousedev_mix; |
116 | static LIST_HEAD(mousedev_mix_list); | 117 | static LIST_HEAD(mousedev_mix_list); |
117 | 118 | ||
118 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) | 119 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) |
@@ -218,10 +219,10 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int | |||
218 | 219 | ||
219 | if (value) { | 220 | if (value) { |
220 | set_bit(index, &mousedev->packet.buttons); | 221 | set_bit(index, &mousedev->packet.buttons); |
221 | set_bit(index, &mousedev_mix.packet.buttons); | 222 | set_bit(index, &mousedev_mix->packet.buttons); |
222 | } else { | 223 | } else { |
223 | clear_bit(index, &mousedev->packet.buttons); | 224 | clear_bit(index, &mousedev->packet.buttons); |
224 | clear_bit(index, &mousedev_mix.packet.buttons); | 225 | clear_bit(index, &mousedev_mix->packet.buttons); |
225 | } | 226 | } |
226 | } | 227 | } |
227 | 228 | ||
@@ -287,11 +288,11 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
287 | * motion packet so we won't mess current position. | 288 | * motion packet so we won't mess current position. |
288 | */ | 289 | */ |
289 | set_bit(0, &mousedev->packet.buttons); | 290 | set_bit(0, &mousedev->packet.buttons); |
290 | set_bit(0, &mousedev_mix.packet.buttons); | 291 | set_bit(0, &mousedev_mix->packet.buttons); |
291 | mousedev_notify_readers(mousedev, &mousedev_mix.packet); | 292 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); |
292 | mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet); | 293 | mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet); |
293 | clear_bit(0, &mousedev->packet.buttons); | 294 | clear_bit(0, &mousedev->packet.buttons); |
294 | clear_bit(0, &mousedev_mix.packet.buttons); | 295 | clear_bit(0, &mousedev_mix->packet.buttons); |
295 | } | 296 | } |
296 | mousedev->touch = mousedev->pkt_count = 0; | 297 | mousedev->touch = mousedev->pkt_count = 0; |
297 | mousedev->frac_dx = 0; | 298 | mousedev->frac_dx = 0; |
@@ -343,7 +344,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig | |||
343 | } | 344 | } |
344 | 345 | ||
345 | mousedev_notify_readers(mousedev, &mousedev->packet); | 346 | mousedev_notify_readers(mousedev, &mousedev->packet); |
346 | mousedev_notify_readers(&mousedev_mix, &mousedev->packet); | 347 | mousedev_notify_readers(mousedev_mix, &mousedev->packet); |
347 | 348 | ||
348 | mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; | 349 | mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; |
349 | mousedev->packet.abs_event = 0; | 350 | mousedev->packet.abs_event = 0; |
@@ -362,8 +363,10 @@ static int mousedev_fasync(int fd, struct file *file, int on) | |||
362 | return retval < 0 ? retval : 0; | 363 | return retval < 0 ? retval : 0; |
363 | } | 364 | } |
364 | 365 | ||
365 | static void mousedev_free(struct mousedev *mousedev) | 366 | static void mousedev_free(struct device *dev) |
366 | { | 367 | { |
368 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); | ||
369 | |||
367 | mousedev_table[mousedev->minor] = NULL; | 370 | mousedev_table[mousedev->minor] = NULL; |
368 | kfree(mousedev); | 371 | kfree(mousedev); |
369 | } | 372 | } |
@@ -372,15 +375,16 @@ static int mixdev_add_device(struct mousedev *mousedev) | |||
372 | { | 375 | { |
373 | int error; | 376 | int error; |
374 | 377 | ||
375 | if (mousedev_mix.open) { | 378 | if (mousedev_mix->open) { |
376 | error = input_open_device(&mousedev->handle); | 379 | error = input_open_device(&mousedev->handle); |
377 | if (error) | 380 | if (error) |
378 | return error; | 381 | return error; |
379 | 382 | ||
380 | mousedev->open++; | 383 | mousedev->open++; |
381 | mousedev->mixdev_open++; | 384 | mousedev->mixdev_open = 1; |
382 | } | 385 | } |
383 | 386 | ||
387 | get_device(&mousedev->dev); | ||
384 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | 388 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); |
385 | 389 | ||
386 | return 0; | 390 | return 0; |
@@ -395,36 +399,40 @@ static void mixdev_remove_device(struct mousedev *mousedev) | |||
395 | } | 399 | } |
396 | 400 | ||
397 | list_del_init(&mousedev->mixdev_node); | 401 | list_del_init(&mousedev->mixdev_node); |
402 | put_device(&mousedev->dev); | ||
398 | } | 403 | } |
399 | 404 | ||
400 | static void mixdev_open_devices(void) | 405 | static void mixdev_open_devices(void) |
401 | { | 406 | { |
402 | struct mousedev *mousedev; | 407 | struct mousedev *mousedev; |
403 | 408 | ||
409 | if (mousedev_mix->open++) | ||
410 | return; | ||
411 | |||
404 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 412 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
405 | if (mousedev->exist && !mousedev->open) { | 413 | if (!mousedev->mixdev_open) { |
406 | if (input_open_device(&mousedev->handle)) | 414 | if (!mousedev->open && mousedev->exist) |
407 | continue; | 415 | if (input_open_device(&mousedev->handle)) |
416 | continue; | ||
408 | 417 | ||
409 | mousedev->open++; | 418 | mousedev->open++; |
410 | mousedev->mixdev_open++; | 419 | mousedev->mixdev_open = 1; |
411 | } | 420 | } |
412 | } | 421 | } |
413 | } | 422 | } |
414 | 423 | ||
415 | static void mixdev_close_devices(void) | 424 | static void mixdev_close_devices(void) |
416 | { | 425 | { |
417 | struct mousedev *mousedev, *next; | 426 | struct mousedev *mousedev; |
418 | 427 | ||
419 | list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) { | 428 | if (--mousedev_mix->open) |
429 | return; | ||
430 | |||
431 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | ||
420 | if (mousedev->mixdev_open) { | 432 | if (mousedev->mixdev_open) { |
421 | mousedev->mixdev_open = 0; | 433 | mousedev->mixdev_open = 0; |
422 | if (!--mousedev->open) { | 434 | if (!--mousedev->open && mousedev->exist) |
423 | if (mousedev->exist) | 435 | input_close_device(&mousedev->handle); |
424 | input_close_device(&mousedev->handle); | ||
425 | else | ||
426 | mousedev_free(mousedev); | ||
427 | } | ||
428 | } | 436 | } |
429 | } | 437 | } |
430 | } | 438 | } |
@@ -439,14 +447,12 @@ static int mousedev_release(struct inode *inode, struct file *file) | |||
439 | list_del(&client->node); | 447 | list_del(&client->node); |
440 | kfree(client); | 448 | kfree(client); |
441 | 449 | ||
442 | if (!--mousedev->open) { | 450 | if (mousedev->minor == MOUSEDEV_MIX) |
443 | if (mousedev->minor == MOUSEDEV_MIX) | 451 | mixdev_close_devices(); |
444 | mixdev_close_devices(); | 452 | else if (!--mousedev->open && mousedev->exist) |
445 | else if (mousedev->exist) | 453 | input_close_device(&mousedev->handle); |
446 | input_close_device(&mousedev->handle); | 454 | |
447 | else | 455 | put_device(&mousedev->dev); |
448 | mousedev_free(mousedev); | ||
449 | } | ||
450 | 456 | ||
451 | return 0; | 457 | return 0; |
452 | } | 458 | } |
@@ -473,9 +479,13 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
473 | if (!mousedev) | 479 | if (!mousedev) |
474 | return -ENODEV; | 480 | return -ENODEV; |
475 | 481 | ||
482 | get_device(&mousedev->dev); | ||
483 | |||
476 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | 484 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
477 | if (!client) | 485 | if (!client) { |
478 | return -ENOMEM; | 486 | error = -ENOMEM; |
487 | goto err_put_mousedev; | ||
488 | } | ||
479 | 489 | ||
480 | spin_lock_init(&client->packet_lock); | 490 | spin_lock_init(&client->packet_lock); |
481 | client->pos_x = xres / 2; | 491 | client->pos_x = xres / 2; |
@@ -483,21 +493,23 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
483 | client->mousedev = mousedev; | 493 | client->mousedev = mousedev; |
484 | list_add_tail(&client->node, &mousedev->client_list); | 494 | list_add_tail(&client->node, &mousedev->client_list); |
485 | 495 | ||
486 | if (!mousedev->open++) { | 496 | if (mousedev->minor == MOUSEDEV_MIX) |
487 | if (mousedev->minor == MOUSEDEV_MIX) | 497 | mixdev_open_devices(); |
488 | mixdev_open_devices(); | 498 | else if (!mousedev->open++ && mousedev->exist) { |
489 | else if (mousedev->exist) { | 499 | error = input_open_device(&mousedev->handle); |
490 | error = input_open_device(&mousedev->handle); | 500 | if (error) |
491 | if (error) { | 501 | goto err_free_client; |
492 | list_del(&client->node); | ||
493 | kfree(client); | ||
494 | return error; | ||
495 | } | ||
496 | } | ||
497 | } | 502 | } |
498 | 503 | ||
499 | file->private_data = client; | 504 | file->private_data = client; |
500 | return 0; | 505 | return 0; |
506 | |||
507 | err_free_client: | ||
508 | list_del(&client->node); | ||
509 | kfree(client); | ||
510 | err_put_mousedev: | ||
511 | put_device(&mousedev->dev); | ||
512 | return error; | ||
501 | } | 513 | } |
502 | 514 | ||
503 | static inline int mousedev_limit_delta(int delta, int limit) | 515 | static inline int mousedev_limit_delta(int delta, int limit) |
@@ -680,57 +692,96 @@ static const struct file_operations mousedev_fops = { | |||
680 | .fasync = mousedev_fasync, | 692 | .fasync = mousedev_fasync, |
681 | }; | 693 | }; |
682 | 694 | ||
683 | static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, | 695 | static struct mousedev *mousedev_create(struct input_dev *dev, |
684 | const struct input_device_id *id) | 696 | struct input_handler *handler, |
697 | int minor) | ||
685 | { | 698 | { |
686 | struct mousedev *mousedev; | 699 | struct mousedev *mousedev; |
687 | struct class_device *cdev; | ||
688 | dev_t devt; | ||
689 | int minor; | ||
690 | int error; | 700 | int error; |
691 | 701 | ||
692 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | ||
693 | if (minor == MOUSEDEV_MINORS) { | ||
694 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | ||
695 | return -ENFILE; | ||
696 | } | ||
697 | |||
698 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); | 702 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); |
699 | if (!mousedev) | 703 | if (!mousedev) { |
700 | return -ENOMEM; | 704 | error = -ENOMEM; |
705 | goto err_out; | ||
706 | } | ||
701 | 707 | ||
702 | INIT_LIST_HEAD(&mousedev->client_list); | 708 | INIT_LIST_HEAD(&mousedev->client_list); |
703 | INIT_LIST_HEAD(&mousedev->mixdev_node); | 709 | INIT_LIST_HEAD(&mousedev->mixdev_node); |
704 | init_waitqueue_head(&mousedev->wait); | 710 | init_waitqueue_head(&mousedev->wait); |
705 | 711 | ||
712 | if (minor == MOUSEDEV_MIX) | ||
713 | strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); | ||
714 | else | ||
715 | snprintf(mousedev->name, sizeof(mousedev->name), | ||
716 | "mouse%d", minor); | ||
717 | |||
706 | mousedev->minor = minor; | 718 | mousedev->minor = minor; |
707 | mousedev->exist = 1; | 719 | mousedev->exist = 1; |
708 | mousedev->handle.dev = dev; | 720 | mousedev->handle.dev = dev; |
709 | mousedev->handle.name = mousedev->name; | 721 | mousedev->handle.name = mousedev->name; |
710 | mousedev->handle.handler = handler; | 722 | mousedev->handle.handler = handler; |
711 | mousedev->handle.private = mousedev; | 723 | mousedev->handle.private = mousedev; |
712 | sprintf(mousedev->name, "mouse%d", minor); | ||
713 | 724 | ||
714 | mousedev_table[minor] = mousedev; | 725 | strlcpy(mousedev->dev.bus_id, mousedev->name, |
726 | sizeof(mousedev->dev.bus_id)); | ||
727 | mousedev->dev.class = &input_class; | ||
728 | if (dev) | ||
729 | mousedev->dev.parent = &dev->dev; | ||
730 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); | ||
731 | mousedev->dev.release = mousedev_free; | ||
732 | device_initialize(&mousedev->dev); | ||
715 | 733 | ||
716 | devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), | 734 | mousedev_table[minor] = mousedev; |
717 | 735 | ||
718 | cdev = class_device_create(&input_class, &dev->cdev, devt, | 736 | error = device_add(&mousedev->dev); |
719 | dev->cdev.dev, mousedev->name); | 737 | if (error) |
720 | if (IS_ERR(cdev)) { | ||
721 | error = PTR_ERR(cdev); | ||
722 | goto err_free_mousedev; | 738 | goto err_free_mousedev; |
739 | |||
740 | return mousedev; | ||
741 | |||
742 | err_free_mousedev: | ||
743 | put_device(&mousedev->dev); | ||
744 | err_out: | ||
745 | return ERR_PTR(error); | ||
746 | } | ||
747 | |||
748 | static void mousedev_destroy(struct mousedev *mousedev) | ||
749 | { | ||
750 | struct mousedev_client *client; | ||
751 | |||
752 | device_del(&mousedev->dev); | ||
753 | mousedev->exist = 0; | ||
754 | |||
755 | if (mousedev->open) { | ||
756 | input_close_device(&mousedev->handle); | ||
757 | list_for_each_entry(client, &mousedev->client_list, node) | ||
758 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
759 | wake_up_interruptible(&mousedev->wait); | ||
723 | } | 760 | } |
724 | 761 | ||
725 | /* temporary symlink to keep userspace happy */ | 762 | put_device(&mousedev->dev); |
726 | error = sysfs_create_link(&input_class.subsys.kobj, | 763 | } |
727 | &cdev->kobj, mousedev->name); | 764 | |
728 | if (error) | 765 | static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, |
729 | goto err_cdev_destroy; | 766 | const struct input_device_id *id) |
767 | { | ||
768 | struct mousedev *mousedev; | ||
769 | int minor; | ||
770 | int error; | ||
771 | |||
772 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | ||
773 | if (minor == MOUSEDEV_MINORS) { | ||
774 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | ||
775 | return -ENFILE; | ||
776 | } | ||
777 | |||
778 | mousedev = mousedev_create(dev, handler, minor); | ||
779 | if (IS_ERR(mousedev)) | ||
780 | return PTR_ERR(mousedev); | ||
730 | 781 | ||
731 | error = input_register_handle(&mousedev->handle); | 782 | error = input_register_handle(&mousedev->handle); |
732 | if (error) | 783 | if (error) |
733 | goto err_remove_link; | 784 | goto err_delete_mousedev; |
734 | 785 | ||
735 | error = mixdev_add_device(mousedev); | 786 | error = mixdev_add_device(mousedev); |
736 | if (error) | 787 | if (error) |
@@ -740,37 +791,18 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev | |||
740 | 791 | ||
741 | err_unregister_handle: | 792 | err_unregister_handle: |
742 | input_unregister_handle(&mousedev->handle); | 793 | input_unregister_handle(&mousedev->handle); |
743 | err_remove_link: | 794 | err_delete_mousedev: |
744 | sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); | 795 | device_unregister(&mousedev->dev); |
745 | err_cdev_destroy: | ||
746 | class_device_destroy(&input_class, devt); | ||
747 | err_free_mousedev: | ||
748 | mousedev_table[minor] = NULL; | ||
749 | kfree(mousedev); | ||
750 | return error; | 796 | return error; |
751 | } | 797 | } |
752 | 798 | ||
753 | static void mousedev_disconnect(struct input_handle *handle) | 799 | static void mousedev_disconnect(struct input_handle *handle) |
754 | { | 800 | { |
755 | struct mousedev *mousedev = handle->private; | 801 | struct mousedev *mousedev = handle->private; |
756 | struct mousedev_client *client; | ||
757 | |||
758 | input_unregister_handle(handle); | ||
759 | |||
760 | sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); | ||
761 | class_device_destroy(&input_class, | ||
762 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); | ||
763 | mousedev->exist = 0; | ||
764 | 802 | ||
765 | mixdev_remove_device(mousedev); | 803 | mixdev_remove_device(mousedev); |
766 | 804 | input_unregister_handle(handle); | |
767 | if (mousedev->open) { | 805 | mousedev_destroy(mousedev); |
768 | input_close_device(handle); | ||
769 | list_for_each_entry(client, &mousedev->client_list, node) | ||
770 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
771 | wake_up_interruptible(&mousedev->wait); | ||
772 | } else | ||
773 | mousedev_free(mousedev); | ||
774 | } | 806 | } |
775 | 807 | ||
776 | static const struct input_device_id mousedev_ids[] = { | 808 | static const struct input_device_id mousedev_ids[] = { |
@@ -822,25 +854,16 @@ static int psaux_registered; | |||
822 | 854 | ||
823 | static int __init mousedev_init(void) | 855 | static int __init mousedev_init(void) |
824 | { | 856 | { |
825 | struct class_device *cdev; | ||
826 | int error; | 857 | int error; |
827 | 858 | ||
859 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); | ||
860 | if (IS_ERR(mousedev_mix)) | ||
861 | return PTR_ERR(mousedev_mix); | ||
862 | |||
828 | error = input_register_handler(&mousedev_handler); | 863 | error = input_register_handler(&mousedev_handler); |
829 | if (error) | 864 | if (error) { |
865 | mousedev_destroy(mousedev_mix); | ||
830 | return error; | 866 | return error; |
831 | |||
832 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); | ||
833 | INIT_LIST_HEAD(&mousedev_mix.client_list); | ||
834 | init_waitqueue_head(&mousedev_mix.wait); | ||
835 | mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; | ||
836 | mousedev_mix.exist = 1; | ||
837 | mousedev_mix.minor = MOUSEDEV_MIX; | ||
838 | |||
839 | cdev = class_device_create(&input_class, NULL, | ||
840 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); | ||
841 | if (IS_ERR(cdev)) { | ||
842 | input_unregister_handler(&mousedev_handler); | ||
843 | return PTR_ERR(cdev); | ||
844 | } | 867 | } |
845 | 868 | ||
846 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 869 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
@@ -863,9 +886,8 @@ static void __exit mousedev_exit(void) | |||
863 | if (psaux_registered) | 886 | if (psaux_registered) |
864 | misc_deregister(&psaux_mouse); | 887 | misc_deregister(&psaux_mouse); |
865 | #endif | 888 | #endif |
866 | class_device_destroy(&input_class, | ||
867 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); | ||
868 | input_unregister_handler(&mousedev_handler); | 889 | input_unregister_handler(&mousedev_handler); |
890 | mousedev_destroy(mousedev_mix); | ||
869 | } | 891 | } |
870 | 892 | ||
871 | module_init(mousedev_init); | 893 | module_init(mousedev_init); |
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 887357666c68..0403622ae267 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c | |||
@@ -160,7 +160,7 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t cou | |||
160 | { | 160 | { |
161 | struct serio_raw_list *list = file->private_data; | 161 | struct serio_raw_list *list = file->private_data; |
162 | struct serio_raw *serio_raw = list->serio_raw; | 162 | struct serio_raw *serio_raw = list->serio_raw; |
163 | char c; | 163 | char uninitialized_var(c); |
164 | ssize_t retval = 0; | 164 | ssize_t retval = 0; |
165 | 165 | ||
166 | if (!serio_raw->serio) | 166 | if (!serio_raw->serio) |
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index cc0a498763d8..94683f58c9e1 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c | |||
@@ -82,8 +82,8 @@ | |||
82 | /* | 82 | /* |
83 | * Version Information | 83 | * Version Information |
84 | */ | 84 | */ |
85 | #define DRIVER_VERSION "v1.5 (May-15-2004)" | 85 | #define DRIVER_VERSION "v2.3 (May 2, 2007)" |
86 | #define DRIVER_AUTHOR "Bryan W. Headley/Chris Atenasio" | 86 | #define DRIVER_AUTHOR "Bryan W. Headley/Chris Atenasio/Cedric Brun/Rene van Paassen" |
87 | #define DRIVER_DESC "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)" | 87 | #define DRIVER_DESC "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)" |
88 | 88 | ||
89 | /* | 89 | /* |
@@ -112,7 +112,7 @@ | |||
112 | * (returned as Report 3 - absolute coordinates from the mouse) | 112 | * (returned as Report 3 - absolute coordinates from the mouse) |
113 | * | 113 | * |
114 | * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 | 114 | * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 |
115 | * byte0 0 0 0 0 0 0 1 0 | 115 | * byte0 0 0 0 0 0 0 1 1 |
116 | * byte1 X7 X6 X5 X4 X3 X2 X1 X0 | 116 | * byte1 X7 X6 X5 X4 X3 X2 X1 X0 |
117 | * byte2 X15 X14 X13 X12 X11 X10 X9 X8 | 117 | * byte2 X15 X14 X13 X12 X11 X10 X9 X8 |
118 | * byte3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 | 118 | * byte3 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 |
@@ -134,7 +134,7 @@ | |||
134 | * (returned as Report 5 - macrokeys from the mouse) | 134 | * (returned as Report 5 - macrokeys from the mouse) |
135 | * | 135 | * |
136 | * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 | 136 | * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 |
137 | * byte0 0 0 0 0 0 1 0 0 | 137 | * byte0 0 0 0 0 0 1 0 1 |
138 | * byte1 0 0 0 BS2 BS Tip IR DV | 138 | * byte1 0 0 0 BS2 BS Tip IR DV |
139 | * byte2 0 0 0 0 0 0 1 0 | 139 | * byte2 0 0 0 0 0 0 1 0 |
140 | * byte3 0 0 0 K4 K3 K2 K1 K0 | 140 | * byte3 0 0 0 K4 K3 K2 K1 K0 |
@@ -218,15 +218,9 @@ | |||
218 | #define AIPTEK_WHEEL_DISABLE (-10101) | 218 | #define AIPTEK_WHEEL_DISABLE (-10101) |
219 | 219 | ||
220 | /* ToolCode values, which BTW are 0x140 .. 0x14f | 220 | /* ToolCode values, which BTW are 0x140 .. 0x14f |
221 | * We have things set up such that if TOOL_BUTTON_FIRED_BIT is | 221 | * We have things set up such that if the tool button has changed, |
222 | * not set, we'll send one instance of AIPTEK_TOOL_BUTTON_xxx. | 222 | * the tools get reset. |
223 | * | ||
224 | * Whenever the user resets the value, TOOL_BUTTON_FIRED_BIT will | ||
225 | * get reset. | ||
226 | */ | 223 | */ |
227 | #define TOOL_BUTTON(x) ((x) & 0x14f) | ||
228 | #define TOOL_BUTTON_FIRED(x) ((x) & 0x200) | ||
229 | #define TOOL_BUTTON_FIRED_BIT 0x200 | ||
230 | /* toolMode codes | 224 | /* toolMode codes |
231 | */ | 225 | */ |
232 | #define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN | 226 | #define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN |
@@ -264,9 +258,9 @@ | |||
264 | 258 | ||
265 | /* Mouse button programming | 259 | /* Mouse button programming |
266 | */ | 260 | */ |
267 | #define AIPTEK_MOUSE_LEFT_BUTTON 0x01 | 261 | #define AIPTEK_MOUSE_LEFT_BUTTON 0x04 |
268 | #define AIPTEK_MOUSE_RIGHT_BUTTON 0x02 | 262 | #define AIPTEK_MOUSE_RIGHT_BUTTON 0x08 |
269 | #define AIPTEK_MOUSE_MIDDLE_BUTTON 0x04 | 263 | #define AIPTEK_MOUSE_MIDDLE_BUTTON 0x10 |
270 | 264 | ||
271 | /* Stylus button programming | 265 | /* Stylus button programming |
272 | */ | 266 | */ |
@@ -294,7 +288,6 @@ struct aiptek_features { | |||
294 | int modelCode; /* Tablet model code (not unique) */ | 288 | int modelCode; /* Tablet model code (not unique) */ |
295 | int firmwareCode; /* prom/eeprom version */ | 289 | int firmwareCode; /* prom/eeprom version */ |
296 | char usbPath[64 + 1]; /* device's physical usb path */ | 290 | char usbPath[64 + 1]; /* device's physical usb path */ |
297 | char inputPath[64 + 1]; /* input device path */ | ||
298 | }; | 291 | }; |
299 | 292 | ||
300 | struct aiptek_settings { | 293 | struct aiptek_settings { |
@@ -327,9 +320,32 @@ struct aiptek { | |||
327 | int inDelay; /* jitter: in jitter delay? */ | 320 | int inDelay; /* jitter: in jitter delay? */ |
328 | unsigned long endDelay; /* jitter: time when delay ends */ | 321 | unsigned long endDelay; /* jitter: time when delay ends */ |
329 | int previousJitterable; /* jitterable prev value */ | 322 | int previousJitterable; /* jitterable prev value */ |
323 | |||
324 | int lastMacro; /* macro key to reset */ | ||
325 | int previousToolMode; /* pen, pencil, brush, etc. tool */ | ||
330 | unsigned char *data; /* incoming packet data */ | 326 | unsigned char *data; /* incoming packet data */ |
331 | }; | 327 | }; |
332 | 328 | ||
329 | static const int eventTypes[] = { | ||
330 | EV_KEY, EV_ABS, EV_REL, EV_MSC, | ||
331 | }; | ||
332 | |||
333 | static const int absEvents[] = { | ||
334 | ABS_X, ABS_Y, ABS_PRESSURE, ABS_TILT_X, ABS_TILT_Y, | ||
335 | ABS_WHEEL, ABS_MISC, | ||
336 | }; | ||
337 | |||
338 | static const int relEvents[] = { | ||
339 | REL_X, REL_Y, REL_WHEEL, | ||
340 | }; | ||
341 | |||
342 | static const int buttonEvents[] = { | ||
343 | BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, | ||
344 | BTN_TOOL_PEN, BTN_TOOL_RUBBER, BTN_TOOL_PENCIL, BTN_TOOL_AIRBRUSH, | ||
345 | BTN_TOOL_BRUSH, BTN_TOOL_MOUSE, BTN_TOOL_LENS, BTN_TOUCH, | ||
346 | BTN_STYLUS, BTN_STYLUS2, | ||
347 | }; | ||
348 | |||
333 | /* | 349 | /* |
334 | * Permit easy lookup of keyboard events to send, versus | 350 | * Permit easy lookup of keyboard events to send, versus |
335 | * the bitmap which comes from the tablet. This hides the | 351 | * the bitmap which comes from the tablet. This hides the |
@@ -345,23 +361,39 @@ static const int macroKeyEvents[] = { | |||
345 | }; | 361 | }; |
346 | 362 | ||
347 | /*********************************************************************** | 363 | /*********************************************************************** |
348 | * Relative reports deliver values in 2's complement format to | 364 | * Map values to strings and back. Every map shoudl have the following |
349 | * deal with negative offsets. | 365 | * as its last element: { NULL, AIPTEK_INVALID_VALUE }. |
350 | */ | 366 | */ |
351 | static int aiptek_convert_from_2s_complement(unsigned char c) | 367 | #define AIPTEK_INVALID_VALUE -1 |
368 | |||
369 | struct aiptek_map { | ||
370 | const char *string; | ||
371 | int value; | ||
372 | }; | ||
373 | |||
374 | static int map_str_to_val(const struct aiptek_map *map, const char *str, size_t count) | ||
352 | { | 375 | { |
353 | int ret; | 376 | const struct aiptek_map *p; |
354 | unsigned char b = c; | ||
355 | int negate = 0; | ||
356 | 377 | ||
357 | if ((b & 0x80) != 0) { | 378 | if (str[count - 1] == '\n') |
358 | b = ~b; | 379 | count--; |
359 | b--; | 380 | |
360 | negate = 1; | 381 | for (p = map; p->string; p++) |
361 | } | 382 | if (!strncmp(str, p->string, count)) |
362 | ret = b; | 383 | return p->value; |
363 | ret = (negate == 1) ? -ret : ret; | 384 | |
364 | return ret; | 385 | return AIPTEK_INVALID_VALUE; |
386 | } | ||
387 | |||
388 | static const char *map_val_to_str(const struct aiptek_map *map, int val) | ||
389 | { | ||
390 | const struct aiptek_map *p; | ||
391 | |||
392 | for (p = map; p->value != AIPTEK_INVALID_VALUE; p++) | ||
393 | if (val == p->value) | ||
394 | return p->string; | ||
395 | |||
396 | return "unknown"; | ||
365 | } | 397 | } |
366 | 398 | ||
367 | /*********************************************************************** | 399 | /*********************************************************************** |
@@ -385,6 +417,9 @@ static int aiptek_convert_from_2s_complement(unsigned char c) | |||
385 | * Proximity. Why two events? I thought it interesting to know if the | 417 | * Proximity. Why two events? I thought it interesting to know if the |
386 | * Proximity event occurred while the tablet was in absolute or relative | 418 | * Proximity event occurred while the tablet was in absolute or relative |
387 | * mode. | 419 | * mode. |
420 | * Update: REL_MISC proved not to be such a good idea. With REL_MISC you | ||
421 | * get an event transmitted each time. ABS_MISC works better, since it | ||
422 | * can be set and re-set. Thus, only using ABS_MISC from now on. | ||
388 | * | 423 | * |
389 | * Other tablets use the notion of a certain minimum stylus pressure | 424 | * Other tablets use the notion of a certain minimum stylus pressure |
390 | * to infer proximity. While that could have been done, that is yet | 425 | * to infer proximity. While that could have been done, that is yet |
@@ -441,8 +476,8 @@ static void aiptek_irq(struct urb *urb) | |||
441 | aiptek->diagnostic = | 476 | aiptek->diagnostic = |
442 | AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE; | 477 | AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE; |
443 | } else { | 478 | } else { |
444 | x = aiptek_convert_from_2s_complement(data[2]); | 479 | x = (signed char) data[2]; |
445 | y = aiptek_convert_from_2s_complement(data[3]); | 480 | y = (signed char) data[3]; |
446 | 481 | ||
447 | /* jitterable keeps track of whether any button has been pressed. | 482 | /* jitterable keeps track of whether any button has been pressed. |
448 | * We're also using it to remap the physical mouse button mask | 483 | * We're also using it to remap the physical mouse button mask |
@@ -451,18 +486,20 @@ static void aiptek_irq(struct urb *urb) | |||
451 | * that a non-zero value indicates that one or more | 486 | * that a non-zero value indicates that one or more |
452 | * mouse button was pressed.) | 487 | * mouse button was pressed.) |
453 | */ | 488 | */ |
454 | jitterable = data[5] & 0x07; | 489 | jitterable = data[1] & 0x07; |
455 | 490 | ||
456 | left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; | 491 | left = (data[1] & aiptek->curSetting.mouseButtonLeft >> 2) != 0 ? 1 : 0; |
457 | right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; | 492 | right = (data[1] & aiptek->curSetting.mouseButtonRight >> 2) != 0 ? 1 : 0; |
458 | middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; | 493 | middle = (data[1] & aiptek->curSetting.mouseButtonMiddle >> 2) != 0 ? 1 : 0; |
459 | 494 | ||
460 | input_report_key(inputdev, BTN_LEFT, left); | 495 | input_report_key(inputdev, BTN_LEFT, left); |
461 | input_report_key(inputdev, BTN_MIDDLE, middle); | 496 | input_report_key(inputdev, BTN_MIDDLE, middle); |
462 | input_report_key(inputdev, BTN_RIGHT, right); | 497 | input_report_key(inputdev, BTN_RIGHT, right); |
498 | |||
499 | input_report_abs(inputdev, ABS_MISC, | ||
500 | 1 | AIPTEK_REPORT_TOOL_UNKNOWN); | ||
463 | input_report_rel(inputdev, REL_X, x); | 501 | input_report_rel(inputdev, REL_X, x); |
464 | input_report_rel(inputdev, REL_Y, y); | 502 | input_report_rel(inputdev, REL_Y, y); |
465 | input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN); | ||
466 | 503 | ||
467 | /* Wheel support is in the form of a single-event | 504 | /* Wheel support is in the form of a single-event |
468 | * firing. | 505 | * firing. |
@@ -472,6 +509,11 @@ static void aiptek_irq(struct urb *urb) | |||
472 | aiptek->curSetting.wheel); | 509 | aiptek->curSetting.wheel); |
473 | aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; | 510 | aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; |
474 | } | 511 | } |
512 | if (aiptek->lastMacro != -1) { | ||
513 | input_report_key(inputdev, | ||
514 | macroKeyEvents[aiptek->lastMacro], 0); | ||
515 | aiptek->lastMacro = -1; | ||
516 | } | ||
475 | input_sync(inputdev); | 517 | input_sync(inputdev); |
476 | } | 518 | } |
477 | } | 519 | } |
@@ -489,8 +531,8 @@ static void aiptek_irq(struct urb *urb) | |||
489 | y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); | 531 | y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); |
490 | z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); | 532 | z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); |
491 | 533 | ||
492 | p = (data[5] & 0x01) != 0 ? 1 : 0; | 534 | dv = (data[5] & 0x01) != 0 ? 1 : 0; |
493 | dv = (data[5] & 0x02) != 0 ? 1 : 0; | 535 | p = (data[5] & 0x02) != 0 ? 1 : 0; |
494 | tip = (data[5] & 0x04) != 0 ? 1 : 0; | 536 | tip = (data[5] & 0x04) != 0 ? 1 : 0; |
495 | 537 | ||
496 | /* Use jitterable to re-arrange button masks | 538 | /* Use jitterable to re-arrange button masks |
@@ -505,16 +547,18 @@ static void aiptek_irq(struct urb *urb) | |||
505 | * all 'bad' reports... | 547 | * all 'bad' reports... |
506 | */ | 548 | */ |
507 | if (dv != 0) { | 549 | if (dv != 0) { |
508 | /* If we've not already sent a tool_button_?? code, do | 550 | /* If the selected tool changed, reset the old |
509 | * so now. Then set FIRED_BIT so it won't be resent unless | 551 | * tool key, and set the new one. |
510 | * the user forces FIRED_BIT off. | ||
511 | */ | 552 | */ |
512 | if (TOOL_BUTTON_FIRED | 553 | if (aiptek->previousToolMode != |
513 | (aiptek->curSetting.toolMode) == 0) { | 554 | aiptek->curSetting.toolMode) { |
555 | input_report_key(inputdev, | ||
556 | aiptek->previousToolMode, 0); | ||
514 | input_report_key(inputdev, | 557 | input_report_key(inputdev, |
515 | TOOL_BUTTON(aiptek->curSetting.toolMode), | 558 | aiptek->curSetting.toolMode, |
516 | 1); | 559 | 1); |
517 | aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; | 560 | aiptek->previousToolMode = |
561 | aiptek->curSetting.toolMode; | ||
518 | } | 562 | } |
519 | 563 | ||
520 | if (p != 0) { | 564 | if (p != 0) { |
@@ -550,6 +594,11 @@ static void aiptek_irq(struct urb *urb) | |||
550 | } | 594 | } |
551 | } | 595 | } |
552 | input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS); | 596 | input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS); |
597 | if (aiptek->lastMacro != -1) { | ||
598 | input_report_key(inputdev, | ||
599 | macroKeyEvents[aiptek->lastMacro], 0); | ||
600 | aiptek->lastMacro = -1; | ||
601 | } | ||
553 | input_sync(inputdev); | 602 | input_sync(inputdev); |
554 | } | 603 | } |
555 | } | 604 | } |
@@ -568,23 +617,25 @@ static void aiptek_irq(struct urb *urb) | |||
568 | 617 | ||
569 | jitterable = data[5] & 0x1c; | 618 | jitterable = data[5] & 0x1c; |
570 | 619 | ||
571 | p = (data[5] & 0x01) != 0 ? 1 : 0; | 620 | dv = (data[5] & 0x01) != 0 ? 1 : 0; |
572 | dv = (data[5] & 0x02) != 0 ? 1 : 0; | 621 | p = (data[5] & 0x02) != 0 ? 1 : 0; |
573 | left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; | 622 | left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; |
574 | right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; | 623 | right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; |
575 | middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; | 624 | middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; |
576 | 625 | ||
577 | if (dv != 0) { | 626 | if (dv != 0) { |
578 | /* If we've not already sent a tool_button_?? code, do | 627 | /* If the selected tool changed, reset the old |
579 | * so now. Then set FIRED_BIT so it won't be resent unless | 628 | * tool key, and set the new one. |
580 | * the user forces FIRED_BIT off. | ||
581 | */ | 629 | */ |
582 | if (TOOL_BUTTON_FIRED | 630 | if (aiptek->previousToolMode != |
583 | (aiptek->curSetting.toolMode) == 0) { | 631 | aiptek->curSetting.toolMode) { |
632 | input_report_key(inputdev, | ||
633 | aiptek->previousToolMode, 0); | ||
584 | input_report_key(inputdev, | 634 | input_report_key(inputdev, |
585 | TOOL_BUTTON(aiptek->curSetting.toolMode), | 635 | aiptek->curSetting.toolMode, |
586 | 1); | 636 | 1); |
587 | aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; | 637 | aiptek->previousToolMode = |
638 | aiptek->curSetting.toolMode; | ||
588 | } | 639 | } |
589 | 640 | ||
590 | if (p != 0) { | 641 | if (p != 0) { |
@@ -605,7 +656,12 @@ static void aiptek_irq(struct urb *urb) | |||
605 | aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; | 656 | aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE; |
606 | } | 657 | } |
607 | } | 658 | } |
608 | input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE); | 659 | input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_MOUSE); |
660 | if (aiptek->lastMacro != -1) { | ||
661 | input_report_key(inputdev, | ||
662 | macroKeyEvents[aiptek->lastMacro], 0); | ||
663 | aiptek->lastMacro = -1; | ||
664 | } | ||
609 | input_sync(inputdev); | 665 | input_sync(inputdev); |
610 | } | 666 | } |
611 | } | 667 | } |
@@ -615,98 +671,83 @@ static void aiptek_irq(struct urb *urb) | |||
615 | else if (data[0] == 4) { | 671 | else if (data[0] == 4) { |
616 | jitterable = data[1] & 0x18; | 672 | jitterable = data[1] & 0x18; |
617 | 673 | ||
618 | p = (data[1] & 0x01) != 0 ? 1 : 0; | 674 | dv = (data[1] & 0x01) != 0 ? 1 : 0; |
619 | dv = (data[1] & 0x02) != 0 ? 1 : 0; | 675 | p = (data[1] & 0x02) != 0 ? 1 : 0; |
620 | tip = (data[1] & 0x04) != 0 ? 1 : 0; | 676 | tip = (data[1] & 0x04) != 0 ? 1 : 0; |
621 | bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0; | 677 | bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0; |
622 | pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; | 678 | pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; |
623 | 679 | ||
624 | macro = data[3]; | 680 | macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1; |
625 | z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); | 681 | z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); |
626 | 682 | ||
627 | if (dv != 0) { | 683 | if (dv) { |
628 | /* If we've not already sent a tool_button_?? code, do | 684 | /* If the selected tool changed, reset the old |
629 | * so now. Then set FIRED_BIT so it won't be resent unless | 685 | * tool key, and set the new one. |
630 | * the user forces FIRED_BIT off. | ||
631 | */ | 686 | */ |
632 | if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) { | 687 | if (aiptek->previousToolMode != |
688 | aiptek->curSetting.toolMode) { | ||
689 | input_report_key(inputdev, | ||
690 | aiptek->previousToolMode, 0); | ||
633 | input_report_key(inputdev, | 691 | input_report_key(inputdev, |
634 | TOOL_BUTTON(aiptek->curSetting.toolMode), | 692 | aiptek->curSetting.toolMode, |
635 | 1); | 693 | 1); |
636 | aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; | 694 | aiptek->previousToolMode = |
695 | aiptek->curSetting.toolMode; | ||
637 | } | 696 | } |
697 | } | ||
638 | 698 | ||
639 | if (p != 0) { | 699 | if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) { |
640 | input_report_key(inputdev, BTN_TOUCH, tip); | 700 | input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0); |
641 | input_report_key(inputdev, BTN_STYLUS, bs); | 701 | aiptek->lastMacro = -1; |
642 | input_report_key(inputdev, BTN_STYLUS2, pck); | 702 | } |
643 | input_report_abs(inputdev, ABS_PRESSURE, z); | ||
644 | } | ||
645 | 703 | ||
646 | /* For safety, we're sending key 'break' codes for the | 704 | if (macro != -1 && macro != aiptek->lastMacro) { |
647 | * neighboring macro keys. | 705 | input_report_key(inputdev, macroKeyEvents[macro], 1); |
648 | */ | 706 | aiptek->lastMacro = macro; |
649 | if (macro > 0) { | ||
650 | input_report_key(inputdev, | ||
651 | macroKeyEvents[macro - 1], 0); | ||
652 | } | ||
653 | if (macro < 25) { | ||
654 | input_report_key(inputdev, | ||
655 | macroKeyEvents[macro + 1], 0); | ||
656 | } | ||
657 | input_report_key(inputdev, macroKeyEvents[macro], p); | ||
658 | input_report_abs(inputdev, ABS_MISC, | ||
659 | p | AIPTEK_REPORT_TOOL_STYLUS); | ||
660 | input_sync(inputdev); | ||
661 | } | 707 | } |
708 | input_report_abs(inputdev, ABS_MISC, | ||
709 | p | AIPTEK_REPORT_TOOL_STYLUS); | ||
710 | input_sync(inputdev); | ||
662 | } | 711 | } |
663 | /* Report 5s come from the macro keys when pressed by mouse | 712 | /* Report 5s come from the macro keys when pressed by mouse |
664 | */ | 713 | */ |
665 | else if (data[0] == 5) { | 714 | else if (data[0] == 5) { |
666 | jitterable = data[1] & 0x1c; | 715 | jitterable = data[1] & 0x1c; |
667 | 716 | ||
668 | p = (data[1] & 0x01) != 0 ? 1 : 0; | 717 | dv = (data[1] & 0x01) != 0 ? 1 : 0; |
669 | dv = (data[1] & 0x02) != 0 ? 1 : 0; | 718 | p = (data[1] & 0x02) != 0 ? 1 : 0; |
670 | left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; | 719 | left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; |
671 | right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; | 720 | right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; |
672 | middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; | 721 | middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; |
673 | macro = data[3]; | 722 | macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : 0; |
674 | 723 | ||
675 | if (dv != 0) { | 724 | if (dv) { |
676 | /* If we've not already sent a tool_button_?? code, do | 725 | /* If the selected tool changed, reset the old |
677 | * so now. Then set FIRED_BIT so it won't be resent unless | 726 | * tool key, and set the new one. |
678 | * the user forces FIRED_BIT off. | ||
679 | */ | 727 | */ |
680 | if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) { | 728 | if (aiptek->previousToolMode != |
681 | input_report_key(inputdev, | 729 | aiptek->curSetting.toolMode) { |
682 | TOOL_BUTTON(aiptek->curSetting.toolMode), | 730 | input_report_key(inputdev, |
683 | 1); | 731 | aiptek->previousToolMode, 0); |
684 | aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; | 732 | input_report_key(inputdev, |
685 | } | 733 | aiptek->curSetting.toolMode, 1); |
686 | 734 | aiptek->previousToolMode = aiptek->curSetting.toolMode; | |
687 | if (p != 0) { | ||
688 | input_report_key(inputdev, BTN_LEFT, left); | ||
689 | input_report_key(inputdev, BTN_MIDDLE, middle); | ||
690 | input_report_key(inputdev, BTN_RIGHT, right); | ||
691 | } | 735 | } |
736 | } | ||
692 | 737 | ||
693 | /* For safety, we're sending key 'break' codes for the | 738 | if (aiptek->lastMacro != -1 && aiptek->lastMacro != macro) { |
694 | * neighboring macro keys. | 739 | input_report_key(inputdev, macroKeyEvents[aiptek->lastMacro], 0); |
695 | */ | 740 | aiptek->lastMacro = -1; |
696 | if (macro > 0) { | 741 | } |
697 | input_report_key(inputdev, | ||
698 | macroKeyEvents[macro - 1], 0); | ||
699 | } | ||
700 | if (macro < 25) { | ||
701 | input_report_key(inputdev, | ||
702 | macroKeyEvents[macro + 1], 0); | ||
703 | } | ||
704 | 742 | ||
743 | if (macro != -1 && macro != aiptek->lastMacro) { | ||
705 | input_report_key(inputdev, macroKeyEvents[macro], 1); | 744 | input_report_key(inputdev, macroKeyEvents[macro], 1); |
706 | input_report_rel(inputdev, ABS_MISC, | 745 | aiptek->lastMacro = macro; |
707 | p | AIPTEK_REPORT_TOOL_MOUSE); | ||
708 | input_sync(inputdev); | ||
709 | } | 746 | } |
747 | |||
748 | input_report_abs(inputdev, ABS_MISC, | ||
749 | p | AIPTEK_REPORT_TOOL_MOUSE); | ||
750 | input_sync(inputdev); | ||
710 | } | 751 | } |
711 | /* We have no idea which tool can generate a report 6. Theoretically, | 752 | /* We have no idea which tool can generate a report 6. Theoretically, |
712 | * neither need to, having been given reports 4 & 5 for such use. | 753 | * neither need to, having been given reports 4 & 5 for such use. |
@@ -725,15 +766,18 @@ static void aiptek_irq(struct urb *urb) | |||
725 | 0); | 766 | 0); |
726 | } | 767 | } |
727 | 768 | ||
728 | /* If we've not already sent a tool_button_?? code, do | 769 | /* If the selected tool changed, reset the old |
729 | * so now. Then set FIRED_BIT so it won't be resent unless | 770 | tool key, and set the new one. |
730 | * the user forces FIRED_BIT off. | 771 | */ |
731 | */ | 772 | if (aiptek->previousToolMode != |
732 | if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) { | 773 | aiptek->curSetting.toolMode) { |
774 | input_report_key(inputdev, | ||
775 | aiptek->previousToolMode, 0); | ||
733 | input_report_key(inputdev, | 776 | input_report_key(inputdev, |
734 | TOOL_BUTTON(aiptek->curSetting. | 777 | aiptek->curSetting.toolMode, |
735 | toolMode), 1); | 778 | 1); |
736 | aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT; | 779 | aiptek->previousToolMode = |
780 | aiptek->curSetting.toolMode; | ||
737 | } | 781 | } |
738 | 782 | ||
739 | input_report_key(inputdev, macroKeyEvents[macro], 1); | 783 | input_report_key(inputdev, macroKeyEvents[macro], 1); |
@@ -1007,9 +1051,6 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr | |||
1007 | { | 1051 | { |
1008 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1052 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1009 | 1053 | ||
1010 | if (aiptek == NULL) | ||
1011 | return 0; | ||
1012 | |||
1013 | return snprintf(buf, PAGE_SIZE, "%dx%d\n", | 1054 | return snprintf(buf, PAGE_SIZE, "%dx%d\n", |
1014 | aiptek->inputdev->absmax[ABS_X] + 1, | 1055 | aiptek->inputdev->absmax[ABS_X] + 1, |
1015 | aiptek->inputdev->absmax[ABS_Y] + 1); | 1056 | aiptek->inputdev->absmax[ABS_Y] + 1); |
@@ -1024,117 +1065,35 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr | |||
1024 | static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL); | 1065 | static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL); |
1025 | 1066 | ||
1026 | /*********************************************************************** | 1067 | /*********************************************************************** |
1027 | * support routines for the 'product_id' file | ||
1028 | */ | ||
1029 | static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf) | ||
1030 | { | ||
1031 | struct aiptek *aiptek = dev_get_drvdata(dev); | ||
1032 | |||
1033 | if (aiptek == NULL) | ||
1034 | return 0; | ||
1035 | |||
1036 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", | ||
1037 | aiptek->inputdev->id.product); | ||
1038 | } | ||
1039 | |||
1040 | static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL); | ||
1041 | |||
1042 | /*********************************************************************** | ||
1043 | * support routines for the 'vendor_id' file | ||
1044 | */ | ||
1045 | static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf) | ||
1046 | { | ||
1047 | struct aiptek *aiptek = dev_get_drvdata(dev); | ||
1048 | |||
1049 | if (aiptek == NULL) | ||
1050 | return 0; | ||
1051 | |||
1052 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor); | ||
1053 | } | ||
1054 | |||
1055 | static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL); | ||
1056 | |||
1057 | /*********************************************************************** | ||
1058 | * support routines for the 'vendor' file | ||
1059 | */ | ||
1060 | static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf) | ||
1061 | { | ||
1062 | struct aiptek *aiptek = dev_get_drvdata(dev); | ||
1063 | int retval; | ||
1064 | |||
1065 | if (aiptek == NULL) | ||
1066 | return 0; | ||
1067 | |||
1068 | retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer); | ||
1069 | return retval; | ||
1070 | } | ||
1071 | |||
1072 | static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL); | ||
1073 | |||
1074 | /*********************************************************************** | ||
1075 | * support routines for the 'product' file | ||
1076 | */ | ||
1077 | static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf) | ||
1078 | { | ||
1079 | struct aiptek *aiptek = dev_get_drvdata(dev); | ||
1080 | int retval; | ||
1081 | |||
1082 | if (aiptek == NULL) | ||
1083 | return 0; | ||
1084 | |||
1085 | retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product); | ||
1086 | return retval; | ||
1087 | } | ||
1088 | |||
1089 | static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL); | ||
1090 | |||
1091 | /*********************************************************************** | ||
1092 | * support routines for the 'pointer_mode' file. Note that this file | 1068 | * support routines for the 'pointer_mode' file. Note that this file |
1093 | * both displays current setting and allows reprogramming. | 1069 | * both displays current setting and allows reprogramming. |
1094 | */ | 1070 | */ |
1071 | static struct aiptek_map pointer_mode_map[] = { | ||
1072 | { "stylus", AIPTEK_POINTER_ONLY_STYLUS_MODE }, | ||
1073 | { "mouse", AIPTEK_POINTER_ONLY_MOUSE_MODE }, | ||
1074 | { "either", AIPTEK_POINTER_EITHER_MODE }, | ||
1075 | { NULL, AIPTEK_INVALID_VALUE } | ||
1076 | }; | ||
1077 | |||
1095 | static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf) | 1078 | static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf) |
1096 | { | 1079 | { |
1097 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1080 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1098 | char *s; | ||
1099 | |||
1100 | if (aiptek == NULL) | ||
1101 | return 0; | ||
1102 | |||
1103 | switch (aiptek->curSetting.pointerMode) { | ||
1104 | case AIPTEK_POINTER_ONLY_STYLUS_MODE: | ||
1105 | s = "stylus"; | ||
1106 | break; | ||
1107 | |||
1108 | case AIPTEK_POINTER_ONLY_MOUSE_MODE: | ||
1109 | s = "mouse"; | ||
1110 | break; | ||
1111 | |||
1112 | case AIPTEK_POINTER_EITHER_MODE: | ||
1113 | s = "either"; | ||
1114 | break; | ||
1115 | 1081 | ||
1116 | default: | 1082 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1117 | s = "unknown"; | 1083 | map_val_to_str(pointer_mode_map, |
1118 | break; | 1084 | aiptek->curSetting.pointerMode)); |
1119 | } | ||
1120 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1121 | } | 1085 | } |
1122 | 1086 | ||
1123 | static ssize_t | 1087 | static ssize_t |
1124 | store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1088 | store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1125 | { | 1089 | { |
1126 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1090 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1127 | if (aiptek == NULL) | 1091 | int new_mode = map_str_to_val(pointer_mode_map, buf, count); |
1128 | return 0; | ||
1129 | 1092 | ||
1130 | if (strcmp(buf, "stylus") == 0) { | 1093 | if (new_mode == AIPTEK_INVALID_VALUE) |
1131 | aiptek->newSetting.pointerMode = | 1094 | return -EINVAL; |
1132 | AIPTEK_POINTER_ONLY_STYLUS_MODE; | 1095 | |
1133 | } else if (strcmp(buf, "mouse") == 0) { | 1096 | aiptek->newSetting.pointerMode = new_mode; |
1134 | aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE; | ||
1135 | } else if (strcmp(buf, "either") == 0) { | ||
1136 | aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE; | ||
1137 | } | ||
1138 | return count; | 1097 | return count; |
1139 | } | 1098 | } |
1140 | 1099 | ||
@@ -1146,44 +1105,32 @@ static DEVICE_ATTR(pointer_mode, | |||
1146 | * support routines for the 'coordinate_mode' file. Note that this file | 1105 | * support routines for the 'coordinate_mode' file. Note that this file |
1147 | * both displays current setting and allows reprogramming. | 1106 | * both displays current setting and allows reprogramming. |
1148 | */ | 1107 | */ |
1108 | |||
1109 | static struct aiptek_map coordinate_mode_map[] = { | ||
1110 | { "absolute", AIPTEK_COORDINATE_ABSOLUTE_MODE }, | ||
1111 | { "relative", AIPTEK_COORDINATE_RELATIVE_MODE }, | ||
1112 | { NULL, AIPTEK_INVALID_VALUE } | ||
1113 | }; | ||
1114 | |||
1149 | static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf) | 1115 | static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf) |
1150 | { | 1116 | { |
1151 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1117 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1152 | char *s; | ||
1153 | 1118 | ||
1154 | if (aiptek == NULL) | 1119 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1155 | return 0; | 1120 | map_val_to_str(coordinate_mode_map, |
1156 | 1121 | aiptek->curSetting.coordinateMode)); | |
1157 | switch (aiptek->curSetting.coordinateMode) { | ||
1158 | case AIPTEK_COORDINATE_ABSOLUTE_MODE: | ||
1159 | s = "absolute"; | ||
1160 | break; | ||
1161 | |||
1162 | case AIPTEK_COORDINATE_RELATIVE_MODE: | ||
1163 | s = "relative"; | ||
1164 | break; | ||
1165 | |||
1166 | default: | ||
1167 | s = "unknown"; | ||
1168 | break; | ||
1169 | } | ||
1170 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1171 | } | 1122 | } |
1172 | 1123 | ||
1173 | static ssize_t | 1124 | static ssize_t |
1174 | store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1125 | store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1175 | { | 1126 | { |
1176 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1127 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1177 | if (aiptek == NULL) | 1128 | int new_mode = map_str_to_val(coordinate_mode_map, buf, count); |
1178 | return 0; | ||
1179 | 1129 | ||
1180 | if (strcmp(buf, "absolute") == 0) { | 1130 | if (new_mode == AIPTEK_INVALID_VALUE) |
1181 | aiptek->newSetting.pointerMode = | 1131 | return -EINVAL; |
1182 | AIPTEK_COORDINATE_ABSOLUTE_MODE; | 1132 | |
1183 | } else if (strcmp(buf, "relative") == 0) { | 1133 | aiptek->newSetting.coordinateMode = new_mode; |
1184 | aiptek->newSetting.pointerMode = | ||
1185 | AIPTEK_COORDINATE_RELATIVE_MODE; | ||
1186 | } | ||
1187 | return count; | 1134 | return count; |
1188 | } | 1135 | } |
1189 | 1136 | ||
@@ -1195,73 +1142,37 @@ static DEVICE_ATTR(coordinate_mode, | |||
1195 | * support routines for the 'tool_mode' file. Note that this file | 1142 | * support routines for the 'tool_mode' file. Note that this file |
1196 | * both displays current setting and allows reprogramming. | 1143 | * both displays current setting and allows reprogramming. |
1197 | */ | 1144 | */ |
1145 | |||
1146 | static struct aiptek_map tool_mode_map[] = { | ||
1147 | { "mouse", AIPTEK_TOOL_BUTTON_MOUSE_MODE }, | ||
1148 | { "eraser", AIPTEK_TOOL_BUTTON_ERASER_MODE }, | ||
1149 | { "pencil", AIPTEK_TOOL_BUTTON_PENCIL_MODE }, | ||
1150 | { "pen", AIPTEK_TOOL_BUTTON_PEN_MODE }, | ||
1151 | { "brush", AIPTEK_TOOL_BUTTON_BRUSH_MODE }, | ||
1152 | { "airbrush", AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE }, | ||
1153 | { "lens", AIPTEK_TOOL_BUTTON_LENS_MODE }, | ||
1154 | { NULL, AIPTEK_INVALID_VALUE } | ||
1155 | }; | ||
1156 | |||
1198 | static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf) | 1157 | static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf) |
1199 | { | 1158 | { |
1200 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1159 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1201 | char *s; | ||
1202 | |||
1203 | if (aiptek == NULL) | ||
1204 | return 0; | ||
1205 | |||
1206 | switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) { | ||
1207 | case AIPTEK_TOOL_BUTTON_MOUSE_MODE: | ||
1208 | s = "mouse"; | ||
1209 | break; | ||
1210 | |||
1211 | case AIPTEK_TOOL_BUTTON_ERASER_MODE: | ||
1212 | s = "eraser"; | ||
1213 | break; | ||
1214 | |||
1215 | case AIPTEK_TOOL_BUTTON_PENCIL_MODE: | ||
1216 | s = "pencil"; | ||
1217 | break; | ||
1218 | |||
1219 | case AIPTEK_TOOL_BUTTON_PEN_MODE: | ||
1220 | s = "pen"; | ||
1221 | break; | ||
1222 | |||
1223 | case AIPTEK_TOOL_BUTTON_BRUSH_MODE: | ||
1224 | s = "brush"; | ||
1225 | break; | ||
1226 | |||
1227 | case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE: | ||
1228 | s = "airbrush"; | ||
1229 | break; | ||
1230 | |||
1231 | case AIPTEK_TOOL_BUTTON_LENS_MODE: | ||
1232 | s = "lens"; | ||
1233 | break; | ||
1234 | 1160 | ||
1235 | default: | 1161 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1236 | s = "unknown"; | 1162 | map_val_to_str(tool_mode_map, |
1237 | break; | 1163 | aiptek->curSetting.toolMode)); |
1238 | } | ||
1239 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1240 | } | 1164 | } |
1241 | 1165 | ||
1242 | static ssize_t | 1166 | static ssize_t |
1243 | store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1167 | store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1244 | { | 1168 | { |
1245 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1169 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1246 | if (aiptek == NULL) | 1170 | int new_mode = map_str_to_val(tool_mode_map, buf, count); |
1247 | return 0; | ||
1248 | 1171 | ||
1249 | if (strcmp(buf, "mouse") == 0) { | 1172 | if (new_mode == AIPTEK_INVALID_VALUE) |
1250 | aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE; | 1173 | return -EINVAL; |
1251 | } else if (strcmp(buf, "eraser") == 0) { | ||
1252 | aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE; | ||
1253 | } else if (strcmp(buf, "pencil") == 0) { | ||
1254 | aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE; | ||
1255 | } else if (strcmp(buf, "pen") == 0) { | ||
1256 | aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE; | ||
1257 | } else if (strcmp(buf, "brush") == 0) { | ||
1258 | aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE; | ||
1259 | } else if (strcmp(buf, "airbrush") == 0) { | ||
1260 | aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE; | ||
1261 | } else if (strcmp(buf, "lens") == 0) { | ||
1262 | aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE; | ||
1263 | } | ||
1264 | 1174 | ||
1175 | aiptek->newSetting.toolMode = new_mode; | ||
1265 | return count; | 1176 | return count; |
1266 | } | 1177 | } |
1267 | 1178 | ||
@@ -1277,9 +1188,6 @@ static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *att | |||
1277 | { | 1188 | { |
1278 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1189 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1279 | 1190 | ||
1280 | if (aiptek == NULL) | ||
1281 | return 0; | ||
1282 | |||
1283 | if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) { | 1191 | if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) { |
1284 | return snprintf(buf, PAGE_SIZE, "disable\n"); | 1192 | return snprintf(buf, PAGE_SIZE, "disable\n"); |
1285 | } else { | 1193 | } else { |
@@ -1294,9 +1202,6 @@ store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char | |||
1294 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1202 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1295 | int x; | 1203 | int x; |
1296 | 1204 | ||
1297 | if (aiptek == NULL) | ||
1298 | return 0; | ||
1299 | |||
1300 | if (strcmp(buf, "disable") == 0) { | 1205 | if (strcmp(buf, "disable") == 0) { |
1301 | aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE; | 1206 | aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE; |
1302 | } else { | 1207 | } else { |
@@ -1319,9 +1224,6 @@ static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *att | |||
1319 | { | 1224 | { |
1320 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1225 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1321 | 1226 | ||
1322 | if (aiptek == NULL) | ||
1323 | return 0; | ||
1324 | |||
1325 | if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) { | 1227 | if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) { |
1326 | return snprintf(buf, PAGE_SIZE, "disable\n"); | 1228 | return snprintf(buf, PAGE_SIZE, "disable\n"); |
1327 | } else { | 1229 | } else { |
@@ -1336,9 +1238,6 @@ store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char | |||
1336 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1238 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1337 | int y; | 1239 | int y; |
1338 | 1240 | ||
1339 | if (aiptek == NULL) | ||
1340 | return 0; | ||
1341 | |||
1342 | if (strcmp(buf, "disable") == 0) { | 1241 | if (strcmp(buf, "disable") == 0) { |
1343 | aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE; | 1242 | aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE; |
1344 | } else { | 1243 | } else { |
@@ -1361,9 +1260,6 @@ static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribut | |||
1361 | { | 1260 | { |
1362 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1261 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1363 | 1262 | ||
1364 | if (aiptek == NULL) | ||
1365 | return 0; | ||
1366 | |||
1367 | return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay); | 1263 | return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay); |
1368 | } | 1264 | } |
1369 | 1265 | ||
@@ -1372,9 +1268,6 @@ store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const | |||
1372 | { | 1268 | { |
1373 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1269 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1374 | 1270 | ||
1375 | if (aiptek == NULL) | ||
1376 | return 0; | ||
1377 | |||
1378 | aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10); | 1271 | aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10); |
1379 | return count; | 1272 | return count; |
1380 | } | 1273 | } |
@@ -1391,9 +1284,6 @@ static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_at | |||
1391 | { | 1284 | { |
1392 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1285 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1393 | 1286 | ||
1394 | if (aiptek == NULL) | ||
1395 | return 0; | ||
1396 | |||
1397 | return snprintf(buf, PAGE_SIZE, "%d\n", | 1287 | return snprintf(buf, PAGE_SIZE, "%d\n", |
1398 | aiptek->curSetting.programmableDelay); | 1288 | aiptek->curSetting.programmableDelay); |
1399 | } | 1289 | } |
@@ -1403,9 +1293,6 @@ store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, | |||
1403 | { | 1293 | { |
1404 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1294 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1405 | 1295 | ||
1406 | if (aiptek == NULL) | ||
1407 | return 0; | ||
1408 | |||
1409 | aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10); | 1296 | aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10); |
1410 | return count; | 1297 | return count; |
1411 | } | 1298 | } |
@@ -1415,23 +1302,6 @@ static DEVICE_ATTR(delay, | |||
1415 | show_tabletProgrammableDelay, store_tabletProgrammableDelay); | 1302 | show_tabletProgrammableDelay, store_tabletProgrammableDelay); |
1416 | 1303 | ||
1417 | /*********************************************************************** | 1304 | /*********************************************************************** |
1418 | * support routines for the 'input_path' file. Note that this file | ||
1419 | * only displays current setting. | ||
1420 | */ | ||
1421 | static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf) | ||
1422 | { | ||
1423 | struct aiptek *aiptek = dev_get_drvdata(dev); | ||
1424 | |||
1425 | if (aiptek == NULL) | ||
1426 | return 0; | ||
1427 | |||
1428 | return snprintf(buf, PAGE_SIZE, "/dev/input/%s\n", | ||
1429 | aiptek->features.inputPath); | ||
1430 | } | ||
1431 | |||
1432 | static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL); | ||
1433 | |||
1434 | /*********************************************************************** | ||
1435 | * support routines for the 'event_count' file. Note that this file | 1305 | * support routines for the 'event_count' file. Note that this file |
1436 | * only displays current setting. | 1306 | * only displays current setting. |
1437 | */ | 1307 | */ |
@@ -1439,9 +1309,6 @@ static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attri | |||
1439 | { | 1309 | { |
1440 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1310 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1441 | 1311 | ||
1442 | if (aiptek == NULL) | ||
1443 | return 0; | ||
1444 | |||
1445 | return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount); | 1312 | return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount); |
1446 | } | 1313 | } |
1447 | 1314 | ||
@@ -1456,9 +1323,6 @@ static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_at | |||
1456 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1323 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1457 | char *retMsg; | 1324 | char *retMsg; |
1458 | 1325 | ||
1459 | if (aiptek == NULL) | ||
1460 | return 0; | ||
1461 | |||
1462 | switch (aiptek->diagnostic) { | 1326 | switch (aiptek->diagnostic) { |
1463 | case AIPTEK_DIAGNOSTIC_NA: | 1327 | case AIPTEK_DIAGNOSTIC_NA: |
1464 | retMsg = "no errors\n"; | 1328 | retMsg = "no errors\n"; |
@@ -1493,45 +1357,32 @@ static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL); | |||
1493 | * support routines for the 'stylus_upper' file. Note that this file | 1357 | * support routines for the 'stylus_upper' file. Note that this file |
1494 | * both displays current setting and allows for setting changing. | 1358 | * both displays current setting and allows for setting changing. |
1495 | */ | 1359 | */ |
1360 | |||
1361 | static struct aiptek_map stylus_button_map[] = { | ||
1362 | { "upper", AIPTEK_STYLUS_UPPER_BUTTON }, | ||
1363 | { "lower", AIPTEK_STYLUS_LOWER_BUTTON }, | ||
1364 | { NULL, AIPTEK_INVALID_VALUE } | ||
1365 | }; | ||
1366 | |||
1496 | static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf) | 1367 | static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf) |
1497 | { | 1368 | { |
1498 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1369 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1499 | char *s; | ||
1500 | |||
1501 | if (aiptek == NULL) | ||
1502 | return 0; | ||
1503 | |||
1504 | switch (aiptek->curSetting.stylusButtonUpper) { | ||
1505 | case AIPTEK_STYLUS_UPPER_BUTTON: | ||
1506 | s = "upper"; | ||
1507 | break; | ||
1508 | |||
1509 | case AIPTEK_STYLUS_LOWER_BUTTON: | ||
1510 | s = "lower"; | ||
1511 | break; | ||
1512 | 1370 | ||
1513 | default: | 1371 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1514 | s = "unknown"; | 1372 | map_val_to_str(stylus_button_map, |
1515 | break; | 1373 | aiptek->curSetting.stylusButtonUpper)); |
1516 | } | ||
1517 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1518 | } | 1374 | } |
1519 | 1375 | ||
1520 | static ssize_t | 1376 | static ssize_t |
1521 | store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1377 | store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1522 | { | 1378 | { |
1523 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1379 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1380 | int new_button = map_str_to_val(stylus_button_map, buf, count); | ||
1524 | 1381 | ||
1525 | if (aiptek == NULL) | 1382 | if (new_button == AIPTEK_INVALID_VALUE) |
1526 | return 0; | 1383 | return -EINVAL; |
1527 | 1384 | ||
1528 | if (strcmp(buf, "upper") == 0) { | 1385 | aiptek->newSetting.stylusButtonUpper = new_button; |
1529 | aiptek->newSetting.stylusButtonUpper = | ||
1530 | AIPTEK_STYLUS_UPPER_BUTTON; | ||
1531 | } else if (strcmp(buf, "lower") == 0) { | ||
1532 | aiptek->newSetting.stylusButtonUpper = | ||
1533 | AIPTEK_STYLUS_LOWER_BUTTON; | ||
1534 | } | ||
1535 | return count; | 1386 | return count; |
1536 | } | 1387 | } |
1537 | 1388 | ||
@@ -1543,45 +1394,26 @@ static DEVICE_ATTR(stylus_upper, | |||
1543 | * support routines for the 'stylus_lower' file. Note that this file | 1394 | * support routines for the 'stylus_lower' file. Note that this file |
1544 | * both displays current setting and allows for setting changing. | 1395 | * both displays current setting and allows for setting changing. |
1545 | */ | 1396 | */ |
1397 | |||
1546 | static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf) | 1398 | static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf) |
1547 | { | 1399 | { |
1548 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1400 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1549 | char *s; | ||
1550 | |||
1551 | if (aiptek == NULL) | ||
1552 | return 0; | ||
1553 | |||
1554 | switch (aiptek->curSetting.stylusButtonLower) { | ||
1555 | case AIPTEK_STYLUS_UPPER_BUTTON: | ||
1556 | s = "upper"; | ||
1557 | break; | ||
1558 | |||
1559 | case AIPTEK_STYLUS_LOWER_BUTTON: | ||
1560 | s = "lower"; | ||
1561 | break; | ||
1562 | 1401 | ||
1563 | default: | 1402 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1564 | s = "unknown"; | 1403 | map_val_to_str(stylus_button_map, |
1565 | break; | 1404 | aiptek->curSetting.stylusButtonLower)); |
1566 | } | ||
1567 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1568 | } | 1405 | } |
1569 | 1406 | ||
1570 | static ssize_t | 1407 | static ssize_t |
1571 | store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1408 | store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1572 | { | 1409 | { |
1573 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1410 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1411 | int new_button = map_str_to_val(stylus_button_map, buf, count); | ||
1574 | 1412 | ||
1575 | if (aiptek == NULL) | 1413 | if (new_button == AIPTEK_INVALID_VALUE) |
1576 | return 0; | 1414 | return -EINVAL; |
1577 | 1415 | ||
1578 | if (strcmp(buf, "upper") == 0) { | 1416 | aiptek->newSetting.stylusButtonLower = new_button; |
1579 | aiptek->newSetting.stylusButtonLower = | ||
1580 | AIPTEK_STYLUS_UPPER_BUTTON; | ||
1581 | } else if (strcmp(buf, "lower") == 0) { | ||
1582 | aiptek->newSetting.stylusButtonLower = | ||
1583 | AIPTEK_STYLUS_LOWER_BUTTON; | ||
1584 | } | ||
1585 | return count; | 1417 | return count; |
1586 | } | 1418 | } |
1587 | 1419 | ||
@@ -1593,49 +1425,33 @@ static DEVICE_ATTR(stylus_lower, | |||
1593 | * support routines for the 'mouse_left' file. Note that this file | 1425 | * support routines for the 'mouse_left' file. Note that this file |
1594 | * both displays current setting and allows for setting changing. | 1426 | * both displays current setting and allows for setting changing. |
1595 | */ | 1427 | */ |
1428 | |||
1429 | static struct aiptek_map mouse_button_map[] = { | ||
1430 | { "left", AIPTEK_MOUSE_LEFT_BUTTON }, | ||
1431 | { "middle", AIPTEK_MOUSE_MIDDLE_BUTTON }, | ||
1432 | { "right", AIPTEK_MOUSE_RIGHT_BUTTON }, | ||
1433 | { NULL, AIPTEK_INVALID_VALUE } | ||
1434 | }; | ||
1435 | |||
1596 | static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf) | 1436 | static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf) |
1597 | { | 1437 | { |
1598 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1438 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1599 | char *s; | ||
1600 | |||
1601 | if (aiptek == NULL) | ||
1602 | return 0; | ||
1603 | |||
1604 | switch (aiptek->curSetting.mouseButtonLeft) { | ||
1605 | case AIPTEK_MOUSE_LEFT_BUTTON: | ||
1606 | s = "left"; | ||
1607 | break; | ||
1608 | |||
1609 | case AIPTEK_MOUSE_MIDDLE_BUTTON: | ||
1610 | s = "middle"; | ||
1611 | break; | ||
1612 | |||
1613 | case AIPTEK_MOUSE_RIGHT_BUTTON: | ||
1614 | s = "right"; | ||
1615 | break; | ||
1616 | 1439 | ||
1617 | default: | 1440 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1618 | s = "unknown"; | 1441 | map_val_to_str(mouse_button_map, |
1619 | break; | 1442 | aiptek->curSetting.mouseButtonLeft)); |
1620 | } | ||
1621 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1622 | } | 1443 | } |
1623 | 1444 | ||
1624 | static ssize_t | 1445 | static ssize_t |
1625 | store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1446 | store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1626 | { | 1447 | { |
1627 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1448 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1449 | int new_button = map_str_to_val(mouse_button_map, buf, count); | ||
1628 | 1450 | ||
1629 | if (aiptek == NULL) | 1451 | if (new_button == AIPTEK_INVALID_VALUE) |
1630 | return 0; | 1452 | return -EINVAL; |
1631 | 1453 | ||
1632 | if (strcmp(buf, "left") == 0) { | 1454 | aiptek->newSetting.mouseButtonLeft = new_button; |
1633 | aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON; | ||
1634 | } else if (strcmp(buf, "middle") == 0) { | ||
1635 | aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON; | ||
1636 | } else if (strcmp(buf, "right") == 0) { | ||
1637 | aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON; | ||
1638 | } | ||
1639 | return count; | 1455 | return count; |
1640 | } | 1456 | } |
1641 | 1457 | ||
@@ -1650,48 +1466,22 @@ static DEVICE_ATTR(mouse_left, | |||
1650 | static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf) | 1466 | static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf) |
1651 | { | 1467 | { |
1652 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1468 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1653 | char *s; | ||
1654 | 1469 | ||
1655 | if (aiptek == NULL) | 1470 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1656 | return 0; | 1471 | map_val_to_str(mouse_button_map, |
1657 | 1472 | aiptek->curSetting.mouseButtonMiddle)); | |
1658 | switch (aiptek->curSetting.mouseButtonMiddle) { | ||
1659 | case AIPTEK_MOUSE_LEFT_BUTTON: | ||
1660 | s = "left"; | ||
1661 | break; | ||
1662 | |||
1663 | case AIPTEK_MOUSE_MIDDLE_BUTTON: | ||
1664 | s = "middle"; | ||
1665 | break; | ||
1666 | |||
1667 | case AIPTEK_MOUSE_RIGHT_BUTTON: | ||
1668 | s = "right"; | ||
1669 | break; | ||
1670 | |||
1671 | default: | ||
1672 | s = "unknown"; | ||
1673 | break; | ||
1674 | } | ||
1675 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1676 | } | 1473 | } |
1677 | 1474 | ||
1678 | static ssize_t | 1475 | static ssize_t |
1679 | store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1476 | store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1680 | { | 1477 | { |
1681 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1478 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1479 | int new_button = map_str_to_val(mouse_button_map, buf, count); | ||
1682 | 1480 | ||
1683 | if (aiptek == NULL) | 1481 | if (new_button == AIPTEK_INVALID_VALUE) |
1684 | return 0; | 1482 | return -EINVAL; |
1685 | 1483 | ||
1686 | if (strcmp(buf, "left") == 0) { | 1484 | aiptek->newSetting.mouseButtonMiddle = new_button; |
1687 | aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON; | ||
1688 | } else if (strcmp(buf, "middle") == 0) { | ||
1689 | aiptek->newSetting.mouseButtonMiddle = | ||
1690 | AIPTEK_MOUSE_MIDDLE_BUTTON; | ||
1691 | } else if (strcmp(buf, "right") == 0) { | ||
1692 | aiptek->newSetting.mouseButtonMiddle = | ||
1693 | AIPTEK_MOUSE_RIGHT_BUTTON; | ||
1694 | } | ||
1695 | return count; | 1485 | return count; |
1696 | } | 1486 | } |
1697 | 1487 | ||
@@ -1706,47 +1496,22 @@ static DEVICE_ATTR(mouse_middle, | |||
1706 | static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf) | 1496 | static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf) |
1707 | { | 1497 | { |
1708 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1498 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1709 | char *s; | ||
1710 | |||
1711 | if (aiptek == NULL) | ||
1712 | return 0; | ||
1713 | |||
1714 | switch (aiptek->curSetting.mouseButtonRight) { | ||
1715 | case AIPTEK_MOUSE_LEFT_BUTTON: | ||
1716 | s = "left"; | ||
1717 | break; | ||
1718 | |||
1719 | case AIPTEK_MOUSE_MIDDLE_BUTTON: | ||
1720 | s = "middle"; | ||
1721 | break; | ||
1722 | 1499 | ||
1723 | case AIPTEK_MOUSE_RIGHT_BUTTON: | 1500 | return snprintf(buf, PAGE_SIZE, "%s\n", |
1724 | s = "right"; | 1501 | map_val_to_str(mouse_button_map, |
1725 | break; | 1502 | aiptek->curSetting.mouseButtonRight)); |
1726 | |||
1727 | default: | ||
1728 | s = "unknown"; | ||
1729 | break; | ||
1730 | } | ||
1731 | return snprintf(buf, PAGE_SIZE, "%s\n", s); | ||
1732 | } | 1503 | } |
1733 | 1504 | ||
1734 | static ssize_t | 1505 | static ssize_t |
1735 | store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1506 | store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
1736 | { | 1507 | { |
1737 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1508 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1509 | int new_button = map_str_to_val(mouse_button_map, buf, count); | ||
1738 | 1510 | ||
1739 | if (aiptek == NULL) | 1511 | if (new_button == AIPTEK_INVALID_VALUE) |
1740 | return 0; | 1512 | return -EINVAL; |
1741 | 1513 | ||
1742 | if (strcmp(buf, "left") == 0) { | 1514 | aiptek->newSetting.mouseButtonRight = new_button; |
1743 | aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON; | ||
1744 | } else if (strcmp(buf, "middle") == 0) { | ||
1745 | aiptek->newSetting.mouseButtonRight = | ||
1746 | AIPTEK_MOUSE_MIDDLE_BUTTON; | ||
1747 | } else if (strcmp(buf, "right") == 0) { | ||
1748 | aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON; | ||
1749 | } | ||
1750 | return count; | 1515 | return count; |
1751 | } | 1516 | } |
1752 | 1517 | ||
@@ -1762,9 +1527,6 @@ static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *att | |||
1762 | { | 1527 | { |
1763 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1528 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1764 | 1529 | ||
1765 | if (aiptek == NULL) | ||
1766 | return 0; | ||
1767 | |||
1768 | if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) { | 1530 | if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) { |
1769 | return snprintf(buf, PAGE_SIZE, "disable\n"); | 1531 | return snprintf(buf, PAGE_SIZE, "disable\n"); |
1770 | } else { | 1532 | } else { |
@@ -1778,9 +1540,6 @@ store_tabletWheel(struct device *dev, struct device_attribute *attr, const char | |||
1778 | { | 1540 | { |
1779 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1541 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1780 | 1542 | ||
1781 | if (aiptek == NULL) | ||
1782 | return 0; | ||
1783 | |||
1784 | aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10); | 1543 | aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10); |
1785 | return count; | 1544 | return count; |
1786 | } | 1545 | } |
@@ -1794,11 +1553,6 @@ static DEVICE_ATTR(wheel, | |||
1794 | */ | 1553 | */ |
1795 | static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf) | 1554 | static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf) |
1796 | { | 1555 | { |
1797 | struct aiptek *aiptek = dev_get_drvdata(dev); | ||
1798 | |||
1799 | if (aiptek == NULL) | ||
1800 | return 0; | ||
1801 | |||
1802 | /* There is nothing useful to display, so a one-line manual | 1556 | /* There is nothing useful to display, so a one-line manual |
1803 | * is in order... | 1557 | * is in order... |
1804 | */ | 1558 | */ |
@@ -1811,9 +1565,6 @@ store_tabletExecute(struct device *dev, struct device_attribute *attr, const cha | |||
1811 | { | 1565 | { |
1812 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1566 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1813 | 1567 | ||
1814 | if (aiptek == NULL) | ||
1815 | return 0; | ||
1816 | |||
1817 | /* We do not care what you write to this file. Merely the action | 1568 | /* We do not care what you write to this file. Merely the action |
1818 | * of writing to this file triggers a tablet reprogramming. | 1569 | * of writing to this file triggers a tablet reprogramming. |
1819 | */ | 1570 | */ |
@@ -1837,9 +1588,6 @@ static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *a | |||
1837 | { | 1588 | { |
1838 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1589 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1839 | 1590 | ||
1840 | if (aiptek == NULL) | ||
1841 | return 0; | ||
1842 | |||
1843 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode); | 1591 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode); |
1844 | } | 1592 | } |
1845 | 1593 | ||
@@ -1853,9 +1601,6 @@ static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute | |||
1853 | { | 1601 | { |
1854 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1602 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1855 | 1603 | ||
1856 | if (aiptek == NULL) | ||
1857 | return 0; | ||
1858 | |||
1859 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode); | 1604 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode); |
1860 | } | 1605 | } |
1861 | 1606 | ||
@@ -1869,86 +1614,39 @@ static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *at | |||
1869 | { | 1614 | { |
1870 | struct aiptek *aiptek = dev_get_drvdata(dev); | 1615 | struct aiptek *aiptek = dev_get_drvdata(dev); |
1871 | 1616 | ||
1872 | if (aiptek == NULL) | ||
1873 | return 0; | ||
1874 | |||
1875 | return snprintf(buf, PAGE_SIZE, "%04x\n", | 1617 | return snprintf(buf, PAGE_SIZE, "%04x\n", |
1876 | aiptek->features.firmwareCode); | 1618 | aiptek->features.firmwareCode); |
1877 | } | 1619 | } |
1878 | 1620 | ||
1879 | static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL); | 1621 | static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL); |
1880 | 1622 | ||
1881 | /*********************************************************************** | 1623 | static struct attribute *aiptek_attributes[] = { |
1882 | * This routine removes all existing sysfs files managed by this device | 1624 | &dev_attr_size.attr, |
1883 | * driver. | 1625 | &dev_attr_pointer_mode.attr, |
1884 | */ | 1626 | &dev_attr_coordinate_mode.attr, |
1885 | static void aiptek_delete_files(struct device *dev) | 1627 | &dev_attr_tool_mode.attr, |
1886 | { | 1628 | &dev_attr_xtilt.attr, |
1887 | device_remove_file(dev, &dev_attr_size); | 1629 | &dev_attr_ytilt.attr, |
1888 | device_remove_file(dev, &dev_attr_product_id); | 1630 | &dev_attr_jitter.attr, |
1889 | device_remove_file(dev, &dev_attr_vendor_id); | 1631 | &dev_attr_delay.attr, |
1890 | device_remove_file(dev, &dev_attr_vendor); | 1632 | &dev_attr_event_count.attr, |
1891 | device_remove_file(dev, &dev_attr_product); | 1633 | &dev_attr_diagnostic.attr, |
1892 | device_remove_file(dev, &dev_attr_pointer_mode); | 1634 | &dev_attr_odm_code.attr, |
1893 | device_remove_file(dev, &dev_attr_coordinate_mode); | 1635 | &dev_attr_model_code.attr, |
1894 | device_remove_file(dev, &dev_attr_tool_mode); | 1636 | &dev_attr_firmware_code.attr, |
1895 | device_remove_file(dev, &dev_attr_xtilt); | 1637 | &dev_attr_stylus_lower.attr, |
1896 | device_remove_file(dev, &dev_attr_ytilt); | 1638 | &dev_attr_stylus_upper.attr, |
1897 | device_remove_file(dev, &dev_attr_jitter); | 1639 | &dev_attr_mouse_left.attr, |
1898 | device_remove_file(dev, &dev_attr_delay); | 1640 | &dev_attr_mouse_middle.attr, |
1899 | device_remove_file(dev, &dev_attr_input_path); | 1641 | &dev_attr_mouse_right.attr, |
1900 | device_remove_file(dev, &dev_attr_event_count); | 1642 | &dev_attr_wheel.attr, |
1901 | device_remove_file(dev, &dev_attr_diagnostic); | 1643 | &dev_attr_execute.attr, |
1902 | device_remove_file(dev, &dev_attr_odm_code); | 1644 | NULL |
1903 | device_remove_file(dev, &dev_attr_model_code); | 1645 | }; |
1904 | device_remove_file(dev, &dev_attr_firmware_code); | ||
1905 | device_remove_file(dev, &dev_attr_stylus_lower); | ||
1906 | device_remove_file(dev, &dev_attr_stylus_upper); | ||
1907 | device_remove_file(dev, &dev_attr_mouse_left); | ||
1908 | device_remove_file(dev, &dev_attr_mouse_middle); | ||
1909 | device_remove_file(dev, &dev_attr_mouse_right); | ||
1910 | device_remove_file(dev, &dev_attr_wheel); | ||
1911 | device_remove_file(dev, &dev_attr_execute); | ||
1912 | } | ||
1913 | |||
1914 | /*********************************************************************** | ||
1915 | * This routine creates the sysfs files managed by this device | ||
1916 | * driver. | ||
1917 | */ | ||
1918 | static int aiptek_add_files(struct device *dev) | ||
1919 | { | ||
1920 | int ret; | ||
1921 | 1646 | ||
1922 | if ((ret = device_create_file(dev, &dev_attr_size)) || | 1647 | static struct attribute_group aiptek_attribute_group = { |
1923 | (ret = device_create_file(dev, &dev_attr_product_id)) || | 1648 | .attrs = aiptek_attributes, |
1924 | (ret = device_create_file(dev, &dev_attr_vendor_id)) || | 1649 | }; |
1925 | (ret = device_create_file(dev, &dev_attr_vendor)) || | ||
1926 | (ret = device_create_file(dev, &dev_attr_product)) || | ||
1927 | (ret = device_create_file(dev, &dev_attr_pointer_mode)) || | ||
1928 | (ret = device_create_file(dev, &dev_attr_coordinate_mode)) || | ||
1929 | (ret = device_create_file(dev, &dev_attr_tool_mode)) || | ||
1930 | (ret = device_create_file(dev, &dev_attr_xtilt)) || | ||
1931 | (ret = device_create_file(dev, &dev_attr_ytilt)) || | ||
1932 | (ret = device_create_file(dev, &dev_attr_jitter)) || | ||
1933 | (ret = device_create_file(dev, &dev_attr_delay)) || | ||
1934 | (ret = device_create_file(dev, &dev_attr_input_path)) || | ||
1935 | (ret = device_create_file(dev, &dev_attr_event_count)) || | ||
1936 | (ret = device_create_file(dev, &dev_attr_diagnostic)) || | ||
1937 | (ret = device_create_file(dev, &dev_attr_odm_code)) || | ||
1938 | (ret = device_create_file(dev, &dev_attr_model_code)) || | ||
1939 | (ret = device_create_file(dev, &dev_attr_firmware_code)) || | ||
1940 | (ret = device_create_file(dev, &dev_attr_stylus_lower)) || | ||
1941 | (ret = device_create_file(dev, &dev_attr_stylus_upper)) || | ||
1942 | (ret = device_create_file(dev, &dev_attr_mouse_left)) || | ||
1943 | (ret = device_create_file(dev, &dev_attr_mouse_middle)) || | ||
1944 | (ret = device_create_file(dev, &dev_attr_mouse_right)) || | ||
1945 | (ret = device_create_file(dev, &dev_attr_wheel)) || | ||
1946 | (ret = device_create_file(dev, &dev_attr_execute))) { | ||
1947 | err("aiptek: killing own sysfs device files\n"); | ||
1948 | aiptek_delete_files(dev); | ||
1949 | } | ||
1950 | return ret; | ||
1951 | } | ||
1952 | 1650 | ||
1953 | /*********************************************************************** | 1651 | /*********************************************************************** |
1954 | * This routine is called when a tablet has been identified. It basically | 1652 | * This routine is called when a tablet has been identified. It basically |
@@ -1961,8 +1659,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
1961 | struct usb_endpoint_descriptor *endpoint; | 1659 | struct usb_endpoint_descriptor *endpoint; |
1962 | struct aiptek *aiptek; | 1660 | struct aiptek *aiptek; |
1963 | struct input_dev *inputdev; | 1661 | struct input_dev *inputdev; |
1964 | struct input_handle *inputhandle; | ||
1965 | struct list_head *node, *next; | ||
1966 | int i; | 1662 | int i; |
1967 | int speeds[] = { 0, | 1663 | int speeds[] = { 0, |
1968 | AIPTEK_PROGRAMMABLE_DELAY_50, | 1664 | AIPTEK_PROGRAMMABLE_DELAY_50, |
@@ -1984,17 +1680,23 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
1984 | 1680 | ||
1985 | aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL); | 1681 | aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL); |
1986 | inputdev = input_allocate_device(); | 1682 | inputdev = input_allocate_device(); |
1987 | if (!aiptek || !inputdev) | 1683 | if (!aiptek || !inputdev) { |
1684 | warn("aiptek: cannot allocate memory or input device"); | ||
1988 | goto fail1; | 1685 | goto fail1; |
1686 | } | ||
1989 | 1687 | ||
1990 | aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, | 1688 | aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, |
1991 | GFP_ATOMIC, &aiptek->data_dma); | 1689 | GFP_ATOMIC, &aiptek->data_dma); |
1992 | if (!aiptek->data) | 1690 | if (!aiptek->data) { |
1691 | warn("aiptek: cannot allocate usb buffer"); | ||
1993 | goto fail1; | 1692 | goto fail1; |
1693 | } | ||
1994 | 1694 | ||
1995 | aiptek->urb = usb_alloc_urb(0, GFP_KERNEL); | 1695 | aiptek->urb = usb_alloc_urb(0, GFP_KERNEL); |
1996 | if (!aiptek->urb) | 1696 | if (!aiptek->urb) { |
1697 | warn("aiptek: cannot allocate urb"); | ||
1997 | goto fail2; | 1698 | goto fail2; |
1699 | } | ||
1998 | 1700 | ||
1999 | aiptek->inputdev = inputdev; | 1701 | aiptek->inputdev = inputdev; |
2000 | aiptek->usbdev = usbdev; | 1702 | aiptek->usbdev = usbdev; |
@@ -2002,6 +1704,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
2002 | aiptek->inDelay = 0; | 1704 | aiptek->inDelay = 0; |
2003 | aiptek->endDelay = 0; | 1705 | aiptek->endDelay = 0; |
2004 | aiptek->previousJitterable = 0; | 1706 | aiptek->previousJitterable = 0; |
1707 | aiptek->lastMacro = -1; | ||
2005 | 1708 | ||
2006 | /* Set up the curSettings struct. Said struct contains the current | 1709 | /* Set up the curSettings struct. Said struct contains the current |
2007 | * programmable parameters. The newSetting struct contains changes | 1710 | * programmable parameters. The newSetting struct contains changes |
@@ -2054,36 +1757,23 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
2054 | /* Now program the capacities of the tablet, in terms of being | 1757 | /* Now program the capacities of the tablet, in terms of being |
2055 | * an input device. | 1758 | * an input device. |
2056 | */ | 1759 | */ |
2057 | inputdev->evbit[0] |= BIT(EV_KEY) | 1760 | for (i = 0; i < ARRAY_SIZE(eventTypes); ++i) |
2058 | | BIT(EV_ABS) | 1761 | __set_bit(eventTypes[i], inputdev->evbit); |
2059 | | BIT(EV_REL) | ||
2060 | | BIT(EV_MSC); | ||
2061 | |||
2062 | inputdev->absbit[0] |= BIT(ABS_MISC); | ||
2063 | 1762 | ||
2064 | inputdev->relbit[0] |= | 1763 | for (i = 0; i < ARRAY_SIZE(absEvents); ++i) |
2065 | (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC)); | 1764 | __set_bit(absEvents[i], inputdev->absbit); |
2066 | 1765 | ||
2067 | inputdev->keybit[LONG(BTN_LEFT)] |= | 1766 | for (i = 0; i < ARRAY_SIZE(relEvents); ++i) |
2068 | (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE)); | 1767 | __set_bit(relEvents[i], inputdev->relbit); |
2069 | 1768 | ||
2070 | inputdev->keybit[LONG(BTN_DIGI)] |= | 1769 | __set_bit(MSC_SERIAL, inputdev->mscbit); |
2071 | (BIT(BTN_TOOL_PEN) | | ||
2072 | BIT(BTN_TOOL_RUBBER) | | ||
2073 | BIT(BTN_TOOL_PENCIL) | | ||
2074 | BIT(BTN_TOOL_AIRBRUSH) | | ||
2075 | BIT(BTN_TOOL_BRUSH) | | ||
2076 | BIT(BTN_TOOL_MOUSE) | | ||
2077 | BIT(BTN_TOOL_LENS) | | ||
2078 | BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2)); | ||
2079 | 1770 | ||
2080 | inputdev->mscbit[0] = BIT(MSC_SERIAL); | 1771 | /* Set up key and button codes */ |
1772 | for (i = 0; i < ARRAY_SIZE(buttonEvents); ++i) | ||
1773 | __set_bit(buttonEvents[i], inputdev->keybit); | ||
2081 | 1774 | ||
2082 | /* Programming the tablet macro keys needs to be done with a for loop | ||
2083 | * as the keycodes are discontiguous. | ||
2084 | */ | ||
2085 | for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i) | 1775 | for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i) |
2086 | set_bit(macroKeyEvents[i], inputdev->keybit); | 1776 | __set_bit(macroKeyEvents[i], inputdev->keybit); |
2087 | 1777 | ||
2088 | /* | 1778 | /* |
2089 | * Program the input device coordinate capacities. We do not yet | 1779 | * Program the input device coordinate capacities. We do not yet |
@@ -2134,25 +1824,11 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
2134 | } | 1824 | } |
2135 | } | 1825 | } |
2136 | 1826 | ||
2137 | /* Register the tablet as an Input Device | 1827 | /* Murphy says that some day someone will have a tablet that fails the |
2138 | */ | 1828 | above test. That's you, Frederic Rodrigo */ |
2139 | err = input_register_device(aiptek->inputdev); | 1829 | if (i == ARRAY_SIZE(speeds)) { |
2140 | if (err) | 1830 | info("input: Aiptek tried all speeds, no sane response"); |
2141 | goto fail2; | 1831 | goto fail2; |
2142 | |||
2143 | /* We now will look for the evdev device which is mapped to | ||
2144 | * the tablet. The partial name is kept in the link list of | ||
2145 | * input_handles associated with this input device. | ||
2146 | * What identifies an evdev input_handler is that it begins | ||
2147 | * with 'event', continues with a digit, and that in turn | ||
2148 | * is mapped to input/eventN. | ||
2149 | */ | ||
2150 | list_for_each_safe(node, next, &inputdev->h_list) { | ||
2151 | inputhandle = to_handle(node); | ||
2152 | if (strncmp(inputhandle->name, "event", 5) == 0) { | ||
2153 | strcpy(aiptek->features.inputPath, inputhandle->name); | ||
2154 | break; | ||
2155 | } | ||
2156 | } | 1832 | } |
2157 | 1833 | ||
2158 | /* Associate this driver's struct with the usb interface. | 1834 | /* Associate this driver's struct with the usb interface. |
@@ -2161,18 +1837,27 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
2161 | 1837 | ||
2162 | /* Set up the sysfs files | 1838 | /* Set up the sysfs files |
2163 | */ | 1839 | */ |
2164 | aiptek_add_files(&intf->dev); | 1840 | err = sysfs_create_group(&intf->dev.kobj, &aiptek_attribute_group); |
1841 | if (err) { | ||
1842 | warn("aiptek: cannot create sysfs group err: %d", err); | ||
1843 | goto fail3; | ||
1844 | } | ||
2165 | 1845 | ||
2166 | /* Make sure the evdev module is loaded. Assuming evdev IS a module :-) | 1846 | /* Register the tablet as an Input Device |
2167 | */ | 1847 | */ |
2168 | if (request_module("evdev") != 0) | 1848 | err = input_register_device(aiptek->inputdev); |
2169 | info("aiptek: error loading 'evdev' module"); | 1849 | if (err) { |
2170 | 1850 | warn("aiptek: input_register_device returned err: %d", err); | |
1851 | goto fail4; | ||
1852 | } | ||
2171 | return 0; | 1853 | return 0; |
2172 | 1854 | ||
1855 | fail4: sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group); | ||
1856 | fail3: usb_free_urb(aiptek->urb); | ||
2173 | fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, | 1857 | fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, |
2174 | aiptek->data_dma); | 1858 | aiptek->data_dma); |
2175 | fail1: input_free_device(inputdev); | 1859 | fail1: usb_set_intfdata(intf, NULL); |
1860 | input_free_device(inputdev); | ||
2176 | kfree(aiptek); | 1861 | kfree(aiptek); |
2177 | return err; | 1862 | return err; |
2178 | } | 1863 | } |
@@ -2192,7 +1877,7 @@ static void aiptek_disconnect(struct usb_interface *intf) | |||
2192 | */ | 1877 | */ |
2193 | usb_kill_urb(aiptek->urb); | 1878 | usb_kill_urb(aiptek->urb); |
2194 | input_unregister_device(aiptek->inputdev); | 1879 | input_unregister_device(aiptek->inputdev); |
2195 | aiptek_delete_files(&intf->dev); | 1880 | sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group); |
2196 | usb_free_urb(aiptek->urb); | 1881 | usb_free_urb(aiptek->urb); |
2197 | usb_buffer_free(interface_to_usbdev(intf), | 1882 | usb_buffer_free(interface_to_usbdev(intf), |
2198 | AIPTEK_PACKET_LENGTH, | 1883 | AIPTEK_PACKET_LENGTH, |
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index ef01a807ec0f..6542edb6f76e 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h | |||
@@ -11,7 +11,7 @@ | |||
11 | * Copyright (c) 2000 Daniel Egger <egger@suse.de> | 11 | * Copyright (c) 2000 Daniel Egger <egger@suse.de> |
12 | * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com> | 12 | * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com> |
13 | * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be> | 13 | * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be> |
14 | * Copyright (c) 2002-2006 Ping Cheng <pingc@wacom.com> | 14 | * Copyright (c) 2002-2007 Ping Cheng <pingc@wacom.com> |
15 | * | 15 | * |
16 | * ChangeLog: | 16 | * ChangeLog: |
17 | * v0.1 (vp) - Initial release | 17 | * v0.1 (vp) - Initial release |
@@ -62,8 +62,9 @@ | |||
62 | * - Minor data report fix | 62 | * - Minor data report fix |
63 | * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, | 63 | * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, |
64 | * - where wacom_sys.c deals with system specific code, | 64 | * - where wacom_sys.c deals with system specific code, |
65 | * - and wacom_wac.c deals with Wacom specific code | 65 | * - and wacom_wac.c deals with Wacom specific code |
66 | * - Support Intuos3 4x6 | 66 | * - Support Intuos3 4x6 |
67 | * v1.47 (pc) - Added support for Bamboo | ||
67 | */ | 68 | */ |
68 | 69 | ||
69 | /* | 70 | /* |
@@ -84,7 +85,7 @@ | |||
84 | /* | 85 | /* |
85 | * Version Information | 86 | * Version Information |
86 | */ | 87 | */ |
87 | #define DRIVER_VERSION "v1.46" | 88 | #define DRIVER_VERSION "v1.47" |
88 | #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" | 89 | #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" |
89 | #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" | 90 | #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" |
90 | #define DRIVER_LICENSE "GPL" | 91 | #define DRIVER_LICENSE "GPL" |
@@ -123,6 +124,7 @@ extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wa | |||
123 | extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 124 | extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
124 | extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 125 | extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
125 | extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | 126 | extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); |
127 | extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac); | ||
126 | extern __u16 wacom_le16_to_cpu(unsigned char *data); | 128 | extern __u16 wacom_le16_to_cpu(unsigned char *data); |
127 | extern __u16 wacom_be16_to_cpu(unsigned char *data); | 129 | extern __u16 wacom_be16_to_cpu(unsigned char *data); |
128 | extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id); | 130 | extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id); |
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 83bddef66067..064e123c9b76 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
@@ -138,6 +138,12 @@ static void wacom_close(struct input_dev *dev) | |||
138 | usb_kill_urb(wacom->irq); | 138 | usb_kill_urb(wacom->irq); |
139 | } | 139 | } |
140 | 140 | ||
141 | void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | ||
142 | { | ||
143 | input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_1) | BIT(BTN_5); | ||
144 | input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); | ||
145 | } | ||
146 | |||
141 | void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 147 | void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) |
142 | { | 148 | { |
143 | input_dev->evbit[0] |= BIT(EV_MSC); | 149 | input_dev->evbit[0] |= BIT(EV_MSC); |
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 7661f03a2db2..fc03ba256f4c 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c | |||
@@ -178,7 +178,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) | |||
178 | 178 | ||
179 | case 2: /* Mouse with wheel */ | 179 | case 2: /* Mouse with wheel */ |
180 | wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04); | 180 | wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04); |
181 | if (wacom->features->type == WACOM_G4) { | 181 | if (wacom->features->type == WACOM_G4 || |
182 | wacom->features->type == WACOM_MO) { | ||
182 | rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03); | 183 | rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03); |
183 | wacom_report_rel(wcombo, REL_WHEEL, -rw); | 184 | wacom_report_rel(wcombo, REL_WHEEL, -rw); |
184 | } else | 185 | } else |
@@ -190,7 +191,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) | |||
190 | id = CURSOR_DEVICE_ID; | 191 | id = CURSOR_DEVICE_ID; |
191 | wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); | 192 | wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); |
192 | wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); | 193 | wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); |
193 | if (wacom->features->type == WACOM_G4) | 194 | if (wacom->features->type == WACOM_G4 || |
195 | wacom->features->type == WACOM_MO) | ||
194 | wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f); | 196 | wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f); |
195 | else | 197 | else |
196 | wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); | 198 | wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); |
@@ -226,7 +228,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) | |||
226 | } | 228 | } |
227 | 229 | ||
228 | /* send pad data */ | 230 | /* send pad data */ |
229 | if (wacom->features->type == WACOM_G4) { | 231 | switch (wacom->features->type) { |
232 | case WACOM_G4: | ||
230 | if (data[7] & 0xf8) { | 233 | if (data[7] & 0xf8) { |
231 | wacom_input_sync(wcombo); /* sync last event */ | 234 | wacom_input_sync(wcombo); /* sync last event */ |
232 | wacom->id[1] = 1; | 235 | wacom->id[1] = 1; |
@@ -247,6 +250,33 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) | |||
247 | wacom_report_abs(wcombo, ABS_MISC, 0); | 250 | wacom_report_abs(wcombo, ABS_MISC, 0); |
248 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | 251 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); |
249 | } | 252 | } |
253 | break; | ||
254 | case WACOM_MO: | ||
255 | if ((data[7] & 0xf8) || (data[8] & 0x80)) { | ||
256 | wacom_input_sync(wcombo); /* sync last event */ | ||
257 | wacom->id[1] = 1; | ||
258 | wacom->serial[1] = (data[7] & 0xf8); | ||
259 | wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); | ||
260 | wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); | ||
261 | wacom_report_key(wcombo, BTN_4, (data[7] & 0x10)); | ||
262 | wacom_report_key(wcombo, BTN_5, (data[7] & 0x40)); | ||
263 | wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f)); | ||
264 | wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0); | ||
265 | wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); | ||
266 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | ||
267 | } else if (wacom->id[1]) { | ||
268 | wacom_input_sync(wcombo); /* sync last event */ | ||
269 | wacom->id[1] = 0; | ||
270 | wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); | ||
271 | wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); | ||
272 | wacom_report_key(wcombo, BTN_4, (data[7] & 0x10)); | ||
273 | wacom_report_key(wcombo, BTN_5, (data[7] & 0x40)); | ||
274 | wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f)); | ||
275 | wacom_report_key(wcombo, BTN_TOOL_FINGER, 0); | ||
276 | wacom_report_abs(wcombo, ABS_MISC, 0); | ||
277 | wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); | ||
278 | } | ||
279 | break; | ||
250 | } | 280 | } |
251 | return 1; | 281 | return 1; |
252 | } | 282 | } |
@@ -331,7 +361,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) | |||
331 | wacom_report_key(wcombo, BTN_EXTRA, 0); | 361 | wacom_report_key(wcombo, BTN_EXTRA, 0); |
332 | wacom_report_abs(wcombo, ABS_THROTTLE, 0); | 362 | wacom_report_abs(wcombo, ABS_THROTTLE, 0); |
333 | wacom_report_abs(wcombo, ABS_RZ, 0); | 363 | wacom_report_abs(wcombo, ABS_RZ, 0); |
334 | } else { | 364 | } else { |
335 | wacom_report_abs(wcombo, ABS_PRESSURE, 0); | 365 | wacom_report_abs(wcombo, ABS_PRESSURE, 0); |
336 | wacom_report_abs(wcombo, ABS_TILT_X, 0); | 366 | wacom_report_abs(wcombo, ABS_TILT_X, 0); |
337 | wacom_report_abs(wcombo, ABS_TILT_Y, 0); | 367 | wacom_report_abs(wcombo, ABS_TILT_Y, 0); |
@@ -423,9 +453,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) | |||
423 | return result-1; | 453 | return result-1; |
424 | 454 | ||
425 | /* Only large I3 and I1 & I2 support Lense Cursor */ | 455 | /* Only large I3 and I1 & I2 support Lense Cursor */ |
426 | if((wacom->tool[idx] == BTN_TOOL_LENS) | 456 | if ((wacom->tool[idx] == BTN_TOOL_LENS) |
427 | && ((wacom->features->type == INTUOS3) | 457 | && ((wacom->features->type == INTUOS3) |
428 | || (wacom->features->type == INTUOS3S))) | 458 | || (wacom->features->type == INTUOS3S))) |
429 | return 0; | 459 | return 0; |
430 | 460 | ||
431 | /* Cintiq doesn't send data when RDY bit isn't set */ | 461 | /* Cintiq doesn't send data when RDY bit isn't set */ |
@@ -517,6 +547,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) | |||
517 | break; | 547 | break; |
518 | case WACOM_G4: | 548 | case WACOM_G4: |
519 | case GRAPHIRE: | 549 | case GRAPHIRE: |
550 | case WACOM_MO: | ||
520 | return (wacom_graphire_irq(wacom_wac, wcombo)); | 551 | return (wacom_graphire_irq(wacom_wac, wcombo)); |
521 | break; | 552 | break; |
522 | case PTU: | 553 | case PTU: |
@@ -538,6 +569,8 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) | |||
538 | void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac) | 569 | void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac) |
539 | { | 570 | { |
540 | switch (wacom_wac->features->type) { | 571 | switch (wacom_wac->features->type) { |
572 | case WACOM_MO: | ||
573 | input_dev_mo(input_dev, wacom_wac); | ||
541 | case WACOM_G4: | 574 | case WACOM_G4: |
542 | input_dev_g4(input_dev, wacom_wac); | 575 | input_dev_g4(input_dev, wacom_wac); |
543 | /* fall through */ | 576 | /* fall through */ |
@@ -579,6 +612,7 @@ static struct wacom_features wacom_features[] = { | |||
579 | { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE }, | 612 | { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE }, |
580 | { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE }, | 613 | { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE }, |
581 | { "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE }, | 614 | { "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE }, |
615 | { "Wacom Bamboo", 9, 14760, 9225, 511, 63, WACOM_MO }, | ||
582 | { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS }, | 616 | { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS }, |
583 | { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, | 617 | { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, |
584 | { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS }, | 618 | { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS }, |
@@ -627,6 +661,7 @@ static struct usb_device_id wacom_ids[] = { | |||
627 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) }, | 661 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) }, |
628 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) }, | 662 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) }, |
629 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) }, | 663 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) }, |
664 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) }, | ||
630 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) }, | 665 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) }, |
631 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) }, | 666 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) }, |
632 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) }, | 667 | { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) }, |
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index a5e12e8756de..a302e229bb8a 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h | |||
@@ -25,6 +25,7 @@ enum { | |||
25 | INTUOS3, | 25 | INTUOS3, |
26 | INTUOS3L, | 26 | INTUOS3L, |
27 | CINTIQ, | 27 | CINTIQ, |
28 | WACOM_MO, | ||
28 | MAX_TYPE | 29 | MAX_TYPE |
29 | }; | 30 | }; |
30 | 31 | ||
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e5cca9bd0406..69371779806a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -177,6 +177,7 @@ config TOUCHSCREEN_USB_COMPOSITE | |||
177 | - some other eTurboTouch | 177 | - some other eTurboTouch |
178 | - Gunze AHL61 | 178 | - Gunze AHL61 |
179 | - DMC TSC-10/25 | 179 | - DMC TSC-10/25 |
180 | - IRTOUCHSYSTEMS/UNITOP | ||
180 | 181 | ||
181 | Have a look at <http://linux.chapter7.ch/touchkit/> for | 182 | Have a look at <http://linux.chapter7.ch/touchkit/> for |
182 | a usage description and the required user-space stuff. | 183 | a usage description and the required user-space stuff. |
@@ -219,4 +220,9 @@ config TOUCHSCREEN_USB_DMC_TSC10 | |||
219 | bool "DMC TSC-10/25 device support" if EMBEDDED | 220 | bool "DMC TSC-10/25 device support" if EMBEDDED |
220 | depends on TOUCHSCREEN_USB_COMPOSITE | 221 | depends on TOUCHSCREEN_USB_COMPOSITE |
221 | 222 | ||
223 | config TOUCHSCREEN_USB_IRTOUCH | ||
224 | default y | ||
225 | bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED | ||
226 | depends on TOUCHSCREEN_USB_COMPOSITE | ||
227 | |||
222 | endif | 228 | endif |
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index e3f22852bd09..b407028ffc59 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * - eTurboTouch | 9 | * - eTurboTouch |
10 | * - Gunze AHL61 | 10 | * - Gunze AHL61 |
11 | * - DMC TSC-10/25 | 11 | * - DMC TSC-10/25 |
12 | * - IRTOUCHSYSTEMS/UNITOP | ||
12 | * | 13 | * |
13 | * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> | 14 | * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> |
14 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) | 15 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) |
@@ -110,6 +111,7 @@ enum { | |||
110 | DEVTYPE_ETURBO, | 111 | DEVTYPE_ETURBO, |
111 | DEVTYPE_GUNZE, | 112 | DEVTYPE_GUNZE, |
112 | DEVTYPE_DMC_TSC10, | 113 | DEVTYPE_DMC_TSC10, |
114 | DEVTYPE_IRTOUCH, | ||
113 | }; | 115 | }; |
114 | 116 | ||
115 | static struct usb_device_id usbtouch_devices[] = { | 117 | static struct usb_device_id usbtouch_devices[] = { |
@@ -150,6 +152,11 @@ static struct usb_device_id usbtouch_devices[] = { | |||
150 | {USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10}, | 152 | {USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10}, |
151 | #endif | 153 | #endif |
152 | 154 | ||
155 | #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH | ||
156 | {USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH}, | ||
157 | {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH}, | ||
158 | #endif | ||
159 | |||
153 | {} | 160 | {} |
154 | }; | 161 | }; |
155 | 162 | ||
@@ -416,6 +423,21 @@ static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | |||
416 | 423 | ||
417 | 424 | ||
418 | /***************************************************************************** | 425 | /***************************************************************************** |
426 | * IRTOUCH Part | ||
427 | */ | ||
428 | #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH | ||
429 | static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | ||
430 | { | ||
431 | dev->x = (pkt[3] << 8) | pkt[2]; | ||
432 | dev->y = (pkt[5] << 8) | pkt[4]; | ||
433 | dev->touch = (pkt[1] & 0x03) ? 1 : 0; | ||
434 | |||
435 | return 1; | ||
436 | } | ||
437 | #endif | ||
438 | |||
439 | |||
440 | /***************************************************************************** | ||
419 | * the different device descriptors | 441 | * the different device descriptors |
420 | */ | 442 | */ |
421 | static struct usbtouch_device_info usbtouch_dev_info[] = { | 443 | static struct usbtouch_device_info usbtouch_dev_info[] = { |
@@ -504,6 +526,17 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { | |||
504 | .read_data = dmc_tsc10_read_data, | 526 | .read_data = dmc_tsc10_read_data, |
505 | }, | 527 | }, |
506 | #endif | 528 | #endif |
529 | |||
530 | #ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH | ||
531 | [DEVTYPE_IRTOUCH] = { | ||
532 | .min_xc = 0x0, | ||
533 | .max_xc = 0x0fff, | ||
534 | .min_yc = 0x0, | ||
535 | .max_yc = 0x0fff, | ||
536 | .rept_size = 8, | ||
537 | .read_data = irtouch_read_data, | ||
538 | }, | ||
539 | #endif | ||
507 | }; | 540 | }; |
508 | 541 | ||
509 | 542 | ||
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 2db364898e15..d2f882e98e5e 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c | |||
@@ -109,9 +109,11 @@ struct tsdev { | |||
109 | int open; | 109 | int open; |
110 | int minor; | 110 | int minor; |
111 | char name[8]; | 111 | char name[8]; |
112 | struct input_handle handle; | ||
112 | wait_queue_head_t wait; | 113 | wait_queue_head_t wait; |
113 | struct list_head client_list; | 114 | struct list_head client_list; |
114 | struct input_handle handle; | 115 | struct device dev; |
116 | |||
115 | int x, y, pressure; | 117 | int x, y, pressure; |
116 | struct ts_calibration cal; | 118 | struct ts_calibration cal; |
117 | }; | 119 | }; |
@@ -163,9 +165,13 @@ static int tsdev_open(struct inode *inode, struct file *file) | |||
163 | if (!tsdev || !tsdev->exist) | 165 | if (!tsdev || !tsdev->exist) |
164 | return -ENODEV; | 166 | return -ENODEV; |
165 | 167 | ||
168 | get_device(&tsdev->dev); | ||
169 | |||
166 | client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); | 170 | client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); |
167 | if (!client) | 171 | if (!client) { |
168 | return -ENOMEM; | 172 | error = -ENOMEM; |
173 | goto err_put_tsdev; | ||
174 | } | ||
169 | 175 | ||
170 | client->tsdev = tsdev; | 176 | client->tsdev = tsdev; |
171 | client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0; | 177 | client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0; |
@@ -173,19 +179,25 @@ static int tsdev_open(struct inode *inode, struct file *file) | |||
173 | 179 | ||
174 | if (!tsdev->open++ && tsdev->exist) { | 180 | if (!tsdev->open++ && tsdev->exist) { |
175 | error = input_open_device(&tsdev->handle); | 181 | error = input_open_device(&tsdev->handle); |
176 | if (error) { | 182 | if (error) |
177 | list_del(&client->node); | 183 | goto err_free_client; |
178 | kfree(client); | ||
179 | return error; | ||
180 | } | ||
181 | } | 184 | } |
182 | 185 | ||
183 | file->private_data = client; | 186 | file->private_data = client; |
184 | return 0; | 187 | return 0; |
188 | |||
189 | err_free_client: | ||
190 | list_del(&client->node); | ||
191 | kfree(client); | ||
192 | err_put_tsdev: | ||
193 | put_device(&tsdev->dev); | ||
194 | return error; | ||
185 | } | 195 | } |
186 | 196 | ||
187 | static void tsdev_free(struct tsdev *tsdev) | 197 | static void tsdev_free(struct device *dev) |
188 | { | 198 | { |
199 | struct tsdev *tsdev = container_of(dev, struct tsdev, dev); | ||
200 | |||
189 | tsdev_table[tsdev->minor] = NULL; | 201 | tsdev_table[tsdev->minor] = NULL; |
190 | kfree(tsdev); | 202 | kfree(tsdev); |
191 | } | 203 | } |
@@ -200,12 +212,10 @@ static int tsdev_release(struct inode *inode, struct file *file) | |||
200 | list_del(&client->node); | 212 | list_del(&client->node); |
201 | kfree(client); | 213 | kfree(client); |
202 | 214 | ||
203 | if (!--tsdev->open) { | 215 | if (!--tsdev->open && tsdev->exist) |
204 | if (tsdev->exist) | 216 | input_close_device(&tsdev->handle); |
205 | input_close_device(&tsdev->handle); | 217 | |
206 | else | 218 | put_device(&tsdev->dev); |
207 | tsdev_free(tsdev); | ||
208 | } | ||
209 | 219 | ||
210 | return 0; | 220 | return 0; |
211 | } | 221 | } |
@@ -361,7 +371,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
361 | int x, y, tmp; | 371 | int x, y, tmp; |
362 | 372 | ||
363 | do_gettimeofday(&time); | 373 | do_gettimeofday(&time); |
364 | client->event[client->head].millisecs = time.tv_usec / 100; | 374 | client->event[client->head].millisecs = time.tv_usec / 1000; |
365 | client->event[client->head].pressure = tsdev->pressure; | 375 | client->event[client->head].pressure = tsdev->pressure; |
366 | 376 | ||
367 | x = tsdev->x; | 377 | x = tsdev->x; |
@@ -388,8 +398,6 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
388 | const struct input_device_id *id) | 398 | const struct input_device_id *id) |
389 | { | 399 | { |
390 | struct tsdev *tsdev; | 400 | struct tsdev *tsdev; |
391 | struct class_device *cdev; | ||
392 | dev_t devt; | ||
393 | int minor, delta; | 401 | int minor, delta; |
394 | int error; | 402 | int error; |
395 | 403 | ||
@@ -407,14 +415,13 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
407 | INIT_LIST_HEAD(&tsdev->client_list); | 415 | INIT_LIST_HEAD(&tsdev->client_list); |
408 | init_waitqueue_head(&tsdev->wait); | 416 | init_waitqueue_head(&tsdev->wait); |
409 | 417 | ||
410 | sprintf(tsdev->name, "ts%d", minor); | ||
411 | |||
412 | tsdev->exist = 1; | 418 | tsdev->exist = 1; |
413 | tsdev->minor = minor; | 419 | tsdev->minor = minor; |
414 | tsdev->handle.dev = dev; | 420 | tsdev->handle.dev = dev; |
415 | tsdev->handle.name = tsdev->name; | 421 | tsdev->handle.name = tsdev->name; |
416 | tsdev->handle.handler = handler; | 422 | tsdev->handle.handler = handler; |
417 | tsdev->handle.private = tsdev; | 423 | tsdev->handle.private = tsdev; |
424 | snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor); | ||
418 | 425 | ||
419 | /* Precompute the rough calibration matrix */ | 426 | /* Precompute the rough calibration matrix */ |
420 | delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; | 427 | delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; |
@@ -429,36 +436,30 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
429 | tsdev->cal.yscale = (yres << 8) / delta; | 436 | tsdev->cal.yscale = (yres << 8) / delta; |
430 | tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); | 437 | tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); |
431 | 438 | ||
432 | tsdev_table[minor] = tsdev; | 439 | snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id), |
433 | 440 | "ts%d", minor); | |
434 | devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), | 441 | tsdev->dev.class = &input_class; |
442 | tsdev->dev.parent = &dev->dev; | ||
443 | tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor); | ||
444 | tsdev->dev.release = tsdev_free; | ||
445 | device_initialize(&tsdev->dev); | ||
435 | 446 | ||
436 | cdev = class_device_create(&input_class, &dev->cdev, devt, | 447 | tsdev_table[minor] = tsdev; |
437 | dev->cdev.dev, tsdev->name); | ||
438 | if (IS_ERR(cdev)) { | ||
439 | error = PTR_ERR(cdev); | ||
440 | goto err_free_tsdev; | ||
441 | } | ||
442 | 448 | ||
443 | /* temporary symlink to keep userspace happy */ | 449 | error = device_add(&tsdev->dev); |
444 | error = sysfs_create_link(&input_class.subsys.kobj, | ||
445 | &cdev->kobj, tsdev->name); | ||
446 | if (error) | 450 | if (error) |
447 | goto err_cdev_destroy; | 451 | goto err_free_tsdev; |
448 | 452 | ||
449 | error = input_register_handle(&tsdev->handle); | 453 | error = input_register_handle(&tsdev->handle); |
450 | if (error) | 454 | if (error) |
451 | goto err_remove_link; | 455 | goto err_delete_tsdev; |
452 | 456 | ||
453 | return 0; | 457 | return 0; |
454 | 458 | ||
455 | err_remove_link: | 459 | err_delete_tsdev: |
456 | sysfs_remove_link(&input_class.subsys.kobj, tsdev->name); | 460 | device_del(&tsdev->dev); |
457 | err_cdev_destroy: | ||
458 | class_device_destroy(&input_class, devt); | ||
459 | err_free_tsdev: | 461 | err_free_tsdev: |
460 | tsdev_table[minor] = NULL; | 462 | put_device(&tsdev->dev); |
461 | kfree(tsdev); | ||
462 | return error; | 463 | return error; |
463 | } | 464 | } |
464 | 465 | ||
@@ -468,10 +469,8 @@ static void tsdev_disconnect(struct input_handle *handle) | |||
468 | struct tsdev_client *client; | 469 | struct tsdev_client *client; |
469 | 470 | ||
470 | input_unregister_handle(handle); | 471 | input_unregister_handle(handle); |
472 | device_del(&tsdev->dev); | ||
471 | 473 | ||
472 | sysfs_remove_link(&input_class.subsys.kobj, tsdev->name); | ||
473 | class_device_destroy(&input_class, | ||
474 | MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); | ||
475 | tsdev->exist = 0; | 474 | tsdev->exist = 0; |
476 | 475 | ||
477 | if (tsdev->open) { | 476 | if (tsdev->open) { |
@@ -479,8 +478,9 @@ static void tsdev_disconnect(struct input_handle *handle) | |||
479 | list_for_each_entry(client, &tsdev->client_list, node) | 478 | list_for_each_entry(client, &tsdev->client_list, node) |
480 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 479 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
481 | wake_up_interruptible(&tsdev->wait); | 480 | wake_up_interruptible(&tsdev->wait); |
482 | } else | 481 | } |
483 | tsdev_free(tsdev); | 482 | |
483 | put_device(&tsdev->dev); | ||
484 | } | 484 | } |
485 | 485 | ||
486 | static const struct input_device_id tsdev_ids[] = { | 486 | static const struct input_device_id tsdev_ids[] = { |
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 78872c3f3760..b96ac8e119dc 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c | |||
@@ -84,7 +84,7 @@ static unsigned long __initdata doc_locations[] = { | |||
84 | #elif defined(CONFIG_MOMENCO_OCELOT) | 84 | #elif defined(CONFIG_MOMENCO_OCELOT) |
85 | 0x2f000000, | 85 | 0x2f000000, |
86 | 0xff000000, | 86 | 0xff000000, |
87 | #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) | 87 | #elif defined(CONFIG_MOMENCO_OCELOT_G) |
88 | 0xff000000, | 88 | 0xff000000, |
89 | ##else | 89 | ##else |
90 | #warning Unknown architecture for DiskOnChip. No default probe locations defined | 90 | #warning Unknown architecture for DiskOnChip. No default probe locations defined |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index b665e4ac2208..f88ebc5b685e 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -258,12 +258,6 @@ config MTD_TSUNAMI | |||
258 | help | 258 | help |
259 | Support for the flash chip on Tsunami TIG bus. | 259 | Support for the flash chip on Tsunami TIG bus. |
260 | 260 | ||
261 | config MTD_LASAT | ||
262 | tristate "LASAT flash device" | ||
263 | depends on LASAT && MTD_CFI | ||
264 | help | ||
265 | Support for the flash chips on the Lasat 100 and 200 boards. | ||
266 | |||
267 | config MTD_NETtel | 261 | config MTD_NETtel |
268 | tristate "CFI flash device on SnapGear/SecureEdge" | 262 | tristate "CFI flash device on SnapGear/SecureEdge" |
269 | depends on X86 && MTD_PARTITIONS && MTD_JEDECPROBE | 263 | depends on X86 && MTD_PARTITIONS && MTD_JEDECPROBE |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 3acbb5d01ca4..970b189271a2 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
@@ -47,7 +47,6 @@ obj-$(CONFIG_MTD_OCELOT) += ocelot.o | |||
47 | obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o | 47 | obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o |
48 | obj-$(CONFIG_MTD_PCI) += pci.o | 48 | obj-$(CONFIG_MTD_PCI) += pci.o |
49 | obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o | 49 | obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o |
50 | obj-$(CONFIG_MTD_LASAT) += lasat.o | ||
51 | obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o | 50 | obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o |
52 | obj-$(CONFIG_MTD_EDB7312) += edb7312.o | 51 | obj-$(CONFIG_MTD_EDB7312) += edb7312.o |
53 | obj-$(CONFIG_MTD_IMPA7) += impa7.o | 52 | obj-$(CONFIG_MTD_IMPA7) += impa7.o |
diff --git a/drivers/mtd/maps/lasat.c b/drivers/mtd/maps/lasat.c deleted file mode 100644 index e34376321050..000000000000 --- a/drivers/mtd/maps/lasat.c +++ /dev/null | |||
@@ -1,103 +0,0 @@ | |||
1 | /* | ||
2 | * Flash device on Lasat 100 and 200 boards | ||
3 | * | ||
4 | * (C) 2002 Brian Murphy <brian@murphy.dk> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * $Id: lasat.c,v 1.9 2004/11/04 13:24:15 gleixner Exp $ | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <linux/mtd/mtd.h> | ||
20 | #include <linux/mtd/map.h> | ||
21 | #include <linux/mtd/partitions.h> | ||
22 | #include <asm/lasat/lasat.h> | ||
23 | |||
24 | static struct mtd_info *lasat_mtd; | ||
25 | |||
26 | static struct mtd_partition partition_info[LASAT_MTD_LAST]; | ||
27 | static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"}; | ||
28 | |||
29 | static void lasat_set_vpp(struct map_info *map, int vpp) | ||
30 | { | ||
31 | if (vpp) | ||
32 | *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit; | ||
33 | else | ||
34 | *lasat_misc->flash_wp_reg &= ~(1 << lasat_misc->flash_wp_bit); | ||
35 | } | ||
36 | |||
37 | static struct map_info lasat_map = { | ||
38 | .name = "LASAT flash", | ||
39 | .bankwidth = 4, | ||
40 | .set_vpp = lasat_set_vpp | ||
41 | }; | ||
42 | |||
43 | static int __init init_lasat(void) | ||
44 | { | ||
45 | int i; | ||
46 | /* since we use AMD chips and set_vpp is not implimented | ||
47 | * for these (yet) we still have to permanently enable flash write */ | ||
48 | printk(KERN_NOTICE "Unprotecting flash\n"); | ||
49 | ENABLE_VPP((&lasat_map)); | ||
50 | |||
51 | lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER); | ||
52 | lasat_map.virt = ioremap_nocache( | ||
53 | lasat_map.phys, lasat_board_info.li_flash_size); | ||
54 | lasat_map.size = lasat_board_info.li_flash_size; | ||
55 | |||
56 | simple_map_init(&lasat_map); | ||
57 | |||
58 | for (i=0; i < LASAT_MTD_LAST; i++) | ||
59 | partition_info[i].name = lasat_mtd_partnames[i]; | ||
60 | |||
61 | lasat_mtd = do_map_probe("cfi_probe", &lasat_map); | ||
62 | |||
63 | if (!lasat_mtd) | ||
64 | lasat_mtd = do_map_probe("jedec_probe", &lasat_map); | ||
65 | |||
66 | if (lasat_mtd) { | ||
67 | u32 size, offset = 0; | ||
68 | |||
69 | lasat_mtd->owner = THIS_MODULE; | ||
70 | |||
71 | for (i=0; i < LASAT_MTD_LAST; i++) { | ||
72 | size = lasat_flash_partition_size(i); | ||
73 | partition_info[i].size = size; | ||
74 | partition_info[i].offset = offset; | ||
75 | offset += size; | ||
76 | } | ||
77 | |||
78 | add_mtd_partitions( lasat_mtd, partition_info, LASAT_MTD_LAST ); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | iounmap(lasat_map.virt); | ||
83 | return -ENXIO; | ||
84 | } | ||
85 | |||
86 | static void __exit cleanup_lasat(void) | ||
87 | { | ||
88 | if (lasat_mtd) { | ||
89 | del_mtd_partitions(lasat_mtd); | ||
90 | map_destroy(lasat_mtd); | ||
91 | } | ||
92 | if (lasat_map.virt) { | ||
93 | iounmap(lasat_map.virt); | ||
94 | lasat_map.virt = 0; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | module_init(init_lasat); | ||
99 | module_exit(cleanup_lasat); | ||
100 | |||
101 | MODULE_LICENSE("GPL"); | ||
102 | MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>"); | ||
103 | MODULE_DESCRIPTION("Lasat Safepipe/Masquerade MTD map driver"); | ||
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 595208f965a5..17c868034aad 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -59,7 +59,7 @@ static unsigned long __initdata doc_locations[] = { | |||
59 | #elif defined(CONFIG_MOMENCO_OCELOT) | 59 | #elif defined(CONFIG_MOMENCO_OCELOT) |
60 | 0x2f000000, | 60 | 0x2f000000, |
61 | 0xff000000, | 61 | 0xff000000, |
62 | #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) | 62 | #elif defined(CONFIG_MOMENCO_OCELOT_G) |
63 | 0xff000000, | 63 | 0xff000000, |
64 | #else | 64 | #else |
65 | #warning Unknown architecture for DiskOnChip. No default probe locations defined | 65 | #warning Unknown architecture for DiskOnChip. No default probe locations defined |
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ec846842c480..b941c74a06c4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2249,7 +2249,7 @@ config UGETH_TX_ON_DEMAND | |||
2249 | 2249 | ||
2250 | config MV643XX_ETH | 2250 | config MV643XX_ETH |
2251 | tristate "MV-643XX Ethernet support" | 2251 | tristate "MV-643XX Ethernet support" |
2252 | depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MV64X60 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32) | 2252 | depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) |
2253 | select MII | 2253 | select MII |
2254 | help | 2254 | help |
2255 | This driver supports the gigabit Ethernet on the Marvell MV643XX | 2255 | This driver supports the gigabit Ethernet on the Marvell MV643XX |
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 463d600ed83d..75655add3f34 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c | |||
@@ -23,9 +23,9 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #ifdef TC35815_NAPI | 25 | #ifdef TC35815_NAPI |
26 | #define DRV_VERSION "1.35-NAPI" | 26 | #define DRV_VERSION "1.36-NAPI" |
27 | #else | 27 | #else |
28 | #define DRV_VERSION "1.35" | 28 | #define DRV_VERSION "1.36" |
29 | #endif | 29 | #endif |
30 | static const char *version = "tc35815.c:v" DRV_VERSION "\n"; | 30 | static const char *version = "tc35815.c:v" DRV_VERSION "\n"; |
31 | #define MODNAME "tc35815" | 31 | #define MODNAME "tc35815" |
@@ -49,6 +49,7 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; | |||
49 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
50 | #include <linux/mii.h> | 50 | #include <linux/mii.h> |
51 | #include <linux/ethtool.h> | 51 | #include <linux/ethtool.h> |
52 | #include <linux/platform_device.h> | ||
52 | #include <asm/io.h> | 53 | #include <asm/io.h> |
53 | #include <asm/byteorder.h> | 54 | #include <asm/byteorder.h> |
54 | 55 | ||
@@ -597,13 +598,46 @@ static int tc_mdio_read(struct net_device *dev, int phy_id, int location); | |||
597 | static void tc_mdio_write(struct net_device *dev, int phy_id, int location, | 598 | static void tc_mdio_write(struct net_device *dev, int phy_id, int location, |
598 | int val); | 599 | int val); |
599 | 600 | ||
600 | static void __devinit tc35815_init_dev_addr (struct net_device *dev) | 601 | #ifdef CONFIG_CPU_TX49XX |
602 | /* | ||
603 | * Find a platform_device providing a MAC address. The platform code | ||
604 | * should provide a "tc35815-mac" device with a MAC address in its | ||
605 | * platform_data. | ||
606 | */ | ||
607 | static int __devinit tc35815_mac_match(struct device *dev, void *data) | ||
608 | { | ||
609 | struct platform_device *plat_dev = to_platform_device(dev); | ||
610 | struct pci_dev *pci_dev = data; | ||
611 | unsigned int id = (pci_dev->bus->number << 8) | pci_dev->devfn; | ||
612 | return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id; | ||
613 | } | ||
614 | |||
615 | static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev) | ||
616 | { | ||
617 | struct tc35815_local *lp = dev->priv; | ||
618 | struct device *pd = bus_find_device(&platform_bus_type, NULL, | ||
619 | lp->pci_dev, tc35815_mac_match); | ||
620 | if (pd) { | ||
621 | if (pd->platform_data) | ||
622 | memcpy(dev->dev_addr, pd->platform_data, ETH_ALEN); | ||
623 | put_device(pd); | ||
624 | return is_valid_ether_addr(dev->dev_addr) ? 0 : -ENODEV; | ||
625 | } | ||
626 | return -ENODEV; | ||
627 | } | ||
628 | #else | ||
629 | static int __devinit tc35815_read_plat_dev_addr(struct device *dev) | ||
630 | { | ||
631 | return -ENODEV; | ||
632 | } | ||
633 | #endif | ||
634 | |||
635 | static int __devinit tc35815_init_dev_addr (struct net_device *dev) | ||
601 | { | 636 | { |
602 | struct tc35815_regs __iomem *tr = | 637 | struct tc35815_regs __iomem *tr = |
603 | (struct tc35815_regs __iomem *)dev->base_addr; | 638 | (struct tc35815_regs __iomem *)dev->base_addr; |
604 | int i; | 639 | int i; |
605 | 640 | ||
606 | /* dev_addr will be overwritten on NETDEV_REGISTER event */ | ||
607 | while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) | 641 | while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) |
608 | ; | 642 | ; |
609 | for (i = 0; i < 6; i += 2) { | 643 | for (i = 0; i < 6; i += 2) { |
@@ -615,6 +649,9 @@ static void __devinit tc35815_init_dev_addr (struct net_device *dev) | |||
615 | dev->dev_addr[i] = data & 0xff; | 649 | dev->dev_addr[i] = data & 0xff; |
616 | dev->dev_addr[i+1] = data >> 8; | 650 | dev->dev_addr[i+1] = data >> 8; |
617 | } | 651 | } |
652 | if (!is_valid_ether_addr(dev->dev_addr)) | ||
653 | return tc35815_read_plat_dev_addr(dev); | ||
654 | return 0; | ||
618 | } | 655 | } |
619 | 656 | ||
620 | static int __devinit tc35815_init_one (struct pci_dev *pdev, | 657 | static int __devinit tc35815_init_one (struct pci_dev *pdev, |
@@ -724,7 +761,10 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, | |||
724 | tc35815_chip_reset(dev); | 761 | tc35815_chip_reset(dev); |
725 | 762 | ||
726 | /* Retrieve the ethernet address. */ | 763 | /* Retrieve the ethernet address. */ |
727 | tc35815_init_dev_addr(dev); | 764 | if (tc35815_init_dev_addr(dev)) { |
765 | dev_warn(&pdev->dev, "not valid ether addr\n"); | ||
766 | random_ether_addr(dev->dev_addr); | ||
767 | } | ||
728 | 768 | ||
729 | rc = register_netdev (dev); | 769 | rc = register_netdev (dev); |
730 | if (rc) | 770 | if (rc) |
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig new file mode 100644 index 000000000000..ab9c3e5a7c1d --- /dev/null +++ b/drivers/power/Kconfig | |||
@@ -0,0 +1,51 @@ | |||
1 | menuconfig POWER_SUPPLY | ||
2 | tristate "Power supply class support" | ||
3 | help | ||
4 | Say Y here to enable power supply class support. This allows | ||
5 | power supply (batteries, AC, USB) monitoring by userspace | ||
6 | via sysfs and uevent (if available) and/or APM kernel interface | ||
7 | (if selected below). | ||
8 | |||
9 | if POWER_SUPPLY | ||
10 | |||
11 | config POWER_SUPPLY_DEBUG | ||
12 | bool "Power supply debug" | ||
13 | help | ||
14 | Say Y here to enable debugging messages for power supply class | ||
15 | and drivers. | ||
16 | |||
17 | config PDA_POWER | ||
18 | tristate "Generic PDA/phone power driver" | ||
19 | help | ||
20 | Say Y here to enable generic power driver for PDAs and phones with | ||
21 | one or two external power supplies (AC/USB) connected to main and | ||
22 | backup batteries, and optional builtin charger. | ||
23 | |||
24 | config APM_POWER | ||
25 | tristate "APM emulation for class batteries" | ||
26 | depends on APM_EMULATION | ||
27 | help | ||
28 | Say Y here to enable support APM status emulation using | ||
29 | battery class devices. | ||
30 | |||
31 | config BATTERY_DS2760 | ||
32 | tristate "DS2760 battery driver (HP iPAQ & others)" | ||
33 | select W1 | ||
34 | select W1_SLAVE_DS2760 | ||
35 | help | ||
36 | Say Y here to enable support for batteries with ds2760 chip. | ||
37 | |||
38 | config BATTERY_PMU | ||
39 | tristate "Apple PMU battery" | ||
40 | depends on ADB_PMU | ||
41 | help | ||
42 | Say Y here to expose battery information on Apple machines | ||
43 | through the generic battery class. | ||
44 | |||
45 | config BATTERY_OLPC | ||
46 | tristate "One Laptop Per Child battery" | ||
47 | depends on X86_32 && OLPC | ||
48 | help | ||
49 | Say Y to enable support for the battery on the OLPC laptop. | ||
50 | |||
51 | endif # POWER_SUPPLY | ||
diff --git a/drivers/power/Makefile b/drivers/power/Makefile new file mode 100644 index 000000000000..6413ded5fe5f --- /dev/null +++ b/drivers/power/Makefile | |||
@@ -0,0 +1,22 @@ | |||
1 | power_supply-objs := power_supply_core.o | ||
2 | |||
3 | ifeq ($(CONFIG_SYSFS),y) | ||
4 | power_supply-objs += power_supply_sysfs.o | ||
5 | endif | ||
6 | |||
7 | ifeq ($(CONFIG_LEDS_TRIGGERS),y) | ||
8 | power_supply-objs += power_supply_leds.o | ||
9 | endif | ||
10 | |||
11 | ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y) | ||
12 | EXTRA_CFLAGS += -DDEBUG | ||
13 | endif | ||
14 | |||
15 | obj-$(CONFIG_POWER_SUPPLY) += power_supply.o | ||
16 | |||
17 | obj-$(CONFIG_PDA_POWER) += pda_power.o | ||
18 | obj-$(CONFIG_APM_POWER) += apm_power.o | ||
19 | |||
20 | obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o | ||
21 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o | ||
22 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | ||
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c new file mode 100644 index 000000000000..042bd950d036 --- /dev/null +++ b/drivers/power/apm_power.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> | ||
3 | * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru> | ||
4 | * | ||
5 | * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru> | ||
6 | * | ||
7 | * Use consistent with the GNU GPL is permitted, | ||
8 | * provided that this copyright notice is | ||
9 | * preserved in its entirety in all copies and derived works. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/power_supply.h> | ||
14 | #include <linux/apm-emulation.h> | ||
15 | |||
16 | #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ | ||
17 | POWER_SUPPLY_PROP_##prop, val) | ||
18 | |||
19 | #define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \ | ||
20 | prop, val) | ||
21 | |||
22 | #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val) | ||
23 | |||
24 | static struct power_supply *main_battery; | ||
25 | |||
26 | static void find_main_battery(void) | ||
27 | { | ||
28 | struct device *dev; | ||
29 | struct power_supply *bat, *batm; | ||
30 | union power_supply_propval full; | ||
31 | int max_charge = 0; | ||
32 | |||
33 | main_battery = NULL; | ||
34 | batm = NULL; | ||
35 | list_for_each_entry(dev, &power_supply_class->devices, node) { | ||
36 | bat = dev_get_drvdata(dev); | ||
37 | /* If none of battery devices cantains 'use_for_apm' flag, | ||
38 | choice one with maximum design charge */ | ||
39 | if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) { | ||
40 | if (full.intval > max_charge) { | ||
41 | batm = bat; | ||
42 | max_charge = full.intval; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | if (bat->use_for_apm) | ||
47 | main_battery = bat; | ||
48 | } | ||
49 | if (!main_battery) | ||
50 | main_battery = batm; | ||
51 | |||
52 | return; | ||
53 | } | ||
54 | |||
55 | static int calculate_time(int status) | ||
56 | { | ||
57 | union power_supply_propval charge_full, charge_empty; | ||
58 | union power_supply_propval charge, I; | ||
59 | |||
60 | if (MPSY_PROP(CHARGE_FULL, &charge_full)) { | ||
61 | /* if battery can't report this property, use design value */ | ||
62 | if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full)) | ||
63 | return -1; | ||
64 | } | ||
65 | |||
66 | if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) { | ||
67 | /* if battery can't report this property, use design value */ | ||
68 | if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty)) | ||
69 | charge_empty.intval = 0; | ||
70 | } | ||
71 | |||
72 | if (MPSY_PROP(CHARGE_AVG, &charge)) { | ||
73 | /* if battery can't report average value, use momentary */ | ||
74 | if (MPSY_PROP(CHARGE_NOW, &charge)) | ||
75 | return -1; | ||
76 | } | ||
77 | |||
78 | if (MPSY_PROP(CURRENT_AVG, &I)) { | ||
79 | /* if battery can't report average value, use momentary */ | ||
80 | if (MPSY_PROP(CURRENT_NOW, &I)) | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | if (status == POWER_SUPPLY_STATUS_CHARGING) | ||
85 | return ((charge.intval - charge_full.intval) * 60L) / | ||
86 | I.intval; | ||
87 | else | ||
88 | return -((charge.intval - charge_empty.intval) * 60L) / | ||
89 | I.intval; | ||
90 | } | ||
91 | |||
92 | static int calculate_capacity(int using_charge) | ||
93 | { | ||
94 | enum power_supply_property full_prop, empty_prop; | ||
95 | enum power_supply_property full_design_prop, empty_design_prop; | ||
96 | enum power_supply_property now_prop, avg_prop; | ||
97 | union power_supply_propval empty, full, cur; | ||
98 | int ret; | ||
99 | |||
100 | if (using_charge) { | ||
101 | full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; | ||
102 | empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; | ||
103 | full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; | ||
104 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN; | ||
105 | now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; | ||
106 | avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; | ||
107 | } else { | ||
108 | full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; | ||
109 | empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; | ||
110 | full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; | ||
111 | empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; | ||
112 | now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; | ||
113 | avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; | ||
114 | } | ||
115 | |||
116 | if (_MPSY_PROP(full_prop, &full)) { | ||
117 | /* if battery can't report this property, use design value */ | ||
118 | if (_MPSY_PROP(full_design_prop, &full)) | ||
119 | return -1; | ||
120 | } | ||
121 | |||
122 | if (_MPSY_PROP(avg_prop, &cur)) { | ||
123 | /* if battery can't report average value, use momentary */ | ||
124 | if (_MPSY_PROP(now_prop, &cur)) | ||
125 | return -1; | ||
126 | } | ||
127 | |||
128 | if (_MPSY_PROP(empty_prop, &empty)) { | ||
129 | /* if battery can't report this property, use design value */ | ||
130 | if (_MPSY_PROP(empty_design_prop, &empty)) | ||
131 | empty.intval = 0; | ||
132 | } | ||
133 | |||
134 | if (full.intval - empty.intval) | ||
135 | ret = ((cur.intval - empty.intval) * 100L) / | ||
136 | (full.intval - empty.intval); | ||
137 | else | ||
138 | return -1; | ||
139 | |||
140 | if (ret > 100) | ||
141 | return 100; | ||
142 | else if (ret < 0) | ||
143 | return 0; | ||
144 | |||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | static void apm_battery_apm_get_power_status(struct apm_power_info *info) | ||
149 | { | ||
150 | union power_supply_propval status; | ||
151 | union power_supply_propval capacity, time_to_full, time_to_empty; | ||
152 | |||
153 | down(&power_supply_class->sem); | ||
154 | find_main_battery(); | ||
155 | if (!main_battery) { | ||
156 | up(&power_supply_class->sem); | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | /* status */ | ||
161 | |||
162 | if (MPSY_PROP(STATUS, &status)) | ||
163 | status.intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
164 | |||
165 | /* ac line status */ | ||
166 | |||
167 | if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) || | ||
168 | (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) || | ||
169 | (status.intval == POWER_SUPPLY_STATUS_FULL)) | ||
170 | info->ac_line_status = APM_AC_ONLINE; | ||
171 | else | ||
172 | info->ac_line_status = APM_AC_OFFLINE; | ||
173 | |||
174 | /* battery life (i.e. capacity, in percents) */ | ||
175 | |||
176 | if (MPSY_PROP(CAPACITY, &capacity) == 0) { | ||
177 | info->battery_life = capacity.intval; | ||
178 | } else { | ||
179 | /* try calculate using energy */ | ||
180 | info->battery_life = calculate_capacity(0); | ||
181 | /* if failed try calculate using charge instead */ | ||
182 | if (info->battery_life == -1) | ||
183 | info->battery_life = calculate_capacity(1); | ||
184 | } | ||
185 | |||
186 | /* charging status */ | ||
187 | |||
188 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { | ||
189 | info->battery_status = APM_BATTERY_STATUS_CHARGING; | ||
190 | } else { | ||
191 | if (info->battery_life > 50) | ||
192 | info->battery_status = APM_BATTERY_STATUS_HIGH; | ||
193 | else if (info->battery_life > 5) | ||
194 | info->battery_status = APM_BATTERY_STATUS_LOW; | ||
195 | else | ||
196 | info->battery_status = APM_BATTERY_STATUS_CRITICAL; | ||
197 | } | ||
198 | info->battery_flag = info->battery_status; | ||
199 | |||
200 | /* time */ | ||
201 | |||
202 | info->units = APM_UNITS_MINS; | ||
203 | |||
204 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { | ||
205 | if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) { | ||
206 | if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) | ||
207 | info->time = calculate_time(status.intval); | ||
208 | else | ||
209 | info->time = time_to_full.intval / 60; | ||
210 | } | ||
211 | } else { | ||
212 | if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) { | ||
213 | if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) | ||
214 | info->time = calculate_time(status.intval); | ||
215 | else | ||
216 | info->time = time_to_empty.intval / 60; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | up(&power_supply_class->sem); | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | static int __init apm_battery_init(void) | ||
225 | { | ||
226 | printk(KERN_INFO "APM Battery Driver\n"); | ||
227 | |||
228 | apm_get_power_status = apm_battery_apm_get_power_status; | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static void __exit apm_battery_exit(void) | ||
233 | { | ||
234 | apm_get_power_status = NULL; | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | module_init(apm_battery_init); | ||
239 | module_exit(apm_battery_exit); | ||
240 | |||
241 | MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>"); | ||
242 | MODULE_DESCRIPTION("APM emulation driver for battery monitoring class"); | ||
243 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c new file mode 100644 index 000000000000..00e1ea6f1de2 --- /dev/null +++ b/drivers/power/ds2760_battery.c | |||
@@ -0,0 +1,470 @@ | |||
1 | /* | ||
2 | * Driver for batteries with DS2760 chips inside. | ||
3 | * | ||
4 | * Copyright © 2007 Anton Vorontsov | ||
5 | * 2004-2007 Matt Reimer | ||
6 | * 2004 Szabolcs Gyurko | ||
7 | * | ||
8 | * Use consistent with the GNU GPL is permitted, | ||
9 | * provided that this copyright notice is | ||
10 | * preserved in its entirety in all copies and derived works. | ||
11 | * | ||
12 | * Author: Anton Vorontsov <cbou@mail.ru> | ||
13 | * February 2007 | ||
14 | * | ||
15 | * Matt Reimer <mreimer@vpop.net> | ||
16 | * April 2004, 2005, 2007 | ||
17 | * | ||
18 | * Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> | ||
19 | * September 2004 | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/param.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | #include <linux/pm.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/power_supply.h> | ||
29 | |||
30 | #include "../w1/w1.h" | ||
31 | #include "../w1/slaves/w1_ds2760.h" | ||
32 | |||
33 | struct ds2760_device_info { | ||
34 | struct device *dev; | ||
35 | |||
36 | /* DS2760 data, valid after calling ds2760_battery_read_status() */ | ||
37 | unsigned long update_time; /* jiffies when data read */ | ||
38 | char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */ | ||
39 | int voltage_raw; /* units of 4.88 mV */ | ||
40 | int voltage_uV; /* units of µV */ | ||
41 | int current_raw; /* units of 0.625 mA */ | ||
42 | int current_uA; /* units of µA */ | ||
43 | int accum_current_raw; /* units of 0.25 mAh */ | ||
44 | int accum_current_uAh; /* units of µAh */ | ||
45 | int temp_raw; /* units of 0.125 °C */ | ||
46 | int temp_C; /* units of 0.1 °C */ | ||
47 | int rated_capacity; /* units of µAh */ | ||
48 | int rem_capacity; /* percentage */ | ||
49 | int full_active_uAh; /* units of µAh */ | ||
50 | int empty_uAh; /* units of µAh */ | ||
51 | int life_sec; /* units of seconds */ | ||
52 | int charge_status; /* POWER_SUPPLY_STATUS_* */ | ||
53 | |||
54 | int full_counter; | ||
55 | struct power_supply bat; | ||
56 | struct device *w1_dev; | ||
57 | struct workqueue_struct *monitor_wqueue; | ||
58 | struct delayed_work monitor_work; | ||
59 | }; | ||
60 | |||
61 | static unsigned int cache_time = 1000; | ||
62 | module_param(cache_time, uint, 0644); | ||
63 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); | ||
64 | |||
65 | /* Some batteries have their rated capacity stored a N * 10 mAh, while | ||
66 | * others use an index into this table. */ | ||
67 | static int rated_capacities[] = { | ||
68 | 0, | ||
69 | 920, /* Samsung */ | ||
70 | 920, /* BYD */ | ||
71 | 920, /* Lishen */ | ||
72 | 920, /* NEC */ | ||
73 | 1440, /* Samsung */ | ||
74 | 1440, /* BYD */ | ||
75 | 1440, /* Lishen */ | ||
76 | 1440, /* NEC */ | ||
77 | 2880, /* Samsung */ | ||
78 | 2880, /* BYD */ | ||
79 | 2880, /* Lishen */ | ||
80 | 2880 /* NEC */ | ||
81 | }; | ||
82 | |||
83 | /* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C | ||
84 | * temp is in Celsius */ | ||
85 | static int battery_interpolate(int array[], int temp) | ||
86 | { | ||
87 | int index, dt; | ||
88 | |||
89 | if (temp <= 0) | ||
90 | return array[0]; | ||
91 | if (temp >= 40) | ||
92 | return array[4]; | ||
93 | |||
94 | index = temp / 10; | ||
95 | dt = temp % 10; | ||
96 | |||
97 | return array[index] + (((array[index + 1] - array[index]) * dt) / 10); | ||
98 | } | ||
99 | |||
100 | static int ds2760_battery_read_status(struct ds2760_device_info *di) | ||
101 | { | ||
102 | int ret, i, start, count, scale[5]; | ||
103 | |||
104 | if (di->update_time && time_before(jiffies, di->update_time + | ||
105 | msecs_to_jiffies(cache_time))) | ||
106 | return 0; | ||
107 | |||
108 | /* The first time we read the entire contents of SRAM/EEPROM, | ||
109 | * but after that we just read the interesting bits that change. */ | ||
110 | if (di->update_time == 0) { | ||
111 | start = 0; | ||
112 | count = DS2760_DATA_SIZE; | ||
113 | } else { | ||
114 | start = DS2760_VOLTAGE_MSB; | ||
115 | count = DS2760_TEMP_LSB - start + 1; | ||
116 | } | ||
117 | |||
118 | ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count); | ||
119 | if (ret != count) { | ||
120 | dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n", | ||
121 | di->w1_dev); | ||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | di->update_time = jiffies; | ||
126 | |||
127 | /* DS2760 reports voltage in units of 4.88mV, but the battery class | ||
128 | * reports in units of uV, so convert by multiplying by 4880. */ | ||
129 | di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) | | ||
130 | (di->raw[DS2760_VOLTAGE_LSB] >> 5); | ||
131 | di->voltage_uV = di->voltage_raw * 4880; | ||
132 | |||
133 | /* DS2760 reports current in signed units of 0.625mA, but the battery | ||
134 | * class reports in units of µA, so convert by multiplying by 625. */ | ||
135 | di->current_raw = | ||
136 | (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) | | ||
137 | (di->raw[DS2760_CURRENT_LSB] >> 3); | ||
138 | di->current_uA = di->current_raw * 625; | ||
139 | |||
140 | /* DS2760 reports accumulated current in signed units of 0.25mAh. */ | ||
141 | di->accum_current_raw = | ||
142 | (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) | | ||
143 | di->raw[DS2760_CURRENT_ACCUM_LSB]; | ||
144 | di->accum_current_uAh = di->accum_current_raw * 250; | ||
145 | |||
146 | /* DS2760 reports temperature in signed units of 0.125°C, but the | ||
147 | * battery class reports in units of 1/10 °C, so we convert by | ||
148 | * multiplying by .125 * 10 = 1.25. */ | ||
149 | di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) | | ||
150 | (di->raw[DS2760_TEMP_LSB] >> 5); | ||
151 | di->temp_C = di->temp_raw + (di->temp_raw / 4); | ||
152 | |||
153 | /* At least some battery monitors (e.g. HP iPAQ) store the battery's | ||
154 | * maximum rated capacity. */ | ||
155 | if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities)) | ||
156 | di->rated_capacity = rated_capacities[ | ||
157 | (unsigned int)di->raw[DS2760_RATED_CAPACITY]]; | ||
158 | else | ||
159 | di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10; | ||
160 | |||
161 | di->rated_capacity *= 1000; /* convert to µAh */ | ||
162 | |||
163 | /* Calculate the full level at the present temperature. */ | ||
164 | di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 | | ||
165 | di->raw[DS2760_ACTIVE_FULL + 1]; | ||
166 | |||
167 | scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 | | ||
168 | di->raw[DS2760_ACTIVE_FULL + 1]; | ||
169 | for (i = 1; i < 5; i++) | ||
170 | scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i]; | ||
171 | |||
172 | di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10); | ||
173 | di->full_active_uAh *= 1000; /* convert to µAh */ | ||
174 | |||
175 | /* Calculate the empty level at the present temperature. */ | ||
176 | scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4]; | ||
177 | for (i = 3; i >= 0; i--) | ||
178 | scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i]; | ||
179 | |||
180 | di->empty_uAh = battery_interpolate(scale, di->temp_C / 10); | ||
181 | di->empty_uAh *= 1000; /* convert to µAh */ | ||
182 | |||
183 | /* From Maxim Application Note 131: remaining capacity = | ||
184 | * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */ | ||
185 | di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) / | ||
186 | (di->full_active_uAh - di->empty_uAh); | ||
187 | |||
188 | if (di->rem_capacity < 0) | ||
189 | di->rem_capacity = 0; | ||
190 | if (di->rem_capacity > 100) | ||
191 | di->rem_capacity = 100; | ||
192 | |||
193 | if (di->current_uA) | ||
194 | di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * | ||
195 | 3600L) / di->current_uA; | ||
196 | else | ||
197 | di->life_sec = 0; | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static void ds2760_battery_update_status(struct ds2760_device_info *di) | ||
203 | { | ||
204 | int old_charge_status = di->charge_status; | ||
205 | |||
206 | ds2760_battery_read_status(di); | ||
207 | |||
208 | if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN) | ||
209 | di->full_counter = 0; | ||
210 | |||
211 | if (power_supply_am_i_supplied(&di->bat)) { | ||
212 | if (di->current_uA > 10000) { | ||
213 | di->charge_status = POWER_SUPPLY_STATUS_CHARGING; | ||
214 | di->full_counter = 0; | ||
215 | } else if (di->current_uA < -5000) { | ||
216 | if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING) | ||
217 | dev_notice(di->dev, "not enough power to " | ||
218 | "charge\n"); | ||
219 | di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
220 | di->full_counter = 0; | ||
221 | } else if (di->current_uA < 10000 && | ||
222 | di->charge_status != POWER_SUPPLY_STATUS_FULL) { | ||
223 | |||
224 | /* Don't consider the battery to be full unless | ||
225 | * we've seen the current < 10 mA at least two | ||
226 | * consecutive times. */ | ||
227 | |||
228 | di->full_counter++; | ||
229 | |||
230 | if (di->full_counter < 2) { | ||
231 | di->charge_status = POWER_SUPPLY_STATUS_CHARGING; | ||
232 | } else { | ||
233 | unsigned char acr[2]; | ||
234 | int acr_val; | ||
235 | |||
236 | /* acr is in units of 0.25 mAh */ | ||
237 | acr_val = di->full_active_uAh * 4L / 1000; | ||
238 | |||
239 | acr[0] = acr_val >> 8; | ||
240 | acr[1] = acr_val & 0xff; | ||
241 | |||
242 | if (w1_ds2760_write(di->w1_dev, acr, | ||
243 | DS2760_CURRENT_ACCUM_MSB, 2) < 2) | ||
244 | dev_warn(di->dev, | ||
245 | "ACR reset failed\n"); | ||
246 | |||
247 | di->charge_status = POWER_SUPPLY_STATUS_FULL; | ||
248 | } | ||
249 | } | ||
250 | } else { | ||
251 | di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING; | ||
252 | di->full_counter = 0; | ||
253 | } | ||
254 | |||
255 | if (di->charge_status != old_charge_status) | ||
256 | power_supply_changed(&di->bat); | ||
257 | |||
258 | return; | ||
259 | } | ||
260 | |||
261 | static void ds2760_battery_work(struct work_struct *work) | ||
262 | { | ||
263 | struct ds2760_device_info *di = container_of(work, | ||
264 | struct ds2760_device_info, monitor_work.work); | ||
265 | const int interval = HZ * 60; | ||
266 | |||
267 | dev_dbg(di->dev, "%s\n", __FUNCTION__); | ||
268 | |||
269 | ds2760_battery_update_status(di); | ||
270 | queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval); | ||
271 | |||
272 | return; | ||
273 | } | ||
274 | |||
275 | #define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \ | ||
276 | bat); | ||
277 | |||
278 | static void ds2760_battery_external_power_changed(struct power_supply *psy) | ||
279 | { | ||
280 | struct ds2760_device_info *di = to_ds2760_device_info(psy); | ||
281 | |||
282 | dev_dbg(di->dev, "%s\n", __FUNCTION__); | ||
283 | |||
284 | cancel_delayed_work(&di->monitor_work); | ||
285 | queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10); | ||
286 | |||
287 | return; | ||
288 | } | ||
289 | |||
290 | static int ds2760_battery_get_property(struct power_supply *psy, | ||
291 | enum power_supply_property psp, | ||
292 | union power_supply_propval *val) | ||
293 | { | ||
294 | struct ds2760_device_info *di = to_ds2760_device_info(psy); | ||
295 | |||
296 | switch (psp) { | ||
297 | case POWER_SUPPLY_PROP_STATUS: | ||
298 | val->intval = di->charge_status; | ||
299 | return 0; | ||
300 | default: | ||
301 | break; | ||
302 | } | ||
303 | |||
304 | ds2760_battery_read_status(di); | ||
305 | |||
306 | switch (psp) { | ||
307 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
308 | val->intval = di->voltage_uV; | ||
309 | break; | ||
310 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
311 | val->intval = di->current_uA; | ||
312 | break; | ||
313 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
314 | val->intval = di->rated_capacity; | ||
315 | break; | ||
316 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
317 | val->intval = di->full_active_uAh; | ||
318 | break; | ||
319 | case POWER_SUPPLY_PROP_CHARGE_EMPTY: | ||
320 | val->intval = di->empty_uAh; | ||
321 | break; | ||
322 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
323 | val->intval = di->accum_current_uAh; | ||
324 | break; | ||
325 | case POWER_SUPPLY_PROP_TEMP: | ||
326 | val->intval = di->temp_C; | ||
327 | break; | ||
328 | default: | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static enum power_supply_property ds2760_battery_props[] = { | ||
336 | POWER_SUPPLY_PROP_STATUS, | ||
337 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
338 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
339 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
340 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
341 | POWER_SUPPLY_PROP_CHARGE_EMPTY, | ||
342 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
343 | POWER_SUPPLY_PROP_TEMP, | ||
344 | }; | ||
345 | |||
346 | static int ds2760_battery_probe(struct platform_device *pdev) | ||
347 | { | ||
348 | int retval = 0; | ||
349 | struct ds2760_device_info *di; | ||
350 | struct ds2760_platform_data *pdata; | ||
351 | |||
352 | di = kzalloc(sizeof(*di), GFP_KERNEL); | ||
353 | if (!di) { | ||
354 | retval = -ENOMEM; | ||
355 | goto di_alloc_failed; | ||
356 | } | ||
357 | |||
358 | platform_set_drvdata(pdev, di); | ||
359 | |||
360 | pdata = pdev->dev.platform_data; | ||
361 | di->dev = &pdev->dev; | ||
362 | di->w1_dev = pdev->dev.parent; | ||
363 | di->bat.name = pdev->dev.bus_id; | ||
364 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
365 | di->bat.properties = ds2760_battery_props; | ||
366 | di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props); | ||
367 | di->bat.get_property = ds2760_battery_get_property; | ||
368 | di->bat.external_power_changed = | ||
369 | ds2760_battery_external_power_changed; | ||
370 | |||
371 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
372 | |||
373 | retval = power_supply_register(&pdev->dev, &di->bat); | ||
374 | if (retval) { | ||
375 | dev_err(di->dev, "failed to register battery"); | ||
376 | goto batt_failed; | ||
377 | } | ||
378 | |||
379 | INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); | ||
380 | di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id); | ||
381 | if (!di->monitor_wqueue) { | ||
382 | retval = -ESRCH; | ||
383 | goto workqueue_failed; | ||
384 | } | ||
385 | queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); | ||
386 | |||
387 | goto success; | ||
388 | |||
389 | workqueue_failed: | ||
390 | power_supply_unregister(&di->bat); | ||
391 | batt_failed: | ||
392 | kfree(di); | ||
393 | di_alloc_failed: | ||
394 | success: | ||
395 | return retval; | ||
396 | } | ||
397 | |||
398 | static int ds2760_battery_remove(struct platform_device *pdev) | ||
399 | { | ||
400 | struct ds2760_device_info *di = platform_get_drvdata(pdev); | ||
401 | |||
402 | cancel_rearming_delayed_workqueue(di->monitor_wqueue, | ||
403 | &di->monitor_work); | ||
404 | destroy_workqueue(di->monitor_wqueue); | ||
405 | power_supply_unregister(&di->bat); | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | #ifdef CONFIG_PM | ||
411 | |||
412 | static int ds2760_battery_suspend(struct platform_device *pdev, | ||
413 | pm_message_t state) | ||
414 | { | ||
415 | struct ds2760_device_info *di = platform_get_drvdata(pdev); | ||
416 | |||
417 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int ds2760_battery_resume(struct platform_device *pdev) | ||
423 | { | ||
424 | struct ds2760_device_info *di = platform_get_drvdata(pdev); | ||
425 | |||
426 | di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
427 | power_supply_changed(&di->bat); | ||
428 | |||
429 | cancel_delayed_work(&di->monitor_work); | ||
430 | queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | #else | ||
436 | |||
437 | #define ds2760_battery_suspend NULL | ||
438 | #define ds2760_battery_resume NULL | ||
439 | |||
440 | #endif /* CONFIG_PM */ | ||
441 | |||
442 | static struct platform_driver ds2760_battery_driver = { | ||
443 | .driver = { | ||
444 | .name = "ds2760-battery", | ||
445 | }, | ||
446 | .probe = ds2760_battery_probe, | ||
447 | .remove = ds2760_battery_remove, | ||
448 | .suspend = ds2760_battery_suspend, | ||
449 | .resume = ds2760_battery_resume, | ||
450 | }; | ||
451 | |||
452 | static int __init ds2760_battery_init(void) | ||
453 | { | ||
454 | return platform_driver_register(&ds2760_battery_driver); | ||
455 | } | ||
456 | |||
457 | static void __exit ds2760_battery_exit(void) | ||
458 | { | ||
459 | platform_driver_unregister(&ds2760_battery_driver); | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | module_init(ds2760_battery_init); | ||
464 | module_exit(ds2760_battery_exit); | ||
465 | |||
466 | MODULE_LICENSE("GPL"); | ||
467 | MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " | ||
468 | "Matt Reimer <mreimer@vpop.net>, " | ||
469 | "Anton Vorontsov <cbou@mail.ru>"); | ||
470 | MODULE_DESCRIPTION("ds2760 battery driver"); | ||
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c new file mode 100644 index 000000000000..878684df7667 --- /dev/null +++ b/drivers/power/olpc_battery.c | |||
@@ -0,0 +1,352 @@ | |||
1 | /* | ||
2 | * Battery driver for One Laptop Per Child board. | ||
3 | * | ||
4 | * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> | ||
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 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/power_supply.h> | ||
15 | #include <linux/jiffies.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <asm/olpc.h> | ||
18 | |||
19 | |||
20 | #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */ | ||
21 | #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */ | ||
22 | #define EC_BAT_ACR 0x12 | ||
23 | #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */ | ||
24 | #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */ | ||
25 | #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */ | ||
26 | #define EC_BAT_SOC 0x16 /* uint8_t, percentage */ | ||
27 | #define EC_BAT_SERIAL 0x17 /* uint8_t[6] */ | ||
28 | #define EC_BAT_EEPROM 0x18 /* uint8_t adr as input, uint8_t output */ | ||
29 | #define EC_BAT_ERRCODE 0x1f /* uint8_t, bitmask */ | ||
30 | |||
31 | #define BAT_STAT_PRESENT 0x01 | ||
32 | #define BAT_STAT_FULL 0x02 | ||
33 | #define BAT_STAT_LOW 0x04 | ||
34 | #define BAT_STAT_DESTROY 0x08 | ||
35 | #define BAT_STAT_AC 0x10 | ||
36 | #define BAT_STAT_CHARGING 0x20 | ||
37 | #define BAT_STAT_DISCHARGING 0x40 | ||
38 | |||
39 | #define BAT_ERR_INFOFAIL 0x02 | ||
40 | #define BAT_ERR_OVERVOLTAGE 0x04 | ||
41 | #define BAT_ERR_OVERTEMP 0x05 | ||
42 | #define BAT_ERR_GAUGESTOP 0x06 | ||
43 | #define BAT_ERR_OUT_OF_CONTROL 0x07 | ||
44 | #define BAT_ERR_ID_FAIL 0x09 | ||
45 | #define BAT_ERR_ACR_FAIL 0x10 | ||
46 | |||
47 | #define BAT_ADDR_MFR_TYPE 0x5F | ||
48 | |||
49 | /********************************************************************* | ||
50 | * Power | ||
51 | *********************************************************************/ | ||
52 | |||
53 | static int olpc_ac_get_prop(struct power_supply *psy, | ||
54 | enum power_supply_property psp, | ||
55 | union power_supply_propval *val) | ||
56 | { | ||
57 | int ret = 0; | ||
58 | uint8_t status; | ||
59 | |||
60 | switch (psp) { | ||
61 | case POWER_SUPPLY_PROP_ONLINE: | ||
62 | ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1); | ||
63 | if (ret) | ||
64 | return ret; | ||
65 | |||
66 | val->intval = !!(status & BAT_STAT_AC); | ||
67 | break; | ||
68 | default: | ||
69 | ret = -EINVAL; | ||
70 | break; | ||
71 | } | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static enum power_supply_property olpc_ac_props[] = { | ||
76 | POWER_SUPPLY_PROP_ONLINE, | ||
77 | }; | ||
78 | |||
79 | static struct power_supply olpc_ac = { | ||
80 | .name = "olpc-ac", | ||
81 | .type = POWER_SUPPLY_TYPE_MAINS, | ||
82 | .properties = olpc_ac_props, | ||
83 | .num_properties = ARRAY_SIZE(olpc_ac_props), | ||
84 | .get_property = olpc_ac_get_prop, | ||
85 | }; | ||
86 | |||
87 | /********************************************************************* | ||
88 | * Battery properties | ||
89 | *********************************************************************/ | ||
90 | static int olpc_bat_get_property(struct power_supply *psy, | ||
91 | enum power_supply_property psp, | ||
92 | union power_supply_propval *val) | ||
93 | { | ||
94 | int ret = 0; | ||
95 | int16_t ec_word; | ||
96 | uint8_t ec_byte; | ||
97 | |||
98 | ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1); | ||
99 | if (ret) | ||
100 | return ret; | ||
101 | |||
102 | /* Theoretically there's a race here -- the battery could be | ||
103 | removed immediately after we check whether it's present, and | ||
104 | then we query for some other property of the now-absent battery. | ||
105 | It doesn't matter though -- the EC will return the last-known | ||
106 | information, and it's as if we just ran that _little_ bit faster | ||
107 | and managed to read it out before the battery went away. */ | ||
108 | if (!(ec_byte & BAT_STAT_PRESENT) && psp != POWER_SUPPLY_PROP_PRESENT) | ||
109 | return -ENODEV; | ||
110 | |||
111 | switch (psp) { | ||
112 | case POWER_SUPPLY_PROP_STATUS: | ||
113 | if (olpc_platform_info.ecver > 0x44) { | ||
114 | if (ec_byte & BAT_STAT_CHARGING) | ||
115 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
116 | else if (ec_byte & BAT_STAT_DISCHARGING) | ||
117 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
118 | else if (ec_byte & BAT_STAT_FULL) | ||
119 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
120 | else /* er,... */ | ||
121 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
122 | } else { | ||
123 | /* Older EC didn't report charge/discharge bits */ | ||
124 | if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */ | ||
125 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
126 | else if (ec_byte & BAT_STAT_FULL) | ||
127 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
128 | else /* Not _necessarily_ true but EC doesn't tell all yet */ | ||
129 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
130 | break; | ||
131 | } | ||
132 | case POWER_SUPPLY_PROP_PRESENT: | ||
133 | val->intval = !!(ec_byte & BAT_STAT_PRESENT); | ||
134 | break; | ||
135 | |||
136 | case POWER_SUPPLY_PROP_HEALTH: | ||
137 | if (ec_byte & BAT_STAT_DESTROY) | ||
138 | val->intval = POWER_SUPPLY_HEALTH_DEAD; | ||
139 | else { | ||
140 | ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1); | ||
141 | if (ret) | ||
142 | return ret; | ||
143 | |||
144 | switch (ec_byte) { | ||
145 | case 0: | ||
146 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | ||
147 | break; | ||
148 | |||
149 | case BAT_ERR_OVERTEMP: | ||
150 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; | ||
151 | break; | ||
152 | |||
153 | case BAT_ERR_OVERVOLTAGE: | ||
154 | val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | ||
155 | break; | ||
156 | |||
157 | case BAT_ERR_INFOFAIL: | ||
158 | case BAT_ERR_OUT_OF_CONTROL: | ||
159 | case BAT_ERR_ID_FAIL: | ||
160 | case BAT_ERR_ACR_FAIL: | ||
161 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | ||
162 | break; | ||
163 | |||
164 | default: | ||
165 | /* Eep. We don't know this failure code */ | ||
166 | return -EIO; | ||
167 | } | ||
168 | } | ||
169 | break; | ||
170 | |||
171 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
172 | ec_byte = BAT_ADDR_MFR_TYPE; | ||
173 | ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); | ||
174 | if (ret) | ||
175 | return ret; | ||
176 | |||
177 | switch (ec_byte >> 4) { | ||
178 | case 1: | ||
179 | val->strval = "Gold Peak"; | ||
180 | break; | ||
181 | case 2: | ||
182 | val->strval = "BYD"; | ||
183 | break; | ||
184 | default: | ||
185 | val->strval = "Unknown"; | ||
186 | break; | ||
187 | } | ||
188 | break; | ||
189 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
190 | ec_byte = BAT_ADDR_MFR_TYPE; | ||
191 | ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); | ||
192 | if (ret) | ||
193 | return ret; | ||
194 | |||
195 | switch (ec_byte & 0xf) { | ||
196 | case 1: | ||
197 | val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH; | ||
198 | break; | ||
199 | case 2: | ||
200 | val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe; | ||
201 | break; | ||
202 | default: | ||
203 | val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; | ||
204 | break; | ||
205 | } | ||
206 | break; | ||
207 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
208 | ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); | ||
209 | if (ret) | ||
210 | return ret; | ||
211 | |||
212 | ec_word = be16_to_cpu(ec_word); | ||
213 | val->intval = ec_word * 9760L / 32; | ||
214 | break; | ||
215 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
216 | ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); | ||
217 | if (ret) | ||
218 | return ret; | ||
219 | |||
220 | ec_word = be16_to_cpu(ec_word); | ||
221 | val->intval = ec_word * 15625L / 120; | ||
222 | break; | ||
223 | case POWER_SUPPLY_PROP_CAPACITY: | ||
224 | ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1); | ||
225 | if (ret) | ||
226 | return ret; | ||
227 | val->intval = ec_byte; | ||
228 | break; | ||
229 | case POWER_SUPPLY_PROP_CAPACITY_LEVEL: | ||
230 | if (ec_byte & BAT_STAT_FULL) | ||
231 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; | ||
232 | else if (ec_byte & BAT_STAT_LOW) | ||
233 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; | ||
234 | else | ||
235 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | ||
236 | break; | ||
237 | case POWER_SUPPLY_PROP_TEMP: | ||
238 | ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); | ||
239 | if (ret) | ||
240 | return ret; | ||
241 | ec_word = be16_to_cpu(ec_word); | ||
242 | val->intval = ec_word * 100 / 256; | ||
243 | break; | ||
244 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: | ||
245 | ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2); | ||
246 | if (ret) | ||
247 | return ret; | ||
248 | |||
249 | ec_word = be16_to_cpu(ec_word); | ||
250 | val->intval = ec_word * 100 / 256; | ||
251 | break; | ||
252 | default: | ||
253 | ret = -EINVAL; | ||
254 | break; | ||
255 | } | ||
256 | |||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | static enum power_supply_property olpc_bat_props[] = { | ||
261 | POWER_SUPPLY_PROP_STATUS, | ||
262 | POWER_SUPPLY_PROP_PRESENT, | ||
263 | POWER_SUPPLY_PROP_HEALTH, | ||
264 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
265 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | ||
266 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
267 | POWER_SUPPLY_PROP_CAPACITY, | ||
268 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
269 | POWER_SUPPLY_PROP_TEMP, | ||
270 | POWER_SUPPLY_PROP_TEMP_AMBIENT, | ||
271 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
272 | }; | ||
273 | |||
274 | /********************************************************************* | ||
275 | * Initialisation | ||
276 | *********************************************************************/ | ||
277 | |||
278 | static struct platform_device *bat_pdev; | ||
279 | |||
280 | static struct power_supply olpc_bat = { | ||
281 | .properties = olpc_bat_props, | ||
282 | .num_properties = ARRAY_SIZE(olpc_bat_props), | ||
283 | .get_property = olpc_bat_get_property, | ||
284 | .use_for_apm = 1, | ||
285 | }; | ||
286 | |||
287 | void olpc_battery_trigger_uevent(unsigned long cause) | ||
288 | { | ||
289 | if (cause & EC_SCI_SRC_ACPWR) | ||
290 | kobject_uevent(&olpc_ac.dev->kobj, KOBJ_CHANGE); | ||
291 | if (cause & (EC_SCI_SRC_BATERR|EC_SCI_SRC_BATSOC|EC_SCI_SRC_BATTERY)) | ||
292 | kobject_uevent(&olpc_bat.dev->kobj, KOBJ_CHANGE); | ||
293 | } | ||
294 | |||
295 | static int __init olpc_bat_init(void) | ||
296 | { | ||
297 | int ret = 0; | ||
298 | uint8_t status; | ||
299 | |||
300 | if (!olpc_platform_info.ecver) | ||
301 | return -ENXIO; | ||
302 | if (olpc_platform_info.ecver < 0x43) { | ||
303 | printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver); | ||
304 | return -ENXIO; | ||
305 | } | ||
306 | |||
307 | ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1); | ||
308 | if (ret) | ||
309 | return ret; | ||
310 | |||
311 | /* Ignore the status. It doesn't actually matter */ | ||
312 | |||
313 | bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0); | ||
314 | if (IS_ERR(bat_pdev)) | ||
315 | return PTR_ERR(bat_pdev); | ||
316 | |||
317 | ret = power_supply_register(&bat_pdev->dev, &olpc_ac); | ||
318 | if (ret) | ||
319 | goto ac_failed; | ||
320 | |||
321 | olpc_bat.name = bat_pdev->name; | ||
322 | |||
323 | ret = power_supply_register(&bat_pdev->dev, &olpc_bat); | ||
324 | if (ret) | ||
325 | goto battery_failed; | ||
326 | |||
327 | olpc_register_battery_callback(&olpc_battery_trigger_uevent); | ||
328 | goto success; | ||
329 | |||
330 | battery_failed: | ||
331 | power_supply_unregister(&olpc_ac); | ||
332 | ac_failed: | ||
333 | platform_device_unregister(bat_pdev); | ||
334 | success: | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | static void __exit olpc_bat_exit(void) | ||
339 | { | ||
340 | olpc_deregister_battery_callback(); | ||
341 | power_supply_unregister(&olpc_bat); | ||
342 | power_supply_unregister(&olpc_ac); | ||
343 | platform_device_unregister(bat_pdev); | ||
344 | return; | ||
345 | } | ||
346 | |||
347 | module_init(olpc_bat_init); | ||
348 | module_exit(olpc_bat_exit); | ||
349 | |||
350 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | ||
351 | MODULE_LICENSE("GPL"); | ||
352 | MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine"); | ||
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c new file mode 100644 index 000000000000..4e1eb040e148 --- /dev/null +++ b/drivers/power/pda_power.c | |||
@@ -0,0 +1,261 @@ | |||
1 | /* | ||
2 | * Common power driver for PDAs and phones with one or two external | ||
3 | * power supplies (AC/USB) connected to main and backup batteries, | ||
4 | * and optional builtin charger. | ||
5 | * | ||
6 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/power_supply.h> | ||
17 | #include <linux/pda_power.h> | ||
18 | #include <linux/timer.h> | ||
19 | #include <linux/jiffies.h> | ||
20 | |||
21 | static inline unsigned int get_irq_flags(struct resource *res) | ||
22 | { | ||
23 | unsigned int flags = IRQF_DISABLED | IRQF_SHARED; | ||
24 | |||
25 | flags |= res->flags & IRQF_TRIGGER_MASK; | ||
26 | |||
27 | return flags; | ||
28 | } | ||
29 | |||
30 | static struct device *dev; | ||
31 | static struct pda_power_pdata *pdata; | ||
32 | static struct resource *ac_irq, *usb_irq; | ||
33 | static struct timer_list charger_timer; | ||
34 | static struct timer_list supply_timer; | ||
35 | |||
36 | static int pda_power_get_property(struct power_supply *psy, | ||
37 | enum power_supply_property psp, | ||
38 | union power_supply_propval *val) | ||
39 | { | ||
40 | switch (psp) { | ||
41 | case POWER_SUPPLY_PROP_ONLINE: | ||
42 | if (psy->type == POWER_SUPPLY_TYPE_MAINS) | ||
43 | val->intval = pdata->is_ac_online ? | ||
44 | pdata->is_ac_online() : 0; | ||
45 | else | ||
46 | val->intval = pdata->is_usb_online ? | ||
47 | pdata->is_usb_online() : 0; | ||
48 | break; | ||
49 | default: | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static enum power_supply_property pda_power_props[] = { | ||
56 | POWER_SUPPLY_PROP_ONLINE, | ||
57 | }; | ||
58 | |||
59 | static char *pda_power_supplied_to[] = { | ||
60 | "main-battery", | ||
61 | "backup-battery", | ||
62 | }; | ||
63 | |||
64 | static struct power_supply pda_power_supplies[] = { | ||
65 | { | ||
66 | .name = "ac", | ||
67 | .type = POWER_SUPPLY_TYPE_MAINS, | ||
68 | .supplied_to = pda_power_supplied_to, | ||
69 | .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), | ||
70 | .properties = pda_power_props, | ||
71 | .num_properties = ARRAY_SIZE(pda_power_props), | ||
72 | .get_property = pda_power_get_property, | ||
73 | }, | ||
74 | { | ||
75 | .name = "usb", | ||
76 | .type = POWER_SUPPLY_TYPE_USB, | ||
77 | .supplied_to = pda_power_supplied_to, | ||
78 | .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), | ||
79 | .properties = pda_power_props, | ||
80 | .num_properties = ARRAY_SIZE(pda_power_props), | ||
81 | .get_property = pda_power_get_property, | ||
82 | }, | ||
83 | }; | ||
84 | |||
85 | static void update_charger(void) | ||
86 | { | ||
87 | if (!pdata->set_charge) | ||
88 | return; | ||
89 | |||
90 | if (pdata->is_ac_online && pdata->is_ac_online()) { | ||
91 | dev_dbg(dev, "charger on (AC)\n"); | ||
92 | pdata->set_charge(PDA_POWER_CHARGE_AC); | ||
93 | } else if (pdata->is_usb_online && pdata->is_usb_online()) { | ||
94 | dev_dbg(dev, "charger on (USB)\n"); | ||
95 | pdata->set_charge(PDA_POWER_CHARGE_USB); | ||
96 | } else { | ||
97 | dev_dbg(dev, "charger off\n"); | ||
98 | pdata->set_charge(0); | ||
99 | } | ||
100 | |||
101 | return; | ||
102 | } | ||
103 | |||
104 | static void supply_timer_func(unsigned long irq) | ||
105 | { | ||
106 | if (ac_irq && irq == ac_irq->start) | ||
107 | power_supply_changed(&pda_power_supplies[0]); | ||
108 | else if (usb_irq && irq == usb_irq->start) | ||
109 | power_supply_changed(&pda_power_supplies[1]); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | static void charger_timer_func(unsigned long irq) | ||
114 | { | ||
115 | update_charger(); | ||
116 | |||
117 | /* Okay, charger set. Now wait a bit before notifying supplicants, | ||
118 | * charge power should stabilize. */ | ||
119 | supply_timer.data = irq; | ||
120 | mod_timer(&supply_timer, | ||
121 | jiffies + msecs_to_jiffies(pdata->wait_for_charger)); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | static irqreturn_t power_changed_isr(int irq, void *unused) | ||
126 | { | ||
127 | /* Wait a bit before reading ac/usb line status and setting charger, | ||
128 | * because ac/usb status readings may lag from irq. */ | ||
129 | charger_timer.data = irq; | ||
130 | mod_timer(&charger_timer, | ||
131 | jiffies + msecs_to_jiffies(pdata->wait_for_status)); | ||
132 | return IRQ_HANDLED; | ||
133 | } | ||
134 | |||
135 | static int pda_power_probe(struct platform_device *pdev) | ||
136 | { | ||
137 | int ret = 0; | ||
138 | |||
139 | dev = &pdev->dev; | ||
140 | |||
141 | if (pdev->id != -1) { | ||
142 | dev_err(dev, "it's meaningless to register several " | ||
143 | "pda_powers; use id = -1\n"); | ||
144 | ret = -EINVAL; | ||
145 | goto wrongid; | ||
146 | } | ||
147 | |||
148 | pdata = pdev->dev.platform_data; | ||
149 | |||
150 | update_charger(); | ||
151 | |||
152 | if (!pdata->wait_for_status) | ||
153 | pdata->wait_for_status = 500; | ||
154 | |||
155 | if (!pdata->wait_for_charger) | ||
156 | pdata->wait_for_charger = 500; | ||
157 | |||
158 | setup_timer(&charger_timer, charger_timer_func, 0); | ||
159 | setup_timer(&supply_timer, supply_timer_func, 0); | ||
160 | |||
161 | ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); | ||
162 | usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); | ||
163 | if (!ac_irq && !usb_irq) { | ||
164 | dev_err(dev, "no ac/usb irq specified\n"); | ||
165 | ret = -ENODEV; | ||
166 | goto noirqs; | ||
167 | } | ||
168 | |||
169 | if (pdata->supplied_to) { | ||
170 | pda_power_supplies[0].supplied_to = pdata->supplied_to; | ||
171 | pda_power_supplies[1].supplied_to = pdata->supplied_to; | ||
172 | pda_power_supplies[0].num_supplicants = pdata->num_supplicants; | ||
173 | pda_power_supplies[1].num_supplicants = pdata->num_supplicants; | ||
174 | } | ||
175 | |||
176 | ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]); | ||
177 | if (ret) { | ||
178 | dev_err(dev, "failed to register %s power supply\n", | ||
179 | pda_power_supplies[0].name); | ||
180 | goto supply0_failed; | ||
181 | } | ||
182 | |||
183 | ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); | ||
184 | if (ret) { | ||
185 | dev_err(dev, "failed to register %s power supply\n", | ||
186 | pda_power_supplies[1].name); | ||
187 | goto supply1_failed; | ||
188 | } | ||
189 | |||
190 | if (ac_irq) { | ||
191 | ret = request_irq(ac_irq->start, power_changed_isr, | ||
192 | get_irq_flags(ac_irq), ac_irq->name, | ||
193 | &pda_power_supplies[0]); | ||
194 | if (ret) { | ||
195 | dev_err(dev, "request ac irq failed\n"); | ||
196 | goto ac_irq_failed; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | if (usb_irq) { | ||
201 | ret = request_irq(usb_irq->start, power_changed_isr, | ||
202 | get_irq_flags(usb_irq), usb_irq->name, | ||
203 | &pda_power_supplies[1]); | ||
204 | if (ret) { | ||
205 | dev_err(dev, "request usb irq failed\n"); | ||
206 | goto usb_irq_failed; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | goto success; | ||
211 | |||
212 | usb_irq_failed: | ||
213 | if (ac_irq) | ||
214 | free_irq(ac_irq->start, &pda_power_supplies[0]); | ||
215 | ac_irq_failed: | ||
216 | power_supply_unregister(&pda_power_supplies[1]); | ||
217 | supply1_failed: | ||
218 | power_supply_unregister(&pda_power_supplies[0]); | ||
219 | supply0_failed: | ||
220 | noirqs: | ||
221 | wrongid: | ||
222 | success: | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static int pda_power_remove(struct platform_device *pdev) | ||
227 | { | ||
228 | if (usb_irq) | ||
229 | free_irq(usb_irq->start, &pda_power_supplies[1]); | ||
230 | if (ac_irq) | ||
231 | free_irq(ac_irq->start, &pda_power_supplies[0]); | ||
232 | del_timer_sync(&charger_timer); | ||
233 | del_timer_sync(&supply_timer); | ||
234 | power_supply_unregister(&pda_power_supplies[1]); | ||
235 | power_supply_unregister(&pda_power_supplies[0]); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static struct platform_driver pda_power_pdrv = { | ||
240 | .driver = { | ||
241 | .name = "pda-power", | ||
242 | }, | ||
243 | .probe = pda_power_probe, | ||
244 | .remove = pda_power_remove, | ||
245 | }; | ||
246 | |||
247 | static int __init pda_power_init(void) | ||
248 | { | ||
249 | return platform_driver_register(&pda_power_pdrv); | ||
250 | } | ||
251 | |||
252 | static void __exit pda_power_exit(void) | ||
253 | { | ||
254 | platform_driver_unregister(&pda_power_pdrv); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | module_init(pda_power_init); | ||
259 | module_exit(pda_power_exit); | ||
260 | MODULE_LICENSE("GPL"); | ||
261 | MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); | ||
diff --git a/drivers/power/pmu_battery.c b/drivers/power/pmu_battery.c new file mode 100644 index 000000000000..2fea4af0e40a --- /dev/null +++ b/drivers/power/pmu_battery.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Battery class driver for Apple PMU | ||
3 | * | ||
4 | * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> | ||
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 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/power_supply.h> | ||
15 | #include <linux/adb.h> | ||
16 | #include <linux/pmu.h> | ||
17 | |||
18 | static struct pmu_battery_dev { | ||
19 | struct power_supply bat; | ||
20 | struct pmu_battery_info *pbi; | ||
21 | char name[16]; | ||
22 | int propval; | ||
23 | } *pbats[PMU_MAX_BATTERIES]; | ||
24 | |||
25 | #define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat) | ||
26 | |||
27 | /********************************************************************* | ||
28 | * Power | ||
29 | *********************************************************************/ | ||
30 | |||
31 | static int pmu_get_ac_prop(struct power_supply *psy, | ||
32 | enum power_supply_property psp, | ||
33 | union power_supply_propval *val) | ||
34 | { | ||
35 | switch (psp) { | ||
36 | case POWER_SUPPLY_PROP_ONLINE: | ||
37 | val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) || | ||
38 | (pmu_battery_count == 0); | ||
39 | break; | ||
40 | default: | ||
41 | return -EINVAL; | ||
42 | } | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static enum power_supply_property pmu_ac_props[] = { | ||
48 | POWER_SUPPLY_PROP_ONLINE, | ||
49 | }; | ||
50 | |||
51 | static struct power_supply pmu_ac = { | ||
52 | .name = "pmu-ac", | ||
53 | .type = POWER_SUPPLY_TYPE_MAINS, | ||
54 | .properties = pmu_ac_props, | ||
55 | .num_properties = ARRAY_SIZE(pmu_ac_props), | ||
56 | .get_property = pmu_get_ac_prop, | ||
57 | }; | ||
58 | |||
59 | /********************************************************************* | ||
60 | * Battery properties | ||
61 | *********************************************************************/ | ||
62 | |||
63 | static char *pmu_batt_types[] = { | ||
64 | "Smart", "Comet", "Hooper", "Unknown" | ||
65 | }; | ||
66 | |||
67 | static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi) | ||
68 | { | ||
69 | switch (pbi->flags & PMU_BATT_TYPE_MASK) { | ||
70 | case PMU_BATT_TYPE_SMART: | ||
71 | return pmu_batt_types[0]; | ||
72 | case PMU_BATT_TYPE_COMET: | ||
73 | return pmu_batt_types[1]; | ||
74 | case PMU_BATT_TYPE_HOOPER: | ||
75 | return pmu_batt_types[2]; | ||
76 | default: break; | ||
77 | } | ||
78 | return pmu_batt_types[3]; | ||
79 | } | ||
80 | |||
81 | static int pmu_bat_get_property(struct power_supply *psy, | ||
82 | enum power_supply_property psp, | ||
83 | union power_supply_propval *val) | ||
84 | { | ||
85 | struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy); | ||
86 | struct pmu_battery_info *pbi = pbat->pbi; | ||
87 | |||
88 | switch (psp) { | ||
89 | case POWER_SUPPLY_PROP_STATUS: | ||
90 | if (pbi->flags & PMU_BATT_CHARGING) | ||
91 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
92 | else | ||
93 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
94 | break; | ||
95 | case POWER_SUPPLY_PROP_PRESENT: | ||
96 | val->intval = !!(pbi->flags & PMU_BATT_PRESENT); | ||
97 | break; | ||
98 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
99 | val->strval = pmu_bat_get_model_name(pbi); | ||
100 | break; | ||
101 | case POWER_SUPPLY_PROP_ENERGY_AVG: | ||
102 | val->intval = pbi->charge * 1000; /* mWh -> µWh */ | ||
103 | break; | ||
104 | case POWER_SUPPLY_PROP_ENERGY_FULL: | ||
105 | val->intval = pbi->max_charge * 1000; /* mWh -> µWh */ | ||
106 | break; | ||
107 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
108 | val->intval = pbi->amperage * 1000; /* mA -> µA */ | ||
109 | break; | ||
110 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
111 | val->intval = pbi->voltage * 1000; /* mV -> µV */ | ||
112 | break; | ||
113 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | ||
114 | val->intval = pbi->time_remaining; | ||
115 | break; | ||
116 | default: | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static enum power_supply_property pmu_bat_props[] = { | ||
124 | POWER_SUPPLY_PROP_STATUS, | ||
125 | POWER_SUPPLY_PROP_PRESENT, | ||
126 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
127 | POWER_SUPPLY_PROP_ENERGY_AVG, | ||
128 | POWER_SUPPLY_PROP_ENERGY_FULL, | ||
129 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
130 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | ||
131 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, | ||
132 | }; | ||
133 | |||
134 | /********************************************************************* | ||
135 | * Initialisation | ||
136 | *********************************************************************/ | ||
137 | |||
138 | static struct platform_device *bat_pdev; | ||
139 | |||
140 | static int __init pmu_bat_init(void) | ||
141 | { | ||
142 | int ret; | ||
143 | int i; | ||
144 | |||
145 | bat_pdev = platform_device_register_simple("pmu-battery", | ||
146 | 0, NULL, 0); | ||
147 | if (IS_ERR(bat_pdev)) { | ||
148 | ret = PTR_ERR(bat_pdev); | ||
149 | goto pdev_register_failed; | ||
150 | } | ||
151 | |||
152 | ret = power_supply_register(&bat_pdev->dev, &pmu_ac); | ||
153 | if (ret) | ||
154 | goto ac_register_failed; | ||
155 | |||
156 | for (i = 0; i < pmu_battery_count; i++) { | ||
157 | struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat), | ||
158 | GFP_KERNEL); | ||
159 | if (!pbat) | ||
160 | break; | ||
161 | |||
162 | sprintf(pbat->name, "PMU battery %d", i); | ||
163 | pbat->bat.name = pbat->name; | ||
164 | pbat->bat.properties = pmu_bat_props; | ||
165 | pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props); | ||
166 | pbat->bat.get_property = pmu_bat_get_property; | ||
167 | pbat->pbi = &pmu_batteries[i]; | ||
168 | |||
169 | ret = power_supply_register(&bat_pdev->dev, &pbat->bat); | ||
170 | if (ret) { | ||
171 | kfree(pbat); | ||
172 | goto battery_register_failed; | ||
173 | } | ||
174 | pbats[i] = pbat; | ||
175 | } | ||
176 | |||
177 | goto success; | ||
178 | |||
179 | battery_register_failed: | ||
180 | while (i--) { | ||
181 | if (!pbats[i]) | ||
182 | continue; | ||
183 | power_supply_unregister(&pbats[i]->bat); | ||
184 | kfree(pbats[i]); | ||
185 | } | ||
186 | power_supply_unregister(&pmu_ac); | ||
187 | ac_register_failed: | ||
188 | platform_device_unregister(bat_pdev); | ||
189 | pdev_register_failed: | ||
190 | success: | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static void __exit pmu_bat_exit(void) | ||
195 | { | ||
196 | int i; | ||
197 | |||
198 | for (i = 0; i < PMU_MAX_BATTERIES; i++) { | ||
199 | if (!pbats[i]) | ||
200 | continue; | ||
201 | power_supply_unregister(&pbats[i]->bat); | ||
202 | kfree(pbats[i]); | ||
203 | } | ||
204 | power_supply_unregister(&pmu_ac); | ||
205 | platform_device_unregister(bat_pdev); | ||
206 | |||
207 | return; | ||
208 | } | ||
209 | |||
210 | module_init(pmu_bat_init); | ||
211 | module_exit(pmu_bat_exit); | ||
212 | |||
213 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | ||
214 | MODULE_LICENSE("GPL"); | ||
215 | MODULE_DESCRIPTION("PMU battery driver"); | ||
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h new file mode 100644 index 000000000000..a9880d468ee4 --- /dev/null +++ b/drivers/power/power_supply.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Functions private to power supply class | ||
3 | * | ||
4 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> | ||
5 | * Copyright © 2004 Szabolcs Gyurko | ||
6 | * Copyright © 2003 Ian Molton <spyro@f2s.com> | ||
7 | * | ||
8 | * Modified: 2004, Oct Szabolcs Gyurko | ||
9 | * | ||
10 | * You may use this code as per GPL version 2 | ||
11 | */ | ||
12 | |||
13 | #ifdef CONFIG_SYSFS | ||
14 | |||
15 | extern int power_supply_create_attrs(struct power_supply *psy); | ||
16 | extern void power_supply_remove_attrs(struct power_supply *psy); | ||
17 | extern int power_supply_uevent(struct device *dev, char **envp, int num_envp, | ||
18 | char *buffer, int buffer_size); | ||
19 | |||
20 | #else | ||
21 | |||
22 | static inline int power_supply_create_attrs(struct power_supply *psy) | ||
23 | { return 0; } | ||
24 | static inline void power_supply_remove_attrs(struct power_supply *psy) {} | ||
25 | #define power_supply_uevent NULL | ||
26 | |||
27 | #endif /* CONFIG_SYSFS */ | ||
28 | |||
29 | #ifdef CONFIG_LEDS_TRIGGERS | ||
30 | |||
31 | extern void power_supply_update_leds(struct power_supply *psy); | ||
32 | extern int power_supply_create_triggers(struct power_supply *psy); | ||
33 | extern void power_supply_remove_triggers(struct power_supply *psy); | ||
34 | |||
35 | #else | ||
36 | |||
37 | static inline void power_supply_update_leds(struct power_supply *psy) {} | ||
38 | static inline int power_supply_create_triggers(struct power_supply *psy) | ||
39 | { return 0; } | ||
40 | static inline void power_supply_remove_triggers(struct power_supply *psy) {} | ||
41 | |||
42 | #endif /* CONFIG_LEDS_TRIGGERS */ | ||
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c new file mode 100644 index 000000000000..e87ea5156755 --- /dev/null +++ b/drivers/power/power_supply_core.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * Universal power supply monitor class | ||
3 | * | ||
4 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> | ||
5 | * Copyright © 2004 Szabolcs Gyurko | ||
6 | * Copyright © 2003 Ian Molton <spyro@f2s.com> | ||
7 | * | ||
8 | * Modified: 2004, Oct Szabolcs Gyurko | ||
9 | * | ||
10 | * You may use this code as per GPL version 2 | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/power_supply.h> | ||
19 | #include "power_supply.h" | ||
20 | |||
21 | struct class *power_supply_class; | ||
22 | |||
23 | static void power_supply_changed_work(struct work_struct *work) | ||
24 | { | ||
25 | struct power_supply *psy = container_of(work, struct power_supply, | ||
26 | changed_work); | ||
27 | int i; | ||
28 | |||
29 | dev_dbg(psy->dev, "%s\n", __FUNCTION__); | ||
30 | |||
31 | for (i = 0; i < psy->num_supplicants; i++) { | ||
32 | struct device *dev; | ||
33 | |||
34 | down(&power_supply_class->sem); | ||
35 | list_for_each_entry(dev, &power_supply_class->devices, node) { | ||
36 | struct power_supply *pst = dev_get_drvdata(dev); | ||
37 | |||
38 | if (!strcmp(psy->supplied_to[i], pst->name)) { | ||
39 | if (pst->external_power_changed) | ||
40 | pst->external_power_changed(pst); | ||
41 | } | ||
42 | } | ||
43 | up(&power_supply_class->sem); | ||
44 | } | ||
45 | |||
46 | power_supply_update_leds(psy); | ||
47 | |||
48 | kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); | ||
49 | |||
50 | return; | ||
51 | } | ||
52 | |||
53 | void power_supply_changed(struct power_supply *psy) | ||
54 | { | ||
55 | dev_dbg(psy->dev, "%s\n", __FUNCTION__); | ||
56 | |||
57 | schedule_work(&psy->changed_work); | ||
58 | |||
59 | return; | ||
60 | } | ||
61 | |||
62 | int power_supply_am_i_supplied(struct power_supply *psy) | ||
63 | { | ||
64 | union power_supply_propval ret = {0,}; | ||
65 | struct device *dev; | ||
66 | |||
67 | down(&power_supply_class->sem); | ||
68 | list_for_each_entry(dev, &power_supply_class->devices, node) { | ||
69 | struct power_supply *epsy = dev_get_drvdata(dev); | ||
70 | int i; | ||
71 | |||
72 | for (i = 0; i < epsy->num_supplicants; i++) { | ||
73 | if (!strcmp(epsy->supplied_to[i], psy->name)) { | ||
74 | if (epsy->get_property(epsy, | ||
75 | POWER_SUPPLY_PROP_ONLINE, &ret)) | ||
76 | continue; | ||
77 | if (ret.intval) | ||
78 | goto out; | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | out: | ||
83 | up(&power_supply_class->sem); | ||
84 | |||
85 | dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval); | ||
86 | |||
87 | return ret.intval; | ||
88 | } | ||
89 | |||
90 | int power_supply_register(struct device *parent, struct power_supply *psy) | ||
91 | { | ||
92 | int rc = 0; | ||
93 | |||
94 | psy->dev = device_create(power_supply_class, parent, 0, | ||
95 | "%s", psy->name); | ||
96 | if (IS_ERR(psy->dev)) { | ||
97 | rc = PTR_ERR(psy->dev); | ||
98 | goto dev_create_failed; | ||
99 | } | ||
100 | |||
101 | dev_set_drvdata(psy->dev, psy); | ||
102 | |||
103 | INIT_WORK(&psy->changed_work, power_supply_changed_work); | ||
104 | |||
105 | rc = power_supply_create_attrs(psy); | ||
106 | if (rc) | ||
107 | goto create_attrs_failed; | ||
108 | |||
109 | rc = power_supply_create_triggers(psy); | ||
110 | if (rc) | ||
111 | goto create_triggers_failed; | ||
112 | |||
113 | power_supply_changed(psy); | ||
114 | |||
115 | goto success; | ||
116 | |||
117 | create_triggers_failed: | ||
118 | power_supply_remove_attrs(psy); | ||
119 | create_attrs_failed: | ||
120 | device_unregister(psy->dev); | ||
121 | dev_create_failed: | ||
122 | success: | ||
123 | return rc; | ||
124 | } | ||
125 | |||
126 | void power_supply_unregister(struct power_supply *psy) | ||
127 | { | ||
128 | flush_scheduled_work(); | ||
129 | power_supply_remove_triggers(psy); | ||
130 | power_supply_remove_attrs(psy); | ||
131 | device_unregister(psy->dev); | ||
132 | return; | ||
133 | } | ||
134 | |||
135 | static int __init power_supply_class_init(void) | ||
136 | { | ||
137 | power_supply_class = class_create(THIS_MODULE, "power_supply"); | ||
138 | |||
139 | if (IS_ERR(power_supply_class)) | ||
140 | return PTR_ERR(power_supply_class); | ||
141 | |||
142 | power_supply_class->dev_uevent = power_supply_uevent; | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static void __exit power_supply_class_exit(void) | ||
148 | { | ||
149 | class_destroy(power_supply_class); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | EXPORT_SYMBOL_GPL(power_supply_changed); | ||
154 | EXPORT_SYMBOL_GPL(power_supply_am_i_supplied); | ||
155 | EXPORT_SYMBOL_GPL(power_supply_register); | ||
156 | EXPORT_SYMBOL_GPL(power_supply_unregister); | ||
157 | |||
158 | /* exported for the APM Power driver, APM emulation */ | ||
159 | EXPORT_SYMBOL_GPL(power_supply_class); | ||
160 | |||
161 | subsys_initcall(power_supply_class_init); | ||
162 | module_exit(power_supply_class_exit); | ||
163 | |||
164 | MODULE_DESCRIPTION("Universal power supply monitor class"); | ||
165 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, " | ||
166 | "Szabolcs Gyurko, " | ||
167 | "Anton Vorontsov <cbou@mail.ru>"); | ||
168 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c new file mode 100644 index 000000000000..7232490bb595 --- /dev/null +++ b/drivers/power/power_supply_leds.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * LEDs triggers for power supply class | ||
3 | * | ||
4 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> | ||
5 | * Copyright © 2004 Szabolcs Gyurko | ||
6 | * Copyright © 2003 Ian Molton <spyro@f2s.com> | ||
7 | * | ||
8 | * Modified: 2004, Oct Szabolcs Gyurko | ||
9 | * | ||
10 | * You may use this code as per GPL version 2 | ||
11 | */ | ||
12 | |||
13 | #include <linux/power_supply.h> | ||
14 | |||
15 | /* Battery specific LEDs triggers. */ | ||
16 | |||
17 | static void power_supply_update_bat_leds(struct power_supply *psy) | ||
18 | { | ||
19 | union power_supply_propval status; | ||
20 | |||
21 | if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) | ||
22 | return; | ||
23 | |||
24 | dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval); | ||
25 | |||
26 | switch (status.intval) { | ||
27 | case POWER_SUPPLY_STATUS_FULL: | ||
28 | led_trigger_event(psy->charging_full_trig, LED_FULL); | ||
29 | led_trigger_event(psy->charging_trig, LED_OFF); | ||
30 | led_trigger_event(psy->full_trig, LED_FULL); | ||
31 | break; | ||
32 | case POWER_SUPPLY_STATUS_CHARGING: | ||
33 | led_trigger_event(psy->charging_full_trig, LED_FULL); | ||
34 | led_trigger_event(psy->charging_trig, LED_FULL); | ||
35 | led_trigger_event(psy->full_trig, LED_OFF); | ||
36 | break; | ||
37 | default: | ||
38 | led_trigger_event(psy->charging_full_trig, LED_OFF); | ||
39 | led_trigger_event(psy->charging_trig, LED_OFF); | ||
40 | led_trigger_event(psy->full_trig, LED_OFF); | ||
41 | break; | ||
42 | } | ||
43 | |||
44 | return; | ||
45 | } | ||
46 | |||
47 | static int power_supply_create_bat_triggers(struct power_supply *psy) | ||
48 | { | ||
49 | int rc = 0; | ||
50 | |||
51 | psy->charging_full_trig_name = kmalloc(strlen(psy->name) + | ||
52 | sizeof("-charging-or-full"), GFP_KERNEL); | ||
53 | if (!psy->charging_full_trig_name) | ||
54 | goto charging_full_failed; | ||
55 | |||
56 | psy->charging_trig_name = kmalloc(strlen(psy->name) + | ||
57 | sizeof("-charging"), GFP_KERNEL); | ||
58 | if (!psy->charging_trig_name) | ||
59 | goto charging_failed; | ||
60 | |||
61 | psy->full_trig_name = kmalloc(strlen(psy->name) + | ||
62 | sizeof("-full"), GFP_KERNEL); | ||
63 | if (!psy->full_trig_name) | ||
64 | goto full_failed; | ||
65 | |||
66 | strcpy(psy->charging_full_trig_name, psy->name); | ||
67 | strcat(psy->charging_full_trig_name, "-charging-or-full"); | ||
68 | strcpy(psy->charging_trig_name, psy->name); | ||
69 | strcat(psy->charging_trig_name, "-charging"); | ||
70 | strcpy(psy->full_trig_name, psy->name); | ||
71 | strcat(psy->full_trig_name, "-full"); | ||
72 | |||
73 | led_trigger_register_simple(psy->charging_full_trig_name, | ||
74 | &psy->charging_full_trig); | ||
75 | led_trigger_register_simple(psy->charging_trig_name, | ||
76 | &psy->charging_trig); | ||
77 | led_trigger_register_simple(psy->full_trig_name, | ||
78 | &psy->full_trig); | ||
79 | |||
80 | goto success; | ||
81 | |||
82 | full_failed: | ||
83 | kfree(psy->charging_trig_name); | ||
84 | charging_failed: | ||
85 | kfree(psy->charging_full_trig_name); | ||
86 | charging_full_failed: | ||
87 | rc = -ENOMEM; | ||
88 | success: | ||
89 | return rc; | ||
90 | } | ||
91 | |||
92 | static void power_supply_remove_bat_triggers(struct power_supply *psy) | ||
93 | { | ||
94 | led_trigger_unregister_simple(psy->charging_full_trig); | ||
95 | led_trigger_unregister_simple(psy->charging_trig); | ||
96 | led_trigger_unregister_simple(psy->full_trig); | ||
97 | kfree(psy->full_trig_name); | ||
98 | kfree(psy->charging_trig_name); | ||
99 | kfree(psy->charging_full_trig_name); | ||
100 | return; | ||
101 | } | ||
102 | |||
103 | /* Generated power specific LEDs triggers. */ | ||
104 | |||
105 | static void power_supply_update_gen_leds(struct power_supply *psy) | ||
106 | { | ||
107 | union power_supply_propval online; | ||
108 | |||
109 | if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) | ||
110 | return; | ||
111 | |||
112 | dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval); | ||
113 | |||
114 | if (online.intval) | ||
115 | led_trigger_event(psy->online_trig, LED_FULL); | ||
116 | else | ||
117 | led_trigger_event(psy->online_trig, LED_OFF); | ||
118 | |||
119 | return; | ||
120 | } | ||
121 | |||
122 | static int power_supply_create_gen_triggers(struct power_supply *psy) | ||
123 | { | ||
124 | int rc = 0; | ||
125 | |||
126 | psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"), | ||
127 | GFP_KERNEL); | ||
128 | if (!psy->online_trig_name) | ||
129 | goto online_failed; | ||
130 | |||
131 | strcpy(psy->online_trig_name, psy->name); | ||
132 | strcat(psy->online_trig_name, "-online"); | ||
133 | |||
134 | led_trigger_register_simple(psy->online_trig_name, &psy->online_trig); | ||
135 | |||
136 | goto success; | ||
137 | |||
138 | online_failed: | ||
139 | rc = -ENOMEM; | ||
140 | success: | ||
141 | return rc; | ||
142 | } | ||
143 | |||
144 | static void power_supply_remove_gen_triggers(struct power_supply *psy) | ||
145 | { | ||
146 | led_trigger_unregister_simple(psy->online_trig); | ||
147 | kfree(psy->online_trig_name); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | /* Choice what triggers to create&update. */ | ||
152 | |||
153 | void power_supply_update_leds(struct power_supply *psy) | ||
154 | { | ||
155 | if (psy->type == POWER_SUPPLY_TYPE_BATTERY) | ||
156 | power_supply_update_bat_leds(psy); | ||
157 | else | ||
158 | power_supply_update_gen_leds(psy); | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | int power_supply_create_triggers(struct power_supply *psy) | ||
163 | { | ||
164 | if (psy->type == POWER_SUPPLY_TYPE_BATTERY) | ||
165 | return power_supply_create_bat_triggers(psy); | ||
166 | return power_supply_create_gen_triggers(psy); | ||
167 | } | ||
168 | |||
169 | void power_supply_remove_triggers(struct power_supply *psy) | ||
170 | { | ||
171 | if (psy->type == POWER_SUPPLY_TYPE_BATTERY) | ||
172 | power_supply_remove_bat_triggers(psy); | ||
173 | else | ||
174 | power_supply_remove_gen_triggers(psy); | ||
175 | return; | ||
176 | } | ||
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c new file mode 100644 index 000000000000..c07d4258d347 --- /dev/null +++ b/drivers/power/power_supply_sysfs.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * Sysfs interface for the universal power supply monitor class | ||
3 | * | ||
4 | * Copyright © 2007 David Woodhouse <dwmw2@infradead.org> | ||
5 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> | ||
6 | * Copyright © 2004 Szabolcs Gyurko | ||
7 | * Copyright © 2003 Ian Molton <spyro@f2s.com> | ||
8 | * | ||
9 | * Modified: 2004, Oct Szabolcs Gyurko | ||
10 | * | ||
11 | * You may use this code as per GPL version 2 | ||
12 | */ | ||
13 | |||
14 | #include <linux/ctype.h> | ||
15 | #include <linux/power_supply.h> | ||
16 | |||
17 | /* | ||
18 | * This is because the name "current" breaks the device attr macro. | ||
19 | * The "current" word resolves to "(get_current())" so instead of | ||
20 | * "current" "(get_current())" appears in the sysfs. | ||
21 | * | ||
22 | * The source of this definition is the device.h which calls __ATTR | ||
23 | * macro in sysfs.h which calls the __stringify macro. | ||
24 | * | ||
25 | * Only modification that the name is not tried to be resolved | ||
26 | * (as a macro let's say). | ||
27 | */ | ||
28 | |||
29 | #define POWER_SUPPLY_ATTR(_name) \ | ||
30 | { \ | ||
31 | .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \ | ||
32 | .show = power_supply_show_property, \ | ||
33 | .store = NULL, \ | ||
34 | } | ||
35 | |||
36 | static struct device_attribute power_supply_attrs[]; | ||
37 | |||
38 | static ssize_t power_supply_show_property(struct device *dev, | ||
39 | struct device_attribute *attr, | ||
40 | char *buf) { | ||
41 | static char *status_text[] = { | ||
42 | "Unknown", "Charging", "Discharging", "Not charging", "Full" | ||
43 | }; | ||
44 | static char *health_text[] = { | ||
45 | "Unknown", "Good", "Overheat", "Dead", "Over voltage", | ||
46 | "Unspecified failure" | ||
47 | }; | ||
48 | static char *technology_text[] = { | ||
49 | "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd" | ||
50 | }; | ||
51 | static char *capacity_level_text[] = { | ||
52 | "Unknown", "Critical", "Low", "Normal", "High", "Full" | ||
53 | }; | ||
54 | ssize_t ret; | ||
55 | struct power_supply *psy = dev_get_drvdata(dev); | ||
56 | const ptrdiff_t off = attr - power_supply_attrs; | ||
57 | union power_supply_propval value; | ||
58 | |||
59 | ret = psy->get_property(psy, off, &value); | ||
60 | |||
61 | if (ret < 0) { | ||
62 | if (ret != -ENODEV) | ||
63 | dev_err(dev, "driver failed to report `%s' property\n", | ||
64 | attr->attr.name); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | if (off == POWER_SUPPLY_PROP_STATUS) | ||
69 | return sprintf(buf, "%s\n", status_text[value.intval]); | ||
70 | else if (off == POWER_SUPPLY_PROP_HEALTH) | ||
71 | return sprintf(buf, "%s\n", health_text[value.intval]); | ||
72 | else if (off == POWER_SUPPLY_PROP_TECHNOLOGY) | ||
73 | return sprintf(buf, "%s\n", technology_text[value.intval]); | ||
74 | else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) | ||
75 | return sprintf(buf, "%s\n", | ||
76 | capacity_level_text[value.intval]); | ||
77 | else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) | ||
78 | return sprintf(buf, "%s\n", value.strval); | ||
79 | |||
80 | return sprintf(buf, "%d\n", value.intval); | ||
81 | } | ||
82 | |||
83 | /* Must be in the same order as POWER_SUPPLY_PROP_* */ | ||
84 | static struct device_attribute power_supply_attrs[] = { | ||
85 | /* Properties of type `int' */ | ||
86 | POWER_SUPPLY_ATTR(status), | ||
87 | POWER_SUPPLY_ATTR(health), | ||
88 | POWER_SUPPLY_ATTR(present), | ||
89 | POWER_SUPPLY_ATTR(online), | ||
90 | POWER_SUPPLY_ATTR(technology), | ||
91 | POWER_SUPPLY_ATTR(voltage_max_design), | ||
92 | POWER_SUPPLY_ATTR(voltage_min_design), | ||
93 | POWER_SUPPLY_ATTR(voltage_now), | ||
94 | POWER_SUPPLY_ATTR(voltage_avg), | ||
95 | POWER_SUPPLY_ATTR(current_now), | ||
96 | POWER_SUPPLY_ATTR(current_avg), | ||
97 | POWER_SUPPLY_ATTR(charge_full_design), | ||
98 | POWER_SUPPLY_ATTR(charge_empty_design), | ||
99 | POWER_SUPPLY_ATTR(charge_full), | ||
100 | POWER_SUPPLY_ATTR(charge_empty), | ||
101 | POWER_SUPPLY_ATTR(charge_now), | ||
102 | POWER_SUPPLY_ATTR(charge_avg), | ||
103 | POWER_SUPPLY_ATTR(energy_full_design), | ||
104 | POWER_SUPPLY_ATTR(energy_empty_design), | ||
105 | POWER_SUPPLY_ATTR(energy_full), | ||
106 | POWER_SUPPLY_ATTR(energy_empty), | ||
107 | POWER_SUPPLY_ATTR(energy_now), | ||
108 | POWER_SUPPLY_ATTR(energy_avg), | ||
109 | POWER_SUPPLY_ATTR(capacity), | ||
110 | POWER_SUPPLY_ATTR(capacity_level), | ||
111 | POWER_SUPPLY_ATTR(temp), | ||
112 | POWER_SUPPLY_ATTR(temp_ambient), | ||
113 | POWER_SUPPLY_ATTR(time_to_empty_now), | ||
114 | POWER_SUPPLY_ATTR(time_to_empty_avg), | ||
115 | POWER_SUPPLY_ATTR(time_to_full_now), | ||
116 | POWER_SUPPLY_ATTR(time_to_full_avg), | ||
117 | /* Properties of type `const char *' */ | ||
118 | POWER_SUPPLY_ATTR(model_name), | ||
119 | POWER_SUPPLY_ATTR(manufacturer), | ||
120 | }; | ||
121 | |||
122 | static ssize_t power_supply_show_static_attrs(struct device *dev, | ||
123 | struct device_attribute *attr, | ||
124 | char *buf) { | ||
125 | static char *type_text[] = { "Battery", "UPS", "Mains", "USB" }; | ||
126 | struct power_supply *psy = dev_get_drvdata(dev); | ||
127 | |||
128 | return sprintf(buf, "%s\n", type_text[psy->type]); | ||
129 | } | ||
130 | |||
131 | static struct device_attribute power_supply_static_attrs[] = { | ||
132 | __ATTR(type, 0444, power_supply_show_static_attrs, NULL), | ||
133 | }; | ||
134 | |||
135 | int power_supply_create_attrs(struct power_supply *psy) | ||
136 | { | ||
137 | int rc = 0; | ||
138 | int i, j; | ||
139 | |||
140 | for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) { | ||
141 | rc = device_create_file(psy->dev, | ||
142 | &power_supply_static_attrs[i]); | ||
143 | if (rc) | ||
144 | goto statics_failed; | ||
145 | } | ||
146 | |||
147 | for (j = 0; j < psy->num_properties; j++) { | ||
148 | rc = device_create_file(psy->dev, | ||
149 | &power_supply_attrs[psy->properties[j]]); | ||
150 | if (rc) | ||
151 | goto dynamics_failed; | ||
152 | } | ||
153 | |||
154 | goto succeed; | ||
155 | |||
156 | dynamics_failed: | ||
157 | while (j--) | ||
158 | device_remove_file(psy->dev, | ||
159 | &power_supply_attrs[psy->properties[j]]); | ||
160 | statics_failed: | ||
161 | while (i--) | ||
162 | device_remove_file(psy->dev, | ||
163 | &power_supply_static_attrs[psy->properties[i]]); | ||
164 | succeed: | ||
165 | return rc; | ||
166 | } | ||
167 | |||
168 | void power_supply_remove_attrs(struct power_supply *psy) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) | ||
173 | device_remove_file(psy->dev, | ||
174 | &power_supply_static_attrs[i]); | ||
175 | |||
176 | for (i = 0; i < psy->num_properties; i++) | ||
177 | device_remove_file(psy->dev, | ||
178 | &power_supply_attrs[psy->properties[i]]); | ||
179 | |||
180 | return; | ||
181 | } | ||
182 | |||
183 | static char *kstruprdup(const char *str, gfp_t gfp) | ||
184 | { | ||
185 | char *ret, *ustr; | ||
186 | |||
187 | ustr = ret = kmalloc(strlen(str) + 1, gfp); | ||
188 | |||
189 | if (!ret) | ||
190 | return NULL; | ||
191 | |||
192 | while (*str) | ||
193 | *ustr++ = toupper(*str++); | ||
194 | |||
195 | *ustr = 0; | ||
196 | |||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | int power_supply_uevent(struct device *dev, char **envp, int num_envp, | ||
201 | char *buffer, int buffer_size) | ||
202 | { | ||
203 | struct power_supply *psy = dev_get_drvdata(dev); | ||
204 | int i = 0, length = 0, ret = 0, j; | ||
205 | char *prop_buf; | ||
206 | char *attrname; | ||
207 | |||
208 | dev_dbg(dev, "uevent\n"); | ||
209 | |||
210 | if (!psy) { | ||
211 | dev_dbg(dev, "No power supply yet\n"); | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); | ||
216 | |||
217 | ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, | ||
218 | &length, "POWER_SUPPLY_NAME=%s", psy->name); | ||
219 | if (ret) | ||
220 | return ret; | ||
221 | |||
222 | prop_buf = (char *)get_zeroed_page(GFP_KERNEL); | ||
223 | if (!prop_buf) | ||
224 | return -ENOMEM; | ||
225 | |||
226 | for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) { | ||
227 | struct device_attribute *attr; | ||
228 | char *line; | ||
229 | |||
230 | attr = &power_supply_static_attrs[j]; | ||
231 | |||
232 | ret = power_supply_show_static_attrs(dev, attr, prop_buf); | ||
233 | if (ret < 0) | ||
234 | goto out; | ||
235 | |||
236 | line = strchr(prop_buf, '\n'); | ||
237 | if (line) | ||
238 | *line = 0; | ||
239 | |||
240 | attrname = kstruprdup(attr->attr.name, GFP_KERNEL); | ||
241 | if (!attrname) { | ||
242 | ret = -ENOMEM; | ||
243 | goto out; | ||
244 | } | ||
245 | |||
246 | dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); | ||
247 | |||
248 | ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, | ||
249 | &length, "POWER_SUPPLY_%s=%s", | ||
250 | attrname, prop_buf); | ||
251 | kfree(attrname); | ||
252 | if (ret) | ||
253 | goto out; | ||
254 | } | ||
255 | |||
256 | dev_dbg(dev, "%zd dynamic props\n", psy->num_properties); | ||
257 | |||
258 | for (j = 0; j < psy->num_properties; j++) { | ||
259 | struct device_attribute *attr; | ||
260 | char *line; | ||
261 | |||
262 | attr = &power_supply_attrs[psy->properties[j]]; | ||
263 | |||
264 | ret = power_supply_show_property(dev, attr, prop_buf); | ||
265 | if (ret == -ENODEV) { | ||
266 | /* When a battery is absent, we expect -ENODEV. Don't abort; | ||
267 | send the uevent with at least the the PRESENT=0 property */ | ||
268 | ret = 0; | ||
269 | continue; | ||
270 | } | ||
271 | |||
272 | if (ret < 0) | ||
273 | goto out; | ||
274 | |||
275 | line = strchr(prop_buf, '\n'); | ||
276 | if (line) | ||
277 | *line = 0; | ||
278 | |||
279 | attrname = kstruprdup(attr->attr.name, GFP_KERNEL); | ||
280 | if (!attrname) { | ||
281 | ret = -ENOMEM; | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); | ||
286 | |||
287 | ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, | ||
288 | &length, "POWER_SUPPLY_%s=%s", | ||
289 | attrname, prop_buf); | ||
290 | kfree(attrname); | ||
291 | if (ret) | ||
292 | goto out; | ||
293 | } | ||
294 | |||
295 | out: | ||
296 | free_page((unsigned long)prop_buf); | ||
297 | |||
298 | return ret; | ||
299 | } | ||
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 8b3b0f4a157c..ac7e8ef504cb 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c | |||
@@ -28,6 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL; | |||
28 | static struct proc_dir_entry *dasd_devices_entry = NULL; | 28 | static struct proc_dir_entry *dasd_devices_entry = NULL; |
29 | static struct proc_dir_entry *dasd_statistics_entry = NULL; | 29 | static struct proc_dir_entry *dasd_statistics_entry = NULL; |
30 | 30 | ||
31 | #ifdef CONFIG_DASD_PROFILE | ||
31 | static char * | 32 | static char * |
32 | dasd_get_user_string(const char __user *user_buf, size_t user_len) | 33 | dasd_get_user_string(const char __user *user_buf, size_t user_len) |
33 | { | 34 | { |
@@ -47,6 +48,7 @@ dasd_get_user_string(const char __user *user_buf, size_t user_len) | |||
47 | buffer[user_len] = 0; | 48 | buffer[user_len] = 0; |
48 | return buffer; | 49 | return buffer; |
49 | } | 50 | } |
51 | #endif /* CONFIG_DASD_PROFILE */ | ||
50 | 52 | ||
51 | static int | 53 | static int |
52 | dasd_devices_show(struct seq_file *m, void *v) | 54 | dasd_devices_show(struct seq_file *m, void *v) |
@@ -167,6 +169,7 @@ dasd_calc_metrics(char *page, char **start, off_t off, | |||
167 | return len; | 169 | return len; |
168 | } | 170 | } |
169 | 171 | ||
172 | #ifdef CONFIG_DASD_PROFILE | ||
170 | static char * | 173 | static char * |
171 | dasd_statistics_array(char *str, unsigned int *array, int shift) | 174 | dasd_statistics_array(char *str, unsigned int *array, int shift) |
172 | { | 175 | { |
@@ -180,6 +183,7 @@ dasd_statistics_array(char *str, unsigned int *array, int shift) | |||
180 | str += sprintf(str,"\n"); | 183 | str += sprintf(str,"\n"); |
181 | return str; | 184 | return str; |
182 | } | 185 | } |
186 | #endif /* CONFIG_DASD_PROFILE */ | ||
183 | 187 | ||
184 | static int | 188 | static int |
185 | dasd_statistics_read(char *page, char **start, off_t off, | 189 | dasd_statistics_read(char *page, char **start, off_t off, |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index dbb99d1b6f57..c7318a125852 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -72,6 +72,18 @@ typedef unsigned int sclp_cmdw_t; | |||
72 | 72 | ||
73 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ | 73 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ |
74 | 74 | ||
75 | struct sccb_header { | ||
76 | u16 length; | ||
77 | u8 function_code; | ||
78 | u8 control_mask[3]; | ||
79 | u16 response_code; | ||
80 | } __attribute__((packed)); | ||
81 | |||
82 | extern u64 sclp_facilities; | ||
83 | |||
84 | #define SCLP_HAS_CHP_INFO (sclp_facilities & 0x8000000000000000ULL) | ||
85 | #define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL) | ||
86 | |||
75 | struct gds_subvector { | 87 | struct gds_subvector { |
76 | u8 length; | 88 | u8 length; |
77 | u8 key; | 89 | u8 key; |
diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c index a66b914519b5..c68f5e7e63a0 100644 --- a/drivers/s390/char/sclp_chp.c +++ b/drivers/s390/char/sclp_chp.c | |||
@@ -55,6 +55,8 @@ static int do_configure(sclp_cmdw_t cmd) | |||
55 | struct chp_cfg_data *data; | 55 | struct chp_cfg_data *data; |
56 | int rc; | 56 | int rc; |
57 | 57 | ||
58 | if (!SCLP_HAS_CHP_RECONFIG) | ||
59 | return -EOPNOTSUPP; | ||
58 | /* Prepare sccb. */ | 60 | /* Prepare sccb. */ |
59 | data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | 61 | data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); |
60 | if (!data) | 62 | if (!data) |
@@ -152,6 +154,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info) | |||
152 | struct chp_info_data *data; | 154 | struct chp_info_data *data; |
153 | int rc; | 155 | int rc; |
154 | 156 | ||
157 | if (!SCLP_HAS_CHP_INFO) | ||
158 | return -EOPNOTSUPP; | ||
155 | /* Prepare sccb. */ | 159 | /* Prepare sccb. */ |
156 | data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | 160 | data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); |
157 | if (!data) | 161 | if (!data) |
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c index 7bcbe643b087..a1136e052750 100644 --- a/drivers/s390/char/sclp_info.c +++ b/drivers/s390/char/sclp_info.c | |||
@@ -11,47 +11,106 @@ | |||
11 | #include <asm/sclp.h> | 11 | #include <asm/sclp.h> |
12 | #include "sclp.h" | 12 | #include "sclp.h" |
13 | 13 | ||
14 | struct sclp_readinfo_sccb s390_readinfo_sccb; | 14 | struct sclp_readinfo_sccb { |
15 | struct sccb_header header; /* 0-7 */ | ||
16 | u16 rnmax; /* 8-9 */ | ||
17 | u8 rnsize; /* 10 */ | ||
18 | u8 _reserved0[24 - 11]; /* 11-23 */ | ||
19 | u8 loadparm[8]; /* 24-31 */ | ||
20 | u8 _reserved1[48 - 32]; /* 32-47 */ | ||
21 | u64 facilities; /* 48-55 */ | ||
22 | u8 _reserved2[91 - 56]; /* 56-90 */ | ||
23 | u8 flags; /* 91 */ | ||
24 | u8 _reserved3[100 - 92]; /* 92-99 */ | ||
25 | u32 rnsize2; /* 100-103 */ | ||
26 | u64 rnmax2; /* 104-111 */ | ||
27 | u8 _reserved4[4096 - 112]; /* 112-4095 */ | ||
28 | } __attribute__((packed, aligned(4096))); | ||
29 | |||
30 | static struct sclp_readinfo_sccb __initdata early_readinfo_sccb; | ||
31 | static int __initdata early_readinfo_sccb_valid; | ||
32 | |||
33 | u64 sclp_facilities; | ||
15 | 34 | ||
16 | void __init sclp_readinfo_early(void) | 35 | void __init sclp_readinfo_early(void) |
17 | { | 36 | { |
18 | sclp_cmdw_t command; | ||
19 | struct sccb_header *sccb; | ||
20 | int ret; | 37 | int ret; |
38 | int i; | ||
39 | struct sclp_readinfo_sccb *sccb; | ||
40 | sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, | ||
41 | SCLP_CMDW_READ_SCP_INFO}; | ||
21 | 42 | ||
22 | __ctl_set_bit(0, 9); /* enable service signal subclass mask */ | 43 | /* Enable service signal subclass mask. */ |
23 | 44 | __ctl_set_bit(0, 9); | |
24 | sccb = &s390_readinfo_sccb.header; | 45 | sccb = &early_readinfo_sccb; |
25 | command = SCLP_CMDW_READ_SCP_INFO_FORCED; | 46 | for (i = 0; i < ARRAY_SIZE(commands); i++) { |
26 | while (1) { | 47 | do { |
27 | u16 response; | 48 | memset(sccb, 0, sizeof(*sccb)); |
28 | 49 | sccb->header.length = sizeof(*sccb); | |
29 | memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb)); | 50 | sccb->header.control_mask[2] = 0x80; |
30 | sccb->length = sizeof(s390_readinfo_sccb); | 51 | ret = sclp_service_call(commands[i], sccb); |
31 | sccb->control_mask[2] = 0x80; | 52 | } while (ret == -EBUSY); |
32 | |||
33 | ret = sclp_service_call(command, &s390_readinfo_sccb); | ||
34 | |||
35 | if (ret == -EIO) | ||
36 | goto out; | ||
37 | if (ret == -EBUSY) | ||
38 | continue; | ||
39 | 53 | ||
54 | if (ret) | ||
55 | break; | ||
40 | __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | | 56 | __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | |
41 | PSW_MASK_WAIT | PSW_DEFAULT_KEY); | 57 | PSW_MASK_WAIT | PSW_DEFAULT_KEY); |
42 | local_irq_disable(); | 58 | local_irq_disable(); |
59 | /* | ||
60 | * Contents of the sccb might have changed | ||
61 | * therefore a barrier is needed. | ||
62 | */ | ||
43 | barrier(); | 63 | barrier(); |
64 | if (sccb->header.response_code == 0x10) { | ||
65 | early_readinfo_sccb_valid = 1; | ||
66 | break; | ||
67 | } | ||
68 | if (sccb->header.response_code != 0x1f0) | ||
69 | break; | ||
70 | } | ||
71 | /* Disable service signal subclass mask again. */ | ||
72 | __ctl_clear_bit(0, 9); | ||
73 | } | ||
44 | 74 | ||
45 | response = sccb->response_code; | 75 | void __init sclp_facilities_detect(void) |
76 | { | ||
77 | if (!early_readinfo_sccb_valid) | ||
78 | return; | ||
79 | sclp_facilities = early_readinfo_sccb.facilities; | ||
80 | } | ||
46 | 81 | ||
47 | if (response == 0x10) | 82 | unsigned long long __init sclp_memory_detect(void) |
48 | break; | 83 | { |
84 | unsigned long long memsize; | ||
85 | struct sclp_readinfo_sccb *sccb; | ||
49 | 86 | ||
50 | if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO) | 87 | if (!early_readinfo_sccb_valid) |
51 | break; | 88 | return 0; |
89 | sccb = &early_readinfo_sccb; | ||
90 | if (sccb->rnsize) | ||
91 | memsize = sccb->rnsize << 20; | ||
92 | else | ||
93 | memsize = sccb->rnsize2 << 20; | ||
94 | if (sccb->rnmax) | ||
95 | memsize *= sccb->rnmax; | ||
96 | else | ||
97 | memsize *= sccb->rnmax2; | ||
98 | return memsize; | ||
99 | } | ||
52 | 100 | ||
53 | command = SCLP_CMDW_READ_SCP_INFO; | 101 | /* |
54 | } | 102 | * This function will be called after sclp_memory_detect(), which gets called |
55 | out: | 103 | * early from early.c code. Therefore the sccb should have valid contents. |
56 | __ctl_clear_bit(0, 9); /* disable service signal subclass mask */ | 104 | */ |
105 | void __init sclp_get_ipl_info(struct sclp_ipl_info *info) | ||
106 | { | ||
107 | struct sclp_readinfo_sccb *sccb; | ||
108 | |||
109 | if (!early_readinfo_sccb_valid) | ||
110 | return; | ||
111 | sccb = &early_readinfo_sccb; | ||
112 | info->is_valid = 1; | ||
113 | if (sccb->flags & 0x2) | ||
114 | info->has_dump = 1; | ||
115 | memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); | ||
57 | } | 116 | } |
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index fce3dac5cb3e..82e6a6b253eb 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c | |||
@@ -175,13 +175,12 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
175 | 175 | ||
176 | static const struct file_operations vmcp_fops = { | 176 | static const struct file_operations vmcp_fops = { |
177 | .owner = THIS_MODULE, | 177 | .owner = THIS_MODULE, |
178 | .open = &vmcp_open, | 178 | .open = vmcp_open, |
179 | .release = &vmcp_release, | 179 | .release = vmcp_release, |
180 | .read = &vmcp_read, | 180 | .read = vmcp_read, |
181 | .llseek = &no_llseek, | 181 | .write = vmcp_write, |
182 | .write = &vmcp_write, | 182 | .unlocked_ioctl = vmcp_ioctl, |
183 | .unlocked_ioctl = &vmcp_ioctl, | 183 | .compat_ioctl = vmcp_ioctl |
184 | .compat_ioctl = &vmcp_ioctl | ||
185 | }; | 184 | }; |
186 | 185 | ||
187 | static struct miscdevice vmcp_dev = { | 186 | static struct miscdevice vmcp_dev = { |
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index a5a00e9ae4d0..12f7a4ce82c1 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
@@ -835,7 +835,7 @@ static void vmlogrdr_cleanup(void) | |||
835 | } | 835 | } |
836 | 836 | ||
837 | 837 | ||
838 | static int vmlogrdr_init(void) | 838 | static int __init vmlogrdr_init(void) |
839 | { | 839 | { |
840 | int rc; | 840 | int rc; |
841 | int i; | 841 | int i; |
@@ -885,7 +885,7 @@ cleanup: | |||
885 | } | 885 | } |
886 | 886 | ||
887 | 887 | ||
888 | static void vmlogrdr_exit(void) | 888 | static void __exit vmlogrdr_exit(void) |
889 | { | 889 | { |
890 | vmlogrdr_cleanup(); | 890 | vmlogrdr_cleanup(); |
891 | printk (KERN_INFO "vmlogrdr: driver unloaded\n"); | 891 | printk (KERN_INFO "vmlogrdr: driver unloaded\n"); |
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 4e711a985d59..3712ede16723 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c | |||
@@ -156,7 +156,7 @@ static int memcpy_real(void *dest, unsigned long src, size_t count) | |||
156 | return rc; | 156 | return rc; |
157 | } | 157 | } |
158 | 158 | ||
159 | static int memcpy_real_user(__user void *dest, unsigned long src, size_t count) | 159 | static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) |
160 | { | 160 | { |
161 | static char buf[4096]; | 161 | static char buf[4096]; |
162 | int offs = 0, size; | 162 | int offs = 0, size; |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 997f46874537..60b9347f7c92 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -27,7 +27,6 @@ | |||
27 | /* | 27 | /* |
28 | * diag210 is used under VM to get information about a virtual device | 28 | * diag210 is used under VM to get information about a virtual device |
29 | */ | 29 | */ |
30 | #ifdef CONFIG_64BIT | ||
31 | int | 30 | int |
32 | diag210(struct diag210 * addr) | 31 | diag210(struct diag210 * addr) |
33 | { | 32 | { |
@@ -43,6 +42,7 @@ diag210(struct diag210 * addr) | |||
43 | spin_lock_irqsave(&diag210_lock, flags); | 42 | spin_lock_irqsave(&diag210_lock, flags); |
44 | diag210_tmp = *addr; | 43 | diag210_tmp = *addr; |
45 | 44 | ||
45 | #ifdef CONFIG_64BIT | ||
46 | asm volatile( | 46 | asm volatile( |
47 | " lhi %0,-1\n" | 47 | " lhi %0,-1\n" |
48 | " sam31\n" | 48 | " sam31\n" |
@@ -51,19 +51,8 @@ diag210(struct diag210 * addr) | |||
51 | " srl %0,28\n" | 51 | " srl %0,28\n" |
52 | "1: sam64\n" | 52 | "1: sam64\n" |
53 | EX_TABLE(0b,1b) | 53 | EX_TABLE(0b,1b) |
54 | : "=&d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory"); | 54 | : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); |
55 | |||
56 | *addr = diag210_tmp; | ||
57 | spin_unlock_irqrestore(&diag210_lock, flags); | ||
58 | |||
59 | return ccode; | ||
60 | } | ||
61 | #else | 55 | #else |
62 | int | ||
63 | diag210(struct diag210 * addr) | ||
64 | { | ||
65 | int ccode; | ||
66 | |||
67 | asm volatile( | 56 | asm volatile( |
68 | " lhi %0,-1\n" | 57 | " lhi %0,-1\n" |
69 | " diag %1,0,0x210\n" | 58 | " diag %1,0,0x210\n" |
@@ -71,11 +60,14 @@ diag210(struct diag210 * addr) | |||
71 | " srl %0,28\n" | 60 | " srl %0,28\n" |
72 | "1:\n" | 61 | "1:\n" |
73 | EX_TABLE(0b,1b) | 62 | EX_TABLE(0b,1b) |
74 | : "=&d" (ccode) : "a" (__pa(addr)) : "cc", "memory"); | 63 | : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); |
64 | #endif | ||
65 | |||
66 | *addr = diag210_tmp; | ||
67 | spin_unlock_irqrestore(&diag210_lock, flags); | ||
75 | 68 | ||
76 | return ccode; | 69 | return ccode; |
77 | } | 70 | } |
78 | #endif | ||
79 | 71 | ||
80 | /* | 72 | /* |
81 | * Input : | 73 | * Input : |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 5aac0ec36368..90bd22014513 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -43,6 +43,7 @@ static void ap_poll_all(unsigned long); | |||
43 | static void ap_poll_timeout(unsigned long); | 43 | static void ap_poll_timeout(unsigned long); |
44 | static int ap_poll_thread_start(void); | 44 | static int ap_poll_thread_start(void); |
45 | static void ap_poll_thread_stop(void); | 45 | static void ap_poll_thread_stop(void); |
46 | static void ap_request_timeout(unsigned long); | ||
46 | 47 | ||
47 | /** | 48 | /** |
48 | * Module description. | 49 | * Module description. |
@@ -189,6 +190,7 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) | |||
189 | case AP_RESPONSE_NORMAL: | 190 | case AP_RESPONSE_NORMAL: |
190 | return 0; | 191 | return 0; |
191 | case AP_RESPONSE_Q_FULL: | 192 | case AP_RESPONSE_Q_FULL: |
193 | case AP_RESPONSE_RESET_IN_PROGRESS: | ||
192 | return -EBUSY; | 194 | return -EBUSY; |
193 | default: /* Device is gone. */ | 195 | default: /* Device is gone. */ |
194 | return -ENODEV; | 196 | return -ENODEV; |
@@ -252,6 +254,8 @@ int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) | |||
252 | if (status.queue_empty) | 254 | if (status.queue_empty) |
253 | return -ENOENT; | 255 | return -ENOENT; |
254 | return -EBUSY; | 256 | return -EBUSY; |
257 | case AP_RESPONSE_RESET_IN_PROGRESS: | ||
258 | return -EBUSY; | ||
255 | default: | 259 | default: |
256 | return -ENODEV; | 260 | return -ENODEV; |
257 | } | 261 | } |
@@ -326,11 +330,12 @@ static int ap_init_queue(ap_qid_t qid) | |||
326 | i = AP_MAX_RESET; /* return with -ENODEV */ | 330 | i = AP_MAX_RESET; /* return with -ENODEV */ |
327 | break; | 331 | break; |
328 | case AP_RESPONSE_RESET_IN_PROGRESS: | 332 | case AP_RESPONSE_RESET_IN_PROGRESS: |
333 | rc = -EBUSY; | ||
329 | case AP_RESPONSE_BUSY: | 334 | case AP_RESPONSE_BUSY: |
330 | default: | 335 | default: |
331 | break; | 336 | break; |
332 | } | 337 | } |
333 | if (rc != -ENODEV) | 338 | if (rc != -ENODEV && rc != -EBUSY) |
334 | break; | 339 | break; |
335 | if (i < AP_MAX_RESET - 1) { | 340 | if (i < AP_MAX_RESET - 1) { |
336 | udelay(5); | 341 | udelay(5); |
@@ -341,6 +346,40 @@ static int ap_init_queue(ap_qid_t qid) | |||
341 | } | 346 | } |
342 | 347 | ||
343 | /** | 348 | /** |
349 | * Arm request timeout if a AP device was idle and a new request is submitted. | ||
350 | */ | ||
351 | static void ap_increase_queue_count(struct ap_device *ap_dev) | ||
352 | { | ||
353 | int timeout = ap_dev->drv->request_timeout; | ||
354 | |||
355 | ap_dev->queue_count++; | ||
356 | if (ap_dev->queue_count == 1) { | ||
357 | mod_timer(&ap_dev->timeout, jiffies + timeout); | ||
358 | ap_dev->reset = AP_RESET_ARMED; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | /** | ||
363 | * AP device is still alive, re-schedule request timeout if there are still | ||
364 | * pending requests. | ||
365 | */ | ||
366 | static void ap_decrease_queue_count(struct ap_device *ap_dev) | ||
367 | { | ||
368 | int timeout = ap_dev->drv->request_timeout; | ||
369 | |||
370 | ap_dev->queue_count--; | ||
371 | if (ap_dev->queue_count > 0) | ||
372 | mod_timer(&ap_dev->timeout, jiffies + timeout); | ||
373 | else | ||
374 | /** | ||
375 | * The timeout timer should to be disabled now - since | ||
376 | * del_timer_sync() is very expensive, we just tell via the | ||
377 | * reset flag to ignore the pending timeout timer. | ||
378 | */ | ||
379 | ap_dev->reset = AP_RESET_IGNORE; | ||
380 | } | ||
381 | |||
382 | /** | ||
344 | * AP device related attributes. | 383 | * AP device related attributes. |
345 | */ | 384 | */ |
346 | static ssize_t ap_hwtype_show(struct device *dev, | 385 | static ssize_t ap_hwtype_show(struct device *dev, |
@@ -498,6 +537,7 @@ static int ap_device_remove(struct device *dev) | |||
498 | struct ap_driver *ap_drv = ap_dev->drv; | 537 | struct ap_driver *ap_drv = ap_dev->drv; |
499 | 538 | ||
500 | ap_flush_queue(ap_dev); | 539 | ap_flush_queue(ap_dev); |
540 | del_timer_sync(&ap_dev->timeout); | ||
501 | if (ap_drv->remove) | 541 | if (ap_drv->remove) |
502 | ap_drv->remove(ap_dev); | 542 | ap_drv->remove(ap_dev); |
503 | spin_lock_bh(&ap_device_lock); | 543 | spin_lock_bh(&ap_device_lock); |
@@ -759,17 +799,21 @@ static void ap_scan_bus(struct work_struct *unused) | |||
759 | __ap_scan_bus); | 799 | __ap_scan_bus); |
760 | rc = ap_query_queue(qid, &queue_depth, &device_type); | 800 | rc = ap_query_queue(qid, &queue_depth, &device_type); |
761 | if (dev) { | 801 | if (dev) { |
802 | if (rc == -EBUSY) { | ||
803 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
804 | schedule_timeout(AP_RESET_TIMEOUT); | ||
805 | rc = ap_query_queue(qid, &queue_depth, | ||
806 | &device_type); | ||
807 | } | ||
762 | ap_dev = to_ap_dev(dev); | 808 | ap_dev = to_ap_dev(dev); |
763 | spin_lock_bh(&ap_dev->lock); | 809 | spin_lock_bh(&ap_dev->lock); |
764 | if (rc || ap_dev->unregistered) { | 810 | if (rc || ap_dev->unregistered) { |
765 | spin_unlock_bh(&ap_dev->lock); | 811 | spin_unlock_bh(&ap_dev->lock); |
766 | put_device(dev); | ||
767 | device_unregister(dev); | 812 | device_unregister(dev); |
813 | put_device(dev); | ||
768 | continue; | 814 | continue; |
769 | } else | 815 | } |
770 | spin_unlock_bh(&ap_dev->lock); | 816 | spin_unlock_bh(&ap_dev->lock); |
771 | } | ||
772 | if (dev) { | ||
773 | put_device(dev); | 817 | put_device(dev); |
774 | continue; | 818 | continue; |
775 | } | 819 | } |
@@ -788,6 +832,8 @@ static void ap_scan_bus(struct work_struct *unused) | |||
788 | INIT_LIST_HEAD(&ap_dev->pendingq); | 832 | INIT_LIST_HEAD(&ap_dev->pendingq); |
789 | INIT_LIST_HEAD(&ap_dev->requestq); | 833 | INIT_LIST_HEAD(&ap_dev->requestq); |
790 | INIT_LIST_HEAD(&ap_dev->list); | 834 | INIT_LIST_HEAD(&ap_dev->list); |
835 | setup_timer(&ap_dev->timeout, ap_request_timeout, | ||
836 | (unsigned long) ap_dev); | ||
791 | if (device_type == 0) | 837 | if (device_type == 0) |
792 | ap_probe_device_type(ap_dev); | 838 | ap_probe_device_type(ap_dev); |
793 | else | 839 | else |
@@ -853,7 +899,7 @@ static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) | |||
853 | switch (status.response_code) { | 899 | switch (status.response_code) { |
854 | case AP_RESPONSE_NORMAL: | 900 | case AP_RESPONSE_NORMAL: |
855 | atomic_dec(&ap_poll_requests); | 901 | atomic_dec(&ap_poll_requests); |
856 | ap_dev->queue_count--; | 902 | ap_decrease_queue_count(ap_dev); |
857 | list_for_each_entry(ap_msg, &ap_dev->pendingq, list) { | 903 | list_for_each_entry(ap_msg, &ap_dev->pendingq, list) { |
858 | if (ap_msg->psmid != ap_dev->reply->psmid) | 904 | if (ap_msg->psmid != ap_dev->reply->psmid) |
859 | continue; | 905 | continue; |
@@ -904,7 +950,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) | |||
904 | switch (status.response_code) { | 950 | switch (status.response_code) { |
905 | case AP_RESPONSE_NORMAL: | 951 | case AP_RESPONSE_NORMAL: |
906 | atomic_inc(&ap_poll_requests); | 952 | atomic_inc(&ap_poll_requests); |
907 | ap_dev->queue_count++; | 953 | ap_increase_queue_count(ap_dev); |
908 | list_move_tail(&ap_msg->list, &ap_dev->pendingq); | 954 | list_move_tail(&ap_msg->list, &ap_dev->pendingq); |
909 | ap_dev->requestq_count--; | 955 | ap_dev->requestq_count--; |
910 | ap_dev->pendingq_count++; | 956 | ap_dev->pendingq_count++; |
@@ -914,6 +960,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) | |||
914 | *flags |= 2; | 960 | *flags |= 2; |
915 | break; | 961 | break; |
916 | case AP_RESPONSE_Q_FULL: | 962 | case AP_RESPONSE_Q_FULL: |
963 | case AP_RESPONSE_RESET_IN_PROGRESS: | ||
917 | *flags |= 2; | 964 | *flags |= 2; |
918 | break; | 965 | break; |
919 | case AP_RESPONSE_MESSAGE_TOO_BIG: | 966 | case AP_RESPONSE_MESSAGE_TOO_BIG: |
@@ -960,10 +1007,11 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms | |||
960 | list_add_tail(&ap_msg->list, &ap_dev->pendingq); | 1007 | list_add_tail(&ap_msg->list, &ap_dev->pendingq); |
961 | atomic_inc(&ap_poll_requests); | 1008 | atomic_inc(&ap_poll_requests); |
962 | ap_dev->pendingq_count++; | 1009 | ap_dev->pendingq_count++; |
963 | ap_dev->queue_count++; | 1010 | ap_increase_queue_count(ap_dev); |
964 | ap_dev->total_request_count++; | 1011 | ap_dev->total_request_count++; |
965 | break; | 1012 | break; |
966 | case AP_RESPONSE_Q_FULL: | 1013 | case AP_RESPONSE_Q_FULL: |
1014 | case AP_RESPONSE_RESET_IN_PROGRESS: | ||
967 | list_add_tail(&ap_msg->list, &ap_dev->requestq); | 1015 | list_add_tail(&ap_msg->list, &ap_dev->requestq); |
968 | ap_dev->requestq_count++; | 1016 | ap_dev->requestq_count++; |
969 | ap_dev->total_request_count++; | 1017 | ap_dev->total_request_count++; |
@@ -1046,6 +1094,25 @@ static void ap_poll_timeout(unsigned long unused) | |||
1046 | } | 1094 | } |
1047 | 1095 | ||
1048 | /** | 1096 | /** |
1097 | * Reset a not responding AP device and move all requests from the | ||
1098 | * pending queue to the request queue. | ||
1099 | */ | ||
1100 | static void ap_reset(struct ap_device *ap_dev) | ||
1101 | { | ||
1102 | int rc; | ||
1103 | |||
1104 | ap_dev->reset = AP_RESET_IGNORE; | ||
1105 | atomic_sub(ap_dev->queue_count, &ap_poll_requests); | ||
1106 | ap_dev->queue_count = 0; | ||
1107 | list_splice_init(&ap_dev->pendingq, &ap_dev->requestq); | ||
1108 | ap_dev->requestq_count += ap_dev->pendingq_count; | ||
1109 | ap_dev->pendingq_count = 0; | ||
1110 | rc = ap_init_queue(ap_dev->qid); | ||
1111 | if (rc == -ENODEV) | ||
1112 | ap_dev->unregistered = 1; | ||
1113 | } | ||
1114 | |||
1115 | /** | ||
1049 | * Poll all AP devices on the bus in a round robin fashion. Continue | 1116 | * Poll all AP devices on the bus in a round robin fashion. Continue |
1050 | * polling until bit 2^0 of the control flags is not set. If bit 2^1 | 1117 | * polling until bit 2^0 of the control flags is not set. If bit 2^1 |
1051 | * of the control flags has been set arm the poll timer. | 1118 | * of the control flags has been set arm the poll timer. |
@@ -1056,6 +1123,8 @@ static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags) | |||
1056 | if (!ap_dev->unregistered) { | 1123 | if (!ap_dev->unregistered) { |
1057 | if (ap_poll_queue(ap_dev, flags)) | 1124 | if (ap_poll_queue(ap_dev, flags)) |
1058 | ap_dev->unregistered = 1; | 1125 | ap_dev->unregistered = 1; |
1126 | if (ap_dev->reset == AP_RESET_DO) | ||
1127 | ap_reset(ap_dev); | ||
1059 | } | 1128 | } |
1060 | spin_unlock(&ap_dev->lock); | 1129 | spin_unlock(&ap_dev->lock); |
1061 | return 0; | 1130 | return 0; |
@@ -1147,6 +1216,17 @@ static void ap_poll_thread_stop(void) | |||
1147 | mutex_unlock(&ap_poll_thread_mutex); | 1216 | mutex_unlock(&ap_poll_thread_mutex); |
1148 | } | 1217 | } |
1149 | 1218 | ||
1219 | /** | ||
1220 | * Handling of request timeouts | ||
1221 | */ | ||
1222 | static void ap_request_timeout(unsigned long data) | ||
1223 | { | ||
1224 | struct ap_device *ap_dev = (struct ap_device *) data; | ||
1225 | |||
1226 | if (ap_dev->reset == AP_RESET_ARMED) | ||
1227 | ap_dev->reset = AP_RESET_DO; | ||
1228 | } | ||
1229 | |||
1150 | static void ap_reset_domain(void) | 1230 | static void ap_reset_domain(void) |
1151 | { | 1231 | { |
1152 | int i; | 1232 | int i; |
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 008559ea742b..87c2d6442875 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #define AP_DEVICES 64 /* Number of AP devices. */ | 33 | #define AP_DEVICES 64 /* Number of AP devices. */ |
34 | #define AP_DOMAINS 16 /* Number of AP domains. */ | 34 | #define AP_DOMAINS 16 /* Number of AP domains. */ |
35 | #define AP_MAX_RESET 90 /* Maximum number of resets. */ | 35 | #define AP_MAX_RESET 90 /* Maximum number of resets. */ |
36 | #define AP_RESET_TIMEOUT (HZ/2) /* Time in ticks for reset timeouts. */ | ||
36 | #define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */ | 37 | #define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */ |
37 | #define AP_POLL_TIME 1 /* Time in ticks between receive polls. */ | 38 | #define AP_POLL_TIME 1 /* Time in ticks between receive polls. */ |
38 | 39 | ||
@@ -83,6 +84,13 @@ struct ap_queue_status { | |||
83 | #define AP_DEVICE_TYPE_CEX2A 6 | 84 | #define AP_DEVICE_TYPE_CEX2A 6 |
84 | #define AP_DEVICE_TYPE_CEX2C 7 | 85 | #define AP_DEVICE_TYPE_CEX2C 7 |
85 | 86 | ||
87 | /** | ||
88 | * AP reset flag states | ||
89 | */ | ||
90 | #define AP_RESET_IGNORE 0 /* request timeout will be ignored */ | ||
91 | #define AP_RESET_ARMED 1 /* request timeout timer is active */ | ||
92 | #define AP_RESET_DO 2 /* AP reset required */ | ||
93 | |||
86 | struct ap_device; | 94 | struct ap_device; |
87 | struct ap_message; | 95 | struct ap_message; |
88 | 96 | ||
@@ -95,6 +103,7 @@ struct ap_driver { | |||
95 | /* receive is called from tasklet context */ | 103 | /* receive is called from tasklet context */ |
96 | void (*receive)(struct ap_device *, struct ap_message *, | 104 | void (*receive)(struct ap_device *, struct ap_message *, |
97 | struct ap_message *); | 105 | struct ap_message *); |
106 | int request_timeout; /* request timeout in jiffies */ | ||
98 | }; | 107 | }; |
99 | 108 | ||
100 | #define to_ap_drv(x) container_of((x), struct ap_driver, driver) | 109 | #define to_ap_drv(x) container_of((x), struct ap_driver, driver) |
@@ -112,6 +121,8 @@ struct ap_device { | |||
112 | int queue_depth; /* AP queue depth.*/ | 121 | int queue_depth; /* AP queue depth.*/ |
113 | int device_type; /* AP device type. */ | 122 | int device_type; /* AP device type. */ |
114 | int unregistered; /* marks AP device as unregistered */ | 123 | int unregistered; /* marks AP device as unregistered */ |
124 | struct timer_list timeout; /* Timer for request timeouts. */ | ||
125 | int reset; /* Reset required after req. timeout. */ | ||
115 | 126 | ||
116 | int queue_count; /* # messages currently on AP queue. */ | 127 | int queue_count; /* # messages currently on AP queue. */ |
117 | 128 | ||
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 5bb13a9d0898..08657f604b8c 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c | |||
@@ -70,6 +70,7 @@ static struct ap_driver zcrypt_cex2a_driver = { | |||
70 | .remove = zcrypt_cex2a_remove, | 70 | .remove = zcrypt_cex2a_remove, |
71 | .receive = zcrypt_cex2a_receive, | 71 | .receive = zcrypt_cex2a_receive, |
72 | .ids = zcrypt_cex2a_ids, | 72 | .ids = zcrypt_cex2a_ids, |
73 | .request_timeout = CEX2A_CLEANUP_TIME, | ||
73 | }; | 74 | }; |
74 | 75 | ||
75 | /** | 76 | /** |
@@ -306,18 +307,13 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, | |||
306 | goto out_free; | 307 | goto out_free; |
307 | init_completion(&work); | 308 | init_completion(&work); |
308 | ap_queue_message(zdev->ap_dev, &ap_msg); | 309 | ap_queue_message(zdev->ap_dev, &ap_msg); |
309 | rc = wait_for_completion_interruptible_timeout( | 310 | rc = wait_for_completion_interruptible(&work); |
310 | &work, CEX2A_CLEANUP_TIME); | 311 | if (rc == 0) |
311 | if (rc > 0) | ||
312 | rc = convert_response(zdev, &ap_msg, mex->outputdata, | 312 | rc = convert_response(zdev, &ap_msg, mex->outputdata, |
313 | mex->outputdatalength); | 313 | mex->outputdatalength); |
314 | else { | 314 | else |
315 | /* Signal pending or message timed out. */ | 315 | /* Signal pending. */ |
316 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 316 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
317 | if (rc == 0) | ||
318 | /* Message timed out. */ | ||
319 | rc = -ETIME; | ||
320 | } | ||
321 | out_free: | 317 | out_free: |
322 | kfree(ap_msg.message); | 318 | kfree(ap_msg.message); |
323 | return rc; | 319 | return rc; |
@@ -348,18 +344,13 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, | |||
348 | goto out_free; | 344 | goto out_free; |
349 | init_completion(&work); | 345 | init_completion(&work); |
350 | ap_queue_message(zdev->ap_dev, &ap_msg); | 346 | ap_queue_message(zdev->ap_dev, &ap_msg); |
351 | rc = wait_for_completion_interruptible_timeout( | 347 | rc = wait_for_completion_interruptible(&work); |
352 | &work, CEX2A_CLEANUP_TIME); | 348 | if (rc == 0) |
353 | if (rc > 0) | ||
354 | rc = convert_response(zdev, &ap_msg, crt->outputdata, | 349 | rc = convert_response(zdev, &ap_msg, crt->outputdata, |
355 | crt->outputdatalength); | 350 | crt->outputdatalength); |
356 | else { | 351 | else |
357 | /* Signal pending or message timed out. */ | 352 | /* Signal pending. */ |
358 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 353 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
359 | if (rc == 0) | ||
360 | /* Message timed out. */ | ||
361 | rc = -ETIME; | ||
362 | } | ||
363 | out_free: | 354 | out_free: |
364 | kfree(ap_msg.message); | 355 | kfree(ap_msg.message); |
365 | return rc; | 356 | return rc; |
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 818ffe05ac00..6e93b4751782 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c | |||
@@ -70,6 +70,7 @@ static struct ap_driver zcrypt_pcica_driver = { | |||
70 | .remove = zcrypt_pcica_remove, | 70 | .remove = zcrypt_pcica_remove, |
71 | .receive = zcrypt_pcica_receive, | 71 | .receive = zcrypt_pcica_receive, |
72 | .ids = zcrypt_pcica_ids, | 72 | .ids = zcrypt_pcica_ids, |
73 | .request_timeout = PCICA_CLEANUP_TIME, | ||
73 | }; | 74 | }; |
74 | 75 | ||
75 | /** | 76 | /** |
@@ -290,18 +291,13 @@ static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev, | |||
290 | goto out_free; | 291 | goto out_free; |
291 | init_completion(&work); | 292 | init_completion(&work); |
292 | ap_queue_message(zdev->ap_dev, &ap_msg); | 293 | ap_queue_message(zdev->ap_dev, &ap_msg); |
293 | rc = wait_for_completion_interruptible_timeout( | 294 | rc = wait_for_completion_interruptible(&work); |
294 | &work, PCICA_CLEANUP_TIME); | 295 | if (rc == 0) |
295 | if (rc > 0) | ||
296 | rc = convert_response(zdev, &ap_msg, mex->outputdata, | 296 | rc = convert_response(zdev, &ap_msg, mex->outputdata, |
297 | mex->outputdatalength); | 297 | mex->outputdatalength); |
298 | else { | 298 | else |
299 | /* Signal pending or message timed out. */ | 299 | /* Signal pending. */ |
300 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 300 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
301 | if (rc == 0) | ||
302 | /* Message timed out. */ | ||
303 | rc = -ETIME; | ||
304 | } | ||
305 | out_free: | 301 | out_free: |
306 | kfree(ap_msg.message); | 302 | kfree(ap_msg.message); |
307 | return rc; | 303 | return rc; |
@@ -332,18 +328,13 @@ static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev, | |||
332 | goto out_free; | 328 | goto out_free; |
333 | init_completion(&work); | 329 | init_completion(&work); |
334 | ap_queue_message(zdev->ap_dev, &ap_msg); | 330 | ap_queue_message(zdev->ap_dev, &ap_msg); |
335 | rc = wait_for_completion_interruptible_timeout( | 331 | rc = wait_for_completion_interruptible(&work); |
336 | &work, PCICA_CLEANUP_TIME); | 332 | if (rc == 0) |
337 | if (rc > 0) | ||
338 | rc = convert_response(zdev, &ap_msg, crt->outputdata, | 333 | rc = convert_response(zdev, &ap_msg, crt->outputdata, |
339 | crt->outputdatalength); | 334 | crt->outputdatalength); |
340 | else { | 335 | else |
341 | /* Signal pending or message timed out. */ | 336 | /* Signal pending. */ |
342 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 337 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
343 | if (rc == 0) | ||
344 | /* Message timed out. */ | ||
345 | rc = -ETIME; | ||
346 | } | ||
347 | out_free: | 338 | out_free: |
348 | kfree(ap_msg.message); | 339 | kfree(ap_msg.message); |
349 | return rc; | 340 | return rc; |
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c index f295a403b29a..d6d59bf9ac38 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.c +++ b/drivers/s390/crypto/zcrypt_pcicc.c | |||
@@ -82,6 +82,7 @@ static struct ap_driver zcrypt_pcicc_driver = { | |||
82 | .remove = zcrypt_pcicc_remove, | 82 | .remove = zcrypt_pcicc_remove, |
83 | .receive = zcrypt_pcicc_receive, | 83 | .receive = zcrypt_pcicc_receive, |
84 | .ids = zcrypt_pcicc_ids, | 84 | .ids = zcrypt_pcicc_ids, |
85 | .request_timeout = PCICC_CLEANUP_TIME, | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | /** | 88 | /** |
@@ -501,18 +502,13 @@ static long zcrypt_pcicc_modexpo(struct zcrypt_device *zdev, | |||
501 | goto out_free; | 502 | goto out_free; |
502 | init_completion(&work); | 503 | init_completion(&work); |
503 | ap_queue_message(zdev->ap_dev, &ap_msg); | 504 | ap_queue_message(zdev->ap_dev, &ap_msg); |
504 | rc = wait_for_completion_interruptible_timeout( | 505 | rc = wait_for_completion_interruptible(&work); |
505 | &work, PCICC_CLEANUP_TIME); | 506 | if (rc == 0) |
506 | if (rc > 0) | ||
507 | rc = convert_response(zdev, &ap_msg, mex->outputdata, | 507 | rc = convert_response(zdev, &ap_msg, mex->outputdata, |
508 | mex->outputdatalength); | 508 | mex->outputdatalength); |
509 | else { | 509 | else |
510 | /* Signal pending or message timed out. */ | 510 | /* Signal pending. */ |
511 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 511 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
512 | if (rc == 0) | ||
513 | /* Message timed out. */ | ||
514 | rc = -ETIME; | ||
515 | } | ||
516 | out_free: | 512 | out_free: |
517 | free_page((unsigned long) ap_msg.message); | 513 | free_page((unsigned long) ap_msg.message); |
518 | return rc; | 514 | return rc; |
@@ -544,18 +540,13 @@ static long zcrypt_pcicc_modexpo_crt(struct zcrypt_device *zdev, | |||
544 | goto out_free; | 540 | goto out_free; |
545 | init_completion(&work); | 541 | init_completion(&work); |
546 | ap_queue_message(zdev->ap_dev, &ap_msg); | 542 | ap_queue_message(zdev->ap_dev, &ap_msg); |
547 | rc = wait_for_completion_interruptible_timeout( | 543 | rc = wait_for_completion_interruptible(&work); |
548 | &work, PCICC_CLEANUP_TIME); | 544 | if (rc == 0) |
549 | if (rc > 0) | ||
550 | rc = convert_response(zdev, &ap_msg, crt->outputdata, | 545 | rc = convert_response(zdev, &ap_msg, crt->outputdata, |
551 | crt->outputdatalength); | 546 | crt->outputdatalength); |
552 | else { | 547 | else |
553 | /* Signal pending or message timed out. */ | 548 | /* Signal pending. */ |
554 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 549 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
555 | if (rc == 0) | ||
556 | /* Message timed out. */ | ||
557 | rc = -ETIME; | ||
558 | } | ||
559 | out_free: | 550 | out_free: |
560 | free_page((unsigned long) ap_msg.message); | 551 | free_page((unsigned long) ap_msg.message); |
561 | return rc; | 552 | return rc; |
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 252443b6bd1b..64948788d301 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c | |||
@@ -93,6 +93,7 @@ static struct ap_driver zcrypt_pcixcc_driver = { | |||
93 | .remove = zcrypt_pcixcc_remove, | 93 | .remove = zcrypt_pcixcc_remove, |
94 | .receive = zcrypt_pcixcc_receive, | 94 | .receive = zcrypt_pcixcc_receive, |
95 | .ids = zcrypt_pcixcc_ids, | 95 | .ids = zcrypt_pcixcc_ids, |
96 | .request_timeout = PCIXCC_CLEANUP_TIME, | ||
96 | }; | 97 | }; |
97 | 98 | ||
98 | /** | 99 | /** |
@@ -641,18 +642,13 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev, | |||
641 | goto out_free; | 642 | goto out_free; |
642 | init_completion(&resp_type.work); | 643 | init_completion(&resp_type.work); |
643 | ap_queue_message(zdev->ap_dev, &ap_msg); | 644 | ap_queue_message(zdev->ap_dev, &ap_msg); |
644 | rc = wait_for_completion_interruptible_timeout( | 645 | rc = wait_for_completion_interruptible(&resp_type.work); |
645 | &resp_type.work, PCIXCC_CLEANUP_TIME); | 646 | if (rc == 0) |
646 | if (rc > 0) | ||
647 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, | 647 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, |
648 | mex->outputdatalength); | 648 | mex->outputdatalength); |
649 | else { | 649 | else |
650 | /* Signal pending or message timed out. */ | 650 | /* Signal pending. */ |
651 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 651 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
652 | if (rc == 0) | ||
653 | /* Message timed out. */ | ||
654 | rc = -ETIME; | ||
655 | } | ||
656 | out_free: | 652 | out_free: |
657 | free_page((unsigned long) ap_msg.message); | 653 | free_page((unsigned long) ap_msg.message); |
658 | return rc; | 654 | return rc; |
@@ -685,18 +681,13 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev, | |||
685 | goto out_free; | 681 | goto out_free; |
686 | init_completion(&resp_type.work); | 682 | init_completion(&resp_type.work); |
687 | ap_queue_message(zdev->ap_dev, &ap_msg); | 683 | ap_queue_message(zdev->ap_dev, &ap_msg); |
688 | rc = wait_for_completion_interruptible_timeout( | 684 | rc = wait_for_completion_interruptible(&resp_type.work); |
689 | &resp_type.work, PCIXCC_CLEANUP_TIME); | 685 | if (rc == 0) |
690 | if (rc > 0) | ||
691 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, | 686 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, |
692 | crt->outputdatalength); | 687 | crt->outputdatalength); |
693 | else { | 688 | else |
694 | /* Signal pending or message timed out. */ | 689 | /* Signal pending. */ |
695 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 690 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
696 | if (rc == 0) | ||
697 | /* Message timed out. */ | ||
698 | rc = -ETIME; | ||
699 | } | ||
700 | out_free: | 691 | out_free: |
701 | free_page((unsigned long) ap_msg.message); | 692 | free_page((unsigned long) ap_msg.message); |
702 | return rc; | 693 | return rc; |
@@ -729,17 +720,12 @@ static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, | |||
729 | goto out_free; | 720 | goto out_free; |
730 | init_completion(&resp_type.work); | 721 | init_completion(&resp_type.work); |
731 | ap_queue_message(zdev->ap_dev, &ap_msg); | 722 | ap_queue_message(zdev->ap_dev, &ap_msg); |
732 | rc = wait_for_completion_interruptible_timeout( | 723 | rc = wait_for_completion_interruptible(&resp_type.work); |
733 | &resp_type.work, PCIXCC_CLEANUP_TIME); | 724 | if (rc == 0) |
734 | if (rc > 0) | ||
735 | rc = convert_response_xcrb(zdev, &ap_msg, xcRB); | 725 | rc = convert_response_xcrb(zdev, &ap_msg, xcRB); |
736 | else { | 726 | else |
737 | /* Signal pending or message timed out. */ | 727 | /* Signal pending. */ |
738 | ap_cancel_message(zdev->ap_dev, &ap_msg); | 728 | ap_cancel_message(zdev->ap_dev, &ap_msg); |
739 | if (rc == 0) | ||
740 | /* Message timed out. */ | ||
741 | rc = -ETIME; | ||
742 | } | ||
743 | out_free: | 729 | out_free: |
744 | memset(ap_msg.message, 0x0, ap_msg.length); | 730 | memset(ap_msg.message, 0x0, ap_msg.length); |
745 | kfree(ap_msg.message); | 731 | kfree(ap_msg.message); |
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 61de78a9f6ee..4fff61b32dcb 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c | |||
@@ -143,7 +143,7 @@ static struct console sercons; | |||
143 | static unsigned long break_pressed; /* break, really ... */ | 143 | static unsigned long break_pressed; /* break, really ... */ |
144 | #endif | 144 | #endif |
145 | 145 | ||
146 | static unsigned char zs_init_regs[16] __initdata = { | 146 | static unsigned char zs_init_regs[16] = { |
147 | 0, /* write 0 */ | 147 | 0, /* write 0 */ |
148 | 0, /* write 1 */ | 148 | 0, /* write 1 */ |
149 | 0, /* write 2 */ | 149 | 0, /* write 2 */ |
@@ -1581,7 +1581,7 @@ static void __init show_serial_version(void) | |||
1581 | /* Initialize Z8530s zs_channels | 1581 | /* Initialize Z8530s zs_channels |
1582 | */ | 1582 | */ |
1583 | 1583 | ||
1584 | static void __init probe_sccs(void) | 1584 | static void probe_sccs(void) |
1585 | { | 1585 | { |
1586 | struct dec_serial **pp; | 1586 | struct dec_serial **pp; |
1587 | int i, n, n_chips = 0, n_channels, chip, channel; | 1587 | int i, n, n_chips = 0, n_channels, chip, channel; |
@@ -1923,7 +1923,7 @@ static struct tty_driver *serial_console_device(struct console *c, int *index) | |||
1923 | * - initialize the serial port | 1923 | * - initialize the serial port |
1924 | * Return non-zero if we didn't find a serial port. | 1924 | * Return non-zero if we didn't find a serial port. |
1925 | */ | 1925 | */ |
1926 | static int __init serial_console_setup(struct console *co, char *options) | 1926 | static int serial_console_setup(struct console *co, char *options) |
1927 | { | 1927 | { |
1928 | struct dec_serial *info; | 1928 | struct dec_serial *info; |
1929 | int baud = 9600; | 1929 | int baud = 9600; |
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 904e5aeb696c..df95d6c2cefa 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
@@ -35,4 +35,17 @@ config W1_SLAVE_DS2433_CRC | |||
35 | Each block has 30 bytes of data and a two byte CRC16. | 35 | Each block has 30 bytes of data and a two byte CRC16. |
36 | Full block writes are only allowed if the CRC is valid. | 36 | Full block writes are only allowed if the CRC is valid. |
37 | 37 | ||
38 | config W1_SLAVE_DS2760 | ||
39 | tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" | ||
40 | depends on W1 | ||
41 | help | ||
42 | If you enable this you will have the DS2760 battery monitor | ||
43 | chip support. | ||
44 | |||
45 | The battery monitor chip is used in many batteries/devices | ||
46 | as the one who is responsible for charging/discharging/monitoring | ||
47 | Li+ batteries. | ||
48 | |||
49 | If you are unsure, say N. | ||
50 | |||
38 | endmenu | 51 | endmenu |
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index 725dcfdfddb4..a8eb7524df1d 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile | |||
@@ -5,4 +5,5 @@ | |||
5 | obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o | 5 | obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o |
6 | obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o | 6 | obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o |
7 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o | 7 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o |
8 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o | ||
8 | 9 | ||
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c new file mode 100644 index 000000000000..88a37fbccc3f --- /dev/null +++ b/drivers/w1/slaves/w1_ds2760.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2760 chip | ||
3 | * | ||
4 | * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> | ||
5 | * | ||
6 | * Use consistent with the GNU GPL is permitted, | ||
7 | * provided that this copyright notice is | ||
8 | * preserved in its entirety in all copies and derived works. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/idr.h> | ||
19 | |||
20 | #include "../w1.h" | ||
21 | #include "../w1_int.h" | ||
22 | #include "../w1_family.h" | ||
23 | #include "w1_ds2760.h" | ||
24 | |||
25 | static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count, | ||
26 | int io) | ||
27 | { | ||
28 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
29 | |||
30 | if (!dev) | ||
31 | return 0; | ||
32 | |||
33 | mutex_lock(&sl->master->mutex); | ||
34 | |||
35 | if (addr > DS2760_DATA_SIZE || addr < 0) { | ||
36 | count = 0; | ||
37 | goto out; | ||
38 | } | ||
39 | if (addr + count > DS2760_DATA_SIZE) | ||
40 | count = DS2760_DATA_SIZE - addr; | ||
41 | |||
42 | if (!w1_reset_select_slave(sl)) { | ||
43 | if (!io) { | ||
44 | w1_write_8(sl->master, W1_DS2760_READ_DATA); | ||
45 | w1_write_8(sl->master, addr); | ||
46 | count = w1_read_block(sl->master, buf, count); | ||
47 | } else { | ||
48 | w1_write_8(sl->master, W1_DS2760_WRITE_DATA); | ||
49 | w1_write_8(sl->master, addr); | ||
50 | w1_write_block(sl->master, buf, count); | ||
51 | /* XXX w1_write_block returns void, not n_written */ | ||
52 | } | ||
53 | } | ||
54 | |||
55 | out: | ||
56 | mutex_unlock(&sl->master->mutex); | ||
57 | |||
58 | return count; | ||
59 | } | ||
60 | |||
61 | int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count) | ||
62 | { | ||
63 | return w1_ds2760_io(dev, buf, addr, count, 0); | ||
64 | } | ||
65 | |||
66 | int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count) | ||
67 | { | ||
68 | return w1_ds2760_io(dev, buf, addr, count, 1); | ||
69 | } | ||
70 | |||
71 | static ssize_t w1_ds2760_read_bin(struct kobject *kobj, char *buf, loff_t off, | ||
72 | size_t count) | ||
73 | { | ||
74 | struct device *dev = container_of(kobj, struct device, kobj); | ||
75 | return w1_ds2760_read(dev, buf, off, count); | ||
76 | } | ||
77 | |||
78 | static struct bin_attribute w1_ds2760_bin_attr = { | ||
79 | .attr = { | ||
80 | .name = "w1_slave", | ||
81 | .mode = S_IRUGO, | ||
82 | .owner = THIS_MODULE, | ||
83 | }, | ||
84 | .size = DS2760_DATA_SIZE, | ||
85 | .read = w1_ds2760_read_bin, | ||
86 | }; | ||
87 | |||
88 | static DEFINE_IDR(bat_idr); | ||
89 | static DEFINE_MUTEX(bat_idr_lock); | ||
90 | |||
91 | static int new_bat_id(void) | ||
92 | { | ||
93 | int ret; | ||
94 | |||
95 | while (1) { | ||
96 | int id; | ||
97 | |||
98 | ret = idr_pre_get(&bat_idr, GFP_KERNEL); | ||
99 | if (ret == 0) | ||
100 | return -ENOMEM; | ||
101 | |||
102 | mutex_lock(&bat_idr_lock); | ||
103 | ret = idr_get_new(&bat_idr, NULL, &id); | ||
104 | mutex_unlock(&bat_idr_lock); | ||
105 | |||
106 | if (ret == 0) { | ||
107 | ret = id & MAX_ID_MASK; | ||
108 | break; | ||
109 | } else if (ret == -EAGAIN) { | ||
110 | continue; | ||
111 | } else { | ||
112 | break; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static void release_bat_id(int id) | ||
120 | { | ||
121 | mutex_lock(&bat_idr_lock); | ||
122 | idr_remove(&bat_idr, id); | ||
123 | mutex_unlock(&bat_idr_lock); | ||
124 | |||
125 | return; | ||
126 | } | ||
127 | |||
128 | static int w1_ds2760_add_slave(struct w1_slave *sl) | ||
129 | { | ||
130 | int ret; | ||
131 | int id; | ||
132 | struct platform_device *pdev; | ||
133 | |||
134 | id = new_bat_id(); | ||
135 | if (id < 0) { | ||
136 | ret = id; | ||
137 | goto noid; | ||
138 | } | ||
139 | |||
140 | pdev = platform_device_alloc("ds2760-battery", id); | ||
141 | if (!pdev) { | ||
142 | ret = -ENOMEM; | ||
143 | goto pdev_alloc_failed; | ||
144 | } | ||
145 | pdev->dev.parent = &sl->dev; | ||
146 | |||
147 | ret = platform_device_add(pdev); | ||
148 | if (ret) | ||
149 | goto pdev_add_failed; | ||
150 | |||
151 | ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr); | ||
152 | if (ret) | ||
153 | goto bin_attr_failed; | ||
154 | |||
155 | dev_set_drvdata(&sl->dev, pdev); | ||
156 | |||
157 | goto success; | ||
158 | |||
159 | bin_attr_failed: | ||
160 | pdev_add_failed: | ||
161 | platform_device_unregister(pdev); | ||
162 | pdev_alloc_failed: | ||
163 | release_bat_id(id); | ||
164 | noid: | ||
165 | success: | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | static void w1_ds2760_remove_slave(struct w1_slave *sl) | ||
170 | { | ||
171 | struct platform_device *pdev = dev_get_drvdata(&sl->dev); | ||
172 | int id = pdev->id; | ||
173 | |||
174 | platform_device_unregister(pdev); | ||
175 | release_bat_id(id); | ||
176 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr); | ||
177 | |||
178 | return; | ||
179 | } | ||
180 | |||
181 | static struct w1_family_ops w1_ds2760_fops = { | ||
182 | .add_slave = w1_ds2760_add_slave, | ||
183 | .remove_slave = w1_ds2760_remove_slave, | ||
184 | }; | ||
185 | |||
186 | static struct w1_family w1_ds2760_family = { | ||
187 | .fid = W1_FAMILY_DS2760, | ||
188 | .fops = &w1_ds2760_fops, | ||
189 | }; | ||
190 | |||
191 | static int __init w1_ds2760_init(void) | ||
192 | { | ||
193 | printk(KERN_INFO "1-Wire driver for the DS2760 battery monitor " | ||
194 | " chip - (c) 2004-2005, Szabolcs Gyurko\n"); | ||
195 | idr_init(&bat_idr); | ||
196 | return w1_register_family(&w1_ds2760_family); | ||
197 | } | ||
198 | |||
199 | static void __exit w1_ds2760_exit(void) | ||
200 | { | ||
201 | w1_unregister_family(&w1_ds2760_family); | ||
202 | idr_destroy(&bat_idr); | ||
203 | } | ||
204 | |||
205 | EXPORT_SYMBOL(w1_ds2760_read); | ||
206 | EXPORT_SYMBOL(w1_ds2760_write); | ||
207 | |||
208 | module_init(w1_ds2760_init); | ||
209 | module_exit(w1_ds2760_exit); | ||
210 | |||
211 | MODULE_LICENSE("GPL"); | ||
212 | MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>"); | ||
213 | MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip"); | ||
diff --git a/drivers/w1/slaves/w1_ds2760.h b/drivers/w1/slaves/w1_ds2760.h new file mode 100644 index 000000000000..f1302429cb02 --- /dev/null +++ b/drivers/w1/slaves/w1_ds2760.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2760 chip | ||
3 | * | ||
4 | * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> | ||
5 | * | ||
6 | * Use consistent with the GNU GPL is permitted, | ||
7 | * provided that this copyright notice is | ||
8 | * preserved in its entirety in all copies and derived works. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef __w1_ds2760_h__ | ||
13 | #define __w1_ds2760_h__ | ||
14 | |||
15 | /* Known commands to the DS2760 chip */ | ||
16 | #define W1_DS2760_SWAP 0xAA | ||
17 | #define W1_DS2760_READ_DATA 0x69 | ||
18 | #define W1_DS2760_WRITE_DATA 0x6C | ||
19 | #define W1_DS2760_COPY_DATA 0x48 | ||
20 | #define W1_DS2760_RECALL_DATA 0xB8 | ||
21 | #define W1_DS2760_LOCK 0x6A | ||
22 | |||
23 | /* Number of valid register addresses */ | ||
24 | #define DS2760_DATA_SIZE 0x40 | ||
25 | |||
26 | #define DS2760_PROTECTION_REG 0x00 | ||
27 | #define DS2760_STATUS_REG 0x01 | ||
28 | #define DS2760_EEPROM_REG 0x07 | ||
29 | #define DS2760_SPECIAL_FEATURE_REG 0x08 | ||
30 | #define DS2760_VOLTAGE_MSB 0x0c | ||
31 | #define DS2760_VOLTAGE_LSB 0x0d | ||
32 | #define DS2760_CURRENT_MSB 0x0e | ||
33 | #define DS2760_CURRENT_LSB 0x0f | ||
34 | #define DS2760_CURRENT_ACCUM_MSB 0x10 | ||
35 | #define DS2760_CURRENT_ACCUM_LSB 0x11 | ||
36 | #define DS2760_TEMP_MSB 0x18 | ||
37 | #define DS2760_TEMP_LSB 0x19 | ||
38 | #define DS2760_EEPROM_BLOCK0 0x20 | ||
39 | #define DS2760_ACTIVE_FULL 0x20 | ||
40 | #define DS2760_EEPROM_BLOCK1 0x30 | ||
41 | #define DS2760_RATED_CAPACITY 0x32 | ||
42 | #define DS2760_CURRENT_OFFSET_BIAS 0x33 | ||
43 | #define DS2760_ACTIVE_EMPTY 0x3b | ||
44 | |||
45 | extern int w1_ds2760_read(struct device *dev, char *buf, int addr, | ||
46 | size_t count); | ||
47 | extern int w1_ds2760_write(struct device *dev, char *buf, int addr, | ||
48 | size_t count); | ||
49 | |||
50 | #endif /* !__w1_ds2760_h__ */ | ||
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 1e2ac40c2c14..ef1e1dafa19a 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #define W1_THERM_DS1822 0x22 | 33 | #define W1_THERM_DS1822 0x22 |
34 | #define W1_EEPROM_DS2433 0x23 | 34 | #define W1_EEPROM_DS2433 0x23 |
35 | #define W1_THERM_DS18B20 0x28 | 35 | #define W1_THERM_DS18B20 0x28 |
36 | #define W1_FAMILY_DS2760 0x30 | ||
36 | 37 | ||
37 | #define MAXNAMELEN 32 | 38 | #define MAXNAMELEN 32 |
38 | 39 | ||