diff --git a/[refs] b/[refs] index 07b6dcde45f3..eb34a949579f 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c142bda458a9c81097238800e1bd8eeeea09913d +refs/heads/master: 12b29f34558b9b45a2c6eabd4f3c6be939a3980f diff --git a/trunk/Documentation/ABI/testing/sysfs-block b/trunk/Documentation/ABI/testing/sysfs-block index 44f52a4f5903..4bd9ea539129 100644 --- a/trunk/Documentation/ABI/testing/sysfs-block +++ b/trunk/Documentation/ABI/testing/sysfs-block @@ -26,37 +26,3 @@ Description: I/O statistics of partition . The format is the same as the above-written /sys/block//stat format. - - -What: /sys/block//integrity/format -Date: June 2008 -Contact: Martin K. Petersen -Description: - Metadata format for integrity capable block device. - E.g. T10-DIF-TYPE1-CRC. - - -What: /sys/block//integrity/read_verify -Date: June 2008 -Contact: Martin K. Petersen -Description: - Indicates whether the block layer should verify the - integrity of read requests serviced by devices that - support sending integrity metadata. - - -What: /sys/block//integrity/tag_size -Date: June 2008 -Contact: Martin K. Petersen -Description: - Number of bytes of integrity tag space available per - 512 bytes of data. - - -What: /sys/block//integrity/write_generate -Date: June 2008 -Contact: Martin K. Petersen -Description: - Indicates whether the block layer should automatically - generate checksums for write requests bound for - devices that support receiving integrity metadata. diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-css b/trunk/Documentation/ABI/testing/sysfs-bus-css deleted file mode 100644 index b585ec258a08..000000000000 --- a/trunk/Documentation/ABI/testing/sysfs-bus-css +++ /dev/null @@ -1,35 +0,0 @@ -What: /sys/bus/css/devices/.../type -Date: March 2008 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the subchannel type, as reported by the hardware. - This attribute is present for all subchannel types. - -What: /sys/bus/css/devices/.../modalias -Date: March 2008 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the module alias as reported with uevents. - It is of the format css:t and present for all - subchannel types. - -What: /sys/bus/css/drivers/io_subchannel/.../chpids -Date: December 2002 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the ids of the channel paths used by this - subchannel, as reported by the channel subsystem - during subchannel recognition. - Note: This is an I/O-subchannel specific attribute. -Users: s390-tools, HAL - -What: /sys/bus/css/drivers/io_subchannel/.../pimpampom -Date: December 2002 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the PIM/PAM/POM values, as reported by the - channel subsystem when last queried by the common I/O - layer (this implies that this attribute is not neccessarily - in sync with the values current in the channel subsystem). - Note: This is an I/O-subchannel specific attribute. -Users: s390-tools, HAL diff --git a/trunk/Documentation/block/data-integrity.txt b/trunk/Documentation/block/data-integrity.txt deleted file mode 100644 index e9dc8d86adc7..000000000000 --- a/trunk/Documentation/block/data-integrity.txt +++ /dev/null @@ -1,327 +0,0 @@ ----------------------------------------------------------------------- -1. INTRODUCTION - -Modern filesystems feature checksumming of data and metadata to -protect against data corruption. However, the detection of the -corruption is done at read time which could potentially be months -after the data was written. At that point the original data that the -application tried to write is most likely lost. - -The solution is to ensure that the disk is actually storing what the -application meant it to. Recent additions to both the SCSI family -protocols (SBC Data Integrity Field, SCC protection proposal) as well -as SATA/T13 (External Path Protection) try to remedy this by adding -support for appending integrity metadata to an I/O. The integrity -metadata (or protection information in SCSI terminology) includes a -checksum for each sector as well as an incrementing counter that -ensures the individual sectors are written in the right order. And -for some protection schemes also that the I/O is written to the right -place on disk. - -Current storage controllers and devices implement various protective -measures, for instance checksumming and scrubbing. But these -technologies are working in their own isolated domains or at best -between adjacent nodes in the I/O path. The interesting thing about -DIF and the other integrity extensions is that the protection format -is well defined and every node in the I/O path can verify the -integrity of the I/O and reject it if corruption is detected. This -allows not only corruption prevention but also isolation of the point -of failure. - ----------------------------------------------------------------------- -2. THE DATA INTEGRITY EXTENSIONS - -As written, the protocol extensions only protect the path between -controller and storage device. However, many controllers actually -allow the operating system to interact with the integrity metadata -(IMD). We have been working with several FC/SAS HBA vendors to enable -the protection information to be transferred to and from their -controllers. - -The SCSI Data Integrity Field works by appending 8 bytes of protection -information to each sector. The data + integrity metadata is stored -in 520 byte sectors on disk. Data + IMD are interleaved when -transferred between the controller and target. The T13 proposal is -similar. - -Because it is highly inconvenient for operating systems to deal with -520 (and 4104) byte sectors, we approached several HBA vendors and -encouraged them to allow separation of the data and integrity metadata -scatter-gather lists. - -The controller will interleave the buffers on write and split them on -read. This means that the Linux can DMA the data buffers to and from -host memory without changes to the page cache. - -Also, the 16-bit CRC checksum mandated by both the SCSI and SATA specs -is somewhat heavy to compute in software. Benchmarks found that -calculating this checksum had a significant impact on system -performance for a number of workloads. Some controllers allow a -lighter-weight checksum to be used when interfacing with the operating -system. Emulex, for instance, supports the TCP/IP checksum instead. -The IP checksum received from the OS is converted to the 16-bit CRC -when writing and vice versa. This allows the integrity metadata to be -generated by Linux or the application at very low cost (comparable to -software RAID5). - -The IP checksum is weaker than the CRC in terms of detecting bit -errors. However, the strength is really in the separation of the data -buffers and the integrity metadata. These two distinct buffers much -match up for an I/O to complete. - -The separation of the data and integrity metadata buffers as well as -the choice in checksums is referred to as the Data Integrity -Extensions. As these extensions are outside the scope of the protocol -bodies (T10, T13), Oracle and its partners are trying to standardize -them within the Storage Networking Industry Association. - ----------------------------------------------------------------------- -3. KERNEL CHANGES - -The data integrity framework in Linux enables protection information -to be pinned to I/Os and sent to/received from controllers that -support it. - -The advantage to the integrity extensions in SCSI and SATA is that -they enable us to protect the entire path from application to storage -device. However, at the same time this is also the biggest -disadvantage. It means that the protection information must be in a -format that can be understood by the disk. - -Generally Linux/POSIX applications are agnostic to the intricacies of -the storage devices they are accessing. The virtual filesystem switch -and the block layer make things like hardware sector size and -transport protocols completely transparent to the application. - -However, this level of detail is required when preparing the -protection information to send to a disk. Consequently, the very -concept of an end-to-end protection scheme is a layering violation. -It is completely unreasonable for an application to be aware whether -it is accessing a SCSI or SATA disk. - -The data integrity support implemented in Linux attempts to hide this -from the application. As far as the application (and to some extent -the kernel) is concerned, the integrity metadata is opaque information -that's attached to the I/O. - -The current implementation allows the block layer to automatically -generate the protection information for any I/O. Eventually the -intent is to move the integrity metadata calculation to userspace for -user data. Metadata and other I/O that originates within the kernel -will still use the automatic generation interface. - -Some storage devices allow each hardware sector to be tagged with a -16-bit value. The owner of this tag space is the owner of the block -device. I.e. the filesystem in most cases. The filesystem can use -this extra space to tag sectors as they see fit. Because the tag -space is limited, the block interface allows tagging bigger chunks by -way of interleaving. This way, 8*16 bits of information can be -attached to a typical 4KB filesystem block. - -This also means that applications such as fsck and mkfs will need -access to manipulate the tags from user space. A passthrough -interface for this is being worked on. - - ----------------------------------------------------------------------- -4. BLOCK LAYER IMPLEMENTATION DETAILS - -4.1 BIO - -The data integrity patches add a new field to struct bio when -CONFIG_BLK_DEV_INTEGRITY is enabled. bio->bi_integrity is a pointer -to a struct bip which contains the bio integrity payload. Essentially -a bip is a trimmed down struct bio which holds a bio_vec containing -the integrity metadata and the required housekeeping information (bvec -pool, vector count, etc.) - -A kernel subsystem can enable data integrity protection on a bio by -calling bio_integrity_alloc(bio). This will allocate and attach the -bip to the bio. - -Individual pages containing integrity metadata can subsequently be -attached using bio_integrity_add_page(). - -bio_free() will automatically free the bip. - - -4.2 BLOCK DEVICE - -Because the format of the protection data is tied to the physical -disk, each block device has been extended with a block integrity -profile (struct blk_integrity). This optional profile is registered -with the block layer using blk_integrity_register(). - -The profile contains callback functions for generating and verifying -the protection data, as well as getting and setting application tags. -The profile also contains a few constants to aid in completing, -merging and splitting the integrity metadata. - -Layered block devices will need to pick a profile that's appropriate -for all subdevices. blk_integrity_compare() can help with that. DM -and MD linear, RAID0 and RAID1 are currently supported. RAID4/5/6 -will require extra work due to the application tag. - - ----------------------------------------------------------------------- -5.0 BLOCK LAYER INTEGRITY API - -5.1 NORMAL FILESYSTEM - - The normal filesystem is unaware that the underlying block device - is capable of sending/receiving integrity metadata. The IMD will - be automatically generated by the block layer at submit_bio() time - in case of a WRITE. A READ request will cause the I/O integrity - to be verified upon completion. - - IMD generation and verification can be toggled using the - - /sys/block//integrity/write_generate - - and - - /sys/block//integrity/read_verify - - flags. - - -5.2 INTEGRITY-AWARE FILESYSTEM - - A filesystem that is integrity-aware can prepare I/Os with IMD - attached. It can also use the application tag space if this is - supported by the block device. - - - int bdev_integrity_enabled(block_device, int rw); - - bdev_integrity_enabled() will return 1 if the block device - supports integrity metadata transfer for the data direction - specified in 'rw'. - - bdev_integrity_enabled() honors the write_generate and - read_verify flags in sysfs and will respond accordingly. - - - int bio_integrity_prep(bio); - - To generate IMD for WRITE and to set up buffers for READ, the - filesystem must call bio_integrity_prep(bio). - - Prior to calling this function, the bio data direction and start - sector must be set, and the bio should have all data pages - added. It is up to the caller to ensure that the bio does not - change while I/O is in progress. - - bio_integrity_prep() should only be called if - bio_integrity_enabled() returned 1. - - - int bio_integrity_tag_size(bio); - - If the filesystem wants to use the application tag space it will - first have to find out how much storage space is available. - Because tag space is generally limited (usually 2 bytes per - sector regardless of sector size), the integrity framework - supports interleaving the information between the sectors in an - I/O. - - Filesystems can call bio_integrity_tag_size(bio) to find out how - many bytes of storage are available for that particular bio. - - Another option is bdev_get_tag_size(block_device) which will - return the number of available bytes per hardware sector. - - - int bio_integrity_set_tag(bio, void *tag_buf, len); - - After a successful return from bio_integrity_prep(), - bio_integrity_set_tag() can be used to attach an opaque tag - buffer to a bio. Obviously this only makes sense if the I/O is - a WRITE. - - - int bio_integrity_get_tag(bio, void *tag_buf, len); - - Similarly, at READ I/O completion time the filesystem can - retrieve the tag buffer using bio_integrity_get_tag(). - - -6.3 PASSING EXISTING INTEGRITY METADATA - - Filesystems that either generate their own integrity metadata or - are capable of transferring IMD from user space can use the - following calls: - - - struct bip * bio_integrity_alloc(bio, gfp_mask, nr_pages); - - Allocates the bio integrity payload and hangs it off of the bio. - nr_pages indicate how many pages of protection data need to be - stored in the integrity bio_vec list (similar to bio_alloc()). - - The integrity payload will be freed at bio_free() time. - - - int bio_integrity_add_page(bio, page, len, offset); - - Attaches a page containing integrity metadata to an existing - bio. The bio must have an existing bip, - i.e. bio_integrity_alloc() must have been called. For a WRITE, - the integrity metadata in the pages must be in a format - understood by the target device with the notable exception that - the sector numbers will be remapped as the request traverses the - I/O stack. This implies that the pages added using this call - will be modified during I/O! The first reference tag in the - integrity metadata must have a value of bip->bip_sector. - - Pages can be added using bio_integrity_add_page() as long as - there is room in the bip bio_vec array (nr_pages). - - Upon completion of a READ operation, the attached pages will - contain the integrity metadata received from the storage device. - It is up to the receiver to process them and verify data - integrity upon completion. - - -6.4 REGISTERING A BLOCK DEVICE AS CAPABLE OF EXCHANGING INTEGRITY - METADATA - - To enable integrity exchange on a block device the gendisk must be - registered as capable: - - int blk_integrity_register(gendisk, blk_integrity); - - The blk_integrity struct is a template and should contain the - following: - - static struct blk_integrity my_profile = { - .name = "STANDARDSBODY-TYPE-VARIANT-CSUM", - .generate_fn = my_generate_fn, - .verify_fn = my_verify_fn, - .get_tag_fn = my_get_tag_fn, - .set_tag_fn = my_set_tag_fn, - .tuple_size = sizeof(struct my_tuple_size), - .tag_size = , - }; - - 'name' is a text string which will be visible in sysfs. This is - part of the userland API so chose it carefully and never change - it. The format is standards body-type-variant. - E.g. T10-DIF-TYPE1-IP or T13-EPP-0-CRC. - - 'generate_fn' generates appropriate integrity metadata (for WRITE). - - 'verify_fn' verifies that the data buffer matches the integrity - metadata. - - 'tuple_size' must be set to match the size of the integrity - metadata per sector. I.e. 8 for DIF and EPP. - - 'tag_size' must be set to identify how many bytes of tag space - are available per hardware sector. For DIF this is either 2 or - 0 depending on the value of the Control Mode Page ATO bit. - - See 6.2 for a description of get_tag_fn and set_tag_fn. - ----------------------------------------------------------------------- -2007-12-24 Martin K. Petersen diff --git a/trunk/Documentation/ioctl-number.txt b/trunk/Documentation/ioctl-number.txt index 3bb5f466a90d..240ce7a56c40 100644 --- a/trunk/Documentation/ioctl-number.txt +++ b/trunk/Documentation/ioctl-number.txt @@ -117,7 +117,6 @@ Code Seq# Include File Comments 'c' 00-7F linux/comstats.h conflict! 'c' 00-7F linux/coda.h conflict! -'c' 80-9F asm-s390/chsc.h 'd' 00-FF linux/char/drm/drm/h conflict! 'd' 00-DF linux/video_decoder.h conflict! 'd' F0-FF linux/digi1.h diff --git a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt index 72aff61e7315..0bbee38acd26 100644 --- a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt @@ -753,11 +753,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. [Multiple options for each card instance] model - force the model name - position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) + position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) - bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. - Passing -1 will make the driver to choose the appropriate - value based on the controller chip. [Single (global) options] single_cmd - Use single immediate commands to communicate with @@ -848,7 +845,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ALC269 basic Basic preset - ALC662/663 + ALC662 3stack-dig 3-stack (2-channel) with SPDIF 3stack-6ch 3-stack (6-channel) 3stack-6ch-dig 3-stack (6-channel) with SPDIF @@ -856,10 +853,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. lenovo-101e Lenovo laptop eeepc-p701 ASUS Eeepc P701 eeepc-ep20 ASUS Eeepc EP20 - m51va ASUS M51VA - g71v ASUS G71V - h13 ASUS H13 - g50v ASUS G50V auto auto-config reading BIOS (default) ALC882/885 @@ -1098,7 +1091,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This occurs when the access to non-existing or non-working codec slot (likely a modem one) causes a stall of the communication via HD-audio bus. You can see which codec slots are probed by enabling - CONFIG_SND_DEBUG_VERBOSE, or simply from the file name of the codec + CONFIG_SND_DEBUG_DETECT, or simply from the file name of the codec proc files. Then limit the slots to probe by probe_mask option. For example, probe_mask=1 means to probe only the first slot, and probe_mask=4 means only the third slot. @@ -2274,10 +2267,6 @@ case above again, the first two slots are already reserved. If any other driver (e.g. snd-usb-audio) is loaded before snd-interwave or snd-ens1371, it will be assigned to the third or later slot. -When a module name is given with '!', the slot will be given for any -modules but that name. For example, "slots=!snd-pcsp" will reserve -the first slot for any modules but snd-pcsp. - ALSA PCM devices to OSS devices mapping ======================================= diff --git a/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index e13c4e67029f..b03df4d4795c 100644 --- a/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -6127,8 +6127,8 @@ struct _snd_pcm_runtime { snd_printdd() is compiled in only when - CONFIG_SND_DEBUG_VERBOSE is set. Please note - that CONFIG_SND_DEBUG_VERBOSE is not set as default + CONFIG_SND_DEBUG_DETECT is set. Please note + that DEBUG_DETECT is not set as default even if you configure the alsa-driver with option. You need to give explicitly option instead. diff --git a/trunk/arch/s390/Kconfig b/trunk/arch/s390/Kconfig index 5dc8f8028d52..107e492cb47e 100644 --- a/trunk/arch/s390/Kconfig +++ b/trunk/arch/s390/Kconfig @@ -146,7 +146,6 @@ config MATHEMU config COMPAT bool "Kernel support for 31 bit emulation" depends on 64BIT - select COMPAT_BINFMT_ELF help Select this option if you want to enable your system kernel to handle system-calls from ELF binaries for 31 bit ESA. This option @@ -313,10 +312,6 @@ config ARCH_SPARSEMEM_DEFAULT config ARCH_SELECT_MEMORY_MODEL def_bool y -config ARCH_ENABLE_MEMORY_HOTPLUG - def_bool y - depends on SPARSEMEM - source "mm/Kconfig" comment "I/O subsystem configuration" @@ -349,22 +344,6 @@ config QDIO_DEBUG If unsure, say N. -config CHSC_SCH - tristate "Support for CHSC subchannels" - help - This driver allows usage of CHSC subchannels. A CHSC subchannel - is usually present on LPAR only. - The driver creates a device /dev/chsc, which may be used to - obtain I/O configuration information about the machine and - to issue asynchronous chsc commands (DANGEROUS). - You will usually only want to use this interface on a special - LPAR designated for system management. - - To compile this driver as a module, choose M here: the - module will be called chsc_sch. - - If unsure, say N. - comment "Misc" config IPL diff --git a/trunk/arch/s390/appldata/appldata.h b/trunk/arch/s390/appldata/appldata.h index 17a2636fec0a..db3ae8505103 100644 --- a/trunk/arch/s390/appldata/appldata.h +++ b/trunk/arch/s390/appldata/appldata.h @@ -3,11 +3,13 @@ * * Definitions and interface for Linux - z/VM Monitor Stream. * - * Copyright IBM Corp. 2003, 2008 + * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer */ +//#define APPLDATA_DEBUG /* Debug messages on/off */ + #define APPLDATA_MAX_REC_SIZE 4024 /* Maximum size of the */ /* data buffer */ #define APPLDATA_MAX_PROCS 100 @@ -30,6 +32,12 @@ #define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x) #define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x) +#ifdef APPLDATA_DEBUG +#define P_DEBUG(x...) printk(KERN_DEBUG MY_PRINT_NAME " debug: " x) +#else +#define P_DEBUG(x...) do {} while (0) +#endif + struct appldata_ops { struct list_head list; struct ctl_table_header *sysctl_header; diff --git a/trunk/arch/s390/appldata/appldata_base.c b/trunk/arch/s390/appldata/appldata_base.c index 9cb3d92447a3..ad40729bec3d 100644 --- a/trunk/arch/s390/appldata/appldata_base.c +++ b/trunk/arch/s390/appldata/appldata_base.c @@ -5,7 +5,7 @@ * Exports appldata_register_ops() and appldata_unregister_ops() for the * data gathering modules. * - * Copyright IBM Corp. 2003, 2008 + * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer */ @@ -108,6 +108,9 @@ static LIST_HEAD(appldata_ops_list); */ static void appldata_timer_function(unsigned long data) { + P_DEBUG(" -= Timer =-\n"); + P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(), + atomic_read(&appldata_expire_count)); if (atomic_dec_and_test(&appldata_expire_count)) { atomic_set(&appldata_expire_count, num_online_cpus()); queue_work(appldata_wq, (struct work_struct *) data); @@ -125,11 +128,14 @@ static void appldata_work_fn(struct work_struct *work) struct appldata_ops *ops; int i; + P_DEBUG(" -= Work Queue =-\n"); i = 0; get_online_cpus(); spin_lock(&appldata_ops_lock); list_for_each(lh, &appldata_ops_list) { ops = list_entry(lh, struct appldata_ops, list); + P_DEBUG("list_for_each loop: %i) active = %u, name = %s\n", + ++i, ops->active, ops->name); if (ops->active == 1) { ops->callback(ops->data); } @@ -206,6 +212,7 @@ __appldata_vtimer_setup(int cmd) 0, 1); } appldata_timer_active = 1; + P_INFO("Monitoring timer started.\n"); break; case APPLDATA_DEL_TIMER: for_each_online_cpu(i) @@ -214,6 +221,7 @@ __appldata_vtimer_setup(int cmd) break; appldata_timer_active = 0; atomic_set(&appldata_expire_count, num_online_cpus()); + P_INFO("Monitoring timer stopped.\n"); break; case APPLDATA_MOD_TIMER: per_cpu_interval = (u64) (appldata_interval*1000 / @@ -305,8 +313,10 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, } interval = 0; sscanf(buf, "%i", &interval); - if (interval <= 0) + if (interval <= 0) { + P_ERROR("Timer CPU interval has to be > 0!\n"); return -EINVAL; + } get_online_cpus(); spin_lock(&appldata_timer_lock); @@ -314,6 +324,9 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, __appldata_vtimer_setup(APPLDATA_MOD_TIMER); spin_unlock(&appldata_timer_lock); put_online_cpus(); + + P_INFO("Monitoring CPU interval set to %u milliseconds.\n", + interval); out: *lenp = len; *ppos += len; @@ -393,16 +406,23 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, P_ERROR("START DIAG 0xDC for %s failed, " "return code: %d\n", ops->name, rc); module_put(ops->owner); - } else + } else { + P_INFO("Monitoring %s data enabled, " + "DIAG 0xDC started.\n", ops->name); ops->active = 1; + } } else if ((buf[0] == '0') && (ops->active == 1)) { ops->active = 0; rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, (unsigned long) ops->data, ops->size, ops->mod_lvl); - if (rc != 0) + if (rc != 0) { P_ERROR("STOP DIAG 0xDC for %s failed, " "return code: %d\n", ops->name, rc); + } else { + P_INFO("Monitoring %s data disabled, " + "DIAG 0xDC stopped.\n", ops->name); + } module_put(ops->owner); } spin_unlock(&appldata_ops_lock); @@ -448,6 +468,7 @@ int appldata_register_ops(struct appldata_ops *ops) ops->sysctl_header = register_sysctl_table(ops->ctl_table); if (!ops->sysctl_header) goto out; + P_INFO("%s-ops registered!\n", ops->name); return 0; out: spin_lock(&appldata_ops_lock); @@ -469,6 +490,7 @@ void appldata_unregister_ops(struct appldata_ops *ops) spin_unlock(&appldata_ops_lock); unregister_sysctl_table(ops->sysctl_header); kfree(ops->ctl_table); + P_INFO("%s-ops unregistered!\n", ops->name); } /********************** module-ops management **************************/ @@ -531,9 +553,14 @@ static int __init appldata_init(void) { int i; + P_DEBUG("sizeof(parameter_list) = %lu\n", + sizeof(struct appldata_parameter_list)); + appldata_wq = create_singlethread_workqueue("appldata"); - if (!appldata_wq) + if (!appldata_wq) { + P_ERROR("Could not create work queue\n"); return -ENOMEM; + } get_online_cpus(); for_each_online_cpu(i) @@ -544,6 +571,8 @@ static int __init appldata_init(void) register_hotcpu_notifier(&appldata_nb); appldata_sysctl_header = register_sysctl_table(appldata_dir_table); + + P_DEBUG("Base interface initialized.\n"); return 0; } @@ -555,9 +584,7 @@ EXPORT_SYMBOL_GPL(appldata_register_ops); EXPORT_SYMBOL_GPL(appldata_unregister_ops); EXPORT_SYMBOL_GPL(appldata_diag); -#ifdef CONFIG_SWAP EXPORT_SYMBOL_GPL(si_swapinfo); -#endif EXPORT_SYMBOL_GPL(nr_threads); EXPORT_SYMBOL_GPL(nr_running); EXPORT_SYMBOL_GPL(nr_iowait); diff --git a/trunk/arch/s390/appldata/appldata_mem.c b/trunk/arch/s390/appldata/appldata_mem.c index 3ed56b7d1b2f..51181ccdb87b 100644 --- a/trunk/arch/s390/appldata/appldata_mem.c +++ b/trunk/arch/s390/appldata/appldata_mem.c @@ -14,13 +14,14 @@ #include #include #include +#include #include #include -#include #include "appldata.h" +#define MY_PRINT_NAME "appldata_mem" /* for debug messages, etc. */ #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* Converts #Pages to KB */ /* @@ -69,6 +70,30 @@ static struct appldata_mem_data { } __attribute__((packed)) appldata_mem_data; +static inline void appldata_debug_print(struct appldata_mem_data *mem_data) +{ + P_DEBUG("--- MEM - RECORD ---\n"); + P_DEBUG("pgpgin = %8lu KB\n", mem_data->pgpgin); + P_DEBUG("pgpgout = %8lu KB\n", mem_data->pgpgout); + P_DEBUG("pswpin = %8lu Pages\n", mem_data->pswpin); + P_DEBUG("pswpout = %8lu Pages\n", mem_data->pswpout); + P_DEBUG("pgalloc = %8lu \n", mem_data->pgalloc); + P_DEBUG("pgfault = %8lu \n", mem_data->pgfault); + P_DEBUG("pgmajfault = %8lu \n", mem_data->pgmajfault); + P_DEBUG("sharedram = %8lu KB\n", mem_data->sharedram); + P_DEBUG("totalram = %8lu KB\n", mem_data->totalram); + P_DEBUG("freeram = %8lu KB\n", mem_data->freeram); + P_DEBUG("totalhigh = %8lu KB\n", mem_data->totalhigh); + P_DEBUG("freehigh = %8lu KB\n", mem_data->freehigh); + P_DEBUG("bufferram = %8lu KB\n", mem_data->bufferram); + P_DEBUG("cached = %8lu KB\n", mem_data->cached); + P_DEBUG("totalswap = %8lu KB\n", mem_data->totalswap); + P_DEBUG("freeswap = %8lu KB\n", mem_data->freeswap); + P_DEBUG("sync_count_1 = %u\n", mem_data->sync_count_1); + P_DEBUG("sync_count_2 = %u\n", mem_data->sync_count_2); + P_DEBUG("timestamp = %lX\n", mem_data->timestamp); +} + /* * appldata_get_mem_data() * @@ -115,6 +140,9 @@ static void appldata_get_mem_data(void *data) mem_data->timestamp = get_clock(); mem_data->sync_count_2++; +#ifdef APPLDATA_DEBUG + appldata_debug_print(mem_data); +#endif } @@ -136,7 +164,17 @@ static struct appldata_ops ops = { */ static int __init appldata_mem_init(void) { - return appldata_register_ops(&ops); + int rc; + + P_DEBUG("sizeof(mem) = %lu\n", sizeof(struct appldata_mem_data)); + + rc = appldata_register_ops(&ops); + if (rc != 0) { + P_ERROR("Error registering ops, rc = %i\n", rc); + } else { + P_DEBUG("%s-ops registered!\n", ops.name); + } + return rc; } /* @@ -147,6 +185,7 @@ static int __init appldata_mem_init(void) static void __exit appldata_mem_exit(void) { appldata_unregister_ops(&ops); + P_DEBUG("%s-ops unregistered!\n", ops.name); } diff --git a/trunk/arch/s390/appldata/appldata_net_sum.c b/trunk/arch/s390/appldata/appldata_net_sum.c index 3b746556e1a3..4d8344336001 100644 --- a/trunk/arch/s390/appldata/appldata_net_sum.c +++ b/trunk/arch/s390/appldata/appldata_net_sum.c @@ -21,6 +21,9 @@ #include "appldata.h" +#define MY_PRINT_NAME "appldata_net_sum" /* for debug messages, etc. */ + + /* * Network data * @@ -57,6 +60,26 @@ static struct appldata_net_sum_data { } __attribute__((packed)) appldata_net_sum_data; +static inline void appldata_print_debug(struct appldata_net_sum_data *net_data) +{ + P_DEBUG("--- NET - RECORD ---\n"); + + P_DEBUG("nr_interfaces = %u\n", net_data->nr_interfaces); + P_DEBUG("rx_packets = %8lu\n", net_data->rx_packets); + P_DEBUG("tx_packets = %8lu\n", net_data->tx_packets); + P_DEBUG("rx_bytes = %8lu\n", net_data->rx_bytes); + P_DEBUG("tx_bytes = %8lu\n", net_data->tx_bytes); + P_DEBUG("rx_errors = %8lu\n", net_data->rx_errors); + P_DEBUG("tx_errors = %8lu\n", net_data->tx_errors); + P_DEBUG("rx_dropped = %8lu\n", net_data->rx_dropped); + P_DEBUG("tx_dropped = %8lu\n", net_data->tx_dropped); + P_DEBUG("collisions = %8lu\n", net_data->collisions); + + P_DEBUG("sync_count_1 = %u\n", net_data->sync_count_1); + P_DEBUG("sync_count_2 = %u\n", net_data->sync_count_2); + P_DEBUG("timestamp = %lX\n", net_data->timestamp); +} + /* * appldata_get_net_sum_data() * @@ -112,6 +135,9 @@ static void appldata_get_net_sum_data(void *data) net_data->timestamp = get_clock(); net_data->sync_count_2++; +#ifdef APPLDATA_DEBUG + appldata_print_debug(net_data); +#endif } @@ -133,7 +159,17 @@ static struct appldata_ops ops = { */ static int __init appldata_net_init(void) { - return appldata_register_ops(&ops); + int rc; + + P_DEBUG("sizeof(net) = %lu\n", sizeof(struct appldata_net_sum_data)); + + rc = appldata_register_ops(&ops); + if (rc != 0) { + P_ERROR("Error registering ops, rc = %i\n", rc); + } else { + P_DEBUG("%s-ops registered!\n", ops.name); + } + return rc; } /* @@ -144,6 +180,7 @@ static int __init appldata_net_init(void) static void __exit appldata_net_exit(void) { appldata_unregister_ops(&ops); + P_DEBUG("%s-ops unregistered!\n", ops.name); } diff --git a/trunk/arch/s390/appldata/appldata_os.c b/trunk/arch/s390/appldata/appldata_os.c index eb44f9f8ab91..6b3eafe10453 100644 --- a/trunk/arch/s390/appldata/appldata_os.c +++ b/trunk/arch/s390/appldata/appldata_os.c @@ -89,6 +89,44 @@ static struct appldata_ops ops = { }; +static inline void appldata_print_debug(struct appldata_os_data *os_data) +{ + int a0, a1, a2, i; + + P_DEBUG("--- OS - RECORD ---\n"); + P_DEBUG("nr_threads = %u\n", os_data->nr_threads); + P_DEBUG("nr_running = %u\n", os_data->nr_running); + P_DEBUG("nr_iowait = %u\n", os_data->nr_iowait); + P_DEBUG("avenrun(int) = %8x / %8x / %8x\n", os_data->avenrun[0], + os_data->avenrun[1], os_data->avenrun[2]); + a0 = os_data->avenrun[0]; + a1 = os_data->avenrun[1]; + a2 = os_data->avenrun[2]; + P_DEBUG("avenrun(float) = %d.%02d / %d.%02d / %d.%02d\n", + LOAD_INT(a0), LOAD_FRAC(a0), LOAD_INT(a1), LOAD_FRAC(a1), + LOAD_INT(a2), LOAD_FRAC(a2)); + + P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus); + for (i = 0; i < os_data->nr_cpus; i++) { + P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, " + "idle = %u, irq = %u, softirq = %u, iowait = %u, " + "steal = %u\n", + os_data->os_cpu[i].cpu_id, + os_data->os_cpu[i].per_cpu_user, + os_data->os_cpu[i].per_cpu_nice, + os_data->os_cpu[i].per_cpu_system, + os_data->os_cpu[i].per_cpu_idle, + os_data->os_cpu[i].per_cpu_irq, + os_data->os_cpu[i].per_cpu_softirq, + os_data->os_cpu[i].per_cpu_iowait, + os_data->os_cpu[i].per_cpu_steal); + } + + P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1); + P_DEBUG("sync_count_2 = %u\n", os_data->sync_count_2); + P_DEBUG("timestamp = %lX\n", os_data->timestamp); +} + /* * appldata_get_os_data() * @@ -142,10 +180,13 @@ static void appldata_get_os_data(void *data) APPLDATA_START_INTERVAL_REC, (unsigned long) ops.data, new_size, ops.mod_lvl); - if (rc != 0) + if (rc != 0) { P_ERROR("os: START NEW DIAG 0xDC failed, " "return code: %d, new size = %i\n", rc, new_size); + P_INFO("os: stopping old record now\n"); + } else + P_INFO("os: new record size = %i\n", new_size); rc = appldata_diag(APPLDATA_RECORD_OS_ID, APPLDATA_STOP_REC, @@ -163,6 +204,9 @@ static void appldata_get_os_data(void *data) } os_data->timestamp = get_clock(); os_data->sync_count_2++; +#ifdef APPLDATA_DEBUG + appldata_print_debug(os_data); +#endif } @@ -183,9 +227,12 @@ static int __init appldata_os_init(void) rc = -ENOMEM; goto out; } + P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu\n", max_size, + sizeof(struct appldata_os_per_cpu)); appldata_os_data = kzalloc(max_size, GFP_DMA); if (appldata_os_data == NULL) { + P_ERROR("No memory for %s!\n", ops.name); rc = -ENOMEM; goto out; } @@ -193,12 +240,17 @@ static int __init appldata_os_init(void) appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu); appldata_os_data->cpu_offset = offsetof(struct appldata_os_data, os_cpu); + P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset); ops.data = appldata_os_data; ops.callback = &appldata_get_os_data; rc = appldata_register_ops(&ops); - if (rc != 0) + if (rc != 0) { + P_ERROR("Error registering ops, rc = %i\n", rc); kfree(appldata_os_data); + } else { + P_DEBUG("%s-ops registered!\n", ops.name); + } out: return rc; } @@ -212,6 +264,7 @@ static void __exit appldata_os_exit(void) { appldata_unregister_ops(&ops); kfree(appldata_os_data); + P_DEBUG("%s-ops unregistered!\n", ops.name); } diff --git a/trunk/arch/s390/crypto/prng.c b/trunk/arch/s390/crypto/prng.c index 6a4300b3ff52..0cfefddd8375 100644 --- a/trunk/arch/s390/crypto/prng.c +++ b/trunk/arch/s390/crypto/prng.c @@ -185,8 +185,11 @@ static int __init prng_init(void) prng_seed(16); ret = misc_register(&prng_dev); - if (ret) + if (ret) { + printk(KERN_WARNING + "Could not register misc device for PRNG.\n"); goto out_buf; + } return 0; out_buf: diff --git a/trunk/arch/s390/hypfs/inode.c b/trunk/arch/s390/hypfs/inode.c index 7383781f3e6a..4b010ff814c9 100644 --- a/trunk/arch/s390/hypfs/inode.c +++ b/trunk/arch/s390/hypfs/inode.c @@ -150,24 +150,33 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t offset) { char *data; - ssize_t ret; + size_t len; struct file *filp = iocb->ki_filp; /* XXX: temporary */ char __user *buf = iov[0].iov_base; size_t count = iov[0].iov_len; - if (nr_segs != 1) - return -EINVAL; + if (nr_segs != 1) { + count = -EINVAL; + goto out; + } data = filp->private_data; - ret = simple_read_from_buffer(buf, count, &offset, data, strlen(data)); - if (ret <= 0) - return ret; - - iocb->ki_pos += ret; + len = strlen(data); + if (offset > len) { + count = 0; + goto out; + } + if (count > len - offset) + count = len - offset; + if (copy_to_user(buf, data + offset, count)) { + count = -EFAULT; + goto out; + } + iocb->ki_pos += count; file_accessed(filp); - - return ret; +out: + return count; } static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t offset) diff --git a/trunk/arch/s390/kernel/Makefile b/trunk/arch/s390/kernel/Makefile index 50f657e77344..6302f5082588 100644 --- a/trunk/arch/s390/kernel/Makefile +++ b/trunk/arch/s390/kernel/Makefile @@ -7,14 +7,9 @@ # CFLAGS_smp.o := -Wno-nonnull -# -# Pass UTS_MACHINE for user_regset definition -# -CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' - obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o + s390_ext.o debug.o irq.o ipl.o dis.o diag.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) @@ -28,7 +23,7 @@ obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ compat_wrapper.o compat_exec_domain.o \ - $(compat-obj-y) + binfmt_elf32.o $(compat-obj-y) obj-$(CONFIG_VIRT_TIMER) += vtime.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/trunk/arch/s390/kernel/binfmt_elf32.c b/trunk/arch/s390/kernel/binfmt_elf32.c new file mode 100644 index 000000000000..3e1c315b736d --- /dev/null +++ b/trunk/arch/s390/kernel/binfmt_elf32.c @@ -0,0 +1,214 @@ +/* + * Support for 32-bit Linux for S390 ELF binaries. + * + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Gerhard Tonn (ton@de.ibm.com) + * + * Heavily inspired by the 32-bit Sparc compat code which is + * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) + * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#define __ASMS390_ELF_H + +#include + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_S390 + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) \ + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) + +/* ELF register definitions */ +#define NUM_GPRS 16 +#define NUM_FPRS 16 +#define NUM_ACRS 16 + +/* For SVR4/S390 the function pointer to be registered with `atexit` is + passed in R14. */ +#define ELF_PLAT_INIT(_r, load_addr) \ + do { \ + _r->gprs[14] = 0; \ + } while(0) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) + +/* Wow, the "main" arch needs arch dependent functions too.. :) */ + +/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is + now struct_user_regs, they are different) */ + +#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs32(regs, &pr_reg); + +#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs32(tsk, regs) + +#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs) + +/* This yields a mask that user programs can use to figure out what + instruction set this CPU supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. + + For the moment, we have only optimizations for the Intel generations, + but that could change... */ + +#define ELF_PLATFORM (NULL) + +#define SET_PERSONALITY(ex, ibcs2) \ +do { \ + if (ibcs2) \ + set_personality(PER_SVR4); \ + else if (current->personality != PER_LINUX32) \ + set_personality(PER_LINUX); \ + set_thread_flag(TIF_31BIT); \ +} while (0) + +#include "compat_linux.h" + +typedef _s390_fp_regs32 elf_fpregset_t; + +typedef struct +{ + + _psw_t32 psw; + __u32 gprs[__NUM_GPRS]; + __u32 acrs[__NUM_ACRS]; + __u32 orig_gpr2; +} s390_regs32; +typedef s390_regs32 elf_gregset_t; + +static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs) +{ + int i; + + memcpy(®s->psw.mask, &ptregs->psw.mask, 4); + memcpy(®s->psw.addr, (char *)&ptregs->psw.addr + 4, 4); + for (i = 0; i < NUM_GPRS; i++) + regs->gprs[i] = ptregs->gprs[i]; + save_access_regs(regs->acrs); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +static inline int dump_task_regs32(struct task_struct *tsk, elf_gregset_t *regs) +{ + struct pt_regs *ptregs = task_pt_regs(tsk); + int i; + + memcpy(®s->psw.mask, &ptregs->psw.mask, 4); + memcpy(®s->psw.addr, (char *)&ptregs->psw.addr + 4, 4); + for (i = 0; i < NUM_GPRS; i++) + regs->gprs[i] = ptregs->gprs[i]; + memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs)); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +{ + if (tsk == current) + save_fp_regs((s390_fp_regs *) fpregs); + else + memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t)); + return 1; +} + +#include +#include +#include +#include +#include +#include + +#define elf_prstatus elf_prstatus32 +struct elf_prstatus32 +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + u32 pr_sigpend; /* Set of pending signals */ + u32 pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct compat_timeval pr_utime; /* User time */ + struct compat_timeval pr_stime; /* System time */ + struct compat_timeval pr_cutime; /* Cumulative user time */ + struct compat_timeval pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + int pr_fpvalid; /* True if math co-processor being used. */ +}; + +#define elf_prpsinfo elf_prpsinfo32 +struct elf_prpsinfo32 +{ + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + u32 pr_flag; /* flags */ + u16 pr_uid; + u16 pr_gid; + pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; + +#include + +/* +#define init_elf_binfmt init_elf32_binfmt +*/ + +#undef start_thread +#define start_thread start_thread31 + +static inline void start_thread31(struct pt_regs *regs, unsigned long new_psw, + unsigned long new_stackp) +{ + set_fs(USER_DS); + regs->psw.mask = psw_user32_bits; + regs->psw.addr = new_psw; + regs->gprs[15] = new_stackp; + crst_table_downgrade(current->mm, 1UL << 31); +} + +MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries," + " Copyright 2000 IBM Corporation"); +MODULE_AUTHOR("Gerhard Tonn "); + +#undef MODULE_DESCRIPTION +#undef MODULE_AUTHOR + +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval +static inline void +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) +{ + value->tv_usec = cputime % 1000000; + value->tv_sec = cputime / 1000000; +} + +#include "../../../fs/binfmt_elf.c" + diff --git a/trunk/arch/s390/kernel/compat_ptrace.h b/trunk/arch/s390/kernel/compat_ptrace.h index cde81fa64f89..419aef913ee1 100644 --- a/trunk/arch/s390/kernel/compat_ptrace.h +++ b/trunk/arch/s390/kernel/compat_ptrace.h @@ -1,7 +1,7 @@ #ifndef _PTRACE32_H #define _PTRACE32_H -#include "compat_linux.h" /* needed for psw_compat_t */ +#include "compat_linux.h" /* needed for _psw_t32 */ typedef struct { __u32 cr[3]; @@ -38,7 +38,7 @@ typedef struct { struct user_regs_struct32 { - psw_compat_t psw; + _psw_t32 psw; u32 gprs[NUM_GPRS]; u32 acrs[NUM_ACRS]; u32 orig_gpr2; diff --git a/trunk/arch/s390/kernel/debug.c b/trunk/arch/s390/kernel/debug.c index d80fcd4a7fe1..c93d1296cc0a 100644 --- a/trunk/arch/s390/kernel/debug.c +++ b/trunk/arch/s390/kernel/debug.c @@ -1079,6 +1079,7 @@ __init debug_init(void) s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table); mutex_lock(&debug_mutex); debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL); + printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; mutex_unlock(&debug_mutex); @@ -1192,6 +1193,7 @@ debug_get_uint(char *buf) for(; isspace(*buf); buf++); rc = simple_strtoul(buf, &buf, 10); if(*buf){ + printk("debug: no integer specified!\n"); rc = -EINVAL; } return rc; @@ -1338,12 +1340,19 @@ static void debug_flush(debug_info_t* id, int area) memset(id->areas[i][j], 0, PAGE_SIZE); } } + printk(KERN_INFO "debug: %s: all areas flushed\n",id->name); } else if(area >= 0 && area < id->nr_areas) { id->active_entries[area] = 0; id->active_pages[area] = 0; for(i = 0; i < id->pages_per_area; i++) { memset(id->areas[area][i],0,PAGE_SIZE); } + printk(KERN_INFO "debug: %s: area %i has been flushed\n", + id->name, area); + } else { + printk(KERN_INFO + "debug: %s: area %i cannot be flushed (range: %i - %i)\n", + id->name, area, 0, id->nr_areas-1); } spin_unlock_irqrestore(&id->lock,flags); } diff --git a/trunk/arch/s390/kernel/early.c b/trunk/arch/s390/kernel/early.c index 2a2ca268b1dd..d0e09684b9ce 100644 --- a/trunk/arch/s390/kernel/early.c +++ b/trunk/arch/s390/kernel/early.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -27,40 +26,12 @@ /* * Create a Kernel NSS if the SAVESYS= parameter is defined */ -#define DEFSYS_CMD_SIZE 128 +#define DEFSYS_CMD_SIZE 96 #define SAVESYS_CMD_SIZE 32 char kernel_nss_name[NSS_NAME_SIZE + 1]; -static void __init setup_boot_command_line(void); - - #ifdef CONFIG_SHARED_KERNEL -int __init savesys_ipl_nss(char *cmd, const int cmdlen); - -asm( - " .section .init.text,\"ax\",@progbits\n" - " .align 4\n" - " .type savesys_ipl_nss, @function\n" - "savesys_ipl_nss:\n" -#ifdef CONFIG_64BIT - " stmg 6,15,48(15)\n" - " lgr 14,3\n" - " sam31\n" - " diag 2,14,0x8\n" - " sam64\n" - " lgr 2,14\n" - " lmg 6,15,48(15)\n" -#else - " stm 6,15,24(15)\n" - " lr 14,3\n" - " diag 2,14,0x8\n" - " lr 2,14\n" - " lm 6,15,24(15)\n" -#endif - " br 14\n" - " .size savesys_ipl_nss, .-savesys_ipl_nss\n"); - static noinline __init void create_kernel_nss(void) { unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; @@ -68,7 +39,6 @@ static noinline __init void create_kernel_nss(void) unsigned int sinitrd_pfn, einitrd_pfn; #endif int response; - size_t len; char *savesys_ptr; char upper_command_line[COMMAND_LINE_SIZE]; char defsys_cmd[DEFSYS_CMD_SIZE]; @@ -79,8 +49,8 @@ static noinline __init void create_kernel_nss(void) return; /* Convert COMMAND_LINE to upper case */ - for (i = 0; i < strlen(boot_command_line); i++) - upper_command_line[i] = toupper(boot_command_line[i]); + for (i = 0; i < strlen(COMMAND_LINE); i++) + upper_command_line[i] = toupper(COMMAND_LINE[i]); savesys_ptr = strstr(upper_command_line, "SAVESYS="); @@ -113,8 +83,7 @@ static noinline __init void create_kernel_nss(void) } #endif - sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13", - defsys_cmd, min_size); + sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size); sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", kernel_nss_name, kernel_nss_name); @@ -125,24 +94,13 @@ static noinline __init void create_kernel_nss(void) return; } - len = strlen(savesys_cmd); - ASCEBC(savesys_cmd, len); - response = savesys_ipl_nss(savesys_cmd, len); + __cpcmd(savesys_cmd, NULL, 0, &response); - /* On success: response is equal to the command size, - * max SAVESYS_CMD_SIZE - * On error: response contains the numeric portion of cp error message. - * for SAVESYS it will be >= 263 - */ - if (response > SAVESYS_CMD_SIZE) { + if (response != strlen(savesys_cmd)) { kernel_nss_name[0] = '\0'; return; } - /* re-setup boot command line with new ipl vm parms */ - ipl_update_parameters(); - setup_boot_command_line(); - ipl_flags = IPL_NSS_VALID; } @@ -183,11 +141,109 @@ static noinline __init void detect_machine_type(void) if (cpuinfo->cpu_id.version == 0xff) machine_flags |= MACHINE_FLAG_VM; + /* Running on a P/390 ? */ + if (cpuinfo->cpu_id.machine == 0x7490) + machine_flags |= MACHINE_FLAG_P390; + /* Running under KVM ? */ if (cpuinfo->cpu_id.version == 0xfe) machine_flags |= MACHINE_FLAG_KVM; } +#ifdef CONFIG_64BIT +static noinline __init int memory_fast_detect(void) +{ + unsigned long val0 = 0; + unsigned long val1 = 0xc; + int ret = -ENOSYS; + + if (ipl_flags & IPL_NSS_VALID) + return -ENOSYS; + + asm volatile( + " diag %1,%2,0x260\n" + "0: lhi %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc"); + + if (ret || val0 != val1) + return -ENOSYS; + + memory_chunk[0].size = val0 + 1; + return 0; +} +#else +static inline int memory_fast_detect(void) +{ + return -ENOSYS; +} +#endif + +static inline __init unsigned long __tprot(unsigned long addr) +{ + int cc = -1; + + asm volatile( + " tprot 0(%1),0\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (cc) : "a" (addr) : "cc"); + return (unsigned long)cc; +} + +/* Checking memory in 128KB increments. */ +#define CHUNK_INCR (1UL << 17) +#define ADDR2G (1UL << 31) + +static noinline __init void find_memory_chunks(unsigned long memsize) +{ + unsigned long addr = 0, old_addr = 0; + unsigned long old_cc = CHUNK_READ_WRITE; + unsigned long cc; + int chunk = 0; + + while (chunk < MEMORY_CHUNKS) { + cc = __tprot(addr); + while (cc == old_cc) { + addr += CHUNK_INCR; + if (memsize && addr >= memsize) + break; +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + cc = __tprot(addr); + } + + if (old_addr != addr && + (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) { + memory_chunk[chunk].addr = old_addr; + memory_chunk[chunk].size = addr - old_addr; + memory_chunk[chunk].type = old_cc; + chunk++; + } + + old_addr = addr; + old_cc = cc; + +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + /* + * Finish memory detection at the first hole + * if storage size is unknown. + */ + if (cc == -1UL && !memsize) + break; + if (memsize && addr >= memsize) + break; + } +} + static __init void early_pgm_check_handler(void) { unsigned long addr; @@ -324,61 +380,23 @@ static __init void detect_machine_facilities(void) #endif } -static __init void rescue_initrd(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - /* - * Move the initrd right behind the bss section in case it starts - * within the bss section. So we don't overwrite it when the bss - * section gets cleared. - */ - if (!INITRD_START || !INITRD_SIZE) - return; - if (INITRD_START >= (unsigned long) __bss_stop) - return; - memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE); - INITRD_START = (unsigned long) __bss_stop; -#endif -} - -/* Set up boot command line */ -static void __init setup_boot_command_line(void) -{ - char *parm = NULL; - - /* copy arch command line */ - strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); - boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0; - - /* append IPL PARM data to the boot command line */ - if (MACHINE_IS_VM) { - parm = boot_command_line + strlen(boot_command_line); - *parm++ = ' '; - get_ipl_vmparm(parm); - if (parm[0] == '=') - memmove(boot_command_line, parm + 1, strlen(parm)); - } -} - - /* * Save ipl parameters, clear bss memory, initialize storage keys * and create a kernel NSS at startup if the SAVESYS= parm is defined */ void __init startup_init(void) { + unsigned long long memsize; + ipl_save_parameters(); - rescue_initrd(); clear_bss_section(); init_kernel_storage_key(); lockdep_init(); lockdep_off(); - sort_main_extable(); - setup_lowcore_early(); detect_machine_type(); - ipl_update_parameters(); - setup_boot_command_line(); create_kernel_nss(); + sort_main_extable(); + setup_lowcore_early(); detect_mvpg(); detect_ieee(); detect_csp(); @@ -386,7 +404,18 @@ void __init startup_init(void) detect_diag44(); detect_machine_facilities(); setup_hpage(); + sclp_read_info_early(); sclp_facilities_detect(); - detect_memory_layout(memory_chunk); + memsize = sclp_memory_detect(); +#ifndef CONFIG_64BIT + /* + * Can't deal with more than 2G in 31 bit addressing mode, so + * limit the value in order to avoid strange side effects. + */ + if (memsize > ADDR2G) + memsize = ADDR2G; +#endif + if (memory_fast_detect() < 0) + find_memory_chunks((unsigned long) memsize); lockdep_on(); } diff --git a/trunk/arch/s390/kernel/ipl.c b/trunk/arch/s390/kernel/ipl.c index 54b2779b5e2f..532542447d66 100644 --- a/trunk/arch/s390/kernel/ipl.c +++ b/trunk/arch/s390/kernel/ipl.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -23,7 +22,6 @@ #include #include #include -#include #define IPL_PARM_BLOCK_VERSION 0 @@ -123,7 +121,6 @@ enum ipl_method { REIPL_METHOD_FCP_RO_VM, REIPL_METHOD_FCP_DUMP, REIPL_METHOD_NSS, - REIPL_METHOD_NSS_DIAG, REIPL_METHOD_DEFAULT, }; @@ -137,15 +134,14 @@ enum dump_method { static int diag308_set_works = 0; -static struct ipl_parameter_block ipl_block; - static int reipl_capabilities = IPL_TYPE_UNKNOWN; static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; static struct ipl_parameter_block *reipl_block_fcp; static struct ipl_parameter_block *reipl_block_ccw; -static struct ipl_parameter_block *reipl_block_nss; + +static char reipl_nss_name[NSS_NAME_SIZE + 1]; static int dump_capabilities = DUMP_TYPE_NONE; static enum dump_type dump_type = DUMP_TYPE_NONE; @@ -267,56 +263,6 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); -/* VM IPL PARM routines */ -static void reipl_get_ascii_vmparm(char *dest, - const struct ipl_parameter_block *ipb) -{ - int i; - int len = 0; - char has_lowercase = 0; - - if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && - (ipb->ipl_info.ccw.vm_parm_len > 0)) { - - len = ipb->ipl_info.ccw.vm_parm_len; - memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); - /* If at least one character is lowercase, we assume mixed - * case; otherwise we convert everything to lowercase. - */ - for (i = 0; i < len; i++) - if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */ - (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */ - (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */ - has_lowercase = 1; - break; - } - if (!has_lowercase) - EBC_TOLOWER(dest, len); - EBCASC(dest, len); - } - dest[len] = 0; -} - -void get_ipl_vmparm(char *dest) -{ - if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)) - reipl_get_ascii_vmparm(dest, &ipl_block); - else - dest[0] = 0; -} - -static ssize_t ipl_vm_parm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - char parm[DIAG308_VMPARM_SIZE + 1] = {}; - - get_ipl_vmparm(parm); - return sprintf(page, "%s\n", parm); -} - -static struct kobj_attribute sys_ipl_vm_parm_attr = - __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); - static ssize_t sys_ipl_device_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { @@ -339,8 +285,14 @@ static struct kobj_attribute sys_ipl_device_attr = static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - return memory_read_from_buffer(buf, count, &off, IPL_PARMBLOCK_START, - IPL_PARMBLOCK_SIZE); + unsigned int size = IPL_PARMBLOCK_SIZE; + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count); + return count; } static struct bin_attribute ipl_parameter_attr = { @@ -358,7 +310,12 @@ static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *att unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len; void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data; - return memory_read_from_buffer(buf, count, &off, scp_data, size); + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, scp_data + off, count); + return count; } static struct bin_attribute ipl_scp_data_attr = { @@ -413,27 +370,15 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj, static struct kobj_attribute sys_ipl_ccw_loadparm_attr = __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); -static struct attribute *ipl_ccw_attrs_vm[] = { +static struct attribute *ipl_ccw_attrs[] = { &sys_ipl_type_attr.attr, &sys_ipl_device_attr.attr, &sys_ipl_ccw_loadparm_attr.attr, - &sys_ipl_vm_parm_attr.attr, NULL, }; -static struct attribute *ipl_ccw_attrs_lpar[] = { - &sys_ipl_type_attr.attr, - &sys_ipl_device_attr.attr, - &sys_ipl_ccw_loadparm_attr.attr, - NULL, -}; - -static struct attribute_group ipl_ccw_attr_group_vm = { - .attrs = ipl_ccw_attrs_vm, -}; - -static struct attribute_group ipl_ccw_attr_group_lpar = { - .attrs = ipl_ccw_attrs_lpar +static struct attribute_group ipl_ccw_attr_group = { + .attrs = ipl_ccw_attrs, }; /* NSS ipl device attributes */ @@ -443,8 +388,6 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name); static struct attribute *ipl_nss_attrs[] = { &sys_ipl_type_attr.attr, &sys_ipl_nss_name_attr.attr, - &sys_ipl_ccw_loadparm_attr.attr, - &sys_ipl_vm_parm_attr.attr, NULL, }; @@ -507,12 +450,7 @@ static int __init ipl_init(void) } switch (ipl_info.type) { case IPL_TYPE_CCW: - if (MACHINE_IS_VM) - rc = sysfs_create_group(&ipl_kset->kobj, - &ipl_ccw_attr_group_vm); - else - rc = sysfs_create_group(&ipl_kset->kobj, - &ipl_ccw_attr_group_lpar); + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group); break; case IPL_TYPE_FCP: case IPL_TYPE_FCP_DUMP: @@ -543,83 +481,6 @@ static struct shutdown_action __refdata ipl_action = { * reipl shutdown action: Reboot Linux on shutdown. */ -/* VM IPL PARM attributes */ -static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb, - char *page) -{ - char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; - - reipl_get_ascii_vmparm(vmparm, ipb); - return sprintf(page, "%s\n", vmparm); -} - -static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb, - size_t vmparm_max, - const char *buf, size_t len) -{ - int i, ip_len; - - /* ignore trailing newline */ - ip_len = len; - if ((len > 0) && (buf[len - 1] == '\n')) - ip_len--; - - if (ip_len > vmparm_max) - return -EINVAL; - - /* parm is used to store kernel options, check for common chars */ - for (i = 0; i < ip_len; i++) - if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i]))) - return -EINVAL; - - memset(ipb->ipl_info.ccw.vm_parm, 0, DIAG308_VMPARM_SIZE); - ipb->ipl_info.ccw.vm_parm_len = ip_len; - if (ip_len > 0) { - ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID; - memcpy(ipb->ipl_info.ccw.vm_parm, buf, ip_len); - ASCEBC(ipb->ipl_info.ccw.vm_parm, ip_len); - } else { - ipb->ipl_info.ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID; - } - - return len; -} - -/* NSS wrapper */ -static ssize_t reipl_nss_vmparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_vmparm_show(reipl_block_nss, page); -} - -static ssize_t reipl_nss_vmparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len); -} - -/* CCW wrapper */ -static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_vmparm_show(reipl_block_ccw, page); -} - -static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len); -} - -static struct kobj_attribute sys_reipl_nss_vmparm_attr = - __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show, - reipl_nss_vmparm_store); -static struct kobj_attribute sys_reipl_ccw_vmparm_attr = - __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show, - reipl_ccw_vmparm_store); - /* FCP reipl device attributes */ DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", @@ -652,26 +513,27 @@ static struct attribute_group reipl_fcp_attr_group = { DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", reipl_block_ccw->ipl_info.ccw.devno); -static void reipl_get_ascii_loadparm(char *loadparm, - struct ipl_parameter_block *ibp) +static void reipl_get_ascii_loadparm(char *loadparm) { - memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN); + memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, + LOADPARM_LEN); EBCASC(loadparm, LOADPARM_LEN); loadparm[LOADPARM_LEN] = 0; strstrip(loadparm); } -static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb, - char *page) +static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { char buf[LOADPARM_LEN + 1]; - reipl_get_ascii_loadparm(buf, ipb); + reipl_get_ascii_loadparm(buf); return sprintf(page, "%s\n", buf); } -static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, - const char *buf, size_t len) +static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) { int i, lp_len; @@ -690,128 +552,35 @@ static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, return -EINVAL; } /* initialize loadparm with blanks */ - memset(ipb->ipl_info.ccw.load_parm, ' ', LOADPARM_LEN); + memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); /* copy and convert to ebcdic */ - memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len); - ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN); + memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); + ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); return len; } -/* NSS wrapper */ -static ssize_t reipl_nss_loadparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_loadparm_show(reipl_block_nss, page); -} - -static ssize_t reipl_nss_loadparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_loadparm_store(reipl_block_nss, buf, len); -} - -/* CCW wrapper */ -static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_loadparm_show(reipl_block_ccw, page); -} - -static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_loadparm_store(reipl_block_ccw, buf, len); -} - static struct kobj_attribute sys_reipl_ccw_loadparm_attr = - __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show, - reipl_ccw_loadparm_store); + __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, + reipl_ccw_loadparm_store); -static struct attribute *reipl_ccw_attrs_vm[] = { +static struct attribute *reipl_ccw_attrs[] = { &sys_reipl_ccw_device_attr.attr, &sys_reipl_ccw_loadparm_attr.attr, - &sys_reipl_ccw_vmparm_attr.attr, NULL, }; -static struct attribute *reipl_ccw_attrs_lpar[] = { - &sys_reipl_ccw_device_attr.attr, - &sys_reipl_ccw_loadparm_attr.attr, - NULL, -}; - -static struct attribute_group reipl_ccw_attr_group_vm = { - .name = IPL_CCW_STR, - .attrs = reipl_ccw_attrs_vm, -}; - -static struct attribute_group reipl_ccw_attr_group_lpar = { +static struct attribute_group reipl_ccw_attr_group = { .name = IPL_CCW_STR, - .attrs = reipl_ccw_attrs_lpar, + .attrs = reipl_ccw_attrs, }; /* NSS reipl device attributes */ -static void reipl_get_ascii_nss_name(char *dst, - struct ipl_parameter_block *ipb) -{ - memcpy(dst, ipb->ipl_info.ccw.nss_name, NSS_NAME_SIZE); - EBCASC(dst, NSS_NAME_SIZE); - dst[NSS_NAME_SIZE] = 0; -} - -static ssize_t reipl_nss_name_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - char nss_name[NSS_NAME_SIZE + 1] = {}; - reipl_get_ascii_nss_name(nss_name, reipl_block_nss); - return sprintf(page, "%s\n", nss_name); -} - -static ssize_t reipl_nss_name_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - int nss_len; - - /* ignore trailing newline */ - nss_len = len; - if ((len > 0) && (buf[len - 1] == '\n')) - nss_len--; - - if (nss_len > NSS_NAME_SIZE) - return -EINVAL; - - memset(reipl_block_nss->ipl_info.ccw.nss_name, 0x40, NSS_NAME_SIZE); - if (nss_len > 0) { - reipl_block_nss->ipl_info.ccw.vm_flags |= - DIAG308_VM_FLAGS_NSS_VALID; - memcpy(reipl_block_nss->ipl_info.ccw.nss_name, buf, nss_len); - ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, nss_len); - EBC_TOUPPER(reipl_block_nss->ipl_info.ccw.nss_name, nss_len); - } else { - reipl_block_nss->ipl_info.ccw.vm_flags &= - ~DIAG308_VM_FLAGS_NSS_VALID; - } - - return len; -} - -static struct kobj_attribute sys_reipl_nss_name_attr = - __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show, - reipl_nss_name_store); - -static struct kobj_attribute sys_reipl_nss_loadparm_attr = - __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show, - reipl_nss_loadparm_store); +DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); static struct attribute *reipl_nss_attrs[] = { &sys_reipl_nss_name_attr.attr, - &sys_reipl_nss_loadparm_attr.attr, - &sys_reipl_nss_vmparm_attr.attr, NULL, }; @@ -848,10 +617,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_FCP_DUMP; break; case IPL_TYPE_NSS: - if (diag308_set_works) - reipl_method = REIPL_METHOD_NSS_DIAG; - else - reipl_method = REIPL_METHOD_NSS; + reipl_method = REIPL_METHOD_NSS; break; case IPL_TYPE_UNKNOWN: reipl_method = REIPL_METHOD_DEFAULT; @@ -889,38 +655,11 @@ static struct kobj_attribute reipl_type_attr = static struct kset *reipl_kset; -static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, - const enum ipl_method m) -{ - char loadparm[LOADPARM_LEN + 1] = {}; - char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; - char nss_name[NSS_NAME_SIZE + 1] = {}; - size_t pos = 0; - - reipl_get_ascii_loadparm(loadparm, ipb); - reipl_get_ascii_nss_name(nss_name, ipb); - reipl_get_ascii_vmparm(vmparm, ipb); - - switch (m) { - case REIPL_METHOD_CCW_VM: - pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno); - break; - case REIPL_METHOD_NSS: - pos = sprintf(dst, "IPL %s", nss_name); - break; - default: - break; - } - if (strlen(loadparm) > 0) - pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm); - if (strlen(vmparm) > 0) - sprintf(dst + pos, " PARM %s", vmparm); -} - static void reipl_run(struct shutdown_trigger *trigger) { struct ccw_dev_id devid; - static char buf[128]; + static char buf[100]; + char loadparm[LOADPARM_LEN + 1]; switch (reipl_method) { case REIPL_METHOD_CCW_CIO: @@ -929,7 +668,13 @@ static void reipl_run(struct shutdown_trigger *trigger) reipl_ccw_dev(&devid); break; case REIPL_METHOD_CCW_VM: - get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM); + reipl_get_ascii_loadparm(loadparm); + if (strlen(loadparm) == 0) + sprintf(buf, "IPL %X CLEAR", + reipl_block_ccw->ipl_info.ccw.devno); + else + sprintf(buf, "IPL %X CLEAR LOADPARM '%s'", + reipl_block_ccw->ipl_info.ccw.devno, loadparm); __cpcmd(buf, NULL, 0, NULL); break; case REIPL_METHOD_CCW_DIAG: @@ -946,12 +691,8 @@ static void reipl_run(struct shutdown_trigger *trigger) case REIPL_METHOD_FCP_RO_VM: __cpcmd("IPL", NULL, 0, NULL); break; - case REIPL_METHOD_NSS_DIAG: - diag308(DIAG308_SET, reipl_block_nss); - diag308(DIAG308_IPL, NULL); - break; case REIPL_METHOD_NSS: - get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS); + sprintf(buf, "IPL %s", reipl_nss_name); __cpcmd(buf, NULL, 0, NULL); break; case REIPL_METHOD_DEFAULT: @@ -966,36 +707,16 @@ static void reipl_run(struct shutdown_trigger *trigger) disabled_wait((unsigned long) __builtin_return_address(0)); } -static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) +static void __init reipl_probe(void) { - ipb->hdr.len = IPL_PARM_BLK_CCW_LEN; - ipb->hdr.version = IPL_PARM_BLOCK_VERSION; - ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; - ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW; -} + void *buffer; -static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb) -{ - /* LOADPARM */ - /* check if read scp info worked and set loadparm */ - if (sclp_ipl_info.is_valid) - memcpy(ipb->ipl_info.ccw.load_parm, - &sclp_ipl_info.loadparm, LOADPARM_LEN); - else - /* read scp info failed: set empty loadparm (EBCDIC blanks) */ - memset(ipb->ipl_info.ccw.load_parm, 0x40, LOADPARM_LEN); - ipb->hdr.flags = DIAG308_FLAGS_LP_VALID; - - /* VM PARM */ - if (MACHINE_IS_VM && diag308_set_works && - (ipl_block.ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) { - - ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID; - ipb->ipl_info.ccw.vm_parm_len = - ipl_block.ipl_info.ccw.vm_parm_len; - memcpy(ipb->ipl_info.ccw.vm_parm, - ipl_block.ipl_info.ccw.vm_parm, DIAG308_VMPARM_SIZE); - } + buffer = (void *) get_zeroed_page(GFP_KERNEL); + if (!buffer) + return; + if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK) + diag308_set_works = 1; + free_page((unsigned long)buffer); } static int __init reipl_nss_init(void) @@ -1004,31 +725,10 @@ static int __init reipl_nss_init(void) if (!MACHINE_IS_VM) return 0; - - reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL); - if (!reipl_block_nss) - return -ENOMEM; - - if (!diag308_set_works) - sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO; - rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group); if (rc) return rc; - - reipl_block_ccw_init(reipl_block_nss); - if (ipl_info.type == IPL_TYPE_NSS) { - memset(reipl_block_nss->ipl_info.ccw.nss_name, - ' ', NSS_NAME_SIZE); - memcpy(reipl_block_nss->ipl_info.ccw.nss_name, - kernel_nss_name, strlen(kernel_nss_name)); - ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE); - reipl_block_nss->ipl_info.ccw.vm_flags |= - DIAG308_VM_FLAGS_NSS_VALID; - - reipl_block_ccw_fill_parms(reipl_block_nss); - } - + strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); reipl_capabilities |= IPL_TYPE_NSS; return 0; } @@ -1040,27 +740,28 @@ static int __init reipl_ccw_init(void) reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_ccw) return -ENOMEM; - - if (MACHINE_IS_VM) { - if (!diag308_set_works) - sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO; - rc = sysfs_create_group(&reipl_kset->kobj, - &reipl_ccw_attr_group_vm); - } else { - if(!diag308_set_works) - sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; - rc = sysfs_create_group(&reipl_kset->kobj, - &reipl_ccw_attr_group_lpar); - } - if (rc) + rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group); + if (rc) { + free_page((unsigned long)reipl_block_ccw); return rc; - - reipl_block_ccw_init(reipl_block_ccw); - if (ipl_info.type == IPL_TYPE_CCW) { - reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; - reipl_block_ccw_fill_parms(reipl_block_ccw); } - + reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN; + reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; + reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; + reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; + reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID; + /* check if read scp info worked and set loadparm */ + if (sclp_ipl_info.is_valid) + memcpy(reipl_block_ccw->ipl_info.ccw.load_param, + &sclp_ipl_info.loadparm, LOADPARM_LEN); + else + /* read scp info failed: set empty loadparm (EBCDIC blanks) */ + memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, + LOADPARM_LEN); + if (!MACHINE_IS_VM && !diag308_set_works) + sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; + if (ipl_info.type == IPL_TYPE_CCW) + reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; reipl_capabilities |= IPL_TYPE_CCW; return 0; } @@ -1597,6 +1298,7 @@ static void __init shutdown_actions_init(void) static int __init s390_ipl_init(void) { + reipl_probe(); sclp_get_ipl_info(&sclp_ipl_info); shutdown_actions_init(); shutdown_triggers_init(); @@ -1703,12 +1405,6 @@ void __init setup_ipl(void) atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); } -void __init ipl_update_parameters(void) -{ - if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK) - diag308_set_works = 1; -} - void __init ipl_save_parameters(void) { struct cio_iplinfo iplinfo; diff --git a/trunk/arch/s390/kernel/kprobes.c b/trunk/arch/s390/kernel/kprobes.c index 288ad490a6dd..ed04d1372d5d 100644 --- a/trunk/arch/s390/kernel/kprobes.c +++ b/trunk/arch/s390/kernel/kprobes.c @@ -41,8 +41,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if (is_prohibited_opcode((kprobe_opcode_t *) p->addr)) return -EINVAL; - if ((unsigned long)p->addr & 0x01) + if ((unsigned long)p->addr & 0x01) { + printk("Attempt to register kprobe at an unaligned address\n"); return -EINVAL; + } /* Use the get_insn_slot() facility for correctness */ if (!(p->ainsn.insn = get_insn_slot())) diff --git a/trunk/arch/s390/kernel/machine_kexec.c b/trunk/arch/s390/kernel/machine_kexec.c index 131d7ee8b416..3c77dd36994c 100644 --- a/trunk/arch/s390/kernel/machine_kexec.c +++ b/trunk/arch/s390/kernel/machine_kexec.c @@ -52,6 +52,7 @@ void machine_kexec_cleanup(struct kimage *image) void machine_shutdown(void) { + printk(KERN_INFO "kexec: machine_shutdown called\n"); } void machine_kexec(struct kimage *image) diff --git a/trunk/arch/s390/kernel/mem_detect.c b/trunk/arch/s390/kernel/mem_detect.c deleted file mode 100644 index 18ed7abe16c5..000000000000 --- a/trunk/arch/s390/kernel/mem_detect.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright IBM Corp. 2008 - * Author(s): Heiko Carstens - */ - -#include -#include -#include -#include -#include - -static int memory_fast_detect(struct mem_chunk *chunk) -{ - unsigned long val0 = 0; - unsigned long val1 = 0xc; - int rc = -EOPNOTSUPP; - - if (ipl_flags & IPL_NSS_VALID) - return -EOPNOTSUPP; - asm volatile( - " diag %1,%2,0x260\n" - "0: lhi %0,0\n" - "1:\n" - EX_TABLE(0b,1b) - : "+d" (rc), "+d" (val0), "+d" (val1) : : "cc"); - - if (rc || val0 != val1) - return -EOPNOTSUPP; - chunk->size = val0 + 1; - return 0; -} - -static inline int tprot(unsigned long addr) -{ - int rc = -EFAULT; - - asm volatile( - " tprot 0(%1),0\n" - "0: ipm %0\n" - " srl %0,28\n" - "1:\n" - EX_TABLE(0b,1b) - : "+d" (rc) : "a" (addr) : "cc"); - return rc; -} - -#define ADDR2G (1ULL << 31) - -static void find_memory_chunks(struct mem_chunk chunk[]) -{ - unsigned long long memsize, rnmax, rzm; - unsigned long addr = 0, size; - int i = 0, type; - - rzm = sclp_get_rzm(); - rnmax = sclp_get_rnmax(); - memsize = rzm * rnmax; - if (!rzm) - rzm = 1ULL << 17; - if (sizeof(long) == 4) { - rzm = min(ADDR2G, rzm); - memsize = memsize ? min(ADDR2G, memsize) : ADDR2G; - } - do { - size = 0; - type = tprot(addr); - do { - size += rzm; - if (memsize && addr + size >= memsize) - break; - } while (type == tprot(addr + size)); - if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { - chunk[i].addr = addr; - chunk[i].size = size; - chunk[i].type = type; - i++; - } - addr += size; - } while (addr < memsize && i < MEMORY_CHUNKS); -} - -void detect_memory_layout(struct mem_chunk chunk[]) -{ - unsigned long flags, cr0; - - memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); - if (memory_fast_detect(&chunk[0]) == 0) - return; - /* Disable IRQs, DAT and low address protection so tprot does the - * right thing and we don't get scheduled away with low address - * protection disabled. - */ - flags = __raw_local_irq_stnsm(0xf8); - __ctl_store(cr0, 0, 0); - __ctl_clear_bit(0, 28); - find_memory_chunks(chunk); - __ctl_load(cr0, 0, 0); - __raw_local_irq_ssm(flags); -} -EXPORT_SYMBOL(detect_memory_layout); diff --git a/trunk/arch/s390/kernel/process.c b/trunk/arch/s390/kernel/process.c index 85defd01d293..7920861109d2 100644 --- a/trunk/arch/s390/kernel/process.c +++ b/trunk/arch/s390/kernel/process.c @@ -75,19 +75,46 @@ unsigned long thread_saved_pc(struct task_struct *tsk) return sf->gprs[8]; } +/* + * Need to know about CPUs going idle? + */ +static ATOMIC_NOTIFIER_HEAD(idle_chain); DEFINE_PER_CPU(struct s390_idle_data, s390_idle); +int register_idle_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&idle_chain, nb); +} +EXPORT_SYMBOL(register_idle_notifier); + +int unregister_idle_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&idle_chain, nb); +} +EXPORT_SYMBOL(unregister_idle_notifier); + static int s390_idle_enter(void) { struct s390_idle_data *idle; + int nr_calls = 0; + void *hcpu; + int rc; + hcpu = (void *)(long)smp_processor_id(); + rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1, + &nr_calls); + if (rc == NOTIFY_BAD) { + nr_calls--; + __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, + hcpu, nr_calls, NULL); + return rc; + } idle = &__get_cpu_var(s390_idle); spin_lock(&idle->lock); idle->idle_count++; idle->in_idle = 1; idle->idle_enter = get_clock(); spin_unlock(&idle->lock); - vtime_stop_cpu_timer(); return NOTIFY_OK; } @@ -95,12 +122,13 @@ void s390_idle_leave(void) { struct s390_idle_data *idle; - vtime_start_cpu_timer(); idle = &__get_cpu_var(s390_idle); spin_lock(&idle->lock); idle->idle_time += get_clock() - idle->idle_enter; idle->in_idle = 0; spin_unlock(&idle->lock); + atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, + (void *)(long) smp_processor_id()); } extern void s390_handle_mcck(void); diff --git a/trunk/arch/s390/kernel/ptrace.c b/trunk/arch/s390/kernel/ptrace.c index 2815bfe348a6..35827b9bd4d1 100644 --- a/trunk/arch/s390/kernel/ptrace.c +++ b/trunk/arch/s390/kernel/ptrace.c @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include @@ -49,11 +47,6 @@ #include "compat_ptrace.h" #endif -enum s390_regset { - REGSET_GENERAL, - REGSET_FP, -}; - static void FixPerRegisters(struct task_struct *task) { @@ -133,10 +126,24 @@ ptrace_disable(struct task_struct *child) * struct user contain pad bytes that should be read as zeroes. * Lovely... */ -static unsigned long __peek_user(struct task_struct *child, addr_t addr) +static int +peek_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; - addr_t offset, tmp; + addr_t offset, tmp, mask; + + /* + * Stupid gdb peeks/pokes the access registers in 64 bit with + * an alignment of 4. Programmers from hell... + */ + mask = __ADDR_MASK; +#ifdef CONFIG_64BIT + if (addr >= (addr_t) &dummy->regs.acrs && + addr < (addr_t) &dummy->regs.orig_gpr2) + mask = 3; +#endif + if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) + return -EIO; if (addr < (addr_t) &dummy->regs.acrs) { /* @@ -190,18 +197,24 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) } else tmp = 0; - return tmp; + return put_user(tmp, (addr_t __user *) data); } +/* + * Write a word to the user area of a process at location addr. This + * operation does have an additional problem compared to peek_user. + * Stores to the program status word and on the floating point + * control register needs to get checked for validity. + */ static int -peek_user(struct task_struct *child, addr_t addr, addr_t data) +poke_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; - addr_t tmp, mask; + addr_t offset, mask; /* * Stupid gdb peeks/pokes the access registers in 64 bit with - * an alignment of 4. Programmers from hell... + * an alignment of 4. Programmers from hell indeed... */ mask = __ADDR_MASK; #ifdef CONFIG_64BIT @@ -212,21 +225,6 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) return -EIO; - tmp = __peek_user(child, addr); - return put_user(tmp, (addr_t __user *) data); -} - -/* - * Write a word to the user area of a process at location addr. This - * operation does have an additional problem compared to peek_user. - * Stores to the program status word and on the floating point - * control register needs to get checked for validity. - */ -static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user *dummy = NULL; - addr_t offset; - if (addr < (addr_t) &dummy->regs.acrs) { /* * psw and gprs are stored on the stack @@ -294,28 +292,6 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) return 0; } -static int -poke_user(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user *dummy = NULL; - addr_t mask; - - /* - * Stupid gdb peeks/pokes the access registers in 64 bit with - * an alignment of 4. Programmers from hell indeed... - */ - mask = __ADDR_MASK; -#ifdef CONFIG_64BIT - if (addr >= (addr_t) &dummy->regs.acrs && - addr < (addr_t) &dummy->regs.orig_gpr2) - mask = 3; -#endif - if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) - return -EIO; - - return __poke_user(child, addr, data); -} - long arch_ptrace(struct task_struct *child, long request, long addr, long data) { ptrace_area parea; @@ -391,13 +367,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* * Same as peek_user but for a 31 bit program. */ -static u32 __peek_user_compat(struct task_struct *child, addr_t addr) +static int +peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) { struct user32 *dummy32 = NULL; per_struct32 *dummy_per32 = NULL; addr_t offset; __u32 tmp; + if (!test_thread_flag(TIF_31BIT) || + (addr & 3) || addr > sizeof(struct user) - 3) + return -EIO; + if (addr < (addr_t) &dummy32->regs.acrs) { /* * psw and gprs are stored on the stack @@ -454,32 +435,25 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) } else tmp = 0; - return tmp; -} - -static int peek_user_compat(struct task_struct *child, - addr_t addr, addr_t data) -{ - __u32 tmp; - - if (!test_thread_flag(TIF_31BIT) || - (addr & 3) || addr > sizeof(struct user) - 3) - return -EIO; - - tmp = __peek_user_compat(child, addr); return put_user(tmp, (__u32 __user *) data); } /* * Same as poke_user but for a 31 bit program. */ -static int __poke_user_compat(struct task_struct *child, - addr_t addr, addr_t data) +static int +poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) { struct user32 *dummy32 = NULL; per_struct32 *dummy_per32 = NULL; - __u32 tmp = (__u32) data; addr_t offset; + __u32 tmp; + + if (!test_thread_flag(TIF_31BIT) || + (addr & 3) || addr > sizeof(struct user32) - 3) + return -EIO; + + tmp = (__u32) data; if (addr < (addr_t) &dummy32->regs.acrs) { /* @@ -554,16 +528,6 @@ static int __poke_user_compat(struct task_struct *child, return 0; } -static int poke_user_compat(struct task_struct *child, - addr_t addr, addr_t data) -{ - if (!test_thread_flag(TIF_31BIT) || - (addr & 3) || addr > sizeof(struct user32) - 3) - return -EIO; - - return __poke_user_compat(child, addr, data); -} - long compat_arch_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t caddr, compat_ulong_t cdata) { @@ -575,11 +539,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, switch (request) { case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ - return peek_user_compat(child, addr, data); + return peek_user_emu31(child, addr, data); case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - return poke_user_compat(child, addr, data); + return poke_user_emu31(child, addr, data); case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: @@ -591,13 +555,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, copied = 0; while (copied < parea.len) { if (request == PTRACE_PEEKUSR_AREA) - ret = peek_user_compat(child, addr, data); + ret = peek_user_emu31(child, addr, data); else { __u32 utmp; if (get_user(utmp, (__u32 __force __user *) data)) return -EFAULT; - ret = poke_user_compat(child, addr, utmp); + ret = poke_user_emu31(child, addr, utmp); } if (ret) return ret; @@ -646,240 +610,3 @@ syscall_trace(struct pt_regs *regs, int entryexit) regs->gprs[2], regs->orig_gpr2, regs->gprs[3], regs->gprs[4], regs->gprs[5]); } - -/* - * user_regset definitions. - */ - -static int s390_regs_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - unsigned long *k = kbuf; - while (count > 0) { - *k++ = __peek_user(target, pos); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - unsigned long __user *u = ubuf; - while (count > 0) { - if (__put_user(__peek_user(target, pos), u++)) - return -EFAULT; - count -= sizeof(*u); - pos += sizeof(*u); - } - } - return 0; -} - -static int s390_regs_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int rc = 0; - - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - const unsigned long *k = kbuf; - while (count > 0 && !rc) { - rc = __poke_user(target, pos, *k++); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - const unsigned long __user *u = ubuf; - while (count > 0 && !rc) { - unsigned long word; - rc = __get_user(word, u++); - if (rc) - break; - rc = __poke_user(target, pos, word); - count -= sizeof(*u); - pos += sizeof(*u); - } - } - - if (rc == 0 && target == current) - restore_access_regs(target->thread.acrs); - - return rc; -} - -static int s390_fpregs_get(struct task_struct *target, - const struct user_regset *regset, unsigned int pos, - unsigned int count, void *kbuf, void __user *ubuf) -{ - if (target == current) - save_fp_regs(&target->thread.fp_regs); - - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fp_regs, 0, -1); -} - -static int s390_fpregs_set(struct task_struct *target, - const struct user_regset *regset, unsigned int pos, - unsigned int count, const void *kbuf, - const void __user *ubuf) -{ - int rc = 0; - - if (target == current) - save_fp_regs(&target->thread.fp_regs); - - /* If setting FPC, must validate it first. */ - if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) { - u32 fpc[2] = { target->thread.fp_regs.fpc, 0 }; - rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpc, - 0, offsetof(s390_fp_regs, fprs)); - if (rc) - return rc; - if ((fpc[0] & ~FPC_VALID_MASK) != 0 || fpc[1] != 0) - return -EINVAL; - target->thread.fp_regs.fpc = fpc[0]; - } - - if (rc == 0 && count > 0) - rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - target->thread.fp_regs.fprs, - offsetof(s390_fp_regs, fprs), -1); - - if (rc == 0 && target == current) - restore_fp_regs(&target->thread.fp_regs); - - return rc; -} - -static const struct user_regset s390_regsets[] = { - [REGSET_GENERAL] = { - .core_note_type = NT_PRSTATUS, - .n = sizeof(s390_regs) / sizeof(long), - .size = sizeof(long), - .align = sizeof(long), - .get = s390_regs_get, - .set = s390_regs_set, - }, - [REGSET_FP] = { - .core_note_type = NT_PRFPREG, - .n = sizeof(s390_fp_regs) / sizeof(long), - .size = sizeof(long), - .align = sizeof(long), - .get = s390_fpregs_get, - .set = s390_fpregs_set, - }, -}; - -static const struct user_regset_view user_s390_view = { - .name = UTS_MACHINE, - .e_machine = EM_S390, - .regsets = s390_regsets, - .n = ARRAY_SIZE(s390_regsets) -}; - -#ifdef CONFIG_COMPAT -static int s390_compat_regs_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - compat_ulong_t *k = kbuf; - while (count > 0) { - *k++ = __peek_user_compat(target, pos); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - compat_ulong_t __user *u = ubuf; - while (count > 0) { - if (__put_user(__peek_user_compat(target, pos), u++)) - return -EFAULT; - count -= sizeof(*u); - pos += sizeof(*u); - } - } - return 0; -} - -static int s390_compat_regs_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int rc = 0; - - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - const compat_ulong_t *k = kbuf; - while (count > 0 && !rc) { - rc = __poke_user_compat(target, pos, *k++); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - const compat_ulong_t __user *u = ubuf; - while (count > 0 && !rc) { - compat_ulong_t word; - rc = __get_user(word, u++); - if (rc) - break; - rc = __poke_user_compat(target, pos, word); - count -= sizeof(*u); - pos += sizeof(*u); - } - } - - if (rc == 0 && target == current) - restore_access_regs(target->thread.acrs); - - return rc; -} - -static const struct user_regset s390_compat_regsets[] = { - [REGSET_GENERAL] = { - .core_note_type = NT_PRSTATUS, - .n = sizeof(s390_compat_regs) / sizeof(compat_long_t), - .size = sizeof(compat_long_t), - .align = sizeof(compat_long_t), - .get = s390_compat_regs_get, - .set = s390_compat_regs_set, - }, - [REGSET_FP] = { - .core_note_type = NT_PRFPREG, - .n = sizeof(s390_fp_regs) / sizeof(compat_long_t), - .size = sizeof(compat_long_t), - .align = sizeof(compat_long_t), - .get = s390_fpregs_get, - .set = s390_fpregs_set, - }, -}; - -static const struct user_regset_view user_s390_compat_view = { - .name = "s390", - .e_machine = EM_S390, - .regsets = s390_compat_regsets, - .n = ARRAY_SIZE(s390_compat_regsets) -}; -#endif - -const struct user_regset_view *task_user_regset_view(struct task_struct *task) -{ -#ifdef CONFIG_COMPAT - if (test_tsk_thread_flag(task, TIF_31BIT)) - return &user_s390_compat_view; -#endif - return &user_s390_view; -} diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c index b358e18273b0..2bc70b6e876a 100644 --- a/trunk/arch/s390/kernel/setup.c +++ b/trunk/arch/s390/kernel/setup.c @@ -77,7 +77,7 @@ unsigned long machine_flags; unsigned long elf_hwcap = 0; char elf_platform[ELF_PLATFORM_SIZE]; -struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; +struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ static unsigned long __initdata memory_end; @@ -205,6 +205,12 @@ static void __init conmode_default(void) SET_CONSOLE_SCLP; #endif } + } else if (MACHINE_IS_P390) { +#if defined(CONFIG_TN3215_CONSOLE) + SET_CONSOLE_3215; +#elif defined(CONFIG_TN3270_CONSOLE) + SET_CONSOLE_3270; +#endif } else { #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; @@ -215,17 +221,18 @@ static void __init conmode_default(void) #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) static void __init setup_zfcpdump(unsigned int console_devno) { - static char str[41]; + static char str[64]; if (ipl_info.type != IPL_TYPE_FCP_DUMP) return; if (console_devno != -1) - sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x", + sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x", ipl_info.data.fcp.dev_id.devno, console_devno); else - sprintf(str, " cio_ignore=all,!0.0.%04x", + sprintf(str, "cio_ignore=all,!0.0.%04x", ipl_info.data.fcp.dev_id.devno); - strcat(boot_command_line, str); + strcat(COMMAND_LINE, " "); + strcat(COMMAND_LINE, str); console_loglevel = 2; } #else @@ -282,6 +289,32 @@ static int __init early_parse_mem(char *p) } early_param("mem", early_parse_mem); +/* + * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes + */ +static int __init early_parse_ipldelay(char *p) +{ + unsigned long delay = 0; + + delay = simple_strtoul(p, &p, 0); + + switch (*p) { + case 's': + case 'S': + delay *= 1000000; + break; + case 'm': + case 'M': + delay *= 60 * 1000000; + } + + /* now wait for the requested amount of time */ + udelay(delay); + + return 0; +} +early_param("ipldelay", early_parse_ipldelay); + #ifdef CONFIG_S390_SWITCH_AMODE #ifdef CONFIG_PGSTE unsigned int switch_amode = 1; @@ -771,9 +804,11 @@ setup_arch(char **cmdline_p) printk("We are running native (64 bit mode)\n"); #endif /* CONFIG_64BIT */ - /* Have one command line that is parsed and saved in /proc/cmdline */ - /* boot_command_line has been already set up in early.c */ - *cmdline_p = boot_command_line; + /* Save unparsed command line copy for /proc/cmdline */ + strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + + *cmdline_p = COMMAND_LINE; + *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0'; ROOT_DEV = Root_RAM0; diff --git a/trunk/arch/s390/kernel/time.c b/trunk/arch/s390/kernel/time.c index 7418bebb547f..7aec676fefd5 100644 --- a/trunk/arch/s390/kernel/time.c +++ b/trunk/arch/s390/kernel/time.c @@ -3,7 +3,7 @@ * Time of day based timer functions. * * S390 version - * Copyright IBM Corp. 1999, 2008 + * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -163,7 +162,7 @@ void init_cpu_timer(void) /* Enable clock comparator timer interrupt. */ __ctl_set_bit(0,11); - /* Always allow the timing alert external interrupt. */ + /* Always allow ETR external interrupts, even without an ETR. */ __ctl_set_bit(0, 4); } @@ -171,21 +170,8 @@ static void clock_comparator_interrupt(__u16 code) { } -static void etr_timing_alert(struct etr_irq_parm *); -static void stp_timing_alert(struct stp_irq_parm *); - -static void timing_alert_interrupt(__u16 code) -{ - if (S390_lowcore.ext_params & 0x00c40000) - etr_timing_alert((struct etr_irq_parm *) - &S390_lowcore.ext_params); - if (S390_lowcore.ext_params & 0x00038000) - stp_timing_alert((struct stp_irq_parm *) - &S390_lowcore.ext_params); -} - static void etr_reset(void); -static void stp_reset(void); +static void etr_ext_handler(__u16); /* * Get the TOD clock running. @@ -195,7 +181,6 @@ static u64 __init reset_tod_clock(void) u64 time; etr_reset(); - stp_reset(); if (store_clock(&time) == 0) return time; /* TOD clock not running. Set the clock to Unix Epoch. */ @@ -246,9 +231,8 @@ void __init time_init(void) if (clocksource_register(&clocksource_tod) != 0) panic("Could not register TOD clock source"); - /* request the timing alert external interrupt */ - if (register_early_external_interrupt(0x1406, - timing_alert_interrupt, + /* request the etr external interrupt */ + if (register_early_external_interrupt(0x1406, etr_ext_handler, &ext_int_etr_cc) != 0) panic("Couldn't request external interrupt 0x1406"); @@ -260,113 +244,11 @@ void __init time_init(void) #endif } -/* - * The time is "clock". old is what we think the time is. - * Adjust the value by a multiple of jiffies and add the delta to ntp. - * "delay" is an approximation how long the synchronization took. If - * the time correction is positive, then "delay" is subtracted from - * the time difference and only the remaining part is passed to ntp. - */ -static unsigned long long adjust_time(unsigned long long old, - unsigned long long clock, - unsigned long long delay) -{ - unsigned long long delta, ticks; - struct timex adjust; - - if (clock > old) { - /* It is later than we thought. */ - delta = ticks = clock - old; - delta = ticks = (delta < delay) ? 0 : delta - delay; - delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - adjust.offset = ticks * (1000000 / HZ); - } else { - /* It is earlier than we thought. */ - delta = ticks = old - clock; - delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - delta = -delta; - adjust.offset = -ticks * (1000000 / HZ); - } - jiffies_timer_cc += delta; - if (adjust.offset != 0) { - printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", - adjust.offset); - adjust.modes = ADJ_OFFSET_SINGLESHOT; - do_adjtimex(&adjust); - } - return delta; -} - -static DEFINE_PER_CPU(atomic_t, clock_sync_word); -static unsigned long clock_sync_flags; - -#define CLOCK_SYNC_HAS_ETR 0 -#define CLOCK_SYNC_HAS_STP 1 -#define CLOCK_SYNC_ETR 2 -#define CLOCK_SYNC_STP 3 - -/* - * The synchronous get_clock function. It will write the current clock - * value to the clock pointer and return 0 if the clock is in sync with - * the external time source. If the clock mode is local it will return - * -ENOSYS and -EAGAIN if the clock is not in sync with the external - * reference. - */ -int get_sync_clock(unsigned long long *clock) -{ - atomic_t *sw_ptr; - unsigned int sw0, sw1; - - sw_ptr = &get_cpu_var(clock_sync_word); - sw0 = atomic_read(sw_ptr); - *clock = get_clock(); - sw1 = atomic_read(sw_ptr); - put_cpu_var(clock_sync_sync); - if (sw0 == sw1 && (sw0 & 0x80000000U)) - /* Success: time is in sync. */ - return 0; - if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags) && - !test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) - return -ENOSYS; - if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags) && - !test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return -EACCES; - return -EAGAIN; -} -EXPORT_SYMBOL(get_sync_clock); - -/* - * Make get_sync_clock return -EAGAIN. - */ -static void disable_sync_clock(void *dummy) -{ - atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word); - /* - * Clear the in-sync bit 2^31. All get_sync_clock calls will - * fail until the sync bit is turned back on. In addition - * increase the "sequence" counter to avoid the race of an - * etr event and the complete recovery against get_sync_clock. - */ - atomic_clear_mask(0x80000000, sw_ptr); - atomic_inc(sw_ptr); -} - -/* - * Make get_sync_clock return 0 again. - * Needs to be called from a context disabled for preemption. - */ -static void enable_sync_clock(void) -{ - atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word); - atomic_set_mask(0x80000000, sw_ptr); -} - /* * External Time Reference (ETR) code. */ static int etr_port0_online; static int etr_port1_online; -static int etr_steai_available; static int __init early_parse_etr(char *p) { @@ -391,6 +273,12 @@ enum etr_event { ETR_EVENT_UPDATE, }; +enum etr_flags { + ETR_FLAG_ENOSYS, + ETR_FLAG_EACCES, + ETR_FLAG_STEAI, +}; + /* * Valid bit combinations of the eacr register are (x = don't care): * e0 e1 dp p0 p1 ea es sl @@ -417,17 +305,73 @@ enum etr_event { */ static struct etr_eacr etr_eacr; static u64 etr_tolec; /* time of last eacr update */ +static unsigned long etr_flags; static struct etr_aib etr_port0; static int etr_port0_uptodate; static struct etr_aib etr_port1; static int etr_port1_uptodate; static unsigned long etr_events; static struct timer_list etr_timer; +static DEFINE_PER_CPU(atomic_t, etr_sync_word); static void etr_timeout(unsigned long dummy); static void etr_work_fn(struct work_struct *work); static DECLARE_WORK(etr_work, etr_work_fn); +/* + * The etr get_clock function. It will write the current clock value + * to the clock pointer and return 0 if the clock is in sync with the + * external time source. If the clock mode is local it will return + * -ENOSYS and -EAGAIN if the clock is not in sync with the external + * reference. This function is what ETR is all about.. + */ +int get_sync_clock(unsigned long long *clock) +{ + atomic_t *sw_ptr; + unsigned int sw0, sw1; + + sw_ptr = &get_cpu_var(etr_sync_word); + sw0 = atomic_read(sw_ptr); + *clock = get_clock(); + sw1 = atomic_read(sw_ptr); + put_cpu_var(etr_sync_sync); + if (sw0 == sw1 && (sw0 & 0x80000000U)) + /* Success: time is in sync. */ + return 0; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; + if (test_bit(ETR_FLAG_EACCES, &etr_flags)) + return -EACCES; + return -EAGAIN; +} +EXPORT_SYMBOL(get_sync_clock); + +/* + * Make get_sync_clock return -EAGAIN. + */ +static void etr_disable_sync_clock(void *dummy) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + /* + * Clear the in-sync bit 2^31. All get_sync_clock calls will + * fail until the sync bit is turned back on. In addition + * increase the "sequence" counter to avoid the race of an + * etr event and the complete recovery against get_sync_clock. + */ + atomic_clear_mask(0x80000000, sw_ptr); + atomic_inc(sw_ptr); +} + +/* + * Make get_sync_clock return 0 again. + * Needs to be called from a context disabled for preemption. + */ +static void etr_enable_sync_clock(void) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + atomic_set_mask(0x80000000, sw_ptr); +} + /* * Reset ETR attachment. */ @@ -437,13 +381,15 @@ static void etr_reset(void) .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0, .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0, .es = 0, .sl = 0 }; - if (etr_setr(&etr_eacr) == 0) { + if (etr_setr(&etr_eacr) == 0) etr_tolec = get_clock(); - set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags); - } else if (etr_port0_online || etr_port1_online) { - printk(KERN_WARNING "Running on non ETR capable " - "machine, only local mode available.\n"); - etr_port0_online = etr_port1_online = 0; + else { + set_bit(ETR_FLAG_ENOSYS, &etr_flags); + if (etr_port0_online || etr_port1_online) { + printk(KERN_WARNING "Running on non ETR capable " + "machine, only local mode available.\n"); + etr_port0_online = etr_port1_online = 0; + } } } @@ -451,12 +397,14 @@ static int __init etr_init(void) { struct etr_aib aib; - if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags)) + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) return 0; /* Check if this machine has the steai instruction. */ if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) - etr_steai_available = 1; + set_bit(ETR_FLAG_STEAI, &etr_flags); setup_timer(&etr_timer, etr_timeout, 0UL); + if (!etr_port0_online && !etr_port1_online) + set_bit(ETR_FLAG_EACCES, &etr_flags); if (etr_port0_online) { set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); schedule_work(&etr_work); @@ -487,8 +435,7 @@ void etr_switch_to_local(void) { if (!etr_eacr.sl) return; - if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); schedule_work(&etr_work); } @@ -503,21 +450,23 @@ void etr_sync_check(void) { if (!etr_eacr.es) return; - if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); schedule_work(&etr_work); } /* - * ETR timing alert. There are two causes: + * ETR external interrupt. There are two causes: * 1) port state change, check the usability of the port * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the * sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3) * or ETR-data word 4 (edf4) has changed. */ -static void etr_timing_alert(struct etr_irq_parm *intparm) +static void etr_ext_handler(__u16 code) { + struct etr_interruption_parameter *intparm = + (struct etr_interruption_parameter *) &S390_lowcore.ext_params; + if (intparm->pc0) /* ETR port 0 state change. */ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); @@ -642,23 +591,58 @@ static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p) return 1; } -struct clock_sync_data { +/* + * The time is "clock". old is what we think the time is. + * Adjust the value by a multiple of jiffies and add the delta to ntp. + * "delay" is an approximation how long the synchronization took. If + * the time correction is positive, then "delay" is subtracted from + * the time difference and only the remaining part is passed to ntp. + */ +static unsigned long long etr_adjust_time(unsigned long long old, + unsigned long long clock, + unsigned long long delay) +{ + unsigned long long delta, ticks; + struct timex adjust; + + if (clock > old) { + /* It is later than we thought. */ + delta = ticks = clock - old; + delta = ticks = (delta < delay) ? 0 : delta - delay; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + adjust.offset = ticks * (1000000 / HZ); + } else { + /* It is earlier than we thought. */ + delta = ticks = old - clock; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + delta = -delta; + adjust.offset = -ticks * (1000000 / HZ); + } + jiffies_timer_cc += delta; + if (adjust.offset != 0) { + printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", + adjust.offset); + adjust.modes = ADJ_OFFSET_SINGLESHOT; + do_adjtimex(&adjust); + } + return delta; +} + +static struct { int in_sync; unsigned long long fixup_cc; -}; +} etr_sync; -static void clock_sync_cpu_start(void *dummy) +static void etr_sync_cpu_start(void *dummy) { - struct clock_sync_data *sync = dummy; - - enable_sync_clock(); + etr_enable_sync_clock(); /* * This looks like a busy wait loop but it isn't. etr_sync_cpus * is called on all other cpus while the TOD clocks is stopped. * __udelay will stop the cpu on an enabled wait psw until the * TOD is running again. */ - while (sync->in_sync == 0) { + while (etr_sync.in_sync == 0) { __udelay(1); /* * A different cpu changes *in_sync. Therefore use @@ -666,17 +650,17 @@ static void clock_sync_cpu_start(void *dummy) */ barrier(); } - if (sync->in_sync != 1) + if (etr_sync.in_sync != 1) /* Didn't work. Clear per-cpu in sync bit again. */ - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); /* * This round of TOD syncing is done. Set the clock comparator * to the next tick and let the processor continue. */ - fixup_clock_comparator(sync->fixup_cc); + fixup_clock_comparator(etr_sync.fixup_cc); } -static void clock_sync_cpu_end(void *dummy) +static void etr_sync_cpu_end(void *dummy) { } @@ -688,7 +672,6 @@ static void clock_sync_cpu_end(void *dummy) static int etr_sync_clock(struct etr_aib *aib, int port) { struct etr_aib *sync_port; - struct clock_sync_data etr_sync; unsigned long long clock, old_clock, delay, delta; int follows; int rc; @@ -707,9 +690,9 @@ static int etr_sync_clock(struct etr_aib *aib, int port) */ memset(&etr_sync, 0, sizeof(etr_sync)); preempt_disable(); - smp_call_function(clock_sync_cpu_start, &etr_sync, 0, 0); + smp_call_function(etr_sync_cpu_start, NULL, 0, 0); local_irq_disable(); - enable_sync_clock(); + etr_enable_sync_clock(); /* Set clock to next OTE. */ __ctl_set_bit(14, 21); @@ -724,13 +707,13 @@ static int etr_sync_clock(struct etr_aib *aib, int port) /* Adjust Linux timing variables. */ delay = (unsigned long long) (aib->edf2.etv - sync_port->edf2.etv) << 32; - delta = adjust_time(old_clock, clock, delay); + delta = etr_adjust_time(old_clock, clock, delay); etr_sync.fixup_cc = delta; fixup_clock_comparator(delta); /* Verify that the clock is properly set. */ if (!etr_aib_follows(sync_port, aib, port)) { /* Didn't work. */ - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); etr_sync.in_sync = -EAGAIN; rc = -EAGAIN; } else { @@ -741,12 +724,12 @@ static int etr_sync_clock(struct etr_aib *aib, int port) /* Could not set the clock ?!? */ __ctl_clear_bit(0, 29); __ctl_clear_bit(14, 21); - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); etr_sync.in_sync = -EAGAIN; rc = -EAGAIN; } local_irq_enable(); - smp_call_function(clock_sync_cpu_end, NULL, 0, 0); + smp_call_function(etr_sync_cpu_end,NULL,0,0); preempt_enable(); return rc; } @@ -849,7 +832,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, * Do not try to get the alternate port aib if the clock * is not in sync yet. */ - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags) && !eacr.es) + if (!eacr.es) return eacr; /* @@ -857,7 +840,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, * the other port immediately. If only stetr is available the * data-port bit toggle has to be used. */ - if (etr_steai_available) { + if (test_bit(ETR_FLAG_STEAI, &etr_flags)) { if (eacr.p0 && !etr_port0_uptodate) { etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0); etr_port0_uptodate = 1; @@ -926,10 +909,10 @@ static void etr_work_fn(struct work_struct *work) if (!eacr.ea) { /* Both ports offline. Reset everything. */ eacr.dp = eacr.es = eacr.sl = 0; - on_each_cpu(disable_sync_clock, NULL, 0, 1); + on_each_cpu(etr_disable_sync_clock, NULL, 0, 1); del_timer_sync(&etr_timer); etr_update_eacr(eacr); - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); + set_bit(ETR_FLAG_EACCES, &etr_flags); return; } @@ -970,6 +953,7 @@ static void etr_work_fn(struct work_struct *work) eacr.e1 = 1; sync_port = (etr_port0_uptodate && etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) { eacr.sl = 0; eacr.e0 = 0; @@ -978,6 +962,7 @@ static void etr_work_fn(struct work_struct *work) eacr.es = 0; sync_port = (etr_port1_uptodate && etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) { eacr.sl = 1; eacr.e0 = 1; @@ -991,6 +976,7 @@ static void etr_work_fn(struct work_struct *work) eacr.e1 = 1; sync_port = (etr_port0_uptodate && etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) { eacr.sl = 1; eacr.e0 = 0; @@ -999,22 +985,19 @@ static void etr_work_fn(struct work_struct *work) eacr.es = 0; sync_port = (etr_port1_uptodate && etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else { /* Both ports not usable. */ eacr.es = eacr.sl = 0; sync_port = -1; - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); + set_bit(ETR_FLAG_EACCES, &etr_flags); } - if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - eacr.es = 0; - /* * If the clock is in sync just update the eacr and return. * If there is no valid sync port wait for a port update. */ - if (test_bit(CLOCK_SYNC_STP, &clock_sync_flags) || - eacr.es || sync_port < 0) { + if (eacr.es || sync_port < 0) { etr_update_eacr(eacr); etr_set_tolec_timeout(now); return; @@ -1035,13 +1018,11 @@ static void etr_work_fn(struct work_struct *work) * and set up a timer to try again after 0.5 seconds */ etr_update_eacr(eacr); - set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); if (now < etr_tolec + (1600000 << 12) || etr_sync_clock(&aib, sync_port) != 0) { /* Sync failed. Try again in 1/2 second. */ eacr.es = 0; etr_update_eacr(eacr); - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); etr_set_sync_timeout(); } else etr_set_tolec_timeout(now); @@ -1116,8 +1097,8 @@ static ssize_t etr_online_store(struct sys_device *dev, value = simple_strtoul(buf, NULL, 0); if (value != 0 && value != 1) return -EINVAL; - if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags)) - return -EOPNOTSUPP; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; if (dev == &etr_port0_dev) { if (etr_port0_online == value) return count; /* Nothing to do. */ @@ -1311,318 +1292,3 @@ static int __init etr_init_sysfs(void) } device_initcall(etr_init_sysfs); - -/* - * Server Time Protocol (STP) code. - */ -static int stp_online; -static struct stp_sstpi stp_info; -static void *stp_page; - -static void stp_work_fn(struct work_struct *work); -static DECLARE_WORK(stp_work, stp_work_fn); - -static int __init early_parse_stp(char *p) -{ - if (strncmp(p, "off", 3) == 0) - stp_online = 0; - else if (strncmp(p, "on", 2) == 0) - stp_online = 1; - return 0; -} -early_param("stp", early_parse_stp); - -/* - * Reset STP attachment. - */ -static void stp_reset(void) -{ - int rc; - - stp_page = alloc_bootmem_pages(PAGE_SIZE); - rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); - if (rc == 1) - set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); - else if (stp_online) { - printk(KERN_WARNING "Running on non STP capable machine.\n"); - free_bootmem((unsigned long) stp_page, PAGE_SIZE); - stp_page = NULL; - stp_online = 0; - } -} - -static int __init stp_init(void) -{ - if (test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online) - schedule_work(&stp_work); - return 0; -} - -arch_initcall(stp_init); - -/* - * STP timing alert. There are three causes: - * 1) timing status change - * 2) link availability change - * 3) time control parameter change - * In all three cases we are only interested in the clock source state. - * If a STP clock source is now available use it. - */ -static void stp_timing_alert(struct stp_irq_parm *intparm) -{ - if (intparm->tsc || intparm->lac || intparm->tcpc) - schedule_work(&stp_work); -} - -/* - * STP sync check machine check. This is called when the timing state - * changes from the synchronized state to the unsynchronized state. - * After a STP sync check the clock is not in sync. The machine check - * is broadcasted to all cpus at the same time. - */ -void stp_sync_check(void) -{ - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return; - disable_sync_clock(NULL); - schedule_work(&stp_work); -} - -/* - * STP island condition machine check. This is called when an attached - * server attempts to communicate over an STP link and the servers - * have matching CTN ids and have a valid stratum-1 configuration - * but the configurations do not match. - */ -void stp_island_check(void) -{ - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return; - disable_sync_clock(NULL); - schedule_work(&stp_work); -} - -/* - * STP tasklet. Check for the STP state and take over the clock - * synchronization if the STP clock source is usable. - */ -static void stp_work_fn(struct work_struct *work) -{ - struct clock_sync_data stp_sync; - unsigned long long old_clock, delta; - int rc; - - if (!stp_online) { - chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); - return; - } - - rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); - if (rc) - return; - - rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); - if (rc || stp_info.c == 0) - return; - - /* - * Catch all other cpus and make them wait until we have - * successfully synced the clock. smp_call_function will - * return after all other cpus are in clock_sync_cpu_start. - */ - memset(&stp_sync, 0, sizeof(stp_sync)); - preempt_disable(); - smp_call_function(clock_sync_cpu_start, &stp_sync, 0, 0); - local_irq_disable(); - enable_sync_clock(); - - set_bit(CLOCK_SYNC_STP, &clock_sync_flags); - if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - schedule_work(&etr_work); - - rc = 0; - if (stp_info.todoff[0] || stp_info.todoff[1] || - stp_info.todoff[2] || stp_info.todoff[3] || - stp_info.tmd != 2) { - old_clock = get_clock(); - rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0); - if (rc == 0) { - delta = adjust_time(old_clock, get_clock(), 0); - fixup_clock_comparator(delta); - rc = chsc_sstpi(stp_page, &stp_info, - sizeof(struct stp_sstpi)); - if (rc == 0 && stp_info.tmd != 2) - rc = -EAGAIN; - } - } - if (rc) { - disable_sync_clock(NULL); - stp_sync.in_sync = -EAGAIN; - clear_bit(CLOCK_SYNC_STP, &clock_sync_flags); - if (etr_port0_online || etr_port1_online) - schedule_work(&etr_work); - } else - stp_sync.in_sync = 1; - - local_irq_enable(); - smp_call_function(clock_sync_cpu_end, NULL, 0, 0); - preempt_enable(); -} - -/* - * STP class sysfs interface functions - */ -static struct sysdev_class stp_sysclass = { - .name = "stp", -}; - -static ssize_t stp_ctn_id_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%016llx\n", - *(unsigned long long *) stp_info.ctnid); -} - -static SYSDEV_CLASS_ATTR(ctn_id, 0400, stp_ctn_id_show, NULL); - -static ssize_t stp_ctn_type_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", stp_info.ctn); -} - -static SYSDEV_CLASS_ATTR(ctn_type, 0400, stp_ctn_type_show, NULL); - -static ssize_t stp_dst_offset_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x2000)) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.dsto); -} - -static SYSDEV_CLASS_ATTR(dst_offset, 0400, stp_dst_offset_show, NULL); - -static ssize_t stp_leap_seconds_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x8000)) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.leaps); -} - -static SYSDEV_CLASS_ATTR(leap_seconds, 0400, stp_leap_seconds_show, NULL); - -static ssize_t stp_stratum_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.stratum); -} - -static SYSDEV_CLASS_ATTR(stratum, 0400, stp_stratum_show, NULL); - -static ssize_t stp_time_offset_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x0800)) - return -ENODATA; - return sprintf(buf, "%i\n", (int) stp_info.tto); -} - -static SYSDEV_CLASS_ATTR(time_offset, 0400, stp_time_offset_show, NULL); - -static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x4000)) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.tzo); -} - -static SYSDEV_CLASS_ATTR(time_zone_offset, 0400, - stp_time_zone_offset_show, NULL); - -static ssize_t stp_timing_mode_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", stp_info.tmd); -} - -static SYSDEV_CLASS_ATTR(timing_mode, 0400, stp_timing_mode_show, NULL); - -static ssize_t stp_timing_state_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", stp_info.tst); -} - -static SYSDEV_CLASS_ATTR(timing_state, 0400, stp_timing_state_show, NULL); - -static ssize_t stp_online_show(struct sysdev_class *class, char *buf) -{ - return sprintf(buf, "%i\n", stp_online); -} - -static ssize_t stp_online_store(struct sysdev_class *class, - const char *buf, size_t count) -{ - unsigned int value; - - value = simple_strtoul(buf, NULL, 0); - if (value != 0 && value != 1) - return -EINVAL; - if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) - return -EOPNOTSUPP; - stp_online = value; - schedule_work(&stp_work); - return count; -} - -/* - * Can't use SYSDEV_CLASS_ATTR because the attribute should be named - * stp/online but attr_online already exists in this file .. - */ -static struct sysdev_class_attribute attr_stp_online = { - .attr = { .name = "online", .mode = 0600 }, - .show = stp_online_show, - .store = stp_online_store, -}; - -static struct sysdev_class_attribute *stp_attributes[] = { - &attr_ctn_id, - &attr_ctn_type, - &attr_dst_offset, - &attr_leap_seconds, - &attr_stp_online, - &attr_stratum, - &attr_time_offset, - &attr_time_zone_offset, - &attr_timing_mode, - &attr_timing_state, - NULL -}; - -static int __init stp_init_sysfs(void) -{ - struct sysdev_class_attribute **attr; - int rc; - - rc = sysdev_class_register(&stp_sysclass); - if (rc) - goto out; - for (attr = stp_attributes; *attr; attr++) { - rc = sysdev_class_create_file(&stp_sysclass, *attr); - if (rc) - goto out_unreg; - } - return 0; -out_unreg: - for (; attr >= stp_attributes; attr--) - sysdev_class_remove_file(&stp_sysclass, *attr); - sysdev_class_unregister(&stp_sysclass); -out: - return rc; -} - -device_initcall(stp_init_sysfs); diff --git a/trunk/arch/s390/kernel/topology.c b/trunk/arch/s390/kernel/topology.c index 212d618b0095..661a07217057 100644 --- a/trunk/arch/s390/kernel/topology.c +++ b/trunk/arch/s390/kernel/topology.c @@ -313,6 +313,8 @@ void __init s390_init_cpu_topology(void) machine_has_topology_irq = 1; tl_info = alloc_bootmem_pages(PAGE_SIZE); + if (!tl_info) + goto error; info = tl_info; stsi(info, 15, 1, 2); diff --git a/trunk/arch/s390/kernel/vtime.c b/trunk/arch/s390/kernel/vtime.c index 0fa5dc5d68e1..ca90ee3f930e 100644 --- a/trunk/arch/s390/kernel/vtime.c +++ b/trunk/arch/s390/kernel/vtime.c @@ -136,7 +136,7 @@ static inline void set_vtimer(__u64 expires) } #endif -void vtime_start_cpu_timer(void) +static void start_cpu_timer(void) { struct vtimer_queue *vt_list; @@ -150,7 +150,7 @@ void vtime_start_cpu_timer(void) set_vtimer(vt_list->idle); } -void vtime_stop_cpu_timer(void) +static void stop_cpu_timer(void) { struct vtimer_queue *vt_list; @@ -318,7 +318,8 @@ static void internal_add_vtimer(struct vtimer_list *timer) vt_list = &per_cpu(virt_cpu_timer, timer->cpu); spin_lock_irqsave(&vt_list->lock, flags); - BUG_ON(timer->cpu != smp_processor_id()); + if (timer->cpu != smp_processor_id()) + printk("internal_add_vtimer: BUG, running on wrong CPU"); /* if list is empty we only have to set the timer */ if (list_empty(&vt_list->list)) { @@ -352,12 +353,25 @@ static void internal_add_vtimer(struct vtimer_list *timer) put_cpu(); } -static inline void prepare_vtimer(struct vtimer_list *timer) +static inline int prepare_vtimer(struct vtimer_list *timer) { - BUG_ON(!timer->function); - BUG_ON(!timer->expires || timer->expires > VTIMER_MAX_SLICE); - BUG_ON(vtimer_pending(timer)); + if (!timer->function) { + printk("add_virt_timer: uninitialized timer\n"); + return -EINVAL; + } + + if (!timer->expires || timer->expires > VTIMER_MAX_SLICE) { + printk("add_virt_timer: invalid timer expire value!\n"); + return -EINVAL; + } + + if (vtimer_pending(timer)) { + printk("add_virt_timer: timer pending\n"); + return -EBUSY; + } + timer->cpu = get_cpu(); + return 0; } /* @@ -368,7 +382,10 @@ void add_virt_timer(void *new) struct vtimer_list *timer; timer = (struct vtimer_list *)new; - prepare_vtimer(timer); + + if (prepare_vtimer(timer) < 0) + return; + timer->interval = 0; internal_add_vtimer(timer); } @@ -382,7 +399,10 @@ void add_virt_timer_periodic(void *new) struct vtimer_list *timer; timer = (struct vtimer_list *)new; - prepare_vtimer(timer); + + if (prepare_vtimer(timer) < 0) + return; + timer->interval = timer->expires; internal_add_vtimer(timer); } @@ -403,8 +423,15 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) unsigned long flags; int cpu; - BUG_ON(!timer->function); - BUG_ON(!expires || expires > VTIMER_MAX_SLICE); + if (!timer->function) { + printk("mod_virt_timer: uninitialized timer\n"); + return -EINVAL; + } + + if (!expires || expires > VTIMER_MAX_SLICE) { + printk("mod_virt_timer: invalid expire range\n"); + return -EINVAL; + } /* * This is a common optimization triggered by the @@ -417,9 +444,6 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) cpu = get_cpu(); vt_list = &per_cpu(virt_cpu_timer, cpu); - /* check if we run on the right CPU */ - BUG_ON(timer->cpu != cpu); - /* disable interrupts before test if timer is pending */ spin_lock_irqsave(&vt_list->lock, flags); @@ -434,6 +458,14 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) return 0; } + /* check if we run on the right CPU */ + if (timer->cpu != cpu) { + printk("mod_virt_timer: running on wrong CPU, check your code\n"); + spin_unlock_irqrestore(&vt_list->lock, flags); + put_cpu(); + return -EINVAL; + } + list_del_init(&timer->entry); timer->expires = expires; @@ -504,6 +536,24 @@ void init_cpu_vtimer(void) } +static int vtimer_idle_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + switch (action) { + case S390_CPU_IDLE: + stop_cpu_timer(); + break; + case S390_CPU_NOT_IDLE: + start_cpu_timer(); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block vtimer_idle_nb = { + .notifier_call = vtimer_idle_notify, +}; + void __init vtime_init(void) { /* request the cpu timer external interrupt */ @@ -511,6 +561,9 @@ void __init vtime_init(void) &ext_int_info_timer) != 0) panic("Couldn't request external interrupt 0x1005"); + if (register_idle_notifier(&vtimer_idle_nb)) + panic("Couldn't register idle notifier"); + /* Enable cpu timer interrupts on the boot cpu. */ init_cpu_vtimer(); } diff --git a/trunk/arch/s390/mm/init.c b/trunk/arch/s390/mm/init.c index 388cc7420055..05598649b326 100644 --- a/trunk/arch/s390/mm/init.c +++ b/trunk/arch/s390/mm/init.c @@ -202,22 +202,3 @@ void free_initrd_mem(unsigned long start, unsigned long end) } } #endif - -#ifdef CONFIG_MEMORY_HOTPLUG -int arch_add_memory(int nid, u64 start, u64 size) -{ - struct pglist_data *pgdat; - struct zone *zone; - int rc; - - pgdat = NODE_DATA(nid); - zone = pgdat->node_zones + ZONE_NORMAL; - rc = vmem_add_mapping(start, size); - if (rc) - return rc; - rc = __add_pages(zone, PFN_DOWN(start), PFN_DOWN(size)); - if (rc) - vmem_remove_mapping(start, size); - return rc; -} -#endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/trunk/arch/x86/kernel/traps_64.c b/trunk/arch/x86/kernel/traps_64.c index f1a95d105953..adff76ea97c4 100644 --- a/trunk/arch/x86/kernel/traps_64.c +++ b/trunk/arch/x86/kernel/traps_64.c @@ -104,7 +104,30 @@ int kstack_depth_to_print = 12; void printk_address(unsigned long address, int reliable) { - printk(" [<%016lx>] %s%pS\n", address, reliable ? "": "? ", (void *) address); +#ifdef CONFIG_KALLSYMS + unsigned long offset = 0, symsize; + const char *symname; + char *modname; + char *delim = ":"; + char namebuf[KSYM_NAME_LEN]; + char reliab[4] = ""; + + symname = kallsyms_lookup(address, &symsize, &offset, + &modname, namebuf); + if (!symname) { + printk(" [<%016lx>]\n", address); + return; + } + if (!reliable) + strcpy(reliab, "? "); + + if (!modname) + modname = delim = ""; + printk(" [<%016lx>] %s%s%s%s%s+0x%lx/0x%lx\n", + address, reliab, delim, modname, delim, symname, offset, symsize); +#else + printk(" [<%016lx>]\n", address); +#endif } static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, diff --git a/trunk/block/Kconfig b/trunk/block/Kconfig index 1ab7c15c8d7a..3e97f2bc446f 100644 --- a/trunk/block/Kconfig +++ b/trunk/block/Kconfig @@ -81,18 +81,6 @@ config BLK_DEV_BSG If unsure, say N. -config BLK_DEV_INTEGRITY - bool "Block layer data integrity support" - ---help--- - Some storage devices allow extra information to be - stored/retrieved to help protect the data. The block layer - data integrity option provides hooks which can be used by - filesystems to ensure better data integrity. - - Say yes here if you have a storage device that provides the - T10/SCSI Data Integrity Field or the T13/ATA External Path - Protection. If in doubt, say N. - endif # BLOCK config BLOCK_COMPAT diff --git a/trunk/block/Makefile b/trunk/block/Makefile index 208000b0750d..5a43c7d79594 100644 --- a/trunk/block/Makefile +++ b/trunk/block/Makefile @@ -4,8 +4,7 @@ obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \ - blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o \ - cmd-filter.o + blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o obj-$(CONFIG_BLK_DEV_BSG) += bsg.o obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o @@ -15,4 +14,3 @@ obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o -obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o diff --git a/trunk/block/as-iosched.c b/trunk/block/as-iosched.c index 9735acb5b4f5..743f33a01a07 100644 --- a/trunk/block/as-iosched.c +++ b/trunk/block/as-iosched.c @@ -151,7 +151,6 @@ enum arq_state { static DEFINE_PER_CPU(unsigned long, ioc_count); static struct completion *ioc_gone; -static DEFINE_SPINLOCK(ioc_gone_lock); static void as_move_to_dispatch(struct as_data *ad, struct request *rq); static void as_antic_stop(struct as_data *ad); @@ -165,19 +164,8 @@ static void free_as_io_context(struct as_io_context *aic) { kfree(aic); elv_ioc_count_dec(ioc_count); - if (ioc_gone) { - /* - * AS scheduler is exiting, grab exit lock and check - * the pending io context count. If it hits zero, - * complete ioc_gone and set it back to NULL. - */ - spin_lock(&ioc_gone_lock); - if (ioc_gone && !elv_ioc_count_read(ioc_count)) { - complete(ioc_gone); - ioc_gone = NULL; - } - spin_unlock(&ioc_gone_lock); - } + if (ioc_gone && !elv_ioc_count_read(ioc_count)) + complete(ioc_gone); } static void as_trim(struct io_context *ioc) @@ -1505,7 +1493,7 @@ static void __exit as_exit(void) /* ioc_gone's update must be visible before reading ioc_count */ smp_wmb(); if (elv_ioc_count_read(ioc_count)) - wait_for_completion(&all_gone); + wait_for_completion(ioc_gone); synchronize_rcu(); } diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c index dbc7f42b5d2b..1905aaba49fb 100644 --- a/trunk/block/blk-core.c +++ b/trunk/block/blk-core.c @@ -143,10 +143,6 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio->bi_size -= nbytes; bio->bi_sector += (nbytes >> 9); - - if (bio_integrity(bio)) - bio_integrity_advance(bio, nbytes); - if (bio->bi_size == 0) bio_endio(bio, error); } else { @@ -205,7 +201,8 @@ void blk_plug_device(struct request_queue *q) if (blk_queue_stopped(q)) return; - if (!queue_flag_test_and_set(QUEUE_FLAG_PLUGGED, q)) { + if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) { + __set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); mod_timer(&q->unplug_timer, jiffies + q->unplug_delay); blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG); } @@ -220,9 +217,10 @@ int blk_remove_plug(struct request_queue *q) { WARN_ON(!irqs_disabled()); - if (!queue_flag_test_and_clear(QUEUE_FLAG_PLUGGED, q)) + if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) return 0; + queue_flag_clear(QUEUE_FLAG_PLUGGED, q); del_timer(&q->unplug_timer); return 1; } @@ -326,7 +324,8 @@ void blk_start_queue(struct request_queue *q) * one level of recursion is ok and is much faster than kicking * the unplug handling */ - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { + if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { + queue_flag_set(QUEUE_FLAG_REENTER, q); q->request_fn(q); queue_flag_clear(QUEUE_FLAG_REENTER, q); } else { @@ -391,7 +390,8 @@ void __blk_run_queue(struct request_queue *q) * handling reinvoke the handler shortly if we already got there. */ if (!elv_queue_empty(q)) { - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { + if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { + queue_flag_set(QUEUE_FLAG_REENTER, q); q->request_fn(q); queue_flag_clear(QUEUE_FLAG_REENTER, q); } else { @@ -1381,9 +1381,6 @@ static inline void __generic_make_request(struct bio *bio) */ blk_partition_remap(bio); - if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) - goto end_io; - if (old_sector != -1) blk_add_trace_remap(q, bio, old_dev, bio->bi_sector, old_sector); diff --git a/trunk/block/blk-integrity.c b/trunk/block/blk-integrity.c deleted file mode 100644 index 3f1a8478cc38..000000000000 --- a/trunk/block/blk-integrity.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * blk-integrity.c - Block layer data integrity extensions - * - * Copyright (C) 2007, 2008 Oracle Corporation - * Written by: Martin K. Petersen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - */ - -#include -#include -#include -#include - -#include "blk.h" - -static struct kmem_cache *integrity_cachep; - -/** - * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements - * @rq: request with integrity metadata attached - * - * Description: Returns the number of elements required in a - * scatterlist corresponding to the integrity metadata in a request. - */ -int blk_rq_count_integrity_sg(struct request *rq) -{ - struct bio_vec *iv, *ivprv; - struct req_iterator iter; - unsigned int segments; - - ivprv = NULL; - segments = 0; - - rq_for_each_integrity_segment(iv, rq, iter) { - - if (!ivprv || !BIOVEC_PHYS_MERGEABLE(ivprv, iv)) - segments++; - - ivprv = iv; - } - - return segments; -} -EXPORT_SYMBOL(blk_rq_count_integrity_sg); - -/** - * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist - * @rq: request with integrity metadata attached - * @sglist: target scatterlist - * - * Description: Map the integrity vectors in request into a - * scatterlist. The scatterlist must be big enough to hold all - * elements. I.e. sized using blk_rq_count_integrity_sg(). - */ -int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist) -{ - struct bio_vec *iv, *ivprv; - struct req_iterator iter; - struct scatterlist *sg; - unsigned int segments; - - ivprv = NULL; - sg = NULL; - segments = 0; - - rq_for_each_integrity_segment(iv, rq, iter) { - - if (ivprv) { - if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) - goto new_segment; - - sg->length += iv->bv_len; - } else { -new_segment: - if (!sg) - sg = sglist; - else { - sg->page_link &= ~0x02; - sg = sg_next(sg); - } - - sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset); - segments++; - } - - ivprv = iv; - } - - if (sg) - sg_mark_end(sg); - - return segments; -} -EXPORT_SYMBOL(blk_rq_map_integrity_sg); - -/** - * blk_integrity_compare - Compare integrity profile of two block devices - * @b1: Device to compare - * @b2: Device to compare - * - * Description: Meta-devices like DM and MD need to verify that all - * sub-devices use the same integrity format before advertising to - * upper layers that they can send/receive integrity metadata. This - * function can be used to check whether two block devices have - * compatible integrity formats. - */ -int blk_integrity_compare(struct block_device *bd1, struct block_device *bd2) -{ - struct blk_integrity *b1 = bd1->bd_disk->integrity; - struct blk_integrity *b2 = bd2->bd_disk->integrity; - - BUG_ON(bd1->bd_disk == NULL); - BUG_ON(bd2->bd_disk == NULL); - - if (!b1 || !b2) - return 0; - - if (b1->sector_size != b2->sector_size) { - printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->sector_size, b2->sector_size); - return -1; - } - - if (b1->tuple_size != b2->tuple_size) { - printk(KERN_ERR "%s: %s/%s tuple sz %u != %u\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->tuple_size, b2->tuple_size); - return -1; - } - - if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) { - printk(KERN_ERR "%s: %s/%s tag sz %u != %u\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->tag_size, b2->tag_size); - return -1; - } - - if (strcmp(b1->name, b2->name)) { - printk(KERN_ERR "%s: %s/%s type %s != %s\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->name, b2->name); - return -1; - } - - return 0; -} -EXPORT_SYMBOL(blk_integrity_compare); - -struct integrity_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_integrity *, char *); - ssize_t (*store)(struct blk_integrity *, const char *, size_t); -}; - -static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr, - char *page) -{ - struct blk_integrity *bi = - container_of(kobj, struct blk_integrity, kobj); - struct integrity_sysfs_entry *entry = - container_of(attr, struct integrity_sysfs_entry, attr); - - return entry->show(bi, page); -} - -static ssize_t integrity_attr_store(struct kobject *kobj, - struct attribute *attr, const char *page, - size_t count) -{ - struct blk_integrity *bi = - container_of(kobj, struct blk_integrity, kobj); - struct integrity_sysfs_entry *entry = - container_of(attr, struct integrity_sysfs_entry, attr); - ssize_t ret = 0; - - if (entry->store) - ret = entry->store(bi, page, count); - - return ret; -} - -static ssize_t integrity_format_show(struct blk_integrity *bi, char *page) -{ - if (bi != NULL && bi->name != NULL) - return sprintf(page, "%s\n", bi->name); - else - return sprintf(page, "none\n"); -} - -static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page) -{ - if (bi != NULL) - return sprintf(page, "%u\n", bi->tag_size); - else - return sprintf(page, "0\n"); -} - -static ssize_t integrity_read_store(struct blk_integrity *bi, - const char *page, size_t count) -{ - char *p = (char *) page; - unsigned long val = simple_strtoul(p, &p, 10); - - if (val) - bi->flags |= INTEGRITY_FLAG_READ; - else - bi->flags &= ~INTEGRITY_FLAG_READ; - - return count; -} - -static ssize_t integrity_read_show(struct blk_integrity *bi, char *page) -{ - return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_READ) != 0); -} - -static ssize_t integrity_write_store(struct blk_integrity *bi, - const char *page, size_t count) -{ - char *p = (char *) page; - unsigned long val = simple_strtoul(p, &p, 10); - - if (val) - bi->flags |= INTEGRITY_FLAG_WRITE; - else - bi->flags &= ~INTEGRITY_FLAG_WRITE; - - return count; -} - -static ssize_t integrity_write_show(struct blk_integrity *bi, char *page) -{ - return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_WRITE) != 0); -} - -static struct integrity_sysfs_entry integrity_format_entry = { - .attr = { .name = "format", .mode = S_IRUGO }, - .show = integrity_format_show, -}; - -static struct integrity_sysfs_entry integrity_tag_size_entry = { - .attr = { .name = "tag_size", .mode = S_IRUGO }, - .show = integrity_tag_size_show, -}; - -static struct integrity_sysfs_entry integrity_read_entry = { - .attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR }, - .show = integrity_read_show, - .store = integrity_read_store, -}; - -static struct integrity_sysfs_entry integrity_write_entry = { - .attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR }, - .show = integrity_write_show, - .store = integrity_write_store, -}; - -static struct attribute *integrity_attrs[] = { - &integrity_format_entry.attr, - &integrity_tag_size_entry.attr, - &integrity_read_entry.attr, - &integrity_write_entry.attr, - NULL, -}; - -static struct sysfs_ops integrity_ops = { - .show = &integrity_attr_show, - .store = &integrity_attr_store, -}; - -static int __init blk_dev_integrity_init(void) -{ - integrity_cachep = kmem_cache_create("blkdev_integrity", - sizeof(struct blk_integrity), - 0, SLAB_PANIC, NULL); - return 0; -} -subsys_initcall(blk_dev_integrity_init); - -static void blk_integrity_release(struct kobject *kobj) -{ - struct blk_integrity *bi = - container_of(kobj, struct blk_integrity, kobj); - - kmem_cache_free(integrity_cachep, bi); -} - -static struct kobj_type integrity_ktype = { - .default_attrs = integrity_attrs, - .sysfs_ops = &integrity_ops, - .release = blk_integrity_release, -}; - -/** - * blk_integrity_register - Register a gendisk as being integrity-capable - * @disk: struct gendisk pointer to make integrity-aware - * @template: integrity profile - * - * Description: When a device needs to advertise itself as being able - * to send/receive integrity metadata it must use this function to - * register the capability with the block layer. The template is a - * blk_integrity struct with values appropriate for the underlying - * hardware. See Documentation/block/data-integrity.txt. - */ -int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) -{ - struct blk_integrity *bi; - - BUG_ON(disk == NULL); - BUG_ON(template == NULL); - - if (disk->integrity == NULL) { - bi = kmem_cache_alloc(integrity_cachep, - GFP_KERNEL | __GFP_ZERO); - if (!bi) - return -1; - - if (kobject_init_and_add(&bi->kobj, &integrity_ktype, - &disk->dev.kobj, "%s", "integrity")) { - kmem_cache_free(integrity_cachep, bi); - return -1; - } - - kobject_uevent(&bi->kobj, KOBJ_ADD); - - bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE; - bi->sector_size = disk->queue->hardsect_size; - disk->integrity = bi; - } else - bi = disk->integrity; - - /* Use the provided profile as template */ - bi->name = template->name; - bi->generate_fn = template->generate_fn; - bi->verify_fn = template->verify_fn; - bi->tuple_size = template->tuple_size; - bi->set_tag_fn = template->set_tag_fn; - bi->get_tag_fn = template->get_tag_fn; - bi->tag_size = template->tag_size; - - return 0; -} -EXPORT_SYMBOL(blk_integrity_register); - -/** - * blk_integrity_unregister - Remove block integrity profile - * @disk: disk whose integrity profile to deallocate - * - * Description: This function frees all memory used by the block - * integrity profile. To be called at device teardown. - */ -void blk_integrity_unregister(struct gendisk *disk) -{ - struct blk_integrity *bi; - - if (!disk || !disk->integrity) - return; - - bi = disk->integrity; - - kobject_uevent(&bi->kobj, KOBJ_REMOVE); - kobject_del(&bi->kobj); - kobject_put(&disk->dev.kobj); - kmem_cache_free(integrity_cachep, bi); -} -EXPORT_SYMBOL(blk_integrity_unregister); diff --git a/trunk/block/blk-map.c b/trunk/block/blk-map.c index ddd96fb11a7d..0b1af5a3537c 100644 --- a/trunk/block/blk-map.c +++ b/trunk/block/blk-map.c @@ -210,7 +210,6 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, if (!bio_flagged(bio, BIO_USER_MAPPED)) rq->cmd_flags |= REQ_COPY_USER; - blk_queue_bounce(q, &bio); bio_get(bio); blk_rq_bio_prep(q, rq, bio); rq->buffer = rq->data = NULL; @@ -269,7 +268,6 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, int reading = rq_data_dir(rq) == READ; int do_copy = 0; struct bio *bio; - unsigned long stack_mask = ~(THREAD_SIZE - 1); if (len > (q->max_hw_sectors << 9)) return -EINVAL; @@ -280,10 +278,6 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, alignment = queue_dma_alignment(q) | q->dma_pad_mask; do_copy = ((kaddr & alignment) || (len & alignment)); - if (!((kaddr & stack_mask) ^ - ((unsigned long)current->stack & stack_mask))) - do_copy = 1; - if (do_copy) bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading); else diff --git a/trunk/block/blk-merge.c b/trunk/block/blk-merge.c index 5efc9e7a68b7..651136aae76e 100644 --- a/trunk/block/blk-merge.c +++ b/trunk/block/blk-merge.c @@ -441,9 +441,6 @@ static int attempt_merge(struct request_queue *q, struct request *req, || next->special) return 0; - if (blk_integrity_rq(req) != blk_integrity_rq(next)) - return 0; - /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn diff --git a/trunk/block/blk-settings.c b/trunk/block/blk-settings.c index dfc77012843f..8dd86418f35d 100644 --- a/trunk/block/blk-settings.c +++ b/trunk/block/blk-settings.c @@ -302,10 +302,11 @@ EXPORT_SYMBOL(blk_queue_stack_limits); * @q: the request queue for the device * @mask: pad mask * - * Set dma pad mask. + * Set pad mask. Direct IO requests are padded to the mask specified. * - * Appending pad buffer to a request modifies the last entry of a - * scatter list such that it includes the pad buffer. + * Appending pad buffer to a request modifies ->data_len such that it + * includes the pad buffer. The original requested data length can be + * obtained using blk_rq_raw_data_len(). **/ void blk_queue_dma_pad(struct request_queue *q, unsigned int mask) { @@ -313,23 +314,6 @@ void blk_queue_dma_pad(struct request_queue *q, unsigned int mask) } EXPORT_SYMBOL(blk_queue_dma_pad); -/** - * blk_queue_update_dma_pad - update pad mask - * @q: the request queue for the device - * @mask: pad mask - * - * Update dma pad mask. - * - * Appending pad buffer to a request modifies the last entry of a - * scatter list such that it includes the pad buffer. - **/ -void blk_queue_update_dma_pad(struct request_queue *q, unsigned int mask) -{ - if (mask > q->dma_pad_mask) - q->dma_pad_mask = mask; -} -EXPORT_SYMBOL(blk_queue_update_dma_pad); - /** * blk_queue_dma_drain - Set up a drain buffer for excess dma. * @q: the request queue for the device diff --git a/trunk/block/blk.h b/trunk/block/blk.h index c79f30e1df52..59776ab4742a 100644 --- a/trunk/block/blk.h +++ b/trunk/block/blk.h @@ -51,12 +51,4 @@ static inline int queue_congestion_off_threshold(struct request_queue *q) return q->nr_congestion_off; } -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -#define rq_for_each_integrity_segment(bvl, _rq, _iter) \ - __rq_for_each_bio(_iter.bio, _rq) \ - bip_for_each_vec(bvl, _iter.bio->bi_integrity, _iter.i) - -#endif /* BLK_DEV_INTEGRITY */ - #endif diff --git a/trunk/block/blktrace.c b/trunk/block/blktrace.c index eb9651ccb241..8d3a27780260 100644 --- a/trunk/block/blktrace.c +++ b/trunk/block/blktrace.c @@ -244,7 +244,6 @@ static struct dentry *blk_create_tree(const char *blk_name) static void blk_trace_cleanup(struct blk_trace *bt) { relay_close(bt->rchan); - debugfs_remove(bt->msg_file); debugfs_remove(bt->dropped_file); blk_remove_tree(bt->dir); free_percpu(bt->sequence); @@ -292,44 +291,6 @@ static const struct file_operations blk_dropped_fops = { .read = blk_dropped_read, }; -static int blk_msg_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - - return 0; -} - -static ssize_t blk_msg_write(struct file *filp, const char __user *buffer, - size_t count, loff_t *ppos) -{ - char *msg; - struct blk_trace *bt; - - if (count > BLK_TN_MAX_MSG) - return -EINVAL; - - msg = kmalloc(count, GFP_KERNEL); - if (msg == NULL) - return -ENOMEM; - - if (copy_from_user(msg, buffer, count)) { - kfree(msg); - return -EFAULT; - } - - bt = filp->private_data; - __trace_note_message(bt, "%s", msg); - kfree(msg); - - return count; -} - -static const struct file_operations blk_msg_fops = { - .owner = THIS_MODULE, - .open = blk_msg_open, - .write = blk_msg_write, -}; - /* * Keep track of how many times we encountered a full subbuffer, to aid * the user space app in telling how many lost events there were. @@ -419,10 +380,6 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, if (!bt->dropped_file) goto err; - bt->msg_file = debugfs_create_file("msg", 0222, dir, bt, &blk_msg_fops); - if (!bt->msg_file) - goto err; - bt->rchan = relay_open("trace", dir, buts->buf_size, buts->buf_nr, &blk_relay_callbacks, bt); if (!bt->rchan) @@ -452,8 +409,6 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, if (dir) blk_remove_tree(dir); if (bt) { - if (bt->msg_file) - debugfs_remove(bt->msg_file); if (bt->dropped_file) debugfs_remove(bt->dropped_file); free_percpu(bt->sequence); diff --git a/trunk/block/bsg.c b/trunk/block/bsg.c index 93e757d7174b..54d617f7df3e 100644 --- a/trunk/block/bsg.c +++ b/trunk/block/bsg.c @@ -44,12 +44,11 @@ struct bsg_device { char name[BUS_ID_SIZE]; int max_queue; unsigned long flags; - struct blk_scsi_cmd_filter *cmd_filter; - mode_t *f_mode; }; enum { BSG_F_BLOCK = 1, + BSG_F_WRITE_PERM = 2, }; #define BSG_DEFAULT_CMDS 64 @@ -173,7 +172,7 @@ static int bsg_io_schedule(struct bsg_device *bd) } static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, - struct sg_io_v4 *hdr, struct bsg_device *bd) + struct sg_io_v4 *hdr, int has_write_perm) { if (hdr->request_len > BLK_MAX_CDB) { rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL); @@ -186,8 +185,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, return -EFAULT; if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) { - if (blk_cmd_filter_verify_command(bd->cmd_filter, rq->cmd, - bd->f_mode)) + if (blk_verify_command(rq->cmd, has_write_perm)) return -EPERM; } else if (!capable(CAP_SYS_RAWIO)) return -EPERM; @@ -265,7 +263,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr) rq = blk_get_request(q, rw, GFP_KERNEL); if (!rq) return ERR_PTR(-ENOMEM); - ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd); + ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM, + &bd->flags)); if (ret) goto out; @@ -567,23 +566,12 @@ static inline void bsg_set_block(struct bsg_device *bd, struct file *file) set_bit(BSG_F_BLOCK, &bd->flags); } -static void bsg_set_cmd_filter(struct bsg_device *bd, - struct file *file) +static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file) { - struct inode *inode; - struct gendisk *disk; - - if (!file) - return; - - inode = file->f_dentry->d_inode; - if (!inode) - return; - - disk = inode->i_bdev->bd_disk; - - bd->cmd_filter = &disk->cmd_filter; - bd->f_mode = &file->f_mode; + if (file->f_mode & FMODE_WRITE) + set_bit(BSG_F_WRITE_PERM, &bd->flags); + else + clear_bit(BSG_F_WRITE_PERM, &bd->flags); } /* @@ -607,8 +595,6 @@ bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) dprintk("%s: read %Zd bytes\n", bd->name, count); bsg_set_block(bd, file); - bsg_set_cmd_filter(bd, file); - bytes_read = 0; ret = __bsg_read(buf, count, bd, NULL, &bytes_read); *ppos = bytes_read; @@ -682,7 +668,7 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) dprintk("%s: write %Zd bytes\n", bd->name, count); bsg_set_block(bd, file); - bsg_set_cmd_filter(bd, file); + bsg_set_write_perm(bd, file); bytes_written = 0; ret = __bsg_write(bd, buf, count, &bytes_written); @@ -786,9 +772,7 @@ static struct bsg_device *bsg_add_device(struct inode *inode, } bd->queue = rq; - bsg_set_block(bd, file); - bsg_set_cmd_filter(bd, file); atomic_set(&bd->ref_count, 1); mutex_lock(&bsg_mutex); diff --git a/trunk/block/cfq-iosched.c b/trunk/block/cfq-iosched.c index 1e2aff812ee2..d01b411c72f0 100644 --- a/trunk/block/cfq-iosched.c +++ b/trunk/block/cfq-iosched.c @@ -11,7 +11,6 @@ #include #include #include -#include /* * tunables @@ -42,14 +41,13 @@ static int cfq_slice_idle = HZ / 125; #define RQ_CIC(rq) \ ((struct cfq_io_context *) (rq)->elevator_private) -#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elevator_private2) +#define RQ_CFQQ(rq) ((rq)->elevator_private2) static struct kmem_cache *cfq_pool; static struct kmem_cache *cfq_ioc_pool; static DEFINE_PER_CPU(unsigned long, ioc_count); static struct completion *ioc_gone; -static DEFINE_SPINLOCK(ioc_gone_lock); #define CFQ_PRIO_LISTS IOPRIO_BE_NR #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) @@ -157,7 +155,6 @@ struct cfq_queue { unsigned short ioprio, org_ioprio; unsigned short ioprio_class, org_ioprio_class; - pid_t pid; }; enum cfqq_state_flags { @@ -201,11 +198,6 @@ CFQ_CFQQ_FNS(slice_new); CFQ_CFQQ_FNS(sync); #undef CFQ_CFQQ_FNS -#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ - blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args) -#define cfq_log(cfqd, fmt, args...) \ - blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args) - static void cfq_dispatch_insert(struct request_queue *, struct request *); static struct cfq_queue *cfq_get_queue(struct cfq_data *, int, struct io_context *, gfp_t); @@ -242,10 +234,8 @@ static inline int cfq_bio_sync(struct bio *bio) */ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) { - if (cfqd->busy_queues) { - cfq_log(cfqd, "schedule dispatch"); + if (cfqd->busy_queues) kblockd_schedule_work(&cfqd->unplug_work); - } } static int cfq_queue_empty(struct request_queue *q) @@ -280,7 +270,6 @@ static inline void cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) { cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies; - cfq_log_cfqq(cfqd, cfqq, "set_slice=%lu", cfqq->slice_end - jiffies); } /* @@ -550,7 +539,6 @@ static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq) */ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_log_cfqq(cfqd, cfqq, "add_to_rr"); BUG_ON(cfq_cfqq_on_rr(cfqq)); cfq_mark_cfqq_on_rr(cfqq); cfqd->busy_queues++; @@ -564,7 +552,6 @@ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) */ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_log_cfqq(cfqd, cfqq, "del_from_rr"); BUG_ON(!cfq_cfqq_on_rr(cfqq)); cfq_clear_cfqq_on_rr(cfqq); @@ -651,8 +638,6 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq) struct cfq_data *cfqd = q->elevator->elevator_data; cfqd->rq_in_driver++; - cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d", - cfqd->rq_in_driver); /* * If the depth is larger 1, it really could be queueing. But lets @@ -672,8 +657,6 @@ static void cfq_deactivate_request(struct request_queue *q, struct request *rq) WARN_ON(!cfqd->rq_in_driver); cfqd->rq_in_driver--; - cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d", - cfqd->rq_in_driver); } static void cfq_remove_request(struct request *rq) @@ -763,7 +746,6 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) { if (cfqq) { - cfq_log_cfqq(cfqd, cfqq, "set_active"); cfqq->slice_end = 0; cfq_clear_cfqq_must_alloc_slice(cfqq); cfq_clear_cfqq_fifo_expire(cfqq); @@ -781,8 +763,6 @@ static void __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, int timed_out) { - cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out); - if (cfq_cfqq_wait_request(cfqq)) del_timer(&cfqd->idle_slice_timer); @@ -792,10 +772,8 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, /* * store what was left of this slice, if the queue idled/timed out */ - if (timed_out && !cfq_cfqq_slice_new(cfqq)) { + if (timed_out && !cfq_cfqq_slice_new(cfqq)) cfqq->slice_resid = cfqq->slice_end - jiffies; - cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid); - } cfq_resort_rr_list(cfqd, cfqq); @@ -887,12 +865,6 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq)) return; - /* - * still requests with the driver, don't idle - */ - if (cfqd->rq_in_driver) - return; - /* * task has exited, don't wait */ @@ -920,7 +892,6 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT)); mod_timer(&cfqd->idle_slice_timer, jiffies + sl); - cfq_log(cfqd, "arm_idle: %lu", sl); } /* @@ -931,8 +902,6 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = RQ_CFQQ(rq); - cfq_log_cfqq(cfqd, cfqq, "dispatch_insert"); - cfq_remove_request(rq); cfqq->dispatched++; elv_dispatch_sort(q, rq); @@ -962,9 +931,8 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq) rq = rq_entry_fifo(cfqq->fifo.next); if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) - rq = NULL; + return NULL; - cfq_log_cfqq(cfqd, cfqq, "fifo=%p", rq); return rq; } @@ -1104,7 +1072,6 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) BUG_ON(cfqd->busy_queues); - cfq_log(cfqd, "forced_dispatch=%d\n", dispatched); return dispatched; } @@ -1145,7 +1112,6 @@ static int cfq_dispatch_requests(struct request_queue *q, int force) dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); } - cfq_log(cfqd, "dispatched=%d", dispatched); return dispatched; } @@ -1164,7 +1130,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq) if (!atomic_dec_and_test(&cfqq->ref)) return; - cfq_log_cfqq(cfqd, cfqq, "put_queue"); BUG_ON(rb_first(&cfqq->sort_list)); BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]); BUG_ON(cfq_cfqq_on_rr(cfqq)); @@ -1212,19 +1177,8 @@ static void cfq_cic_free_rcu(struct rcu_head *head) kmem_cache_free(cfq_ioc_pool, cic); elv_ioc_count_dec(ioc_count); - if (ioc_gone) { - /* - * CFQ scheduler is exiting, grab exit lock and check - * the pending io context count. If it hits zero, - * complete ioc_gone and set it back to NULL - */ - spin_lock(&ioc_gone_lock); - if (ioc_gone && !elv_ioc_count_read(ioc_count)) { - complete(ioc_gone); - ioc_gone = NULL; - } - spin_unlock(&ioc_gone_lock); - } + if (ioc_gone && !elv_ioc_count_read(ioc_count)) + complete(ioc_gone); } static void cfq_cic_free(struct cfq_io_context *cic) @@ -1473,8 +1427,6 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync, cfq_mark_cfqq_idle_window(cfqq); cfq_mark_cfqq_sync(cfqq); } - cfqq->pid = current->pid; - cfq_log_cfqq(cfqd, cfqq, "alloced"); } if (new_cfqq) @@ -1723,7 +1675,7 @@ static void cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_io_context *cic) { - int old_idle, enable_idle; + int enable_idle; /* * Don't idle for async or idle io prio class @@ -1731,7 +1683,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq)) return; - enable_idle = old_idle = cfq_cfqq_idle_window(cfqq); + enable_idle = cfq_cfqq_idle_window(cfqq); if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle || (cfqd->hw_tag && CIC_SEEKY(cic))) @@ -1743,13 +1695,10 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, enable_idle = 1; } - if (old_idle != enable_idle) { - cfq_log_cfqq(cfqd, cfqq, "idle=%d", enable_idle); - if (enable_idle) - cfq_mark_cfqq_idle_window(cfqq); - else - cfq_clear_cfqq_idle_window(cfqq); - } + if (enable_idle) + cfq_mark_cfqq_idle_window(cfqq); + else + cfq_clear_cfqq_idle_window(cfqq); } /* @@ -1808,7 +1757,6 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, */ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_log_cfqq(cfqd, cfqq, "preempt"); cfq_slice_expired(cfqd, 1); /* @@ -1870,7 +1818,6 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq) struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = RQ_CFQQ(rq); - cfq_log_cfqq(cfqd, cfqq, "insert_request"); cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc); cfq_add_rq_rb(rq); @@ -1888,7 +1835,6 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) unsigned long now; now = jiffies; - cfq_log_cfqq(cfqd, cfqq, "complete"); WARN_ON(!cfqd->rq_in_driver); WARN_ON(!cfqq->dispatched); @@ -2058,7 +2004,6 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) cfq_schedule_dispatch(cfqd); spin_unlock_irqrestore(q->queue_lock, flags); - cfq_log(cfqd, "set_request fail"); return 1; } @@ -2084,8 +2029,6 @@ static void cfq_idle_slice_timer(unsigned long data) unsigned long flags; int timed_out = 1; - cfq_log(cfqd, "idle timer fired"); - spin_lock_irqsave(cfqd->queue->queue_lock, flags); cfqq = cfqd->active_queue; @@ -2374,7 +2317,7 @@ static void __exit cfq_exit(void) * pending RCU callbacks */ if (elv_ioc_count_read(ioc_count)) - wait_for_completion(&all_gone); + wait_for_completion(ioc_gone); cfq_slab_kill(); } diff --git a/trunk/block/cmd-filter.c b/trunk/block/cmd-filter.c deleted file mode 100644 index eec4404fd357..000000000000 --- a/trunk/block/cmd-filter.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2004 Peter M. Jones - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public Licens - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter, - unsigned char *cmd, mode_t *f_mode) -{ - /* root can do any command. */ - if (capable(CAP_SYS_RAWIO)) - return 0; - - /* if there's no filter set, assume we're filtering everything out */ - if (!filter) - return -EPERM; - - /* Anybody who can open the device can do a read-safe command */ - if (test_bit(cmd[0], filter->read_ok)) - return 0; - - /* Write-safe commands require a writable open */ - if (test_bit(cmd[0], filter->write_ok) && (*f_mode & FMODE_WRITE)) - return 0; - - return -EPERM; -} -EXPORT_SYMBOL(blk_cmd_filter_verify_command); - -int blk_verify_command(struct file *file, unsigned char *cmd) -{ - struct gendisk *disk; - struct inode *inode; - - if (!file) - return -EINVAL; - - inode = file->f_dentry->d_inode; - if (!inode) - return -EINVAL; - - disk = inode->i_bdev->bd_disk; - - return blk_cmd_filter_verify_command(&disk->cmd_filter, - cmd, &file->f_mode); -} -EXPORT_SYMBOL(blk_verify_command); - -/* and now, the sysfs stuff */ -static ssize_t rcf_cmds_show(struct blk_scsi_cmd_filter *filter, char *page, - int rw) -{ - char *npage = page; - unsigned long *okbits; - int i; - - if (rw == READ) - okbits = filter->read_ok; - else - okbits = filter->write_ok; - - for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) { - if (test_bit(i, okbits)) { - sprintf(npage, "%02x", i); - npage += 2; - if (i < BLK_SCSI_MAX_CMDS - 1) - sprintf(npage++, " "); - } - } - - if (npage != page) - npage += sprintf(npage, "\n"); - - return npage - page; -} - -static ssize_t rcf_readcmds_show(struct blk_scsi_cmd_filter *filter, char *page) -{ - return rcf_cmds_show(filter, page, READ); -} - -static ssize_t rcf_writecmds_show(struct blk_scsi_cmd_filter *filter, - char *page) -{ - return rcf_cmds_show(filter, page, WRITE); -} - -static ssize_t rcf_cmds_store(struct blk_scsi_cmd_filter *filter, - const char *page, size_t count, int rw) -{ - ssize_t ret = 0; - unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits; - int cmd, status, len; - substring_t ss; - - memset(&okbits, 0, sizeof(okbits)); - - for (len = strlen(page); len > 0; len -= 3) { - if (len < 2) - break; - ss.from = (char *) page + ret; - ss.to = (char *) page + ret + 2; - ret += 3; - status = match_hex(&ss, &cmd); - /* either of these cases means invalid input, so do nothing. */ - if (status || cmd >= BLK_SCSI_MAX_CMDS) - return -EINVAL; - - __set_bit(cmd, okbits); - } - - if (rw == READ) - target_okbits = filter->read_ok; - else - target_okbits = filter->write_ok; - - memmove(target_okbits, okbits, sizeof(okbits)); - return count; -} - -static ssize_t rcf_readcmds_store(struct blk_scsi_cmd_filter *filter, - const char *page, size_t count) -{ - return rcf_cmds_store(filter, page, count, READ); -} - -static ssize_t rcf_writecmds_store(struct blk_scsi_cmd_filter *filter, - const char *page, size_t count) -{ - return rcf_cmds_store(filter, page, count, WRITE); -} - -struct rcf_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_scsi_cmd_filter *, char *); - ssize_t (*store)(struct blk_scsi_cmd_filter *, const char *, size_t); -}; - -static struct rcf_sysfs_entry rcf_readcmds_entry = { - .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR }, - .show = rcf_readcmds_show, - .store = rcf_readcmds_store, -}; - -static struct rcf_sysfs_entry rcf_writecmds_entry = { - .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR }, - .show = rcf_writecmds_show, - .store = rcf_writecmds_store, -}; - -static struct attribute *default_attrs[] = { - &rcf_readcmds_entry.attr, - &rcf_writecmds_entry.attr, - NULL, -}; - -#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr) - -static ssize_t -rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page) -{ - struct rcf_sysfs_entry *entry = to_rcf(attr); - struct blk_scsi_cmd_filter *filter; - - filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj); - if (entry->show) - return entry->show(filter, page); - - return 0; -} - -static ssize_t -rcf_attr_store(struct kobject *kobj, struct attribute *attr, - const char *page, size_t length) -{ - struct rcf_sysfs_entry *entry = to_rcf(attr); - struct blk_scsi_cmd_filter *filter; - - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (!entry->store) - return -EINVAL; - - filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj); - return entry->store(filter, page, length); -} - -static struct sysfs_ops rcf_sysfs_ops = { - .show = rcf_attr_show, - .store = rcf_attr_store, -}; - -static struct kobj_type rcf_ktype = { - .sysfs_ops = &rcf_sysfs_ops, - .default_attrs = default_attrs, -}; - -#ifndef MAINTENANCE_IN_CMD -#define MAINTENANCE_IN_CMD 0xa3 -#endif - -static void rcf_set_defaults(struct blk_scsi_cmd_filter *filter) -{ - /* Basic read-only commands */ - __set_bit(TEST_UNIT_READY, filter->read_ok); - __set_bit(REQUEST_SENSE, filter->read_ok); - __set_bit(READ_6, filter->read_ok); - __set_bit(READ_10, filter->read_ok); - __set_bit(READ_12, filter->read_ok); - __set_bit(READ_16, filter->read_ok); - __set_bit(READ_BUFFER, filter->read_ok); - __set_bit(READ_DEFECT_DATA, filter->read_ok); - __set_bit(READ_CAPACITY, filter->read_ok); - __set_bit(READ_LONG, filter->read_ok); - __set_bit(INQUIRY, filter->read_ok); - __set_bit(MODE_SENSE, filter->read_ok); - __set_bit(MODE_SENSE_10, filter->read_ok); - __set_bit(LOG_SENSE, filter->read_ok); - __set_bit(START_STOP, filter->read_ok); - __set_bit(GPCMD_VERIFY_10, filter->read_ok); - __set_bit(VERIFY_16, filter->read_ok); - __set_bit(REPORT_LUNS, filter->read_ok); - __set_bit(SERVICE_ACTION_IN, filter->read_ok); - __set_bit(RECEIVE_DIAGNOSTIC, filter->read_ok); - __set_bit(MAINTENANCE_IN_CMD, filter->read_ok); - __set_bit(GPCMD_READ_BUFFER_CAPACITY, filter->read_ok); - - /* Audio CD commands */ - __set_bit(GPCMD_PLAY_CD, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_10, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_MSF, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_TI, filter->read_ok); - __set_bit(GPCMD_PAUSE_RESUME, filter->read_ok); - - /* CD/DVD data reading */ - __set_bit(GPCMD_READ_CD, filter->read_ok); - __set_bit(GPCMD_READ_CD_MSF, filter->read_ok); - __set_bit(GPCMD_READ_DISC_INFO, filter->read_ok); - __set_bit(GPCMD_READ_CDVD_CAPACITY, filter->read_ok); - __set_bit(GPCMD_READ_DVD_STRUCTURE, filter->read_ok); - __set_bit(GPCMD_READ_HEADER, filter->read_ok); - __set_bit(GPCMD_READ_TRACK_RZONE_INFO, filter->read_ok); - __set_bit(GPCMD_READ_SUBCHANNEL, filter->read_ok); - __set_bit(GPCMD_READ_TOC_PMA_ATIP, filter->read_ok); - __set_bit(GPCMD_REPORT_KEY, filter->read_ok); - __set_bit(GPCMD_SCAN, filter->read_ok); - __set_bit(GPCMD_GET_CONFIGURATION, filter->read_ok); - __set_bit(GPCMD_READ_FORMAT_CAPACITIES, filter->read_ok); - __set_bit(GPCMD_GET_EVENT_STATUS_NOTIFICATION, filter->read_ok); - __set_bit(GPCMD_GET_PERFORMANCE, filter->read_ok); - __set_bit(GPCMD_SEEK, filter->read_ok); - __set_bit(GPCMD_STOP_PLAY_SCAN, filter->read_ok); - - /* Basic writing commands */ - __set_bit(WRITE_6, filter->write_ok); - __set_bit(WRITE_10, filter->write_ok); - __set_bit(WRITE_VERIFY, filter->write_ok); - __set_bit(WRITE_12, filter->write_ok); - __set_bit(WRITE_VERIFY_12, filter->write_ok); - __set_bit(WRITE_16, filter->write_ok); - __set_bit(WRITE_LONG, filter->write_ok); - __set_bit(WRITE_LONG_2, filter->write_ok); - __set_bit(ERASE, filter->write_ok); - __set_bit(GPCMD_MODE_SELECT_10, filter->write_ok); - __set_bit(MODE_SELECT, filter->write_ok); - __set_bit(LOG_SELECT, filter->write_ok); - __set_bit(GPCMD_BLANK, filter->write_ok); - __set_bit(GPCMD_CLOSE_TRACK, filter->write_ok); - __set_bit(GPCMD_FLUSH_CACHE, filter->write_ok); - __set_bit(GPCMD_FORMAT_UNIT, filter->write_ok); - __set_bit(GPCMD_REPAIR_RZONE_TRACK, filter->write_ok); - __set_bit(GPCMD_RESERVE_RZONE_TRACK, filter->write_ok); - __set_bit(GPCMD_SEND_DVD_STRUCTURE, filter->write_ok); - __set_bit(GPCMD_SEND_EVENT, filter->write_ok); - __set_bit(GPCMD_SEND_KEY, filter->write_ok); - __set_bit(GPCMD_SEND_OPC, filter->write_ok); - __set_bit(GPCMD_SEND_CUE_SHEET, filter->write_ok); - __set_bit(GPCMD_SET_SPEED, filter->write_ok); - __set_bit(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, filter->write_ok); - __set_bit(GPCMD_LOAD_UNLOAD, filter->write_ok); - __set_bit(GPCMD_SET_STREAMING, filter->write_ok); -} - -int blk_register_filter(struct gendisk *disk) -{ - int ret; - struct blk_scsi_cmd_filter *filter = &disk->cmd_filter; - struct kobject *parent = kobject_get(disk->holder_dir->parent); - - if (!parent) - return -ENODEV; - - ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, parent, - "%s", "cmd_filter"); - - if (ret < 0) - return ret; - - rcf_set_defaults(filter); - return 0; -} - -void blk_unregister_filter(struct gendisk *disk) -{ - struct blk_scsi_cmd_filter *filter = &disk->cmd_filter; - - kobject_put(&filter->kobj); - kobject_put(disk->holder_dir->parent); -} - diff --git a/trunk/block/elevator.c b/trunk/block/elevator.c index ed6f8f32d27e..902dd1344d56 100644 --- a/trunk/block/elevator.c +++ b/trunk/block/elevator.c @@ -86,12 +86,6 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio) if (rq->rq_disk != bio->bi_bdev->bd_disk || rq->special) return 0; - /* - * only merge integrity protected bio into ditto rq - */ - if (bio_integrity(bio) != blk_integrity_rq(rq)) - return 0; - if (!elv_iosched_allow_merge(rq, bio)) return 0; @@ -150,7 +144,7 @@ static struct elevator_type *elevator_get(const char *name) else sprintf(elv, "%s-iosched", name); - request_module("%s", elv); + request_module(elv); spin_lock(&elv_list_lock); e = elevator_find(name); } diff --git a/trunk/block/genhd.c b/trunk/block/genhd.c index 9074f384b097..b922d4801c87 100644 --- a/trunk/block/genhd.c +++ b/trunk/block/genhd.c @@ -189,7 +189,6 @@ void add_disk(struct gendisk *disk) disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); blk_register_queue(disk); - blk_register_filter(disk); bdi = &disk->queue->backing_dev_info; bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); @@ -201,7 +200,6 @@ EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ void unlink_gendisk(struct gendisk *disk) { - blk_unregister_filter(disk); sysfs_remove_link(&disk->dev.kobj, "bdi"); bdi_unregister(&disk->queue->backing_dev_info); blk_unregister_queue(disk); @@ -402,14 +400,6 @@ static ssize_t disk_removable_show(struct device *dev, (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); } -static ssize_t disk_ro_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", disk->policy ? 1 : 0); -} - static ssize_t disk_size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -482,7 +472,6 @@ static ssize_t disk_fail_store(struct device *dev, static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); -static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); @@ -494,7 +483,6 @@ static struct device_attribute dev_attr_fail = static struct attribute *disk_attrs[] = { &dev_attr_range.attr, &dev_attr_removable.attr, - &dev_attr_ro.attr, &dev_attr_size.attr, &dev_attr_capability.attr, &dev_attr_stat.attr, diff --git a/trunk/block/scsi_ioctl.c b/trunk/block/scsi_ioctl.c index c5b9bcfc0a6d..78199c08ec92 100644 --- a/trunk/block/scsi_ioctl.c +++ b/trunk/block/scsi_ioctl.c @@ -105,12 +105,120 @@ static int sg_emulated_host(struct request_queue *q, int __user *p) return put_user(1, p); } +#define CMD_READ_SAFE 0x01 +#define CMD_WRITE_SAFE 0x02 +#define CMD_WARNED 0x04 +#define safe_for_read(cmd) [cmd] = CMD_READ_SAFE +#define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE + +int blk_verify_command(unsigned char *cmd, int has_write_perm) +{ + static unsigned char cmd_type[256] = { + + /* Basic read-only commands */ + safe_for_read(TEST_UNIT_READY), + safe_for_read(REQUEST_SENSE), + safe_for_read(READ_6), + safe_for_read(READ_10), + safe_for_read(READ_12), + safe_for_read(READ_16), + safe_for_read(READ_BUFFER), + safe_for_read(READ_DEFECT_DATA), + safe_for_read(READ_LONG), + safe_for_read(INQUIRY), + safe_for_read(MODE_SENSE), + safe_for_read(MODE_SENSE_10), + safe_for_read(LOG_SENSE), + safe_for_read(START_STOP), + safe_for_read(GPCMD_VERIFY_10), + safe_for_read(VERIFY_16), + + /* Audio CD commands */ + safe_for_read(GPCMD_PLAY_CD), + safe_for_read(GPCMD_PLAY_AUDIO_10), + safe_for_read(GPCMD_PLAY_AUDIO_MSF), + safe_for_read(GPCMD_PLAY_AUDIO_TI), + safe_for_read(GPCMD_PAUSE_RESUME), + + /* CD/DVD data reading */ + safe_for_read(GPCMD_READ_BUFFER_CAPACITY), + safe_for_read(GPCMD_READ_CD), + safe_for_read(GPCMD_READ_CD_MSF), + safe_for_read(GPCMD_READ_DISC_INFO), + safe_for_read(GPCMD_READ_CDVD_CAPACITY), + safe_for_read(GPCMD_READ_DVD_STRUCTURE), + safe_for_read(GPCMD_READ_HEADER), + safe_for_read(GPCMD_READ_TRACK_RZONE_INFO), + safe_for_read(GPCMD_READ_SUBCHANNEL), + safe_for_read(GPCMD_READ_TOC_PMA_ATIP), + safe_for_read(GPCMD_REPORT_KEY), + safe_for_read(GPCMD_SCAN), + safe_for_read(GPCMD_GET_CONFIGURATION), + safe_for_read(GPCMD_READ_FORMAT_CAPACITIES), + safe_for_read(GPCMD_GET_EVENT_STATUS_NOTIFICATION), + safe_for_read(GPCMD_GET_PERFORMANCE), + safe_for_read(GPCMD_SEEK), + safe_for_read(GPCMD_STOP_PLAY_SCAN), + + /* Basic writing commands */ + safe_for_write(WRITE_6), + safe_for_write(WRITE_10), + safe_for_write(WRITE_VERIFY), + safe_for_write(WRITE_12), + safe_for_write(WRITE_VERIFY_12), + safe_for_write(WRITE_16), + safe_for_write(WRITE_LONG), + safe_for_write(WRITE_LONG_2), + safe_for_write(ERASE), + safe_for_write(GPCMD_MODE_SELECT_10), + safe_for_write(MODE_SELECT), + safe_for_write(LOG_SELECT), + safe_for_write(GPCMD_BLANK), + safe_for_write(GPCMD_CLOSE_TRACK), + safe_for_write(GPCMD_FLUSH_CACHE), + safe_for_write(GPCMD_FORMAT_UNIT), + safe_for_write(GPCMD_REPAIR_RZONE_TRACK), + safe_for_write(GPCMD_RESERVE_RZONE_TRACK), + safe_for_write(GPCMD_SEND_DVD_STRUCTURE), + safe_for_write(GPCMD_SEND_EVENT), + safe_for_write(GPCMD_SEND_KEY), + safe_for_write(GPCMD_SEND_OPC), + safe_for_write(GPCMD_SEND_CUE_SHEET), + safe_for_write(GPCMD_SET_SPEED), + safe_for_write(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL), + safe_for_write(GPCMD_LOAD_UNLOAD), + safe_for_write(GPCMD_SET_STREAMING), + }; + unsigned char type = cmd_type[cmd[0]]; + + /* Anybody who can open the device can do a read-safe command */ + if (type & CMD_READ_SAFE) + return 0; + + /* Write-safe commands just require a writable open.. */ + if ((type & CMD_WRITE_SAFE) && has_write_perm) + return 0; + + /* And root can do any command.. */ + if (capable(CAP_SYS_RAWIO)) + return 0; + + if (!type) { + cmd_type[cmd[0]] = CMD_WARNED; + printk(KERN_WARNING "scsi: unknown opcode 0x%02x\n", cmd[0]); + } + + /* Otherwise fail it with an "Operation not permitted" */ + return -EPERM; +} +EXPORT_SYMBOL_GPL(blk_verify_command); + static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, - struct sg_io_hdr *hdr, struct file *file) + struct sg_io_hdr *hdr, int has_write_perm) { if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) return -EFAULT; - if (blk_verify_command(file, rq->cmd)) + if (blk_verify_command(rq->cmd, has_write_perm)) return -EPERM; /* @@ -179,7 +287,7 @@ static int sg_io(struct file *file, struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; - int writing = 0, ret = 0; + int writing = 0, ret = 0, has_write_perm = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; @@ -208,7 +316,10 @@ static int sg_io(struct file *file, struct request_queue *q, if (!rq) return -ENOMEM; - if (blk_fill_sghdr_rq(q, rq, hdr, file)) { + if (file) + has_write_perm = file->f_mode & FMODE_WRITE; + + if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) { blk_put_request(rq); return -EFAULT; } @@ -340,7 +451,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q, if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; - err = blk_verify_command(file, rq->cmd); + err = blk_verify_command(rq->cmd, file->f_mode & FMODE_WRITE); if (err) goto error; diff --git a/trunk/drivers/Makefile b/trunk/drivers/Makefile index fda44679dffc..f65deda72d61 100644 --- a/trunk/drivers/Makefile +++ b/trunk/drivers/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_RAPIDIO) += rapidio/ obj-y += video/ -obj-y += gpu/ obj-$(CONFIG_ACPI) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi # was used and do nothing if so diff --git a/trunk/drivers/ata/libata-scsi.c b/trunk/drivers/ata/libata-scsi.c index 499ccc628d81..57a43649a461 100644 --- a/trunk/drivers/ata/libata-scsi.c +++ b/trunk/drivers/ata/libata-scsi.c @@ -885,8 +885,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, /* set the min alignment and padding */ blk_queue_update_dma_alignment(sdev->request_queue, ATA_DMA_PAD_SZ - 1); - blk_queue_update_dma_pad(sdev->request_queue, - ATA_DMA_PAD_SZ - 1); + blk_queue_dma_pad(sdev->request_queue, ATA_DMA_PAD_SZ - 1); /* configure draining */ buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL); diff --git a/trunk/drivers/block/DAC960.c b/trunk/drivers/block/DAC960.c index a002a381df92..cd03473f3547 100644 --- a/trunk/drivers/block/DAC960.c +++ b/trunk/drivers/block/DAC960.c @@ -6628,18 +6628,15 @@ static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller) * DAC960_gam_ioctl is the ioctl function for performing RAID operations. */ -static long DAC960_gam_ioctl(struct file *file, unsigned int Request, - unsigned long Argument) +static int DAC960_gam_ioctl(struct inode *inode, struct file *file, + unsigned int Request, unsigned long Argument) { - long ErrorCode = 0; + int ErrorCode = 0; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - - lock_kernel(); switch (Request) { case DAC960_IOCTL_GET_CONTROLLER_COUNT: - ErrorCode = DAC960_ControllerCount; - break; + return DAC960_ControllerCount; case DAC960_IOCTL_GET_CONTROLLER_INFO: { DAC960_ControllerInfo_T __user *UserSpaceControllerInfo = @@ -6647,20 +6644,15 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, DAC960_ControllerInfo_T ControllerInfo; DAC960_Controller_T *Controller; int ControllerNumber; - if (UserSpaceControllerInfo == NULL) - ErrorCode = -EINVAL; - else ErrorCode = get_user(ControllerNumber, + if (UserSpaceControllerInfo == NULL) return -EINVAL; + ErrorCode = get_user(ControllerNumber, &UserSpaceControllerInfo->ControllerNumber); - if (ErrorCode != 0) - break;; - ErrorCode = -ENXIO; + if (ErrorCode != 0) return ErrorCode; if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) { - break; - } + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break;; + if (Controller == NULL) return -ENXIO; memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); ControllerInfo.ControllerNumber = ControllerNumber; ControllerInfo.FirmwareType = Controller->FirmwareType; @@ -6673,9 +6665,8 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, ControllerInfo.PCI_Address = Controller->PCI_Address; strcpy(ControllerInfo.ModelName, Controller->ModelName); strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); - ErrorCode = (copy_to_user(UserSpaceControllerInfo, &ControllerInfo, + return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo, sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0); - break; } case DAC960_IOCTL_V1_EXECUTE_COMMAND: { @@ -6693,39 +6684,30 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, int ControllerNumber, DataTransferLength; unsigned char *DataTransferBuffer = NULL; dma_addr_t DataTransferBufferDMA; - if (UserSpaceUserCommand == NULL) { - ErrorCode = -EINVAL; - break; - } + if (UserSpaceUserCommand == NULL) return -EINVAL; if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V1_UserCommand_T))) { ErrorCode = -EFAULT; - break; + goto Failure1a; } ControllerNumber = UserCommand.ControllerNumber; - ErrorCode = -ENXIO; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break; - ErrorCode = -EINVAL; - if (Controller->FirmwareType != DAC960_V1_Controller) - break; + if (Controller == NULL) return -ENXIO; + if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL; CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; DataTransferLength = UserCommand.DataTransferLength; - if (CommandOpcode & 0x80) - break; + if (CommandOpcode & 0x80) return -EINVAL; if (CommandOpcode == DAC960_V1_DCDB) { if (copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T))) { ErrorCode = -EFAULT; - break; + goto Failure1a; } - if (DCDB.Channel >= DAC960_V1_MaxChannels) - break; + if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && DCDB.Direction == DAC960_V1_DCDB_NoDataTransfer) || @@ -6735,37 +6717,38 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, (DataTransferLength < 0 && DCDB.Direction == DAC960_V1_DCDB_DataTransferSystemToDevice))) - break; + return -EINVAL; if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) != abs(DataTransferLength)) - break; + return -EINVAL; DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA); - if (DCDB_IOBUF == NULL) { - ErrorCode = -ENOMEM; - break; - } + if (DCDB_IOBUF == NULL) + return -ENOMEM; } - ErrorCode = -ENOMEM; if (DataTransferLength > 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) { + ErrorCode = -ENOMEM; + goto Failure1; + } memset(DataTransferBuffer, 0, DataTransferLength); } else if (DataTransferLength < 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, -DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) { + ErrorCode = -ENOMEM; + goto Failure1; + } if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, -DataTransferLength)) { ErrorCode = -EFAULT; - break; + goto Failure1; } } if (CommandOpcode == DAC960_V1_DCDB) @@ -6842,7 +6825,8 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, if (DCDB_IOBUF != NULL) pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), DCDB_IOBUF, DCDB_IOBUFDMA); - break; + Failure1a: + return ErrorCode; } case DAC960_IOCTL_V2_EXECUTE_COMMAND: { @@ -6860,43 +6844,32 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, dma_addr_t DataTransferBufferDMA; unsigned char *RequestSenseBuffer = NULL; dma_addr_t RequestSenseBufferDMA; - - ErrorCode = -EINVAL; - if (UserSpaceUserCommand == NULL) - break; + if (UserSpaceUserCommand == NULL) return -EINVAL; if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V2_UserCommand_T))) { ErrorCode = -EFAULT; - break; + goto Failure2a; } - ErrorCode = -ENXIO; ControllerNumber = UserCommand.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break; - if (Controller->FirmwareType != DAC960_V2_Controller){ - ErrorCode = -EINVAL; - break; - } + if (Controller == NULL) return -ENXIO; + if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL; DataTransferLength = UserCommand.DataTransferLength; - ErrorCode = -ENOMEM; if (DataTransferLength > 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) return -ENOMEM; memset(DataTransferBuffer, 0, DataTransferLength); } else if (DataTransferLength < 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, -DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) return -ENOMEM; if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, -DataTransferLength)) { @@ -7006,7 +6979,8 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, if (RequestSenseBuffer != NULL) pci_free_consistent(Controller->PCIDevice, RequestSenseLength, RequestSenseBuffer, RequestSenseBufferDMA); - break; + Failure2a: + return ErrorCode; } case DAC960_IOCTL_V2_GET_HEALTH_STATUS: { @@ -7016,33 +6990,21 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer; DAC960_Controller_T *Controller; int ControllerNumber; - if (UserSpaceGetHealthStatus == NULL) { - ErrorCode = -EINVAL; - break; - } + if (UserSpaceGetHealthStatus == NULL) return -EINVAL; if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus, - sizeof(DAC960_V2_GetHealthStatus_T))) { - ErrorCode = -EFAULT; - break; - } - ErrorCode = -ENXIO; + sizeof(DAC960_V2_GetHealthStatus_T))) + return -EFAULT; ControllerNumber = GetHealthStatus.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break; - if (Controller->FirmwareType != DAC960_V2_Controller) { - ErrorCode = -EINVAL; - break; - } + if (Controller == NULL) return -ENXIO; + if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL; if (copy_from_user(&HealthStatusBuffer, GetHealthStatus.HealthStatusBuffer, - sizeof(DAC960_V2_HealthStatusBuffer_T))) { - ErrorCode = -EFAULT; - break; - } + sizeof(DAC960_V2_HealthStatusBuffer_T))) + return -EFAULT; while (Controller->V2.HealthStatusBuffer->StatusChangeCounter == HealthStatusBuffer.StatusChangeCounter && Controller->V2.HealthStatusBuffer->NextEventSequenceNumber @@ -7050,28 +7012,21 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, { interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue, DAC960_MonitoringTimerInterval); - if (signal_pending(current)) { - ErrorCode = -EINTR; - break; - } + if (signal_pending(current)) return -EINTR; } if (copy_to_user(GetHealthStatus.HealthStatusBuffer, Controller->V2.HealthStatusBuffer, sizeof(DAC960_V2_HealthStatusBuffer_T))) - ErrorCode = -EFAULT; - else - ErrorCode = 0; + return -EFAULT; + return 0; } - default: - ErrorCode = -ENOTTY; } - unlock_kernel(); - return ErrorCode; + return -EINVAL; } static const struct file_operations DAC960_gam_fops = { .owner = THIS_MODULE, - .unlocked_ioctl = DAC960_gam_ioctl + .ioctl = DAC960_gam_ioctl }; static struct miscdevice DAC960_gam_dev = { diff --git a/trunk/drivers/block/aoe/aoecmd.c b/trunk/drivers/block/aoe/aoecmd.c index 2f1746295d06..41f818be2f7e 100644 --- a/trunk/drivers/block/aoe/aoecmd.c +++ b/trunk/drivers/block/aoe/aoecmd.c @@ -1003,7 +1003,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) * Enough people have their dip switches set backwards to * warrant a loud message for this special case. */ - aoemajor = get_unaligned_be16(&h->major); + aoemajor = be16_to_cpu(get_unaligned(&h->major)); if (aoemajor == 0xfff) { printk(KERN_ERR "aoe: Warning: shelf address is all ones. " "Check shelf dip switches.\n"); diff --git a/trunk/drivers/block/paride/pt.c b/trunk/drivers/block/paride/pt.c index 27455ee1e9da..8b9549ab4a4e 100644 --- a/trunk/drivers/block/paride/pt.c +++ b/trunk/drivers/block/paride/pt.c @@ -146,7 +146,6 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include #include #include /* current, TASK_*, schedule_timeout() */ -#include #include @@ -190,7 +189,8 @@ module_param_array(drive3, int, NULL, 0); #define ATAPI_LOG_SENSE 0x4d static int pt_open(struct inode *inode, struct file *file); -static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static int pt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); static int pt_release(struct inode *inode, struct file *file); static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos); @@ -236,7 +236,7 @@ static const struct file_operations pt_fops = { .owner = THIS_MODULE, .read = pt_read, .write = pt_write, - .unlocked_ioctl = pt_ioctl, + .ioctl = pt_ioctl, .open = pt_open, .release = pt_release, }; @@ -685,7 +685,8 @@ static int pt_open(struct inode *inode, struct file *file) return err; } -static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static int pt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct pt_unit *tape = file->private_data; struct mtop __user *p = (void __user *)arg; @@ -699,26 +700,23 @@ static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (mtop.mt_op) { case MTREW: - lock_kernel(); pt_rewind(tape); - unlock_kernel(); return 0; case MTWEOF: - lock_kernel(); pt_write_fm(tape); - unlock_kernel(); return 0; default: - /* FIXME: rate limit ?? */ - printk(KERN_DEBUG "%s: Unimplemented mt_op %d\n", tape->name, + printk("%s: Unimplemented mt_op %d\n", tape->name, mtop.mt_op); return -EINVAL; } default: - return -ENOTTY; + printk("%s: Unimplemented ioctl 0x%x\n", tape->name, cmd); + return -EINVAL; + } } diff --git a/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c index 45bee918c46a..3ba1df93e9e3 100644 --- a/trunk/drivers/block/pktcdvd.c +++ b/trunk/drivers/block/pktcdvd.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -2080,6 +2079,7 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, unsigned char buf[64]; int ret; + memset(buf, 0, sizeof(buf)); init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.sense = &sense; cgc.buflen = pd->mode_offset + 12; @@ -2126,6 +2126,7 @@ static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned char *cap_buf; int ret, offset; + memset(buf, 0, sizeof(buf)); cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset]; init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN); cgc.sense = &sense; @@ -2632,12 +2633,11 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) -static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, - struct bio_vec *bvec) +static int pkt_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *bvec) { struct pktcdvd_device *pd = q->queuedata; - sector_t zone = ZONE(bmd->bi_sector, pd); - int used = ((bmd->bi_sector - zone) << 9) + bmd->bi_size; + sector_t zone = ZONE(bio->bi_sector, pd); + int used = ((bio->bi_sector - zone) << 9) + bio->bi_size; int remaining = (pd->settings.size << 9) - used; int remaining2; @@ -2645,7 +2645,7 @@ static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, * A bio <= PAGE_SIZE must be allowed. If it crosses a packet * boundary, pkt_make_request() will split the bio. */ - remaining2 = PAGE_SIZE - bmd->bi_size; + remaining2 = PAGE_SIZE - bio->bi_size; remaining = max(remaining, remaining2); BUG_ON(remaining < 0); @@ -2796,14 +2796,9 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) return ret; } -static long pkt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - struct pktcdvd_device *pd; - long ret; - - lock_kernel(); - pd = inode->i_bdev->bd_disk->private_data; + struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data; VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode)); @@ -2816,8 +2811,7 @@ static long pkt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case CDROM_LAST_WRITTEN: case CDROM_SEND_PACKET: case SCSI_IOCTL_SEND_COMMAND: - ret = blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); - break; + return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); case CDROMEJECT: /* @@ -2826,15 +2820,14 @@ static long pkt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) */ if (pd->refcnt == 1) pkt_lock_door(pd, 0); - ret = blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); - break; + return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); default: VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd); - ret = -ENOTTY; + return -ENOTTY; } - unlock_kernel(); - return ret; + + return 0; } static int pkt_media_changed(struct gendisk *disk) @@ -2856,7 +2849,7 @@ static struct block_device_operations pktcdvd_ops = { .owner = THIS_MODULE, .open = pkt_open, .release = pkt_close, - .unlocked_ioctl = pkt_ioctl, + .ioctl = pkt_ioctl, .media_changed = pkt_media_changed, }; @@ -3021,8 +3014,7 @@ static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) mutex_unlock(&ctl_mutex); } -static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; struct pkt_ctrl_command ctrl_cmd; @@ -3039,22 +3031,16 @@ static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, case PKT_CTRL_CMD_SETUP: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev); ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev); - unlock_kernel(); break; case PKT_CTRL_CMD_TEARDOWN: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev)); - unlock_kernel(); break; case PKT_CTRL_CMD_STATUS: - lock_kernel(); pkt_get_status(&ctrl_cmd); - unlock_kernel(); break; default: return -ENOTTY; @@ -3067,7 +3053,7 @@ static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, static const struct file_operations pkt_ctl_fops = { - .unlocked_ioctl = pkt_ctl_ioctl, + .ioctl = pkt_ctl_ioctl, .owner = THIS_MODULE, }; diff --git a/trunk/drivers/block/xen-blkfront.c b/trunk/drivers/block/xen-blkfront.c index 9ae05c584234..f2fff5799ddf 100644 --- a/trunk/drivers/block/xen-blkfront.c +++ b/trunk/drivers/block/xen-blkfront.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -154,40 +153,6 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) return 0; } -int blkif_ioctl(struct inode *inode, struct file *filep, - unsigned command, unsigned long argument) -{ - struct blkfront_info *info = - inode->i_bdev->bd_disk->private_data; - int i; - - dev_dbg(&info->xbdev->dev, "command: 0x%x, argument: 0x%lx\n", - command, (long)argument); - - switch (command) { - case CDROMMULTISESSION: - dev_dbg(&info->xbdev->dev, "FIXME: support multisession CDs later\n"); - for (i = 0; i < sizeof(struct cdrom_multisession); i++) - if (put_user(0, (char __user *)(argument + i))) - return -EFAULT; - return 0; - - case CDROM_GET_CAPABILITY: { - struct gendisk *gd = info->gd; - if (gd->flags & GENHD_FL_CD) - return 0; - return -EINVAL; - } - - default: - /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", - command);*/ - return -EINVAL; /* same return as native Linux */ - } - - return 0; -} - /* * blkif_queue_request * @@ -359,9 +324,6 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) /* Make sure buffer addresses are sector-aligned. */ blk_queue_dma_alignment(rq, 511); - /* Make sure we don't use bounce buffers. */ - blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY); - gd->queue = rq; return 0; @@ -584,7 +546,7 @@ static int setup_blkring(struct xenbus_device *dev, info->ring_ref = GRANT_INVALID_REF; - sring = (struct blkif_sring *)__get_free_page(GFP_NOIO | __GFP_HIGH); + sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL); if (!sring) { xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); return -ENOMEM; @@ -741,8 +703,7 @@ static int blkif_recover(struct blkfront_info *info) int j; /* Stage 1: Make a safe copy of the shadow state. */ - copy = kmalloc(sizeof(info->shadow), - GFP_NOIO | __GFP_REPEAT | __GFP_HIGH); + copy = kmalloc(sizeof(info->shadow), GFP_KERNEL); if (!copy) return -ENOMEM; memcpy(copy, info->shadow, sizeof(info->shadow)); @@ -998,7 +959,7 @@ static int blkif_release(struct inode *inode, struct file *filep) struct xenbus_device *dev = info->xbdev; enum xenbus_state state = xenbus_read_driver_state(dev->otherend); - if (state == XenbusStateClosing && info->is_ready) + if (state == XenbusStateClosing) blkfront_closing(dev); } return 0; @@ -1010,7 +971,6 @@ static struct block_device_operations xlvbd_block_fops = .open = blkif_open, .release = blkif_release, .getgeo = blkif_getgeo, - .ioctl = blkif_ioctl, }; @@ -1046,7 +1006,7 @@ static int __init xlblk_init(void) module_init(xlblk_init); -static void __exit xlblk_exit(void) +static void xlblk_exit(void) { return xenbus_unregister_driver(&blkfront); } diff --git a/trunk/drivers/cdrom/cdrom.c b/trunk/drivers/cdrom/cdrom.c index a5da35632651..69f26eb6415b 100644 --- a/trunk/drivers/cdrom/cdrom.c +++ b/trunk/drivers/cdrom/cdrom.c @@ -461,27 +461,37 @@ int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med) { struct packet_command cgc; - unsigned char buffer[8]; - struct event_header *eh = (struct event_header *) buffer; + unsigned char *buffer; + struct event_header *eh; + int ret = 1; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + eh = (struct event_header *)buffer; + + init_cdrom_command(&cgc, buffer, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; cgc.cmd[1] = 1; /* IMMED */ cgc.cmd[4] = 1 << 4; /* media event */ - cgc.cmd[8] = sizeof(buffer); + cgc.cmd[8] = 8; cgc.quiet = 1; if (cdi->ops->generic_packet(cdi, &cgc)) - return 1; + goto err; if (be16_to_cpu(eh->data_len) < sizeof(*med)) - return 1; + goto err; if (eh->nea || eh->notification_class != 0x4) - return 1; + goto err; - memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); - return 0; + memcpy(med, buffer + sizeof(*eh), sizeof(*med)); + ret = 0; +err: + kfree(buffer); + return ret; } /* @@ -491,68 +501,82 @@ int cdrom_get_media_event(struct cdrom_device_info *cdi, static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[16]; + char *buffer; + int ret = 1; + + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.timeout = HZ; cgc.quiet = 1; if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) { cdi->mrw_mode_page = MRW_MODE_PC; - return 0; + ret = 0; } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) { cdi->mrw_mode_page = MRW_MODE_PC_PRE1; - return 0; + ret = 0; } - - return 1; + kfree(buffer); + return ret; } static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write) { struct packet_command cgc; struct mrw_feature_desc *mfd; - unsigned char buffer[16]; + unsigned char *buffer; int ret; *write = 0; + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[3] = CDF_MRW; - cgc.cmd[8] = sizeof(buffer); + cgc.cmd[8] = 16; cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) - return ret; + goto err; mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; - if (be16_to_cpu(mfd->feature_code) != CDF_MRW) - return 1; + if (be16_to_cpu(mfd->feature_code) != CDF_MRW) { + ret = 1; + goto err; + } *write = mfd->write; if ((ret = cdrom_mrw_probe_pc(cdi))) { *write = 0; - return ret; } - - return 0; +err: + kfree(buffer); + return ret; } static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) { struct packet_command cgc; - unsigned char buffer[12]; + unsigned char *buffer; int ret; printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : ""); + buffer = kmalloc(12, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + /* * FmtData bit set (bit 4), format type is 1 */ - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE); + init_cdrom_command(&cgc, buffer, 12, CGC_DATA_WRITE); cgc.cmd[0] = GPCMD_FORMAT_UNIT; cgc.cmd[1] = (1 << 4) | 1; @@ -579,6 +603,7 @@ static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) if (ret) printk(KERN_INFO "cdrom: bgformat failed\n"); + kfree(buffer); return ret; } @@ -638,16 +663,17 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) { struct packet_command cgc; struct mode_page_header *mph; - char buffer[16]; + char *buffer; int ret, offset, size; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - cgc.buffer = buffer; - cgc.buflen = sizeof(buffer); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) - return ret; + goto err; mph = (struct mode_page_header *) buffer; offset = be16_to_cpu(mph->desc_length); @@ -657,55 +683,70 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) cgc.buflen = size; if ((ret = cdrom_mode_select(cdi, &cgc))) - return ret; + goto err; printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]); - return 0; + ret = 0; +err: + kfree(buffer); + return ret; } static int cdrom_get_random_writable(struct cdrom_device_info *cdi, struct rwrt_feature_desc *rfd) { struct packet_command cgc; - char buffer[24]; + char *buffer; int ret; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(24, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + init_cdrom_command(&cgc, buffer, 24, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */ cgc.cmd[3] = CDF_RWRT; /* often 0x0020 */ - cgc.cmd[8] = sizeof(buffer); /* often 0x18 */ + cgc.cmd[8] = 24; /* often 0x18 */ cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) - return ret; + goto err; memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd)); - return 0; + ret = 0; +err: + kfree(buffer); + return ret; } static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[16]; + char *buffer; __be16 *feature_code; int ret; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[3] = CDF_HWDM; - cgc.cmd[8] = sizeof(buffer); + cgc.cmd[8] = 16; cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) - return ret; + goto err; feature_code = (__be16 *) &buffer[sizeof(struct feature_header)]; if (be16_to_cpu(*feature_code) == CDF_HWDM) - return 0; - - return 1; + ret = 0; +err: + kfree(buffer); + return ret; } @@ -796,10 +837,14 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) static int mo_open_write(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[255]; + char *buffer; int ret; - init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ); + buffer = kmalloc(255, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + init_cdrom_command(&cgc, buffer, 4, CGC_DATA_READ); cgc.quiet = 1; /* @@ -816,10 +861,15 @@ static int mo_open_write(struct cdrom_device_info *cdi) } /* drive gave us no info, let the user go ahead */ - if (ret) - return 0; + if (ret) { + ret = 0; + goto err; + } - return buffer[3] & 0x80; + ret = buffer[3] & 0x80; +err: + kfree(buffer); + return ret; } static int cdrom_ram_open_write(struct cdrom_device_info *cdi) @@ -842,15 +892,19 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi) static void cdrom_mmc3_profile(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[32]; + char *buffer; int ret, mmc3_profile; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(32, GFP_KERNEL); + if (!buffer) + return; + + init_cdrom_command(&cgc, buffer, 32, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[1] = 0; cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */ - cgc.cmd[8] = sizeof(buffer); /* Allocation Length */ + cgc.cmd[8] = 32; /* Allocation Length */ cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) @@ -859,6 +913,7 @@ static void cdrom_mmc3_profile(struct cdrom_device_info *cdi) mmc3_profile = (buffer[6] << 8) | buffer[7]; cdi->mmc3_profile = mmc3_profile; + kfree(buffer); } static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) @@ -1573,12 +1628,15 @@ static void setup_send_key(struct packet_command *cgc, unsigned agid, unsigned t static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) { int ret; - u_char buf[20]; + u_char *buf; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - rpc_state_t rpc_state; + rpc_state_t *rpc_state; + + buf = kzalloc(20, GFP_KERNEL); + if (!buf) + return -ENOMEM; - memset(buf, 0, sizeof(buf)); init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); switch (ai->type) { @@ -1589,7 +1647,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsa.agid, 0); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->lsa.agid = buf[7] >> 6; /* Returning data, let host change state */ @@ -1600,7 +1658,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsk.agid, 2); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; copy_key(ai->lsk.key, &buf[4]); /* Returning data, let host change state */ @@ -1611,7 +1669,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsc.agid, 1); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; copy_chal(ai->lsc.chal, &buf[4]); /* Returning data, let host change state */ @@ -1628,7 +1686,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) cgc.cmd[2] = ai->lstk.lba >> 24; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->lstk.cpm = (buf[4] >> 7) & 1; ai->lstk.cp_sec = (buf[4] >> 6) & 1; @@ -1642,7 +1700,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsasf.agid, 5); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->lsasf.asf = buf[7] & 1; break; @@ -1655,7 +1713,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) copy_chal(&buf[4], ai->hsc.chal); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->type = DVD_LU_SEND_KEY1; break; @@ -1668,7 +1726,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) if ((ret = cdo->generic_packet(cdi, &cgc))) { ai->type = DVD_AUTH_FAILURE; - return ret; + goto err; } ai->type = DVD_AUTH_ESTABLISHED; break; @@ -1679,24 +1737,23 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); setup_report_key(&cgc, ai->lsa.agid, 0x3f); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; break; /* Get region settings */ case DVD_LU_SEND_RPC_STATE: cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); setup_report_key(&cgc, 0, 8); - memset(&rpc_state, 0, sizeof(rpc_state_t)); - cgc.buffer = (char *) &rpc_state; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; - ai->lrpcs.type = rpc_state.type_code; - ai->lrpcs.vra = rpc_state.vra; - ai->lrpcs.ucca = rpc_state.ucca; - ai->lrpcs.region_mask = rpc_state.region_mask; - ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; + rpc_state = (rpc_state_t *)buf; + ai->lrpcs.type = rpc_state->type_code; + ai->lrpcs.vra = rpc_state->vra; + ai->lrpcs.ucca = rpc_state->ucca; + ai->lrpcs.region_mask = rpc_state->region_mask; + ai->lrpcs.rpc_scheme = rpc_state->rpc_scheme; break; /* Set region settings */ @@ -1707,20 +1764,23 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) buf[4] = ai->hrpcs.pdrc; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; break; default: cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); - return -ENOTTY; + ret = -ENOTTY; + goto err; } - - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) { - unsigned char buf[21], *base; + unsigned char *buf, *base; struct dvd_layer *layer; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; @@ -1729,7 +1789,11 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) if (layer_num >= DVD_LAYERS) return -EINVAL; - init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + buf = kmalloc(21, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, 21, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = layer_num; cgc.cmd[7] = s->type; @@ -1741,7 +1805,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) cgc.quiet = 1; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; base = &buf[4]; layer = &s->physical.layer[layer_num]; @@ -1765,17 +1829,24 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; layer->bca = base[16] >> 7; - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) { int ret; - u_char buf[8]; + u_char *buf; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + buf = kmalloc(8, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->copyright.layer_num; cgc.cmd[7] = s->type; @@ -1783,12 +1854,15 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) cgc.cmd[9] = cgc.buflen & 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; s->copyright.cpst = buf[4]; s->copyright.rmi = buf[5]; - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) @@ -1820,26 +1894,33 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) { int ret; - u_char buf[4 + 188]; + u_char *buf; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + buf = kmalloc(4 + 188, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, 4 + 188, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen & 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; s->bca.len = buf[0] << 8 | buf[1]; if (s->bca.len < 12 || s->bca.len > 188) { cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); - return -EIO; + ret = -EIO; + goto err; } memcpy(s->bca.value, &buf[4], s->bca.len); - - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) @@ -1939,9 +2020,13 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi, { struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; - char buffer[32]; + char *buffer; int ret; + buffer = kmalloc(32, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; cgc.cmd[1] = 2; /* MSF addressing */ @@ -1950,7 +2035,7 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi, cgc.cmd[8] = 16; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; subchnl->cdsc_audiostatus = cgc.buffer[1]; subchnl->cdsc_format = CDROM_MSF; @@ -1965,7 +2050,10 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi, subchnl->cdsc_absaddr.msf.second = cgc.buffer[10]; subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11]; - return 0; + ret = 0; +err: + kfree(buffer); + return ret; } /* diff --git a/trunk/drivers/char/Makefile b/trunk/drivers/char/Makefile index 81630a68475c..4c1c584e9eb6 100644 --- a/trunk/drivers/char/Makefile +++ b/trunk/drivers/char/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ +obj-$(CONFIG_DRM) += drm/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ diff --git a/trunk/drivers/gpu/drm/Kconfig b/trunk/drivers/char/drm/Kconfig similarity index 100% rename from trunk/drivers/gpu/drm/Kconfig rename to trunk/drivers/char/drm/Kconfig diff --git a/trunk/drivers/char/drm/Makefile b/trunk/drivers/char/drm/Makefile new file mode 100644 index 000000000000..1283ded88ead --- /dev/null +++ b/trunk/drivers/char/drm/Makefile @@ -0,0 +1,40 @@ +# +# Makefile for the drm device driver. This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. + +drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ + drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ + drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ + drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ + drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o + +tdfx-objs := tdfx_drv.o +r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o +mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o +i810-objs := i810_drv.o i810_dma.o +i830-objs := i830_drv.o i830_dma.o i830_irq.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o +sis-objs := sis_drv.o sis_mm.o +savage-objs := savage_drv.o savage_bci.o savage_state.o +via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o + +ifeq ($(CONFIG_COMPAT),y) +drm-objs += drm_ioc32.o +radeon-objs += radeon_ioc32.o +mga-objs += mga_ioc32.o +r128-objs += r128_ioc32.o +i915-objs += i915_ioc32.o +endif + +obj-$(CONFIG_DRM) += drm.o +obj-$(CONFIG_DRM_TDFX) += tdfx.o +obj-$(CONFIG_DRM_R128) += r128.o +obj-$(CONFIG_DRM_RADEON)+= radeon.o +obj-$(CONFIG_DRM_MGA) += mga.o +obj-$(CONFIG_DRM_I810) += i810.o +obj-$(CONFIG_DRM_I830) += i830.o +obj-$(CONFIG_DRM_I915) += i915.o +obj-$(CONFIG_DRM_SIS) += sis.o +obj-$(CONFIG_DRM_SAVAGE)+= savage.o +obj-$(CONFIG_DRM_VIA) +=via.o diff --git a/trunk/drivers/gpu/drm/README.drm b/trunk/drivers/char/drm/README.drm similarity index 100% rename from trunk/drivers/gpu/drm/README.drm rename to trunk/drivers/char/drm/README.drm diff --git a/trunk/drivers/gpu/drm/ati_pcigart.c b/trunk/drivers/char/drm/ati_pcigart.c similarity index 100% rename from trunk/drivers/gpu/drm/ati_pcigart.c rename to trunk/drivers/char/drm/ati_pcigart.c diff --git a/trunk/include/drm/drm.h b/trunk/drivers/char/drm/drm.h similarity index 100% rename from trunk/include/drm/drm.h rename to trunk/drivers/char/drm/drm.h diff --git a/trunk/include/drm/drmP.h b/trunk/drivers/char/drm/drmP.h similarity index 100% rename from trunk/include/drm/drmP.h rename to trunk/drivers/char/drm/drmP.h diff --git a/trunk/drivers/gpu/drm/drm_agpsupport.c b/trunk/drivers/char/drm/drm_agpsupport.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_agpsupport.c rename to trunk/drivers/char/drm/drm_agpsupport.c diff --git a/trunk/drivers/gpu/drm/drm_auth.c b/trunk/drivers/char/drm/drm_auth.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_auth.c rename to trunk/drivers/char/drm/drm_auth.c diff --git a/trunk/drivers/gpu/drm/drm_bufs.c b/trunk/drivers/char/drm/drm_bufs.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_bufs.c rename to trunk/drivers/char/drm/drm_bufs.c diff --git a/trunk/drivers/gpu/drm/drm_context.c b/trunk/drivers/char/drm/drm_context.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_context.c rename to trunk/drivers/char/drm/drm_context.c diff --git a/trunk/include/drm/drm_core.h b/trunk/drivers/char/drm/drm_core.h similarity index 100% rename from trunk/include/drm/drm_core.h rename to trunk/drivers/char/drm/drm_core.h diff --git a/trunk/drivers/gpu/drm/drm_dma.c b/trunk/drivers/char/drm/drm_dma.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_dma.c rename to trunk/drivers/char/drm/drm_dma.c diff --git a/trunk/drivers/gpu/drm/drm_drawable.c b/trunk/drivers/char/drm/drm_drawable.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_drawable.c rename to trunk/drivers/char/drm/drm_drawable.c diff --git a/trunk/drivers/gpu/drm/drm_drv.c b/trunk/drivers/char/drm/drm_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_drv.c rename to trunk/drivers/char/drm/drm_drv.c diff --git a/trunk/drivers/gpu/drm/drm_fops.c b/trunk/drivers/char/drm/drm_fops.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_fops.c rename to trunk/drivers/char/drm/drm_fops.c diff --git a/trunk/drivers/gpu/drm/drm_hashtab.c b/trunk/drivers/char/drm/drm_hashtab.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_hashtab.c rename to trunk/drivers/char/drm/drm_hashtab.c diff --git a/trunk/include/drm/drm_hashtab.h b/trunk/drivers/char/drm/drm_hashtab.h similarity index 100% rename from trunk/include/drm/drm_hashtab.h rename to trunk/drivers/char/drm/drm_hashtab.h diff --git a/trunk/drivers/gpu/drm/drm_ioc32.c b/trunk/drivers/char/drm/drm_ioc32.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_ioc32.c rename to trunk/drivers/char/drm/drm_ioc32.c diff --git a/trunk/drivers/gpu/drm/drm_ioctl.c b/trunk/drivers/char/drm/drm_ioctl.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_ioctl.c rename to trunk/drivers/char/drm/drm_ioctl.c diff --git a/trunk/drivers/gpu/drm/drm_irq.c b/trunk/drivers/char/drm/drm_irq.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_irq.c rename to trunk/drivers/char/drm/drm_irq.c diff --git a/trunk/drivers/gpu/drm/drm_lock.c b/trunk/drivers/char/drm/drm_lock.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_lock.c rename to trunk/drivers/char/drm/drm_lock.c diff --git a/trunk/drivers/gpu/drm/drm_memory.c b/trunk/drivers/char/drm/drm_memory.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_memory.c rename to trunk/drivers/char/drm/drm_memory.c diff --git a/trunk/include/drm/drm_memory.h b/trunk/drivers/char/drm/drm_memory.h similarity index 100% rename from trunk/include/drm/drm_memory.h rename to trunk/drivers/char/drm/drm_memory.h diff --git a/trunk/include/drm/drm_memory_debug.h b/trunk/drivers/char/drm/drm_memory_debug.h similarity index 100% rename from trunk/include/drm/drm_memory_debug.h rename to trunk/drivers/char/drm/drm_memory_debug.h diff --git a/trunk/drivers/gpu/drm/drm_mm.c b/trunk/drivers/char/drm/drm_mm.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_mm.c rename to trunk/drivers/char/drm/drm_mm.c diff --git a/trunk/include/drm/drm_os_linux.h b/trunk/drivers/char/drm/drm_os_linux.h similarity index 100% rename from trunk/include/drm/drm_os_linux.h rename to trunk/drivers/char/drm/drm_os_linux.h diff --git a/trunk/drivers/gpu/drm/drm_pci.c b/trunk/drivers/char/drm/drm_pci.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_pci.c rename to trunk/drivers/char/drm/drm_pci.c diff --git a/trunk/include/drm/drm_pciids.h b/trunk/drivers/char/drm/drm_pciids.h similarity index 100% rename from trunk/include/drm/drm_pciids.h rename to trunk/drivers/char/drm/drm_pciids.h diff --git a/trunk/drivers/gpu/drm/drm_proc.c b/trunk/drivers/char/drm/drm_proc.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_proc.c rename to trunk/drivers/char/drm/drm_proc.c diff --git a/trunk/include/drm/drm_sarea.h b/trunk/drivers/char/drm/drm_sarea.h similarity index 100% rename from trunk/include/drm/drm_sarea.h rename to trunk/drivers/char/drm/drm_sarea.h diff --git a/trunk/drivers/gpu/drm/drm_scatter.c b/trunk/drivers/char/drm/drm_scatter.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_scatter.c rename to trunk/drivers/char/drm/drm_scatter.c diff --git a/trunk/drivers/gpu/drm/drm_sman.c b/trunk/drivers/char/drm/drm_sman.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_sman.c rename to trunk/drivers/char/drm/drm_sman.c diff --git a/trunk/include/drm/drm_sman.h b/trunk/drivers/char/drm/drm_sman.h similarity index 100% rename from trunk/include/drm/drm_sman.h rename to trunk/drivers/char/drm/drm_sman.h diff --git a/trunk/drivers/gpu/drm/drm_stub.c b/trunk/drivers/char/drm/drm_stub.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_stub.c rename to trunk/drivers/char/drm/drm_stub.c diff --git a/trunk/drivers/gpu/drm/drm_sysfs.c b/trunk/drivers/char/drm/drm_sysfs.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_sysfs.c rename to trunk/drivers/char/drm/drm_sysfs.c diff --git a/trunk/drivers/gpu/drm/drm_vm.c b/trunk/drivers/char/drm/drm_vm.c similarity index 100% rename from trunk/drivers/gpu/drm/drm_vm.c rename to trunk/drivers/char/drm/drm_vm.c diff --git a/trunk/drivers/gpu/drm/i810/i810_dma.c b/trunk/drivers/char/drm/i810_dma.c similarity index 100% rename from trunk/drivers/gpu/drm/i810/i810_dma.c rename to trunk/drivers/char/drm/i810_dma.c diff --git a/trunk/include/drm/i810_drm.h b/trunk/drivers/char/drm/i810_drm.h similarity index 100% rename from trunk/include/drm/i810_drm.h rename to trunk/drivers/char/drm/i810_drm.h diff --git a/trunk/drivers/gpu/drm/i810/i810_drv.c b/trunk/drivers/char/drm/i810_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/i810/i810_drv.c rename to trunk/drivers/char/drm/i810_drv.c diff --git a/trunk/drivers/gpu/drm/i810/i810_drv.h b/trunk/drivers/char/drm/i810_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/i810/i810_drv.h rename to trunk/drivers/char/drm/i810_drv.h diff --git a/trunk/drivers/gpu/drm/i830/i830_dma.c b/trunk/drivers/char/drm/i830_dma.c similarity index 100% rename from trunk/drivers/gpu/drm/i830/i830_dma.c rename to trunk/drivers/char/drm/i830_dma.c diff --git a/trunk/include/drm/i830_drm.h b/trunk/drivers/char/drm/i830_drm.h similarity index 100% rename from trunk/include/drm/i830_drm.h rename to trunk/drivers/char/drm/i830_drm.h diff --git a/trunk/drivers/gpu/drm/i830/i830_drv.c b/trunk/drivers/char/drm/i830_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/i830/i830_drv.c rename to trunk/drivers/char/drm/i830_drv.c diff --git a/trunk/drivers/gpu/drm/i830/i830_drv.h b/trunk/drivers/char/drm/i830_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/i830/i830_drv.h rename to trunk/drivers/char/drm/i830_drv.h diff --git a/trunk/drivers/gpu/drm/i830/i830_irq.c b/trunk/drivers/char/drm/i830_irq.c similarity index 100% rename from trunk/drivers/gpu/drm/i830/i830_irq.c rename to trunk/drivers/char/drm/i830_irq.c diff --git a/trunk/drivers/gpu/drm/i915/i915_dma.c b/trunk/drivers/char/drm/i915_dma.c similarity index 100% rename from trunk/drivers/gpu/drm/i915/i915_dma.c rename to trunk/drivers/char/drm/i915_dma.c diff --git a/trunk/include/drm/i915_drm.h b/trunk/drivers/char/drm/i915_drm.h similarity index 100% rename from trunk/include/drm/i915_drm.h rename to trunk/drivers/char/drm/i915_drm.h diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.c b/trunk/drivers/char/drm/i915_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/i915/i915_drv.c rename to trunk/drivers/char/drm/i915_drv.c diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.h b/trunk/drivers/char/drm/i915_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/i915/i915_drv.h rename to trunk/drivers/char/drm/i915_drv.h diff --git a/trunk/drivers/gpu/drm/i915/i915_ioc32.c b/trunk/drivers/char/drm/i915_ioc32.c similarity index 100% rename from trunk/drivers/gpu/drm/i915/i915_ioc32.c rename to trunk/drivers/char/drm/i915_ioc32.c diff --git a/trunk/drivers/gpu/drm/i915/i915_irq.c b/trunk/drivers/char/drm/i915_irq.c similarity index 100% rename from trunk/drivers/gpu/drm/i915/i915_irq.c rename to trunk/drivers/char/drm/i915_irq.c diff --git a/trunk/drivers/gpu/drm/i915/i915_mem.c b/trunk/drivers/char/drm/i915_mem.c similarity index 100% rename from trunk/drivers/gpu/drm/i915/i915_mem.c rename to trunk/drivers/char/drm/i915_mem.c diff --git a/trunk/drivers/gpu/drm/mga/mga_dma.c b/trunk/drivers/char/drm/mga_dma.c similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_dma.c rename to trunk/drivers/char/drm/mga_dma.c diff --git a/trunk/include/drm/mga_drm.h b/trunk/drivers/char/drm/mga_drm.h similarity index 100% rename from trunk/include/drm/mga_drm.h rename to trunk/drivers/char/drm/mga_drm.h diff --git a/trunk/drivers/gpu/drm/mga/mga_drv.c b/trunk/drivers/char/drm/mga_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_drv.c rename to trunk/drivers/char/drm/mga_drv.c diff --git a/trunk/drivers/gpu/drm/mga/mga_drv.h b/trunk/drivers/char/drm/mga_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_drv.h rename to trunk/drivers/char/drm/mga_drv.h diff --git a/trunk/drivers/gpu/drm/mga/mga_ioc32.c b/trunk/drivers/char/drm/mga_ioc32.c similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_ioc32.c rename to trunk/drivers/char/drm/mga_ioc32.c diff --git a/trunk/drivers/gpu/drm/mga/mga_irq.c b/trunk/drivers/char/drm/mga_irq.c similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_irq.c rename to trunk/drivers/char/drm/mga_irq.c diff --git a/trunk/drivers/gpu/drm/mga/mga_state.c b/trunk/drivers/char/drm/mga_state.c similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_state.c rename to trunk/drivers/char/drm/mga_state.c diff --git a/trunk/drivers/gpu/drm/mga/mga_ucode.h b/trunk/drivers/char/drm/mga_ucode.h similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_ucode.h rename to trunk/drivers/char/drm/mga_ucode.h diff --git a/trunk/drivers/gpu/drm/mga/mga_warp.c b/trunk/drivers/char/drm/mga_warp.c similarity index 100% rename from trunk/drivers/gpu/drm/mga/mga_warp.c rename to trunk/drivers/char/drm/mga_warp.c diff --git a/trunk/drivers/gpu/drm/r128/r128_cce.c b/trunk/drivers/char/drm/r128_cce.c similarity index 100% rename from trunk/drivers/gpu/drm/r128/r128_cce.c rename to trunk/drivers/char/drm/r128_cce.c diff --git a/trunk/include/drm/r128_drm.h b/trunk/drivers/char/drm/r128_drm.h similarity index 100% rename from trunk/include/drm/r128_drm.h rename to trunk/drivers/char/drm/r128_drm.h diff --git a/trunk/drivers/gpu/drm/r128/r128_drv.c b/trunk/drivers/char/drm/r128_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/r128/r128_drv.c rename to trunk/drivers/char/drm/r128_drv.c diff --git a/trunk/drivers/gpu/drm/r128/r128_drv.h b/trunk/drivers/char/drm/r128_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/r128/r128_drv.h rename to trunk/drivers/char/drm/r128_drv.h diff --git a/trunk/drivers/gpu/drm/r128/r128_ioc32.c b/trunk/drivers/char/drm/r128_ioc32.c similarity index 100% rename from trunk/drivers/gpu/drm/r128/r128_ioc32.c rename to trunk/drivers/char/drm/r128_ioc32.c diff --git a/trunk/drivers/gpu/drm/r128/r128_irq.c b/trunk/drivers/char/drm/r128_irq.c similarity index 100% rename from trunk/drivers/gpu/drm/r128/r128_irq.c rename to trunk/drivers/char/drm/r128_irq.c diff --git a/trunk/drivers/gpu/drm/r128/r128_state.c b/trunk/drivers/char/drm/r128_state.c similarity index 100% rename from trunk/drivers/gpu/drm/r128/r128_state.c rename to trunk/drivers/char/drm/r128_state.c diff --git a/trunk/drivers/gpu/drm/radeon/r300_cmdbuf.c b/trunk/drivers/char/drm/r300_cmdbuf.c similarity index 100% rename from trunk/drivers/gpu/drm/radeon/r300_cmdbuf.c rename to trunk/drivers/char/drm/r300_cmdbuf.c diff --git a/trunk/drivers/gpu/drm/radeon/r300_reg.h b/trunk/drivers/char/drm/r300_reg.h similarity index 100% rename from trunk/drivers/gpu/drm/radeon/r300_reg.h rename to trunk/drivers/char/drm/r300_reg.h diff --git a/trunk/drivers/gpu/drm/radeon/radeon_cp.c b/trunk/drivers/char/drm/radeon_cp.c similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_cp.c rename to trunk/drivers/char/drm/radeon_cp.c diff --git a/trunk/include/drm/radeon_drm.h b/trunk/drivers/char/drm/radeon_drm.h similarity index 100% rename from trunk/include/drm/radeon_drm.h rename to trunk/drivers/char/drm/radeon_drm.h diff --git a/trunk/drivers/gpu/drm/radeon/radeon_drv.c b/trunk/drivers/char/drm/radeon_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_drv.c rename to trunk/drivers/char/drm/radeon_drv.c diff --git a/trunk/drivers/gpu/drm/radeon/radeon_drv.h b/trunk/drivers/char/drm/radeon_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_drv.h rename to trunk/drivers/char/drm/radeon_drv.h diff --git a/trunk/drivers/gpu/drm/radeon/radeon_ioc32.c b/trunk/drivers/char/drm/radeon_ioc32.c similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_ioc32.c rename to trunk/drivers/char/drm/radeon_ioc32.c diff --git a/trunk/drivers/gpu/drm/radeon/radeon_irq.c b/trunk/drivers/char/drm/radeon_irq.c similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_irq.c rename to trunk/drivers/char/drm/radeon_irq.c diff --git a/trunk/drivers/gpu/drm/radeon/radeon_mem.c b/trunk/drivers/char/drm/radeon_mem.c similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_mem.c rename to trunk/drivers/char/drm/radeon_mem.c diff --git a/trunk/drivers/gpu/drm/radeon/radeon_microcode.h b/trunk/drivers/char/drm/radeon_microcode.h similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_microcode.h rename to trunk/drivers/char/drm/radeon_microcode.h diff --git a/trunk/drivers/gpu/drm/radeon/radeon_state.c b/trunk/drivers/char/drm/radeon_state.c similarity index 100% rename from trunk/drivers/gpu/drm/radeon/radeon_state.c rename to trunk/drivers/char/drm/radeon_state.c diff --git a/trunk/drivers/gpu/drm/savage/savage_bci.c b/trunk/drivers/char/drm/savage_bci.c similarity index 100% rename from trunk/drivers/gpu/drm/savage/savage_bci.c rename to trunk/drivers/char/drm/savage_bci.c diff --git a/trunk/include/drm/savage_drm.h b/trunk/drivers/char/drm/savage_drm.h similarity index 100% rename from trunk/include/drm/savage_drm.h rename to trunk/drivers/char/drm/savage_drm.h diff --git a/trunk/drivers/gpu/drm/savage/savage_drv.c b/trunk/drivers/char/drm/savage_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/savage/savage_drv.c rename to trunk/drivers/char/drm/savage_drv.c diff --git a/trunk/drivers/gpu/drm/savage/savage_drv.h b/trunk/drivers/char/drm/savage_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/savage/savage_drv.h rename to trunk/drivers/char/drm/savage_drv.h diff --git a/trunk/drivers/gpu/drm/savage/savage_state.c b/trunk/drivers/char/drm/savage_state.c similarity index 100% rename from trunk/drivers/gpu/drm/savage/savage_state.c rename to trunk/drivers/char/drm/savage_state.c diff --git a/trunk/include/drm/sis_drm.h b/trunk/drivers/char/drm/sis_drm.h similarity index 100% rename from trunk/include/drm/sis_drm.h rename to trunk/drivers/char/drm/sis_drm.h diff --git a/trunk/drivers/gpu/drm/sis/sis_drv.c b/trunk/drivers/char/drm/sis_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/sis/sis_drv.c rename to trunk/drivers/char/drm/sis_drv.c diff --git a/trunk/drivers/gpu/drm/sis/sis_drv.h b/trunk/drivers/char/drm/sis_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/sis/sis_drv.h rename to trunk/drivers/char/drm/sis_drv.h diff --git a/trunk/drivers/gpu/drm/sis/sis_mm.c b/trunk/drivers/char/drm/sis_mm.c similarity index 100% rename from trunk/drivers/gpu/drm/sis/sis_mm.c rename to trunk/drivers/char/drm/sis_mm.c diff --git a/trunk/drivers/gpu/drm/tdfx/tdfx_drv.c b/trunk/drivers/char/drm/tdfx_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/tdfx/tdfx_drv.c rename to trunk/drivers/char/drm/tdfx_drv.c diff --git a/trunk/drivers/gpu/drm/tdfx/tdfx_drv.h b/trunk/drivers/char/drm/tdfx_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/tdfx/tdfx_drv.h rename to trunk/drivers/char/drm/tdfx_drv.h diff --git a/trunk/drivers/gpu/drm/via/via_3d_reg.h b/trunk/drivers/char/drm/via_3d_reg.h similarity index 100% rename from trunk/drivers/gpu/drm/via/via_3d_reg.h rename to trunk/drivers/char/drm/via_3d_reg.h diff --git a/trunk/drivers/gpu/drm/via/via_dma.c b/trunk/drivers/char/drm/via_dma.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_dma.c rename to trunk/drivers/char/drm/via_dma.c diff --git a/trunk/drivers/gpu/drm/via/via_dmablit.c b/trunk/drivers/char/drm/via_dmablit.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_dmablit.c rename to trunk/drivers/char/drm/via_dmablit.c diff --git a/trunk/drivers/gpu/drm/via/via_dmablit.h b/trunk/drivers/char/drm/via_dmablit.h similarity index 100% rename from trunk/drivers/gpu/drm/via/via_dmablit.h rename to trunk/drivers/char/drm/via_dmablit.h diff --git a/trunk/include/drm/via_drm.h b/trunk/drivers/char/drm/via_drm.h similarity index 100% rename from trunk/include/drm/via_drm.h rename to trunk/drivers/char/drm/via_drm.h diff --git a/trunk/drivers/gpu/drm/via/via_drv.c b/trunk/drivers/char/drm/via_drv.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_drv.c rename to trunk/drivers/char/drm/via_drv.c diff --git a/trunk/drivers/gpu/drm/via/via_drv.h b/trunk/drivers/char/drm/via_drv.h similarity index 100% rename from trunk/drivers/gpu/drm/via/via_drv.h rename to trunk/drivers/char/drm/via_drv.h diff --git a/trunk/drivers/gpu/drm/via/via_irq.c b/trunk/drivers/char/drm/via_irq.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_irq.c rename to trunk/drivers/char/drm/via_irq.c diff --git a/trunk/drivers/gpu/drm/via/via_map.c b/trunk/drivers/char/drm/via_map.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_map.c rename to trunk/drivers/char/drm/via_map.c diff --git a/trunk/drivers/gpu/drm/via/via_mm.c b/trunk/drivers/char/drm/via_mm.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_mm.c rename to trunk/drivers/char/drm/via_mm.c diff --git a/trunk/drivers/gpu/drm/via/via_verifier.c b/trunk/drivers/char/drm/via_verifier.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_verifier.c rename to trunk/drivers/char/drm/via_verifier.c diff --git a/trunk/drivers/gpu/drm/via/via_verifier.h b/trunk/drivers/char/drm/via_verifier.h similarity index 100% rename from trunk/drivers/gpu/drm/via/via_verifier.h rename to trunk/drivers/char/drm/via_verifier.h diff --git a/trunk/drivers/gpu/drm/via/via_video.c b/trunk/drivers/char/drm/via_video.c similarity index 100% rename from trunk/drivers/gpu/drm/via/via_video.c rename to trunk/drivers/char/drm/via_video.c diff --git a/trunk/drivers/char/pcmcia/cm4000_cs.c b/trunk/drivers/char/pcmcia/cm4000_cs.c index 59ca35156d81..4a933d413423 100644 --- a/trunk/drivers/char/pcmcia/cm4000_cs.c +++ b/trunk/drivers/char/pcmcia/cm4000_cs.c @@ -32,9 +32,8 @@ #include #include #include -#include -#include -#include +#include +#include #include #include @@ -1406,11 +1405,11 @@ static void stop_monitor(struct cm4000_dev *dev) DEBUGP(3, dev, "<- stop_monitor\n"); } -static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) { struct cm4000_dev *dev = filp->private_data; unsigned int iobase = dev->p_dev->io.BasePort1; - struct inode *inode = filp->f_path.dentry->d_inode; struct pcmcia_device *link; int size; int rc; @@ -1427,42 +1426,38 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), iminor(inode), ioctl_names[_IOC_NR(cmd)]); - lock_kernel(); - rc = -ENODEV; link = dev_table[iminor(inode)]; if (!pcmcia_dev_present(link)) { DEBUGP(4, dev, "DEV_OK false\n"); - goto out; + return -ENODEV; } if (test_bit(IS_CMM_ABSENT, &dev->flags)) { DEBUGP(4, dev, "CMM_ABSENT flag set\n"); - goto out; + return -ENODEV; } - rc = EINVAL; if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) { DEBUGP(4, dev, "ioctype mismatch\n"); - goto out; + return -EINVAL; } if (_IOC_NR(cmd) > CM_IOC_MAXNR) { DEBUGP(4, dev, "iocnr mismatch\n"); - goto out; + return -EINVAL; } size = _IOC_SIZE(cmd); - rc = -EFAULT; + rc = 0; DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n", _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd); if (_IOC_DIR(cmd) & _IOC_READ) { if (!access_ok(VERIFY_WRITE, argp, size)) - goto out; + return -EFAULT; } if (_IOC_DIR(cmd) & _IOC_WRITE) { if (!access_ok(VERIFY_READ, argp, size)) - goto out; + return -EFAULT; } - rc = 0; switch (cmd) { case CM_IOCGSTATUS: @@ -1482,9 +1477,9 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (test_bit(IS_BAD_CARD, &dev->flags)) status |= CM_BAD_CARD; if (copy_to_user(argp, &status, sizeof(int))) - rc = -EFAULT; + return -EFAULT; } - break; + return 0; case CM_IOCGATR: DEBUGP(4, dev, "... in CM_IOCGATR\n"); { @@ -1497,29 +1492,25 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } - rc = -EFAULT; if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { tmp = -1; if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) - break; + return -EFAULT; } else { if (copy_to_user(atreq->atr, dev->atr, dev->atr_len)) - break; + return -EFAULT; tmp = dev->atr_len; if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) - break; + return -EFAULT; } - rc = 0; - break; + return 0; } case CM_IOCARDOFF: @@ -1547,10 +1538,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } /* Set Flags0 = 0x42 */ DEBUGP(4, dev, "Set Flags0=0x42 \n"); @@ -1565,10 +1554,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_bit(IS_ATR_VALID, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } } /* release lock */ @@ -1581,10 +1568,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ptsreq krnptsreq; if (copy_from_user(&krnptsreq, argp, - sizeof(struct ptsreq))) { - rc = -EFAULT; - break; - } + sizeof(struct ptsreq))) + return -EFAULT; rc = 0; DEBUGP(4, dev, "... in CM_IOCSPTS\n"); @@ -1595,10 +1580,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } /* get IO lock */ if (wait_event_interruptible @@ -1607,10 +1590,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } if ((rc = set_protocol(dev, &krnptsreq)) != 0) { @@ -1623,7 +1604,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) wake_up_interruptible(&dev->ioq); } - break; + return rc; #ifdef PCMCIA_DEBUG case CM_IOSDBGLVL: /* set debug log level */ { @@ -1631,20 +1612,18 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) old_pc_debug = pc_debug; if (copy_from_user(&pc_debug, argp, sizeof(int))) - rc = -EFAULT; - else if (old_pc_debug != pc_debug) + return -EFAULT; + + if (old_pc_debug != pc_debug) DEBUGP(0, dev, "Changed debug log level " "to %i\n", pc_debug); } - break; + return rc; #endif default: DEBUGP(4, dev, "... in default (unknown IOCTL code)\n"); - rc = -ENOTTY; + return -EINVAL; } -out: - unlock_kernel(); - return rc; } static int cmm_open(struct inode *inode, struct file *filp) @@ -1652,22 +1631,16 @@ static int cmm_open(struct inode *inode, struct file *filp) struct cm4000_dev *dev; struct pcmcia_device *link; int minor = iminor(inode); - int ret; if (minor >= CM4000_MAX_DEV) return -ENODEV; - lock_kernel(); link = dev_table[minor]; - if (link == NULL || !pcmcia_dev_present(link)) { - ret = -ENODEV; - goto out; - } + if (link == NULL || !pcmcia_dev_present(link)) + return -ENODEV; - if (link->open) { - ret = -EBUSY; - goto out; - } + if (link->open) + return -EBUSY; dev = link->priv; filp->private_data = dev; @@ -1687,10 +1660,8 @@ static int cmm_open(struct inode *inode, struct file *filp) * vaild = block until valid (or card * inserted) */ - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto out; - } + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; dev->mdelay = T_50MSEC; @@ -1700,10 +1671,7 @@ static int cmm_open(struct inode *inode, struct file *filp) link->open = 1; /* only one open per device */ DEBUGP(2, dev, "<- cmm_open\n"); - ret = nonseekable_open(inode, filp); -out: - unlock_kernel(); - return ret; + return nonseekable_open(inode, filp); } static int cmm_close(struct inode *inode, struct file *filp) @@ -1929,7 +1897,7 @@ static const struct file_operations cm4000_fops = { .owner = THIS_MODULE, .read = cmm_read, .write = cmm_write, - .unlocked_ioctl = cmm_ioctl, + .ioctl = cmm_ioctl, .open = cmm_open, .release= cmm_close, }; diff --git a/trunk/drivers/char/pcmcia/cm4040_cs.c b/trunk/drivers/char/pcmcia/cm4040_cs.c index 6181f8a9b0bd..035084c07329 100644 --- a/trunk/drivers/char/pcmcia/cm4040_cs.c +++ b/trunk/drivers/char/pcmcia/cm4040_cs.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -449,30 +448,23 @@ static int cm4040_open(struct inode *inode, struct file *filp) struct reader_dev *dev; struct pcmcia_device *link; int minor = iminor(inode); - int ret; if (minor >= CM_MAX_DEV) return -ENODEV; - lock_kernel(); link = dev_table[minor]; - if (link == NULL || !pcmcia_dev_present(link)) { - ret = -ENODEV; - goto out; - } + if (link == NULL || !pcmcia_dev_present(link)) + return -ENODEV; - if (link->open) { - ret = -EBUSY; - goto out; - } + if (link->open) + return -EBUSY; dev = link->priv; filp->private_data = dev; if (filp->f_flags & O_NONBLOCK) { DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); - ret = -EAGAIN; - goto out; + return -EAGAIN; } link->open = 1; @@ -481,10 +473,7 @@ static int cm4040_open(struct inode *inode, struct file *filp) mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); DEBUGP(2, dev, "<- cm4040_open (successfully)\n"); - ret = nonseekable_open(inode, filp); -out: - unlock_kernel(); - return ret; + return nonseekable_open(inode, filp); } static int cm4040_close(struct inode *inode, struct file *filp) diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.c b/trunk/drivers/char/pcmcia/ipwireless/main.c index cc7dcea2d283..00c7f8407e3e 100644 --- a/trunk/drivers/char/pcmcia/ipwireless/main.c +++ b/trunk/drivers/char/pcmcia/ipwireless/main.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/gpu/Makefile b/trunk/drivers/gpu/Makefile deleted file mode 100644 index de566cf0414c..000000000000 --- a/trunk/drivers/gpu/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += drm/ diff --git a/trunk/drivers/gpu/drm/Makefile b/trunk/drivers/gpu/drm/Makefile deleted file mode 100644 index e9f9a97ae00a..000000000000 --- a/trunk/drivers/gpu/drm/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm - -drm-y := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ - drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ - drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ - drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ - drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o - -drm-$(CONFIG_COMPAT) += drm_ioc32.o - -obj-$(CONFIG_DRM) += drm.o -obj-$(CONFIG_DRM_TDFX) += tdfx/ -obj-$(CONFIG_DRM_R128) += r128/ -obj-$(CONFIG_DRM_RADEON)+= radeon/ -obj-$(CONFIG_DRM_MGA) += mga/ -obj-$(CONFIG_DRM_I810) += i810/ -obj-$(CONFIG_DRM_I830) += i830/ -obj-$(CONFIG_DRM_I915) += i915/ -obj-$(CONFIG_DRM_SIS) += sis/ -obj-$(CONFIG_DRM_SAVAGE)+= savage/ -obj-$(CONFIG_DRM_VIA) +=via/ - diff --git a/trunk/drivers/gpu/drm/i810/Makefile b/trunk/drivers/gpu/drm/i810/Makefile deleted file mode 100644 index 43844ecafcc5..000000000000 --- a/trunk/drivers/gpu/drm/i810/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -i810-y := i810_drv.o i810_dma.o - -obj-$(CONFIG_DRM_I810) += i810.o diff --git a/trunk/drivers/gpu/drm/i830/Makefile b/trunk/drivers/gpu/drm/i830/Makefile deleted file mode 100644 index c642ee0b238c..000000000000 --- a/trunk/drivers/gpu/drm/i830/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -i830-y := i830_drv.o i830_dma.o i830_irq.o - -obj-$(CONFIG_DRM_I830) += i830.o diff --git a/trunk/drivers/gpu/drm/i915/Makefile b/trunk/drivers/gpu/drm/i915/Makefile deleted file mode 100644 index a9e60464df74..000000000000 --- a/trunk/drivers/gpu/drm/i915/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o - -i915-$(CONFIG_COMPAT) += i915_ioc32.o - -obj-$(CONFIG_DRM_I915) += i915.o diff --git a/trunk/drivers/gpu/drm/mga/Makefile b/trunk/drivers/gpu/drm/mga/Makefile deleted file mode 100644 index 60684785c203..000000000000 --- a/trunk/drivers/gpu/drm/mga/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -mga-y := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o - -mga-$(CONFIG_COMPAT) += mga_ioc32.o - -obj-$(CONFIG_DRM_MGA) += mga.o - diff --git a/trunk/drivers/gpu/drm/r128/Makefile b/trunk/drivers/gpu/drm/r128/Makefile deleted file mode 100644 index 1cc72ae3a880..000000000000 --- a/trunk/drivers/gpu/drm/r128/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -r128-y := r128_drv.o r128_cce.o r128_state.o r128_irq.o - -r128-$(CONFIG_COMPAT) += r128_ioc32.o - -obj-$(CONFIG_DRM_R128) += r128.o diff --git a/trunk/drivers/gpu/drm/radeon/Makefile b/trunk/drivers/gpu/drm/radeon/Makefile deleted file mode 100644 index feb521ebc393..000000000000 --- a/trunk/drivers/gpu/drm/radeon/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o - -radeon-$(CONFIG_COMPAT) += radeon_ioc32.o - -obj-$(CONFIG_DRM_RADEON)+= radeon.o diff --git a/trunk/drivers/gpu/drm/savage/Makefile b/trunk/drivers/gpu/drm/savage/Makefile deleted file mode 100644 index d8f84ac7bb26..000000000000 --- a/trunk/drivers/gpu/drm/savage/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y = -Iinclude/drm -savage-y := savage_drv.o savage_bci.o savage_state.o - -obj-$(CONFIG_DRM_SAVAGE)+= savage.o - diff --git a/trunk/drivers/gpu/drm/sis/Makefile b/trunk/drivers/gpu/drm/sis/Makefile deleted file mode 100644 index 441c061c3ad0..000000000000 --- a/trunk/drivers/gpu/drm/sis/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y = -Iinclude/drm -sis-y := sis_drv.o sis_mm.o - -obj-$(CONFIG_DRM_SIS) += sis.o - - diff --git a/trunk/drivers/gpu/drm/tdfx/Makefile b/trunk/drivers/gpu/drm/tdfx/Makefile deleted file mode 100644 index 0379f294b32a..000000000000 --- a/trunk/drivers/gpu/drm/tdfx/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -tdfx-y := tdfx_drv.o - -obj-$(CONFIG_DRM_TDFX) += tdfx.o diff --git a/trunk/drivers/gpu/drm/via/Makefile b/trunk/drivers/gpu/drm/via/Makefile deleted file mode 100644 index d59e258e2c13..000000000000 --- a/trunk/drivers/gpu/drm/via/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -ccflags-y := -Iinclude/drm -via-y := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o - -obj-$(CONFIG_DRM_VIA) +=via.o diff --git a/trunk/drivers/ide/legacy/ide-cs.c b/trunk/drivers/ide/legacy/ide-cs.c index 8dbf4d9b6447..3381424d70a1 100644 --- a/trunk/drivers/ide/legacy/ide-cs.c +++ b/trunk/drivers/ide/legacy/ide-cs.c @@ -63,11 +63,11 @@ MODULE_LICENSE("Dual MPL/GPL"); #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) -#ifdef CONFIG_PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, 0); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -/*static char *version = -"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";*/ +static char *version = +"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -375,7 +375,7 @@ static int ide_config(struct pcmcia_device *link) ======================================================================*/ -static void ide_release(struct pcmcia_device *link) +void ide_release(struct pcmcia_device *link) { ide_info_t *info = link->priv; ide_hwif_t *hwif = info->hwif; diff --git a/trunk/drivers/md/linear.c b/trunk/drivers/md/linear.c index 6a866d7c8ae5..10748240cb2f 100644 --- a/trunk/drivers/md/linear.c +++ b/trunk/drivers/md/linear.c @@ -50,19 +50,17 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector) /** * linear_mergeable_bvec -- tell bio layer if two requests can be merged * @q: request queue - * @bvm: properties of new bio + * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * * Return amount of bytes we can take at this offset */ -static int linear_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int linear_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) { mddev_t *mddev = q->queuedata; dev_info_t *dev0; - unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + unsigned long maxsectors, bio_sectors = bio->bi_size >> 9; + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); dev0 = which_dev(mddev, sector); maxsectors = (dev0->size << 1) - (sector - (dev0->offset<<1)); diff --git a/trunk/drivers/md/raid0.c b/trunk/drivers/md/raid0.c index bcbb82594a19..914c04ddec7c 100644 --- a/trunk/drivers/md/raid0.c +++ b/trunk/drivers/md/raid0.c @@ -241,20 +241,18 @@ static int create_strip_zones (mddev_t *mddev) /** * raid0_mergeable_bvec -- tell bio layer if a two requests can be merged * @q: request queue - * @bvm: properties of new bio + * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * * Return amount of bytes we can accept at this offset */ -static int raid0_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int raid0_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) { mddev_t *mddev = q->queuedata; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); int max; unsigned int chunk_sectors = mddev->chunk_size >> 9; - unsigned int bio_sectors = bvm->bi_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; if (max < 0) max = 0; /* bio_add cannot handle a negative return */ diff --git a/trunk/drivers/md/raid10.c b/trunk/drivers/md/raid10.c index 22bb2b1b886d..a71277b640ab 100644 --- a/trunk/drivers/md/raid10.c +++ b/trunk/drivers/md/raid10.c @@ -439,27 +439,26 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev) /** * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged * @q: request queue - * @bvm: properties of new bio + * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * * Return amount of bytes we can accept at this offset * If near_copies == raid_disk, there are no striping issues, * but in that case, the function isn't called at all. */ -static int raid10_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int raid10_mergeable_bvec(struct request_queue *q, struct bio *bio, + struct bio_vec *bio_vec) { mddev_t *mddev = q->queuedata; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); int max; unsigned int chunk_sectors = mddev->chunk_size >> 9; - unsigned int bio_sectors = bvm->bi_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; if (max < 0) max = 0; /* bio_add cannot handle a negative return */ - if (max <= biovec->bv_len && bio_sectors == 0) - return biovec->bv_len; + if (max <= bio_vec->bv_len && bio_sectors == 0) + return bio_vec->bv_len; else return max; } diff --git a/trunk/drivers/md/raid5.c b/trunk/drivers/md/raid5.c index 9ce7154845c6..3b27df52456b 100644 --- a/trunk/drivers/md/raid5.c +++ b/trunk/drivers/md/raid5.c @@ -3314,17 +3314,15 @@ static int raid5_congested(void *data, int bits) /* We want read requests to align with chunks where possible, * but write requests don't need to. */ -static int raid5_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int raid5_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) { mddev_t *mddev = q->queuedata; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); int max; unsigned int chunk_sectors = mddev->chunk_size >> 9; - unsigned int bio_sectors = bvm->bi_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; - if ((bvm->bi_rw & 1) == WRITE) + if (bio_data_dir(bio) == WRITE) return biovec->bv_len; /* always allow writes to be mergeable */ max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; diff --git a/trunk/drivers/mtd/ftl.c b/trunk/drivers/mtd/ftl.c index 5c29872184e6..4a79b187b568 100644 --- a/trunk/drivers/mtd/ftl.c +++ b/trunk/drivers/mtd/ftl.c @@ -130,6 +130,10 @@ typedef struct partition_t { u_int16_t DataUnits; u_int32_t BlocksPerUnit; erase_unit_header_t header; +#if 0 + region_info_t region; + memory_handle_t handle; +#endif } partition_t; /* Partition state flags */ diff --git a/trunk/drivers/mtd/maps/pcmciamtd.c b/trunk/drivers/mtd/maps/pcmciamtd.c index 0cc31675aeb9..1912d968718b 100644 --- a/trunk/drivers/mtd/maps/pcmciamtd.c +++ b/trunk/drivers/mtd/maps/pcmciamtd.c @@ -498,14 +498,17 @@ static int pcmciamtd_config(struct pcmcia_device *link) int i; config_info_t t; static char *probes[] = { "jedec_probe", "cfi_probe" }; + cisinfo_t cisinfo; int new_name = 0; DEBUG(3, "link=0x%p", link); DEBUG(2, "Validating CIS"); - ret = pcmcia_validate_cis(link, NULL); + ret = pcmcia_validate_cis(link, &cisinfo); if(ret != CS_SUCCESS) { cs_error(link, GetTupleData, ret); + } else { + DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains); } card_settings(dev, link, &new_name); @@ -560,7 +563,9 @@ static int pcmciamtd_config(struct pcmcia_device *link) DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); /* Get write protect status */ - DEBUG(2, "window handle = 0x%8.8lx", (unsigned long)link->win); + CS_CHECK(GetStatus, pcmcia_get_status(link, &status)); + DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", + status.CardState, (unsigned long)link->win); dev->win_base = ioremap(req.Base, req.Size); if(!dev->win_base) { err("ioremap(%lu, %u) failed", req.Base, req.Size); diff --git a/trunk/drivers/net/xen-netfront.c b/trunk/drivers/net/xen-netfront.c index ef671d1a3bf0..d26f69b0184f 100644 --- a/trunk/drivers/net/xen-netfront.c +++ b/trunk/drivers/net/xen-netfront.c @@ -1324,7 +1324,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) goto fail; } - txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); + txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL); if (!txs) { err = -ENOMEM; xenbus_dev_fatal(dev, err, "allocating tx ring page"); @@ -1340,7 +1340,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) } info->tx_ring_ref = err; - rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); + rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL); if (!rxs) { err = -ENOMEM; xenbus_dev_fatal(dev, err, "allocating rx ring page"); diff --git a/trunk/drivers/pcmcia/Kconfig b/trunk/drivers/pcmcia/Kconfig index e45402adac3f..1b0eb5aaf650 100644 --- a/trunk/drivers/pcmcia/Kconfig +++ b/trunk/drivers/pcmcia/Kconfig @@ -263,13 +263,6 @@ config OMAP_CF Say Y here to support the CompactFlash controller on OMAP. Note that this doesn't support "True IDE" mode. -config BFIN_CFPCMCIA - tristate "Blackfin CompactFlash PCMCIA Driver" - depends on PCMCIA && BLACKFIN - help - Say Y here to support the CompactFlash PCMCIA driver for Blackfin. - - config AT91_CF tristate "AT91 CompactFlash Controller" depends on PCMCIA && ARCH_AT91RM9200 diff --git a/trunk/drivers/pcmcia/Makefile b/trunk/drivers/pcmcia/Makefile index 85c6cc931f97..6f6478ba7174 100644 --- a/trunk/drivers/pcmcia/Makefile +++ b/trunk/drivers/pcmcia/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o obj-$(CONFIG_OMAP_CF) += omap_cf.o -obj-$(CONFIG_BFIN_CFPCMCIA) += bfin_cf_pcmcia.o obj-$(CONFIG_AT91_CF) += at91_cf.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o diff --git a/trunk/drivers/pcmcia/au1000_generic.h b/trunk/drivers/pcmcia/au1000_generic.h index a53ef5902518..1e467bb54077 100644 --- a/trunk/drivers/pcmcia/au1000_generic.h +++ b/trunk/drivers/pcmcia/au1000_generic.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "cs_internal.h" @@ -33,9 +34,9 @@ #define AU1000_PCMCIA_IO_SPEED (255) #define AU1000_PCMCIA_MEM_SPEED (300) -#define AU1X_SOCK0_IO 0xF00000000ULL -#define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL -#define AU1X_SOCK0_PHYS_MEM 0xF80000000ULL +#define AU1X_SOCK0_IO 0xF00000000 +#define AU1X_SOCK0_PHYS_ATTR 0xF40000000 +#define AU1X_SOCK0_PHYS_MEM 0xF80000000 /* pseudo 32 bit phys addresses, which get fixed up to the * real 36 bit address in fixup_bigphys_addr() */ #define AU1X_SOCK0_PSEUDO_PHYS_ATTR 0xF4000000 @@ -44,20 +45,16 @@ /* pcmcia socket 1 needs external glue logic so the memory map * differs from board to board. */ -#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || \ - defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || \ - defined(CONFIG_MIPS_PB1200) -#define AU1X_SOCK1_IO 0xF08000000ULL -#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL -#define AU1X_SOCK1_PHYS_MEM 0xF88000000ULL +#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_PB1200) +#define AU1X_SOCK1_IO 0xF08000000 +#define AU1X_SOCK1_PHYS_ATTR 0xF48000000 +#define AU1X_SOCK1_PHYS_MEM 0xF88000000 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000 #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8800000 -#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \ - defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || \ - defined(CONFIG_MIPS_DB1200) -#define AU1X_SOCK1_IO 0xF04000000ULL -#define AU1X_SOCK1_PHYS_ATTR 0xF44000000ULL -#define AU1X_SOCK1_PHYS_MEM 0xF84000000ULL +#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_DB1200) +#define AU1X_SOCK1_IO 0xF04000000 +#define AU1X_SOCK1_PHYS_ATTR 0xF44000000 +#define AU1X_SOCK1_PHYS_MEM 0xF84000000 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000 #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8400000 #endif diff --git a/trunk/drivers/pcmcia/au1000_pb1x00.c b/trunk/drivers/pcmcia/au1000_pb1x00.c index aa1cd4d3aa29..157e41423a0a 100644 --- a/trunk/drivers/pcmcia/au1000_pb1x00.c +++ b/trunk/drivers/pcmcia/au1000_pb1x00.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/au1000_xxs1500.c b/trunk/drivers/pcmcia/au1000_xxs1500.c index 8a9b18cee847..c78ed5347510 100644 --- a/trunk/drivers/pcmcia/au1000_xxs1500.c +++ b/trunk/drivers/pcmcia/au1000_xxs1500.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/bfin_cf_pcmcia.c b/trunk/drivers/pcmcia/bfin_cf_pcmcia.c deleted file mode 100644 index bb7338863fb9..000000000000 --- a/trunk/drivers/pcmcia/bfin_cf_pcmcia.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * file: drivers/pcmcia/bfin_cf.c - * - * based on: drivers/pcmcia/omap_cf.c - * omap_cf.c -- OMAP 16xx CompactFlash controller driver - * - * Copyright (c) 2005 David Brownell - * Copyright (c) 2006-2008 Michael Hennerich Analog Devices Inc. - * - * bugs: enter bugs at http://blackfin.uclinux.org/ - * - * this program is free software; you can redistribute it and/or modify - * it under the terms of the gnu general public license as published by - * the free software foundation; either version 2, or (at your option) - * any later version. - * - * this program is distributed in the hope that it will be useful, - * but without any warranty; without even the implied warranty of - * merchantability or fitness for a particular purpose. see the - * gnu general public license for more details. - * - * you should have received a copy of the gnu general public license - * along with this program; see the file copying. - * if not, write to the free software foundation, - * 59 temple place - suite 330, boston, ma 02111-1307, usa. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SZ_1K 0x00000400 -#define SZ_8K 0x00002000 -#define SZ_2K (2 * SZ_1K) - -#define POLL_INTERVAL (2 * HZ) - -#define CF_ATASEL_ENA 0x20311802 /* Inverts RESET */ -#define CF_ATASEL_DIS 0x20311800 - -#define bfin_cf_present(pfx) (gpio_get_value(pfx)) - -/*--------------------------------------------------------------------------*/ - -static const char driver_name[] = "bfin_cf_pcmcia"; - -struct bfin_cf_socket { - struct pcmcia_socket socket; - - struct timer_list timer; - unsigned present:1; - unsigned active:1; - - struct platform_device *pdev; - unsigned long phys_cf_io; - unsigned long phys_cf_attr; - u_int irq; - u_short cd_pfx; -}; - -/*--------------------------------------------------------------------------*/ -static int bfin_cf_reset(void) -{ - outw(0, CF_ATASEL_ENA); - mdelay(200); - outw(0, CF_ATASEL_DIS); - - return 0; -} - -static int bfin_cf_ss_init(struct pcmcia_socket *s) -{ - return 0; -} - -/* the timer is primarily to kick this socket's pccardd */ -static void bfin_cf_timer(unsigned long _cf) -{ - struct bfin_cf_socket *cf = (void *)_cf; - unsigned short present = bfin_cf_present(cf->cd_pfx); - - if (present != cf->present) { - cf->present = present; - dev_dbg(&cf->pdev->dev, ": card %s\n", - present ? "present" : "gone"); - pcmcia_parse_events(&cf->socket, SS_DETECT); - } - - if (cf->active) - mod_timer(&cf->timer, jiffies + POLL_INTERVAL); -} - -static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp) -{ - struct bfin_cf_socket *cf; - - if (!sp) - return -EINVAL; - - cf = container_of(s, struct bfin_cf_socket, socket); - - if (bfin_cf_present(cf->cd_pfx)) { - *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD; - s->irq.AssignedIRQ = 0; - s->pci_irq = cf->irq; - - } else - *sp = 0; - return 0; -} - -static int -bfin_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) -{ - - struct bfin_cf_socket *cf; - cf = container_of(sock, struct bfin_cf_socket, socket); - - switch (s->Vcc) { - case 0: - case 33: - break; - case 50: - break; - default: - return -EINVAL; - } - - if (s->flags & SS_RESET) { - disable_irq(cf->irq); - bfin_cf_reset(); - enable_irq(cf->irq); - } - - dev_dbg(&cf->pdev->dev, ": Vcc %d, io_irq %d, flags %04x csc %04x\n", - s->Vcc, s->io_irq, s->flags, s->csc_mask); - - return 0; -} - -static int bfin_cf_ss_suspend(struct pcmcia_socket *s) -{ - return bfin_cf_set_socket(s, &dead_socket); -} - -/* regions are 2K each: mem, attrib, io (and reserved-for-ide) */ - -static int bfin_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) -{ - struct bfin_cf_socket *cf; - - cf = container_of(s, struct bfin_cf_socket, socket); - io->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT; - io->start = cf->phys_cf_io; - io->stop = io->start + SZ_2K - 1; - return 0; -} - -static int -bfin_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) -{ - struct bfin_cf_socket *cf; - - if (map->card_start) - return -EINVAL; - cf = container_of(s, struct bfin_cf_socket, socket); - map->static_start = cf->phys_cf_io; - map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT; - if (map->flags & MAP_ATTRIB) - map->static_start = cf->phys_cf_attr; - - return 0; -} - -static struct pccard_operations bfin_cf_ops = { - .init = bfin_cf_ss_init, - .suspend = bfin_cf_ss_suspend, - .get_status = bfin_cf_get_status, - .set_socket = bfin_cf_set_socket, - .set_io_map = bfin_cf_set_io_map, - .set_mem_map = bfin_cf_set_mem_map, -}; - -/*--------------------------------------------------------------------------*/ - -static int __devinit bfin_cf_probe(struct platform_device *pdev) -{ - struct bfin_cf_socket *cf; - struct resource *io_mem, *attr_mem; - int irq; - unsigned short cd_pfx; - int status = 0; - - dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n"); - - irq = platform_get_irq(pdev, 0); - if (!irq) - return -EINVAL; - - cd_pfx = platform_get_irq(pdev, 1); /*Card Detect GPIO PIN */ - - if (gpio_request(cd_pfx, "pcmcia: CD")) { - dev_err(&pdev->dev, - "Failed ro request Card Detect GPIO_%d\n", - cd_pfx); - return -EBUSY; - } - gpio_direction_input(cd_pfx); - - cf = kzalloc(sizeof *cf, GFP_KERNEL); - if (!cf) { - gpio_free(cd_pfx); - return -ENOMEM; - } - - cf->cd_pfx = cd_pfx; - - setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf); - - cf->pdev = pdev; - platform_set_drvdata(pdev, cf); - - cf->irq = irq; - cf->socket.pci_irq = irq; - - set_irq_type(irq, IRQF_TRIGGER_LOW); - - io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - if (!io_mem || !attr_mem) - goto fail0; - - cf->phys_cf_io = io_mem->start; - cf->phys_cf_attr = attr_mem->start; - - /* pcmcia layer only remaps "real" memory */ - cf->socket.io_offset = (unsigned long) - ioremap(cf->phys_cf_io, SZ_2K); - - if (!cf->socket.io_offset) - goto fail0; - - dev_err(&pdev->dev, ": on irq %d\n", irq); - - dev_dbg(&pdev->dev, ": %s\n", - bfin_cf_present(cf->cd_pfx) ? "present" : "(not present)"); - - cf->socket.owner = THIS_MODULE; - cf->socket.dev.parent = &pdev->dev; - cf->socket.ops = &bfin_cf_ops; - cf->socket.resource_ops = &pccard_static_ops; - cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP - | SS_CAP_MEM_ALIGN; - cf->socket.map_size = SZ_2K; - - status = pcmcia_register_socket(&cf->socket); - if (status < 0) - goto fail2; - - cf->active = 1; - mod_timer(&cf->timer, jiffies + POLL_INTERVAL); - return 0; - -fail2: - iounmap((void __iomem *)cf->socket.io_offset); - release_mem_region(cf->phys_cf_io, SZ_8K); - -fail0: - gpio_free(cf->cd_pfx); - kfree(cf); - platform_set_drvdata(pdev, NULL); - - return status; -} - -static int __devexit bfin_cf_remove(struct platform_device *pdev) -{ - struct bfin_cf_socket *cf = platform_get_drvdata(pdev); - - gpio_free(cf->cd_pfx); - cf->active = 0; - pcmcia_unregister_socket(&cf->socket); - del_timer_sync(&cf->timer); - iounmap((void __iomem *)cf->socket.io_offset); - release_mem_region(cf->phys_cf_io, SZ_8K); - platform_set_drvdata(pdev, NULL); - kfree(cf); - return 0; -} - -static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - return pcmcia_socket_dev_suspend(&pdev->dev, mesg); -} - -static int bfin_cf_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} - -static struct platform_driver bfin_cf_driver = { - .driver = { - .name = (char *)driver_name, - .owner = THIS_MODULE, - }, - .probe = bfin_cf_probe, - .remove = __devexit_p(bfin_cf_remove), - .suspend = bfin_cf_suspend, - .resume = bfin_cf_resume, -}; - -static int __init bfin_cf_init(void) -{ - return platform_driver_register(&bfin_cf_driver); -} - -static void __exit bfin_cf_exit(void) -{ - platform_driver_unregister(&bfin_cf_driver); -} - -module_init(bfin_cf_init); -module_exit(bfin_cf_exit); - -MODULE_AUTHOR("Michael Hennerich ") -MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/pcmcia/cardbus.c b/trunk/drivers/pcmcia/cardbus.c index 911ca0e8dfc2..fb2f38dc92c5 100644 --- a/trunk/drivers/pcmcia/cardbus.c +++ b/trunk/drivers/pcmcia/cardbus.c @@ -30,9 +30,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/cistpl.c b/trunk/drivers/pcmcia/cistpl.c index 9fcff0c33619..36379535f9da 100644 --- a/trunk/drivers/pcmcia/cistpl.c +++ b/trunk/drivers/pcmcia/cistpl.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include "cs_internal.h" @@ -1438,11 +1439,10 @@ EXPORT_SYMBOL(pccard_read_tuple); ======================================================================*/ -int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *info) +int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info) { tuple_t *tuple; cisparse_t *p; - unsigned int count = 0; int ret, reserved, dev_ok = 0, ident_ok = 0; if (!s) @@ -1457,7 +1457,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned return CS_OUT_OF_RESOURCE; } - count = reserved = 0; + info->Chains = reserved = 0; tuple->DesiredTuple = RETURN_FIRST_TUPLE; tuple->Attributes = TUPLE_RETURN_COMMON; ret = pccard_get_first_tuple(s, function, tuple); @@ -1482,7 +1482,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned if (!dev_ok && !ident_ok) goto done; - for (count = 1; count < MAX_TUPLES; count++) { + for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) { ret = pccard_get_next_tuple(s, function, tuple); if (ret != CS_SUCCESS) break; if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || @@ -1490,13 +1490,11 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) reserved++; } - if ((count) || (reserved > 5) || - ((!dev_ok || !ident_ok) && (count > 10))) - count = 0; + if ((info->Chains == MAX_TUPLES) || (reserved > 5) || + ((!dev_ok || !ident_ok) && (info->Chains > 10))) + info->Chains = 0; done: - if (info) - *info = count; kfree(tuple); kfree(p); return CS_SUCCESS; diff --git a/trunk/drivers/pcmcia/cs.c b/trunk/drivers/pcmcia/cs.c index d1207393fc3e..29276bd28295 100644 --- a/trunk/drivers/pcmcia/cs.c +++ b/trunk/drivers/pcmcia/cs.c @@ -32,9 +32,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include #include @@ -236,6 +238,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) init_completion(&socket->socket_released); init_completion(&socket->thread_done); + init_waitqueue_head(&socket->thread_wait); mutex_init(&socket->skt_mutex); spin_lock_init(&socket->thread_lock); @@ -275,9 +278,10 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops); - if (socket->thread) + if (socket->thread) { + wake_up(&socket->thread_wait); kthread_stop(socket->thread); - + } release_cis_mem(socket); /* remove from our own list */ @@ -631,6 +635,7 @@ static void socket_detect_change(struct pcmcia_socket *skt) static int pccardd(void *__skt) { struct pcmcia_socket *skt = __skt; + DECLARE_WAITQUEUE(wait, current); int ret; skt->thread = current; @@ -651,6 +656,7 @@ static int pccardd(void *__skt) if (ret) dev_warn(&skt->dev, "err %d adding socket attributes\n", ret); + add_wait_queue(&skt->thread_wait, &wait); complete(&skt->thread_done); set_freezable(); @@ -688,6 +694,8 @@ static int pccardd(void *__skt) /* make sure we are running before we exit */ set_current_state(TASK_RUNNING); + remove_wait_queue(&skt->thread_wait, &wait); + /* remove from the device core */ pccard_sysfs_remove_socket(&skt->dev); device_unregister(&skt->dev); @@ -708,7 +716,7 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) s->thread_events |= events; spin_unlock_irqrestore(&s->thread_lock, flags); - wake_up_process(s->thread); + wake_up(&s->thread_wait); } } /* pcmcia_parse_events */ EXPORT_SYMBOL(pcmcia_parse_events); diff --git a/trunk/drivers/pcmcia/cs_internal.h b/trunk/drivers/pcmcia/cs_internal.h index 63dc1a28bda2..e7d5d141f24d 100644 --- a/trunk/drivers/pcmcia/cs_internal.h +++ b/trunk/drivers/pcmcia/cs_internal.h @@ -26,6 +26,18 @@ #define CLIENT_WIN_REQ(i) (0x1<<(i)) #define CLIENT_CARDBUS 0x8000 +#define REGION_MAGIC 0xE3C9 +typedef struct region_t { + u_short region_magic; + u_short state; + dev_info_t dev_info; + struct pcmcia_device *mtd; + u_int MediaID; + region_info_t info; +} region_t; + +#define REGION_STALE 0x01 + /* Each card function gets one of these guys */ typedef struct config_t { struct kref ref; @@ -118,6 +130,7 @@ extern struct list_head pcmcia_socket_list; int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req); int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config); int pccard_reset_card(struct pcmcia_socket *skt); +int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_status_t *status); struct pcmcia_callback{ diff --git a/trunk/drivers/pcmcia/ds.c b/trunk/drivers/pcmcia/ds.c index 4174d9656e35..e40775443d04 100644 --- a/trunk/drivers/pcmcia/ds.c +++ b/trunk/drivers/pcmcia/ds.c @@ -25,6 +25,7 @@ #include #include +#define IN_CARD_SERVICES #include #include #include @@ -740,8 +741,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f static int pcmcia_card_add(struct pcmcia_socket *s) { + cisinfo_t cisinfo; cistpl_longlink_mfc_t mfc; - unsigned int no_funcs, i, no_chains; + unsigned int no_funcs, i; int ret = 0; if (!(s->resource_setup_done)) { @@ -755,8 +757,8 @@ static int pcmcia_card_add(struct pcmcia_socket *s) return -EAGAIN; /* try again, but later... */ } - ret = pccard_validate_cis(s, BIND_FN_ALL, &no_chains); - if (ret || !no_chains) { + ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); + if (ret || !cisinfo.Chains) { ds_dbg(0, "invalid CIS or invalid resources\n"); return -ENODEV; } @@ -850,7 +852,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) { struct pcmcia_socket *s = dev->socket; const struct firmware *fw; - char path[FIRMWARE_NAME_MAX]; + char path[20]; int ret = -ENOMEM; int no_funcs; int old_funcs; @@ -862,7 +864,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) ds_dbg(1, "trying to load CIS file %s\n", filename); - if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) { + if (strlen(filename) > 14) { printk(KERN_WARNING "pcmcia: CIS filename is too long [%s]\n", filename); return -EINVAL; diff --git a/trunk/drivers/pcmcia/hd64465_ss.c b/trunk/drivers/pcmcia/hd64465_ss.c index fb2bc1fb015d..f2e810f53c81 100644 --- a/trunk/drivers/pcmcia/hd64465_ss.c +++ b/trunk/drivers/pcmcia/hd64465_ss.c @@ -1,4 +1,6 @@ /* + * $Id: hd64465_ss.c,v 1.7 2003/07/06 14:42:50 lethal Exp $ + * * Device driver for the PCMCIA controller module of the * Hitachi HD64465 handheld companion chip. * @@ -46,6 +48,7 @@ #include #include #include +#include #include "cs_internal.h" #define MODNAME "hd64465_ss" diff --git a/trunk/drivers/pcmcia/i82092.c b/trunk/drivers/pcmcia/i82092.c index 46561face128..e13618656ff7 100644 --- a/trunk/drivers/pcmcia/i82092.c +++ b/trunk/drivers/pcmcia/i82092.c @@ -5,6 +5,8 @@ * * Author: Arjan Van De Ven * Loosly based on i82365.c from the pcmcia-cs package + * + * $Id: i82092aa.c,v 1.2 2001/10/23 14:43:34 arjanv Exp $ */ #include diff --git a/trunk/drivers/pcmcia/i82092aa.h b/trunk/drivers/pcmcia/i82092aa.h index 8836d393ad02..b0d453303c5d 100644 --- a/trunk/drivers/pcmcia/i82092aa.h +++ b/trunk/drivers/pcmcia/i82092aa.h @@ -3,6 +3,8 @@ #include +/* $Id: i82092aa.h,v 1.1.1.1 2001/09/19 14:53:15 dwmw2 Exp $ */ + /* Debuging defines */ #ifdef NOTRACE #define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) diff --git a/trunk/drivers/pcmcia/i82365.c b/trunk/drivers/pcmcia/i82365.c index 68f6b2702bc4..32a2ab119798 100644 --- a/trunk/drivers/pcmcia/i82365.c +++ b/trunk/drivers/pcmcia/i82365.c @@ -1263,7 +1263,7 @@ static int __init init_i82365(void) ret = driver_register(&i82365_driver); if (ret) - goto err_out; + return ret; i82365_device = platform_device_alloc("i82365", 0); if (i82365_device) { @@ -1273,8 +1273,10 @@ static int __init init_i82365(void) } else ret = -ENOMEM; - if (ret) - goto err_driver_unregister; + if (ret) { + driver_unregister(&i82365_driver); + return ret; + } printk(KERN_INFO "Intel ISA PCIC probe: "); sockets = 0; @@ -1283,17 +1285,16 @@ static int __init init_i82365(void) if (sockets == 0) { printk("not found.\n"); - ret = -ENODEV; - goto err_dev_unregister; + platform_device_unregister(i82365_device); + release_region(i365_base, 2); + driver_unregister(&i82365_driver); + return -ENODEV; } /* Set up interrupt handler(s) */ if (grab_irq != 0) - ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); - - if (ret) - goto err_socket_release; - + request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); + /* register sockets with the pcmcia core */ for (i = 0; i < sockets; i++) { socket[i].socket.dev.parent = &i82365_device->dev; @@ -1323,23 +1324,7 @@ static int __init init_i82365(void) } return 0; -err_socket_release: - for (i = 0; i < sockets; i++) { - /* Turn off all interrupt sources! */ - i365_set(i, I365_CSCINT, 0); - release_region(socket[i].ioaddr, 2); - } -err_dev_unregister: - platform_device_unregister(i82365_device); - release_region(i365_base, 2); -#ifdef CONFIG_PNP - if (i82365_pnpdev) - pnp_disable_dev(i82365_pnpdev); -#endif -err_driver_unregister: - driver_unregister(&i82365_driver); -err_out: - return ret; + } /* init_i82365 */ static void __exit exit_i82365(void) diff --git a/trunk/drivers/pcmcia/m8xx_pcmcia.c b/trunk/drivers/pcmcia/m8xx_pcmcia.c index 13a5fbd50a07..ac70d2cb7dd4 100644 --- a/trunk/drivers/pcmcia/m8xx_pcmcia.c +++ b/trunk/drivers/pcmcia/m8xx_pcmcia.c @@ -1,7 +1,7 @@ /* * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. * - * (C) 1999-2000 Magnus Damm + * (C) 1999-2000 Magnus Damm * (C) 2001-2002 Montavista Software, Inc. * * @@ -60,6 +60,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/pcmcia/pcmcia_ioctl.c b/trunk/drivers/pcmcia/pcmcia_ioctl.c index afd00e7bbbef..5f186abca108 100644 --- a/trunk/drivers/pcmcia/pcmcia_ioctl.c +++ b/trunk/drivers/pcmcia/pcmcia_ioctl.c @@ -29,10 +29,10 @@ #include #include +#define IN_CARD_SERVICES #include #include #include -#include #include #include @@ -138,154 +138,6 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, } #endif - -#ifdef CONFIG_PCMCIA_PROBE - -static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) -{ - int irq; - u32 mask; - - irq = adj->resource.irq.IRQ; - if ((irq < 0) || (irq > 15)) - return CS_BAD_IRQ; - - if (adj->Action != REMOVE_MANAGED_RESOURCE) - return 0; - - mask = 1 << irq; - - if (!(s->irq_mask & mask)) - return 0; - - s->irq_mask &= ~mask; - - return 0; -} - -#else - -static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { - return CS_SUCCESS; -} - -#endif - -static int pcmcia_adjust_resource_info(adjust_t *adj) -{ - struct pcmcia_socket *s; - int ret = CS_UNSUPPORTED_FUNCTION; - unsigned long flags; - - down_read(&pcmcia_socket_list_rwsem); - list_for_each_entry(s, &pcmcia_socket_list, socket_list) { - - if (adj->Resource == RES_IRQ) - ret = adjust_irq(s, adj); - - else if (s->resource_ops->add_io) { - unsigned long begin, end; - - /* you can't use the old interface if the new - * one was used before */ - spin_lock_irqsave(&s->lock, flags); - if ((s->resource_setup_new) && - !(s->resource_setup_old)) { - spin_unlock_irqrestore(&s->lock, flags); - continue; - } else if (!(s->resource_setup_old)) - s->resource_setup_old = 1; - spin_unlock_irqrestore(&s->lock, flags); - - switch (adj->Resource) { - case RES_MEMORY_RANGE: - begin = adj->resource.memory.Base; - end = adj->resource.memory.Base + adj->resource.memory.Size - 1; - if (s->resource_ops->add_mem) - ret =s->resource_ops->add_mem(s, adj->Action, begin, end); - case RES_IO_RANGE: - begin = adj->resource.io.BasePort; - end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1; - if (s->resource_ops->add_io) - ret = s->resource_ops->add_io(s, adj->Action, begin, end); - } - if (!ret) { - /* as there's no way we know this is the - * last call to adjust_resource_info, we - * always need to assume this is the latest - * one... */ - spin_lock_irqsave(&s->lock, flags); - s->resource_setup_done = 1; - spin_unlock_irqrestore(&s->lock, flags); - } - } - } - up_read(&pcmcia_socket_list_rwsem); - - return (ret); -} - -/** pccard_get_status - * - * Get the current socket state bits. We don't support the latched - * SocketState yet: I haven't seen any point for it. - */ - -static int pccard_get_status(struct pcmcia_socket *s, - struct pcmcia_device *p_dev, - cs_status_t *status) -{ - config_t *c; - int val; - - s->ops->get_status(s, &val); - status->CardState = status->SocketState = 0; - status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; - status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; - status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; - status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; - if (s->state & SOCKET_SUSPEND) - status->CardState |= CS_EVENT_PM_SUSPEND; - if (!(s->state & SOCKET_PRESENT)) - return CS_NO_CARD; - - c = (p_dev) ? p_dev->function_config : NULL; - - if ((c != NULL) && (c->state & CONFIG_LOCKED) && - (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { - u_char reg; - if (c->CardValues & PRESENT_PIN_REPLACE) { - pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); - status->CardState |= - (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; - status->CardState |= - (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; - status->CardState |= - (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; - status->CardState |= - (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; - } else { - /* No PRR? Then assume we're always ready */ - status->CardState |= CS_EVENT_READY_CHANGE; - } - if (c->CardValues & PRESENT_EXT_STATUS) { - pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); - status->CardState |= - (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; - } - return CS_SUCCESS; - } - status->CardState |= - (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; - status->CardState |= - (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; - status->CardState |= - (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; - status->CardState |= - (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; - return CS_SUCCESS; -} /* pccard_get_status */ - /*====================================================================== These manage a ring buffer of events pending for one user process @@ -694,6 +546,8 @@ static u_int ds_poll(struct file *file, poll_table *wait) /*====================================================================*/ +extern int pcmcia_adjust_resource_info(adjust_t *adj); + static int ds_ioctl(struct inode * inode, struct file * file, u_int cmd, u_long arg) { @@ -795,7 +649,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, mutex_lock(&s->skt_mutex); pcmcia_validate_mem(s); mutex_unlock(&s->skt_mutex); - ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains); + ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo); break; case DS_SUSPEND_CARD: ret = pcmcia_suspend_card(s); diff --git a/trunk/drivers/pcmcia/pcmcia_resource.c b/trunk/drivers/pcmcia/pcmcia_resource.c index 4884a18cf9e6..1d128fbd1a92 100644 --- a/trunk/drivers/pcmcia/pcmcia_resource.c +++ b/trunk/drivers/pcmcia/pcmcia_resource.c @@ -21,9 +21,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include #include @@ -309,6 +311,74 @@ int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, EXPORT_SYMBOL(pcmcia_get_window); +/** pccard_get_status + * + * Get the current socket state bits. We don't support the latched + * SocketState yet: I haven't seen any point for it. + */ + +int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, + cs_status_t *status) +{ + config_t *c; + int val; + + s->ops->get_status(s, &val); + status->CardState = status->SocketState = 0; + status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; + status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; + status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; + status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; + if (s->state & SOCKET_SUSPEND) + status->CardState |= CS_EVENT_PM_SUSPEND; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + + c = (p_dev) ? p_dev->function_config : NULL; + + if ((c != NULL) && (c->state & CONFIG_LOCKED) && + (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { + u_char reg; + if (c->CardValues & PRESENT_PIN_REPLACE) { + pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); + status->CardState |= + (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; + status->CardState |= + (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; + status->CardState |= + (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; + status->CardState |= + (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; + } else { + /* No PRR? Then assume we're always ready */ + status->CardState |= CS_EVENT_READY_CHANGE; + } + if (c->CardValues & PRESENT_EXT_STATUS) { + pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); + status->CardState |= + (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; + } + return CS_SUCCESS; + } + status->CardState |= + (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; + status->CardState |= + (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; + status->CardState |= + (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; + status->CardState |= + (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; + return CS_SUCCESS; +} /* pccard_get_status */ + +int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status) +{ + return pccard_get_status(p_dev->socket, p_dev, status); +} +EXPORT_SYMBOL(pcmcia_get_status); + + + /** pcmcia_get_mem_page * * Change the card address of an already open memory window. @@ -742,15 +812,6 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) type = IRQF_SHARED; #ifdef CONFIG_PCMCIA_PROBE - -#ifdef IRQ_NOAUTOEN - /* if the underlying IRQ infrastructure allows for it, only allocate - * the IRQ, but do not enable it - */ - if (!(req->Attributes & IRQ_HANDLE_PRESENT)) - type |= IRQ_NOAUTOEN; -#endif /* IRQ_NOAUTOEN */ - if (s->irq.AssignedIRQ != 0) { /* If the interrupt is already assigned, it must be the same */ irq = s->irq.AssignedIRQ; @@ -905,7 +966,7 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) { pcmcia_release_configuration(p_dev); pcmcia_release_io(p_dev, &p_dev->io); pcmcia_release_irq(p_dev, &p_dev->irq); - if (p_dev->win) + if (&p_dev->win) pcmcia_release_window(p_dev->win); } EXPORT_SYMBOL(pcmcia_disable_device); diff --git a/trunk/drivers/pcmcia/pxa2xx_base.c b/trunk/drivers/pcmcia/pxa2xx_base.c index ccfdf1969a7f..9414163c78e7 100644 --- a/trunk/drivers/pcmcia/pxa2xx_base.c +++ b/trunk/drivers/pcmcia/pxa2xx_base.c @@ -33,6 +33,7 @@ #include #include +#include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/rsrc_mgr.c b/trunk/drivers/pcmcia/rsrc_mgr.c index c0e2afc79e3e..ce2226273aaa 100644 --- a/trunk/drivers/pcmcia/rsrc_mgr.c +++ b/trunk/drivers/pcmcia/rsrc_mgr.c @@ -21,6 +21,86 @@ #include "cs_internal.h" +#ifdef CONFIG_PCMCIA_IOCTL + +#ifdef CONFIG_PCMCIA_PROBE + +static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) +{ + int irq; + u32 mask; + + irq = adj->resource.irq.IRQ; + if ((irq < 0) || (irq > 15)) + return CS_BAD_IRQ; + + if (adj->Action != REMOVE_MANAGED_RESOURCE) + return 0; + + mask = 1 << irq; + + if (!(s->irq_mask & mask)) + return 0; + + s->irq_mask &= ~mask; + + return 0; +} + +#else + +static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { + return CS_SUCCESS; +} + +#endif + + +int pcmcia_adjust_resource_info(adjust_t *adj) +{ + struct pcmcia_socket *s; + int ret = CS_UNSUPPORTED_FUNCTION; + unsigned long flags; + + down_read(&pcmcia_socket_list_rwsem); + list_for_each_entry(s, &pcmcia_socket_list, socket_list) { + + if (adj->Resource == RES_IRQ) + ret = adjust_irq(s, adj); + + else if (s->resource_ops->adjust_resource) { + + /* you can't use the old interface if the new + * one was used before */ + spin_lock_irqsave(&s->lock, flags); + if ((s->resource_setup_new) && + !(s->resource_setup_old)) { + spin_unlock_irqrestore(&s->lock, flags); + continue; + } else if (!(s->resource_setup_old)) + s->resource_setup_old = 1; + spin_unlock_irqrestore(&s->lock, flags); + + ret = s->resource_ops->adjust_resource(s, adj); + if (!ret) { + /* as there's no way we know this is the + * last call to adjust_resource_info, we + * always need to assume this is the latest + * one... */ + spin_lock_irqsave(&s->lock, flags); + s->resource_setup_done = 1; + spin_unlock_irqrestore(&s->lock, flags); + } + } + } + up_read(&pcmcia_socket_list_rwsem); + + return (ret); +} +EXPORT_SYMBOL(pcmcia_adjust_resource_info); + +#endif + int pcmcia_validate_mem(struct pcmcia_socket *s) { if (s->resource_ops->validate_mem) @@ -84,8 +164,7 @@ struct pccard_resource_ops pccard_static_ops = { .adjust_io_region = NULL, .find_io = NULL, .find_mem = NULL, - .add_io = NULL, - .add_mem = NULL, + .adjust_resource = NULL, .init = static_init, .exit = NULL, }; @@ -185,8 +264,7 @@ struct pccard_resource_ops pccard_iodyn_ops = { .adjust_io_region = iodyn_adjust_io_region, .find_io = iodyn_find_io_region, .find_mem = NULL, - .add_io = NULL, - .add_mem = NULL, + .adjust_resource = NULL, .init = static_init, .exit = NULL, }; diff --git a/trunk/drivers/pcmcia/rsrc_nonstatic.c b/trunk/drivers/pcmcia/rsrc_nonstatic.c index d0c1d63d1891..0fcf763b9175 100644 --- a/trunk/drivers/pcmcia/rsrc_nonstatic.c +++ b/trunk/drivers/pcmcia/rsrc_nonstatic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "cs_internal.h" @@ -260,22 +261,21 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, ======================================================================*/ /* Validation function for cards with a valid CIS */ -static int readable(struct pcmcia_socket *s, struct resource *res, - unsigned int *count) +static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info) { int ret = -1; s->cis_mem.res = res; s->cis_virt = ioremap(res->start, s->map_size); if (s->cis_virt) { - ret = pccard_validate_cis(s, BIND_FN_ALL, count); + ret = pccard_validate_cis(s, BIND_FN_ALL, info); /* invalidate mapping and CIS cache */ iounmap(s->cis_virt); s->cis_virt = NULL; destroy_cis_cache(s); } s->cis_mem.res = NULL; - if ((ret != 0) || (count == 0)) + if ((ret != 0) || (info->Chains == 0)) return 0; return 1; } @@ -316,7 +316,7 @@ static int cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) { struct resource *res1, *res2; - unsigned int info1, info2; + cisinfo_t info1, info2; int ret = 0; res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe"); @@ -330,7 +330,7 @@ cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) free_region(res2); free_region(res1); - return (ret == 2) && (info1 == info2); + return (ret == 2) && (info1.Chains == info2.Chains); } static int @@ -766,6 +766,21 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long } +static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj) +{ + unsigned long end; + + switch (adj->Resource) { + case RES_MEMORY_RANGE: + end = adj->resource.memory.Base + adj->resource.memory.Size - 1; + return adjust_memory(s, adj->Action, adj->resource.memory.Base, end); + case RES_IO_RANGE: + end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1; + return adjust_io(s, adj->Action, adj->resource.io.BasePort, end); + } + return CS_UNSUPPORTED_FUNCTION; +} + #ifdef CONFIG_PCI static int nonstatic_autoadd_resources(struct pcmcia_socket *s) { @@ -874,8 +889,7 @@ struct pccard_resource_ops pccard_nonstatic_ops = { .adjust_io_region = nonstatic_adjust_io_region, .find_io = nonstatic_find_io_region, .find_mem = nonstatic_find_mem_region, - .add_io = adjust_io, - .add_mem = adjust_memory, + .adjust_resource = nonstatic_adjust_resource_info, .init = nonstatic_init, .exit = nonstatic_release_resource_db, }; @@ -994,34 +1008,41 @@ static ssize_t store_mem_db(struct device *dev, } static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); -static struct attribute *pccard_rsrc_attributes[] = { - &dev_attr_available_resources_io.attr, - &dev_attr_available_resources_mem.attr, +static struct device_attribute *pccard_rsrc_attributes[] = { + &dev_attr_available_resources_io, + &dev_attr_available_resources_mem, NULL, }; -static const struct attribute_group rsrc_attributes = { - .attrs = pccard_rsrc_attributes, -}; - static int __devinit pccard_sysfs_add_rsrc(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *s = dev_get_drvdata(dev); - + struct device_attribute **attr; + int ret = 0; if (s->resource_ops != &pccard_nonstatic_ops) return 0; - return sysfs_create_group(&dev->kobj, &rsrc_attributes); + + for (attr = pccard_rsrc_attributes; *attr; attr++) { + ret = device_create_file(dev, *attr); + if (ret) + break; + } + + return ret; } static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; if (s->resource_ops != &pccard_nonstatic_ops) return; - sysfs_remove_group(&dev->kobj, &rsrc_attributes); + + for (attr = pccard_rsrc_attributes; *attr; attr++) + device_remove_file(dev, *attr); } static struct class_interface pccard_rsrc_interface __refdata = { diff --git a/trunk/drivers/pcmcia/soc_common.h b/trunk/drivers/pcmcia/soc_common.h index 91ef6a0da3ab..1edc1da9d353 100644 --- a/trunk/drivers/pcmcia/soc_common.h +++ b/trunk/drivers/pcmcia/soc_common.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/socket_sysfs.c b/trunk/drivers/pcmcia/socket_sysfs.c index 006a29e91d83..562384d6f321 100644 --- a/trunk/drivers/pcmcia/socket_sysfs.c +++ b/trunk/drivers/pcmcia/socket_sysfs.c @@ -27,9 +27,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include #include @@ -291,7 +293,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, count = 0; else { struct pcmcia_socket *s; - unsigned int chains; + cisinfo_t cisinfo; if (off + count > size) count = size - off; @@ -300,9 +302,9 @@ static ssize_t pccard_show_cis(struct kobject *kobj, if (!(s->state & SOCKET_PRESENT)) return -ENODEV; - if (pccard_validate_cis(s, BIND_FN_ALL, &chains)) + if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo)) return -EIO; - if (!chains) + if (!cisinfo.Chains) return -ENODATA; count = pccard_extract_cis(s, buf, off, count); diff --git a/trunk/drivers/pcmcia/ti113x.h b/trunk/drivers/pcmcia/ti113x.h index 129db7bd06c3..d29657bf1b40 100644 --- a/trunk/drivers/pcmcia/ti113x.h +++ b/trunk/drivers/pcmcia/ti113x.h @@ -155,7 +155,7 @@ #define ENE_TEST_C9_TLTENABLE 0x02 #define ENE_TEST_C9_PFENABLE_F0 0x04 #define ENE_TEST_C9_PFENABLE_F1 0x08 -#define ENE_TEST_C9_PFENABLE (ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F1) +#define ENE_TEST_C9_PFENABLE (ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F0) #define ENE_TEST_C9_WPDISALBLE_F0 0x40 #define ENE_TEST_C9_WPDISALBLE_F1 0x80 #define ENE_TEST_C9_WPDISALBLE (ENE_TEST_C9_WPDISALBLE_F0 | ENE_TEST_C9_WPDISALBLE_F1) @@ -692,7 +692,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) goto out; /* check state */ - yenta_get_status(&slot2->socket, &state); + yenta_get_status(&socket->socket, &state); if (state & SS_DETECT) { ret = 0; goto out; diff --git a/trunk/drivers/s390/block/dasd.c b/trunk/drivers/s390/block/dasd.c index 1b6c52ef7339..1a4025683362 100644 --- a/trunk/drivers/s390/block/dasd.c +++ b/trunk/drivers/s390/block/dasd.c @@ -995,14 +995,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, now = get_clock(); DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x", - cdev->dev.bus_id, ((irb->scsw.cmd.cstat << 8) | - irb->scsw.cmd.dstat), (unsigned int) intparm); + cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat), + (unsigned int) intparm); /* check for unsolicited interrupts */ cqr = (struct dasd_ccw_req *) intparm; - if (!cqr || ((irb->scsw.cmd.cc == 1) && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && - (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND))) { + if (!cqr || ((irb->scsw.cc == 1) && + (irb->scsw.fctl & SCSW_FCTL_START_FUNC) && + (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) { if (cqr && cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_QUEUED; device = dasd_device_from_cdev_locked(cdev); @@ -1025,7 +1025,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, /* Check for clear pending */ if (cqr->status == DASD_CQR_CLEAR_PENDING && - irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { + irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { cqr->status = DASD_CQR_CLEARED; dasd_device_clear_timer(device); wake_up(&dasd_flush_wq); @@ -1041,11 +1041,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", - ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr); + ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr); next = NULL; expires = 0; - if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && - irb->scsw.cmd.cstat == 0 && !irb->esw.esw0.erw.cons) { + if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && + irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) { /* request was completed successfully */ cqr->status = DASD_CQR_SUCCESS; cqr->stopclk = now; diff --git a/trunk/drivers/s390/block/dasd_3990_erp.c b/trunk/drivers/s390/block/dasd_3990_erp.c index 5c6e6f331cb0..e6700df52df4 100644 --- a/trunk/drivers/s390/block/dasd_3990_erp.c +++ b/trunk/drivers/s390/block/dasd_3990_erp.c @@ -1572,7 +1572,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* determine the address of the CCW to be restarted */ /* Imprecise ending is not set -> addr from IRB-SCSW */ - cpa = default_erp->refers->irb.scsw.cmd.cpa; + cpa = default_erp->refers->irb.scsw.cpa; if (cpa == 0) { @@ -1725,7 +1725,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) /* determine the address of the CCW to be restarted */ /* Imprecise ending is not set -> addr from IRB-SCSW */ - cpa = previous_erp->irb.scsw.cmd.cpa; + cpa = previous_erp->irb.scsw.cpa; if (cpa == 0) { @@ -2171,7 +2171,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) { struct dasd_device *device = erp->startdev; - if (erp->refers->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK + if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK)) { DEV_MESSAGE(KERN_DEBUG, device, "%s", "channel or interface control check"); @@ -2352,9 +2352,9 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) if ((cqr1->irb.esw.esw0.erw.cons == 0) && (cqr2->irb.esw.esw0.erw.cons == 0)) { - if ((cqr1->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | + if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK)) == - (cqr2->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | + (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK))) return 1; /* match with ifcc*/ } @@ -2622,9 +2622,8 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } /* double-check if current erp/cqr was successfull */ - if ((cqr->irb.scsw.cmd.cstat == 0x00) && - (cqr->irb.scsw.cmd.dstat == - (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { + if ((cqr->irb.scsw.cstat == 0x00) && + (cqr->irb.scsw.dstat == (DEV_STAT_CHN_END|DEV_STAT_DEV_END))) { DEV_MESSAGE(KERN_DEBUG, device, "ERP called for successful request %p" diff --git a/trunk/drivers/s390/block/dasd_eckd.c b/trunk/drivers/s390/block/dasd_eckd.c index e0b77210d37a..a0edae091b5e 100644 --- a/trunk/drivers/s390/block/dasd_eckd.c +++ b/trunk/drivers/s390/block/dasd_eckd.c @@ -1404,14 +1404,13 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; - if ((irb->scsw.cmd.dstat & mask) == mask) { + if ((irb->scsw.dstat & mask) == mask) { dasd_generic_handle_state_change(device); return; } /* summary unit check */ - if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && - (irb->ecw[7] == 0x0D)) { + if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) { dasd_alias_handle_summary_unit_check(device, irb); return; } @@ -2069,11 +2068,11 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, device->cdev->dev.bus_id); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, - irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); + irb->scsw.cstat, irb->scsw.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", device->cdev->dev.bus_id, - (void *) (addr_t) irb->scsw.cmd.cpa); + (void *) (addr_t) irb->scsw.cpa); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER @@ -2123,8 +2122,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, /* scsw->cda is either valid or zero */ len = 0; from = ++to; - fail = (struct ccw1 *)(addr_t) - irb->scsw.cmd.cpa; /* failing CCW */ + fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */ if (from < fail - 2) { from = fail - 2; /* there is a gap - print header */ len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n"); diff --git a/trunk/drivers/s390/block/dasd_fba.c b/trunk/drivers/s390/block/dasd_fba.c index aee4656127f7..116611583df8 100644 --- a/trunk/drivers/s390/block/dasd_fba.c +++ b/trunk/drivers/s390/block/dasd_fba.c @@ -222,7 +222,7 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; - if ((irb->scsw.cmd.dstat & mask) == mask) { + if ((irb->scsw.dstat & mask) == mask) { dasd_generic_handle_state_change(device); return; } @@ -449,11 +449,11 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, device->cdev->dev.bus_id); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, - irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); + irb->scsw.cstat, irb->scsw.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", device->cdev->dev.bus_id, - (void *) (addr_t) irb->scsw.cmd.cpa); + (void *) (addr_t) irb->scsw.cpa); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER @@ -498,11 +498,11 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, /* print failing CCW area */ len = 0; - if (act < ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2) { - act = ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2; + if (act < ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) { + act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2; len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); } - end = min((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa + 2, last); + end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last); while (act <= end) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " CCW %p: %08X %08X DAT:", diff --git a/trunk/drivers/s390/block/dcssblk.c b/trunk/drivers/s390/block/dcssblk.c index 01fcdd91b846..bb52d2fbac18 100644 --- a/trunk/drivers/s390/block/dcssblk.c +++ b/trunk/drivers/s390/block/dcssblk.c @@ -167,8 +167,10 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch struct dcssblk_dev_info *dev_info; int rc; - if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) + if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) { + PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; + } down_write(&dcssblk_devices_sem); dev_info = container_of(dev, struct dcssblk_dev_info, dev); if (atomic_read(&dev_info->use_count)) { @@ -213,6 +215,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch set_disk_ro(dev_info->gd, 0); } } else { + PRINT_WARN("Invalid value, must be 0 or 1\n"); rc = -EINVAL; goto out; } @@ -255,8 +258,10 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char { struct dcssblk_dev_info *dev_info; - if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) + if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) { + PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; + } dev_info = container_of(dev, struct dcssblk_dev_info, dev); down_write(&dcssblk_devices_sem); @@ -284,6 +289,7 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char } } else { up_write(&dcssblk_devices_sem); + PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; } up_write(&dcssblk_devices_sem); @@ -435,6 +441,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char goto out; unregister_dev: + PRINT_ERR("device_create_file() failed!\n"); list_del(&dev_info->lh); blk_cleanup_queue(dev_info->dcssblk_queue); dev_info->gd->queue = NULL; @@ -695,8 +702,10 @@ dcssblk_check_params(void) static void __exit dcssblk_exit(void) { + PRINT_DEBUG("DCSSBLOCK EXIT...\n"); s390_root_dev_unregister(dcssblk_root_dev); unregister_blkdev(dcssblk_major, DCSSBLK_NAME); + PRINT_DEBUG("...finished!\n"); } static int __init @@ -704,21 +713,27 @@ dcssblk_init(void) { int rc; + PRINT_DEBUG("DCSSBLOCK INIT...\n"); dcssblk_root_dev = s390_root_dev_register("dcssblk"); - if (IS_ERR(dcssblk_root_dev)) + if (IS_ERR(dcssblk_root_dev)) { + PRINT_ERR("device_register() failed!\n"); return PTR_ERR(dcssblk_root_dev); + } rc = device_create_file(dcssblk_root_dev, &dev_attr_add); if (rc) { + PRINT_ERR("device_create_file(add) failed!\n"); s390_root_dev_unregister(dcssblk_root_dev); return rc; } rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); if (rc) { + PRINT_ERR("device_create_file(remove) failed!\n"); s390_root_dev_unregister(dcssblk_root_dev); return rc; } rc = register_blkdev(0, DCSSBLK_NAME); if (rc < 0) { + PRINT_ERR("Can't get dynamic major!\n"); s390_root_dev_unregister(dcssblk_root_dev); return rc; } @@ -727,6 +742,7 @@ dcssblk_init(void) dcssblk_check_params(); + PRINT_DEBUG("...finished!\n"); return 0; } diff --git a/trunk/drivers/s390/block/xpram.c b/trunk/drivers/s390/block/xpram.c index dd9b986389a2..f231bc21b1ca 100644 --- a/trunk/drivers/s390/block/xpram.c +++ b/trunk/drivers/s390/block/xpram.c @@ -100,10 +100,15 @@ static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index) : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc"); if (cc == 3) return -ENXIO; - if (cc == 2) + if (cc == 2) { + PRINT_ERR("expanded storage lost!\n"); return -ENXIO; - if (cc == 1) + } + if (cc == 1) { + PRINT_ERR("page in failed for page index %u.\n", + xpage_index); return -EIO; + } return 0; } @@ -130,10 +135,15 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc"); if (cc == 3) return -ENXIO; - if (cc == 2) + if (cc == 2) { + PRINT_ERR("expanded storage lost!\n"); return -ENXIO; - if (cc == 1) + } + if (cc == 1) { + PRINT_ERR("page out failed for page index %u.\n", + xpage_index); return -EIO; + } return 0; } diff --git a/trunk/drivers/s390/char/con3215.c b/trunk/drivers/s390/char/con3215.c index d3ec9b55ab35..3e5653c92f4b 100644 --- a/trunk/drivers/s390/char/con3215.c +++ b/trunk/drivers/s390/char/con3215.c @@ -93,6 +93,9 @@ struct raw3215_info { struct raw3215_req *queued_write;/* pointer to queued write requests */ wait_queue_head_t empty_wait; /* wait queue for flushing */ struct timer_list timer; /* timer for delayed output */ + char *message; /* pending message from raw3215_irq */ + int msg_dstat; /* dstat for pending message */ + int msg_cstat; /* cstat for pending message */ int line_pos; /* position on the line (for tabs) */ char ubuffer[80]; /* copy_from_user buffer */ }; @@ -356,6 +359,11 @@ raw3215_tasklet(void *data) raw3215_mk_write_req(raw); raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); + /* Check for pending message from raw3215_irq */ + if (raw->message != NULL) { + printk(raw->message, raw->msg_dstat, raw->msg_cstat); + raw->message = NULL; + } tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { @@ -373,14 +381,20 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct raw3215_req *req; struct tty_struct *tty; int cstat, dstat; - int count; + int count, slen; raw = cdev->dev.driver_data; req = (struct raw3215_req *) intparm; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; - if (cstat != 0) + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; + if (cstat != 0) { + raw->message = KERN_WARNING + "Got nonzero channel status in raw3215_irq " + "(dev sts 0x%2x, sch sts 0x%2x)"; + raw->msg_dstat = dstat; + raw->msg_cstat = cstat; tasklet_schedule(&raw->tasklet); + } if (dstat & 0x01) { /* we got a unit exception */ dstat &= ~0x01; /* we can ignore it */ } @@ -390,6 +404,8 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) break; /* Attention interrupt, someone hit the enter key */ raw3215_mk_read_req(raw); + if (MACHINE_IS_P390) + memset(raw->inbuf, 0, RAW3215_INBUF_SIZE); tasklet_schedule(&raw->tasklet); break; case 0x08: @@ -399,7 +415,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ) { /* store residual count, then wait for device end */ - req->residual = irb->scsw.cmd.count; + req->residual = irb->scsw.count; } if (dstat == 0x08) break; @@ -412,6 +428,11 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) tty = raw->tty; count = 160 - req->residual; + if (MACHINE_IS_P390) { + slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE); + if (count > slen) + count = slen; + } else EBCASC(raw->inbuf, count); cchar = ctrlchar_handle(raw->inbuf, count, tty); switch (cchar & CTRLCHAR_MASK) { @@ -460,6 +481,11 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); } + raw->message = KERN_WARNING + "Spurious interrupt in in raw3215_irq " + "(dev sts 0x%2x, sch sts 0x%2x)"; + raw->msg_dstat = dstat; + raw->msg_cstat = cstat; tasklet_schedule(&raw->tasklet); } return; @@ -857,6 +883,7 @@ con3215_init(void) free_bootmem((unsigned long) raw->buffer, RAW3215_BUFFER_SIZE); free_bootmem((unsigned long) raw, sizeof(struct raw3215_info)); raw3215[0] = NULL; + printk("Couldn't find a 3215 console device\n"); return -ENODEV; } register_console(&con3215); @@ -1130,6 +1157,7 @@ tty3215_init(void) tty_set_operations(driver, &tty3215_ops); ret = tty_register_driver(driver); if (ret) { + printk("Couldn't register tty3215 driver\n"); put_tty_driver(driver); return ret; } diff --git a/trunk/drivers/s390/char/con3270.c b/trunk/drivers/s390/char/con3270.c index 3c07974886ed..0b040557db02 100644 --- a/trunk/drivers/s390/char/con3270.c +++ b/trunk/drivers/s390/char/con3270.c @@ -411,15 +411,15 @@ static int con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Schedule tasklet to read aid. */ - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) + if (irb->scsw.dstat & DEV_STAT_ATTENTION) con3270_issue_read(cp); if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } return RAW3270_IO_DONE; } diff --git a/trunk/drivers/s390/char/fs3270.c b/trunk/drivers/s390/char/fs3270.c index e136d10a0de6..ef36f2132aa4 100644 --- a/trunk/drivers/s390/char/fs3270.c +++ b/trunk/drivers/s390/char/fs3270.c @@ -216,17 +216,17 @@ static int fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Set indication and wake waiters for attention. */ - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { fp->attention = 1; wake_up(&fp->wait); } if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } return RAW3270_IO_DONE; } @@ -512,8 +512,11 @@ fs3270_init(void) int rc; rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops); - if (rc) + if (rc) { + printk(KERN_ERR "fs3270 can't get major number %d: errno %d\n", + IBM_FS3270_MAJOR, rc); return rc; + } return 0; } diff --git a/trunk/drivers/s390/char/monreader.c b/trunk/drivers/s390/char/monreader.c index f0e4c96afbf8..1e1f50655bbf 100644 --- a/trunk/drivers/s390/char/monreader.c +++ b/trunk/drivers/s390/char/monreader.c @@ -3,8 +3,9 @@ * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright IBM Corp. 2004, 2008 - * Author: Gerald Schaefer + * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. + * + * Author: Gerald Schaefer */ #include @@ -17,11 +18,12 @@ #include #include #include -#include -#include #include #include #include +#include +#include + //#define MON_DEBUG /* Debug messages on/off */ @@ -150,7 +152,10 @@ static int mon_check_mca(struct mon_msg *monmsg) (mon_mca_end(monmsg) > mon_dcss_end) || (mon_mca_start(monmsg) < mon_dcss_start) || ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0))) + { + P_DEBUG("READ, IGNORED INVALID MCA\n\n"); return -EINVAL; + } return 0; } @@ -159,6 +164,10 @@ static int mon_send_reply(struct mon_msg *monmsg, { int rc; + P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " + "0x%08X\n\n", + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); + rc = iucv_message_reply(monpriv->path, &monmsg->msg, IUCV_IPRMDATA, NULL, 0); atomic_dec(&monpriv->msglim_count); @@ -193,12 +202,15 @@ static struct mon_private *mon_alloc_mem(void) struct mon_private *monpriv; monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); - if (!monpriv) + if (!monpriv) { + P_ERROR("no memory for monpriv\n"); return NULL; + } for (i = 0; i < MON_MSGLIM; i++) { monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg), GFP_KERNEL); if (!monpriv->msg_array[i]) { + P_ERROR("open, no memory for msg_array\n"); mon_free_mem(monpriv); return NULL; } @@ -206,10 +218,41 @@ static struct mon_private *mon_alloc_mem(void) return monpriv; } +static inline void mon_read_debug(struct mon_msg *monmsg, + struct mon_private *monpriv) +{ +#ifdef MON_DEBUG + u8 msg_type[2], mca_type; + unsigned long records_len; + + records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; + + memcpy(msg_type, &monmsg->msg.class, 2); + EBCASC(msg_type, 2); + mca_type = mon_mca_type(monmsg, 0); + EBCASC(&mca_type, 1); + + P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", + monpriv->read_index, monpriv->write_index); + P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); + P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", + msg_type[0], msg_type[1], mca_type ? mca_type : 'X', + mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); + P_DEBUG("read, MCA: start = 0x%lX, end = 0x%lX\n", + mon_mca_start(monmsg), mon_mca_end(monmsg)); + P_DEBUG("read, REC: start = 0x%X, end = 0x%X, len = %lu\n\n", + mon_rec_start(monmsg), mon_rec_end(monmsg), records_len); + if (mon_mca_size(monmsg) > 12) + P_DEBUG("READ, MORE THAN ONE MCA\n\n"); +#endif +} + static inline void mon_next_mca(struct mon_msg *monmsg) { if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) return; + P_DEBUG("READ, NEXT MCA\n\n"); monmsg->mca_offset += 12; monmsg->pos = 0; } @@ -226,6 +269,7 @@ static struct mon_msg *mon_next_message(struct mon_private *monpriv) monmsg->msglim_reached = 0; monmsg->pos = 0; monmsg->mca_offset = 0; + P_WARNING("read, message limit reached\n"); monpriv->read_index = (monpriv->read_index + 1) % MON_MSGLIM; atomic_dec(&monpriv->read_ready); @@ -242,6 +286,10 @@ static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { struct mon_private *monpriv = path->private; + P_DEBUG("IUCV connection completed\n"); + P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " + "0x%02X, Sample = 0x%02X\n", + ipuser[0], ipuser[1], ipuser[2]); atomic_set(&monpriv->iucv_connected, 1); wake_up(&mon_conn_wait_queue); } @@ -262,6 +310,7 @@ static void mon_iucv_message_pending(struct iucv_path *path, { struct mon_private *monpriv = path->private; + P_DEBUG("IUCV message pending\n"); memcpy(&monpriv->msg_array[monpriv->write_index]->msg, msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { @@ -326,6 +375,7 @@ static int mon_open(struct inode *inode, struct file *filp) rc = -EIO; goto out_path; } + P_INFO("open, established connection to *MONITOR service\n\n"); filp->private_data = monpriv; return nonseekable_open(inode, filp); @@ -350,6 +400,8 @@ static int mon_close(struct inode *inode, struct file *filp) rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) P_ERROR("close, iucv_sever failed with rc = %i\n", rc); + else + P_INFO("close, terminated connection to *MONITOR service\n"); atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); @@ -390,8 +442,10 @@ static ssize_t mon_read(struct file *filp, char __user *data, monmsg = monpriv->msg_array[monpriv->read_index]; } - if (!monmsg->pos) + if (!monmsg->pos) { monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset; + mon_read_debug(monmsg, monpriv); + } if (mon_check_mca(monmsg)) goto reply; @@ -477,6 +531,7 @@ static int __init mon_init(void) P_ERROR("failed to register with iucv driver\n"); return rc; } + P_INFO("open, registered with IUCV\n"); rc = segment_type(mon_dcss_name); if (rc < 0) { @@ -500,8 +555,13 @@ static int __init mon_init(void) dcss_mkname(mon_dcss_name, &user_data_connect[8]); rc = misc_register(&mon_dev); - if (rc < 0 ) + if (rc < 0 ) { + P_ERROR("misc_register failed, rc = %i\n", rc); goto out; + } + P_INFO("Loaded segment %s from %p to %p, size = %lu Byte\n", + mon_dcss_name, (void *) mon_dcss_start, (void *) mon_dcss_end, + mon_dcss_end - mon_dcss_start + 1); return 0; out: diff --git a/trunk/drivers/s390/char/raw3270.c b/trunk/drivers/s390/char/raw3270.c index 81a96e019080..848ef7e8523f 100644 --- a/trunk/drivers/s390/char/raw3270.c +++ b/trunk/drivers/s390/char/raw3270.c @@ -153,10 +153,19 @@ struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size) struct raw3270_request *rq; rq = alloc_bootmem_low(sizeof(struct raw3270)); + if (!rq) + return ERR_PTR(-ENOMEM); + memset(rq, 0, sizeof(struct raw3270_request)); /* alloc output buffer. */ - if (size > 0) + if (size > 0) { rq->buffer = alloc_bootmem_low(size); + if (!rq->buffer) { + free_bootmem((unsigned long) rq, + sizeof(struct raw3270)); + return ERR_PTR(-ENOMEM); + } + } rq->size = size; INIT_LIST_HEAD(&rq->list); @@ -363,17 +372,17 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) if (IS_ERR(irb)) rc = RAW3270_IO_RETRY; - else if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) { + else if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { rq->rc = -EIO; rc = RAW3270_IO_DONE; - } else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END | - DEV_STAT_UNIT_EXCEP)) { + } else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END | + DEV_STAT_UNIT_EXCEP)) { /* Handle CE-DE-UE and subsequent UDE */ set_bit(RAW3270_FLAGS_BUSY, &rp->flags); rc = RAW3270_IO_BUSY; } else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) { /* Wait for UDE if busy flag is set. */ - if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { + if (irb->scsw.dstat & DEV_STAT_DEV_END) { clear_bit(RAW3270_FLAGS_BUSY, &rp->flags); /* Got it, now retry. */ rc = RAW3270_IO_RETRY; @@ -488,7 +497,7 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq, * Unit-Check Processing: * Expect Command Reject or Intervention Required. */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { /* Request finished abnormally. */ if (irb->ecw[0] & SNS0_INTERVENTION_REQ) { set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags); @@ -496,16 +505,16 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq, } } if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { if (irb->ecw[0] & SNS0_CMD_REJECT) rq->rc = -EOPNOTSUPP; else rq->rc = -EIO; } else /* Request finished normally. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags); wake_up(&raw3270_wait_queue); } @@ -610,6 +619,7 @@ __raw3270_size_device_vm(struct raw3270 *rp) rp->cols = 132; break; default: + printk(KERN_WARNING "vrdccrmd is 0x%.8x\n", model); rc = -EOPNOTSUPP; break; } diff --git a/trunk/drivers/s390/char/sclp.c b/trunk/drivers/s390/char/sclp.c index 3c8b25e6c345..2c7a1ee6b041 100644 --- a/trunk/drivers/s390/char/sclp.c +++ b/trunk/drivers/s390/char/sclp.c @@ -506,8 +506,6 @@ sclp_state_change_cb(struct evbuf_header *evbuf) if (scbuf->validity_sclp_send_mask) sclp_send_mask = scbuf->sclp_send_mask; spin_unlock_irqrestore(&sclp_lock, flags); - if (scbuf->validity_sclp_active_facility_mask) - sclp_facilities = scbuf->sclp_active_facility_mask; sclp_dispatch_state_change(); } @@ -784,9 +782,11 @@ sclp_check_handler(__u16 code) /* Is this the interrupt we are waiting for? */ if (finished_sccb == 0) return; - if (finished_sccb != (u32) (addr_t) sclp_init_sccb) - panic("sclp: unsolicited interrupt for buffer at 0x%x\n", - finished_sccb); + if (finished_sccb != (u32) (addr_t) sclp_init_sccb) { + printk(KERN_WARNING SCLP_HEADER "unsolicited interrupt " + "for buffer at 0x%x\n", finished_sccb); + return; + } spin_lock(&sclp_lock); if (sclp_running_state == sclp_running_state_running) { sclp_init_req.status = SCLP_REQ_DONE; @@ -883,6 +883,8 @@ sclp_init(void) unsigned long flags; int rc; + if (!MACHINE_HAS_SCLP) + return -ENODEV; spin_lock_irqsave(&sclp_lock, flags); /* Check for previous or running initialization */ if (sclp_init_state != sclp_init_state_uninitialized) { diff --git a/trunk/drivers/s390/char/sclp_cmd.c b/trunk/drivers/s390/char/sclp_cmd.c index 0c2b77493db4..b5c23396f8fe 100644 --- a/trunk/drivers/s390/char/sclp_cmd.c +++ b/trunk/drivers/s390/char/sclp_cmd.c @@ -11,9 +11,6 @@ #include #include #include -#include -#include -#include #include #include #include "sclp.h" @@ -46,8 +43,6 @@ static int __initdata early_read_info_sccb_valid; u64 sclp_facilities; static u8 sclp_fac84; -static unsigned long long rzm; -static unsigned long long rnmax; static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) { @@ -67,7 +62,7 @@ static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) return rc; } -static void __init sclp_read_info_early(void) +void __init sclp_read_info_early(void) { int rc; int i; @@ -97,33 +92,34 @@ static void __init sclp_read_info_early(void) void __init sclp_facilities_detect(void) { - struct read_info_sccb *sccb; - - sclp_read_info_early(); if (!early_read_info_sccb_valid) return; - - sccb = &early_read_info_sccb; - sclp_facilities = sccb->facilities; - sclp_fac84 = sccb->fac84; - rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; - rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; - rzm <<= 20; + sclp_facilities = early_read_info_sccb.facilities; + sclp_fac84 = early_read_info_sccb.fac84; } -unsigned long long sclp_get_rnmax(void) +unsigned long long __init sclp_memory_detect(void) { - return rnmax; -} + unsigned long long memsize; + struct read_info_sccb *sccb; -unsigned long long sclp_get_rzm(void) -{ - return rzm; + if (!early_read_info_sccb_valid) + return 0; + sccb = &early_read_info_sccb; + if (sccb->rnsize) + memsize = sccb->rnsize << 20; + else + memsize = sccb->rnsize2 << 20; + if (sccb->rnmax) + memsize *= sccb->rnmax; + else + memsize *= sccb->rnmax2; + return memsize; } /* - * This function will be called after sclp_facilities_detect(), which gets - * called from early.c code. Therefore the sccb should have valid contents. + * This function will be called after sclp_memory_detect(), which gets called + * early from early.c code. Therefore the sccb should have valid contents. */ void __init sclp_get_ipl_info(struct sclp_ipl_info *info) { @@ -282,305 +278,6 @@ int sclp_cpu_deconfigure(u8 cpu) return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8); } -#ifdef CONFIG_MEMORY_HOTPLUG - -static DEFINE_MUTEX(sclp_mem_mutex); -static LIST_HEAD(sclp_mem_list); -static u8 sclp_max_storage_id; -static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; - -struct memory_increment { - struct list_head list; - u16 rn; - int standby; - int usecount; -}; - -struct assign_storage_sccb { - struct sccb_header header; - u16 rn; -} __packed; - -static unsigned long long rn2addr(u16 rn) -{ - return (unsigned long long) (rn - 1) * rzm; -} - -static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) -{ - struct assign_storage_sccb *sccb; - int rc; - - sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - return -ENOMEM; - sccb->header.length = PAGE_SIZE; - sccb->rn = rn; - rc = do_sync_request(cmd, sccb); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0020: - case 0x0120: - break; - default: - rc = -EIO; - break; - } -out: - free_page((unsigned long) sccb); - return rc; -} - -static int sclp_assign_storage(u16 rn) -{ - return do_assign_storage(0x000d0001, rn); -} - -static int sclp_unassign_storage(u16 rn) -{ - return do_assign_storage(0x000c0001, rn); -} - -struct attach_storage_sccb { - struct sccb_header header; - u16 :16; - u16 assigned; - u32 :32; - u32 entries[0]; -} __packed; - -static int sclp_attach_storage(u8 id) -{ - struct attach_storage_sccb *sccb; - int rc; - int i; - - sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - return -ENOMEM; - sccb->header.length = PAGE_SIZE; - rc = do_sync_request(0x00080001 | id << 8, sccb); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0020: - set_bit(id, sclp_storage_ids); - for (i = 0; i < sccb->assigned; i++) - sclp_unassign_storage(sccb->entries[i] >> 16); - break; - default: - rc = -EIO; - break; - } -out: - free_page((unsigned long) sccb); - return rc; -} - -static int sclp_mem_change_state(unsigned long start, unsigned long size, - int online) -{ - struct memory_increment *incr; - unsigned long long istart; - int rc = 0; - - list_for_each_entry(incr, &sclp_mem_list, list) { - istart = rn2addr(incr->rn); - if (start + size - 1 < istart) - break; - if (start > istart + rzm - 1) - continue; - if (online) { - if (incr->usecount++) - continue; - /* - * Don't break the loop if one assign fails. Loop may - * be walked again on CANCEL and we can't save - * information if state changed before or not. - * So continue and increase usecount for all increments. - */ - rc |= sclp_assign_storage(incr->rn); - } else { - if (--incr->usecount) - continue; - sclp_unassign_storage(incr->rn); - } - } - return rc ? -EIO : 0; -} - -static int sclp_mem_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - unsigned long start, size; - struct memory_notify *arg; - unsigned char id; - int rc = 0; - - arg = data; - start = arg->start_pfn << PAGE_SHIFT; - size = arg->nr_pages << PAGE_SHIFT; - mutex_lock(&sclp_mem_mutex); - for (id = 0; id <= sclp_max_storage_id; id++) - if (!test_bit(id, sclp_storage_ids)) - sclp_attach_storage(id); - switch (action) { - case MEM_ONLINE: - break; - case MEM_GOING_ONLINE: - rc = sclp_mem_change_state(start, size, 1); - break; - case MEM_CANCEL_ONLINE: - sclp_mem_change_state(start, size, 0); - break; - default: - rc = -EINVAL; - break; - } - mutex_unlock(&sclp_mem_mutex); - return rc ? NOTIFY_BAD : NOTIFY_OK; -} - -static struct notifier_block sclp_mem_nb = { - .notifier_call = sclp_mem_notifier, -}; - -static void __init add_memory_merged(u16 rn) -{ - static u16 first_rn, num; - unsigned long long start, size; - - if (rn && first_rn && (first_rn + num == rn)) { - num++; - return; - } - if (!first_rn) - goto skip_add; - start = rn2addr(first_rn); - size = (unsigned long long ) num * rzm; - if (start >= VMEM_MAX_PHYS) - goto skip_add; - if (start + size > VMEM_MAX_PHYS) - size = VMEM_MAX_PHYS - start; - add_memory(0, start, size); -skip_add: - first_rn = rn; - num = 1; -} - -static void __init sclp_add_standby_memory(void) -{ - struct memory_increment *incr; - - list_for_each_entry(incr, &sclp_mem_list, list) - if (incr->standby) - add_memory_merged(incr->rn); - add_memory_merged(0); -} - -static void __init insert_increment(u16 rn, int standby, int assigned) -{ - struct memory_increment *incr, *new_incr; - struct list_head *prev; - u16 last_rn; - - new_incr = kzalloc(sizeof(*new_incr), GFP_KERNEL); - if (!new_incr) - return; - new_incr->rn = rn; - new_incr->standby = standby; - last_rn = 0; - prev = &sclp_mem_list; - list_for_each_entry(incr, &sclp_mem_list, list) { - if (assigned && incr->rn > rn) - break; - if (!assigned && incr->rn - last_rn > 1) - break; - last_rn = incr->rn; - prev = &incr->list; - } - if (!assigned) - new_incr->rn = last_rn + 1; - if (new_incr->rn > rnmax) { - kfree(new_incr); - return; - } - list_add(&new_incr->list, prev); -} - -struct read_storage_sccb { - struct sccb_header header; - u16 max_id; - u16 assigned; - u16 standby; - u16 :16; - u32 entries[0]; -} __packed; - -static int __init sclp_detect_standby_memory(void) -{ - struct read_storage_sccb *sccb; - int i, id, assigned, rc; - - if (!early_read_info_sccb_valid) - return 0; - if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL) - return 0; - rc = -ENOMEM; - sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - goto out; - assigned = 0; - for (id = 0; id <= sclp_max_storage_id; id++) { - memset(sccb, 0, PAGE_SIZE); - sccb->header.length = PAGE_SIZE; - rc = do_sync_request(0x00040001 | id << 8, sccb); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0010: - set_bit(id, sclp_storage_ids); - for (i = 0; i < sccb->assigned; i++) { - if (!sccb->entries[i]) - continue; - assigned++; - insert_increment(sccb->entries[i] >> 16, 0, 1); - } - break; - case 0x0310: - break; - case 0x0410: - for (i = 0; i < sccb->assigned; i++) { - if (!sccb->entries[i]) - continue; - assigned++; - insert_increment(sccb->entries[i] >> 16, 1, 1); - } - break; - default: - rc = -EIO; - break; - } - if (!rc) - sclp_max_storage_id = sccb->max_id; - } - if (rc || list_empty(&sclp_mem_list)) - goto out; - for (i = 1; i <= rnmax - assigned; i++) - insert_increment(0, 1, 0); - rc = register_memory_notifier(&sclp_mem_nb); - if (rc) - goto out; - sclp_add_standby_memory(); -out: - free_page((unsigned long) sccb); - return rc; -} -__initcall(sclp_detect_standby_memory); - -#endif /* CONFIG_MEMORY_HOTPLUG */ - /* * Channel path configuration related functions. */ diff --git a/trunk/drivers/s390/char/sclp_con.c b/trunk/drivers/s390/char/sclp_con.c index 7e619c534bf4..ead1043d788e 100644 --- a/trunk/drivers/s390/char/sclp_con.c +++ b/trunk/drivers/s390/char/sclp_con.c @@ -14,13 +14,14 @@ #include #include #include -#include #include #include "sclp.h" #include "sclp_rw.h" #include "sclp_tty.h" +#define SCLP_CON_PRINT_HEADER "sclp console driver: " + #define sclp_console_major 4 /* TTYAUX_MAJOR */ #define sclp_console_minor 64 #define sclp_console_name "ttyS" @@ -221,6 +222,8 @@ sclp_console_init(void) INIT_LIST_HEAD(&sclp_con_pages); for (i = 0; i < MAX_CONSOLE_PAGES; i++) { page = alloc_bootmem_low_pages(PAGE_SIZE); + if (page == NULL) + return -ENOMEM; list_add_tail((struct list_head *) page, &sclp_con_pages); } INIT_LIST_HEAD(&sclp_con_outqueue); diff --git a/trunk/drivers/s390/char/sclp_config.c b/trunk/drivers/s390/char/sclp_config.c index fff4ff485d9b..ad05a87bc480 100644 --- a/trunk/drivers/s390/char/sclp_config.c +++ b/trunk/drivers/s390/char/sclp_config.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work) put_online_cpus(); } -static int sclp_cpu_kthread(void *data) -{ - smp_rescan_cpus(); - return 0; -} - static void __ref sclp_cpu_change_notify(struct work_struct *work) { - /* Can't call smp_rescan_cpus() from workqueue context since it may - * deadlock in case of cpu hotplug. So we have to create a kernel - * thread in order to call it. - */ - kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan"); + smp_rescan_cpus(); } static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) @@ -85,8 +74,10 @@ static int __init sclp_conf_init(void) INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); rc = sclp_register(&sclp_conf_register); - if (rc) + if (rc) { + printk(KERN_ERR TAG "failed to register (%d).\n", rc); return rc; + } if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { printk(KERN_WARNING TAG "no configuration management.\n"); diff --git a/trunk/drivers/s390/char/sclp_cpi_sys.c b/trunk/drivers/s390/char/sclp_cpi_sys.c index d887bd261d28..9f37456222e9 100644 --- a/trunk/drivers/s390/char/sclp_cpi_sys.c +++ b/trunk/drivers/s390/char/sclp_cpi_sys.c @@ -27,8 +27,6 @@ #define CPI_LENGTH_NAME 8 #define CPI_LENGTH_LEVEL 16 -static DEFINE_MUTEX(sclp_cpi_mutex); - struct cpi_evbuf { struct evbuf_header header; u8 id_format; @@ -126,15 +124,21 @@ static int cpi_req(void) int response; rc = sclp_register(&sclp_cpi_event); - if (rc) + if (rc) { + printk(KERN_WARNING "cpi: could not register " + "to hardware console.\n"); goto out; + } if (!(sclp_cpi_event.sclp_receive_mask & EVTYP_CTLPROGIDENT_MASK)) { + printk(KERN_WARNING "cpi: no control program " + "identification support\n"); rc = -EOPNOTSUPP; goto out_unregister; } req = cpi_prepare_req(); if (IS_ERR(req)) { + printk(KERN_WARNING "cpi: could not allocate request\n"); rc = PTR_ERR(req); goto out_unregister; } @@ -144,8 +148,10 @@ static int cpi_req(void) /* Add request to sclp queue */ rc = sclp_add_request(req); - if (rc) + if (rc) { + printk(KERN_WARNING "cpi: could not start request\n"); goto out_free_req; + } wait_for_completion(&completion); @@ -217,12 +223,7 @@ static void set_string(char *attr, const char *value) static ssize_t system_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - int rc; - - mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", system_name); - mutex_unlock(&sclp_cpi_mutex); - return rc; + return snprintf(page, PAGE_SIZE, "%s\n", system_name); } static ssize_t system_name_store(struct kobject *kobj, @@ -236,9 +237,7 @@ static ssize_t system_name_store(struct kobject *kobj, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(system_name, buf); - mutex_unlock(&sclp_cpi_mutex); return len; } @@ -249,12 +248,7 @@ static struct kobj_attribute system_name_attr = static ssize_t sysplex_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - int rc; - - mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name); - mutex_unlock(&sclp_cpi_mutex); - return rc; + return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name); } static ssize_t sysplex_name_store(struct kobject *kobj, @@ -268,9 +262,7 @@ static ssize_t sysplex_name_store(struct kobject *kobj, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(sysplex_name, buf); - mutex_unlock(&sclp_cpi_mutex); return len; } @@ -281,12 +273,7 @@ static struct kobj_attribute sysplex_name_attr = static ssize_t system_type_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - int rc; - - mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", system_type); - mutex_unlock(&sclp_cpi_mutex); - return rc; + return snprintf(page, PAGE_SIZE, "%s\n", system_type); } static ssize_t system_type_store(struct kobject *kobj, @@ -300,9 +287,7 @@ static ssize_t system_type_store(struct kobject *kobj, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(system_type, buf); - mutex_unlock(&sclp_cpi_mutex); return len; } @@ -313,11 +298,8 @@ static struct kobj_attribute system_type_attr = static ssize_t system_level_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - unsigned long long level; + unsigned long long level = system_level; - mutex_lock(&sclp_cpi_mutex); - level = system_level; - mutex_unlock(&sclp_cpi_mutex); return snprintf(page, PAGE_SIZE, "%#018llx\n", level); } @@ -338,9 +320,8 @@ static ssize_t system_level_store(struct kobject *kobj, if (*endp) return -EINVAL; - mutex_lock(&sclp_cpi_mutex); system_level = level; - mutex_unlock(&sclp_cpi_mutex); + return len; } @@ -353,9 +334,7 @@ static ssize_t set_store(struct kobject *kobj, { int rc; - mutex_lock(&sclp_cpi_mutex); rc = cpi_req(); - mutex_unlock(&sclp_cpi_mutex); if (rc) return rc; @@ -394,16 +373,12 @@ int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(system_name, system); set_string(sysplex_name, sysplex); set_string(system_type, type); system_level = level; - rc = cpi_req(); - mutex_unlock(&sclp_cpi_mutex); - - return rc; + return cpi_req(); } EXPORT_SYMBOL(sclp_cpi_set_data); diff --git a/trunk/drivers/s390/char/sclp_quiesce.c b/trunk/drivers/s390/char/sclp_quiesce.c index 84c191c1cd62..45ff25e787cb 100644 --- a/trunk/drivers/s390/char/sclp_quiesce.c +++ b/trunk/drivers/s390/char/sclp_quiesce.c @@ -51,7 +51,13 @@ static struct sclp_register sclp_quiesce_event = { static int __init sclp_quiesce_init(void) { - return sclp_register(&sclp_quiesce_event); + int rc; + + rc = sclp_register(&sclp_quiesce_event); + if (rc) + printk(KERN_WARNING "sclp: could not register quiesce handler " + "(rc=%d)\n", rc); + return rc; } module_init(sclp_quiesce_init); diff --git a/trunk/drivers/s390/char/sclp_rw.c b/trunk/drivers/s390/char/sclp_rw.c index 710af42603f8..da09781b32f7 100644 --- a/trunk/drivers/s390/char/sclp_rw.c +++ b/trunk/drivers/s390/char/sclp_rw.c @@ -19,6 +19,8 @@ #include "sclp.h" #include "sclp_rw.h" +#define SCLP_RW_PRINT_HEADER "sclp low level driver: " + /* * The room for the SCCB (only for writing) is not equal to a pages size * (as it is specified as the maximum size in the SCLP documentation) diff --git a/trunk/drivers/s390/char/sclp_sdias.c b/trunk/drivers/s390/char/sclp_sdias.c index 8b854857ba07..1c064976b32b 100644 --- a/trunk/drivers/s390/char/sclp_sdias.c +++ b/trunk/drivers/s390/char/sclp_sdias.c @@ -239,8 +239,10 @@ int __init sclp_sdias_init(void) debug_register_view(sdias_dbf, &debug_sprintf_view); debug_set_level(sdias_dbf, 6); rc = sclp_register(&sclp_sdias_register); - if (rc) + if (rc) { + ERROR_MSG("sclp register failed\n"); return rc; + } init_waitqueue_head(&sdias_wq); TRACE("init done\n"); return 0; diff --git a/trunk/drivers/s390/char/sclp_tty.c b/trunk/drivers/s390/char/sclp_tty.c index 434ba04b1309..40b11521cd20 100644 --- a/trunk/drivers/s390/char/sclp_tty.c +++ b/trunk/drivers/s390/char/sclp_tty.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,8 @@ #include "sclp_rw.h" #include "sclp_tty.h" +#define SCLP_TTY_PRINT_HEADER "sclp tty driver: " + /* * size of a buffer that collects single characters coming in * via sclp_tty_put_char() @@ -47,6 +50,8 @@ static int sclp_tty_buffer_count; static struct sclp_buffer *sclp_ttybuf; /* Timer for delayed output of console messages. */ static struct timer_list sclp_tty_timer; +/* Waitqueue to wait for buffers to get empty. */ +static wait_queue_head_t sclp_tty_waitq; static struct tty_struct *sclp_tty; static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE]; @@ -54,11 +59,19 @@ static unsigned short int sclp_tty_chars_count; struct tty_driver *sclp_tty_driver; -static int sclp_tty_tolower; -static int sclp_tty_columns = 80; - -#define SPACES_PER_TAB 8 -#define CASE_DELIMITER 0x6c /* to separate upper and lower case (% in EBCDIC) */ +static struct sclp_ioctls sclp_ioctls; +static struct sclp_ioctls sclp_ioctls_init = +{ + 8, /* 1 hor. tab. = 8 spaces */ + 0, /* no echo of input by this driver */ + 80, /* 80 characters/line */ + 1, /* write after 1/10 s without final new line */ + MAX_KMEM_PAGES, /* quick fix: avoid __alloc_pages */ + MAX_KMEM_PAGES, /* take 32/64 pages from kernel memory, */ + 0, /* do not convert to lower case */ + 0x6c /* to seprate upper and lower case */ + /* ('%' in EBCDIC) */ +}; /* This routine is called whenever we try to open a SCLP terminal. */ static int @@ -79,6 +92,136 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp) sclp_tty = NULL; } +/* execute commands to control the i/o behaviour of the SCLP tty at runtime */ +static int +sclp_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + unsigned int obuf; + int check; + int rc; + + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + rc = 0; + check = 0; + switch (cmd) { + case TIOCSCLPSHTAB: + /* set width of horizontal tab */ + if (get_user(sclp_ioctls.htab, (unsigned short __user *) arg)) + rc = -EFAULT; + else + check = 1; + break; + case TIOCSCLPGHTAB: + /* get width of horizontal tab */ + if (put_user(sclp_ioctls.htab, (unsigned short __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSECHO: + /* enable/disable echo of input */ + if (get_user(sclp_ioctls.echo, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGECHO: + /* Is echo of input enabled ? */ + if (put_user(sclp_ioctls.echo, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSCOLS: + /* set number of columns for output */ + if (get_user(sclp_ioctls.columns, (unsigned short __user *) arg)) + rc = -EFAULT; + else + check = 1; + break; + case TIOCSCLPGCOLS: + /* get number of columns for output */ + if (put_user(sclp_ioctls.columns, (unsigned short __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSNL: + /* enable/disable writing without final new line character */ + if (get_user(sclp_ioctls.final_nl, (signed char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGNL: + /* Is writing without final new line character enabled ? */ + if (put_user(sclp_ioctls.final_nl, (signed char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSOBUF: + /* + * set the maximum buffers size for output, will be rounded + * up to next 4kB boundary and stored as number of SCCBs + * (4kB Buffers) limitation: 256 x 4kB + */ + if (get_user(obuf, (unsigned int __user *) arg) == 0) { + if (obuf & 0xFFF) + sclp_ioctls.max_sccb = (obuf >> 12) + 1; + else + sclp_ioctls.max_sccb = (obuf >> 12); + } else + rc = -EFAULT; + break; + case TIOCSCLPGOBUF: + /* get the maximum buffers size for output */ + obuf = sclp_ioctls.max_sccb << 12; + if (put_user(obuf, (unsigned int __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGKBUF: + /* get the number of buffers got from kernel at startup */ + if (put_user(sclp_ioctls.kmem_sccb, (unsigned short __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSCASE: + /* enable/disable conversion from upper to lower case */ + if (get_user(sclp_ioctls.tolower, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGCASE: + /* Is conversion from upper to lower case of input enabled? */ + if (put_user(sclp_ioctls.tolower, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSDELIM: + /* + * set special character used for separating upper and + * lower case, 0x00 disables this feature + */ + if (get_user(sclp_ioctls.delim, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGDELIM: + /* + * get special character used for separating upper and + * lower case, 0x00 disables this feature + */ + if (put_user(sclp_ioctls.delim, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSINIT: + /* set initial (default) sclp ioctls */ + sclp_ioctls = sclp_ioctls_init; + check = 1; + break; + default: + rc = -ENOIOCTLCMD; + break; + } + if (check) { + spin_lock_irqsave(&sclp_tty_lock, flags); + if (sclp_ttybuf != NULL) { + sclp_set_htab(sclp_ttybuf, sclp_ioctls.htab); + sclp_set_columns(sclp_ttybuf, sclp_ioctls.columns); + } + spin_unlock_irqrestore(&sclp_tty_lock, flags); + } + return rc; +} + /* * This routine returns the numbers of characters the tty driver * will accept for queuing to be written. This number is subject @@ -125,6 +268,7 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) struct sclp_buffer, list); spin_unlock_irqrestore(&sclp_tty_lock, flags); } while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback)); + wake_up(&sclp_tty_waitq); /* check if the tty needs a wake up call */ if (sclp_tty != NULL) { tty_wakeup(sclp_tty); @@ -172,37 +316,37 @@ sclp_tty_timeout(unsigned long data) /* * Write a string to the sclp tty. */ -static int sclp_tty_write_string(const unsigned char *str, int count, int may_fail) +static void +sclp_tty_write_string(const unsigned char *str, int count) { unsigned long flags; void *page; int written; - int overall_written; struct sclp_buffer *buf; if (count <= 0) - return 0; - overall_written = 0; + return; spin_lock_irqsave(&sclp_tty_lock, flags); do { /* Create a sclp output buffer if none exists yet */ if (sclp_ttybuf == NULL) { while (list_empty(&sclp_tty_pages)) { spin_unlock_irqrestore(&sclp_tty_lock, flags); - if (may_fail) - goto out; - else + if (in_interrupt()) sclp_sync_wait(); + else + wait_event(sclp_tty_waitq, + !list_empty(&sclp_tty_pages)); spin_lock_irqsave(&sclp_tty_lock, flags); } page = sclp_tty_pages.next; list_del((struct list_head *) page); - sclp_ttybuf = sclp_make_buffer(page, sclp_tty_columns, - SPACES_PER_TAB); + sclp_ttybuf = sclp_make_buffer(page, + sclp_ioctls.columns, + sclp_ioctls.htab); } /* try to write the string to the current output buffer */ written = sclp_write(sclp_ttybuf, str, count); - overall_written += written; if (written == count) break; /* @@ -219,17 +363,27 @@ static int sclp_tty_write_string(const unsigned char *str, int count, int may_fa count -= written; } while (count > 0); /* Setup timer to output current console buffer after 1/10 second */ - if (sclp_ttybuf && sclp_chars_in_buffer(sclp_ttybuf) && - !timer_pending(&sclp_tty_timer)) { - init_timer(&sclp_tty_timer); - sclp_tty_timer.function = sclp_tty_timeout; - sclp_tty_timer.data = 0UL; - sclp_tty_timer.expires = jiffies + HZ/10; - add_timer(&sclp_tty_timer); + if (sclp_ioctls.final_nl) { + if (sclp_ttybuf != NULL && + sclp_chars_in_buffer(sclp_ttybuf) != 0 && + !timer_pending(&sclp_tty_timer)) { + init_timer(&sclp_tty_timer); + sclp_tty_timer.function = sclp_tty_timeout; + sclp_tty_timer.data = 0UL; + sclp_tty_timer.expires = jiffies + HZ/10; + add_timer(&sclp_tty_timer); + } + } else { + if (sclp_ttybuf != NULL && + sclp_chars_in_buffer(sclp_ttybuf) != 0) { + buf = sclp_ttybuf; + sclp_ttybuf = NULL; + spin_unlock_irqrestore(&sclp_tty_lock, flags); + __sclp_ttybuf_emit(buf); + spin_lock_irqsave(&sclp_tty_lock, flags); + } } spin_unlock_irqrestore(&sclp_tty_lock, flags); -out: - return overall_written; } /* @@ -241,10 +395,11 @@ static int sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) { if (sclp_tty_chars_count > 0) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; } - return sclp_tty_write_string(buf, count, 1); + sclp_tty_write_string(buf, count); + return count; } /* @@ -262,10 +417,9 @@ sclp_tty_put_char(struct tty_struct *tty, unsigned char ch) { sclp_tty_chars[sclp_tty_chars_count++] = ch; if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; - } - return 1; + } return 1; } /* @@ -276,7 +430,7 @@ static void sclp_tty_flush_chars(struct tty_struct *tty) { if (sclp_tty_chars_count > 0) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; } } @@ -315,7 +469,7 @@ static void sclp_tty_flush_buffer(struct tty_struct *tty) { if (sclp_tty_chars_count > 0) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; } } @@ -363,7 +517,9 @@ sclp_tty_input(unsigned char* buf, unsigned int count) * modifiy original string, * returns length of resulting string */ -static int sclp_switch_cases(unsigned char *buf, int count) +static int +sclp_switch_cases(unsigned char *buf, int count, + unsigned char delim, int tolower) { unsigned char *ip, *op; int toggle; @@ -373,9 +529,9 @@ static int sclp_switch_cases(unsigned char *buf, int count) ip = op = buf; while (count-- > 0) { /* compare with special character */ - if (*ip == CASE_DELIMITER) { + if (*ip == delim) { /* followed by another special character? */ - if (count && ip[1] == CASE_DELIMITER) { + if (count && ip[1] == delim) { /* * ... then put a single copy of the special * character to the output string @@ -394,7 +550,7 @@ static int sclp_switch_cases(unsigned char *buf, int count) /* not the special character */ if (toggle) /* but case switching is on */ - if (sclp_tty_tolower) + if (tolower) /* switch to uppercase */ *op++ = _ebc_toupper[(int) *ip++]; else @@ -414,12 +570,30 @@ sclp_get_input(unsigned char *start, unsigned char *end) int count; count = end - start; - if (sclp_tty_tolower) + /* + * if set in ioctl convert EBCDIC to lower case + * (modify original input in SCCB) + */ + if (sclp_ioctls.tolower) EBC_TOLOWER(start, count); - count = sclp_switch_cases(start, count); + + /* + * if set in ioctl find out characters in lower or upper case + * (depends on current case) separated by a special character, + * works on EBCDIC + */ + if (sclp_ioctls.delim) + count = sclp_switch_cases(start, count, + sclp_ioctls.delim, + sclp_ioctls.tolower); + /* convert EBCDIC to ASCII (modify original input in SCCB) */ sclp_ebcasc_str(start, count); + /* if set in ioctl write operators input to console */ + if (sclp_ioctls.echo) + sclp_tty_write(sclp_tty, start, count); + /* transfer input to high level driver */ sclp_tty_input(start, count); } @@ -543,6 +717,7 @@ static const struct tty_operations sclp_ops = { .write_room = sclp_tty_write_room, .chars_in_buffer = sclp_tty_chars_in_buffer, .flush_buffer = sclp_tty_flush_buffer, + .ioctl = sclp_tty_ioctl, }; static int __init @@ -561,6 +736,9 @@ sclp_tty_init(void) rc = sclp_rw_init(); if (rc) { + printk(KERN_ERR SCLP_TTY_PRINT_HEADER + "could not register tty - " + "sclp_rw_init returned %d\n", rc); put_tty_driver(driver); return rc; } @@ -576,6 +754,7 @@ sclp_tty_init(void) } INIT_LIST_HEAD(&sclp_tty_outqueue); spin_lock_init(&sclp_tty_lock); + init_waitqueue_head(&sclp_tty_waitq); init_timer(&sclp_tty_timer); sclp_ttybuf = NULL; sclp_tty_buffer_count = 0; @@ -584,10 +763,11 @@ sclp_tty_init(void) * save 4 characters for the CPU number * written at start of each line by VM/CP */ - sclp_tty_columns = 76; + sclp_ioctls_init.columns = 76; /* case input lines to lowercase */ - sclp_tty_tolower = 1; + sclp_ioctls_init.tolower = 1; } + sclp_ioctls = sclp_ioctls_init; sclp_tty_chars_count = 0; sclp_tty = NULL; @@ -612,6 +792,9 @@ sclp_tty_init(void) tty_set_operations(driver, &sclp_ops); rc = tty_register_driver(driver); if (rc) { + printk(KERN_ERR SCLP_TTY_PRINT_HEADER + "could not register tty - " + "tty_register_driver returned %d\n", rc); put_tty_driver(driver); return rc; } diff --git a/trunk/drivers/s390/char/sclp_tty.h b/trunk/drivers/s390/char/sclp_tty.h index 4b965b22fecd..0ce2c1fc5340 100644 --- a/trunk/drivers/s390/char/sclp_tty.h +++ b/trunk/drivers/s390/char/sclp_tty.h @@ -11,8 +11,61 @@ #ifndef __SCLP_TTY_H__ #define __SCLP_TTY_H__ +#include +#include #include +/* This is the type of data structures storing sclp ioctl setting. */ +struct sclp_ioctls { + unsigned short htab; + unsigned char echo; + unsigned short columns; + unsigned char final_nl; + unsigned short max_sccb; + unsigned short kmem_sccb; /* can't be modified at run time */ + unsigned char tolower; + unsigned char delim; +}; + +/* must be unique, FIXME: must be added in Documentation/ioctl_number.txt */ +#define SCLP_IOCTL_LETTER 'B' + +/* set width of horizontal tabulator */ +#define TIOCSCLPSHTAB _IOW(SCLP_IOCTL_LETTER, 0, unsigned short) +/* enable/disable echo of input (independent from line discipline) */ +#define TIOCSCLPSECHO _IOW(SCLP_IOCTL_LETTER, 1, unsigned char) +/* set number of colums for output */ +#define TIOCSCLPSCOLS _IOW(SCLP_IOCTL_LETTER, 2, unsigned short) +/* enable/disable writing without final new line character */ +#define TIOCSCLPSNL _IOW(SCLP_IOCTL_LETTER, 4, signed char) +/* set the maximum buffers size for output, rounded up to next 4kB boundary */ +#define TIOCSCLPSOBUF _IOW(SCLP_IOCTL_LETTER, 5, unsigned short) +/* set initial (default) sclp ioctls */ +#define TIOCSCLPSINIT _IO(SCLP_IOCTL_LETTER, 6) +/* enable/disable conversion from upper to lower case of input */ +#define TIOCSCLPSCASE _IOW(SCLP_IOCTL_LETTER, 7, unsigned char) +/* set special character used for separating upper and lower case, */ +/* 0x00 disables this feature */ +#define TIOCSCLPSDELIM _IOW(SCLP_IOCTL_LETTER, 9, unsigned char) + +/* get width of horizontal tabulator */ +#define TIOCSCLPGHTAB _IOR(SCLP_IOCTL_LETTER, 10, unsigned short) +/* Is echo of input enabled ? (independent from line discipline) */ +#define TIOCSCLPGECHO _IOR(SCLP_IOCTL_LETTER, 11, unsigned char) +/* get number of colums for output */ +#define TIOCSCLPGCOLS _IOR(SCLP_IOCTL_LETTER, 12, unsigned short) +/* Is writing without final new line character enabled ? */ +#define TIOCSCLPGNL _IOR(SCLP_IOCTL_LETTER, 14, signed char) +/* get the maximum buffers size for output */ +#define TIOCSCLPGOBUF _IOR(SCLP_IOCTL_LETTER, 15, unsigned short) +/* Is conversion from upper to lower case of input enabled ? */ +#define TIOCSCLPGCASE _IOR(SCLP_IOCTL_LETTER, 17, unsigned char) +/* get special character used for separating upper and lower case, */ +/* 0x00 disables this feature */ +#define TIOCSCLPGDELIM _IOR(SCLP_IOCTL_LETTER, 19, unsigned char) +/* get the number of buffers/pages got from kernel at startup */ +#define TIOCSCLPGKBUF _IOR(SCLP_IOCTL_LETTER, 20, unsigned short) + extern struct tty_driver *sclp_tty_driver; #endif /* __SCLP_TTY_H__ */ diff --git a/trunk/drivers/s390/char/sclp_vt220.c b/trunk/drivers/s390/char/sclp_vt220.c index ad51738c4261..3e577f655b18 100644 --- a/trunk/drivers/s390/char/sclp_vt220.c +++ b/trunk/drivers/s390/char/sclp_vt220.c @@ -27,6 +27,7 @@ #include #include "sclp.h" +#define SCLP_VT220_PRINT_HEADER "sclp vt220 tty driver: " #define SCLP_VT220_MAJOR TTY_MAJOR #define SCLP_VT220_MINOR 65 #define SCLP_VT220_DRIVER_NAME "sclp_vt220" @@ -81,8 +82,8 @@ static struct sclp_vt220_request *sclp_vt220_current_request; /* Number of characters in current request buffer */ static int sclp_vt220_buffered_chars; -/* Counter controlling core driver initialization. */ -static int __initdata sclp_vt220_init_count; +/* Flag indicating whether this driver has already been initialized */ +static int sclp_vt220_initialized = 0; /* Flag indicating that sclp_vt220_current_request should really * have been already queued but wasn't because the SCLP was processing @@ -608,8 +609,10 @@ sclp_vt220_flush_buffer(struct tty_struct *tty) sclp_vt220_emit_current(); } -/* Release allocated pages. */ -static void __init __sclp_vt220_free_pages(void) +/* + * Initialize all relevant components and register driver with system. + */ +static void __init __sclp_vt220_cleanup(void) { struct list_head *page, *p; @@ -620,30 +623,21 @@ static void __init __sclp_vt220_free_pages(void) else free_bootmem((unsigned long) page, PAGE_SIZE); } + if (!list_empty(&sclp_vt220_register.list)) + sclp_unregister(&sclp_vt220_register); + sclp_vt220_initialized = 0; } -/* Release memory and unregister from sclp core. Controlled by init counting - - * only the last invoker will actually perform these actions. */ -static void __init __sclp_vt220_cleanup(void) -{ - sclp_vt220_init_count--; - if (sclp_vt220_init_count != 0) - return; - sclp_unregister(&sclp_vt220_register); - __sclp_vt220_free_pages(); -} - -/* Allocate buffer pages and register with sclp core. Controlled by init - * counting - only the first invoker will actually perform these actions. */ -static int __init __sclp_vt220_init(int num_pages) +static int __init __sclp_vt220_init(void) { void *page; int i; + int num_pages; int rc; - sclp_vt220_init_count++; - if (sclp_vt220_init_count != 1) + if (sclp_vt220_initialized) return 0; + sclp_vt220_initialized = 1; spin_lock_init(&sclp_vt220_lock); INIT_LIST_HEAD(&sclp_vt220_empty); INIT_LIST_HEAD(&sclp_vt220_outqueue); @@ -655,22 +649,24 @@ static int __init __sclp_vt220_init(int num_pages) sclp_vt220_flush_later = 0; /* Allocate pages for output buffering */ + num_pages = slab_is_available() ? MAX_KMEM_PAGES : MAX_CONSOLE_PAGES; for (i = 0; i < num_pages; i++) { if (slab_is_available()) page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); else page = alloc_bootmem_low_pages(PAGE_SIZE); if (!page) { - rc = -ENOMEM; - goto out; + __sclp_vt220_cleanup(); + return -ENOMEM; } list_add_tail((struct list_head *) page, &sclp_vt220_empty); } rc = sclp_register(&sclp_vt220_register); -out: if (rc) { - __sclp_vt220_free_pages(); - sclp_vt220_init_count--; + printk(KERN_ERR SCLP_VT220_PRINT_HEADER + "could not register vt220 - " + "sclp_register returned %d\n", rc); + __sclp_vt220_cleanup(); } return rc; } @@ -693,13 +689,15 @@ static int __init sclp_vt220_tty_init(void) { struct tty_driver *driver; int rc; + int cleanup; /* Note: we're not testing for CONSOLE_IS_SCLP here to preserve * symmetry between VM and LPAR systems regarding ttyS1. */ driver = alloc_tty_driver(1); if (!driver) return -ENOMEM; - rc = __sclp_vt220_init(MAX_KMEM_PAGES); + cleanup = !sclp_vt220_initialized; + rc = __sclp_vt220_init(); if (rc) goto out_driver; @@ -715,13 +713,18 @@ static int __init sclp_vt220_tty_init(void) tty_set_operations(driver, &sclp_vt220_ops); rc = tty_register_driver(driver); - if (rc) + if (rc) { + printk(KERN_ERR SCLP_VT220_PRINT_HEADER + "could not register tty - " + "tty_register_driver returned %d\n", rc); goto out_init; + } sclp_vt220_driver = driver; return 0; out_init: - __sclp_vt220_cleanup(); + if (cleanup) + __sclp_vt220_cleanup(); out_driver: put_tty_driver(driver); return rc; @@ -770,9 +773,10 @@ sclp_vt220_con_init(void) { int rc; + INIT_LIST_HEAD(&sclp_vt220_register.list); if (!CONSOLE_IS_SCLP) return 0; - rc = __sclp_vt220_init(MAX_CONSOLE_PAGES); + rc = __sclp_vt220_init(); if (rc) return rc; /* Attach linux console */ diff --git a/trunk/drivers/s390/char/tape_34xx.c b/trunk/drivers/s390/char/tape_34xx.c index 22ca34361ed7..874adf365e46 100644 --- a/trunk/drivers/s390/char/tape_34xx.c +++ b/trunk/drivers/s390/char/tape_34xx.c @@ -196,7 +196,7 @@ tape_34xx_erp_retry(struct tape_request *request) static int tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb) { - if (irb->scsw.cmd.dstat == 0x85) { /* READY */ + if (irb->scsw.dstat == 0x85 /* READY */) { /* A medium was inserted in the drive. */ DBF_EVENT(6, "xuud med\n"); tape_34xx_delete_sbid_from(device, 0); @@ -844,22 +844,22 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request, if (request == NULL) return tape_34xx_unsolicited_irq(device, irb); - if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) && - (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) && + if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) && + (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) { /* Write at end of volume */ PRINT_INFO("End of volume\n"); /* XXX */ return tape_34xx_erp_failed(request, -ENOSPC); } - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) return tape_34xx_unit_check(device, request, irb); - if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { + if (irb->scsw.dstat & DEV_STAT_DEV_END) { /* * A unit exception occurs on skipping over a tapemark block. */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) { + if (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) { if (request->op == TO_BSB || request->op == TO_FSB) request->rescnt++; else diff --git a/trunk/drivers/s390/char/tape_3590.c b/trunk/drivers/s390/char/tape_3590.c index 839987618ffd..42ce7915fc5d 100644 --- a/trunk/drivers/s390/char/tape_3590.c +++ b/trunk/drivers/s390/char/tape_3590.c @@ -837,13 +837,13 @@ tape_3590_erp_retry(struct tape_device *device, struct tape_request *request, static int tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) { - if (irb->scsw.cmd.dstat == DEV_STAT_CHN_END) + if (irb->scsw.dstat == DEV_STAT_CHN_END) /* Probably result of halt ssch */ return TAPE_IO_PENDING; - else if (irb->scsw.cmd.dstat == 0x85) + else if (irb->scsw.dstat == 0x85) /* Device Ready */ DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id); - else if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + else if (irb->scsw.dstat & DEV_STAT_ATTENTION) { tape_3590_schedule_work(device, TO_READ_ATTMSG); } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); @@ -1515,19 +1515,18 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request, if (request == NULL) return tape_3590_unsolicited_irq(device, irb); - if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) && - (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) && - (request->op == TO_WRI)) { + if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) && + (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) { /* Write at end of volume */ DBF_EVENT(2, "End of volume\n"); return tape_3590_erp_failed(device, request, irb, -ENOSPC); } - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) return tape_3590_unit_check(device, request, irb); - if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { - if (irb->scsw.cmd.dstat == DEV_STAT_UNIT_EXCEP) { + if (irb->scsw.dstat & DEV_STAT_DEV_END) { + if (irb->scsw.dstat == DEV_STAT_UNIT_EXCEP) { if (request->op == TO_FSB || request->op == TO_BSB) request->rescnt++; else @@ -1537,12 +1536,12 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request, return tape_3590_done(device, request); } - if (irb->scsw.cmd.dstat & DEV_STAT_CHN_END) { + if (irb->scsw.dstat & DEV_STAT_CHN_END) { DBF_EVENT(2, "cannel end\n"); return TAPE_IO_PENDING; } - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { DBF_EVENT(2, "Unit Attention when busy..\n"); return TAPE_IO_PENDING; } diff --git a/trunk/drivers/s390/char/tape_core.c b/trunk/drivers/s390/char/tape_core.c index 181a5441af16..c20e3c548343 100644 --- a/trunk/drivers/s390/char/tape_core.c +++ b/trunk/drivers/s390/char/tape_core.c @@ -839,7 +839,7 @@ tape_dump_sense(struct tape_device* device, struct tape_request *request, PRINT_INFO("-------------------------------------------------\n"); PRINT_INFO("DSTAT : %02x CSTAT: %02x CPA: %04x\n", - irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa); + irb->scsw.dstat, irb->scsw.cstat, irb->scsw.cpa); PRINT_INFO("DEVICE: %s\n", device->cdev->dev.bus_id); if (request != NULL) PRINT_INFO("OP : %s\n", tape_op_verbose[request->op]); @@ -867,7 +867,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request, else op = "---"; DBF_EVENT(3, "DSTAT : %02x CSTAT: %02x\n", - irb->scsw.cmd.dstat, irb->scsw.cmd.cstat); + irb->scsw.dstat,irb->scsw.cstat); DBF_EVENT(3, "DEVICE: %08x OP\t: %s\n", device->cdev_id, op); sptr = (unsigned int *) irb->ecw; DBF_EVENT(3, "%08x %08x\n", sptr[0], sptr[1]); @@ -1083,11 +1083,10 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) * error might still apply. So we just schedule the request to be * started later. */ - if (irb->scsw.cmd.cc != 0 && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && + if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC) && (request->status == TAPE_REQUEST_IN_IO)) { DBF_EVENT(3,"(%08x): deferred cc=%i, fctl=%i. restarting\n", - device->cdev_id, irb->scsw.cmd.cc, irb->scsw.cmd.fctl); + device->cdev_id, irb->scsw.cc, irb->scsw.fctl); request->status = TAPE_REQUEST_QUEUED; schedule_delayed_work(&device->tape_dnr, HZ); return; @@ -1095,8 +1094,8 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* May be an unsolicited irq */ if(request != NULL) - request->rescnt = irb->scsw.cmd.count; - else if ((irb->scsw.cmd.dstat == 0x85 || irb->scsw.cmd.dstat == 0x80) && + request->rescnt = irb->scsw.count; + else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) && !list_empty(&device->req_queue)) { /* Not Ready to Ready after long busy ? */ struct tape_request *req; @@ -1112,7 +1111,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) return; } } - if (irb->scsw.cmd.dstat != 0x0c) { + if (irb->scsw.dstat != 0x0c) { /* Set the 'ONLINE' flag depending on sense byte 1 */ if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE) device->tape_generic_status |= GMT_ONLINE(~0); diff --git a/trunk/drivers/s390/char/tty3270.c b/trunk/drivers/s390/char/tty3270.c index a7fe6302c982..5043150019ac 100644 --- a/trunk/drivers/s390/char/tty3270.c +++ b/trunk/drivers/s390/char/tty3270.c @@ -663,7 +663,7 @@ static int tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Schedule tasklet to read aid. */ - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { if (!tp->throttle) tty3270_issue_read(tp, 0); else @@ -671,11 +671,11 @@ tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) } if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } return RAW3270_IO_DONE; } @@ -1792,12 +1792,15 @@ static int __init tty3270_init(void) tty_set_operations(driver, &tty3270_ops); ret = tty_register_driver(driver); if (ret) { + printk(KERN_ERR "tty3270 registration failed with %d\n", ret); put_tty_driver(driver); return ret; } tty3270_driver = driver; ret = raw3270_register_notifier(tty3270_notifier); if (ret) { + printk(KERN_ERR "tty3270 notifier registration failed " + "with %d\n", ret); put_tty_driver(driver); return ret; diff --git a/trunk/drivers/s390/char/vmcp.c b/trunk/drivers/s390/char/vmcp.c index 401ea84b3059..2f419b0ea628 100644 --- a/trunk/drivers/s390/char/vmcp.c +++ b/trunk/drivers/s390/char/vmcp.c @@ -61,24 +61,30 @@ static int vmcp_release(struct inode *inode, struct file *file) static ssize_t vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - ssize_t ret; - size_t size; + size_t tocopy; struct vmcp_session *session; - session = file->private_data; + session = (struct vmcp_session *)file->private_data; if (mutex_lock_interruptible(&session->mutex)) return -ERESTARTSYS; if (!session->response) { mutex_unlock(&session->mutex); return 0; } - size = min_t(size_t, session->resp_size, session->bufsize); - ret = simple_read_from_buffer(buff, count, ppos, - session->response, size); + if (*ppos > session->resp_size) { + mutex_unlock(&session->mutex); + return 0; + } + tocopy = min(session->resp_size - (size_t) (*ppos), count); + tocopy = min(tocopy, session->bufsize - (size_t) (*ppos)); + if (copy_to_user(buff, session->response + (*ppos), tocopy)) { + mutex_unlock(&session->mutex); + return -EFAULT; + } mutex_unlock(&session->mutex); - - return ret; + *ppos += tocopy; + return tocopy; } static ssize_t @@ -192,23 +198,27 @@ static int __init vmcp_init(void) PRINT_WARN("z/VM CP interface is only available under z/VM\n"); return -ENODEV; } - vmcp_debug = debug_register("vmcp", 1, 1, 240); - if (!vmcp_debug) + if (!vmcp_debug) { + PRINT_ERR("z/VM CP interface not loaded. Could not register " + "debug feature\n"); return -ENOMEM; - + } ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view); if (ret) { + PRINT_ERR("z/VM CP interface not loaded. Could not register " + "debug feature view. Error code: %d\n", ret); debug_unregister(vmcp_debug); return ret; } - ret = misc_register(&vmcp_dev); if (ret) { + PRINT_ERR("z/VM CP interface not loaded. Could not register " + "misc device. Error code: %d\n", ret); debug_unregister(vmcp_debug); return ret; } - + PRINT_INFO("z/VM CP interface loaded\n"); return 0; } @@ -216,6 +226,7 @@ static void __exit vmcp_exit(void) { misc_deregister(&vmcp_dev); debug_unregister(vmcp_debug); + PRINT_INFO("z/VM CP interface unloaded.\n"); } module_init(vmcp_init); diff --git a/trunk/drivers/s390/char/vmlogrdr.c b/trunk/drivers/s390/char/vmlogrdr.c index a246bc73ae64..2c2428cc05d8 100644 --- a/trunk/drivers/s390/char/vmlogrdr.c +++ b/trunk/drivers/s390/char/vmlogrdr.c @@ -216,7 +216,9 @@ static int vmlogrdr_get_recording_class_AB(void) char *tail; int len,i; + printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response); len = strnlen(cp_response,sizeof(cp_response)); // now the parsing tail=strnchr(cp_response,len,'='); @@ -266,7 +268,11 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, logptr->recording_name, qid_string); + printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", + cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: recording response: %s", + cp_response); } memset(cp_command, 0x00, sizeof(cp_command)); @@ -276,7 +282,10 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, onoff, qid_string); + printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: recording response: %s", + cp_response); /* The recording command will usually answer with 'Command complete' * on success, but when the specific service was never connected * before then there might be an additional informational message @@ -558,7 +567,10 @@ static ssize_t vmlogrdr_purge_store(struct device * dev, "RECORDING %s PURGE ", priv->recording_name); + printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: recording response: %s", + cp_response); return count; } @@ -670,20 +682,28 @@ static int vmlogrdr_register_driver(void) /* Register with iucv driver */ ret = iucv_register(&vmlogrdr_iucv_handler, 1); - if (ret) + if (ret) { + printk (KERN_ERR "vmlogrdr: failed to register with " + "iucv driver\n"); goto out; + } ret = driver_register(&vmlogrdr_driver); - if (ret) + if (ret) { + printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); goto out_iucv; + } ret = driver_create_file(&vmlogrdr_driver, &driver_attr_recording_status); - if (ret) + if (ret) { + printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); goto out_driver; + } vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); if (IS_ERR(vmlogrdr_class)) { + printk(KERN_ERR "vmlogrdr: failed to create class.\n"); ret = PTR_ERR(vmlogrdr_class); vmlogrdr_class = NULL; goto out_attr; @@ -851,10 +871,12 @@ static int __init vmlogrdr_init(void) rc = vmlogrdr_register_cdev(dev); if (rc) goto cleanup; + printk (KERN_INFO "vmlogrdr: driver loaded\n"); return 0; cleanup: vmlogrdr_cleanup(); + printk (KERN_ERR "vmlogrdr: driver not loaded.\n"); return rc; } @@ -862,6 +884,7 @@ static int __init vmlogrdr_init(void) static void __exit vmlogrdr_exit(void) { vmlogrdr_cleanup(); + printk (KERN_INFO "vmlogrdr: driver unloaded\n"); return; } diff --git a/trunk/drivers/s390/char/vmur.c b/trunk/drivers/s390/char/vmur.c index 49cba9effe89..83ae9a852f00 100644 --- a/trunk/drivers/s390/char/vmur.c +++ b/trunk/drivers/s390/char/vmur.c @@ -277,8 +277,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, struct urdev *urd; TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n", - intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, - irb->scsw.cmd.count); + intparm, irb->scsw.cstat, irb->scsw.dstat, irb->scsw.count); if (!intparm) { TRACE("ur_int_handler: unsolicited interrupt\n"); @@ -289,7 +288,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, /* On special conditions irb is an error pointer */ if (IS_ERR(irb)) urd->io_request_rc = PTR_ERR(irb); - else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) + else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) urd->io_request_rc = 0; else urd->io_request_rc = -EIO; diff --git a/trunk/drivers/s390/char/vmwatchdog.c b/trunk/drivers/s390/char/vmwatchdog.c index 56b3eab019cb..19f8389291b6 100644 --- a/trunk/drivers/s390/char/vmwatchdog.c +++ b/trunk/drivers/s390/char/vmwatchdog.c @@ -92,15 +92,23 @@ static int vmwdt_keepalive(void) func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; ret = __diag288(func, vmwdt_interval, ebc_cmd, len); - WARN_ON(ret != 0); kfree(ebc_cmd); + + if (ret) { + printk(KERN_WARNING "%s: problem setting interval %d, " + "cmd %s\n", __func__, vmwdt_interval, + vmwdt_cmd); + } return ret; } static int vmwdt_disable(void) { int ret = __diag288(wdt_cancel, 0, "", 0); - WARN_ON(ret != 0); + if (ret) { + printk(KERN_WARNING "%s: problem disabling watchdog\n", + __func__); + } return ret; } @@ -113,8 +121,10 @@ static int __init vmwdt_probe(void) static char __initdata ebc_begin[] = { 194, 197, 199, 201, 213 }; - if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) + if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) { + printk(KERN_INFO "z/VM watchdog not available\n"); return -EINVAL; + } return vmwdt_disable(); } diff --git a/trunk/drivers/s390/char/zcore.c b/trunk/drivers/s390/char/zcore.c index 047dd92ae804..bbbd14e9d48f 100644 --- a/trunk/drivers/s390/char/zcore.c +++ b/trunk/drivers/s390/char/zcore.c @@ -223,10 +223,12 @@ static int __init init_cpu_info(enum arch_id arch) /* get info for boot cpu from lowcore, stored in the HSA */ sa = kmalloc(sizeof(*sa), GFP_KERNEL); - if (!sa) + if (!sa) { + ERROR_MSG("kmalloc failed: %s: %i\n",__func__, __LINE__); return -ENOMEM; + } if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) { - TRACE("could not copy from HSA\n"); + ERROR_MSG("could not copy from HSA\n"); kfree(sa); return -EIO; } @@ -509,8 +511,6 @@ static void __init set_s390x_lc_mask(union save_area *map) */ static int __init sys_info_init(enum arch_id arch) { - int rc; - switch (arch) { case ARCH_S390X: MSG("DETECTED 'S390X (64 bit) OS'\n"); @@ -529,9 +529,10 @@ static int __init sys_info_init(enum arch_id arch) return -EINVAL; } sys_info.arch = arch; - rc = init_cpu_info(arch); - if (rc) - return rc; + if (init_cpu_info(arch)) { + ERROR_MSG("get cpu info failed\n"); + return -ENOMEM; + } sys_info.mem_size = real_memory_size; return 0; @@ -543,12 +544,12 @@ static int __init check_sdias(void) rc = sclp_sdias_blk_count(); if (rc < 0) { - TRACE("Could not determine HSA size\n"); + ERROR_MSG("Could not determine HSA size\n"); return rc; } act_hsa_size = (rc - 1) * PAGE_SIZE; if (act_hsa_size < ZFCPDUMP_HSA_SIZE) { - TRACE("HSA size too small: %i\n", act_hsa_size); + ERROR_MSG("HSA size too small: %i\n", act_hsa_size); return -EINVAL; } return 0; @@ -589,12 +590,16 @@ static int __init zcore_init(void) goto fail; rc = check_sdias(); - if (rc) + if (rc) { + ERROR_MSG("Dump initialization failed\n"); goto fail; + } rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1); - if (rc) + if (rc) { + ERROR_MSG("sdial memcpy for arch id failed\n"); goto fail; + } #ifndef __s390x__ if (arch == ARCH_S390X) { @@ -605,8 +610,10 @@ static int __init zcore_init(void) #endif rc = sys_info_init(arch); - if (rc) + if (rc) { + ERROR_MSG("arch init failed\n"); goto fail; + } zcore_header_init(arch, &zcore_header); diff --git a/trunk/drivers/s390/cio/Makefile b/trunk/drivers/s390/cio/Makefile index 91e9e3f3073a..cfaf77b320f5 100644 --- a/trunk/drivers/s390/cio/Makefile +++ b/trunk/drivers/s390/cio/Makefile @@ -2,11 +2,9 @@ # Makefile for the S/390 common i/o drivers # -obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \ - fcx.o itcw.o +obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o obj-y += ccw_device.o cmf.o -obj-$(CONFIG_CHSC_SCH) += chsc_sch.o obj-$(CONFIG_CCWGROUP) += ccwgroup.o obj-$(CONFIG_QDIO) += qdio.o diff --git a/trunk/drivers/s390/cio/airq.c b/trunk/drivers/s390/cio/airq.c index fe6cea15bbaf..b7a07a866291 100644 --- a/trunk/drivers/s390/cio/airq.c +++ b/trunk/drivers/s390/cio/airq.c @@ -15,7 +15,6 @@ #include #include -#include #include "cio.h" #include "cio_debug.h" @@ -34,15 +33,15 @@ struct airq_t { void *drv_data; }; -static union indicator_t indicators[MAX_ISC]; -static struct airq_t *airqs[MAX_ISC][NR_AIRQS]; +static union indicator_t indicators; +static struct airq_t *airqs[NR_AIRQS]; -static int register_airq(struct airq_t *airq, u8 isc) +static int register_airq(struct airq_t *airq) { int i; for (i = 0; i < NR_AIRQS; i++) - if (!cmpxchg(&airqs[isc][i], NULL, airq)) + if (!cmpxchg(&airqs[i], NULL, airq)) return i; return -ENOMEM; } @@ -51,21 +50,18 @@ static int register_airq(struct airq_t *airq, u8 isc) * s390_register_adapter_interrupt() - register adapter interrupt handler * @handler: adapter handler to be registered * @drv_data: driver data passed with each call to the handler - * @isc: isc for which the handler should be called * * Returns: * Pointer to the indicator to be used on success * ERR_PTR() if registration failed */ void *s390_register_adapter_interrupt(adapter_int_handler_t handler, - void *drv_data, u8 isc) + void *drv_data) { struct airq_t *airq; char dbf_txt[16]; int ret; - if (isc > MAX_ISC) - return ERR_PTR(-EINVAL); airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); if (!airq) { ret = -ENOMEM; @@ -73,35 +69,34 @@ void *s390_register_adapter_interrupt(adapter_int_handler_t handler, } airq->handler = handler; airq->drv_data = drv_data; - - ret = register_airq(airq, isc); + ret = register_airq(airq); + if (ret < 0) + kfree(airq); out: snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); CIO_TRACE_EVENT(4, dbf_txt); - if (ret < 0) { - kfree(airq); + if (ret < 0) return ERR_PTR(ret); - } else - return &indicators[isc].byte[ret]; + else + return &indicators.byte[ret]; } EXPORT_SYMBOL(s390_register_adapter_interrupt); /** * s390_unregister_adapter_interrupt - unregister adapter interrupt handler * @ind: indicator for which the handler is to be unregistered - * @isc: interruption subclass */ -void s390_unregister_adapter_interrupt(void *ind, u8 isc) +void s390_unregister_adapter_interrupt(void *ind) { struct airq_t *airq; char dbf_txt[16]; int i; - i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]); + i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]); snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); CIO_TRACE_EVENT(4, dbf_txt); - indicators[isc].byte[i] = 0; - airq = xchg(&airqs[isc][i], NULL); + indicators.byte[i] = 0; + airq = xchg(&airqs[i], NULL); /* * Allow interrupts to complete. This will ensure that the airq handle * is no longer referenced by any interrupt handler. @@ -113,7 +108,7 @@ EXPORT_SYMBOL(s390_unregister_adapter_interrupt); #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) -void do_adapter_IO(u8 isc) +void do_adapter_IO(void) { int w; int i; @@ -125,22 +120,22 @@ void do_adapter_IO(u8 isc) * fetch operations. */ for (w = 0; w < NR_AIRQ_WORDS; w++) { - word = indicators[isc].word[w]; + word = indicators.word[w]; i = w * NR_AIRQS_PER_WORD; /* * Check bytes within word for active indicators. */ while (word) { if (word & INDICATOR_MASK) { - airq = airqs[isc][i]; + airq = airqs[i]; if (likely(airq)) - airq->handler(&indicators[isc].byte[i], + airq->handler(&indicators.byte[i], airq->drv_data); else /* * Reset ill-behaved indicator. */ - indicators[isc].byte[i] = 0; + indicators.byte[i] = 0; } word <<= 8; i++; diff --git a/trunk/drivers/s390/cio/chp.c b/trunk/drivers/s390/cio/chp.c index db00b0591733..297cdceb0ca4 100644 --- a/trunk/drivers/s390/cio/chp.c +++ b/trunk/drivers/s390/cio/chp.c @@ -18,7 +18,6 @@ #include #include -#include "../s390mach.h" #include "cio.h" #include "css.h" #include "ioasm.h" @@ -95,7 +94,6 @@ u8 chp_get_sch_opm(struct subchannel *sch) } return opm; } -EXPORT_SYMBOL_GPL(chp_get_sch_opm); /** * chp_is_registered - check if a channel-path is registered @@ -123,8 +121,11 @@ static int s390_vary_chpid(struct chp_id chpid, int on) CIO_TRACE_EVENT(2, dbf_text); status = chp_get_status(chpid); - if (!on && !status) - return 0; + if (!on && !status) { + printk(KERN_ERR "cio: chpid %x.%02x is already offline\n", + chpid.cssid, chpid.id); + return -EINVAL; + } set_chp_logically_online(chpid, on); chsc_chp_vary(chpid, on); @@ -140,14 +141,21 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj, { struct channel_path *chp; struct device *device; + unsigned int size; device = container_of(kobj, struct device, kobj); chp = to_channelpath(device); if (!chp->cmg_chars) return 0; - return memory_read_from_buffer(buf, count, &off, - chp->cmg_chars, sizeof(struct cmg_chars)); + size = sizeof(struct cmg_chars); + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, chp->cmg_chars + off, count); + return count; } static struct bin_attribute chp_measurement_chars_attr = { @@ -397,7 +405,7 @@ int chp_new(struct chp_id chpid) chpid.id); /* Obtain channel path description and fill it in. */ - ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc); + ret = chsc_determine_channel_path_description(chpid, &chp->desc); if (ret) goto out_free; if ((chp->desc.flags & 0x80) == 0) { @@ -405,7 +413,8 @@ int chp_new(struct chp_id chpid) goto out_free; } /* Get channel-measurement characteristics. */ - if (css_chsc_characteristics.scmc && css_chsc_characteristics.secm) { + if (css_characteristics_avail && css_chsc_characteristics.scmc + && css_chsc_characteristics.secm) { ret = chsc_get_channel_measurement_chars(chp); if (ret) goto out_free; @@ -467,74 +476,26 @@ void *chp_get_chp_desc(struct chp_id chpid) /** * chp_process_crw - process channel-path status change - * @crw0: channel report-word to handler - * @crw1: second channel-report word (always NULL) - * @overflow: crw overflow indication + * @id: channel-path ID number + * @status: non-zero if channel-path has become available, zero otherwise * * Handle channel-report-words indicating that the status of a channel-path * has changed. */ -static void chp_process_crw(struct crw *crw0, struct crw *crw1, - int overflow) +void chp_process_crw(int id, int status) { struct chp_id chpid; - if (overflow) { - css_schedule_eval_all(); - return; - } - CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, - crw0->erc, crw0->rsid); - /* - * Check for solicited machine checks. These are - * created by reset channel path and need not be - * handled here. - */ - if (crw0->slct) { - CIO_CRW_EVENT(2, "solicited machine check for " - "channel path %02X\n", crw0->rsid); - return; - } chp_id_init(&chpid); - chpid.id = crw0->rsid; - switch (crw0->erc) { - case CRW_ERC_IPARM: /* Path has come. */ + chpid.id = id; + if (status) { if (!chp_is_registered(chpid)) chp_new(chpid); chsc_chp_online(chpid); - break; - case CRW_ERC_PERRI: /* Path has gone. */ - case CRW_ERC_PERRN: + } else chsc_chp_offline(chpid); - break; - default: - CIO_CRW_EVENT(2, "Don't know how to handle erc=%x\n", - crw0->erc); - } } -int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct chp_link *link) -{ - int i; - int mask; - - for (i = 0; i < 8; i++) { - mask = 0x80 >> i; - if (!(ssd->path_mask & mask)) - continue; - if (!chp_id_is_equal(&ssd->chpid[i], &link->chpid)) - continue; - if ((ssd->fla_valid_mask & mask) && - ((ssd->fla[i] & link->fla_mask) != link->fla)) - continue; - return mask; - } - return 0; -} -EXPORT_SYMBOL_GPL(chp_ssd_get_mask); - static inline int info_bit_num(struct chp_id id) { return id.id + id.cssid * (__MAX_CHPID + 1); @@ -614,7 +575,6 @@ static void cfg_func(struct work_struct *work) { struct chp_id chpid; enum cfg_task_t t; - int rc; mutex_lock(&cfg_lock); t = cfg_none; @@ -629,24 +589,14 @@ static void cfg_func(struct work_struct *work) switch (t) { case cfg_configure: - rc = sclp_chp_configure(chpid); - if (rc) - CIO_MSG_EVENT(2, "chp: sclp_chp_configure(%x.%02x)=" - "%d\n", chpid.cssid, chpid.id, rc); - else { - info_expire(); - chsc_chp_online(chpid); - } + sclp_chp_configure(chpid); + info_expire(); + chsc_chp_online(chpid); break; case cfg_deconfigure: - rc = sclp_chp_deconfigure(chpid); - if (rc) - CIO_MSG_EVENT(2, "chp: sclp_chp_deconfigure(%x.%02x)=" - "%d\n", chpid.cssid, chpid.id, rc); - else { - info_expire(); - chsc_chp_offline(chpid); - } + sclp_chp_deconfigure(chpid); + info_expire(); + chsc_chp_offline(chpid); break; case cfg_none: /* Get updated information after last change. */ @@ -704,16 +654,10 @@ static int cfg_wait_idle(void) static int __init chp_init(void) { struct chp_id chpid; - int ret; - ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw); - if (ret) - return ret; chp_wq = create_singlethread_workqueue("cio_chp"); - if (!chp_wq) { - s390_unregister_crw_handler(CRW_RSC_CPATH); + if (!chp_wq) return -ENOMEM; - } INIT_WORK(&cfg_work, cfg_func); init_waitqueue_head(&cfg_wait_queue); if (info_update()) diff --git a/trunk/drivers/s390/cio/chp.h b/trunk/drivers/s390/cio/chp.h index 26c3d2246176..65286563c592 100644 --- a/trunk/drivers/s390/cio/chp.h +++ b/trunk/drivers/s390/cio/chp.h @@ -12,24 +12,12 @@ #include #include #include "chsc.h" -#include "css.h" #define CHP_STATUS_STANDBY 0 #define CHP_STATUS_CONFIGURED 1 #define CHP_STATUS_RESERVED 2 #define CHP_STATUS_NOT_RECOGNIZED 3 -#define CHP_ONLINE 0 -#define CHP_OFFLINE 1 -#define CHP_VARY_ON 2 -#define CHP_VARY_OFF 3 - -struct chp_link { - struct chp_id chpid; - u32 fla_mask; - u16 fla; -}; - static inline int chp_test_bit(u8 *bitmap, int num) { int byte = num >> 3; @@ -54,11 +42,12 @@ int chp_get_status(struct chp_id chpid); u8 chp_get_sch_opm(struct subchannel *sch); int chp_is_registered(struct chp_id chpid); void *chp_get_chp_desc(struct chp_id chpid); +void chp_process_crw(int id, int available); void chp_remove_cmg_attr(struct channel_path *chp); int chp_add_cmg_attr(struct channel_path *chp); int chp_new(struct chp_id chpid); void chp_cfg_schedule(struct chp_id chpid, int configure); void chp_cfg_cancel_deconfigure(struct chp_id chpid); int chp_info_get_status(struct chp_id chpid); -int chp_ssd_get_mask(struct chsc_ssd_info *, struct chp_link *); + #endif /* S390_CHP_H */ diff --git a/trunk/drivers/s390/cio/chsc.c b/trunk/drivers/s390/cio/chsc.c index 65264a38057d..5de86908b0d0 100644 --- a/trunk/drivers/s390/cio/chsc.c +++ b/trunk/drivers/s390/cio/chsc.c @@ -2,7 +2,8 @@ * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call * - * Copyright IBM Corp. 1999,2008 + * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -15,9 +16,7 @@ #include #include -#include -#include "../s390mach.h" #include "css.h" #include "cio.h" #include "cio_debug.h" @@ -128,12 +127,77 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) return ret; } +static int check_for_io_on_path(struct subchannel *sch, int mask) +{ + int cc; + + cc = stsch(sch->schid, &sch->schib); + if (cc) + return 0; + if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask) + return 1; + return 0; +} + +static void terminate_internal_io(struct subchannel *sch) +{ + if (cio_clear(sch)) { + /* Recheck device in case clear failed. */ + sch->lpm = 0; + if (device_trigger_verify(sch) != 0) + css_schedule_eval(sch->schid); + return; + } + /* Request retry of internal operation. */ + device_set_intretry(sch); + /* Call handler. */ + if (sch->driver && sch->driver->termination) + sch->driver->termination(sch); +} + static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) { + int j; + int mask; + struct chp_id *chpid = data; + struct schib schib; + + for (j = 0; j < 8; j++) { + mask = 0x80 >> j; + if ((sch->schib.pmcw.pim & mask) && + (sch->schib.pmcw.chpid[j] == chpid->id)) + break; + } + if (j >= 8) + return 0; + spin_lock_irq(sch->lock); - if (sch->driver && sch->driver->chp_event) - if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0) + + stsch(sch->schid, &schib); + if (!css_sch_is_valid(&schib)) + goto out_unreg; + memcpy(&sch->schib, &schib, sizeof(struct schib)); + /* Check for single path devices. */ + if (sch->schib.pmcw.pim == 0x80) + goto out_unreg; + + if (check_for_io_on_path(sch, mask)) { + if (device_is_online(sch)) + device_kill_io(sch); + else { + terminate_internal_io(sch); + /* Re-start path verification. */ + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + } + } else { + /* trigger path verification. */ + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + else if (sch->lpm == mask) goto out_unreg; + } + spin_unlock_irq(sch->lock); return 0; @@ -147,18 +211,15 @@ static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) void chsc_chp_offline(struct chp_id chpid) { char dbf_txt[15]; - struct chp_link link; sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_txt); if (chp_get_status(chpid) <= 0) return; - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); - for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link); + for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid); } static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) @@ -181,25 +242,67 @@ static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) return 0; } +struct res_acc_data { + struct chp_id chpid; + u32 fla_mask; + u16 fla; +}; + +static int get_res_chpid_mask(struct chsc_ssd_info *ssd, + struct res_acc_data *data) +{ + int i; + int mask; + + for (i = 0; i < 8; i++) { + mask = 0x80 >> i; + if (!(ssd->path_mask & mask)) + continue; + if (!chp_id_is_equal(&ssd->chpid[i], &data->chpid)) + continue; + if ((ssd->fla_valid_mask & mask) && + ((ssd->fla[i] & data->fla_mask) != data->fla)) + continue; + return mask; + } + return 0; +} + static int __s390_process_res_acc(struct subchannel *sch, void *data) { + int chp_mask, old_lpm; + struct res_acc_data *res_data = data; + spin_lock_irq(sch->lock); - if (sch->driver && sch->driver->chp_event) - sch->driver->chp_event(sch, data, CHP_ONLINE); + chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data); + if (chp_mask == 0) + goto out; + if (stsch(sch->schid, &sch->schib)) + goto out; + old_lpm = sch->lpm; + sch->lpm = ((sch->schib.pmcw.pim & + sch->schib.pmcw.pam & + sch->schib.pmcw.pom) + | chp_mask) & sch->opm; + if (!old_lpm && sch->lpm) + device_trigger_reprobe(sch); + else if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); +out: spin_unlock_irq(sch->lock); return 0; } -static void s390_process_res_acc(struct chp_link *link) +static void s390_process_res_acc (struct res_acc_data *res_data) { char dbf_txt[15]; - sprintf(dbf_txt, "accpr%x.%02x", link->chpid.cssid, - link->chpid.id); + sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid, + res_data->chpid.id); CIO_TRACE_EVENT( 2, dbf_txt); - if (link->fla != 0) { - sprintf(dbf_txt, "fla%x", link->fla); + if (res_data->fla != 0) { + sprintf(dbf_txt, "fla%x", res_data->fla); CIO_TRACE_EVENT( 2, dbf_txt); } /* Wait until previous actions have settled. */ @@ -212,7 +315,7 @@ static void s390_process_res_acc(struct chp_link *link) * will we have to do. */ for_each_subchannel_staged(__s390_process_res_acc, - s390_process_res_acc_new_sch, link); + s390_process_res_acc_new_sch, res_data); } static int @@ -285,7 +388,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) { - struct chp_link link; + struct res_acc_data res_data; struct chp_id chpid; int status; @@ -301,18 +404,18 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) chp_new(chpid); else if (!status) return; - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; + memset(&res_data, 0, sizeof(struct res_acc_data)); + res_data.chpid = chpid; if ((sei_area->vf & 0xc0) != 0) { - link.fla = sei_area->fla; + res_data.fla = sei_area->fla; if ((sei_area->vf & 0xc0) == 0xc0) /* full link address */ - link.fla_mask = 0xffff; + res_data.fla_mask = 0xffff; else /* link address */ - link.fla_mask = 0xff00; + res_data.fla_mask = 0xff00; } - s390_process_res_acc(&link); + s390_process_res_acc(&res_data); } struct chp_config_data { @@ -377,25 +480,17 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) } } -static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) +void chsc_process_crw(void) { struct chsc_sei_area *sei_area; - if (overflow) { - css_schedule_eval_all(); - return; - } - CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, - crw0->erc, crw0->rsid); if (!sei_page) return; /* Access to sei_page is serialized through machine check handler * thread, so no need for locking. */ sei_area = sei_page; - CIO_TRACE_EVENT(2, "prcss"); + CIO_TRACE_EVENT( 2, "prcss"); do { memset(sei_area, 0, sizeof(*sei_area)); sei_area->request.length = 0x0010; @@ -414,36 +509,114 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) } while (sei_area->flags & 0x80); } +static int __chp_add_new_sch(struct subchannel_id schid, void *data) +{ + struct schib schib; + + if (stsch_err(schid, &schib)) + /* We're through */ + return -ENXIO; + + /* Put it on the slow path. */ + css_schedule_eval(schid); + return 0; +} + + +static int __chp_add(struct subchannel *sch, void *data) +{ + int i, mask; + struct chp_id *chpid = data; + + spin_lock_irq(sch->lock); + for (i=0; i<8; i++) { + mask = 0x80 >> i; + if ((sch->schib.pmcw.pim & mask) && + (sch->schib.pmcw.chpid[i] == chpid->id)) + break; + } + if (i==8) { + spin_unlock_irq(sch->lock); + return 0; + } + if (stsch(sch->schid, &sch->schib)) { + spin_unlock_irq(sch->lock); + css_schedule_eval(sch->schid); + return 0; + } + sch->lpm = ((sch->schib.pmcw.pim & + sch->schib.pmcw.pam & + sch->schib.pmcw.pom) + | mask) & sch->opm; + + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + + spin_unlock_irq(sch->lock); + + return 0; +} + void chsc_chp_online(struct chp_id chpid) { char dbf_txt[15]; - struct chp_link link; sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_txt); if (chp_get_status(chpid) != 0) { - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); - for_each_subchannel_staged(__s390_process_res_acc, NULL, - &link); + for_each_subchannel_staged(__chp_add, __chp_add_new_sch, + &chpid); } } static void __s390_subchannel_vary_chpid(struct subchannel *sch, struct chp_id chpid, int on) { + int chp, old_lpm; + int mask; unsigned long flags; - struct chp_link link; - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; spin_lock_irqsave(sch->lock, flags); - if (sch->driver && sch->driver->chp_event) - sch->driver->chp_event(sch, &link, - on ? CHP_VARY_ON : CHP_VARY_OFF); + old_lpm = sch->lpm; + for (chp = 0; chp < 8; chp++) { + mask = 0x80 >> chp; + if (!(sch->ssd_info.path_mask & mask)) + continue; + if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid)) + continue; + + if (on) { + sch->opm |= mask; + sch->lpm |= mask; + if (!old_lpm) + device_trigger_reprobe(sch); + else if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + break; + } + sch->opm &= ~mask; + sch->lpm &= ~mask; + if (check_for_io_on_path(sch, mask)) { + if (device_is_online(sch)) + /* Path verification is done after killing. */ + device_kill_io(sch); + else { + /* Kill and retry internal I/O. */ + terminate_internal_io(sch); + /* Re-start path verification. */ + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + } + } else if (!sch->lpm) { + if (device_trigger_verify(sch) != 0) + css_schedule_eval(sch->schid); + } else if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + break; + } spin_unlock_irqrestore(sch->lock, flags); } @@ -483,10 +656,6 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) */ int chsc_chp_vary(struct chp_id chpid, int on) { - struct chp_link link; - - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); /* @@ -495,10 +664,10 @@ int chsc_chp_vary(struct chp_id chpid, int on) if (on) for_each_subchannel_staged(s390_subchannel_vary_chpid_on, - __s390_vary_chpid_on, &link); + __s390_vary_chpid_on, &chpid); else for_each_subchannel_staged(s390_subchannel_vary_chpid_off, - NULL, &link); + NULL, &chpid); return 0; } @@ -628,33 +797,23 @@ chsc_secm(struct channel_subsystem *css, int enable) return ret; } -int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, - int c, int m, - struct chsc_response_struct *resp) +int chsc_determine_channel_path_description(struct chp_id chpid, + struct channel_path_desc *desc) { int ccode, ret; struct { struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 c : 1; - u32 fmt : 4; - u32 cssid : 8; - u32 : 4; - u32 rfmt : 4; + u32 : 24; u32 first_chpid : 8; u32 : 24; u32 last_chpid : 8; u32 zeroes1; struct chsc_header response; - u8 data[PAGE_SIZE - 20]; + u32 zeroes2; + struct channel_path_desc desc; } __attribute__ ((packed)) *scpd_area; - if ((rfmt == 1) && !css_general_characteristics.fcs) - return -EINVAL; - if ((rfmt == 2) && !css_general_characteristics.cib) - return -EINVAL; scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scpd_area) return -ENOMEM; @@ -662,13 +821,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, scpd_area->request.length = 0x0010; scpd_area->request.code = 0x0002; - scpd_area->cssid = chpid.cssid; scpd_area->first_chpid = chpid.id; scpd_area->last_chpid = chpid.id; - scpd_area->m = m; - scpd_area->c = c; - scpd_area->fmt = fmt; - scpd_area->rfmt = rfmt; ccode = chsc(scpd_area); if (ccode > 0) { @@ -679,7 +833,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, ret = chsc_error_from_response(scpd_area->response.code); if (ret == 0) /* Success. */ - memcpy(resp, &scpd_area->response, scpd_area->response.length); + memcpy(desc, &scpd_area->desc, + sizeof(struct channel_path_desc)); else CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", scpd_area->response.code); @@ -687,25 +842,6 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, free_page((unsigned long)scpd_area); return ret; } -EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); - -int chsc_determine_base_channel_path_desc(struct chp_id chpid, - struct channel_path_desc *desc) -{ - struct chsc_response_struct *chsc_resp; - int ret; - - chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL); - if (!chsc_resp) - return -ENOMEM; - ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp); - if (ret) - goto out_free; - memcpy(desc, &chsc_resp->data, chsc_resp->length); -out_free: - kfree(chsc_resp); - return ret; -} static void chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, @@ -801,23 +937,15 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) int __init chsc_alloc_sei_area(void) { - int ret; - sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sei_page) { + if (!sei_page) CIO_MSG_EVENT(0, "Can't allocate page for processing of " "chsc machine checks!\n"); - return -ENOMEM; - } - ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw); - if (ret) - kfree(sei_page); - return ret; + return (sei_page ? 0 : -ENOMEM); } void __init chsc_free_sei_area(void) { - s390_unregister_crw_handler(CRW_RSC_CSS); kfree(sei_page); } @@ -915,52 +1043,3 @@ chsc_determine_css_characteristics(void) EXPORT_SYMBOL_GPL(css_general_characteristics); EXPORT_SYMBOL_GPL(css_chsc_characteristics); - -int chsc_sstpc(void *page, unsigned int op, u16 ctrl) -{ - struct { - struct chsc_header request; - unsigned int rsvd0; - unsigned int op : 8; - unsigned int rsvd1 : 8; - unsigned int ctrl : 16; - unsigned int rsvd2[5]; - struct chsc_header response; - unsigned int rsvd3[7]; - } __attribute__ ((packed)) *rr; - int rc; - - memset(page, 0, PAGE_SIZE); - rr = page; - rr->request.length = 0x0020; - rr->request.code = 0x0033; - rr->op = op; - rr->ctrl = ctrl; - rc = chsc(rr); - if (rc) - return -EIO; - rc = (rr->response.code == 0x0001) ? 0 : -EIO; - return rc; -} - -int chsc_sstpi(void *page, void *result, size_t size) -{ - struct { - struct chsc_header request; - unsigned int rsvd0[3]; - struct chsc_header response; - char data[size]; - } __attribute__ ((packed)) *rr; - int rc; - - memset(page, 0, PAGE_SIZE); - rr = page; - rr->request.length = 0x0010; - rr->request.code = 0x0038; - rc = chsc(rr); - if (rc) - return -EIO; - memcpy(result, &rr->data, size); - return (rr->response.code == 0x0001) ? 0 : -EIO; -} - diff --git a/trunk/drivers/s390/cio/chsc.h b/trunk/drivers/s390/cio/chsc.h index fb6c4d6c45b4..d1f5db1e69b9 100644 --- a/trunk/drivers/s390/cio/chsc.h +++ b/trunk/drivers/s390/cio/chsc.h @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include "schid.h" #define CHSC_SDA_OC_MSS 0x2 @@ -37,15 +36,14 @@ struct channel_path_desc { struct channel_path; +extern void chsc_process_crw(void); + struct css_general_char { - u64 : 12; - u32 dynio : 1; /* bit 12 */ - u32 : 28; + u64 : 41; u32 aif : 1; /* bit 41 */ u32 : 3; u32 mcss : 1; /* bit 45 */ - u32 fcs : 1; /* bit 46 */ - u32 : 1; + u32 : 2; u32 ext_mb : 1; /* bit 48 */ u32 : 7; u32 aif_tdd : 1; /* bit 56 */ @@ -53,11 +51,7 @@ struct css_general_char { u32 qebsm : 1; /* bit 58 */ u32 : 8; u32 aif_osa : 1; /* bit 67 */ - u32 : 14; - u32 cib : 1; /* bit 82 */ - u32 : 5; - u32 fcx : 1; /* bit 88 */ - u32 : 7; + u32 : 28; }__attribute__((packed)); struct css_chsc_char { @@ -84,6 +78,7 @@ struct chsc_ssd_info { extern int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd); extern int chsc_determine_css_characteristics(void); +extern int css_characteristics_avail; extern int chsc_alloc_sei_area(void); extern void chsc_free_sei_area(void); @@ -92,11 +87,8 @@ struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); int chsc_chp_vary(struct chp_id chpid, int on); -int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, - int c, int m, - struct chsc_response_struct *resp); -int chsc_determine_base_channel_path_desc(struct chp_id chpid, - struct channel_path_desc *desc); +int chsc_determine_channel_path_description(struct chp_id chpid, + struct channel_path_desc *desc); void chsc_chp_online(struct chp_id chpid); void chsc_chp_offline(struct chp_id chpid); int chsc_get_channel_measurement_chars(struct channel_path *chp); diff --git a/trunk/drivers/s390/cio/chsc_sch.c b/trunk/drivers/s390/cio/chsc_sch.c deleted file mode 100644 index 91ca87aa9f97..000000000000 --- a/trunk/drivers/s390/cio/chsc_sch.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Driver for s390 chsc subchannels - * - * Copyright IBM Corp. 2008 - * Author(s): Cornelia Huck - * - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "cio.h" -#include "cio_debug.h" -#include "css.h" -#include "chsc_sch.h" -#include "ioasm.h" - -static debug_info_t *chsc_debug_msg_id; -static debug_info_t *chsc_debug_log_id; - -#define CHSC_MSG(imp, args...) do { \ - debug_sprintf_event(chsc_debug_msg_id, imp , ##args); \ - } while (0) - -#define CHSC_LOG(imp, txt) do { \ - debug_text_event(chsc_debug_log_id, imp , txt); \ - } while (0) - -static void CHSC_LOG_HEX(int level, void *data, int length) -{ - while (length > 0) { - debug_event(chsc_debug_log_id, level, data, length); - length -= chsc_debug_log_id->buf_size; - data += chsc_debug_log_id->buf_size; - } -} - -MODULE_AUTHOR("IBM Corporation"); -MODULE_DESCRIPTION("driver for s390 chsc subchannels"); -MODULE_LICENSE("GPL"); - -static void chsc_subchannel_irq(struct subchannel *sch) -{ - struct chsc_private *private = sch->private; - struct chsc_request *request = private->request; - struct irb *irb = (struct irb *)__LC_IRB; - - CHSC_LOG(4, "irb"); - CHSC_LOG_HEX(4, irb, sizeof(*irb)); - /* Copy irb to provided request and set done. */ - if (!request) { - CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n", - sch->schid.ssid, sch->schid.sch_no); - return; - } - private->request = NULL; - memcpy(&request->irb, irb, sizeof(*irb)); - stsch(sch->schid, &sch->schib); - complete(&request->completion); - put_device(&sch->dev); -} - -static int chsc_subchannel_probe(struct subchannel *sch) -{ - struct chsc_private *private; - int ret; - - CHSC_MSG(6, "Detected chsc subchannel 0.%x.%04x\n", - sch->schid.ssid, sch->schid.sch_no); - sch->isc = CHSC_SCH_ISC; - private = kzalloc(sizeof(*private), GFP_KERNEL); - if (!private) - return -ENOMEM; - ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); - if (ret) { - CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n", - sch->schid.ssid, sch->schid.sch_no, ret); - kfree(private); - } else { - sch->private = private; - if (sch->dev.uevent_suppress) { - sch->dev.uevent_suppress = 0; - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } - } - return ret; -} - -static int chsc_subchannel_remove(struct subchannel *sch) -{ - struct chsc_private *private; - - cio_disable_subchannel(sch); - private = sch->private; - sch->private = NULL; - if (private->request) { - complete(&private->request->completion); - put_device(&sch->dev); - } - kfree(private); - return 0; -} - -static void chsc_subchannel_shutdown(struct subchannel *sch) -{ - cio_disable_subchannel(sch); -} - -static struct css_device_id chsc_subchannel_ids[] = { - { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(css, chsc_subchannel_ids); - -static struct css_driver chsc_subchannel_driver = { - .owner = THIS_MODULE, - .subchannel_type = chsc_subchannel_ids, - .irq = chsc_subchannel_irq, - .probe = chsc_subchannel_probe, - .remove = chsc_subchannel_remove, - .shutdown = chsc_subchannel_shutdown, - .name = "chsc_subchannel", -}; - -static int __init chsc_init_dbfs(void) -{ - chsc_debug_msg_id = debug_register("chsc_msg", 16, 1, - 16 * sizeof(long)); - if (!chsc_debug_msg_id) - goto out; - debug_register_view(chsc_debug_msg_id, &debug_sprintf_view); - debug_set_level(chsc_debug_msg_id, 2); - chsc_debug_log_id = debug_register("chsc_log", 16, 1, 16); - if (!chsc_debug_log_id) - goto out; - debug_register_view(chsc_debug_log_id, &debug_hex_ascii_view); - debug_set_level(chsc_debug_log_id, 2); - return 0; -out: - if (chsc_debug_msg_id) - debug_unregister(chsc_debug_msg_id); - return -ENOMEM; -} - -static void chsc_remove_dbfs(void) -{ - debug_unregister(chsc_debug_log_id); - debug_unregister(chsc_debug_msg_id); -} - -static int __init chsc_init_sch_driver(void) -{ - return css_driver_register(&chsc_subchannel_driver); -} - -static void chsc_cleanup_sch_driver(void) -{ - css_driver_unregister(&chsc_subchannel_driver); -} - -static DEFINE_SPINLOCK(chsc_lock); - -static int chsc_subchannel_match_next_free(struct device *dev, void *data) -{ - struct subchannel *sch = to_subchannel(dev); - - return sch->schib.pmcw.ena && !scsw_fctl(&sch->schib.scsw); -} - -static struct subchannel *chsc_get_next_subchannel(struct subchannel *sch) -{ - struct device *dev; - - dev = driver_find_device(&chsc_subchannel_driver.drv, - sch ? &sch->dev : NULL, NULL, - chsc_subchannel_match_next_free); - return dev ? to_subchannel(dev) : NULL; -} - -/** - * chsc_async() - try to start a chsc request asynchronously - * @chsc_area: request to be started - * @request: request structure to associate - * - * Tries to start a chsc request on one of the existing chsc subchannels. - * Returns: - * %0 if the request was performed synchronously - * %-EINPROGRESS if the request was successfully started - * %-EBUSY if all chsc subchannels are busy - * %-ENODEV if no chsc subchannels are available - * Context: - * interrupts disabled, chsc_lock held - */ -static int chsc_async(struct chsc_async_area *chsc_area, - struct chsc_request *request) -{ - int cc; - struct chsc_private *private; - struct subchannel *sch = NULL; - int ret = -ENODEV; - char dbf[10]; - - chsc_area->header.key = PAGE_DEFAULT_KEY; - while ((sch = chsc_get_next_subchannel(sch))) { - spin_lock(sch->lock); - private = sch->private; - if (private->request) { - spin_unlock(sch->lock); - ret = -EBUSY; - continue; - } - chsc_area->header.sid = sch->schid; - CHSC_LOG(2, "schid"); - CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid)); - cc = chsc(chsc_area); - sprintf(dbf, "cc:%d", cc); - CHSC_LOG(2, dbf); - switch (cc) { - case 0: - ret = 0; - break; - case 1: - sch->schib.scsw.cmd.fctl |= SCSW_FCTL_START_FUNC; - ret = -EINPROGRESS; - private->request = request; - break; - case 2: - ret = -EBUSY; - break; - default: - ret = -ENODEV; - } - spin_unlock(sch->lock); - CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n", - sch->schid.ssid, sch->schid.sch_no, cc); - if (ret == -EINPROGRESS) - return -EINPROGRESS; - put_device(&sch->dev); - if (ret == 0) - return 0; - } - return ret; -} - -static void chsc_log_command(struct chsc_async_area *chsc_area) -{ - char dbf[10]; - - sprintf(dbf, "CHSC:%x", chsc_area->header.code); - CHSC_LOG(0, dbf); - CHSC_LOG_HEX(0, chsc_area, 32); -} - -static int chsc_examine_irb(struct chsc_request *request) -{ - int backed_up; - - if (!scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND) - return -EIO; - backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK; - request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK; - if (scsw_cstat(&request->irb.scsw) == 0) - return 0; - if (!backed_up) - return 0; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROG_CHECK) - return -EIO; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROT_CHECK) - return -EPERM; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_DATA_CHK) - return -EAGAIN; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_CTRL_CHK) - return -EAGAIN; - return -EIO; -} - -static int chsc_ioctl_start(void __user *user_area) -{ - struct chsc_request *request; - struct chsc_async_area *chsc_area; - int ret; - char dbf[10]; - - if (!css_general_characteristics.dynio) - /* It makes no sense to try. */ - return -EOPNOTSUPP; - chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); - if (!chsc_area) - return -ENOMEM; - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (!request) { - ret = -ENOMEM; - goto out_free; - } - init_completion(&request->completion); - if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) { - ret = -EFAULT; - goto out_free; - } - chsc_log_command(chsc_area); - spin_lock_irq(&chsc_lock); - ret = chsc_async(chsc_area, request); - spin_unlock_irq(&chsc_lock); - if (ret == -EINPROGRESS) { - wait_for_completion(&request->completion); - ret = chsc_examine_irb(request); - } - /* copy area back to user */ - if (!ret) - if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) - ret = -EFAULT; -out_free: - sprintf(dbf, "ret:%d", ret); - CHSC_LOG(0, dbf); - kfree(request); - free_page((unsigned long)chsc_area); - return ret; -} - -static int chsc_ioctl_info_channel_path(void __user *user_cd) -{ - struct chsc_chp_cd *cd; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 1; - u32 fmt1 : 4; - u32 cssid : 8; - u32 : 8; - u32 first_chpid : 8; - u32 : 24; - u32 last_chpid : 8; - u32 : 32; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *scpcd_area; - - scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!scpcd_area) - return -ENOMEM; - cd = kzalloc(sizeof(*cd), GFP_KERNEL); - if (!cd) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(cd, user_cd, sizeof(*cd))) { - ret = -EFAULT; - goto out_free; - } - scpcd_area->request.length = 0x0010; - scpcd_area->request.code = 0x0028; - scpcd_area->m = cd->m; - scpcd_area->fmt1 = cd->fmt; - scpcd_area->cssid = cd->chpid.cssid; - scpcd_area->first_chpid = cd->chpid.id; - scpcd_area->last_chpid = cd->chpid.id; - - ccode = chsc(scpcd_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (scpcd_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "scpcd: response code=%x\n", - scpcd_area->response.code); - goto out_free; - } - memcpy(&cd->cpcb, &scpcd_area->response, scpcd_area->response.length); - if (copy_to_user(user_cd, cd, sizeof(*cd))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(cd); - free_page((unsigned long)scpcd_area); - return ret; -} - -static int chsc_ioctl_info_cu(void __user *user_cd) -{ - struct chsc_cu_cd *cd; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 1; - u32 fmt1 : 4; - u32 cssid : 8; - u32 : 8; - u32 first_cun : 8; - u32 : 24; - u32 last_cun : 8; - u32 : 32; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *scucd_area; - - scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!scucd_area) - return -ENOMEM; - cd = kzalloc(sizeof(*cd), GFP_KERNEL); - if (!cd) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(cd, user_cd, sizeof(*cd))) { - ret = -EFAULT; - goto out_free; - } - scucd_area->request.length = 0x0010; - scucd_area->request.code = 0x0028; - scucd_area->m = cd->m; - scucd_area->fmt1 = cd->fmt; - scucd_area->cssid = cd->cssid; - scucd_area->first_cun = cd->cun; - scucd_area->last_cun = cd->cun; - - ccode = chsc(scucd_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (scucd_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "scucd: response code=%x\n", - scucd_area->response.code); - goto out_free; - } - memcpy(&cd->cucb, &scucd_area->response, scucd_area->response.length); - if (copy_to_user(user_cd, cd, sizeof(*cd))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(cd); - free_page((unsigned long)scucd_area); - return ret; -} - -static int chsc_ioctl_info_sch_cu(void __user *user_cud) -{ - struct chsc_sch_cud *cud; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 5; - u32 fmt1 : 4; - u32 : 2; - u32 ssid : 2; - u32 first_sch : 16; - u32 : 8; - u32 cssid : 8; - u32 last_sch : 16; - u32 : 32; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *sscud_area; - - sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sscud_area) - return -ENOMEM; - cud = kzalloc(sizeof(*cud), GFP_KERNEL); - if (!cud) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(cud, user_cud, sizeof(*cud))) { - ret = -EFAULT; - goto out_free; - } - sscud_area->request.length = 0x0010; - sscud_area->request.code = 0x0006; - sscud_area->m = cud->schid.m; - sscud_area->fmt1 = cud->fmt; - sscud_area->ssid = cud->schid.ssid; - sscud_area->first_sch = cud->schid.sch_no; - sscud_area->cssid = cud->schid.cssid; - sscud_area->last_sch = cud->schid.sch_no; - - ccode = chsc(sscud_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sscud_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sscud: response code=%x\n", - sscud_area->response.code); - goto out_free; - } - memcpy(&cud->scub, &sscud_area->response, sscud_area->response.length); - if (copy_to_user(user_cud, cud, sizeof(*cud))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(cud); - free_page((unsigned long)sscud_area); - return ret; -} - -static int chsc_ioctl_conf_info(void __user *user_ci) -{ - struct chsc_conf_info *ci; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 1; - u32 fmt1 : 4; - u32 cssid : 8; - u32 : 6; - u32 ssid : 2; - u32 : 8; - u64 : 64; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *sci_area; - - sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sci_area) - return -ENOMEM; - ci = kzalloc(sizeof(*ci), GFP_KERNEL); - if (!ci) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(ci, user_ci, sizeof(*ci))) { - ret = -EFAULT; - goto out_free; - } - sci_area->request.length = 0x0010; - sci_area->request.code = 0x0012; - sci_area->m = ci->id.m; - sci_area->fmt1 = ci->fmt; - sci_area->cssid = ci->id.cssid; - sci_area->ssid = ci->id.ssid; - - ccode = chsc(sci_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sci_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sci: response code=%x\n", - sci_area->response.code); - goto out_free; - } - memcpy(&ci->scid, &sci_area->response, sci_area->response.length); - if (copy_to_user(user_ci, ci, sizeof(*ci))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(ci); - free_page((unsigned long)sci_area); - return ret; -} - -static int chsc_ioctl_conf_comp_list(void __user *user_ccl) -{ - struct chsc_comp_list *ccl; - int ret, ccode; - struct { - struct chsc_header request; - u32 ctype : 8; - u32 : 4; - u32 fmt : 4; - u32 : 16; - u64 : 64; - u32 list_parm[2]; - u64 : 64; - struct chsc_header response; - u8 data[PAGE_SIZE - 36]; - } __attribute__ ((packed)) *sccl_area; - struct { - u32 m : 1; - u32 : 31; - u32 cssid : 8; - u32 : 16; - u32 chpid : 8; - } __attribute__ ((packed)) *chpid_parm; - struct { - u32 f_cssid : 8; - u32 l_cssid : 8; - u32 : 16; - u32 res; - } __attribute__ ((packed)) *cssids_parm; - - sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccl_area) - return -ENOMEM; - ccl = kzalloc(sizeof(*ccl), GFP_KERNEL); - if (!ccl) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(ccl, user_ccl, sizeof(*ccl))) { - ret = -EFAULT; - goto out_free; - } - sccl_area->request.length = 0x0020; - sccl_area->request.code = 0x0030; - sccl_area->fmt = ccl->req.fmt; - sccl_area->ctype = ccl->req.ctype; - switch (sccl_area->ctype) { - case CCL_CU_ON_CHP: - case CCL_IOP_CHP: - chpid_parm = (void *)&sccl_area->list_parm; - chpid_parm->m = ccl->req.chpid.m; - chpid_parm->cssid = ccl->req.chpid.chp.cssid; - chpid_parm->chpid = ccl->req.chpid.chp.id; - break; - case CCL_CSS_IMG: - case CCL_CSS_IMG_CONF_CHAR: - cssids_parm = (void *)&sccl_area->list_parm; - cssids_parm->f_cssid = ccl->req.cssids.f_cssid; - cssids_parm->l_cssid = ccl->req.cssids.l_cssid; - break; - } - ccode = chsc(sccl_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sccl_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sccl: response code=%x\n", - sccl_area->response.code); - goto out_free; - } - memcpy(&ccl->sccl, &sccl_area->response, sccl_area->response.length); - if (copy_to_user(user_ccl, ccl, sizeof(*ccl))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(ccl); - free_page((unsigned long)sccl_area); - return ret; -} - -static int chsc_ioctl_chpd(void __user *user_chpd) -{ - struct chsc_cpd_info *chpd; - int ret; - - chpd = kzalloc(sizeof(*chpd), GFP_KERNEL); - if (!chpd) - return -ENOMEM; - if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) { - ret = -EFAULT; - goto out_free; - } - ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt, - chpd->rfmt, chpd->c, chpd->m, - &chpd->chpdb); - if (ret) - goto out_free; - if (copy_to_user(user_chpd, chpd, sizeof(*chpd))) - ret = -EFAULT; -out_free: - kfree(chpd); - return ret; -} - -static int chsc_ioctl_dcal(void __user *user_dcal) -{ - struct chsc_dcal *dcal; - int ret, ccode; - struct { - struct chsc_header request; - u32 atype : 8; - u32 : 4; - u32 fmt : 4; - u32 : 16; - u32 res0[2]; - u32 list_parm[2]; - u32 res1[2]; - struct chsc_header response; - u8 data[PAGE_SIZE - 36]; - } __attribute__ ((packed)) *sdcal_area; - - sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sdcal_area) - return -ENOMEM; - dcal = kzalloc(sizeof(*dcal), GFP_KERNEL); - if (!dcal) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(dcal, user_dcal, sizeof(*dcal))) { - ret = -EFAULT; - goto out_free; - } - sdcal_area->request.length = 0x0020; - sdcal_area->request.code = 0x0034; - sdcal_area->atype = dcal->req.atype; - sdcal_area->fmt = dcal->req.fmt; - memcpy(&sdcal_area->list_parm, &dcal->req.list_parm, - sizeof(sdcal_area->list_parm)); - - ccode = chsc(sdcal_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sdcal_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sdcal: response code=%x\n", - sdcal_area->response.code); - goto out_free; - } - memcpy(&dcal->sdcal, &sdcal_area->response, - sdcal_area->response.length); - if (copy_to_user(user_dcal, dcal, sizeof(*dcal))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(dcal); - free_page((unsigned long)sdcal_area); - return ret; -} - -static long chsc_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - CHSC_MSG(2, "chsc_ioctl called, cmd=%x\n", cmd); - switch (cmd) { - case CHSC_START: - return chsc_ioctl_start((void __user *)arg); - case CHSC_INFO_CHANNEL_PATH: - return chsc_ioctl_info_channel_path((void __user *)arg); - case CHSC_INFO_CU: - return chsc_ioctl_info_cu((void __user *)arg); - case CHSC_INFO_SCH_CU: - return chsc_ioctl_info_sch_cu((void __user *)arg); - case CHSC_INFO_CI: - return chsc_ioctl_conf_info((void __user *)arg); - case CHSC_INFO_CCL: - return chsc_ioctl_conf_comp_list((void __user *)arg); - case CHSC_INFO_CPD: - return chsc_ioctl_chpd((void __user *)arg); - case CHSC_INFO_DCAL: - return chsc_ioctl_dcal((void __user *)arg); - default: /* unknown ioctl number */ - return -ENOIOCTLCMD; - } -} - -static const struct file_operations chsc_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = chsc_ioctl, - .compat_ioctl = chsc_ioctl, -}; - -static struct miscdevice chsc_misc_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "chsc", - .fops = &chsc_fops, -}; - -static int __init chsc_misc_init(void) -{ - return misc_register(&chsc_misc_device); -} - -static void chsc_misc_cleanup(void) -{ - misc_deregister(&chsc_misc_device); -} - -static int __init chsc_sch_init(void) -{ - int ret; - - ret = chsc_init_dbfs(); - if (ret) - return ret; - isc_register(CHSC_SCH_ISC); - ret = chsc_init_sch_driver(); - if (ret) - goto out_dbf; - ret = chsc_misc_init(); - if (ret) - goto out_driver; - return ret; -out_driver: - chsc_cleanup_sch_driver(); -out_dbf: - isc_unregister(CHSC_SCH_ISC); - chsc_remove_dbfs(); - return ret; -} - -static void __exit chsc_sch_exit(void) -{ - chsc_misc_cleanup(); - chsc_cleanup_sch_driver(); - isc_unregister(CHSC_SCH_ISC); - chsc_remove_dbfs(); -} - -module_init(chsc_sch_init); -module_exit(chsc_sch_exit); diff --git a/trunk/drivers/s390/cio/chsc_sch.h b/trunk/drivers/s390/cio/chsc_sch.h deleted file mode 100644 index 589ebfad6aad..000000000000 --- a/trunk/drivers/s390/cio/chsc_sch.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _CHSC_SCH_H -#define _CHSC_SCH_H - -struct chsc_request { - struct completion completion; - struct irb irb; -}; - -struct chsc_private { - struct chsc_request *request; -}; - -#endif diff --git a/trunk/drivers/s390/cio/cio.c b/trunk/drivers/s390/cio/cio.c index 33bff8fec7d1..b32d7eb3d81a 100644 --- a/trunk/drivers/s390/cio/cio.c +++ b/trunk/drivers/s390/cio/cio.c @@ -2,7 +2,7 @@ * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls * - * Copyright IBM Corp. 1999,2008 + * Copyright (C) IBM Corp. 1999,2006 * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -24,9 +24,7 @@ #include #include #include -#include #include -#include #include "cio.h" #include "css.h" #include "chsc.h" @@ -74,6 +72,7 @@ static int __init cio_debug_init(void) debug_unregister(cio_debug_trace_id); if (cio_debug_crw_id) debug_unregister(cio_debug_crw_id); + printk(KERN_WARNING"cio: could not initialize debugging\n"); return -1; } @@ -129,7 +128,7 @@ cio_tpi(void) local_bh_disable(); irq_enter (); spin_lock(sch->lock); - memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); + memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); if (sch->driver && sch->driver->irq) sch->driver->irq(sch); spin_unlock(sch->lock); @@ -168,30 +167,30 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ { char dbf_txt[15]; int ccode; - union orb *orb; + struct orb *orb; CIO_TRACE_EVENT(4, "stIO"); CIO_TRACE_EVENT(4, sch->dev.bus_id); orb = &to_io_private(sch)->orb; /* sch is always under 2G. */ - orb->cmd.intparm = (u32)(addr_t)sch; - orb->cmd.fmt = 1; + orb->intparm = (u32)(addr_t)sch; + orb->fmt = 1; - orb->cmd.pfch = sch->options.prefetch == 0; - orb->cmd.spnd = sch->options.suspend; - orb->cmd.ssic = sch->options.suspend && sch->options.inter; - orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm; + orb->pfch = sch->options.prefetch == 0; + orb->spnd = sch->options.suspend; + orb->ssic = sch->options.suspend && sch->options.inter; + orb->lpm = (lpm != 0) ? lpm : sch->lpm; #ifdef CONFIG_64BIT /* * for 64 bit we always support 64 bit IDAWs with 4k page size only */ - orb->cmd.c64 = 1; - orb->cmd.i2k = 0; + orb->c64 = 1; + orb->i2k = 0; #endif - orb->cmd.key = key >> 4; + orb->key = key >> 4; /* issue "Start Subchannel" */ - orb->cmd.cpa = (__u32) __pa(cpa); + orb->cpa = (__u32) __pa(cpa); ccode = ssch(sch->schid, orb); /* process condition code */ @@ -203,7 +202,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ /* * initialize device status information */ - sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_START_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ @@ -238,7 +237,7 @@ cio_resume (struct subchannel *sch) switch (ccode) { case 0: - sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_RESUME_PEND; return 0; case 1: return -EBUSY; @@ -278,7 +277,7 @@ cio_halt(struct subchannel *sch) switch (ccode) { case 0: - sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ @@ -313,7 +312,7 @@ cio_clear(struct subchannel *sch) switch (ccode) { case 0: - sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND; return 0; default: /* device not operational */ return -ENODEV; @@ -388,10 +387,8 @@ cio_modify (struct subchannel *sch) return ret; } -/** - * cio_enable_subchannel - enable a subchannel. - * @sch: subchannel to be enabled - * @intparm: interruption parameter to set +/* + * Enable subchannel. */ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { @@ -437,13 +434,12 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) CIO_TRACE_EVENT (2, dbf_txt); return ret; } -EXPORT_SYMBOL_GPL(cio_enable_subchannel); -/** - * cio_disable_subchannel - disable a subchannel. - * @sch: subchannel to disable +/* + * Disable subchannel. */ -int cio_disable_subchannel(struct subchannel *sch) +int +cio_disable_subchannel (struct subchannel *sch) { char dbf_txt[15]; int ccode; @@ -459,7 +455,7 @@ int cio_disable_subchannel(struct subchannel *sch) if (ccode == 3) /* Not operational. */ return -ENODEV; - if (scsw_actl(&sch->schib.scsw) != 0) + if (sch->schib.scsw.actl != 0) /* * the disable function must not be called while there are * requests pending for completion ! @@ -488,7 +484,6 @@ int cio_disable_subchannel(struct subchannel *sch) CIO_TRACE_EVENT (2, dbf_txt); return ret; } -EXPORT_SYMBOL_GPL(cio_disable_subchannel); int cio_create_sch_lock(struct subchannel *sch) { @@ -499,61 +494,27 @@ int cio_create_sch_lock(struct subchannel *sch) return 0; } -static int cio_check_devno_blacklisted(struct subchannel *sch) -{ - if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) { - /* - * This device must not be known to Linux. So we simply - * say that there is no device and return ENODEV. - */ - CIO_MSG_EVENT(6, "Blacklisted device detected " - "at devno %04X, subchannel set %x\n", - sch->schib.pmcw.dev, sch->schid.ssid); - return -ENODEV; - } - return 0; -} - -static int cio_validate_io_subchannel(struct subchannel *sch) -{ - /* Initialization for io subchannels. */ - if (!css_sch_is_valid(&sch->schib)) - return -ENODEV; - - /* Devno is valid. */ - return cio_check_devno_blacklisted(sch); -} - -static int cio_validate_msg_subchannel(struct subchannel *sch) -{ - /* Initialization for message subchannels. */ - if (!css_sch_is_valid(&sch->schib)) - return -ENODEV; - - /* Devno is valid. */ - return cio_check_devno_blacklisted(sch); -} - -/** - * cio_validate_subchannel - basic validation of subchannel - * @sch: subchannel structure to be filled out - * @schid: subchannel id +/* + * cio_validate_subchannel() * * Find out subchannel type and initialize struct subchannel. * Return codes: - * 0 on success + * SUBCHANNEL_TYPE_IO for a normal io subchannel + * SUBCHANNEL_TYPE_CHSC for a chsc subchannel + * SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel + * SUBCHANNEL_TYPE_ADM for a adm(?) subchannel * -ENXIO for non-defined subchannels - * -ENODEV for invalid subchannels or blacklisted devices - * -EIO for subchannels in an invalid subchannel set + * -ENODEV for subchannels with invalid device number or blacklisted devices */ -int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) +int +cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) { char dbf_txt[15]; int ccode; int err; - sprintf(dbf_txt, "valsch%x", schid.sch_no); - CIO_TRACE_EVENT(4, dbf_txt); + sprintf (dbf_txt, "valsch%x", schid.sch_no); + CIO_TRACE_EVENT (4, dbf_txt); /* Nuke all fields. */ memset(sch, 0, sizeof(struct subchannel)); @@ -585,21 +546,67 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) /* Copy subchannel type from path management control word. */ sch->st = sch->schib.pmcw.st; - switch (sch->st) { - case SUBCHANNEL_TYPE_IO: - err = cio_validate_io_subchannel(sch); - break; - case SUBCHANNEL_TYPE_MSG: - err = cio_validate_msg_subchannel(sch); - break; - default: - err = 0; + /* + * ... just being curious we check for non I/O subchannels + */ + if (sch->st != 0) { + CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports " + "non-I/O subchannel type %04X\n", + sch->schid.ssid, sch->schid.sch_no, sch->st); + /* We stop here for non-io subchannels. */ + err = sch->st; + goto out; + } + + /* Initialization for io subchannels. */ + if (!css_sch_is_valid(&sch->schib)) { + err = -ENODEV; + goto out; } - if (err) + + /* Devno is valid. */ + if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { + /* + * This device must not be known to Linux. So we simply + * say that there is no device and return ENODEV. + */ + CIO_MSG_EVENT(6, "Blacklisted device detected " + "at devno %04X, subchannel set %x\n", + sch->schib.pmcw.dev, sch->schid.ssid); + err = -ENODEV; goto out; + } + if (cio_is_console(sch->schid)) { + sch->opm = 0xff; + sch->isc = 1; + } else { + sch->opm = chp_get_sch_opm(sch); + sch->isc = 3; + } + sch->lpm = sch->schib.pmcw.pam & sch->opm; + + CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X " + "- PIM = %02X, PAM = %02X, POM = %02X\n", + sch->schib.pmcw.dev, sch->schid.ssid, + sch->schid.sch_no, sch->schib.pmcw.pim, + sch->schib.pmcw.pam, sch->schib.pmcw.pom); - CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n", - sch->schid.ssid, sch->schid.sch_no, sch->st); + /* + * We now have to initially ... + * ... enable "concurrent sense" + * ... enable "multipath mode" if more than one + * CHPID is available. This is done regardless + * whether multiple paths are available for us. + */ + sch->schib.pmcw.csense = 1; /* concurrent sense */ + sch->schib.pmcw.ena = 0; + if ((sch->lpm & (sch->lpm - 1)) != 0) + sch->schib.pmcw.mp = 1; /* multipath mode */ + /* clean up possible residual cmf stuff */ + sch->schib.pmcw.mme = 0; + sch->schib.pmcw.mbfc = 0; + sch->schib.pmcw.mbi = 0; + sch->schib.mba = 0; return 0; out: if (!cio_is_console(schid)) @@ -640,7 +647,7 @@ do_IRQ (struct pt_regs *regs) */ if (tpi_info->adapter_IO == 1 && tpi_info->int_type == IO_INTERRUPT_TYPE) { - do_adapter_IO(tpi_info->isc); + do_adapter_IO(); continue; } sch = (struct subchannel *)(unsigned long)tpi_info->intparm; @@ -699,9 +706,9 @@ void wait_cons_dev(void) if (!console_subchannel_in_use) return; - /* disable all but the console isc */ + /* disable all but isc 1 (console device) */ __ctl_store (save_cr6, 6, 6); - cr6 = 1UL << (31 - CONSOLE_ISC); + cr6 = 0x40000000; __ctl_load (cr6, 6, 6); do { @@ -709,7 +716,7 @@ void wait_cons_dev(void) if (!cio_tpi()) cpu_relax(); spin_lock(console_subchannel.lock); - } while (console_subchannel.schib.scsw.cmd.actl != 0); + } while (console_subchannel.schib.scsw.actl != 0); /* * restore previous isc value */ @@ -754,6 +761,7 @@ cio_get_console_sch_no(void) /* unlike in 2.4, we cannot autoprobe here, since * the channel subsystem is not fully initialized. * With some luck, the HWC console can take over */ + printk(KERN_WARNING "cio: No ccw console found!\n"); return -1; } return console_irq; @@ -770,7 +778,6 @@ cio_probe_console(void) sch_no = cio_get_console_sch_no(); if (sch_no == -1) { console_subchannel_in_use = 0; - printk(KERN_WARNING "cio: No ccw console found!\n"); return ERR_PTR(-ENODEV); } memset(&console_subchannel, 0, sizeof(struct subchannel)); @@ -783,15 +790,15 @@ cio_probe_console(void) } /* - * enable console I/O-interrupt subclass + * enable console I/O-interrupt subclass 1 */ - isc_register(CONSOLE_ISC); - console_subchannel.schib.pmcw.isc = CONSOLE_ISC; + ctl_set_bit(6, 30); + console_subchannel.isc = 1; + console_subchannel.schib.pmcw.isc = 1; console_subchannel.schib.pmcw.intparm = (u32)(addr_t)&console_subchannel; ret = cio_modify(&console_subchannel); if (ret) { - isc_unregister(CONSOLE_ISC); console_subchannel_in_use = 0; return ERR_PTR(ret); } @@ -803,7 +810,7 @@ cio_release_console(void) { console_subchannel.schib.pmcw.intparm = 0; cio_modify(&console_subchannel); - isc_unregister(CONSOLE_ISC); + ctl_clear_bit(6, 24); console_subchannel_in_use = 0; } @@ -857,7 +864,7 @@ static void udelay_reset(unsigned long usecs) } static int -__clear_io_subchannel_easy(struct subchannel_id schid) +__clear_subchannel_easy(struct subchannel_id schid) { int retry; @@ -876,12 +883,6 @@ __clear_io_subchannel_easy(struct subchannel_id schid) return -EBUSY; } -static void __clear_chsc_subchannel_easy(void) -{ - /* It seems we can only wait for a bit here :/ */ - udelay_reset(100); -} - static int pgm_check_occured; static void cio_reset_pgm_check_handler(void) @@ -920,22 +921,11 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) case -ENODEV: break; default: /* -EBUSY */ - switch (schib.pmcw.st) { - case SUBCHANNEL_TYPE_IO: - if (__clear_io_subchannel_easy(schid)) - goto out; /* give up... */ - break; - case SUBCHANNEL_TYPE_CHSC: - __clear_chsc_subchannel_easy(); - break; - default: - /* No default clear strategy */ - break; - } + if (__clear_subchannel_easy(schid)) + break; /* give up... */ stsch(schid, &schib); __disable_subchannel_easy(schid, &schib); } -out: return 0; } @@ -1078,61 +1068,3 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo) iplinfo->is_qdio = schib.pmcw.qf; return 0; } - -/** - * cio_tm_start_key - perform start function - * @sch: subchannel on which to perform the start function - * @tcw: transport-command word to be started - * @lpm: mask of paths to use - * @key: storage key to use for storage access - * - * Start the tcw on the given subchannel. Return zero on success, non-zero - * otherwise. - */ -int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key) -{ - int cc; - union orb *orb = &to_io_private(sch)->orb; - - memset(orb, 0, sizeof(union orb)); - orb->tm.intparm = (u32) (addr_t) sch; - orb->tm.key = key >> 4; - orb->tm.b = 1; - orb->tm.lpm = lpm ? lpm : sch->lpm; - orb->tm.tcw = (u32) (addr_t) tcw; - cc = ssch(sch->schid, orb); - switch (cc) { - case 0: - return 0; - case 1: - case 2: - return -EBUSY; - default: - return cio_start_handle_notoper(sch, lpm); - } -} - -/** - * cio_tm_intrg - perform interrogate function - * @sch - subchannel on which to perform the interrogate function - * - * If the specified subchannel is running in transport-mode, perform the - * interrogate function. Return zero on success, non-zero otherwie. - */ -int cio_tm_intrg(struct subchannel *sch) -{ - int cc; - - if (!to_io_private(sch)->orb.tm.b) - return -EINVAL; - cc = xsch(sch->schid); - switch (cc) { - case 0: - case 2: - return 0; - case 1: - return -EBUSY; - default: - return -ENODEV; - } -} diff --git a/trunk/drivers/s390/cio/cio.h b/trunk/drivers/s390/cio/cio.h index 3b236d20e835..6e933aebe013 100644 --- a/trunk/drivers/s390/cio/cio.h +++ b/trunk/drivers/s390/cio/cio.h @@ -3,12 +3,9 @@ #include #include -#include #include -#include -#include -#include #include "chsc.h" +#include "schid.h" /* * path management control word @@ -16,7 +13,7 @@ struct pmcw { u32 intparm; /* interruption parameter */ u32 qf : 1; /* qdio facility */ - u32 w : 1; + u32 res0 : 1; /* reserved zeros */ u32 isc : 3; /* interruption sublass */ u32 res5 : 3; /* reserved zeros */ u32 ena : 1; /* enabled */ @@ -50,7 +47,7 @@ struct pmcw { */ struct schib { struct pmcw pmcw; /* path management control word */ - union scsw scsw; /* subchannel status word */ + struct scsw scsw; /* subchannel status word */ __u64 mba; /* measurement block address */ __u8 mda[4]; /* model dependent area */ } __attribute__ ((packed,aligned(4))); @@ -102,11 +99,8 @@ extern int cio_set_options (struct subchannel *, int); extern int cio_get_options (struct subchannel *); extern int cio_modify (struct subchannel *); -int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); -int cio_tm_intrg(struct subchannel *sch); - int cio_create_sch_lock(struct subchannel *); -void do_adapter_IO(u8 isc); +void do_adapter_IO(void); void do_IRQ(struct pt_regs *); /* Use with care. */ diff --git a/trunk/drivers/s390/cio/cmf.c b/trunk/drivers/s390/cio/cmf.c index a90b28c0be57..2808b6833b9e 100644 --- a/trunk/drivers/s390/cio/cmf.c +++ b/trunk/drivers/s390/cio/cmf.c @@ -341,12 +341,12 @@ static int cmf_copy_block(struct ccw_device *cdev) if (stsch(sch->schid, &sch->schib)) return -ENODEV; - if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) { + if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) { /* Don't copy if a start function is in progress. */ - if ((!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_SUSPENDED)) && - (scsw_actl(&sch->schib.scsw) & + if ((!(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED)) && + (sch->schib.scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) && - (!(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_SEC_STATUS))) + (!(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))) return -EBUSY; } cmb_data = cdev->private->cmb; @@ -612,6 +612,9 @@ static int alloc_cmb(struct ccw_device *cdev) free_pages((unsigned long)mem, get_order(size)); } else if (!mem) { /* no luck */ + printk(KERN_WARNING "cio: failed to allocate area " + "for measuring %d subchannels\n", + cmb_area.num_channels); ret = -ENOMEM; goto out; } else { @@ -1227,9 +1230,13 @@ static ssize_t cmb_enable_store(struct device *dev, switch (val) { case 0: ret = disable_cmf(cdev); + if (ret) + dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret); break; case 1: ret = enable_cmf(cdev); + if (ret && ret != -EBUSY) + dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret); break; } @@ -1337,7 +1344,8 @@ static int __init init_cmf(void) * to basic mode. */ if (format == CMF_AUTODETECT) { - if (!css_general_characteristics.ext_mb) { + if (!css_characteristics_avail || + !css_general_characteristics.ext_mb) { format = CMF_BASIC; } else { format = CMF_EXTENDED; @@ -1357,6 +1365,8 @@ static int __init init_cmf(void) cmbops = &cmbops_extended; break; default: + printk(KERN_ERR "cio: Invalid format %d for channel " + "measurement facility\n", format); return 1; } diff --git a/trunk/drivers/s390/cio/css.c b/trunk/drivers/s390/cio/css.c index 46c021d880dc..a76956512b2d 100644 --- a/trunk/drivers/s390/cio/css.c +++ b/trunk/drivers/s390/cio/css.c @@ -2,7 +2,8 @@ * drivers/s390/cio/css.c * driver for channel subsystem * - * Copyright IBM Corp. 2002,2008 + * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) */ @@ -13,9 +14,7 @@ #include #include #include -#include -#include "../s390mach.h" #include "css.h" #include "cio.h" #include "cio_debug.h" @@ -31,6 +30,8 @@ static int max_ssid = 0; struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; +int css_characteristics_avail = 0; + int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) { @@ -120,6 +121,25 @@ css_alloc_subchannel(struct subchannel_id schid) kfree(sch); return ERR_PTR(ret); } + + if (sch->st != SUBCHANNEL_TYPE_IO) { + /* For now we ignore all non-io subchannels. */ + kfree(sch); + return ERR_PTR(-EINVAL); + } + + /* + * Set intparm to subchannel address. + * This is fine even on 64bit since the subchannel is always located + * under 2G. + */ + sch->schib.pmcw.intparm = (u32)(addr_t)sch; + ret = cio_modify(sch); + if (ret) { + kfree(sch->lock); + kfree(sch); + return ERR_PTR(ret); + } return sch; } @@ -157,18 +177,12 @@ static int css_sch_device_register(struct subchannel *sch) return ret; } -/** - * css_sch_device_unregister - unregister a subchannel - * @sch: subchannel to be unregistered - */ void css_sch_device_unregister(struct subchannel *sch) { mutex_lock(&sch->reg_mutex); - if (device_is_registered(&sch->dev)) - device_unregister(&sch->dev); + device_unregister(&sch->dev); mutex_unlock(&sch->reg_mutex); } -EXPORT_SYMBOL_GPL(css_sch_device_unregister); static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) { @@ -215,41 +229,6 @@ void css_update_ssd_info(struct subchannel *sch) } } -static ssize_t type_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct subchannel *sch = to_subchannel(dev); - - return sprintf(buf, "%01x\n", sch->st); -} - -static DEVICE_ATTR(type, 0444, type_show, NULL); - -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct subchannel *sch = to_subchannel(dev); - - return sprintf(buf, "css:t%01X\n", sch->st); -} - -static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); - -static struct attribute *subch_attrs[] = { - &dev_attr_type.attr, - &dev_attr_modalias.attr, - NULL, -}; - -static struct attribute_group subch_attr_group = { - .attrs = subch_attrs, -}; - -static struct attribute_group *default_subch_attr_groups[] = { - &subch_attr_group, - NULL, -}; - static int css_register_subchannel(struct subchannel *sch) { int ret; @@ -258,17 +237,16 @@ static int css_register_subchannel(struct subchannel *sch) sch->dev.parent = &channel_subsystems[0]->device; sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; - sch->dev.groups = default_subch_attr_groups; + sch->dev.groups = subch_attr_groups; /* * We don't want to generate uevents for I/O subchannels that don't * have a working ccw device behind them since they will be * unregistered before they can be used anyway, so we delay the add * uevent until after device recognition was successful. - * Note that we suppress the uevent for all subchannel types; - * the subchannel driver can decide itself when it wants to inform - * userspace of its existence. */ - sch->dev.uevent_suppress = 1; + if (!cio_is_console(sch->schid)) + /* Console is special, no need to suppress. */ + sch->dev.uevent_suppress = 1; css_update_ssd_info(sch); /* make it known to the system */ ret = css_sch_device_register(sch); @@ -277,19 +255,10 @@ static int css_register_subchannel(struct subchannel *sch) sch->schid.ssid, sch->schid.sch_no, ret); return ret; } - if (!sch->driver) { - /* - * No driver matched. Generate the uevent now so that - * a fitting driver module may be loaded based on the - * modalias. - */ - sch->dev.uevent_suppress = 0; - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } return ret; } -int css_probe_device(struct subchannel_id schid) +static int css_probe_device(struct subchannel_id schid) { int ret; struct subchannel *sch; @@ -332,12 +301,116 @@ int css_sch_is_valid(struct schib *schib) { if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv) return 0; - if ((schib->pmcw.st == SUBCHANNEL_TYPE_MSG) && !schib->pmcw.w) - return 0; return 1; } EXPORT_SYMBOL_GPL(css_sch_is_valid); +static int css_get_subchannel_status(struct subchannel *sch) +{ + struct schib schib; + + if (stsch(sch->schid, &schib)) + return CIO_GONE; + if (!css_sch_is_valid(&schib)) + return CIO_GONE; + if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev)) + return CIO_REVALIDATE; + if (!sch->lpm) + return CIO_NO_PATH; + return CIO_OPER; +} + +static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) +{ + int event, ret, disc; + unsigned long flags; + enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action; + + spin_lock_irqsave(sch->lock, flags); + disc = device_is_disconnected(sch); + if (disc && slow) { + /* Disconnected devices are evaluated directly only.*/ + spin_unlock_irqrestore(sch->lock, flags); + return 0; + } + /* No interrupt after machine check - kill pending timers. */ + device_kill_pending_timer(sch); + if (!disc && !slow) { + /* Non-disconnected devices are evaluated on the slow path. */ + spin_unlock_irqrestore(sch->lock, flags); + return -EAGAIN; + } + event = css_get_subchannel_status(sch); + CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n", + sch->schid.ssid, sch->schid.sch_no, event, + disc ? "disconnected" : "normal", + slow ? "slow" : "fast"); + /* Analyze subchannel status. */ + action = NONE; + switch (event) { + case CIO_NO_PATH: + if (disc) { + /* Check if paths have become available. */ + action = REPROBE; + break; + } + /* fall through */ + case CIO_GONE: + /* Prevent unwanted effects when opening lock. */ + cio_disable_subchannel(sch); + device_set_disconnected(sch); + /* Ask driver what to do with device. */ + action = UNREGISTER; + if (sch->driver && sch->driver->notify) { + spin_unlock_irqrestore(sch->lock, flags); + ret = sch->driver->notify(sch, event); + spin_lock_irqsave(sch->lock, flags); + if (ret) + action = NONE; + } + break; + case CIO_REVALIDATE: + /* Device will be removed, so no notify necessary. */ + if (disc) + /* Reprobe because immediate unregister might block. */ + action = REPROBE; + else + action = UNREGISTER_PROBE; + break; + case CIO_OPER: + if (disc) + /* Get device operational again. */ + action = REPROBE; + break; + } + /* Perform action. */ + ret = 0; + switch (action) { + case UNREGISTER: + case UNREGISTER_PROBE: + /* Unregister device (will use subchannel lock). */ + spin_unlock_irqrestore(sch->lock, flags); + css_sch_device_unregister(sch); + spin_lock_irqsave(sch->lock, flags); + + /* Reset intparm to zeroes. */ + sch->schib.pmcw.intparm = 0; + cio_modify(sch); + break; + case REPROBE: + device_trigger_reprobe(sch); + break; + default: + break; + } + spin_unlock_irqrestore(sch->lock, flags); + /* Probe if necessary. */ + if (action == UNREGISTER_PROBE) + ret = css_probe_device(sch->schid); + + return ret; +} + static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) { struct schib schib; @@ -356,21 +429,6 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) return css_probe_device(schid); } -static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) -{ - int ret = 0; - - if (sch->driver) { - if (sch->driver->sch_event) - ret = sch->driver->sch_event(sch, slow); - else - dev_dbg(&sch->dev, - "Got subchannel machine check but " - "no sch_event handler provided.\n"); - } - return ret; -} - static void css_evaluate_subchannel(struct subchannel_id schid, int slow) { struct subchannel *sch; @@ -538,29 +596,18 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe); /* * Called from the machine check handler for subchannel report words. */ -static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) +void css_process_crw(int rsid1, int rsid2) { struct subchannel_id mchk_schid; - if (overflow) { - css_schedule_eval_all(); - return; - } - CIO_CRW_EVENT(2, "CRW0 reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, - crw0->erc, crw0->rsid); - if (crw1) - CIO_CRW_EVENT(2, "CRW1 reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw1->slct, crw1->oflw, crw1->chn, crw1->rsc, - crw1->anc, crw1->erc, crw1->rsid); + CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n", + rsid1, rsid2); init_subchannel_id(&mchk_schid); - mchk_schid.sch_no = crw0->rsid; - if (crw1) - mchk_schid.ssid = (crw1->rsid >> 8) & 3; + mchk_schid.sch_no = rsid1; + if (rsid2 != 0) + mchk_schid.ssid = (rsid2 >> 8) & 3; - /* + /* * Since we are always presented with IPI in the CRW, we have to * use stsch() to find out if the subchannel in question has come * or gone. @@ -611,7 +658,7 @@ __init_channel_subsystem(struct subchannel_id schid, void *data) static void __init css_generate_pgid(struct channel_subsystem *css, u32 tod_high) { - if (css_general_characteristics.mcss) { + if (css_characteristics_avail && css_general_characteristics.mcss) { css->global_pgid.pgid_high.ext_cssid.version = 0x80; css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; } else { @@ -748,6 +795,8 @@ init_channel_subsystem (void) ret = chsc_determine_css_characteristics(); if (ret == -ENOMEM) goto out; /* No need to continue. */ + if (ret == 0) + css_characteristics_avail = 1; ret = chsc_alloc_sei_area(); if (ret) @@ -757,10 +806,6 @@ init_channel_subsystem (void) if (ret) goto out; - ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw); - if (ret) - goto out; - if ((ret = bus_register(&css_bus_type))) goto out; @@ -791,7 +836,8 @@ init_channel_subsystem (void) ret = device_register(&css->device); if (ret) goto out_free_all; - if (css_chsc_characteristics.secm) { + if (css_characteristics_avail && + css_chsc_characteristics.secm) { ret = device_create_file(&css->device, &dev_attr_cm_enable); if (ret) @@ -806,8 +852,7 @@ init_channel_subsystem (void) goto out_pseudo; css_init_done = 1; - /* Enable default isc for I/O subchannels. */ - isc_register(IO_SCH_ISC); + ctl_set_bit(6, 28); for_each_subchannel(__init_channel_subsystem, NULL); return 0; @@ -830,7 +875,7 @@ init_channel_subsystem (void) i--; css = channel_subsystems[i]; device_unregister(&css->pseudo_subchannel->dev); - if (css_chsc_characteristics.secm) + if (css_characteristics_avail && css_chsc_characteristics.secm) device_remove_file(&css->device, &dev_attr_cm_enable); device_unregister(&css->device); @@ -838,7 +883,6 @@ init_channel_subsystem (void) out_bus: bus_unregister(&css_bus_type); out: - s390_unregister_crw_handler(CRW_RSC_CSS); chsc_free_sei_area(); kfree(slow_subchannel_set); printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n", @@ -851,16 +895,19 @@ int sch_is_pseudo_sch(struct subchannel *sch) return sch == to_css(sch->dev.parent)->pseudo_subchannel; } -static int css_bus_match(struct device *dev, struct device_driver *drv) +/* + * find a driver for a subchannel. They identify by the subchannel + * type with the exception that the console subchannel driver has its own + * subchannel type although the device is an i/o subchannel + */ +static int +css_bus_match (struct device *dev, struct device_driver *drv) { struct subchannel *sch = to_subchannel(dev); struct css_driver *driver = to_cssdriver(drv); - struct css_device_id *id; - for (id = driver->subchannel_type; id->match_flags; id++) { - if (sch->st == id->type) - return 1; - } + if (sch->st == driver->subchannel_type) + return 1; return 0; } @@ -898,25 +945,12 @@ static void css_shutdown(struct device *dev) sch->driver->shutdown(sch); } -static int css_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct subchannel *sch = to_subchannel(dev); - int ret; - - ret = add_uevent_var(env, "ST=%01X", sch->st); - if (ret) - return ret; - ret = add_uevent_var(env, "MODALIAS=css:t%01X", sch->st); - return ret; -} - struct bus_type css_bus_type = { .name = "css", .match = css_bus_match, .probe = css_probe, .remove = css_remove, .shutdown = css_shutdown, - .uevent = css_uevent, }; /** @@ -951,3 +985,4 @@ subsys_initcall(init_channel_subsystem); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(css_bus_type); +EXPORT_SYMBOL_GPL(css_characteristics_avail); diff --git a/trunk/drivers/s390/cio/css.h b/trunk/drivers/s390/cio/css.h index 57ebf120f825..e1913518f354 100644 --- a/trunk/drivers/s390/cio/css.h +++ b/trunk/drivers/s390/cio/css.h @@ -9,7 +9,8 @@ #include #include -#include + +#include "schid.h" /* * path grouping stuff @@ -57,28 +58,20 @@ struct pgid { __u32 tod_high; /* high word TOD clock */ } __attribute__ ((packed)); -struct subchannel; -struct chp_link; -/** - * struct css_driver - device driver for subchannels - * @owner: owning module - * @subchannel_type: subchannel type supported by this driver - * @drv: embedded device driver structure - * @irq: called on interrupts - * @chp_event: called for events affecting a channel path - * @sch_event: called for events affecting the subchannel - * @probe: function called on probe - * @remove: function called on remove - * @shutdown: called at device shutdown - * @name: name of the device driver +/* + * A css driver handles all subchannels of one type. + * Currently, we only care about I/O subchannels (type 0), these + * have a ccw_device connected to them. */ +struct subchannel; struct css_driver { struct module *owner; - struct css_device_id *subchannel_type; + unsigned int subchannel_type; struct device_driver drv; void (*irq)(struct subchannel *); - int (*chp_event)(struct subchannel *, struct chp_link *, int); - int (*sch_event)(struct subchannel *, int); + int (*notify)(struct subchannel *, int); + void (*verify)(struct subchannel *); + void (*termination)(struct subchannel *); int (*probe)(struct subchannel *); int (*remove)(struct subchannel *); void (*shutdown)(struct subchannel *); @@ -96,13 +89,13 @@ extern int css_driver_register(struct css_driver *); extern void css_driver_unregister(struct css_driver *); extern void css_sch_device_unregister(struct subchannel *); -extern int css_probe_device(struct subchannel_id); -extern struct subchannel *get_subchannel_by_schid(struct subchannel_id); +extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), int (*fn_unknown)(struct subchannel_id, void *), void *data); extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); +extern void css_process_crw(int, int); extern void css_reiterate_subchannels(void); void css_update_ssd_info(struct subchannel *sch); @@ -128,6 +121,20 @@ struct channel_subsystem { extern struct bus_type css_bus_type; extern struct channel_subsystem *channel_subsystems[]; +/* Some helper functions for disconnected state. */ +int device_is_disconnected(struct subchannel *); +void device_set_disconnected(struct subchannel *); +void device_trigger_reprobe(struct subchannel *); + +/* Helper functions for vary on/off. */ +int device_is_online(struct subchannel *); +void device_kill_io(struct subchannel *); +void device_set_intretry(struct subchannel *sch); +int device_trigger_verify(struct subchannel *sch); + +/* Machine check helper function. */ +void device_kill_pending_timer(struct subchannel *); + /* Helper functions to build lists for the slow path. */ void css_schedule_eval(struct subchannel_id schid); void css_schedule_eval_all(void); @@ -138,4 +145,6 @@ int css_sch_is_valid(struct schib *); extern struct workqueue_struct *slow_path_wq; void css_wait_for_slow_path(void); + +extern struct attribute_group *subch_attr_groups[]; #endif diff --git a/trunk/drivers/s390/cio/device.c b/trunk/drivers/s390/cio/device.c index e818d0c54c09..e22813db74a2 100644 --- a/trunk/drivers/s390/cio/device.c +++ b/trunk/drivers/s390/cio/device.c @@ -2,7 +2,8 @@ * drivers/s390/cio/device.c * bus driver for ccw devices * - * Copyright IBM Corp. 2002,2008 + * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) @@ -22,9 +23,7 @@ #include #include /* HZ */ #include -#include -#include "chp.h" #include "cio.h" #include "cio_debug.h" #include "css.h" @@ -126,24 +125,19 @@ struct bus_type ccw_bus_type; static void io_subchannel_irq(struct subchannel *); static int io_subchannel_probe(struct subchannel *); static int io_subchannel_remove(struct subchannel *); +static int io_subchannel_notify(struct subchannel *, int); +static void io_subchannel_verify(struct subchannel *); +static void io_subchannel_ioterm(struct subchannel *); static void io_subchannel_shutdown(struct subchannel *); -static int io_subchannel_sch_event(struct subchannel *, int); -static int io_subchannel_chp_event(struct subchannel *, struct chp_link *, - int); - -static struct css_device_id io_subchannel_ids[] = { - { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(css, io_subchannel_ids); static struct css_driver io_subchannel_driver = { .owner = THIS_MODULE, - .subchannel_type = io_subchannel_ids, + .subchannel_type = SUBCHANNEL_TYPE_IO, .name = "io_subchannel", .irq = io_subchannel_irq, - .sch_event = io_subchannel_sch_event, - .chp_event = io_subchannel_chp_event, + .notify = io_subchannel_notify, + .verify = io_subchannel_verify, + .termination = io_subchannel_ioterm, .probe = io_subchannel_probe, .remove = io_subchannel_remove, .shutdown = io_subchannel_shutdown, @@ -493,22 +487,25 @@ static int online_store_recog_and_online(struct ccw_device *cdev) ccw_device_set_online(cdev); return 0; } -static int online_store_handle_online(struct ccw_device *cdev, int force) +static void online_store_handle_online(struct ccw_device *cdev, int force) { int ret; ret = online_store_recog_and_online(cdev); if (ret) - return ret; + return; if (force && cdev->private->state == DEV_STATE_BOXED) { ret = ccw_device_stlck(cdev); - if (ret) - return ret; + if (ret) { + dev_warn(&cdev->dev, + "ccw_device_stlck returned %d!\n", ret); + return; + } if (cdev->id.cu_type == 0) cdev->private->state = DEV_STATE_NOT_OPER; online_store_recog_and_online(cdev); } - return 0; + } static ssize_t online_store (struct device *dev, struct device_attribute *attr, @@ -541,9 +538,8 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, ret = count; break; case 1: - ret = online_store_handle_online(cdev, force); - if (!ret) - ret = count; + online_store_handle_online(cdev, force); + ret = count; break; default: ret = -EINVAL; @@ -588,14 +584,19 @@ static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); static DEVICE_ATTR(online, 0644, online_show, online_store); static DEVICE_ATTR(availability, 0444, available_show, NULL); -static struct attribute *io_subchannel_attrs[] = { +static struct attribute * subch_attrs[] = { &dev_attr_chpids.attr, &dev_attr_pimpampom.attr, NULL, }; -static struct attribute_group io_subchannel_attr_group = { - .attrs = io_subchannel_attrs, +static struct attribute_group subch_attr_group = { + .attrs = subch_attrs, +}; + +struct attribute_group *subch_attr_groups[] = { + &subch_attr_group, + NULL, }; static struct attribute * ccwdev_attrs[] = { @@ -789,7 +790,7 @@ static void sch_attach_device(struct subchannel *sch, sch_set_cdev(sch, cdev); cdev->private->schid = sch->schid; cdev->ccwlock = sch->lock; - ccw_device_trigger_reprobe(cdev); + device_trigger_reprobe(sch); spin_unlock_irq(sch->lock); } @@ -1036,6 +1037,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) struct ccw_device_private *priv; sch_set_cdev(sch, cdev); + sch->driver = &io_subchannel_driver; cdev->ccwlock = sch->lock; /* Init private data. */ @@ -1120,33 +1122,8 @@ static void io_subchannel_irq(struct subchannel *sch) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); } -static void io_subchannel_init_fields(struct subchannel *sch) -{ - if (cio_is_console(sch->schid)) - sch->opm = 0xff; - else - sch->opm = chp_get_sch_opm(sch); - sch->lpm = sch->schib.pmcw.pam & sch->opm; - sch->isc = cio_is_console(sch->schid) ? CONSOLE_ISC : IO_SCH_ISC; - - CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X" - " - PIM = %02X, PAM = %02X, POM = %02X\n", - sch->schib.pmcw.dev, sch->schid.ssid, - sch->schid.sch_no, sch->schib.pmcw.pim, - sch->schib.pmcw.pam, sch->schib.pmcw.pom); - /* Initially set up some fields in the pmcw. */ - sch->schib.pmcw.ena = 0; - sch->schib.pmcw.csense = 1; /* concurrent sense */ - if ((sch->lpm & (sch->lpm - 1)) != 0) - sch->schib.pmcw.mp = 1; /* multipath mode */ - /* clean up possible residual cmf stuff */ - sch->schib.pmcw.mme = 0; - sch->schib.pmcw.mbfc = 0; - sch->schib.pmcw.mbi = 0; - sch->schib.mba = 0; -} - -static int io_subchannel_probe(struct subchannel *sch) +static int +io_subchannel_probe (struct subchannel *sch) { struct ccw_device *cdev; int rc; @@ -1155,21 +1132,11 @@ static int io_subchannel_probe(struct subchannel *sch) cdev = sch_get_cdev(sch); if (cdev) { - rc = sysfs_create_group(&sch->dev.kobj, - &io_subchannel_attr_group); - if (rc) - CIO_MSG_EVENT(0, "Failed to create io subchannel " - "attributes for subchannel " - "0.%x.%04x (rc=%d)\n", - sch->schid.ssid, sch->schid.sch_no, rc); /* * This subchannel already has an associated ccw_device. - * Throw the delayed uevent for the subchannel, register - * the ccw_device and exit. This happens for all early - * devices, e.g. the console. + * Register it and exit. This happens for all early + * device, e.g. the console. */ - sch->dev.uevent_suppress = 0; - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); cdev->dev.groups = ccwdev_attr_groups; device_initialize(&cdev->dev); ccw_device_register(cdev); @@ -1185,24 +1152,17 @@ static int io_subchannel_probe(struct subchannel *sch) get_device(&cdev->dev); return 0; } - io_subchannel_init_fields(sch); /* * First check if a fitting device may be found amongst the * disconnected devices or in the orphanage. */ dev_id.devno = sch->schib.pmcw.dev; dev_id.ssid = sch->schid.ssid; - rc = sysfs_create_group(&sch->dev.kobj, - &io_subchannel_attr_group); - if (rc) - return rc; /* Allocate I/O subchannel private data. */ sch->private = kzalloc(sizeof(struct io_subchannel_private), GFP_KERNEL | GFP_DMA); - if (!sch->private) { - rc = -ENOMEM; - goto out_err; - } + if (!sch->private) + return -ENOMEM; cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); if (!cdev) cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), @@ -1221,8 +1181,8 @@ static int io_subchannel_probe(struct subchannel *sch) } cdev = io_subchannel_create_ccwdev(sch); if (IS_ERR(cdev)) { - rc = PTR_ERR(cdev); - goto out_err; + kfree(sch->private); + return PTR_ERR(cdev); } rc = io_subchannel_recog(cdev, sch); if (rc) { @@ -1231,12 +1191,9 @@ static int io_subchannel_probe(struct subchannel *sch) spin_unlock_irqrestore(sch->lock, flags); if (cdev->dev.release) cdev->dev.release(&cdev->dev); - goto out_err; + kfree(sch->private); } - return 0; -out_err: - kfree(sch->private); - sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); + return rc; } @@ -1257,7 +1214,6 @@ io_subchannel_remove (struct subchannel *sch) ccw_device_unregister(cdev); put_device(&cdev->dev); kfree(sch->private); - sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); return 0; } @@ -1268,7 +1224,11 @@ static int io_subchannel_notify(struct subchannel *sch, int event) cdev = sch_get_cdev(sch); if (!cdev) return 0; - return ccw_device_notify(cdev, event); + if (!cdev->drv) + return 0; + if (!cdev->online) + return 0; + return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0; } static void io_subchannel_verify(struct subchannel *sch) @@ -1280,96 +1240,22 @@ static void io_subchannel_verify(struct subchannel *sch) dev_fsm_event(cdev, DEV_EVENT_VERIFY); } -static int check_for_io_on_path(struct subchannel *sch, int mask) +static void io_subchannel_ioterm(struct subchannel *sch) { - int cc; - - cc = stsch(sch->schid, &sch->schib); - if (cc) - return 0; - if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask) - return 1; - return 0; -} + struct ccw_device *cdev; -static void terminate_internal_io(struct subchannel *sch, - struct ccw_device *cdev) -{ - if (cio_clear(sch)) { - /* Recheck device in case clear failed. */ - sch->lpm = 0; - if (cdev->online) - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - else - css_schedule_eval(sch->schid); + cdev = sch_get_cdev(sch); + if (!cdev) + return; + /* Internal I/O will be retried by the interrupt handler. */ + if (cdev->private->flags.intretry) return; - } cdev->private->state = DEV_STATE_CLEAR_VERIFY; - /* Request retry of internal operation. */ - cdev->private->flags.intretry = 1; - /* Call handler. */ if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); } -static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask) -{ - struct ccw_device *cdev; - - cdev = sch_get_cdev(sch); - if (!cdev) - return; - if (check_for_io_on_path(sch, mask)) { - if (cdev->private->state == DEV_STATE_ONLINE) - ccw_device_kill_io(cdev); - else { - terminate_internal_io(sch, cdev); - /* Re-start path verification. */ - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - } - } else - /* trigger path verification. */ - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - -} - -static int io_subchannel_chp_event(struct subchannel *sch, - struct chp_link *link, int event) -{ - int mask; - - mask = chp_ssd_get_mask(&sch->ssd_info, link); - if (!mask) - return 0; - switch (event) { - case CHP_VARY_OFF: - sch->opm &= ~mask; - sch->lpm &= ~mask; - io_subchannel_terminate_path(sch, mask); - break; - case CHP_VARY_ON: - sch->opm |= mask; - sch->lpm |= mask; - io_subchannel_verify(sch); - break; - case CHP_OFFLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; - if (!css_sch_is_valid(&sch->schib)) - return -ENODEV; - io_subchannel_terminate_path(sch, mask); - break; - case CHP_ONLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; - sch->lpm |= mask & sch->opm; - io_subchannel_verify(sch); - break; - } - return 0; -} - static void io_subchannel_shutdown(struct subchannel *sch) { @@ -1399,195 +1285,6 @@ io_subchannel_shutdown(struct subchannel *sch) cio_disable_subchannel(sch); } -static int io_subchannel_get_status(struct subchannel *sch) -{ - struct schib schib; - - if (stsch(sch->schid, &schib) || !schib.pmcw.dnv) - return CIO_GONE; - if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev)) - return CIO_REVALIDATE; - if (!sch->lpm) - return CIO_NO_PATH; - return CIO_OPER; -} - -static int device_is_disconnected(struct ccw_device *cdev) -{ - if (!cdev) - return 0; - return (cdev->private->state == DEV_STATE_DISCONNECTED || - cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID); -} - -static int recovery_check(struct device *dev, void *data) -{ - struct ccw_device *cdev = to_ccwdev(dev); - int *redo = data; - - spin_lock_irq(cdev->ccwlock); - switch (cdev->private->state) { - case DEV_STATE_DISCONNECTED: - CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", - cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - *redo = 1; - break; - case DEV_STATE_DISCONNECTED_SENSE_ID: - *redo = 1; - break; - } - spin_unlock_irq(cdev->ccwlock); - - return 0; -} - -static void recovery_work_func(struct work_struct *unused) -{ - int redo = 0; - - bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check); - if (redo) { - spin_lock_irq(&recovery_lock); - if (!timer_pending(&recovery_timer)) { - if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1) - recovery_phase++; - mod_timer(&recovery_timer, jiffies + - recovery_delay[recovery_phase] * HZ); - } - spin_unlock_irq(&recovery_lock); - } else - CIO_MSG_EVENT(4, "recovery: end\n"); -} - -static DECLARE_WORK(recovery_work, recovery_work_func); - -static void recovery_func(unsigned long data) -{ - /* - * We can't do our recovery in softirq context and it's not - * performance critical, so we schedule it. - */ - schedule_work(&recovery_work); -} - -static void ccw_device_schedule_recovery(void) -{ - unsigned long flags; - - CIO_MSG_EVENT(4, "recovery: schedule\n"); - spin_lock_irqsave(&recovery_lock, flags); - if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { - recovery_phase = 0; - mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ); - } - spin_unlock_irqrestore(&recovery_lock, flags); -} - -static void device_set_disconnected(struct ccw_device *cdev) -{ - if (!cdev) - return; - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - if (cdev->online) - ccw_device_schedule_recovery(); -} - -static int io_subchannel_sch_event(struct subchannel *sch, int slow) -{ - int event, ret, disc; - unsigned long flags; - enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action; - struct ccw_device *cdev; - - spin_lock_irqsave(sch->lock, flags); - cdev = sch_get_cdev(sch); - disc = device_is_disconnected(cdev); - if (disc && slow) { - /* Disconnected devices are evaluated directly only.*/ - spin_unlock_irqrestore(sch->lock, flags); - return 0; - } - /* No interrupt after machine check - kill pending timers. */ - if (cdev) - ccw_device_set_timeout(cdev, 0); - if (!disc && !slow) { - /* Non-disconnected devices are evaluated on the slow path. */ - spin_unlock_irqrestore(sch->lock, flags); - return -EAGAIN; - } - event = io_subchannel_get_status(sch); - CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n", - sch->schid.ssid, sch->schid.sch_no, event, - disc ? "disconnected" : "normal", - slow ? "slow" : "fast"); - /* Analyze subchannel status. */ - action = NONE; - switch (event) { - case CIO_NO_PATH: - if (disc) { - /* Check if paths have become available. */ - action = REPROBE; - break; - } - /* fall through */ - case CIO_GONE: - /* Prevent unwanted effects when opening lock. */ - cio_disable_subchannel(sch); - device_set_disconnected(cdev); - /* Ask driver what to do with device. */ - action = UNREGISTER; - spin_unlock_irqrestore(sch->lock, flags); - ret = io_subchannel_notify(sch, event); - spin_lock_irqsave(sch->lock, flags); - if (ret) - action = NONE; - break; - case CIO_REVALIDATE: - /* Device will be removed, so no notify necessary. */ - if (disc) - /* Reprobe because immediate unregister might block. */ - action = REPROBE; - else - action = UNREGISTER_PROBE; - break; - case CIO_OPER: - if (disc) - /* Get device operational again. */ - action = REPROBE; - break; - } - /* Perform action. */ - ret = 0; - switch (action) { - case UNREGISTER: - case UNREGISTER_PROBE: - /* Unregister device (will use subchannel lock). */ - spin_unlock_irqrestore(sch->lock, flags); - css_sch_device_unregister(sch); - spin_lock_irqsave(sch->lock, flags); - - /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); - break; - case REPROBE: - ccw_device_trigger_reprobe(cdev); - break; - default: - break; - } - spin_unlock_irqrestore(sch->lock, flags); - /* Probe if necessary. */ - if (action == UNREGISTER_PROBE) - ret = css_probe_device(sch->schid); - - return ret; -} - #ifdef CONFIG_CCW_CONSOLE static struct ccw_device console_cdev; static struct ccw_device_private console_private; @@ -1600,16 +1297,14 @@ spinlock_t * cio_get_console_lock(void) return &ccw_console_lock; } -static int ccw_device_console_enable(struct ccw_device *cdev, - struct subchannel *sch) +static int +ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) { int rc; /* Attach subchannel private data. */ sch->private = cio_get_console_priv(); memset(sch->private, 0, sizeof(struct io_subchannel_private)); - io_subchannel_init_fields(sch); - sch->driver = &io_subchannel_driver; /* Initialize the ccw_device structure. */ cdev->dev.parent= &sch->dev; rc = io_subchannel_recog(cdev, sch); @@ -1820,6 +1515,71 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev) return sch->schid; } +static int recovery_check(struct device *dev, void *data) +{ + struct ccw_device *cdev = to_ccwdev(dev); + int *redo = data; + + spin_lock_irq(cdev->ccwlock); + switch (cdev->private->state) { + case DEV_STATE_DISCONNECTED: + CIO_MSG_EVENT(4, "recovery: trigger 0.%x.%04x\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + *redo = 1; + break; + case DEV_STATE_DISCONNECTED_SENSE_ID: + *redo = 1; + break; + } + spin_unlock_irq(cdev->ccwlock); + + return 0; +} + +static void recovery_work_func(struct work_struct *unused) +{ + int redo = 0; + + bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check); + if (redo) { + spin_lock_irq(&recovery_lock); + if (!timer_pending(&recovery_timer)) { + if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1) + recovery_phase++; + mod_timer(&recovery_timer, jiffies + + recovery_delay[recovery_phase] * HZ); + } + spin_unlock_irq(&recovery_lock); + } else + CIO_MSG_EVENT(4, "recovery: end\n"); +} + +static DECLARE_WORK(recovery_work, recovery_work_func); + +static void recovery_func(unsigned long data) +{ + /* + * We can't do our recovery in softirq context and it's not + * performance critical, so we schedule it. + */ + schedule_work(&recovery_work); +} + +void ccw_device_schedule_recovery(void) +{ + unsigned long flags; + + CIO_MSG_EVENT(4, "recovery: schedule\n"); + spin_lock_irqsave(&recovery_lock, flags); + if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { + recovery_phase = 0; + mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ); + } + spin_unlock_irqrestore(&recovery_lock, flags); +} + MODULE_LICENSE("GPL"); EXPORT_SYMBOL(ccw_device_set_online); EXPORT_SYMBOL(ccw_device_set_offline); diff --git a/trunk/drivers/s390/cio/device.h b/trunk/drivers/s390/cio/device.h index 9800a8335a3f..cb08092be39f 100644 --- a/trunk/drivers/s390/cio/device.h +++ b/trunk/drivers/s390/cio/device.h @@ -88,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); +void ccw_device_schedule_recovery(void); + /* Function prototypes for device status and basic sense stuff. */ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *); @@ -116,11 +118,6 @@ int ccw_device_call_handler(struct ccw_device *); int ccw_device_stlck(struct ccw_device *); -/* Helper function for machine check handling. */ -void ccw_device_trigger_reprobe(struct ccw_device *); -void ccw_device_kill_io(struct ccw_device *); -int ccw_device_notify(struct ccw_device *, int); - /* qdio needs this. */ void ccw_device_set_timeout(struct ccw_device *, int); extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); diff --git a/trunk/drivers/s390/cio/device_fsm.c b/trunk/drivers/s390/cio/device_fsm.c index 8b5fe57fb2f3..e268d5a77c12 100644 --- a/trunk/drivers/s390/cio/device_fsm.c +++ b/trunk/drivers/s390/cio/device_fsm.c @@ -2,7 +2,8 @@ * drivers/s390/cio/device_fsm.c * finite state machine for device handling * - * Copyright IBM Corp. 2002,2008 + * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) */ @@ -26,6 +27,65 @@ static int timeout_log_enabled; +int +device_is_online(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return 0; + return (cdev->private->state == DEV_STATE_ONLINE); +} + +int +device_is_disconnected(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return 0; + return (cdev->private->state == DEV_STATE_DISCONNECTED || + cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID); +} + +void +device_set_disconnected(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return; + ccw_device_set_timeout(cdev, 0); + cdev->private->flags.fake_irb = 0; + cdev->private->state = DEV_STATE_DISCONNECTED; + if (cdev->online) + ccw_device_schedule_recovery(); +} + +void device_set_intretry(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return; + cdev->private->flags.intretry = 1; +} + +int device_trigger_verify(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev || !cdev->online) + return -EINVAL; + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + return 0; +} + static int __init ccw_timeout_log_setup(char *unused) { timeout_log_enabled = 1; @@ -39,43 +99,31 @@ static void ccw_timeout_log(struct ccw_device *cdev) struct schib schib; struct subchannel *sch; struct io_subchannel_private *private; - union orb *orb; int cc; sch = to_subchannel(cdev->dev.parent); private = to_io_private(sch); - orb = &private->orb; cc = stsch(sch->schid, &schib); printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " "device information:\n", get_clock()); printk(KERN_WARNING "cio: orb:\n"); print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - orb, sizeof(*orb), 0); + &private->orb, sizeof(private->orb), 0); printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id); printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id); printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); - if (orb->tm.b) { - printk(KERN_WARNING "cio: orb indicates transport mode\n"); - printk(KERN_WARNING "cio: last tcw:\n"); - print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - (void *)(addr_t)orb->tm.tcw, - sizeof(struct tcw), 0); - } else { - printk(KERN_WARNING "cio: orb indicates command mode\n"); - if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw || - (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws) - printk(KERN_WARNING "cio: last channel program " - "(intern):\n"); - else - printk(KERN_WARNING "cio: last channel program:\n"); - - print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - (void *)(addr_t)orb->cmd.cpa, - sizeof(struct ccw1), 0); - } + if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw || + (void *)(addr_t)private->orb.cpa == cdev->private->iccws) + printk(KERN_WARNING "cio: last channel program (intern):\n"); + else + printk(KERN_WARNING "cio: last channel program:\n"); + + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + (void *)(addr_t)private->orb.cpa, + sizeof(struct ccw1), 0); printk(KERN_WARNING "cio: ccw device state: %d\n", cdev->private->state); printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc); @@ -123,6 +171,18 @@ ccw_device_set_timeout(struct ccw_device *cdev, int expires) add_timer(&cdev->private->timer); } +/* Kill any pending timers after machine check. */ +void +device_kill_pending_timer(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return; + ccw_device_set_timeout(cdev, 0); +} + /* * Cancel running i/o. This is called repeatedly since halt/clear are * asynchronous operations. We do one try with cio_cancel, two tries @@ -145,18 +205,15 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) /* Not operational -> done. */ return 0; /* Stage 1: cancel io. */ - if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_HALT_PEND) && - !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) { - if (!scsw_is_tm(&sch->schib.scsw)) { - ret = cio_cancel(sch); - if (ret != -EINVAL) - return ret; - } - /* cancel io unsuccessful or not applicable (transport mode). - * Continue with asynchronous instructions. */ + if (!(sch->schib.scsw.actl & SCSW_ACTL_HALT_PEND) && + !(sch->schib.scsw.actl & SCSW_ACTL_CLEAR_PEND)) { + ret = cio_cancel(sch); + if (ret != -EINVAL) + return ret; + /* cancel io unsuccessful. From now on it is asynchronous. */ cdev->private->iretry = 3; /* 3 halt retries. */ } - if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) { + if (!(sch->schib.scsw.actl & SCSW_ACTL_CLEAR_PEND)) { /* Stage 2: halt io. */ if (cdev->private->iretry) { cdev->private->iretry--; @@ -331,30 +388,34 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err) } } -int ccw_device_notify(struct ccw_device *cdev, int event) -{ - if (!cdev->drv) - return 0; - if (!cdev->online) - return 0; - return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0; -} - static void ccw_device_oper_notify(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; + struct subchannel *sch; int ret; + unsigned long flags; priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; - ret = ccw_device_notify(cdev, CIO_OPER); + spin_lock_irqsave(cdev->ccwlock, flags); + sch = to_subchannel(cdev->dev.parent); + if (sch->driver && sch->driver->notify) { + spin_unlock_irqrestore(cdev->ccwlock, flags); + ret = sch->driver->notify(sch, CIO_OPER); + spin_lock_irqsave(cdev->ccwlock, flags); + } else + ret = 0; if (ret) { /* Reenable channel measurements, if needed. */ + spin_unlock_irqrestore(cdev->ccwlock, flags); cmf_reenable(cdev); + spin_lock_irqsave(cdev->ccwlock, flags); wake_up(&cdev->private->wait_q); - } else + } + spin_unlock_irqrestore(cdev->ccwlock, flags); + if (!ret) /* Driver doesn't want device back. */ ccw_device_do_unreg_rereg(work); } @@ -560,11 +621,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) /* Deliver fake irb to device driver, if needed. */ if (cdev->private->flags.fake_irb) { memset(&cdev->private->irb, 0, sizeof(struct irb)); - cdev->private->irb.scsw.cmd.cc = 1; - cdev->private->irb.scsw.cmd.fctl = SCSW_FCTL_START_FUNC; - cdev->private->irb.scsw.cmd.actl = SCSW_ACTL_START_PEND; - cdev->private->irb.scsw.cmd.stctl = - SCSW_STCTL_STATUS_PEND; + cdev->private->irb.scsw.cc = 1; + cdev->private->irb.scsw.fctl = SCSW_FCTL_START_FUNC; + cdev->private->irb.scsw.actl = SCSW_ACTL_START_PEND; + cdev->private->irb.scsw.stctl = SCSW_STCTL_STATUS_PEND; cdev->private->flags.fake_irb = 0; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, @@ -658,10 +718,13 @@ ccw_device_offline(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) return -ENODEV; - if (scsw_actl(&sch->schib.scsw) != 0) - return -EBUSY; - if (cdev->private->state != DEV_STATE_ONLINE) + if (cdev->private->state != DEV_STATE_ONLINE) { + if (sch->schib.scsw.actl != 0) + return -EBUSY; return -EINVAL; + } + if (sch->schib.scsw.actl != 0) + return -EBUSY; /* Are we doing path grouping? */ if (!cdev->private->options.pgroup) { /* No, set state offline immediately. */ @@ -736,9 +799,9 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) */ stsch(sch->schid, &sch->schib); - if (scsw_actl(&sch->schib.scsw) != 0 || - (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || - (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { + if (sch->schib.scsw.actl != 0 || + (sch->schib.scsw.stctl & SCSW_STCTL_STATUS_PEND) || + (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) { /* * No final status yet or final status not yet delivered * to the device driver. Can't do path verfication now, @@ -760,13 +823,13 @@ static void ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) { struct irb *irb; - int is_cmd; irb = (struct irb *) __LC_IRB; - is_cmd = !scsw_is_tm(&irb->scsw); /* Check for unsolicited interrupt. */ - if (!scsw_is_solicited(&irb->scsw)) { - if (is_cmd && (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && + if ((irb->scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) + && (!irb->scsw.cc)) { + if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && !irb->esw.esw0.erw.cons) { /* Unit check but no sense data. Need basic sense. */ if (ccw_device_do_sense(cdev, irb) != 0) @@ -785,7 +848,7 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) } /* Accumulate status and find out if a basic sense is needed. */ ccw_device_accumulate_irb(cdev, irb); - if (is_cmd && cdev->private->flags.dosense) { + if (cdev->private->flags.dosense) { if (ccw_device_do_sense(cdev, irb) == 0) { cdev->private->state = DEV_STATE_W4SENSE; } @@ -829,9 +892,9 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; /* Check for unsolicited interrupt. */ - if (scsw_stctl(&irb->scsw) == - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { - if (scsw_cc(&irb->scsw) == 1) + if (irb->scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { + if (irb->scsw.cc == 1) /* Basic sense hasn't started. Try again. */ ccw_device_do_sense(cdev, irb); else { @@ -849,8 +912,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) * only deliver the halt/clear interrupt to the device driver as if it * had killed the original request. */ - if (scsw_fctl(&irb->scsw) & - (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { /* Retry Basic Sense if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -924,10 +986,12 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) ERR_PTR(-EIO)); } -void ccw_device_kill_io(struct ccw_device *cdev) +void device_kill_io(struct subchannel *sch) { int ret; + struct ccw_device *cdev; + cdev = sch_get_cdev(sch); ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -957,9 +1021,9 @@ ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event) case DEV_EVENT_INTERRUPT: irb = (struct irb *) __LC_IRB; /* Check for unsolicited interrupt. */ - if ((scsw_stctl(&irb->scsw) == + if ((irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) && - (!scsw_cc(&irb->scsw))) + (!irb->scsw.cc)) /* FIXME: we should restart stlck here, but this * is extremely unlikely ... */ goto out_wakeup; @@ -991,14 +1055,17 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_sense_id_start(cdev); } -void ccw_device_trigger_reprobe(struct ccw_device *cdev) +void +device_trigger_reprobe(struct subchannel *sch) { - struct subchannel *sch; + struct ccw_device *cdev; + cdev = sch_get_cdev(sch); + if (!cdev) + return; if (cdev->private->state != DEV_STATE_DISCONNECTED) return; - sch = to_subchannel(cdev->dev.parent); /* Update some values. */ if (stsch(sch->schid, &sch->schib)) return; @@ -1014,6 +1081,7 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev) sch->schib.pmcw.ena = 0; if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; + sch->schib.pmcw.intparm = (u32)(addr_t)sch; /* We should also udate ssd info, but this has to wait. */ /* Check if this is another device which appeared on the same sch. */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { diff --git a/trunk/drivers/s390/cio/device_id.c b/trunk/drivers/s390/cio/device_id.c index 1bdaa614e34f..cba7020517ed 100644 --- a/trunk/drivers/s390/cio/device_id.c +++ b/trunk/drivers/s390/cio/device_id.c @@ -196,7 +196,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) irb = &cdev->private->irb; /* Check the error cases. */ - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Sense ID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -234,10 +234,10 @@ ccw_device_check_sense_id(struct ccw_device *cdev) irb->ecw[6], irb->ecw[7]); return -EAGAIN; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { u8 lpm; - lpm = to_io_private(sch)->orb.cmd.lpm; + lpm = to_io_private(sch)->orb.lpm; if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x " "on subchannel 0.%x.%04x is " @@ -248,9 +248,9 @@ ccw_device_check_sense_id(struct ccw_device *cdev) } /* Did we get a proper answer ? */ - if (irb->scsw.cmd.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF && + if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF && cdev->private->senseid.reserved == 0xFF) { - if (irb->scsw.cmd.count < sizeof(struct senseid) - 8) + if (irb->scsw.count < sizeof(struct senseid) - 8) cdev->private->flags.esid = 1; return 0; /* Success */ } @@ -260,7 +260,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) "subchannel 0.%x.%04x returns status %02X%02X\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, - irb->scsw.cmd.dstat, irb->scsw.cmd.cstat); + irb->scsw.dstat, irb->scsw.cstat); return -EAGAIN; } @@ -277,9 +277,9 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); irb = (struct irb *) __LC_IRB; /* Retry sense id, if needed. */ - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { - if ((irb->scsw.cmd.cc == 1) || !irb->scsw.cmd.actl) { + if ((irb->scsw.cc == 1) || !irb->scsw.actl) { ret = __ccw_device_sense_id_start(cdev); if (ret && ret != -EBUSY) ccw_device_sense_id_done(cdev, ret); diff --git a/trunk/drivers/s390/cio/device_ops.c b/trunk/drivers/s390/cio/device_ops.c index ee1a28310fbb..f308ad55a6d5 100644 --- a/trunk/drivers/s390/cio/device_ops.c +++ b/trunk/drivers/s390/cio/device_ops.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "cio.h" #include "cio_debug.h" @@ -180,8 +179,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, return -EBUSY; } if (cdev->private->state != DEV_STATE_ONLINE || - ((sch->schib.scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) && - !(sch->schib.scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS)) || + ((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) && + !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) || cdev->private->flags.doverify) return -EBUSY; ret = cio_set_options (sch, flags); @@ -380,7 +379,7 @@ int ccw_device_resume(struct ccw_device *cdev) if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE || - !(sch->schib.scsw.cmd.actl & SCSW_ACTL_SUSPENDED)) + !(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED)) return -EINVAL; return cio_resume(sch); } @@ -405,7 +404,7 @@ ccw_device_call_handler(struct ccw_device *cdev) * - fast notification was requested (primary status) * - unsolicited interrupts */ - stctl = scsw_stctl(&cdev->private->irb.scsw); + stctl = cdev->private->irb.scsw.stctl; ending_status = (stctl & SCSW_STCTL_SEC_STATUS) || (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) || (stctl == SCSW_STCTL_STATUS_PEND); @@ -529,15 +528,14 @@ ccw_device_stlck(struct ccw_device *cdev) cio_disable_subchannel(sch); //FIXME: return code? goto out_unlock; } - cdev->private->irb.scsw.cmd.actl |= SCSW_ACTL_START_PEND; + cdev->private->irb.scsw.actl |= SCSW_ACTL_START_PEND; spin_unlock_irqrestore(sch->lock, flags); - wait_event(cdev->private->wait_q, - cdev->private->irb.scsw.cmd.actl == 0); + wait_event(cdev->private->wait_q, cdev->private->irb.scsw.actl == 0); spin_lock_irqsave(sch->lock, flags); cio_disable_subchannel(sch); //FIXME: return code? - if ((cdev->private->irb.scsw.cmd.dstat != + if ((cdev->private->irb.scsw.dstat != (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) || - (cdev->private->irb.scsw.cmd.cstat != 0)) + (cdev->private->irb.scsw.cstat != 0)) ret = -EIO; /* Clear irb. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); @@ -570,122 +568,6 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) } EXPORT_SYMBOL(ccw_device_get_id); -/** - * ccw_device_tm_start_key - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * @key: storage key to use for storage access - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key) -{ - struct subchannel *sch; - int rc; - - sch = to_subchannel(cdev->dev.parent); - if (cdev->private->state != DEV_STATE_ONLINE) - return -EIO; - /* Adjust requested path mask to excluded varied off paths. */ - if (lpm) { - lpm &= sch->opm; - if (lpm == 0) - return -EACCES; - } - rc = cio_tm_start_key(sch, tcw, lpm, key); - if (rc == 0) - cdev->private->intparm = intparm; - return rc; -} -EXPORT_SYMBOL(ccw_device_tm_start_key); - -/** - * ccw_device_tm_start_timeout_key - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * @key: storage key to use for storage access - * @expires: time span in jiffies after which to abort request - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key, - int expires) -{ - int ret; - - ccw_device_set_timeout(cdev, expires); - ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key); - if (ret != 0) - ccw_device_set_timeout(cdev, 0); - return ret; -} -EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); - -/** - * ccw_device_tm_start - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm) -{ - return ccw_device_tm_start_key(cdev, tcw, intparm, lpm, - PAGE_DEFAULT_KEY); -} -EXPORT_SYMBOL(ccw_device_tm_start); - -/** - * ccw_device_tm_start_timeout - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * @expires: time span in jiffies after which to abort request - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, int expires) -{ - return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, - PAGE_DEFAULT_KEY, expires); -} -EXPORT_SYMBOL(ccw_device_tm_start_timeout); - -/** - * ccw_device_tm_intrg - perform interrogate function - * @cdev: ccw device on which to perform the interrogate function - * - * Perform an interrogate function on the given ccw device. Return zero on - * success, non-zero otherwise. - */ -int ccw_device_tm_intrg(struct ccw_device *cdev) -{ - struct subchannel *sch = to_subchannel(cdev->dev.parent); - - if (cdev->private->state != DEV_STATE_ONLINE) - return -EIO; - if (!scsw_is_tm(&sch->schib.scsw) || - !(scsw_actl(&sch->schib.scsw) | SCSW_ACTL_START_PEND)) - return -EINVAL; - return cio_tm_intrg(sch); -} -EXPORT_SYMBOL(ccw_device_tm_intrg); - // FIXME: these have to go: int diff --git a/trunk/drivers/s390/cio/device_pgid.c b/trunk/drivers/s390/cio/device_pgid.c index 86bc94eb607f..5cf7be008e98 100644 --- a/trunk/drivers/s390/cio/device_pgid.c +++ b/trunk/drivers/s390/cio/device_pgid.c @@ -28,13 +28,13 @@ * Helper function called from interrupt context to decide whether an * operation should be tried again. */ -static int __ccw_device_should_retry(union scsw *scsw) +static int __ccw_device_should_retry(struct scsw *scsw) { /* CC is only valid if start function bit is set. */ - if ((scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && scsw->cmd.cc == 1) + if ((scsw->fctl & SCSW_FCTL_START_FUNC) && scsw->cc == 1) return 1; /* No more activity. For sense and set PGID we stubbornly try again. */ - if (!scsw->cmd.actl) + if (!scsw->actl) return 1; return 0; } @@ -125,7 +125,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Sense PGID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -155,10 +155,10 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) irb->ecw[6], irb->ecw[7]); return -EAGAIN; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { u8 lpm; - lpm = to_io_private(sch)->orb.cmd.lpm; + lpm = to_io_private(sch)->orb.lpm; CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, @@ -188,7 +188,7 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (__ccw_device_should_retry(&irb->scsw)) { ret = __ccw_device_sense_pgid_start(cdev); @@ -331,7 +331,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Set PGID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -355,7 +355,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev) irb->ecw[6], irb->ecw[7]); return -EAGAIN; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, @@ -376,7 +376,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry NOP if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -384,7 +384,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) } return -ETIME; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, @@ -438,7 +438,7 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (__ccw_device_should_retry(&irb->scsw)) __ccw_device_verify_start(cdev); @@ -544,7 +544,7 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (__ccw_device_should_retry(&irb->scsw)) __ccw_device_disband_start(cdev); diff --git a/trunk/drivers/s390/cio/device_status.c b/trunk/drivers/s390/cio/device_status.c index 1b03c5423be2..4a38993000f2 100644 --- a/trunk/drivers/s390/cio/device_status.c +++ b/trunk/drivers/s390/cio/device_status.c @@ -29,11 +29,9 @@ static void ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) { - char dbf_text[15]; - - if (!scsw_is_valid_cstat(&irb->scsw) || - !(scsw_cstat(&irb->scsw) & (SCHN_STAT_CHN_DATA_CHK | - SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK))) + if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK | + SCHN_STAT_CHN_CTRL_CHK | + SCHN_STAT_INTF_CTRL_CHK))) return; CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check " "received" @@ -41,10 +39,15 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) ": %02X sch_stat : %02X\n", cdev->private->dev_id.devno, cdev->private->schid.ssid, cdev->private->schid.sch_no, - scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw)); - sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no); - CIO_TRACE_EVENT(0, dbf_text); - CIO_HEX_EVENT(0, irb, sizeof(struct irb)); + irb->scsw.dstat, irb->scsw.cstat); + + if (irb->scsw.cc != 3) { + char dbf_text[15]; + + sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no); + CIO_TRACE_EVENT(0, dbf_text); + CIO_HEX_EVENT(0, irb, sizeof (struct irb)); + } } /* @@ -78,12 +81,12 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) * are condition that have to be met for the extended control * bit to have meaning. Sick. */ - cdev->private->irb.scsw.cmd.ectl = 0; - if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) && - !(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS)) - cdev->private->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl; + cdev->private->irb.scsw.ectl = 0; + if ((irb->scsw.stctl & SCSW_STCTL_ALERT_STATUS) && + !(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS)) + cdev->private->irb.scsw.ectl = irb->scsw.ectl; /* Check if extended control word is valid. */ - if (!cdev->private->irb.scsw.cmd.ectl) + if (!cdev->private->irb.scsw.ectl) return; /* Copy concurrent sense / model dependent information. */ memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw)); @@ -95,12 +98,11 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) static int ccw_device_accumulate_esw_valid(struct irb *irb) { - if (!irb->scsw.cmd.eswf && - (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND)) + if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) return 0; - if (irb->scsw.cmd.stctl == - (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) && - !(irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED)) + if (irb->scsw.stctl == + (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) && + !(irb->scsw.actl & SCSW_ACTL_SUSPENDED)) return 0; return 1; } @@ -123,7 +125,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum; /* Copy subchannel logout information if esw is of format 0. */ - if (irb->scsw.cmd.eswf) { + if (irb->scsw.eswf) { cdev_sublog = &cdev_irb->esw.esw0.sublog; sublog = &irb->esw.esw0.sublog; /* Copy extended status flags. */ @@ -132,7 +134,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) * Copy fields that have a meaning for channel data check * channel control check and interface control check. */ - if (irb->scsw.cmd.cstat & (SCHN_STAT_CHN_DATA_CHK | + if (irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK)) { /* Copy ancillary report bit. */ @@ -153,7 +155,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) /* Copy i/o-error alert. */ cdev_sublog->ioerr = sublog->ioerr; /* Copy channel path timeout bit. */ - if (irb->scsw.cmd.cstat & SCHN_STAT_INTF_CTRL_CHK) + if (irb->scsw.cstat & SCHN_STAT_INTF_CTRL_CHK) cdev_irb->esw.esw0.erw.cpt = irb->esw.esw0.erw.cpt; /* Copy failing storage address validity flag. */ cdev_irb->esw.esw0.erw.fsavf = irb->esw.esw0.erw.fsavf; @@ -198,24 +200,24 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * If not, the remaining bit have no meaning and we must ignore them. * The esw is not meaningful as well... */ - if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) + if (!(irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) return; /* Check for channel checks and interface control checks. */ ccw_device_msg_control_check(cdev, irb); /* Check for path not operational. */ - if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw)) + if (irb->scsw.pno && irb->scsw.fctl != 0 && + (!(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS) || + (irb->scsw.actl & SCSW_ACTL_SUSPENDED))) ccw_device_path_notoper(cdev); - /* No irb accumulation for transport mode irbs. */ - if (scsw_is_tm(&irb->scsw)) { - memcpy(&cdev->private->irb, irb, sizeof(struct irb)); - return; - } + /* * Don't accumulate unsolicited interrupts. */ - if (!scsw_is_solicited(&irb->scsw)) + if ((irb->scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) && + (!irb->scsw.cc)) return; cdev_irb = &cdev->private->irb; @@ -225,63 +227,62 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * status at the subchannel has been cleared and we must not pass * intermediate accumulated status to the device driver. */ - if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) + if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) memset(&cdev->private->irb, 0, sizeof(struct irb)); /* Copy bits which are valid only for the start function. */ - if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) { + if (irb->scsw.fctl & SCSW_FCTL_START_FUNC) { /* Copy key. */ - cdev_irb->scsw.cmd.key = irb->scsw.cmd.key; + cdev_irb->scsw.key = irb->scsw.key; /* Copy suspend control bit. */ - cdev_irb->scsw.cmd.sctl = irb->scsw.cmd.sctl; + cdev_irb->scsw.sctl = irb->scsw.sctl; /* Accumulate deferred condition code. */ - cdev_irb->scsw.cmd.cc |= irb->scsw.cmd.cc; + cdev_irb->scsw.cc |= irb->scsw.cc; /* Copy ccw format bit. */ - cdev_irb->scsw.cmd.fmt = irb->scsw.cmd.fmt; + cdev_irb->scsw.fmt = irb->scsw.fmt; /* Copy prefetch bit. */ - cdev_irb->scsw.cmd.pfch = irb->scsw.cmd.pfch; + cdev_irb->scsw.pfch = irb->scsw.pfch; /* Copy initial-status-interruption-control. */ - cdev_irb->scsw.cmd.isic = irb->scsw.cmd.isic; + cdev_irb->scsw.isic = irb->scsw.isic; /* Copy address limit checking control. */ - cdev_irb->scsw.cmd.alcc = irb->scsw.cmd.alcc; + cdev_irb->scsw.alcc = irb->scsw.alcc; /* Copy suppress suspend bit. */ - cdev_irb->scsw.cmd.ssi = irb->scsw.cmd.ssi; + cdev_irb->scsw.ssi = irb->scsw.ssi; } /* Take care of the extended control bit and extended control word. */ ccw_device_accumulate_ecw(cdev, irb); /* Accumulate function control. */ - cdev_irb->scsw.cmd.fctl |= irb->scsw.cmd.fctl; + cdev_irb->scsw.fctl |= irb->scsw.fctl; /* Copy activity control. */ - cdev_irb->scsw.cmd.actl = irb->scsw.cmd.actl; + cdev_irb->scsw.actl= irb->scsw.actl; /* Accumulate status control. */ - cdev_irb->scsw.cmd.stctl |= irb->scsw.cmd.stctl; + cdev_irb->scsw.stctl |= irb->scsw.stctl; /* * Copy ccw address if it is valid. This is a bit simplified * but should be close enough for all practical purposes. */ - if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) || - ((irb->scsw.cmd.stctl == + if ((irb->scsw.stctl & SCSW_STCTL_PRIM_STATUS) || + ((irb->scsw.stctl == (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND)) && - (irb->scsw.cmd.actl & SCSW_ACTL_DEVACT) && - (irb->scsw.cmd.actl & SCSW_ACTL_SCHACT)) || - (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED)) - cdev_irb->scsw.cmd.cpa = irb->scsw.cmd.cpa; + (irb->scsw.actl & SCSW_ACTL_DEVACT) && + (irb->scsw.actl & SCSW_ACTL_SCHACT)) || + (irb->scsw.actl & SCSW_ACTL_SUSPENDED)) + cdev_irb->scsw.cpa = irb->scsw.cpa; /* Accumulate device status, but not the device busy flag. */ - cdev_irb->scsw.cmd.dstat &= ~DEV_STAT_BUSY; + cdev_irb->scsw.dstat &= ~DEV_STAT_BUSY; /* dstat is not always valid. */ - if (irb->scsw.cmd.stctl & + if (irb->scsw.stctl & (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_SEC_STATUS | SCSW_STCTL_INTER_STATUS | SCSW_STCTL_ALERT_STATUS)) - cdev_irb->scsw.cmd.dstat |= irb->scsw.cmd.dstat; + cdev_irb->scsw.dstat |= irb->scsw.dstat; /* Accumulate subchannel status. */ - cdev_irb->scsw.cmd.cstat |= irb->scsw.cmd.cstat; + cdev_irb->scsw.cstat |= irb->scsw.cstat; /* Copy residual count if it is valid. */ - if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) && - (irb->scsw.cmd.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN)) - == 0) - cdev_irb->scsw.cmd.count = irb->scsw.cmd.count; + if ((irb->scsw.stctl & SCSW_STCTL_PRIM_STATUS) && + (irb->scsw.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN)) == 0) + cdev_irb->scsw.count = irb->scsw.count; /* Take care of bits in the extended status word. */ ccw_device_accumulate_esw(cdev, irb); @@ -298,7 +299,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * sense facility available/supported when enabling the * concurrent sense facility. */ - if ((cdev_irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && + if ((cdev_irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && !(cdev_irb->esw.esw0.erw.cons)) cdev->private->flags.dosense = 1; } @@ -316,7 +317,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) sch = to_subchannel(cdev->dev.parent); /* A sense is required, can we do it now ? */ - if (scsw_actl(&irb->scsw) & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) + if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) /* * we received an Unit Check but we have no final * status yet, therefore we must delay the SENSE @@ -354,18 +355,20 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb) * If not, the remaining bit have no meaning and we must ignore them. * The esw is not meaningful as well... */ - if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) + if (!(irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) return; /* Check for channel checks and interface control checks. */ ccw_device_msg_control_check(cdev, irb); /* Check for path not operational. */ - if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw)) + if (irb->scsw.pno && irb->scsw.fctl != 0 && + (!(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS) || + (irb->scsw.actl & SCSW_ACTL_SUSPENDED))) ccw_device_path_notoper(cdev); - if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && - (irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) { + if (!(irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && + (irb->scsw.dstat & DEV_STAT_CHN_END)) { cdev->private->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; } @@ -383,11 +386,11 @@ int ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb) { ccw_device_accumulate_irb(cdev, irb); - if ((irb->scsw.cmd.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) + if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) return -EBUSY; /* Check for basic sense. */ if (cdev->private->flags.dosense && - !(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) { + !(irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) { cdev->private->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; return 0; diff --git a/trunk/drivers/s390/cio/fcx.c b/trunk/drivers/s390/cio/fcx.c deleted file mode 100644 index 61677dfbdc9b..000000000000 --- a/trunk/drivers/s390/cio/fcx.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Functions for assembling fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include -#include -#include -#include -#include "cio.h" - -/** - * tcw_get_intrg - return pointer to associated interrogate tcw - * @tcw: pointer to the original tcw - * - * Return a pointer to the interrogate tcw associated with the specified tcw - * or %NULL if there is no associated interrogate tcw. - */ -struct tcw *tcw_get_intrg(struct tcw *tcw) -{ - return (struct tcw *) ((addr_t) tcw->intrg); -} -EXPORT_SYMBOL(tcw_get_intrg); - -/** - * tcw_get_data - return pointer to input/output data associated with tcw - * @tcw: pointer to the tcw - * - * Return the input or output data address specified in the tcw depending - * on whether the r-bit or the w-bit is set. If neither bit is set, return - * %NULL. - */ -void *tcw_get_data(struct tcw *tcw) -{ - if (tcw->r) - return (void *) ((addr_t) tcw->input); - if (tcw->w) - return (void *) ((addr_t) tcw->output); - return NULL; -} -EXPORT_SYMBOL(tcw_get_data); - -/** - * tcw_get_tccb - return pointer to tccb associated with tcw - * @tcw: pointer to the tcw - * - * Return pointer to the tccb associated with this tcw. - */ -struct tccb *tcw_get_tccb(struct tcw *tcw) -{ - return (struct tccb *) ((addr_t) tcw->tccb); -} -EXPORT_SYMBOL(tcw_get_tccb); - -/** - * tcw_get_tsb - return pointer to tsb associated with tcw - * @tcw: pointer to the tcw - * - * Return pointer to the tsb associated with this tcw. - */ -struct tsb *tcw_get_tsb(struct tcw *tcw) -{ - return (struct tsb *) ((addr_t) tcw->tsb); -} -EXPORT_SYMBOL(tcw_get_tsb); - -/** - * tcw_init - initialize tcw data structure - * @tcw: pointer to the tcw to be initialized - * @r: initial value of the r-bit - * @w: initial value of the w-bit - * - * Initialize all fields of the specified tcw data structure with zero and - * fill in the format, flags, r and w fields. - */ -void tcw_init(struct tcw *tcw, int r, int w) -{ - memset(tcw, 0, sizeof(struct tcw)); - tcw->format = TCW_FORMAT_DEFAULT; - tcw->flags = TCW_FLAGS_TIDAW_FORMAT(TCW_TIDAW_FORMAT_DEFAULT); - if (r) - tcw->r = 1; - if (w) - tcw->w = 1; -} -EXPORT_SYMBOL(tcw_init); - -static inline size_t tca_size(struct tccb *tccb) -{ - return tccb->tcah.tcal - 12; -} - -static u32 calc_dcw_count(struct tccb *tccb) -{ - int offset; - struct dcw *dcw; - u32 count = 0; - size_t size; - - size = tca_size(tccb); - for (offset = 0; offset < size;) { - dcw = (struct dcw *) &tccb->tca[offset]; - count += dcw->count; - if (!(dcw->flags & DCW_FLAGS_CC)) - break; - offset += sizeof(struct dcw) + ALIGN((int) dcw->cd_count, 4); - } - return count; -} - -static u32 calc_cbc_size(struct tidaw *tidaw, int num) -{ - int i; - u32 cbc_data; - u32 cbc_count = 0; - u64 data_count = 0; - - for (i = 0; i < num; i++) { - if (tidaw[i].flags & TIDAW_FLAGS_LAST) - break; - /* TODO: find out if padding applies to total of data - * transferred or data transferred by this tidaw. Assumption: - * applies to total. */ - data_count += tidaw[i].count; - if (tidaw[i].flags & TIDAW_FLAGS_INSERT_CBC) { - cbc_data = 4 + ALIGN(data_count, 4) - data_count; - cbc_count += cbc_data; - data_count += cbc_data; - } - } - return cbc_count; -} - -/** - * tcw_finalize - finalize tcw length fields and tidaw list - * @tcw: pointer to the tcw - * @num_tidaws: the number of tidaws used to address input/output data or zero - * if no tida is used - * - * Calculate the input-/output-count and tccbl field in the tcw, add a - * tcat the tccb and terminate the data tidaw list if used. - * - * Note: in case input- or output-tida is used, the tidaw-list must be stored - * in contiguous storage (no ttic). The tcal field in the tccb must be - * up-to-date. - */ -void tcw_finalize(struct tcw *tcw, int num_tidaws) -{ - struct tidaw *tidaw; - struct tccb *tccb; - struct tccb_tcat *tcat; - u32 count; - - /* Terminate tidaw list. */ - tidaw = tcw_get_data(tcw); - if (num_tidaws > 0) - tidaw[num_tidaws - 1].flags |= TIDAW_FLAGS_LAST; - /* Add tcat to tccb. */ - tccb = tcw_get_tccb(tcw); - tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)]; - memset(tcat, 0, sizeof(tcat)); - /* Calculate tcw input/output count and tcat transport count. */ - count = calc_dcw_count(tccb); - if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA)) - count += calc_cbc_size(tidaw, num_tidaws); - if (tcw->r) - tcw->input_count = count; - else if (tcw->w) - tcw->output_count = count; - tcat->count = ALIGN(count, 4) + 4; - /* Calculate tccbl. */ - tcw->tccbl = (sizeof(struct tccb) + tca_size(tccb) + - sizeof(struct tccb_tcat) - 20) >> 2; -} -EXPORT_SYMBOL(tcw_finalize); - -/** - * tcw_set_intrg - set the interrogate tcw address of a tcw - * @tcw: the tcw address - * @intrg_tcw: the address of the interrogate tcw - * - * Set the address of the interrogate tcw in the specified tcw. - */ -void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw) -{ - tcw->intrg = (u32) ((addr_t) intrg_tcw); -} -EXPORT_SYMBOL(tcw_set_intrg); - -/** - * tcw_set_data - set data address and tida flag of a tcw - * @tcw: the tcw address - * @data: the data address - * @use_tidal: zero of the data address specifies a contiguous block of data, - * non-zero if it specifies a list if tidaws. - * - * Set the input/output data address of a tcw (depending on the value of the - * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag - * is set as well. - */ -void tcw_set_data(struct tcw *tcw, void *data, int use_tidal) -{ - if (tcw->r) { - tcw->input = (u64) ((addr_t) data); - if (use_tidal) - tcw->flags |= TCW_FLAGS_INPUT_TIDA; - } else if (tcw->w) { - tcw->output = (u64) ((addr_t) data); - if (use_tidal) - tcw->flags |= TCW_FLAGS_OUTPUT_TIDA; - } -} -EXPORT_SYMBOL(tcw_set_data); - -/** - * tcw_set_tccb - set tccb address of a tcw - * @tcw: the tcw address - * @tccb: the tccb address - * - * Set the address of the tccb in the specified tcw. - */ -void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb) -{ - tcw->tccb = (u64) ((addr_t) tccb); -} -EXPORT_SYMBOL(tcw_set_tccb); - -/** - * tcw_set_tsb - set tsb address of a tcw - * @tcw: the tcw address - * @tsb: the tsb address - * - * Set the address of the tsb in the specified tcw. - */ -void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb) -{ - tcw->tsb = (u64) ((addr_t) tsb); -} -EXPORT_SYMBOL(tcw_set_tsb); - -/** - * tccb_init - initialize tccb - * @tccb: the tccb address - * @size: the maximum size of the tccb - * @sac: the service-action-code to be user - * - * Initialize the header of the specified tccb by resetting all values to zero - * and filling in defaults for format, sac and initial tcal fields. - */ -void tccb_init(struct tccb *tccb, size_t size, u32 sac) -{ - memset(tccb, 0, size); - tccb->tcah.format = TCCB_FORMAT_DEFAULT; - tccb->tcah.sac = sac; - tccb->tcah.tcal = 12; -} -EXPORT_SYMBOL(tccb_init); - -/** - * tsb_init - initialize tsb - * @tsb: the tsb address - * - * Initialize the specified tsb by resetting all values to zero. - */ -void tsb_init(struct tsb *tsb) -{ - memset(tsb, 0, sizeof(tsb)); -} -EXPORT_SYMBOL(tsb_init); - -/** - * tccb_add_dcw - add a dcw to the tccb - * @tccb: the tccb address - * @tccb_size: the maximum tccb size - * @cmd: the dcw command - * @flags: flags for the dcw - * @cd: pointer to control data for this dcw or NULL if none is required - * @cd_count: number of control data bytes for this dcw - * @count: number of data bytes for this dcw - * - * Add a new dcw to the specified tccb by writing the dcw information specified - * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return - * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw - * would exceed the available space as defined by @tccb_size. - * - * Note: the tcal field of the tccb header will be updates to reflect added - * content. - */ -struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags, - void *cd, u8 cd_count, u32 count) -{ - struct dcw *dcw; - int size; - int tca_offset; - - /* Check for space. */ - tca_offset = tca_size(tccb); - size = ALIGN(sizeof(struct dcw) + cd_count, 4); - if (sizeof(struct tccb_tcah) + tca_offset + size + - sizeof(struct tccb_tcat) > tccb_size) - return ERR_PTR(-ENOSPC); - /* Add dcw to tca. */ - dcw = (struct dcw *) &tccb->tca[tca_offset]; - memset(dcw, 0, size); - dcw->cmd = cmd; - dcw->flags = flags; - dcw->count = count; - dcw->cd_count = cd_count; - if (cd) - memcpy(&dcw->cd[0], cd, cd_count); - tccb->tcah.tcal += size; - return dcw; -} -EXPORT_SYMBOL(tccb_add_dcw); - -/** - * tcw_add_tidaw - add a tidaw to a tcw - * @tcw: the tcw address - * @num_tidaws: the current number of tidaws - * @flags: flags for the new tidaw - * @addr: address value for the new tidaw - * @count: count value for the new tidaw - * - * Add a new tidaw to the input/output data tidaw-list of the specified tcw - * (depending on the value of the r-flag and w-flag) and return a pointer to - * the new tidaw. - * - * Note: the tidaw-list is assumed to be contiguous with no ttics. The caller - * must ensure that there is enough space for the new tidaw. The last-tidaw - * flag for the last tidaw in the list will be set by tcw_finalize. - */ -struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags, - void *addr, u32 count) -{ - struct tidaw *tidaw; - - /* Add tidaw to tidaw-list. */ - tidaw = ((struct tidaw *) tcw_get_data(tcw)) + num_tidaws; - memset(tidaw, 0, sizeof(struct tidaw)); - tidaw->flags = flags; - tidaw->count = count; - tidaw->addr = (u64) ((addr_t) addr); - return tidaw; -} -EXPORT_SYMBOL(tcw_add_tidaw); diff --git a/trunk/drivers/s390/cio/idset.h b/trunk/drivers/s390/cio/idset.h index 528065cb5021..144466ab8c15 100644 --- a/trunk/drivers/s390/cio/idset.h +++ b/trunk/drivers/s390/cio/idset.h @@ -8,7 +8,7 @@ #ifndef S390_IDSET_H #define S390_IDSET_H S390_IDSET_H -#include +#include "schid.h" struct idset; diff --git a/trunk/drivers/s390/cio/io_sch.h b/trunk/drivers/s390/cio/io_sch.h index 3f8f1cf69c76..8c613160bfce 100644 --- a/trunk/drivers/s390/cio/io_sch.h +++ b/trunk/drivers/s390/cio/io_sch.h @@ -1,12 +1,12 @@ #ifndef S390_IO_SCH_H #define S390_IO_SCH_H -#include +#include "schid.h" /* - * command-mode operation request block + * operation request block */ -struct cmd_orb { +struct orb { u32 intparm; /* interruption parameter */ u32 key : 4; /* flags, like key, suspend control, etc. */ u32 spnd : 1; /* suspend control */ @@ -28,36 +28,8 @@ struct cmd_orb { u32 cpa; /* channel program address */ } __attribute__ ((packed, aligned(4))); -/* - * transport-mode operation request block - */ -struct tm_orb { - u32 intparm; - u32 key:4; - u32 :9; - u32 b:1; - u32 :2; - u32 lpm:8; - u32 :7; - u32 x:1; - u32 tcw; - u32 prio:8; - u32 :8; - u32 rsvpgm:8; - u32 :8; - u32 :32; - u32 :32; - u32 :32; - u32 :32; -} __attribute__ ((packed, aligned(4))); - -union orb { - struct cmd_orb cmd; - struct tm_orb tm; -} __attribute__ ((packed, aligned(4))); - struct io_subchannel_private { - union orb orb; /* operation request block */ + struct orb orb; /* operation request block */ struct ccw1 sense_ccw; /* static ccw for sense command */ } __attribute__ ((aligned(8))); @@ -123,18 +95,16 @@ struct ccw_device_private { void *cmb_wait; /* deferred cmb enable/disable */ }; -static inline int ssch(struct subchannel_id schid, volatile union orb *addr) +static inline int ssch(struct subchannel_id schid, volatile struct orb *addr) { register struct subchannel_id reg1 asm("1") = schid; - int ccode = -EIO; + int ccode; asm volatile( " ssch 0(%2)\n" - "0: ipm %0\n" - " srl %0,28\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); return ccode; } diff --git a/trunk/drivers/s390/cio/ioasm.h b/trunk/drivers/s390/cio/ioasm.h index 9fa2ac13ac85..652ea3625f9d 100644 --- a/trunk/drivers/s390/cio/ioasm.h +++ b/trunk/drivers/s390/cio/ioasm.h @@ -2,7 +2,7 @@ #define S390_CIO_IOASM_H #include -#include +#include "schid.h" /* * TPI info structure diff --git a/trunk/drivers/s390/cio/isc.c b/trunk/drivers/s390/cio/isc.c deleted file mode 100644 index c592087be0f1..000000000000 --- a/trunk/drivers/s390/cio/isc.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Functions for registration of I/O interruption subclasses on s390. - * - * Copyright IBM Corp. 2008 - * Authors: Sebastian Ott - */ - -#include -#include -#include - -static unsigned int isc_refs[MAX_ISC + 1]; -static DEFINE_SPINLOCK(isc_ref_lock); - - -/** - * isc_register - register an I/O interruption subclass. - * @isc: I/O interruption subclass to register - * - * The number of users for @isc is increased. If this is the first user to - * register @isc, the corresponding I/O interruption subclass mask is enabled. - * - * Context: - * This function must not be called in interrupt context. - */ -void isc_register(unsigned int isc) -{ - if (isc > MAX_ISC) { - WARN_ON(1); - return; - } - - spin_lock(&isc_ref_lock); - if (isc_refs[isc] == 0) - ctl_set_bit(6, 31 - isc); - isc_refs[isc]++; - spin_unlock(&isc_ref_lock); -} -EXPORT_SYMBOL_GPL(isc_register); - -/** - * isc_unregister - unregister an I/O interruption subclass. - * @isc: I/O interruption subclass to unregister - * - * The number of users for @isc is decreased. If this is the last user to - * unregister @isc, the corresponding I/O interruption subclass mask is - * disabled. - * Note: This function must not be called if isc_register() hasn't been called - * before by the driver for @isc. - * - * Context: - * This function must not be called in interrupt context. - */ -void isc_unregister(unsigned int isc) -{ - spin_lock(&isc_ref_lock); - /* check for misuse */ - if (isc > MAX_ISC || isc_refs[isc] == 0) { - WARN_ON(1); - goto out_unlock; - } - if (isc_refs[isc] == 1) - ctl_clear_bit(6, 31 - isc); - isc_refs[isc]--; -out_unlock: - spin_unlock(&isc_ref_lock); -} -EXPORT_SYMBOL_GPL(isc_unregister); diff --git a/trunk/drivers/s390/cio/itcw.c b/trunk/drivers/s390/cio/itcw.c deleted file mode 100644 index 17da9ab932ed..000000000000 --- a/trunk/drivers/s390/cio/itcw.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Functions for incremental construction of fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * struct itcw - incremental tcw helper data type - * - * This structure serves as a handle for the incremental construction of a - * tcw and associated tccb, tsb, data tidaw-list plus an optional interrogate - * tcw and associated data. The data structures are contained inside a single - * contiguous buffer provided by the user. - * - * The itcw construction functions take care of overall data integrity: - * - reset unused fields to zero - * - fill in required pointers - * - ensure required alignment for data structures - * - prevent data structures to cross 4k-byte boundary where required - * - calculate tccb-related length fields - * - optionally provide ready-made interrogate tcw and associated structures - * - * Restrictions apply to the itcws created with these construction functions: - * - tida only supported for data address, not for tccb - * - only contiguous tidaw-lists (no ttic) - * - total number of bytes required per itcw may not exceed 4k bytes - * - either read or write operation (may not work with r=0 and w=0) - * - * Example: - * struct itcw *itcw; - * void *buffer; - * size_t size; - * - * size = itcw_calc_size(1, 2, 0); - * buffer = kmalloc(size, GFP_DMA); - * if (!buffer) - * return -ENOMEM; - * itcw = itcw_init(buffer, size, ITCW_OP_READ, 1, 2, 0); - * if (IS_ERR(itcw)) - * return PTR_ER(itcw); - * itcw_add_dcw(itcw, 0x2, 0, NULL, 0, 72); - * itcw_add_tidaw(itcw, 0, 0x30000, 20); - * itcw_add_tidaw(itcw, 0, 0x40000, 52); - * itcw_finalize(itcw); - * - */ -struct itcw { - struct tcw *tcw; - struct tcw *intrg_tcw; - int num_tidaws; - int max_tidaws; - int intrg_num_tidaws; - int intrg_max_tidaws; -}; - -/** - * itcw_get_tcw - return pointer to tcw associated with the itcw - * @itcw: address of the itcw - * - * Return pointer to the tcw associated with the itcw. - */ -struct tcw *itcw_get_tcw(struct itcw *itcw) -{ - return itcw->tcw; -} -EXPORT_SYMBOL(itcw_get_tcw); - -/** - * itcw_calc_size - return the size of an itcw with the given parameters - * @intrg: if non-zero, add an interrogate tcw - * @max_tidaws: maximum number of tidaws to be used for data addressing or zero - * if no tida is to be used. - * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing - * by the interrogate tcw, if specified - * - * Calculate and return the number of bytes required to hold an itcw with the - * given parameters and assuming tccbs with maximum size. - * - * Note that the resulting size also contains bytes needed for alignment - * padding as well as padding to ensure that data structures don't cross a - * 4k-boundary where required. - */ -size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws) -{ - size_t len; - - /* Main data. */ - len = sizeof(struct itcw); - len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE + - /* TSB */ sizeof(struct tsb) + - /* TIDAL */ max_tidaws * sizeof(struct tidaw); - /* Interrogate data. */ - if (intrg) { - len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE + - /* TSB */ sizeof(struct tsb) + - /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw); - } - /* Maximum required alignment padding. */ - len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7; - /* Maximum padding for structures that may not cross 4k boundary. */ - if ((max_tidaws > 0) || (intrg_max_tidaws > 0)) - len += max(max_tidaws, intrg_max_tidaws) * - sizeof(struct tidaw) - 1; - return len; -} -EXPORT_SYMBOL(itcw_calc_size); - -#define CROSS4K(x, l) (((x) & ~4095) != ((x + l) & ~4095)) - -static inline void *fit_chunk(addr_t *start, addr_t end, size_t len, - int align, int check_4k) -{ - addr_t addr; - - addr = ALIGN(*start, align); - if (check_4k && CROSS4K(addr, len)) { - addr = ALIGN(addr, 4096); - addr = ALIGN(addr, align); - } - if (addr + len > end) - return ERR_PTR(-ENOSPC); - *start = addr + len; - return (void *) addr; -} - -/** - * itcw_init - initialize incremental tcw data structure - * @buffer: address of buffer to use for data structures - * @size: number of bytes in buffer - * @op: %ITCW_OP_READ for a read operation tcw, %ITCW_OP_WRITE for a write - * operation tcw - * @intrg: if non-zero, add and initialize an interrogate tcw - * @max_tidaws: maximum number of tidaws to be used for data addressing or zero - * if no tida is to be used. - * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing - * by the interrogate tcw, if specified - * - * Prepare the specified buffer to be used as an incremental tcw, i.e. a - * helper data structure that can be used to construct a valid tcw by - * successive calls to other helper functions. Note: the buffer needs to be - * located below the 2G address limit. The resulting tcw has the following - * restrictions: - * - no tccb tidal - * - input/output tidal is contiguous (no ttic) - * - total data should not exceed 4k - * - tcw specifies either read or write operation - * - * On success, return pointer to the resulting incremental tcw data structure, - * ERR_PTR otherwise. - */ -struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, - int max_tidaws, int intrg_max_tidaws) -{ - struct itcw *itcw; - void *chunk; - addr_t start; - addr_t end; - - /* Check for 2G limit. */ - start = (addr_t) buffer; - end = start + size; - if (end > (1 << 31)) - return ERR_PTR(-EINVAL); - memset(buffer, 0, size); - /* ITCW. */ - chunk = fit_chunk(&start, end, sizeof(struct itcw), 1, 0); - if (IS_ERR(chunk)) - return chunk; - itcw = chunk; - itcw->max_tidaws = max_tidaws; - itcw->intrg_max_tidaws = intrg_max_tidaws; - /* Main TCW. */ - chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); - if (IS_ERR(chunk)) - return chunk; - itcw->tcw = chunk; - tcw_init(itcw->tcw, (op == ITCW_OP_READ) ? 1 : 0, - (op == ITCW_OP_WRITE) ? 1 : 0); - /* Interrogate TCW. */ - if (intrg) { - chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); - if (IS_ERR(chunk)) - return chunk; - itcw->intrg_tcw = chunk; - tcw_init(itcw->intrg_tcw, 1, 0); - tcw_set_intrg(itcw->tcw, itcw->intrg_tcw); - } - /* Data TIDAL. */ - if (max_tidaws > 0) { - chunk = fit_chunk(&start, end, sizeof(struct tidaw) * - max_tidaws, 16, 1); - if (IS_ERR(chunk)) - return chunk; - tcw_set_data(itcw->tcw, chunk, 1); - } - /* Interrogate data TIDAL. */ - if (intrg && (intrg_max_tidaws > 0)) { - chunk = fit_chunk(&start, end, sizeof(struct tidaw) * - intrg_max_tidaws, 16, 1); - if (IS_ERR(chunk)) - return chunk; - tcw_set_data(itcw->intrg_tcw, chunk, 1); - } - /* TSB. */ - chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0); - if (IS_ERR(chunk)) - return chunk; - tsb_init(chunk); - tcw_set_tsb(itcw->tcw, chunk); - /* Interrogate TSB. */ - if (intrg) { - chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0); - if (IS_ERR(chunk)) - return chunk; - tsb_init(chunk); - tcw_set_tsb(itcw->intrg_tcw, chunk); - } - /* TCCB. */ - chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0); - if (IS_ERR(chunk)) - return chunk; - tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_DEFAULT); - tcw_set_tccb(itcw->tcw, chunk); - /* Interrogate TCCB. */ - if (intrg) { - chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0); - if (IS_ERR(chunk)) - return chunk; - tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_INTRG); - tcw_set_tccb(itcw->intrg_tcw, chunk); - tccb_add_dcw(chunk, TCCB_MAX_SIZE, DCW_CMD_INTRG, 0, NULL, - sizeof(struct dcw_intrg_data), 0); - tcw_finalize(itcw->intrg_tcw, 0); - } - return itcw; -} -EXPORT_SYMBOL(itcw_init); - -/** - * itcw_add_dcw - add a dcw to the itcw - * @itcw: address of the itcw - * @cmd: the dcw command - * @flags: flags for the dcw - * @cd: address of control data for this dcw or NULL if none is required - * @cd_count: number of control data bytes for this dcw - * @count: number of data bytes for this dcw - * - * Add a new dcw to the specified itcw by writing the dcw information specified - * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return - * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw - * would exceed the available space. - * - * Note: the tcal field of the tccb header will be updated to reflect added - * content. - */ -struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd, - u8 cd_count, u32 count) -{ - return tccb_add_dcw(tcw_get_tccb(itcw->tcw), TCCB_MAX_SIZE, cmd, - flags, cd, cd_count, count); -} -EXPORT_SYMBOL(itcw_add_dcw); - -/** - * itcw_add_tidaw - add a tidaw to the itcw - * @itcw: address of the itcw - * @flags: flags for the new tidaw - * @addr: address value for the new tidaw - * @count: count value for the new tidaw - * - * Add a new tidaw to the input/output data tidaw-list of the specified itcw - * (depending on the value of the r-flag and w-flag). Return a pointer to - * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the - * available space. - * - * Note: the tidaw-list is assumed to be contiguous with no ttics. The - * last-tidaw flag for the last tidaw in the list will be set by itcw_finalize. - */ -struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count) -{ - if (itcw->num_tidaws >= itcw->max_tidaws) - return ERR_PTR(-ENOSPC); - return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count); -} -EXPORT_SYMBOL(itcw_add_tidaw); - -/** - * itcw_set_data - set data address and tida flag of the itcw - * @itcw: address of the itcw - * @addr: the data address - * @use_tidal: zero of the data address specifies a contiguous block of data, - * non-zero if it specifies a list if tidaws. - * - * Set the input/output data address of the itcw (depending on the value of the - * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag - * is set as well. - */ -void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal) -{ - tcw_set_data(itcw->tcw, addr, use_tidal); -} -EXPORT_SYMBOL(itcw_set_data); - -/** - * itcw_finalize - calculate length and count fields of the itcw - * @itcw: address of the itcw - * - * Calculate tcw input-/output-count and tccbl fields and add a tcat the tccb. - * In case input- or output-tida is used, the tidaw-list must be stored in - * continuous storage (no ttic). The tcal field in the tccb must be - * up-to-date. - */ -void itcw_finalize(struct itcw *itcw) -{ - tcw_finalize(itcw->tcw, itcw->num_tidaws); -} -EXPORT_SYMBOL(itcw_finalize); diff --git a/trunk/drivers/s390/cio/qdio.c b/trunk/drivers/s390/cio/qdio.c index 2bf36e14b102..445cf364e461 100644 --- a/trunk/drivers/s390/cio/qdio.c +++ b/trunk/drivers/s390/cio/qdio.c @@ -2082,6 +2082,7 @@ qdio_timeout_handler(struct ccw_device *cdev) default: BUG(); } + ccw_device_set_timeout(cdev, 0); wake_up(&cdev->private->wait_q); } @@ -2120,8 +2121,6 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) case -EIO: QDIO_PRINT_ERR("i/o error on device %s\n", cdev->dev.bus_id); - qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); - wake_up(&cdev->private->wait_q); return; case -ETIMEDOUT: qdio_timeout_handler(cdev); @@ -2140,8 +2139,8 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) QDIO_DBF_TEXT4(0, trace, dbf_text); #endif /* CONFIG_QDIO_DEBUG */ - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; switch (irq_ptr->state) { case QDIO_IRQ_STATE_INACTIVE: @@ -2354,6 +2353,9 @@ tiqdio_check_chsc_availability(void) { char dbf_text[15]; + if (!css_characteristics_avail) + return -EIO; + /* Check for bit 41. */ if (!css_general_characteristics.aif) { QDIO_PRINT_WARN("Adapter interruption facility not " \ @@ -2665,12 +2667,12 @@ qdio_shutdown(struct ccw_device *cdev, int how) spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); } else if (rc == 0) { qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP); + ccw_device_set_timeout(cdev, timeout); spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); - wait_event_interruptible_timeout(cdev->private->wait_q, - irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || - irq_ptr->state == QDIO_IRQ_STATE_ERR, - timeout); + wait_event(cdev->private->wait_q, + irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || + irq_ptr->state == QDIO_IRQ_STATE_ERR); } else { QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for " "device %s\n", result, cdev->dev.bus_id); @@ -2690,6 +2692,7 @@ qdio_shutdown(struct ccw_device *cdev, int how) /* Ignore errors. */ qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); + ccw_device_set_timeout(cdev, 0); out: up(&irq_ptr->setting_up_sema); return result; @@ -2904,10 +2907,13 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); - if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) + if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) { + ccw_device_set_timeout(cdev, 0); return; + } qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED); + ccw_device_set_timeout(cdev, 0); } int @@ -3190,6 +3196,8 @@ qdio_establish(struct qdio_initialize *init_data) irq_ptr->schid.ssid, irq_ptr->schid.sch_no, result, result2); result=result2; + if (result) + ccw_device_set_timeout(cdev, 0); } spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags); @@ -3271,6 +3279,7 @@ qdio_activate(struct ccw_device *cdev, int flags) spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags); + ccw_device_set_timeout(cdev, 0); ccw_device_set_options(cdev, CCWDEV_REPORT_ALL); result=ccw_device_start(cdev,&irq_ptr->ccw,QDIO_DOING_ACTIVATE, 0, DOIO_DENY_PREFETCH); @@ -3713,8 +3722,7 @@ tiqdio_register_thinints(void) char dbf_text[20]; tiqdio_ind = - s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL, - TIQDIO_THININT_ISC); + s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL); if (IS_ERR(tiqdio_ind)) { sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind)); QDIO_DBF_TEXT0(0,setup,dbf_text); @@ -3730,8 +3738,7 @@ static void tiqdio_unregister_thinints(void) { if (tiqdio_ind) - s390_unregister_adapter_interrupt(tiqdio_ind, - TIQDIO_THININT_ISC); + s390_unregister_adapter_interrupt(tiqdio_ind); } static int @@ -3892,7 +3899,6 @@ init_QDIO(void) qdio_mempool_alloc, qdio_mempool_free, NULL); - isc_register(QDIO_AIRQ_ISC); if (tiqdio_check_chsc_availability()) QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n"); @@ -3905,7 +3911,6 @@ static void __exit cleanup_QDIO(void) { tiqdio_unregister_thinints(); - isc_unregister(QDIO_AIRQ_ISC); qdio_remove_procfs_entry(); qdio_release_qdio_memory(); qdio_unregister_dbf_views(); diff --git a/trunk/drivers/s390/cio/qdio.h b/trunk/drivers/s390/cio/qdio.h index 7656081a24d2..c3df6b2c38b7 100644 --- a/trunk/drivers/s390/cio/qdio.h +++ b/trunk/drivers/s390/cio/qdio.h @@ -2,8 +2,8 @@ #define _CIO_QDIO_H #include -#include -#include + +#include "schid.h" #ifdef CONFIG_QDIO_DEBUG #define QDIO_VERBOSE_LEVEL 9 @@ -26,7 +26,7 @@ */ #define IQDIO_FILL_LEVEL_TO_POLL 4 -#define TIQDIO_THININT_ISC QDIO_AIRQ_ISC +#define TIQDIO_THININT_ISC 3 #define TIQDIO_DELAY_TARGET 0 #define QDIO_BUSY_BIT_PATIENCE 100 /* in microsecs */ #define QDIO_BUSY_BIT_GIVE_UP 10000000 /* 10 seconds */ diff --git a/trunk/include/asm-s390/schid.h b/trunk/drivers/s390/cio/schid.h similarity index 65% rename from trunk/include/asm-s390/schid.h rename to trunk/drivers/s390/cio/schid.h index 5017ffa78e04..54328fec5ade 100644 --- a/trunk/include/asm-s390/schid.h +++ b/trunk/drivers/s390/cio/schid.h @@ -1,14 +1,12 @@ -#ifndef ASM_SCHID_H -#define ASM_SCHID_H +#ifndef S390_SCHID_H +#define S390_SCHID_H struct subchannel_id { - __u32 cssid : 8; - __u32 : 4; - __u32 m : 1; - __u32 ssid : 2; - __u32 one : 1; - __u32 sch_no : 16; -} __attribute__ ((packed, aligned(4))); + __u32 reserved:13; + __u32 ssid:2; + __u32 one:1; + __u32 sch_no:16; +} __attribute__ ((packed,aligned(4))); /* Helper function for sane state of pre-allocated subchannel_id. */ @@ -25,4 +23,4 @@ schid_equal(struct subchannel_id *schid1, struct subchannel_id *schid2) return !memcmp(schid1, schid2, sizeof(struct subchannel_id)); } -#endif /* ASM_SCHID_H */ +#endif /* S390_SCHID_H */ diff --git a/trunk/drivers/s390/cio/scsw.c b/trunk/drivers/s390/cio/scsw.c deleted file mode 100644 index f8da25ab576d..000000000000 --- a/trunk/drivers/s390/cio/scsw.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Helper functions for scsw access. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include "css.h" -#include "chsc.h" - -/** - * scsw_is_tm - check for transport mode scsw - * @scsw: pointer to scsw - * - * Return non-zero if the specified scsw is a transport mode scsw, zero - * otherwise. - */ -int scsw_is_tm(union scsw *scsw) -{ - return css_general_characteristics.fcx && (scsw->tm.x == 1); -} -EXPORT_SYMBOL(scsw_is_tm); - -/** - * scsw_key - return scsw key field - * @scsw: pointer to scsw - * - * Return the value of the key field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.key; - else - return scsw->cmd.key; -} -EXPORT_SYMBOL(scsw_key); - -/** - * scsw_eswf - return scsw eswf field - * @scsw: pointer to scsw - * - * Return the value of the eswf field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.eswf; - else - return scsw->cmd.eswf; -} -EXPORT_SYMBOL(scsw_eswf); - -/** - * scsw_cc - return scsw cc field - * @scsw: pointer to scsw - * - * Return the value of the cc field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cc; - else - return scsw->cmd.cc; -} -EXPORT_SYMBOL(scsw_cc); - -/** - * scsw_ectl - return scsw ectl field - * @scsw: pointer to scsw - * - * Return the value of the ectl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.ectl; - else - return scsw->cmd.ectl; -} -EXPORT_SYMBOL(scsw_ectl); - -/** - * scsw_pno - return scsw pno field - * @scsw: pointer to scsw - * - * Return the value of the pno field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.pno; - else - return scsw->cmd.pno; -} -EXPORT_SYMBOL(scsw_pno); - -/** - * scsw_fctl - return scsw fctl field - * @scsw: pointer to scsw - * - * Return the value of the fctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.fctl; - else - return scsw->cmd.fctl; -} -EXPORT_SYMBOL(scsw_fctl); - -/** - * scsw_actl - return scsw actl field - * @scsw: pointer to scsw - * - * Return the value of the actl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.actl; - else - return scsw->cmd.actl; -} -EXPORT_SYMBOL(scsw_actl); - -/** - * scsw_stctl - return scsw stctl field - * @scsw: pointer to scsw - * - * Return the value of the stctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.stctl; - else - return scsw->cmd.stctl; -} -EXPORT_SYMBOL(scsw_stctl); - -/** - * scsw_dstat - return scsw dstat field - * @scsw: pointer to scsw - * - * Return the value of the dstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.dstat; - else - return scsw->cmd.dstat; -} -EXPORT_SYMBOL(scsw_dstat); - -/** - * scsw_cstat - return scsw cstat field - * @scsw: pointer to scsw - * - * Return the value of the cstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cstat; - else - return scsw->cmd.cstat; -} -EXPORT_SYMBOL(scsw_cstat); - -/** - * scsw_cmd_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_key(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_key); - -/** - * scsw_cmd_is_valid_sctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_sctl(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_sctl); - -/** - * scsw_cmd_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_eswf(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_eswf); - -/** - * scsw_cmd_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cc); - -/** - * scsw_cmd_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fmt(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fmt); - -/** - * scsw_cmd_is_valid_pfch - check pfch field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pfch field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pfch(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pfch); - -/** - * scsw_cmd_is_valid_isic - check isic field validity - * @scsw: pointer to scsw - * - * Return non-zero if the isic field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_isic(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_isic); - -/** - * scsw_cmd_is_valid_alcc - check alcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the alcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_alcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_alcc); - -/** - * scsw_cmd_is_valid_ssi - check ssi field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ssi field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ssi(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ssi); - -/** - * scsw_cmd_is_valid_zcc - check zcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the zcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_zcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_zcc); - -/** - * scsw_cmd_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ectl(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ectl); - -/** - * scsw_cmd_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pno(union scsw *scsw) -{ - return (scsw->cmd.fctl != 0) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pno); - -/** - * scsw_cmd_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fctl); - -/** - * scsw_cmd_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_actl); - -/** - * scsw_cmd_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_stctl); - -/** - * scsw_cmd_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_dstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_dstat); - -/** - * scsw_cmd_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cstat); - -/** - * scsw_tm_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_key(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_tm_is_valid_key); - -/** - * scsw_tm_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_eswf(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_eswf); - -/** - * scsw_tm_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cc(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cc); - -/** - * scsw_tm_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fmt(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fmt); - -/** - * scsw_tm_is_valid_x - check x field validity - * @scsw: pointer to scsw - * - * Return non-zero if the x field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_x(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_x); - -/** - * scsw_tm_is_valid_q - check q field validity - * @scsw: pointer to scsw - * - * Return non-zero if the q field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_q(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_q); - -/** - * scsw_tm_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_ectl(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_tm_is_valid_ectl); - -/** - * scsw_tm_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_pno(union scsw *scsw) -{ - return (scsw->tm.fctl != 0) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_tm_is_valid_pno); - -/** - * scsw_tm_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fctl); - -/** - * scsw_tm_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_actl); - -/** - * scsw_tm_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_stctl); - -/** - * scsw_tm_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_dstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_dstat); - -/** - * scsw_tm_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cstat); - -/** - * scsw_tm_is_valid_fcxs - check fcxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fcxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fcxs(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fcxs); - -/** - * scsw_tm_is_valid_schxs - check schxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the schxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_schxs(union scsw *scsw) -{ - return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK | - SCHN_STAT_INTF_CTRL_CHK | - SCHN_STAT_PROT_CHECK | - SCHN_STAT_CHN_DATA_CHK)); -} -EXPORT_SYMBOL(scsw_tm_is_valid_schxs); - -/** - * scsw_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_actl(scsw); - else - return scsw_cmd_is_valid_actl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_actl); - -/** - * scsw_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cc(scsw); - else - return scsw_cmd_is_valid_cc(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cc); - -/** - * scsw_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cstat(scsw); - else - return scsw_cmd_is_valid_cstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cstat); - -/** - * scsw_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_dstat(scsw); - else - return scsw_cmd_is_valid_dstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_dstat); - -/** - * scsw_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_ectl(scsw); - else - return scsw_cmd_is_valid_ectl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_ectl); - -/** - * scsw_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_eswf(scsw); - else - return scsw_cmd_is_valid_eswf(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_eswf); - -/** - * scsw_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_fctl(scsw); - else - return scsw_cmd_is_valid_fctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_fctl); - -/** - * scsw_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_key(scsw); - else - return scsw_cmd_is_valid_key(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_key); - -/** - * scsw_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_pno(scsw); - else - return scsw_cmd_is_valid_pno(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_pno); - -/** - * scsw_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_stctl(scsw); - else - return scsw_cmd_is_valid_stctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_stctl); - -/** - * scsw_cmd_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the command mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_cmd_is_solicited(union scsw *scsw) -{ - return (scsw->cmd.cc != 0) || (scsw->cmd.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_cmd_is_solicited); - -/** - * scsw_tm_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_tm_is_solicited(union scsw *scsw) -{ - return (scsw->tm.cc != 0) || (scsw->tm.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_tm_is_solicited); - -/** - * scsw_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport or command mode scsw indicates that the - * associated status condition is solicited, zero if it is unsolicited. - */ -int scsw_is_solicited(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_solicited(scsw); - else - return scsw_cmd_is_solicited(scsw); -} -EXPORT_SYMBOL(scsw_is_solicited); diff --git a/trunk/drivers/s390/crypto/ap_bus.c b/trunk/drivers/s390/crypto/ap_bus.c index 62b6b55230d0..a1ab3e3efd11 100644 --- a/trunk/drivers/s390/crypto/ap_bus.c +++ b/trunk/drivers/s390/crypto/ap_bus.c @@ -34,15 +34,13 @@ #include #include #include -#include -#include #include "ap_bus.h" /* Some prototypes. */ static void ap_scan_bus(struct work_struct *); static void ap_poll_all(unsigned long); -static enum hrtimer_restart ap_poll_timeout(struct hrtimer *); +static void ap_poll_timeout(unsigned long); static int ap_poll_thread_start(void); static void ap_poll_thread_stop(void); static void ap_request_timeout(unsigned long); @@ -82,15 +80,12 @@ static DECLARE_WORK(ap_config_work, ap_scan_bus); /* * Tasklet & timer for AP request polling. */ +static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0); static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0); static atomic_t ap_poll_requests = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread = NULL; static DEFINE_MUTEX(ap_poll_thread_mutex); -static struct hrtimer ap_poll_timer; -/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. - * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ -static unsigned long long poll_timeout = 250000; /** * ap_intructions_available() - Test if AP instructions are available. @@ -641,39 +636,11 @@ static ssize_t ap_poll_thread_store(struct bus_type *bus, static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store); -static ssize_t poll_timeout_show(struct bus_type *bus, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout); -} - -static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, - size_t count) -{ - unsigned long long time; - ktime_t hr_time; - - /* 120 seconds = maximum poll interval */ - if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000) - return -EINVAL; - poll_timeout = time; - hr_time = ktime_set(0, poll_timeout); - - if (!hrtimer_is_queued(&ap_poll_timer) || - !hrtimer_forward(&ap_poll_timer, ap_poll_timer.expires, hr_time)) { - ap_poll_timer.expires = hr_time; - hrtimer_start(&ap_poll_timer, hr_time, HRTIMER_MODE_ABS); - } - return count; -} - -static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); - static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_config_time, &bus_attr_poll_thread, - &bus_attr_poll_timeout, - NULL, + NULL }; /** @@ -928,10 +895,9 @@ ap_config_timeout(unsigned long ptr) */ static inline void ap_schedule_poll_timer(void) { - if (hrtimer_is_queued(&ap_poll_timer)) + if (timer_pending(&ap_poll_timer)) return; - hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout), - HRTIMER_MODE_ABS); + mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME); } /** @@ -1149,14 +1115,13 @@ EXPORT_SYMBOL(ap_cancel_message); /** * ap_poll_timeout(): AP receive polling for finished AP requests. - * @unused: Unused pointer. + * @unused: Unused variable. * - * Schedules the AP tasklet using a high resolution timer. + * Schedules the AP tasklet. */ -static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) +static void ap_poll_timeout(unsigned long unused) { tasklet_schedule(&ap_tasklet); - return HRTIMER_NORESTART; } /** @@ -1379,14 +1344,6 @@ int __init ap_module_init(void) ap_config_timer.expires = jiffies + ap_config_time * HZ; add_timer(&ap_config_timer); - /* Setup the high resultion poll timer. - * If we are running under z/VM adjust polling to z/VM polling rate. - */ - if (MACHINE_IS_VM) - poll_timeout = 1500000; - hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - ap_poll_timer.function = ap_poll_timeout; - /* Start the low priority AP bus poll thread. */ if (ap_thread_flag) { rc = ap_poll_thread_start(); @@ -1398,7 +1355,7 @@ int __init ap_module_init(void) out_work: del_timer_sync(&ap_config_timer); - hrtimer_cancel(&ap_poll_timer); + del_timer_sync(&ap_poll_timer); destroy_workqueue(ap_work_queue); out_root: s390_root_dev_unregister(ap_root_device); @@ -1429,7 +1386,7 @@ void ap_module_exit(void) ap_reset_domain(); ap_poll_thread_stop(); del_timer_sync(&ap_config_timer); - hrtimer_cancel(&ap_poll_timer); + del_timer_sync(&ap_poll_timer); destroy_workqueue(ap_work_queue); tasklet_kill(&ap_tasklet); s390_root_dev_unregister(ap_root_device); diff --git a/trunk/drivers/s390/crypto/ap_bus.h b/trunk/drivers/s390/crypto/ap_bus.h index 446378b308fc..c1e1200c43fc 100644 --- a/trunk/drivers/s390/crypto/ap_bus.h +++ b/trunk/drivers/s390/crypto/ap_bus.h @@ -92,8 +92,6 @@ struct ap_queue_status { #define AP_DEVICE_TYPE_PCIXCC 5 #define AP_DEVICE_TYPE_CEX2A 6 #define AP_DEVICE_TYPE_CEX2C 7 -#define AP_DEVICE_TYPE_CEX2A2 8 -#define AP_DEVICE_TYPE_CEX2C2 9 /* * AP reset flag states diff --git a/trunk/drivers/s390/crypto/zcrypt_api.c b/trunk/drivers/s390/crypto/zcrypt_api.c index 8a4964f3584b..4d36e805a234 100644 --- a/trunk/drivers/s390/crypto/zcrypt_api.c +++ b/trunk/drivers/s390/crypto/zcrypt_api.c @@ -1068,8 +1068,10 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer, #define LBUFSIZE 1200UL lbuf = kmalloc(LBUFSIZE, GFP_KERNEL); - if (!lbuf) + if (!lbuf) { + PRINTK("kmalloc failed!\n"); return 0; + } local_count = min(LBUFSIZE - 1, count); if (copy_from_user(lbuf, buffer, local_count) != 0) { @@ -1079,15 +1081,23 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer, lbuf[local_count] = '\0'; ptr = strstr(lbuf, "Online devices"); - if (!ptr) + if (!ptr) { + PRINTK("Unable to parse data (missing \"Online devices\")\n"); goto out; + } ptr = strstr(ptr, "\n"); - if (!ptr) + if (!ptr) { + PRINTK("Unable to parse data (missing newline " + "after \"Online devices\")\n"); goto out; + } ptr++; - if (strstr(ptr, "Waiting work element counts") == NULL) + if (strstr(ptr, "Waiting work element counts") == NULL) { + PRINTK("Unable to parse data (missing " + "\"Waiting work element counts\")\n"); goto out; + } for (j = 0; j < 64 && *ptr; ptr++) { /* @@ -1187,12 +1197,16 @@ int __init zcrypt_api_init(void) /* Register the request sprayer. */ rc = misc_register(&zcrypt_misc_device); - if (rc < 0) + if (rc < 0) { + PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n", + zcrypt_misc_device.minor, rc); goto out; + } /* Set up the proc file system */ zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL); if (!zcrypt_entry) { + PRINTK("Couldn't create z90crypt proc entry\n"); rc = -ENOMEM; goto out_misc; } diff --git a/trunk/drivers/s390/crypto/zcrypt_api.h b/trunk/drivers/s390/crypto/zcrypt_api.h index 1d1ec74dadb2..5c6e222b2ac4 100644 --- a/trunk/drivers/s390/crypto/zcrypt_api.h +++ b/trunk/drivers/s390/crypto/zcrypt_api.h @@ -30,6 +30,34 @@ #ifndef _ZCRYPT_API_H_ #define _ZCRYPT_API_H_ +/** + * Macro definitions + * + * PDEBUG debugs in the form "zcrypt: function_name -> message" + * + * PRINTK is like PDEBUG, except that it is always enabled + * PRINTKN is like PRINTK, except that it does not include the function name + * PRINTKW is like PRINTK, except that it uses KERN_WARNING + * PRINTKC is like PRINTK, except that it uses KERN_CRIT + */ +#define DEV_NAME "zcrypt" + +#define PRINTK(fmt, args...) \ + printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args) +#define PRINTKN(fmt, args...) \ + printk(KERN_DEBUG DEV_NAME ": " fmt, ## args) +#define PRINTKW(fmt, args...) \ + printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __func__ , ## args) +#define PRINTKC(fmt, args...) \ + printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __func__ , ## args) + +#ifdef ZCRYPT_DEBUG +#define PDEBUG(fmt, args...) \ + printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args) +#else +#define PDEBUG(fmt, args...) do {} while (0) +#endif + #include "ap_bus.h" #include diff --git a/trunk/drivers/s390/crypto/zcrypt_cex2a.c b/trunk/drivers/s390/crypto/zcrypt_cex2a.c index 54f4cbc3be9e..08657f604b8c 100644 --- a/trunk/drivers/s390/crypto/zcrypt_cex2a.c +++ b/trunk/drivers/s390/crypto/zcrypt_cex2a.c @@ -49,7 +49,6 @@ static struct ap_device_id zcrypt_cex2a_ids[] = { { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX2A2) }, { /* end of list */ }, }; @@ -243,6 +242,9 @@ static int convert_response(struct zcrypt_device *zdev, return convert_type80(zdev, reply, outputdata, outputdatalength); default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_error.h b/trunk/drivers/s390/crypto/zcrypt_error.h index 03ba27f05f92..3e27fe77d207 100644 --- a/trunk/drivers/s390/crypto/zcrypt_error.h +++ b/trunk/drivers/s390/crypto/zcrypt_error.h @@ -92,6 +92,10 @@ static inline int convert_error(struct zcrypt_device *zdev, { struct error_hdr *ehdr = reply->message; + PRINTK("Hardware error : Type %02x Message Header: %08x%08x\n", + ehdr->type, *(unsigned int *) reply->message, + *(unsigned int *) (reply->message + 4)); + switch (ehdr->reply_code) { case REP82_ERROR_OPERAND_INVALID: case REP82_ERROR_OPERAND_SIZE: @@ -119,6 +123,8 @@ static inline int convert_error(struct zcrypt_device *zdev, zdev->online = 0; return -EAGAIN; default: + PRINTKW("unknown type %02x reply code = %d\n", + ehdr->type, ehdr->reply_code); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_pcica.c b/trunk/drivers/s390/crypto/zcrypt_pcica.c index 12da4815ba8e..6e93b4751782 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcica.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcica.c @@ -226,6 +226,9 @@ static int convert_response(struct zcrypt_device *zdev, return convert_type84(zdev, reply, outputdata, outputdatalength); default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_pcicc.c b/trunk/drivers/s390/crypto/zcrypt_pcicc.c index 779952cb19fc..17ea56ce1c11 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcicc.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcicc.c @@ -361,18 +361,26 @@ static int convert_type86(struct zcrypt_device *zdev, service_rc = le16_to_cpu(msg->cprb.ccp_rtcode); if (unlikely(service_rc != 0)) { service_rs = le16_to_cpu(msg->cprb.ccp_rscode); - if (service_rc == 8 && service_rs == 66) + if (service_rc == 8 && service_rs == 66) { + PDEBUG("Bad block format on PCICC\n"); return -EINVAL; - if (service_rc == 8 && service_rs == 65) + } + if (service_rc == 8 && service_rs == 65) { + PDEBUG("Probably an even modulus on PCICC\n"); return -EINVAL; + } if (service_rc == 8 && service_rs == 770) { + PDEBUG("Invalid key length on PCICC\n"); zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD; return -EAGAIN; } if (service_rc == 8 && service_rs == 783) { + PDEBUG("Extended bitlengths not enabled on PCICC\n"); zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD; return -EAGAIN; } + PRINTK("Unknown service rc/rs (PCICC): %d/%d\n", + service_rc, service_rs); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -426,6 +434,9 @@ static int convert_response(struct zcrypt_device *zdev, outputdata, outputdatalength); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c index d8ad36f81540..0bc9b3188e64 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c @@ -72,7 +72,6 @@ struct response_type { static struct ap_device_id zcrypt_pcixcc_ids[] = { { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) }, { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX2C2) }, { /* end of list */ }, }; @@ -290,19 +289,38 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, ap_msg->length = sizeof(struct type6_hdr) + CEIL4(xcRB->request_control_blk_length) + xcRB->request_data_length; - if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) + if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) { + PRINTK("Combined message is too large (%ld/%d/%d).\n", + sizeof(struct type6_hdr), + xcRB->request_control_blk_length, + xcRB->request_data_length); return -EFAULT; - if (CEIL4(xcRB->reply_control_blk_length) > PCIXCC_MAX_XCRB_REPLY_SIZE) + } + if (CEIL4(xcRB->reply_control_blk_length) > + PCIXCC_MAX_XCRB_REPLY_SIZE) { + PDEBUG("Reply CPRB length is too large (%d).\n", + xcRB->request_control_blk_length); return -EFAULT; - if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) + } + if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) { + PDEBUG("Reply data block length is too large (%d).\n", + xcRB->reply_data_length); return -EFAULT; + } replylen = CEIL4(xcRB->reply_control_blk_length) + CEIL4(xcRB->reply_data_length) + sizeof(struct type86_fmt2_msg); if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) { + PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE" + " (%d/%d/%d).\n", + sizeof(struct type86_fmt2_msg), + xcRB->reply_control_blk_length, + xcRB->reply_data_length); xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE - (sizeof(struct type86_fmt2_msg) + CEIL4(xcRB->reply_data_length)); + PDEBUG("Capping Reply CPRB length at %d\n", + xcRB->reply_control_blk_length); } /* prepare type6 header */ @@ -321,8 +339,11 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, xcRB->request_control_blk_length)) return -EFAULT; if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > - xcRB->request_control_blk_length) + xcRB->request_control_blk_length) { + PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len, + xcRB->request_control_blk_length); return -EFAULT; + } function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); @@ -450,18 +471,29 @@ static int convert_type86_ica(struct zcrypt_device *zdev, service_rc = msg->cprbx.ccp_rtcode; if (unlikely(service_rc != 0)) { service_rs = msg->cprbx.ccp_rscode; - if (service_rc == 8 && service_rs == 66) + if (service_rc == 8 && service_rs == 66) { + PDEBUG("Bad block format on PCIXCC/CEX2C\n"); return -EINVAL; - if (service_rc == 8 && service_rs == 65) + } + if (service_rc == 8 && service_rs == 65) { + PDEBUG("Probably an even modulus on PCIXCC/CEX2C\n"); return -EINVAL; - if (service_rc == 8 && service_rs == 770) + } + if (service_rc == 8 && service_rs == 770) { + PDEBUG("Invalid key length on PCIXCC/CEX2C\n"); return -EINVAL; + } if (service_rc == 8 && service_rs == 783) { + PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n"); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } - if (service_rc == 12 && service_rs == 769) + if (service_rc == 12 && service_rs == 769) { + PDEBUG("Invalid key on PCIXCC/CEX2C\n"); return -EINVAL; + } + PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n", + service_rc, service_rs); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -537,8 +569,11 @@ static int convert_type86_rng(struct zcrypt_device *zdev, } __attribute__((packed)) *msg = reply->message; char *data = reply->message; - if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) + if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) { + PDEBUG("RNG response error on PCIXCC/CEX2C rc=%hu/rs=%hu\n", + rc, rs); return -EINVAL; + } memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); return msg->fmt2.count2; } @@ -563,6 +598,9 @@ static int convert_response_ica(struct zcrypt_device *zdev, outputdata, outputdatalength); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -589,6 +627,9 @@ static int convert_response_xcrb(struct zcrypt_device *zdev, return convert_type86_xcrb(zdev, reply, xcRB); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ @@ -612,6 +653,9 @@ static int convert_response_rng(struct zcrypt_device *zdev, return convert_type86_rng(zdev, reply, data); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -656,7 +700,10 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, memcpy(msg->message, reply->message, length); break; default: - memcpy(msg->message, &error_reply, sizeof error_reply); + PRINTK("Invalid internal response type: %i\n", + resp_type->type); + memcpy(msg->message, &error_reply, + sizeof error_reply); } } else memcpy(msg->message, reply->message, sizeof error_reply); diff --git a/trunk/drivers/s390/net/claw.c b/trunk/drivers/s390/net/claw.c index c644669a75c2..04a1d7bf678c 100644 --- a/trunk/drivers/s390/net/claw.c +++ b/trunk/drivers/s390/net/claw.c @@ -703,8 +703,7 @@ claw_irq_handler(struct ccw_device *cdev, if (!cdev->dev.driver_data) { printk(KERN_WARNING "claw: unsolicited interrupt for device:" "%s received c-%02x d-%02x\n", - cdev->dev.bus_id, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + cdev->dev.bus_id,irb->scsw.cstat, irb->scsw.dstat); #ifdef FUNCTRACE printk(KERN_INFO "claw: %s() " "exit on line %d\n",__func__,__LINE__); @@ -733,23 +732,22 @@ claw_irq_handler(struct ccw_device *cdev, #ifdef IOTRACE printk(KERN_INFO "%s: interrupt for device: %04x " "received c-%02x d-%02x state-%02x\n", - dev->name, p_ch->devno, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat, p_ch->claw_state); + dev->name, p_ch->devno, irb->scsw.cstat, + irb->scsw.dstat, p_ch->claw_state); #endif /* Copy interruption response block. */ memcpy(p_ch->irb, irb, sizeof(struct irb)); /* Check for good subchannel return code, otherwise error message */ - if (irb->scsw.cmd.cstat && !(irb->scsw.cmd.cstat & SCHN_STAT_PCI)) { + if (irb->scsw.cstat && !(irb->scsw.cstat & SCHN_STAT_PCI)) { printk(KERN_INFO "%s: subchannel check for device: %04x -" " Sch Stat %02x Dev Stat %02x CPA - %04x\n", dev->name, p_ch->devno, - irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, - irb->scsw.cmd.cpa); + irb->scsw.cstat, irb->scsw.dstat,irb->scsw.cpa); #ifdef IOTRACE dumpit((char *)irb,sizeof(struct irb)); - dumpit((char *)(unsigned long)irb->scsw.cmd.cpa, + dumpit((char *)(unsigned long)irb->scsw.cpa, sizeof(struct ccw1)); #endif #ifdef FUNCTRACE @@ -761,24 +759,22 @@ claw_irq_handler(struct ccw_device *cdev, } /* Check the reason-code of a unit check */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { ccw_check_unit_check(p_ch, irb->ecw[0]); + } /* State machine to bring the connection up, down and to restart */ - p_ch->last_dstat = irb->scsw.cmd.dstat; + p_ch->last_dstat = irb->scsw.dstat; switch (p_ch->claw_state) { case CLAW_STOP:/* HALT_IO by claw_release (halt sequence) */ #ifdef DEBUGMSG printk(KERN_INFO "%s: CLAW_STOP enter\n", dev->name); #endif - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); @@ -802,13 +798,10 @@ claw_irq_handler(struct ccw_device *cdev, printk(KERN_INFO "%s: process CLAW_STAT_HALT_IO\n", dev->name); #endif - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); @@ -835,8 +828,8 @@ claw_irq_handler(struct ccw_device *cdev, "interrupt for device:" "%s received c-%02x d-%02x\n", cdev->dev.bus_id, - irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + irb->scsw.cstat, + irb->scsw.dstat); return; } #ifdef DEBUGMSG @@ -851,7 +844,7 @@ claw_irq_handler(struct ccw_device *cdev, return; case CLAW_START_READ: CLAW_DBF_TEXT(4,trace,"ReadIRQ"); - if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { clear_bit(0, (void *)&p_ch->IO_active); if ((p_ch->irb->ecw[0] & 0x41) == 0x41 || (p_ch->irb->ecw[0] & 0x40) == 0x40 || @@ -870,8 +863,8 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"notrdy"); return; } - if ((p_ch->irb->scsw.cmd.cstat & SCHN_STAT_PCI) && - (p_ch->irb->scsw.cmd.dstat == 0)) { + if ((p_ch->irb->scsw.cstat & SCHN_STAT_PCI) && + (p_ch->irb->scsw.dstat==0)) { if (test_and_set_bit(CLAW_BH_ACTIVE, (void *)&p_ch->flag_a) == 0) { tasklet_schedule(&p_ch->tasklet); @@ -886,13 +879,10 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"PCI_read"); return; } - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); @@ -921,7 +911,7 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"RdIRQXit"); return; case CLAW_START_WRITE: - if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { printk(KERN_INFO "%s: Unit Check Occured in " "write channel\n",dev->name); clear_bit(0, (void *)&p_ch->IO_active); @@ -944,19 +934,16 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"rstrtwrt"); return; } - if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) { + if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) { clear_bit(0, (void *)&p_ch->IO_active); printk(KERN_INFO "%s: Unit Exception " "Occured in write channel\n", dev->name); } - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); diff --git a/trunk/drivers/s390/net/ctcm_fsms.c b/trunk/drivers/s390/net/ctcm_fsms.c index 7e6bd387f4d8..2a106f3a076d 100644 --- a/trunk/drivers/s390/net/ctcm_fsms.c +++ b/trunk/drivers/s390/net/ctcm_fsms.c @@ -257,9 +257,9 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg) if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; - if (ch->irb->scsw.cmd.count != 0) + if (ch->irb->scsw.count != 0) ctcm_pr_debug("%s: TX not complete, remaining %d bytes\n", - dev->name, ch->irb->scsw.cmd.count); + dev->name, ch->irb->scsw.count); fsm_deltimer(&ch->timer); while ((skb = skb_dequeue(&ch->io_queue))) { priv->stats.tx_packets++; @@ -353,7 +353,7 @@ static void chx_rx(fsm_instance *fi, int event, void *arg) struct channel *ch = arg; struct net_device *dev = ch->netdev; struct ctcm_priv *priv = dev->priv; - int len = ch->max_bufsize - ch->irb->scsw.cmd.count; + int len = ch->max_bufsize - ch->irb->scsw.count; struct sk_buff *skb = ch->trans_skb; __u16 block_len = *((__u16 *)skb->data); int check_len; @@ -1234,9 +1234,9 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg) if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; - if (ch->irb->scsw.cmd.count != 0) + if (ch->irb->scsw.count != 0) ctcm_pr_debug("%s: TX not complete, remaining %d bytes\n", - dev->name, ch->irb->scsw.cmd.count); + dev->name, ch->irb->scsw.count); fsm_deltimer(&ch->timer); while ((skb = skb_dequeue(&ch->io_queue))) { priv->stats.tx_packets++; @@ -1394,7 +1394,7 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg) struct sk_buff *skb = ch->trans_skb; struct sk_buff *new_skb; unsigned long saveflags = 0; /* avoids compiler warning */ - int len = ch->max_bufsize - ch->irb->scsw.cmd.count; + int len = ch->max_bufsize - ch->irb->scsw.count; if (do_debug_data) { CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, "mpc_ch_rx %s cp:%i %s\n", diff --git a/trunk/drivers/s390/net/ctcm_main.c b/trunk/drivers/s390/net/ctcm_main.c index 6b13c1c1beb8..d52843da4f55 100644 --- a/trunk/drivers/s390/net/ctcm_main.c +++ b/trunk/drivers/s390/net/ctcm_main.c @@ -1236,8 +1236,8 @@ static void ctcm_irq_handler(struct ccw_device *cdev, /* Check for unsolicited interrupts. */ if (cgdev == NULL) { ctcm_pr_warn("ctcm: Got unsolicited irq: %s c-%02x d-%02x\n", - cdev->dev.bus_id, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + cdev->dev.bus_id, irb->scsw.cstat, + irb->scsw.dstat); return; } @@ -1266,40 +1266,40 @@ static void ctcm_irq_handler(struct ccw_device *cdev, "received c-%02x d-%02x\n", dev->name, ch->id, - irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + irb->scsw.cstat, + irb->scsw.dstat); /* Copy interruption response block. */ memcpy(ch->irb, irb, sizeof(struct irb)); /* Check for good subchannel return code, otherwise error message */ - if (irb->scsw.cmd.cstat) { + if (irb->scsw.cstat) { fsm_event(ch->fsm, CTC_EVENT_SC_UNKNOWN, ch); ctcm_pr_warn("%s: subchannel check for dev: %s - %02x %02x\n", - dev->name, ch->id, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + dev->name, ch->id, irb->scsw.cstat, + irb->scsw.dstat); return; } /* Check the reason-code of a unit check */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { ccw_unit_check(ch, irb->ecw[0]); return; } - if (irb->scsw.cmd.dstat & DEV_STAT_BUSY) { - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) + if (irb->scsw.dstat & DEV_STAT_BUSY) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) fsm_event(ch->fsm, CTC_EVENT_ATTNBUSY, ch); else fsm_event(ch->fsm, CTC_EVENT_BUSY, ch); return; } - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { fsm_event(ch->fsm, CTC_EVENT_ATTN, ch); return; } - if ((irb->scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS) || - (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND) || - (irb->scsw.cmd.stctl == + if ((irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (irb->scsw.stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) fsm_event(ch->fsm, CTC_EVENT_FINSTAT, ch); else diff --git a/trunk/drivers/s390/net/cu3088.c b/trunk/drivers/s390/net/cu3088.c index f4a32375c037..8e7697305a4c 100644 --- a/trunk/drivers/s390/net/cu3088.c +++ b/trunk/drivers/s390/net/cu3088.c @@ -36,6 +36,7 @@ const char *cu3088_type[] = { "CTC/A", "ESCON channel", "FICON channel", + "P390 LCS card", "OSA LCS card", "CLAW channel device", "unknown channel type", @@ -48,6 +49,7 @@ static struct ccw_device_id cu3088_ids[] = { { CCW_DEVICE(0x3088, 0x08), .driver_info = channel_type_parallel }, { CCW_DEVICE(0x3088, 0x1f), .driver_info = channel_type_escon }, { CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon }, + { CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 }, { CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 }, { CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw }, { /* end of list */ } diff --git a/trunk/drivers/s390/net/cu3088.h b/trunk/drivers/s390/net/cu3088.h index d8558a7105a5..1753661f702a 100644 --- a/trunk/drivers/s390/net/cu3088.h +++ b/trunk/drivers/s390/net/cu3088.h @@ -17,6 +17,9 @@ enum channel_types { /* Device is a FICON channel */ channel_type_ficon, + /* Device is a P390 LCS card */ + channel_type_p390, + /* Device is a OSA2 card */ channel_type_osa2, diff --git a/trunk/drivers/s390/net/lcs.c b/trunk/drivers/s390/net/lcs.c index 6de28385b354..dd22f4b37037 100644 --- a/trunk/drivers/s390/net/lcs.c +++ b/trunk/drivers/s390/net/lcs.c @@ -1327,8 +1327,8 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb) char *sense; sense = (char *) irb->ecw; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | @@ -1388,13 +1388,11 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) else channel = &card->write; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); - LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); - LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.fctl, - irb->scsw.cmd.actl); + LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat); + LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl); /* Check for channel and device errors presented */ rc = lcs_get_problem(cdev, irb); @@ -1412,11 +1410,11 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } /* How far in the ccw chain have we processed? */ if ((channel->state != LCS_CH_STATE_INIT) && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC)) { - index = (struct ccw1 *) __va((addr_t) irb->scsw.cmd.cpa) + (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { + index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) - channel->ccws; - if ((irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED) || - (irb->scsw.cmd.cstat & SCHN_STAT_PCI)) + if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) || + (irb->scsw.cstat & SCHN_STAT_PCI)) /* Bloody io subsystem tells us lies about cpa... */ index = (index - 1) & (LCS_NUM_BUFFS - 1); while (channel->io_idx != index) { @@ -1427,24 +1425,25 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } } - if ((irb->scsw.cmd.dstat & DEV_STAT_DEV_END) || - (irb->scsw.cmd.dstat & DEV_STAT_CHN_END) || - (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) + if ((irb->scsw.dstat & DEV_STAT_DEV_END) || + (irb->scsw.dstat & DEV_STAT_CHN_END) || + (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) /* Mark channel as stopped. */ channel->state = LCS_CH_STATE_STOPPED; - else if (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED) + else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) /* CCW execution stopped on a suspend bit. */ channel->state = LCS_CH_STATE_SUSPENDED; - if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) { - if (irb->scsw.cmd.cc != 0) { + if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { + if (irb->scsw.cc != 0) { ccw_device_halt(channel->ccwdev, (addr_t) channel); return; } /* The channel has been stopped by halt_IO. */ channel->state = LCS_CH_STATE_HALTED; } - if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) + if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { channel->state = LCS_CH_STATE_CLEARED; + } /* Do the rest in the tasklet. */ tasklet_schedule(&channel->irq_tasklet); } @@ -1762,7 +1761,7 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) netif_carrier_off(card->dev); break; default: - LCS_DBF_TEXT(5, trace, "noLGWcmd"); + PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); break; } } else @@ -2043,12 +2042,13 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) LCS_DBF_TEXT(2, setup, "add_dev"); card = lcs_alloc_card(); if (!card) { - LCS_DBF_TEXT_(2, setup, " rc%d", -ENOMEM); + PRINT_ERR("Allocation of lcs card failed\n"); put_device(&ccwgdev->dev); return -ENOMEM; } ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group); if (ret) { + PRINT_ERR("Creating attributes failed"); lcs_free_card(card); put_device(&ccwgdev->dev); return ret; @@ -2140,6 +2140,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) default: LCS_DBF_TEXT(3, setup, "errinit"); PRINT_ERR("LCS: Initialization failed\n"); + PRINT_ERR("LCS: No device found!\n"); goto out; } if (!dev) @@ -2268,6 +2269,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) if (!card) return; + PRINT_INFO("Removing lcs group device ....\n"); LCS_DBF_TEXT(3, setup, "remdev"); LCS_DBF_HEX(3, setup, &card, sizeof(void*)); if (ccwgdev->state == CCWGROUP_ONLINE) { diff --git a/trunk/drivers/s390/net/netiucv.c b/trunk/drivers/s390/net/netiucv.c index 9242b5acc66b..e4ba6a0372ac 100644 --- a/trunk/drivers/s390/net/netiucv.c +++ b/trunk/drivers/s390/net/netiucv.c @@ -625,6 +625,9 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, offset += header->next; header->next -= NETIUCV_HDRLEN; if (skb_tailroom(pskb) < header->next) { + PRINT_WARN("%s: Illegal next field in iucv header: " + "%d > %d\n", + dev->name, header->next, skb_tailroom(pskb)); IUCV_DBF_TEXT_(data, 2, "Illegal next field: %d > %d\n", header->next, skb_tailroom(pskb)); return; @@ -633,6 +636,8 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, skb_reset_mac_header(pskb); skb = dev_alloc_skb(pskb->len); if (!skb) { + PRINT_WARN("%s Out of memory in netiucv_unpack_skb\n", + dev->name); IUCV_DBF_TEXT(data, 2, "Out of memory in netiucv_unpack_skb\n"); privptr->stats.rx_dropped++; @@ -669,6 +674,7 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) if (!conn->netdev) { iucv_message_reject(conn->path, msg); + PRINT_WARN("Received data for unlinked connection\n"); IUCV_DBF_TEXT(data, 2, "Received data for unlinked connection\n"); return; @@ -676,6 +682,8 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) if (msg->length > conn->max_buffsize) { iucv_message_reject(conn->path, msg); privptr->stats.rx_dropped++; + PRINT_WARN("msglen %d > max_buffsize %d\n", + msg->length, conn->max_buffsize); IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", msg->length, conn->max_buffsize); return; @@ -687,6 +695,7 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) msg->length, NULL); if (rc || msg->length < 5) { privptr->stats.rx_errors++; + PRINT_WARN("iucv_receive returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); return; } @@ -769,6 +778,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) fsm_newstate(fi, CONN_STATE_IDLE); if (privptr) privptr->stats.tx_errors += txpackets; + PRINT_WARN("iucv_send returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); } else { if (privptr) { @@ -796,6 +806,8 @@ static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) path->flags = 0; rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); if (rc) { + PRINT_WARN("%s: IUCV accept failed with error %d\n", + netdev->name, rc); IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc); return; } @@ -861,7 +873,7 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) IUCV_DBF_TEXT(trace, 3, __func__); fsm_newstate(fi, CONN_STATE_STARTWAIT); - IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n", + PRINT_DEBUG("%s('%s'): connecting ...\n", conn->netdev->name, conn->userid); /* @@ -956,8 +968,8 @@ static void conn_action_inval(fsm_instance *fi, int event, void *arg) struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - IUCV_DBF_TEXT_(data, 2, "%s('%s'): conn_action_inval called\n", - netdev->name, conn->userid); + PRINT_WARN("%s: Cannot connect without username\n", netdev->name); + IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); } static const fsm_node conn_fsm[] = { @@ -1065,6 +1077,9 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) "connection is up and running\n"); break; case DEV_STATE_STOPWAIT: + PRINT_INFO( + "%s: got connection UP event during shutdown!\n", + dev->name); IUCV_DBF_TEXT(data, 2, "dev_action_connup: in DEV_STATE_STOPWAIT\n"); break; @@ -1159,6 +1174,8 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, nskb = alloc_skb(skb->len + NETIUCV_HDRLEN + NETIUCV_HDRLEN, GFP_ATOMIC | GFP_DMA); if (!nskb) { + PRINT_WARN("%s: Could not allocate tx_skb\n", + conn->netdev->name); IUCV_DBF_TEXT(data, 2, "alloc_skb failed\n"); rc = -ENOMEM; return rc; @@ -1206,6 +1223,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, skb_pull(skb, NETIUCV_HDRLEN); skb_trim(skb, skb->len - NETIUCV_HDRLEN); } + PRINT_WARN("iucv_send returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); } else { if (copied) @@ -1275,11 +1293,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) * Some sanity checks ... */ if (skb == NULL) { + PRINT_WARN("%s: NULL sk_buff passed\n", dev->name); IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n"); privptr->stats.tx_dropped++; return 0; } if (skb_headroom(skb) < NETIUCV_HDRLEN) { + PRINT_WARN("%s: Got sk_buff with head room < %ld bytes\n", + dev->name, NETIUCV_HDRLEN); IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n"); dev_kfree_skb(skb); @@ -1372,6 +1393,7 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, IUCV_DBF_TEXT(trace, 3, __func__); if (count > 9) { + PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); IUCV_DBF_TEXT_(setup, 2, "%d is length of username\n", (int) count); return -EINVAL; @@ -1387,6 +1409,7 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, /* trailing lf, grr */ break; } + PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); IUCV_DBF_TEXT_(setup, 2, "username: invalid character %c\n", *p); return -EINVAL; @@ -1398,15 +1421,18 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, if (memcmp(username, priv->conn->userid, 9) && (ndev->flags & (IFF_UP | IFF_RUNNING))) { /* username changed while the interface is active. */ + PRINT_WARN("netiucv: device %s active, connected to %s\n", + dev->bus_id, priv->conn->userid); + PRINT_WARN("netiucv: user cannot be updated\n"); IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); - return -EPERM; + return -EBUSY; } read_lock_bh(&iucv_connection_rwlock); list_for_each_entry(cp, &iucv_connection_list, list) { if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { read_unlock_bh(&iucv_connection_rwlock); - IUCV_DBF_TEXT_(setup, 2, "user_write: Connection " - "to %s already exists\n", username); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); return -EEXIST; } } @@ -1440,10 +1466,13 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, bs1 = simple_strtoul(buf, &e, 0); if (e && (!isspace(*e))) { + PRINT_WARN("netiucv: Invalid character in buffer!\n"); IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %c\n", *e); return -EINVAL; } if (bs1 > NETIUCV_BUFSIZE_MAX) { + PRINT_WARN("netiucv: Given buffer size %d too large.\n", + bs1); IUCV_DBF_TEXT_(setup, 2, "buffer_write: buffer size %d too large\n", bs1); @@ -1451,12 +1480,16 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, } if ((ndev->flags & IFF_RUNNING) && (bs1 < (ndev->mtu + NETIUCV_HDRLEN + 2))) { + PRINT_WARN("netiucv: Given buffer size %d too small.\n", + bs1); IUCV_DBF_TEXT_(setup, 2, "buffer_write: buffer size %d too small\n", bs1); return -EINVAL; } if (bs1 < (576 + NETIUCV_HDRLEN + NETIUCV_HDRLEN)) { + PRINT_WARN("netiucv: Given buffer size %d too small.\n", + bs1); IUCV_DBF_TEXT_(setup, 2, "buffer_write: buffer size %d too small\n", bs1); @@ -1930,6 +1963,7 @@ static ssize_t conn_write(struct device_driver *drv, IUCV_DBF_TEXT(trace, 3, __func__); if (count>9) { + PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n"); return -EINVAL; } @@ -1942,6 +1976,7 @@ static ssize_t conn_write(struct device_driver *drv, if (*p == '\n') /* trailing lf, grr */ break; + PRINT_WARN("netiucv: Invalid character in username!\n"); IUCV_DBF_TEXT_(setup, 2, "conn_write: invalid character %c\n", *p); return -EINVAL; @@ -1954,8 +1989,8 @@ static ssize_t conn_write(struct device_driver *drv, list_for_each_entry(cp, &iucv_connection_list, list) { if (!strncmp(username, cp->userid, 9)) { read_unlock_bh(&iucv_connection_rwlock); - IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection " - "to %s already exists\n", username); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); return -EEXIST; } } @@ -1963,6 +1998,9 @@ static ssize_t conn_write(struct device_driver *drv, dev = netiucv_init_netdevice(username); if (!dev) { + PRINT_WARN("netiucv: Could not allocate network device " + "structure for user '%s'\n", + netiucv_printname(username)); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); return -ENODEV; } @@ -1982,12 +2020,15 @@ static ssize_t conn_write(struct device_driver *drv, if (rc) goto out_unreg; + PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); return count; out_unreg: netiucv_unregister_device(priv->dev); out_free_ndev: + PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); + IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); netiucv_free_netdevice(dev); return rc; } @@ -2032,13 +2073,14 @@ static ssize_t remove_write (struct device_driver *drv, PRINT_WARN("netiucv: %s cannot be removed\n", ndev->name); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); - return -EPERM; + return -EBUSY; } unregister_netdev(ndev); netiucv_unregister_device(dev); return count; } read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: net device %s unknown\n", name); IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); return -EINVAL; } @@ -2106,6 +2148,7 @@ static int __init netiucv_init(void) netiucv_driver.groups = netiucv_drv_attr_groups; rc = driver_register(&netiucv_driver); if (rc) { + PRINT_ERR("NETIUCV: failed to register driver.\n"); IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); goto out_iucv; } diff --git a/trunk/drivers/s390/net/qeth_core_main.c b/trunk/drivers/s390/net/qeth_core_main.c index 0ac54dc638c2..9a71dae223e8 100644 --- a/trunk/drivers/s390/net/qeth_core_main.c +++ b/trunk/drivers/s390/net/qeth_core_main.c @@ -420,7 +420,7 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, QETH_DBF_TEXT(TRACE, 3, "urla"); break; default: - QETH_DBF_MESSAGE(2, "Received data is IPA " + PRINT_WARN("Received data is IPA " "but not a reply!\n"); break; } @@ -735,8 +735,8 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb) char *sense; sense = (char *) irb->ecw; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | @@ -823,8 +823,8 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, if (__qeth_check_irb_error(cdev, intparm, irb)) return; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; card = CARD_FROM_CDEV(cdev); if (!card) @@ -842,10 +842,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, } atomic_set(&channel->irq_pending, 0); - if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC)) channel->state = CH_STATE_STOPPED; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC)) channel->state = CH_STATE_HALTED; /*let's wake up immediately on data channel*/ @@ -4092,6 +4092,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) rc = qeth_determine_card_type(card); if (rc) { + PRINT_WARN("%s: not a valid card type\n", __func__); QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); goto err_card; } diff --git a/trunk/drivers/s390/net/qeth_l3_main.c b/trunk/drivers/s390/net/qeth_l3_main.c index 06deaee50f6d..999552c83bbe 100644 --- a/trunk/drivers/s390/net/qeth_l3_main.c +++ b/trunk/drivers/s390/net/qeth_l3_main.c @@ -944,8 +944,15 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card, else rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP, addr->del_flags); - if (rc) + if (rc) { QETH_DBF_TEXT(TRACE, 2, "failed"); + /* TODO: re-activate this warning as soon as we have a + * clean mirco code + qeth_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf); + PRINT_WARN("Could not deregister IP address %s (rc=%x)\n", + buf, rc); + */ + } return rc; } diff --git a/trunk/drivers/s390/net/smsgiucv.c b/trunk/drivers/s390/net/smsgiucv.c index 164e090c2625..8735a415a116 100644 --- a/trunk/drivers/s390/net/smsgiucv.c +++ b/trunk/drivers/s390/net/smsgiucv.c @@ -156,8 +156,11 @@ static int __init smsg_init(void) if (rc != 0) goto out; rc = iucv_register(&smsg_handler, 1); - if (rc) + if (rc) { + printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); + rc = -EIO; /* better errno ? */ goto out_driver; + } smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL); if (!smsg_path) { rc = -ENOMEM; @@ -165,8 +168,11 @@ static int __init smsg_init(void) } rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", NULL, NULL, NULL); - if (rc) + if (rc) { + printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); + rc = -EIO; /* better errno ? */ goto out_free; + } cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; diff --git a/trunk/drivers/s390/s390mach.c b/trunk/drivers/s390/s390mach.c index 834e9ee7e934..5bfbe7659830 100644 --- a/trunk/drivers/s390/s390mach.c +++ b/trunk/drivers/s390/s390mach.c @@ -2,10 +2,10 @@ * drivers/s390/s390mach.c * S/390 machine check handler * - * Copyright IBM Corp. 2000,2008 + * S390 version + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) - * Cornelia Huck */ #include @@ -18,6 +18,10 @@ #include #include #include +#include "cio/cio.h" +#include "cio/chsc.h" +#include "cio/css.h" +#include "cio/chp.h" #include "s390mach.h" static struct semaphore m_sem; @@ -32,40 +36,13 @@ s390_handle_damage(char *msg) for(;;); } -static crw_handler_t crw_handlers[NR_RSCS]; - -/** - * s390_register_crw_handler() - register a channel report word handler - * @rsc: reporting source code to handle - * @handler: handler to be registered - * - * Returns %0 on success and a negative error value otherwise. - */ -int s390_register_crw_handler(int rsc, crw_handler_t handler) -{ - if ((rsc < 0) || (rsc >= NR_RSCS)) - return -EINVAL; - if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) - return 0; - return -EBUSY; -} - -/** - * s390_unregister_crw_handler() - unregister a channel report word handler - * @rsc: reporting source code to handle - */ -void s390_unregister_crw_handler(int rsc) -{ - if ((rsc < 0) || (rsc >= NR_RSCS)) - return; - xchg(&crw_handlers[rsc], NULL); - synchronize_sched(); -} - /* * Retrieve CRWs and call function to handle event. + * + * Note : we currently process CRWs for io and chsc subchannels only */ -static int s390_collect_crw_info(void *param) +static int +s390_collect_crw_info(void *param) { struct crw crw[2]; int ccode; @@ -107,24 +84,57 @@ static int s390_collect_crw_info(void *param) crw[chain].rsid); /* Check for overflows. */ if (crw[chain].oflw) { - int i; - pr_debug("%s: crw overflow detected!\n", __func__); - for (i = 0; i < NR_RSCS; i++) { - if (crw_handlers[i]) - crw_handlers[i](NULL, NULL, 1); - } + css_schedule_eval_all(); chain = 0; continue; } - if (crw[0].chn && !chain) { - chain++; - continue; + switch (crw[chain].rsc) { + case CRW_RSC_SCH: + if (crw[0].chn && !chain) + break; + pr_debug("source is subchannel %04X\n", crw[0].rsid); + css_process_crw(crw[0].rsid, chain ? crw[1].rsid : 0); + break; + case CRW_RSC_MONITOR: + pr_debug("source is monitoring facility\n"); + break; + case CRW_RSC_CPATH: + pr_debug("source is channel path %02X\n", crw[0].rsid); + /* + * Check for solicited machine checks. These are + * created by reset channel path and need not be + * reported to the common I/O layer. + */ + if (crw[chain].slct) { + pr_debug("solicited machine check for " + "channel path %02X\n", crw[0].rsid); + break; + } + switch (crw[0].erc) { + case CRW_ERC_IPARM: /* Path has come. */ + chp_process_crw(crw[0].rsid, 1); + break; + case CRW_ERC_PERRI: /* Path has gone. */ + case CRW_ERC_PERRN: + chp_process_crw(crw[0].rsid, 0); + break; + default: + pr_debug("Don't know how to handle erc=%x\n", + crw[0].erc); + } + break; + case CRW_RSC_CONFIG: + pr_debug("source is configuration-alert facility\n"); + break; + case CRW_RSC_CSS: + pr_debug("source is channel subsystem\n"); + chsc_process_crw(); + break; + default: + pr_debug("unknown source\n"); + break; } - if (crw_handlers[crw[chain].rsc]) - crw_handlers[crw[chain].rsc](&crw[0], - chain ? &crw[1] : NULL, - 0); /* chain is always 0 or 1 here. */ chain = crw[chain].chn ? chain + 1 : 0; } @@ -458,10 +468,6 @@ s390_do_machine_check(struct pt_regs *regs) etr_sync_check(); if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH)) etr_switch_to_local(); - if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC)) - stp_sync_check(); - if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND)) - stp_island_check(); } if (mci->se) diff --git a/trunk/drivers/s390/s390mach.h b/trunk/drivers/s390/s390mach.h index d39f8b697d27..ca681f9b67fc 100644 --- a/trunk/drivers/s390/s390mach.h +++ b/trunk/drivers/s390/s390mach.h @@ -72,13 +72,6 @@ struct crw { __u32 rsid : 16; /* reporting-source ID */ } __attribute__ ((packed)); -typedef void (*crw_handler_t)(struct crw *, struct crw *, int); - -extern int s390_register_crw_handler(int rsc, crw_handler_t handler); -extern void s390_unregister_crw_handler(int rsc); - -#define NR_RSCS 16 - #define CRW_RSC_MONITOR 0x2 /* monitoring facility */ #define CRW_RSC_SCH 0x3 /* subchannel */ #define CRW_RSC_CPATH 0x4 /* channel path */ @@ -112,9 +105,6 @@ static inline int stcrw(struct crw *pcrw ) #define ED_ETR_SYNC 12 /* External damage ETR sync check */ #define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ -#define ED_STP_SYNC 7 /* External damage STP sync check */ -#define ED_STP_ISLAND 6 /* External damage STP island check */ - struct pt_regs; void s390_handle_mcck(void); diff --git a/trunk/drivers/scsi/sg.c b/trunk/drivers/scsi/sg.c index fe694f0ee19a..ea0edd1b2e76 100644 --- a/trunk/drivers/scsi/sg.c +++ b/trunk/drivers/scsi/sg.c @@ -182,9 +182,8 @@ static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize); static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp); -static ssize_t sg_new_write(Sg_fd *sfp, struct file *file, - const char __user *buf, size_t count, int blocking, - int read_only, Sg_request **o_srp); +static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, + int blocking, int read_only, Sg_request ** o_srp); static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char *cmnd, int timeout, int blocking); static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, @@ -205,6 +204,7 @@ static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request *sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); +static int sg_allow_access(unsigned char opcode, char dev_type); static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static Sg_device *sg_get_dev(int dev); #ifdef CONFIG_SCSI_PROC_FS @@ -544,7 +544,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) return -EFAULT; blocking = !(filp->f_flags & O_NONBLOCK); if (old_hdr.reply_len < 0) - return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL); + return sg_new_write(sfp, buf, count, blocking, 0, NULL); if (count < (SZ_SG_HEADER + 6)) return -EIO; /* The minimum scsi command length is 6 bytes. */ @@ -621,9 +621,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) } static ssize_t -sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, - size_t count, int blocking, int read_only, - Sg_request **o_srp) +sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, + int blocking, int read_only, Sg_request ** o_srp) { int k; Sg_request *srp; @@ -679,7 +678,8 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EFAULT; } - if (read_only && !blk_verify_command(file, cmnd)) { + if (read_only && + (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) { sg_remove_request(sfp, srp); return -EPERM; } @@ -799,7 +799,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) return -EFAULT; result = - sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, + sg_new_write(sfp, p, SZ_SG_IO_HDR, blocking, read_only, &srp); if (result < 0) return result; @@ -1048,7 +1048,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (copy_from_user(&opcode, siocp->data, 1)) return -EFAULT; - if (!blk_verify_command(filp, &opcode)) + if (!sg_allow_access(opcode, sdp->device->type)) return -EPERM; } return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p); @@ -2502,6 +2502,30 @@ sg_page_free(struct page *page, int size) __free_pages(page, order); } +#ifndef MAINTENANCE_IN_CMD +#define MAINTENANCE_IN_CMD 0xa3 +#endif + +static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE, + INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, + READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS, + SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD +}; + +static int +sg_allow_access(unsigned char opcode, char dev_type) +{ + int k; + + if (TYPE_SCANNER == dev_type) /* TYPE_ROM maybe burner */ + return 1; + for (k = 0; k < sizeof (allow_ops); ++k) { + if (opcode == allow_ops[k]) + return 1; + } + return 0; +} + #ifdef CONFIG_SCSI_PROC_FS static int sg_idr_max_id(int id, void *p, void *data) diff --git a/trunk/drivers/scsi/sr.c b/trunk/drivers/scsi/sr.c index 27f5bfd1def3..c82df8bd4d89 100644 --- a/trunk/drivers/scsi/sr.c +++ b/trunk/drivers/scsi/sr.c @@ -673,20 +673,24 @@ static int sr_probe(struct device *dev) static void get_sectorsize(struct scsi_cd *cd) { unsigned char cmd[10]; - unsigned char buffer[8]; + unsigned char *buffer; int the_result, retries = 3; int sector_size; struct request_queue *queue; + buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + if (!buffer) + goto Enomem; + do { cmd[0] = READ_CAPACITY; memset((void *) &cmd[1], 0, 9); - memset(buffer, 0, sizeof(buffer)); + memset(buffer, 0, 8); /* Do the command and wait.. */ the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, - buffer, sizeof(buffer), NULL, - SR_TIMEOUT, MAX_RETRIES); + buffer, 8, NULL, SR_TIMEOUT, + MAX_RETRIES); retries--; @@ -741,8 +745,14 @@ static void get_sectorsize(struct scsi_cd *cd) queue = cd->device->request_queue; blk_queue_hardsect_size(queue, sector_size); - +out: + kfree(buffer); return; + +Enomem: + cd->capacity = 0x1fffff; + cd->device->sector_size = 2048; /* A guess, just in case */ + goto out; } static void get_capabilities(struct scsi_cd *cd) diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index 9b887ef64ff1..e0c5f96b273d 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -7,7 +7,7 @@ menu "Graphics support" source "drivers/char/agp/Kconfig" -source "drivers/gpu/drm/Kconfig" +source "drivers/char/drm/Kconfig" config VGASTATE tristate diff --git a/trunk/drivers/xen/xenbus/xenbus_client.c b/trunk/drivers/xen/xenbus/xenbus_client.c index 9678b3e98c63..0f86b0ff7879 100644 --- a/trunk/drivers/xen/xenbus/xenbus_client.c +++ b/trunk/drivers/xen/xenbus/xenbus_client.c @@ -117,7 +117,7 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, char *path; va_start(ap, pathfmt); - path = kvasprintf(GFP_NOIO | __GFP_HIGH, pathfmt, ap); + path = kvasprintf(GFP_KERNEL, pathfmt, ap); va_end(ap); if (!path) { diff --git a/trunk/drivers/xen/xenbus/xenbus_xs.c b/trunk/drivers/xen/xenbus/xenbus_xs.c index 7f2f91c0e11d..227d53b12a5c 100644 --- a/trunk/drivers/xen/xenbus/xenbus_xs.c +++ b/trunk/drivers/xen/xenbus/xenbus_xs.c @@ -283,9 +283,9 @@ static char *join(const char *dir, const char *name) char *buffer; if (strlen(name) == 0) - buffer = kasprintf(GFP_NOIO | __GFP_HIGH, "%s", dir); + buffer = kasprintf(GFP_KERNEL, "%s", dir); else - buffer = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/%s", dir, name); + buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name); return (!buffer) ? ERR_PTR(-ENOMEM) : buffer; } @@ -297,7 +297,7 @@ static char **split(char *strings, unsigned int len, unsigned int *num) *num = count_strings(strings, len); /* Transfer to one big alloc for easy freeing. */ - ret = kmalloc(*num * sizeof(char *) + len, GFP_NOIO | __GFP_HIGH); + ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); if (!ret) { kfree(strings); return ERR_PTR(-ENOMEM); @@ -751,7 +751,7 @@ static int process_msg(void) } - msg = kmalloc(sizeof(*msg), GFP_NOIO | __GFP_HIGH); + msg = kmalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { err = -ENOMEM; goto out; @@ -763,7 +763,7 @@ static int process_msg(void) goto out; } - body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH); + body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); if (body == NULL) { kfree(msg); err = -ENOMEM; diff --git a/trunk/fs/Makefile b/trunk/fs/Makefile index 277b079dec9e..1e7a11bd4da1 100644 --- a/trunk/fs/Makefile +++ b/trunk/fs/Makefile @@ -19,7 +19,6 @@ else obj-y += no-block.o endif -obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o obj-$(CONFIG_INOTIFY) += inotify.o obj-$(CONFIG_INOTIFY_USER) += inotify_user.o obj-$(CONFIG_EPOLL) += eventpoll.o diff --git a/trunk/fs/bio-integrity.c b/trunk/fs/bio-integrity.c deleted file mode 100644 index 63e2ee63058d..000000000000 --- a/trunk/fs/bio-integrity.c +++ /dev/null @@ -1,719 +0,0 @@ -/* - * bio-integrity.c - bio data integrity extensions - * - * Copyright (C) 2007, 2008 Oracle Corporation - * Written by: Martin K. Petersen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - */ - -#include -#include -#include -#include - -static struct kmem_cache *bio_integrity_slab __read_mostly; -static struct workqueue_struct *kintegrityd_wq; - -/** - * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio - * @bio: bio to attach integrity metadata to - * @gfp_mask: Memory allocation mask - * @nr_vecs: Number of integrity metadata scatter-gather elements - * @bs: bio_set to allocate from - * - * Description: This function prepares a bio for attaching integrity - * metadata. nr_vecs specifies the maximum number of pages containing - * integrity metadata that can be attached. - */ -struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, - gfp_t gfp_mask, - unsigned int nr_vecs, - struct bio_set *bs) -{ - struct bio_integrity_payload *bip; - struct bio_vec *iv; - unsigned long idx; - - BUG_ON(bio == NULL); - - bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask); - if (unlikely(bip == NULL)) { - printk(KERN_ERR "%s: could not alloc bip\n", __func__); - return NULL; - } - - memset(bip, 0, sizeof(*bip)); - - iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, bs); - if (unlikely(iv == NULL)) { - printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__); - mempool_free(bip, bs->bio_integrity_pool); - return NULL; - } - - bip->bip_pool = idx; - bip->bip_vec = iv; - bip->bip_bio = bio; - bio->bi_integrity = bip; - - return bip; -} -EXPORT_SYMBOL(bio_integrity_alloc_bioset); - -/** - * bio_integrity_alloc - Allocate integrity payload and attach it to bio - * @bio: bio to attach integrity metadata to - * @gfp_mask: Memory allocation mask - * @nr_vecs: Number of integrity metadata scatter-gather elements - * - * Description: This function prepares a bio for attaching integrity - * metadata. nr_vecs specifies the maximum number of pages containing - * integrity metadata that can be attached. - */ -struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, - gfp_t gfp_mask, - unsigned int nr_vecs) -{ - return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set); -} -EXPORT_SYMBOL(bio_integrity_alloc); - -/** - * bio_integrity_free - Free bio integrity payload - * @bio: bio containing bip to be freed - * @bs: bio_set this bio was allocated from - * - * Description: Used to free the integrity portion of a bio. Usually - * called from bio_free(). - */ -void bio_integrity_free(struct bio *bio, struct bio_set *bs) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - - BUG_ON(bip == NULL); - - /* A cloned bio doesn't own the integrity metadata */ - if (!bio_flagged(bio, BIO_CLONED) && bip->bip_buf != NULL) - kfree(bip->bip_buf); - - mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]); - mempool_free(bip, bs->bio_integrity_pool); - - bio->bi_integrity = NULL; -} -EXPORT_SYMBOL(bio_integrity_free); - -/** - * bio_integrity_add_page - Attach integrity metadata - * @bio: bio to update - * @page: page containing integrity metadata - * @len: number of bytes of integrity metadata in page - * @offset: start offset within page - * - * Description: Attach a page containing integrity metadata to bio. - */ -int bio_integrity_add_page(struct bio *bio, struct page *page, - unsigned int len, unsigned int offset) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct bio_vec *iv; - - if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_pool)) { - printk(KERN_ERR "%s: bip_vec full\n", __func__); - return 0; - } - - iv = bip_vec_idx(bip, bip->bip_vcnt); - BUG_ON(iv == NULL); - BUG_ON(iv->bv_page != NULL); - - iv->bv_page = page; - iv->bv_len = len; - iv->bv_offset = offset; - bip->bip_vcnt++; - - return len; -} -EXPORT_SYMBOL(bio_integrity_add_page); - -/** - * bio_integrity_enabled - Check whether integrity can be passed - * @bio: bio to check - * - * Description: Determines whether bio_integrity_prep() can be called - * on this bio or not. bio data direction and target device must be - * set prior to calling. The functions honors the write_generate and - * read_verify flags in sysfs. - */ -int bio_integrity_enabled(struct bio *bio) -{ - /* Already protected? */ - if (bio_integrity(bio)) - return 0; - - return bdev_integrity_enabled(bio->bi_bdev, bio_data_dir(bio)); -} -EXPORT_SYMBOL(bio_integrity_enabled); - -/** - * bio_integrity_hw_sectors - Convert 512b sectors to hardware ditto - * @bi: blk_integrity profile for device - * @sectors: Number of 512 sectors to convert - * - * Description: The block layer calculates everything in 512 byte - * sectors but integrity metadata is done in terms of the hardware - * sector size of the storage device. Convert the block layer sectors - * to physical sectors. - */ -static inline unsigned int bio_integrity_hw_sectors(struct blk_integrity *bi, - unsigned int sectors) -{ - /* At this point there are only 512b or 4096b DIF/EPP devices */ - if (bi->sector_size == 4096) - return sectors >>= 3; - - return sectors; -} - -/** - * bio_integrity_tag_size - Retrieve integrity tag space - * @bio: bio to inspect - * - * Description: Returns the maximum number of tag bytes that can be - * attached to this bio. Filesystems can use this to determine how - * much metadata to attach to an I/O. - */ -unsigned int bio_integrity_tag_size(struct bio *bio) -{ - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - - BUG_ON(bio->bi_size == 0); - - return bi->tag_size * (bio->bi_size / bi->sector_size); -} -EXPORT_SYMBOL(bio_integrity_tag_size); - -int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len, int set) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; - - BUG_ON(bip->bip_buf == NULL); - - if (bi->tag_size == 0) - return -1; - - nr_sectors = bio_integrity_hw_sectors(bi, - DIV_ROUND_UP(len, bi->tag_size)); - - if (nr_sectors * bi->tuple_size > bip->bip_size) { - printk(KERN_ERR "%s: tag too big for bio: %u > %u\n", - __func__, nr_sectors * bi->tuple_size, bip->bip_size); - return -1; - } - - if (set) - bi->set_tag_fn(bip->bip_buf, tag_buf, nr_sectors); - else - bi->get_tag_fn(bip->bip_buf, tag_buf, nr_sectors); - - return 0; -} - -/** - * bio_integrity_set_tag - Attach a tag buffer to a bio - * @bio: bio to attach buffer to - * @tag_buf: Pointer to a buffer containing tag data - * @len: Length of the included buffer - * - * Description: Use this function to tag a bio by leveraging the extra - * space provided by devices formatted with integrity protection. The - * size of the integrity buffer must be <= to the size reported by - * bio_integrity_tag_size(). - */ -int bio_integrity_set_tag(struct bio *bio, void *tag_buf, unsigned int len) -{ - BUG_ON(bio_data_dir(bio) != WRITE); - - return bio_integrity_tag(bio, tag_buf, len, 1); -} -EXPORT_SYMBOL(bio_integrity_set_tag); - -/** - * bio_integrity_get_tag - Retrieve a tag buffer from a bio - * @bio: bio to retrieve buffer from - * @tag_buf: Pointer to a buffer for the tag data - * @len: Length of the target buffer - * - * Description: Use this function to retrieve the tag buffer from a - * completed I/O. The size of the integrity buffer must be <= to the - * size reported by bio_integrity_tag_size(). - */ -int bio_integrity_get_tag(struct bio *bio, void *tag_buf, unsigned int len) -{ - BUG_ON(bio_data_dir(bio) != READ); - - return bio_integrity_tag(bio, tag_buf, len, 0); -} -EXPORT_SYMBOL(bio_integrity_get_tag); - -/** - * bio_integrity_generate - Generate integrity metadata for a bio - * @bio: bio to generate integrity metadata for - * - * Description: Generates integrity metadata for a bio by calling the - * block device's generation callback function. The bio must have a - * bip attached with enough room to accommodate the generated - * integrity metadata. - */ -static void bio_integrity_generate(struct bio *bio) -{ - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - struct blk_integrity_exchg bix; - struct bio_vec *bv; - sector_t sector = bio->bi_sector; - unsigned int i, sectors, total; - void *prot_buf = bio->bi_integrity->bip_buf; - - total = 0; - bix.disk_name = bio->bi_bdev->bd_disk->disk_name; - bix.sector_size = bi->sector_size; - - bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page, KM_USER0); - bix.data_buf = kaddr + bv->bv_offset; - bix.data_size = bv->bv_len; - bix.prot_buf = prot_buf; - bix.sector = sector; - - bi->generate_fn(&bix); - - sectors = bv->bv_len / bi->sector_size; - sector += sectors; - prot_buf += sectors * bi->tuple_size; - total += sectors * bi->tuple_size; - BUG_ON(total > bio->bi_integrity->bip_size); - - kunmap_atomic(kaddr, KM_USER0); - } -} - -/** - * bio_integrity_prep - Prepare bio for integrity I/O - * @bio: bio to prepare - * - * Description: Allocates a buffer for integrity metadata, maps the - * pages and attaches them to a bio. The bio must have data - * direction, target device and start sector set priot to calling. In - * the WRITE case, integrity metadata will be generated using the - * block device's integrity function. In the READ case, the buffer - * will be prepared for DMA and a suitable end_io handler set up. - */ -int bio_integrity_prep(struct bio *bio) -{ - struct bio_integrity_payload *bip; - struct blk_integrity *bi; - struct request_queue *q; - void *buf; - unsigned long start, end; - unsigned int len, nr_pages; - unsigned int bytes, offset, i; - unsigned int sectors; - - bi = bdev_get_integrity(bio->bi_bdev); - q = bdev_get_queue(bio->bi_bdev); - BUG_ON(bi == NULL); - BUG_ON(bio_integrity(bio)); - - sectors = bio_integrity_hw_sectors(bi, bio_sectors(bio)); - - /* Allocate kernel buffer for protection data */ - len = sectors * blk_integrity_tuple_size(bi); - buf = kmalloc(len, GFP_NOIO | __GFP_NOFAIL | q->bounce_gfp); - if (unlikely(buf == NULL)) { - printk(KERN_ERR "could not allocate integrity buffer\n"); - return -EIO; - } - - end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - start = ((unsigned long) buf) >> PAGE_SHIFT; - nr_pages = end - start; - - /* Allocate bio integrity payload and integrity vectors */ - bip = bio_integrity_alloc(bio, GFP_NOIO, nr_pages); - if (unlikely(bip == NULL)) { - printk(KERN_ERR "could not allocate data integrity bioset\n"); - kfree(buf); - return -EIO; - } - - bip->bip_buf = buf; - bip->bip_size = len; - bip->bip_sector = bio->bi_sector; - - /* Map it */ - offset = offset_in_page(buf); - for (i = 0 ; i < nr_pages ; i++) { - int ret; - bytes = PAGE_SIZE - offset; - - if (len <= 0) - break; - - if (bytes > len) - bytes = len; - - ret = bio_integrity_add_page(bio, virt_to_page(buf), - bytes, offset); - - if (ret == 0) - return 0; - - if (ret < bytes) - break; - - buf += bytes; - len -= bytes; - offset = 0; - } - - /* Install custom I/O completion handler if read verify is enabled */ - if (bio_data_dir(bio) == READ) { - bip->bip_end_io = bio->bi_end_io; - bio->bi_end_io = bio_integrity_endio; - } - - /* Auto-generate integrity metadata if this is a write */ - if (bio_data_dir(bio) == WRITE) - bio_integrity_generate(bio); - - return 0; -} -EXPORT_SYMBOL(bio_integrity_prep); - -/** - * bio_integrity_verify - Verify integrity metadata for a bio - * @bio: bio to verify - * - * Description: This function is called to verify the integrity of a - * bio. The data in the bio io_vec is compared to the integrity - * metadata returned by the HBA. - */ -static int bio_integrity_verify(struct bio *bio) -{ - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - struct blk_integrity_exchg bix; - struct bio_vec *bv; - sector_t sector = bio->bi_integrity->bip_sector; - unsigned int i, sectors, total, ret; - void *prot_buf = bio->bi_integrity->bip_buf; - - ret = total = 0; - bix.disk_name = bio->bi_bdev->bd_disk->disk_name; - bix.sector_size = bi->sector_size; - - bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page, KM_USER0); - bix.data_buf = kaddr + bv->bv_offset; - bix.data_size = bv->bv_len; - bix.prot_buf = prot_buf; - bix.sector = sector; - - ret = bi->verify_fn(&bix); - - if (ret) { - kunmap_atomic(kaddr, KM_USER0); - break; - } - - sectors = bv->bv_len / bi->sector_size; - sector += sectors; - prot_buf += sectors * bi->tuple_size; - total += sectors * bi->tuple_size; - BUG_ON(total > bio->bi_integrity->bip_size); - - kunmap_atomic(kaddr, KM_USER0); - } - - return ret; -} - -/** - * bio_integrity_verify_fn - Integrity I/O completion worker - * @work: Work struct stored in bio to be verified - * - * Description: This workqueue function is called to complete a READ - * request. The function verifies the transferred integrity metadata - * and then calls the original bio end_io function. - */ -static void bio_integrity_verify_fn(struct work_struct *work) -{ - struct bio_integrity_payload *bip = - container_of(work, struct bio_integrity_payload, bip_work); - struct bio *bio = bip->bip_bio; - int error = bip->bip_error; - - if (bio_integrity_verify(bio)) { - clear_bit(BIO_UPTODATE, &bio->bi_flags); - error = -EIO; - } - - /* Restore original bio completion handler */ - bio->bi_end_io = bip->bip_end_io; - - if (bio->bi_end_io) - bio->bi_end_io(bio, error); -} - -/** - * bio_integrity_endio - Integrity I/O completion function - * @bio: Protected bio - * @error: Pointer to errno - * - * Description: Completion for integrity I/O - * - * Normally I/O completion is done in interrupt context. However, - * verifying I/O integrity is a time-consuming task which must be run - * in process context. This function postpones completion - * accordingly. - */ -void bio_integrity_endio(struct bio *bio, int error) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - - BUG_ON(bip->bip_bio != bio); - - bip->bip_error = error; - INIT_WORK(&bip->bip_work, bio_integrity_verify_fn); - queue_work(kintegrityd_wq, &bip->bip_work); -} -EXPORT_SYMBOL(bio_integrity_endio); - -/** - * bio_integrity_mark_head - Advance bip_vec skip bytes - * @bip: Integrity vector to advance - * @skip: Number of bytes to advance it - */ -void bio_integrity_mark_head(struct bio_integrity_payload *bip, - unsigned int skip) -{ - struct bio_vec *iv; - unsigned int i; - - bip_for_each_vec(iv, bip, i) { - if (skip == 0) { - bip->bip_idx = i; - return; - } else if (skip >= iv->bv_len) { - skip -= iv->bv_len; - } else { /* skip < iv->bv_len) */ - iv->bv_offset += skip; - iv->bv_len -= skip; - bip->bip_idx = i; - return; - } - } -} - -/** - * bio_integrity_mark_tail - Truncate bip_vec to be len bytes long - * @bip: Integrity vector to truncate - * @len: New length of integrity vector - */ -void bio_integrity_mark_tail(struct bio_integrity_payload *bip, - unsigned int len) -{ - struct bio_vec *iv; - unsigned int i; - - bip_for_each_vec(iv, bip, i) { - if (len == 0) { - bip->bip_vcnt = i; - return; - } else if (len >= iv->bv_len) { - len -= iv->bv_len; - } else { /* len < iv->bv_len) */ - iv->bv_len = len; - len = 0; - } - } -} - -/** - * bio_integrity_advance - Advance integrity vector - * @bio: bio whose integrity vector to update - * @bytes_done: number of data bytes that have been completed - * - * Description: This function calculates how many integrity bytes the - * number of completed data bytes correspond to and advances the - * integrity vector accordingly. - */ -void bio_integrity_advance(struct bio *bio, unsigned int bytes_done) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; - - BUG_ON(bip == NULL); - BUG_ON(bi == NULL); - - nr_sectors = bio_integrity_hw_sectors(bi, bytes_done >> 9); - bio_integrity_mark_head(bip, nr_sectors * bi->tuple_size); -} -EXPORT_SYMBOL(bio_integrity_advance); - -/** - * bio_integrity_trim - Trim integrity vector - * @bio: bio whose integrity vector to update - * @offset: offset to first data sector - * @sectors: number of data sectors - * - * Description: Used to trim the integrity vector in a cloned bio. - * The ivec will be advanced corresponding to 'offset' data sectors - * and the length will be truncated corresponding to 'len' data - * sectors. - */ -void bio_integrity_trim(struct bio *bio, unsigned int offset, - unsigned int sectors) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; - - BUG_ON(bip == NULL); - BUG_ON(bi == NULL); - BUG_ON(!bio_flagged(bio, BIO_CLONED)); - - nr_sectors = bio_integrity_hw_sectors(bi, sectors); - bip->bip_sector = bip->bip_sector + offset; - bio_integrity_mark_head(bip, offset * bi->tuple_size); - bio_integrity_mark_tail(bip, sectors * bi->tuple_size); -} -EXPORT_SYMBOL(bio_integrity_trim); - -/** - * bio_integrity_split - Split integrity metadata - * @bio: Protected bio - * @bp: Resulting bio_pair - * @sectors: Offset - * - * Description: Splits an integrity page into a bio_pair. - */ -void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) -{ - struct blk_integrity *bi; - struct bio_integrity_payload *bip = bio->bi_integrity; - unsigned int nr_sectors; - - if (bio_integrity(bio) == 0) - return; - - bi = bdev_get_integrity(bio->bi_bdev); - BUG_ON(bi == NULL); - BUG_ON(bip->bip_vcnt != 1); - - nr_sectors = bio_integrity_hw_sectors(bi, sectors); - - bp->bio1.bi_integrity = &bp->bip1; - bp->bio2.bi_integrity = &bp->bip2; - - bp->iv1 = bip->bip_vec[0]; - bp->iv2 = bip->bip_vec[0]; - - bp->bip1.bip_vec = &bp->iv1; - bp->bip2.bip_vec = &bp->iv2; - - bp->iv1.bv_len = sectors * bi->tuple_size; - bp->iv2.bv_offset += sectors * bi->tuple_size; - bp->iv2.bv_len -= sectors * bi->tuple_size; - - bp->bip1.bip_sector = bio->bi_integrity->bip_sector; - bp->bip2.bip_sector = bio->bi_integrity->bip_sector + nr_sectors; - - bp->bip1.bip_vcnt = bp->bip2.bip_vcnt = 1; - bp->bip1.bip_idx = bp->bip2.bip_idx = 0; -} -EXPORT_SYMBOL(bio_integrity_split); - -/** - * bio_integrity_clone - Callback for cloning bios with integrity metadata - * @bio: New bio - * @bio_src: Original bio - * @bs: bio_set to allocate bip from - * - * Description: Called to allocate a bip when cloning a bio - */ -int bio_integrity_clone(struct bio *bio, struct bio *bio_src, - struct bio_set *bs) -{ - struct bio_integrity_payload *bip_src = bio_src->bi_integrity; - struct bio_integrity_payload *bip; - - BUG_ON(bip_src == NULL); - - bip = bio_integrity_alloc_bioset(bio, GFP_NOIO, bip_src->bip_vcnt, bs); - - if (bip == NULL) - return -EIO; - - memcpy(bip->bip_vec, bip_src->bip_vec, - bip_src->bip_vcnt * sizeof(struct bio_vec)); - - bip->bip_sector = bip_src->bip_sector; - bip->bip_vcnt = bip_src->bip_vcnt; - bip->bip_idx = bip_src->bip_idx; - - return 0; -} -EXPORT_SYMBOL(bio_integrity_clone); - -int bioset_integrity_create(struct bio_set *bs, int pool_size) -{ - bs->bio_integrity_pool = mempool_create_slab_pool(pool_size, - bio_integrity_slab); - if (!bs->bio_integrity_pool) - return -1; - - return 0; -} -EXPORT_SYMBOL(bioset_integrity_create); - -void bioset_integrity_free(struct bio_set *bs) -{ - if (bs->bio_integrity_pool) - mempool_destroy(bs->bio_integrity_pool); -} -EXPORT_SYMBOL(bioset_integrity_free); - -void __init bio_integrity_init_slab(void) -{ - bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, - SLAB_HWCACHE_ALIGN|SLAB_PANIC); -} -EXPORT_SYMBOL(bio_integrity_init_slab); - -static int __init integrity_init(void) -{ - kintegrityd_wq = create_workqueue("kintegrityd"); - - if (!kintegrityd_wq) - panic("Failed to create kintegrityd\n"); - - return 0; -} -subsys_initcall(integrity_init); diff --git a/trunk/fs/bio.c b/trunk/fs/bio.c index 88322b066acb..78562574cb52 100644 --- a/trunk/fs/bio.c +++ b/trunk/fs/bio.c @@ -28,10 +28,25 @@ #include #include /* for struct sg_iovec */ +#define BIO_POOL_SIZE 2 + static struct kmem_cache *bio_slab __read_mostly; +#define BIOVEC_NR_POOLS 6 + +/* + * a small number of entries is fine, not going to be performance critical. + * basically we just need to survive + */ +#define BIO_SPLIT_ENTRIES 2 mempool_t *bio_split_pool __read_mostly; +struct biovec_slab { + int nr_vecs; + char *name; + struct kmem_cache *slab; +}; + /* * if you change this list, also change bvec_alloc or things will * break badly! cannot be bigger than what you can fit into an @@ -44,18 +59,24 @@ static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = { }; #undef BV +/* + * bio_set is used to allow other portions of the IO system to + * allocate their own private memory pools for bio and iovec structures. + * These memory pools in turn all allocate from the bio_slab + * and the bvec_slabs[]. + */ +struct bio_set { + mempool_t *bio_pool; + mempool_t *bvec_pools[BIOVEC_NR_POOLS]; +}; + /* * fs_bio_set is the bio_set containing bio and iovec memory pools used by * IO code that does not need private memory pools. */ -struct bio_set *fs_bio_set; - -unsigned int bvec_nr_vecs(unsigned short idx) -{ - return bvec_slabs[idx].nr_vecs; -} +static struct bio_set *fs_bio_set; -struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs) +static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs) { struct bio_vec *bvl; @@ -96,9 +117,6 @@ void bio_free(struct bio *bio, struct bio_set *bio_set) mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]); } - if (bio_integrity(bio)) - bio_integrity_free(bio, bio_set); - mempool_free(bio, bio_set->bio_pool); } @@ -257,19 +275,9 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask) { struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set); - if (!b) - return NULL; - - b->bi_destructor = bio_fs_destructor; - __bio_clone(b, bio); - - if (bio_integrity(bio)) { - int ret; - - ret = bio_integrity_clone(b, bio, fs_bio_set); - - if (ret < 0) - return NULL; + if (b) { + b->bi_destructor = bio_fs_destructor; + __bio_clone(b, bio); } return b; @@ -325,19 +333,10 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page if (page == prev->bv_page && offset == prev->bv_offset + prev->bv_len) { prev->bv_len += len; - - if (q->merge_bvec_fn) { - struct bvec_merge_data bvm = { - .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size, - .bi_rw = bio->bi_rw, - }; - - if (q->merge_bvec_fn(q, &bvm, prev) < len) { - prev->bv_len -= len; - return 0; - } + if (q->merge_bvec_fn && + q->merge_bvec_fn(q, bio, prev) < len) { + prev->bv_len -= len; + return 0; } goto done; @@ -378,18 +377,11 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page * queue to get further control */ if (q->merge_bvec_fn) { - struct bvec_merge_data bvm = { - .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size, - .bi_rw = bio->bi_rw, - }; - /* * merge_bvec_fn() returns number of bytes it can accept * at this offset */ - if (q->merge_bvec_fn(q, &bvm, bvec) < len) { + if (q->merge_bvec_fn(q, bio, bvec) < len) { bvec->bv_page = NULL; bvec->bv_len = 0; bvec->bv_offset = 0; @@ -1257,9 +1249,6 @@ struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors) bp->bio1.bi_private = bi; bp->bio2.bi_private = pool; - if (bio_integrity(bi)) - bio_integrity_split(bi, bp, first_sectors); - return bp; } @@ -1301,7 +1290,6 @@ void bioset_free(struct bio_set *bs) if (bs->bio_pool) mempool_destroy(bs->bio_pool); - bioset_integrity_free(bs); biovec_free_pools(bs); kfree(bs); @@ -1318,9 +1306,6 @@ struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size) if (!bs->bio_pool) goto bad; - if (bioset_integrity_create(bs, bio_pool_size)) - goto bad; - if (!biovec_create_pools(bs, bvec_pool_size)) return bs; @@ -1347,7 +1332,6 @@ static int __init init_bio(void) { bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC); - bio_integrity_init_slab(); biovec_init_slabs(); fs_bio_set = bioset_create(BIO_POOL_SIZE, 2); diff --git a/trunk/fs/ramfs/file-mmu.c b/trunk/fs/ramfs/file-mmu.c index 78f613cb9c76..9590b9024300 100644 --- a/trunk/fs/ramfs/file-mmu.c +++ b/trunk/fs/ramfs/file-mmu.c @@ -45,7 +45,6 @@ const struct file_operations ramfs_file_operations = { .mmap = generic_file_mmap, .fsync = simple_sync_file, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, .llseek = generic_file_llseek, }; diff --git a/trunk/fs/ramfs/file-nommu.c b/trunk/fs/ramfs/file-nommu.c index 52312ec93ff4..0989bc2c2f69 100644 --- a/trunk/fs/ramfs/file-nommu.c +++ b/trunk/fs/ramfs/file-nommu.c @@ -43,7 +43,6 @@ const struct file_operations ramfs_file_operations = { .aio_write = generic_file_aio_write, .fsync = simple_sync_file, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, .llseek = generic_file_llseek, }; diff --git a/trunk/fs/splice.c b/trunk/fs/splice.c index 399442179d89..aa5f6f60b305 100644 --- a/trunk/fs/splice.c +++ b/trunk/fs/splice.c @@ -379,22 +379,13 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, lock_page(page); /* - * Page was truncated, or invalidated by the - * filesystem. Redo the find/create, but this time the - * page is kept locked, so there's no chance of another - * race with truncate/invalidate. + * page was truncated, stop here. if this isn't the + * first page, we'll just complete what we already + * added */ if (!page->mapping) { unlock_page(page); - page = find_or_create_page(mapping, index, - mapping_gfp_mask(mapping)); - - if (!page) { - error = -ENOMEM; - break; - } - page_cache_release(pages[page_nr]); - pages[page_nr] = page; + break; } /* * page was already under io and is now done, great diff --git a/trunk/include/Kbuild b/trunk/include/Kbuild index bdca155028ec..b52288774345 100644 --- a/trunk/include/Kbuild +++ b/trunk/include/Kbuild @@ -4,6 +4,5 @@ header-y += sound/ header-y += mtd/ header-y += rdma/ header-y += video/ -header-y += drm/ header-y += asm-$(ARCH)/ diff --git a/trunk/include/asm-mips/mach-au1x00/au1xxx_psc.h b/trunk/include/asm-mips/mach-au1x00/au1xxx_psc.h index 892b7f168eb4..dae4eca2417e 100644 --- a/trunk/include/asm-mips/mach-au1x00/au1xxx_psc.h +++ b/trunk/include/asm-mips/mach-au1x00/au1xxx_psc.h @@ -204,14 +204,6 @@ typedef struct psc_i2s { u32 psc_i2sudf; } psc_i2s_t; -#define PSC_I2SCFG_OFFSET 0x08 -#define PSC_I2SMASK_OFFSET 0x0C -#define PSC_I2SPCR_OFFSET 0x10 -#define PSC_I2SSTAT_OFFSET 0x14 -#define PSC_I2SEVENT_OFFSET 0x18 -#define PSC_I2SRXTX_OFFSET 0x1C -#define PSC_I2SUDF_OFFSET 0x20 - /* I2S Config Register. */ #define PSC_I2SCFG_RT_MASK (3 << 30) #define PSC_I2SCFG_RT_FIFO1 (0 << 30) diff --git a/trunk/include/asm-s390/Kbuild b/trunk/include/asm-s390/Kbuild index 09f312501eb5..13c9805349f1 100644 --- a/trunk/include/asm-s390/Kbuild +++ b/trunk/include/asm-s390/Kbuild @@ -8,9 +8,6 @@ header-y += ucontext.h header-y += vtoc.h header-y += zcrypt.h header-y += kvm.h -header-y += schid.h -header-y += chsc.h unifdef-y += cmb.h unifdef-y += debug.h -unifdef-y += chpid.h diff --git a/trunk/include/asm-s390/airq.h b/trunk/include/asm-s390/airq.h index 1ac80d6b0588..41d028cb52a4 100644 --- a/trunk/include/asm-s390/airq.h +++ b/trunk/include/asm-s390/airq.h @@ -13,7 +13,7 @@ typedef void (*adapter_int_handler_t)(void *, void *); -void *s390_register_adapter_interrupt(adapter_int_handler_t, void *, u8); -void s390_unregister_adapter_interrupt(void *, u8); +void *s390_register_adapter_interrupt(adapter_int_handler_t, void *); +void s390_unregister_adapter_interrupt(void *); #endif /* _ASM_S390_AIRQ_H */ diff --git a/trunk/include/asm-s390/ccwdev.h b/trunk/include/asm-s390/ccwdev.h index ba007d8df941..066aa70518ce 100644 --- a/trunk/include/asm-s390/ccwdev.h +++ b/trunk/include/asm-s390/ccwdev.h @@ -12,7 +12,6 @@ #include #include -#include /* structs from asm/cio.h */ struct irb; @@ -158,17 +157,6 @@ extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *, extern int ccw_device_resume(struct ccw_device *); extern int ccw_device_halt(struct ccw_device *, unsigned long); extern int ccw_device_clear(struct ccw_device *, unsigned long); -int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key); -int ccw_device_tm_start_key(struct ccw_device *, struct tcw *, - unsigned long, u8, u8); -int ccw_device_tm_start_timeout_key(struct ccw_device *, struct tcw *, - unsigned long, u8, u8, int); -int ccw_device_tm_start(struct ccw_device *, struct tcw *, - unsigned long, u8); -int ccw_device_tm_start_timeout(struct ccw_device *, struct tcw *, - unsigned long, u8, int); -int ccw_device_tm_intrg(struct ccw_device *cdev); extern int ccw_device_set_online(struct ccw_device *cdev); extern int ccw_device_set_offline(struct ccw_device *cdev); diff --git a/trunk/include/asm-s390/chpid.h b/trunk/include/asm-s390/chpid.h index 606844d0a5c3..b203336fd892 100644 --- a/trunk/include/asm-s390/chpid.h +++ b/trunk/include/asm-s390/chpid.h @@ -10,6 +10,7 @@ #include #include +#include #define __MAX_CHPID 255 @@ -40,9 +41,6 @@ static inline void chp_id_next(struct chp_id *chpid) } } -#ifdef __KERNEL__ -#include - static inline int chp_id_is_valid(struct chp_id *chpid) { return (chpid->cssid <= __MAX_CSSID); @@ -51,6 +49,5 @@ static inline int chp_id_is_valid(struct chp_id *chpid) #define chp_id_for_each(c) \ for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c)) -#endif /* __KERNEL */ #endif /* _ASM_S390_CHPID_H */ diff --git a/trunk/include/asm-s390/chsc.h b/trunk/include/asm-s390/chsc.h deleted file mode 100644 index d38d0cf62d4b..000000000000 --- a/trunk/include/asm-s390/chsc.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ioctl interface for /dev/chsc - * - * Copyright 2008 IBM Corp. - * Author(s): Cornelia Huck - */ - -#ifndef _ASM_CHSC_H -#define _ASM_CHSC_H - -#include -#include - -struct chsc_async_header { - __u16 length; - __u16 code; - __u32 cmd_dependend; - __u32 key : 4; - __u32 : 28; - struct subchannel_id sid; -} __attribute__ ((packed)); - -struct chsc_async_area { - struct chsc_async_header header; - __u8 data[PAGE_SIZE - 16 /* size of chsc_async_header */]; -} __attribute__ ((packed)); - - -struct chsc_response_struct { - __u16 length; - __u16 code; - __u32 parms; - __u8 data[PAGE_SIZE - 8]; -} __attribute__ ((packed)); - -struct chsc_chp_cd { - struct chp_id chpid; - int m; - int fmt; - struct chsc_response_struct cpcb; -}; - -struct chsc_cu_cd { - __u16 cun; - __u8 cssid; - int m; - int fmt; - struct chsc_response_struct cucb; -}; - -struct chsc_sch_cud { - struct subchannel_id schid; - int fmt; - struct chsc_response_struct scub; -}; - -struct conf_id { - int m; - __u8 cssid; - __u8 ssid; -}; - -struct chsc_conf_info { - struct conf_id id; - int fmt; - struct chsc_response_struct scid; -}; - -struct ccl_parm_chpid { - int m; - struct chp_id chp; -}; - -struct ccl_parm_cssids { - __u8 f_cssid; - __u8 l_cssid; -}; - -struct chsc_comp_list { - struct { - enum { - CCL_CU_ON_CHP = 1, - CCL_CHP_TYPE_CAP = 2, - CCL_CSS_IMG = 4, - CCL_CSS_IMG_CONF_CHAR = 5, - CCL_IOP_CHP = 6, - } ctype; - int fmt; - struct ccl_parm_chpid chpid; - struct ccl_parm_cssids cssids; - } req; - struct chsc_response_struct sccl; -}; - -struct chsc_dcal { - struct { - enum { - DCAL_CSS_IID_PN = 4, - } atype; - __u32 list_parm[2]; - int fmt; - } req; - struct chsc_response_struct sdcal; -}; - -struct chsc_cpd_info { - struct chp_id chpid; - int m; - int fmt; - int rfmt; - int c; - struct chsc_response_struct chpdb; -}; - -#define CHSC_IOCTL_MAGIC 'c' - -#define CHSC_START _IOWR(CHSC_IOCTL_MAGIC, 0x81, struct chsc_async_area) -#define CHSC_INFO_CHANNEL_PATH _IOWR(CHSC_IOCTL_MAGIC, 0x82, \ - struct chsc_chp_cd) -#define CHSC_INFO_CU _IOWR(CHSC_IOCTL_MAGIC, 0x83, struct chsc_cu_cd) -#define CHSC_INFO_SCH_CU _IOWR(CHSC_IOCTL_MAGIC, 0x84, struct chsc_sch_cud) -#define CHSC_INFO_CI _IOWR(CHSC_IOCTL_MAGIC, 0x85, struct chsc_conf_info) -#define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list) -#define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) -#define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) - -#endif diff --git a/trunk/include/asm-s390/cio.h b/trunk/include/asm-s390/cio.h index 6dccb071aec3..0818ecd30ca6 100644 --- a/trunk/include/asm-s390/cio.h +++ b/trunk/include/asm-s390/cio.h @@ -16,7 +16,7 @@ #define __MAX_CSSID 0 /** - * struct cmd_scsw - command-mode subchannel status word + * struct scsw - subchannel status word * @key: subchannel key * @sctl: suspend control * @eswf: esw format @@ -38,7 +38,7 @@ * @cstat: subchannel status * @count: residual count */ -struct cmd_scsw { +struct scsw { __u32 key : 4; __u32 sctl : 1; __u32 eswf : 1; @@ -61,114 +61,6 @@ struct cmd_scsw { __u32 count : 16; } __attribute__ ((packed)); -/** - * struct tm_scsw - transport-mode subchannel status word - * @key: subchannel key - * @eswf: esw format - * @cc: deferred condition code - * @fmt: format - * @x: IRB-format control - * @q: interrogate-complete - * @ectl: extended control - * @pno: path not operational - * @fctl: function control - * @actl: activity control - * @stctl: status control - * @tcw: TCW address - * @dstat: device status - * @cstat: subchannel status - * @fcxs: FCX status - * @schxs: subchannel-extended status - */ -struct tm_scsw { - u32 key:4; - u32 :1; - u32 eswf:1; - u32 cc:2; - u32 fmt:3; - u32 x:1; - u32 q:1; - u32 :1; - u32 ectl:1; - u32 pno:1; - u32 :1; - u32 fctl:3; - u32 actl:7; - u32 stctl:5; - u32 tcw; - u32 dstat:8; - u32 cstat:8; - u32 fcxs:8; - u32 schxs:8; -} __attribute__ ((packed)); - -/** - * union scsw - subchannel status word - * @cmd: command-mode SCSW - * @tm: transport-mode SCSW - */ -union scsw { - struct cmd_scsw cmd; - struct tm_scsw tm; -} __attribute__ ((packed)); - -int scsw_is_tm(union scsw *scsw); -u32 scsw_key(union scsw *scsw); -u32 scsw_eswf(union scsw *scsw); -u32 scsw_cc(union scsw *scsw); -u32 scsw_ectl(union scsw *scsw); -u32 scsw_pno(union scsw *scsw); -u32 scsw_fctl(union scsw *scsw); -u32 scsw_actl(union scsw *scsw); -u32 scsw_stctl(union scsw *scsw); -u32 scsw_dstat(union scsw *scsw); -u32 scsw_cstat(union scsw *scsw); -int scsw_is_solicited(union scsw *scsw); -int scsw_is_valid_key(union scsw *scsw); -int scsw_is_valid_eswf(union scsw *scsw); -int scsw_is_valid_cc(union scsw *scsw); -int scsw_is_valid_ectl(union scsw *scsw); -int scsw_is_valid_pno(union scsw *scsw); -int scsw_is_valid_fctl(union scsw *scsw); -int scsw_is_valid_actl(union scsw *scsw); -int scsw_is_valid_stctl(union scsw *scsw); -int scsw_is_valid_dstat(union scsw *scsw); -int scsw_is_valid_cstat(union scsw *scsw); -int scsw_cmd_is_valid_key(union scsw *scsw); -int scsw_cmd_is_valid_sctl(union scsw *scsw); -int scsw_cmd_is_valid_eswf(union scsw *scsw); -int scsw_cmd_is_valid_cc(union scsw *scsw); -int scsw_cmd_is_valid_fmt(union scsw *scsw); -int scsw_cmd_is_valid_pfch(union scsw *scsw); -int scsw_cmd_is_valid_isic(union scsw *scsw); -int scsw_cmd_is_valid_alcc(union scsw *scsw); -int scsw_cmd_is_valid_ssi(union scsw *scsw); -int scsw_cmd_is_valid_zcc(union scsw *scsw); -int scsw_cmd_is_valid_ectl(union scsw *scsw); -int scsw_cmd_is_valid_pno(union scsw *scsw); -int scsw_cmd_is_valid_fctl(union scsw *scsw); -int scsw_cmd_is_valid_actl(union scsw *scsw); -int scsw_cmd_is_valid_stctl(union scsw *scsw); -int scsw_cmd_is_valid_dstat(union scsw *scsw); -int scsw_cmd_is_valid_cstat(union scsw *scsw); -int scsw_cmd_is_solicited(union scsw *scsw); -int scsw_tm_is_valid_key(union scsw *scsw); -int scsw_tm_is_valid_eswf(union scsw *scsw); -int scsw_tm_is_valid_cc(union scsw *scsw); -int scsw_tm_is_valid_fmt(union scsw *scsw); -int scsw_tm_is_valid_x(union scsw *scsw); -int scsw_tm_is_valid_q(union scsw *scsw); -int scsw_tm_is_valid_ectl(union scsw *scsw); -int scsw_tm_is_valid_pno(union scsw *scsw); -int scsw_tm_is_valid_fctl(union scsw *scsw); -int scsw_tm_is_valid_actl(union scsw *scsw); -int scsw_tm_is_valid_stctl(union scsw *scsw); -int scsw_tm_is_valid_dstat(union scsw *scsw); -int scsw_tm_is_valid_cstat(union scsw *scsw); -int scsw_tm_is_valid_fcxs(union scsw *scsw); -int scsw_tm_is_valid_schxs(union scsw *scsw); -int scsw_tm_is_solicited(union scsw *scsw); - #define SCSW_FCTL_CLEAR_FUNC 0x1 #define SCSW_FCTL_HALT_FUNC 0x2 #define SCSW_FCTL_START_FUNC 0x4 @@ -411,7 +303,7 @@ struct esw3 { * if applicable). */ struct irb { - union scsw scsw; + struct scsw scsw; union { struct esw0 esw0; struct esw1 esw1; diff --git a/trunk/include/asm-s390/elf.h b/trunk/include/asm-s390/elf.h index 3cad56923815..b3ac262c4582 100644 --- a/trunk/include/asm-s390/elf.h +++ b/trunk/include/asm-s390/elf.h @@ -113,9 +113,6 @@ typedef s390_fp_regs elf_fpregset_t; typedef s390_regs elf_gregset_t; -typedef s390_fp_regs compat_elf_fpregset_t; -typedef s390_compat_regs compat_elf_gregset_t; - #include /* for task_struct */ #include /* for save_access_regs */ #include @@ -126,10 +123,6 @@ typedef s390_compat_regs compat_elf_gregset_t; #define elf_check_arch(x) \ (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ && (x)->e_ident[EI_CLASS] == ELF_CLASS) -#define compat_elf_check_arch(x) \ - (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ - && (x)->e_ident[EI_CLASS] == ELF_CLASS) -#define compat_start_thread start_thread31 /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ @@ -138,7 +131,6 @@ typedef s390_compat_regs compat_elf_gregset_t; _r->gprs[14] = 0; \ } while (0) -#define CORE_DUMP_USE_REGSET #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -148,6 +140,44 @@ typedef s390_compat_regs compat_elf_gregset_t; that it will "exec", and that there is sufficient room for the brk. */ #define ELF_ET_DYN_BASE (STACK_TOP / 3 * 2) +/* Wow, the "main" arch needs arch dependent functions too.. :) */ + +/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is + now struct_user_regs, they are different) */ + +static inline int dump_regs(struct pt_regs *ptregs, elf_gregset_t *regs) +{ + memcpy(®s->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs)); + save_access_regs(regs->acrs); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs(regs, &pr_reg); + +static inline int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) +{ + struct pt_regs *ptregs = task_pt_regs(tsk); + memcpy(®s->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs)); + memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs)); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs(tsk, regs) + +static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +{ + if (tsk == current) + save_fp_regs(fpregs); + else + memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t)); + return 1; +} + +#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs) + + /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ @@ -174,10 +204,7 @@ do { \ set_personality(PER_SVR4); \ else if (current->personality != PER_LINUX32) \ set_personality(PER_LINUX); \ - if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ - set_thread_flag(TIF_31BIT); \ - else \ - clear_thread_flag(TIF_31BIT); \ + clear_thread_flag(TIF_31BIT); \ } while (0) #endif /* __s390x__ */ diff --git a/trunk/include/asm-s390/etr.h b/trunk/include/asm-s390/etr.h index 80ef58c61970..b498f19bb9a7 100644 --- a/trunk/include/asm-s390/etr.h +++ b/trunk/include/asm-s390/etr.h @@ -122,7 +122,7 @@ struct etr_aib { } __attribute__ ((packed,aligned(8))); /* ETR interruption parameter */ -struct etr_irq_parm { +struct etr_interruption_parameter { unsigned int _pad0 : 8; unsigned int pc0 : 1; /* port 0 state change */ unsigned int pc1 : 1; /* port 1 state change */ @@ -213,46 +213,7 @@ static inline int etr_ptff(void *ptff_block, unsigned int func) #define ETR_PTFF_SGS 0x43 /* set gross steering rate */ /* Functions needed by the machine check handler */ -void etr_switch_to_local(void); -void etr_sync_check(void); - -/* STP interruption parameter */ -struct stp_irq_parm { - unsigned int _pad0 : 14; - unsigned int tsc : 1; /* Timing status change */ - unsigned int lac : 1; /* Link availability change */ - unsigned int tcpc : 1; /* Time control parameter change */ - unsigned int _pad2 : 15; -} __attribute__ ((packed)); - -#define STP_OP_SYNC 1 -#define STP_OP_CTRL 3 - -struct stp_sstpi { - unsigned int rsvd0; - unsigned int rsvd1 : 8; - unsigned int stratum : 8; - unsigned int vbits : 16; - unsigned int leaps : 16; - unsigned int tmd : 4; - unsigned int ctn : 4; - unsigned int rsvd2 : 3; - unsigned int c : 1; - unsigned int tst : 4; - unsigned int tzo : 16; - unsigned int dsto : 16; - unsigned int ctrl : 16; - unsigned int rsvd3 : 16; - unsigned int tto; - unsigned int rsvd4; - unsigned int ctnid[3]; - unsigned int rsvd5; - unsigned int todoff[4]; - unsigned int rsvd6[48]; -} __attribute__ ((packed)); - -/* Functions needed by the machine check handler */ -void stp_sync_check(void); -void stp_island_check(void); +extern void etr_switch_to_local(void); +extern void etr_sync_check(void); #endif /* __S390_ETR_H */ diff --git a/trunk/include/asm-s390/fcx.h b/trunk/include/asm-s390/fcx.h deleted file mode 100644 index 8be1f3a58042..000000000000 --- a/trunk/include/asm-s390/fcx.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Functions for assembling fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#ifndef _ASM_S390_FCX_H -#define _ASM_S390_FCX_H _ASM_S390_FCX_H - -#include - -#define TCW_FORMAT_DEFAULT 0 -#define TCW_TIDAW_FORMAT_DEFAULT 0 -#define TCW_FLAGS_INPUT_TIDA 1 << (23 - 5) -#define TCW_FLAGS_TCCB_TIDA 1 << (23 - 6) -#define TCW_FLAGS_OUTPUT_TIDA 1 << (23 - 7) -#define TCW_FLAGS_TIDAW_FORMAT(x) ((x) & 3) << (23 - 9) -#define TCW_FLAGS_GET_TIDAW_FORMAT(x) (((x) >> (23 - 9)) & 3) - -/** - * struct tcw - Transport Control Word (TCW) - * @format: TCW format - * @flags: TCW flags - * @tccbl: Transport-Command-Control-Block Length - * @r: Read Operations - * @w: Write Operations - * @output: Output-Data Address - * @input: Input-Data Address - * @tsb: Transport-Status-Block Address - * @tccb: Transport-Command-Control-Block Address - * @output_count: Output Count - * @input_count: Input Count - * @intrg: Interrogate TCW Address - */ -struct tcw { - u32 format:2; - u32 :6; - u32 flags:24; - u32 :8; - u32 tccbl:6; - u32 r:1; - u32 w:1; - u32 :16; - u64 output; - u64 input; - u64 tsb; - u64 tccb; - u32 output_count; - u32 input_count; - u32 :32; - u32 :32; - u32 :32; - u32 intrg; -} __attribute__ ((packed, aligned(64))); - -#define TIDAW_FLAGS_LAST 1 << (7 - 0) -#define TIDAW_FLAGS_SKIP 1 << (7 - 1) -#define TIDAW_FLAGS_DATA_INT 1 << (7 - 2) -#define TIDAW_FLAGS_TTIC 1 << (7 - 3) -#define TIDAW_FLAGS_INSERT_CBC 1 << (7 - 4) - -/** - * struct tidaw - Transport-Indirect-Addressing Word (TIDAW) - * @flags: TIDAW flags. Can be an arithmetic OR of the following constants: - * %TIDAW_FLAGS_LAST, %TIDAW_FLAGS_SKIP, %TIDAW_FLAGS_DATA_INT, - * %TIDAW_FLAGS_TTIC, %TIDAW_FLAGS_INSERT_CBC - * @count: Count - * @addr: Address - */ -struct tidaw { - u32 flags:8; - u32 :24; - u32 count; - u64 addr; -} __attribute__ ((packed, aligned(16))); - -/** - * struct tsa_iostat - I/O-Status Transport-Status Area (IO-Stat TSA) - * @dev_time: Device Time - * @def_time: Defer Time - * @queue_time: Queue Time - * @dev_busy_time: Device-Busy Time - * @dev_act_time: Device-Active-Only Time - * @sense: Sense Data (if present) - */ -struct tsa_iostat { - u32 dev_time; - u32 def_time; - u32 queue_time; - u32 dev_busy_time; - u32 dev_act_time; - u8 sense[32]; -} __attribute__ ((packed)); - -/** - * struct tsa_ddpcs - Device-Detected-Program-Check Transport-Status Area (DDPC TSA) - * @rc: Reason Code - * @rcq: Reason Code Qualifier - * @sense: Sense Data (if present) - */ -struct tsa_ddpc { - u32 :24; - u32 rc:8; - u8 rcq[16]; - u8 sense[32]; -} __attribute__ ((packed)); - -#define TSA_INTRG_FLAGS_CU_STATE_VALID 1 << (7 - 0) -#define TSA_INTRG_FLAGS_DEV_STATE_VALID 1 << (7 - 1) -#define TSA_INTRG_FLAGS_OP_STATE_VALID 1 << (7 - 2) - -/** - * struct tsa_intrg - Interrogate Transport-Status Area (Intrg. TSA) - * @format: Format - * @flags: Flags. Can be an arithmetic OR of the following constants: - * %TSA_INTRG_FLAGS_CU_STATE_VALID, %TSA_INTRG_FLAGS_DEV_STATE_VALID, - * %TSA_INTRG_FLAGS_OP_STATE_VALID - * @cu_state: Controle-Unit State - * @dev_state: Device State - * @op_state: Operation State - * @sd_info: State-Dependent Information - * @dl_id: Device-Level Identifier - * @dd_data: Device-Dependent Data - */ -struct tsa_intrg { - u32 format:8; - u32 flags:8; - u32 cu_state:8; - u32 dev_state:8; - u32 op_state:8; - u32 :24; - u8 sd_info[12]; - u32 dl_id; - u8 dd_data[28]; -} __attribute__ ((packed)); - -#define TSB_FORMAT_NONE 0 -#define TSB_FORMAT_IOSTAT 1 -#define TSB_FORMAT_DDPC 2 -#define TSB_FORMAT_INTRG 3 - -#define TSB_FLAGS_DCW_OFFSET_VALID 1 << (7 - 0) -#define TSB_FLAGS_COUNT_VALID 1 << (7 - 1) -#define TSB_FLAGS_CACHE_MISS 1 << (7 - 2) -#define TSB_FLAGS_TIME_VALID 1 << (7 - 3) -#define TSB_FLAGS_FORMAT(x) ((x) & 7) -#define TSB_FORMAT(t) ((t)->flags & 7) - -/** - * struct tsb - Transport-Status Block (TSB) - * @length: Length - * @flags: Flags. Can be an arithmetic OR of the following constants: - * %TSB_FLAGS_DCW_OFFSET_VALID, %TSB_FLAGS_COUNT_VALID, %TSB_FLAGS_CACHE_MISS, - * %TSB_FLAGS_TIME_VALID - * @dcw_offset: DCW Offset - * @count: Count - * @tsa: Transport-Status-Area - */ -struct tsb { - u32 length:8; - u32 flags:8; - u32 dcw_offset:16; - u32 count; - u32 :32; - union { - struct tsa_iostat iostat; - struct tsa_ddpc ddpc; - struct tsa_intrg intrg; - } __attribute__ ((packed)) tsa; -} __attribute__ ((packed, aligned(8))); - -#define DCW_INTRG_FORMAT_DEFAULT 0 - -#define DCW_INTRG_RC_UNSPECIFIED 0 -#define DCW_INTRG_RC_TIMEOUT 1 - -#define DCW_INTRG_RCQ_UNSPECIFIED 0 -#define DCW_INTRG_RCQ_PRIMARY 1 -#define DCW_INTRG_RCQ_SECONDARY 2 - -#define DCW_INTRG_FLAGS_MPM 1 < (7 - 0) -#define DCW_INTRG_FLAGS_PPR 1 < (7 - 1) -#define DCW_INTRG_FLAGS_CRIT 1 < (7 - 2) - -/** - * struct dcw_intrg_data - Interrogate DCW data - * @format: Format. Should be %DCW_INTRG_FORMAT_DEFAULT - * @rc: Reason Code. Can be one of %DCW_INTRG_RC_UNSPECIFIED, - * %DCW_INTRG_RC_TIMEOUT - * @rcq: Reason Code Qualifier: Can be one of %DCW_INTRG_RCQ_UNSPECIFIED, - * %DCW_INTRG_RCQ_PRIMARY, %DCW_INTRG_RCQ_SECONDARY - * @lpm: Logical-Path Mask - * @pam: Path-Available Mask - * @pim: Path-Installed Mask - * @timeout: Timeout - * @flags: Flags. Can be an arithmetic OR of %DCW_INTRG_FLAGS_MPM, - * %DCW_INTRG_FLAGS_PPR, %DCW_INTRG_FLAGS_CRIT - * @time: Time - * @prog_id: Program Identifier - * @prog_data: Program-Dependent Data - */ -struct dcw_intrg_data { - u32 format:8; - u32 rc:8; - u32 rcq:8; - u32 lpm:8; - u32 pam:8; - u32 pim:8; - u32 timeout:16; - u32 flags:8; - u32 :24; - u32 :32; - u64 time; - u64 prog_id; - u8 prog_data[0]; -} __attribute__ ((packed)); - -#define DCW_FLAGS_CC 1 << (7 - 1) - -#define DCW_CMD_WRITE 0x01 -#define DCW_CMD_READ 0x02 -#define DCW_CMD_CONTROL 0x03 -#define DCW_CMD_SENSE 0x04 -#define DCW_CMD_SENSE_ID 0xe4 -#define DCW_CMD_INTRG 0x40 - -/** - * struct dcw - Device-Command Word (DCW) - * @cmd: Command Code. Can be one of %DCW_CMD_WRITE, %DCW_CMD_READ, - * %DCW_CMD_CONTROL, %DCW_CMD_SENSE, %DCW_CMD_SENSE_ID, %DCW_CMD_INTRG - * @flags: Flags. Can be an arithmetic OR of %DCW_FLAGS_CC - * @cd_count: Control-Data Count - * @count: Count - * @cd: Control Data - */ -struct dcw { - u32 cmd:8; - u32 flags:8; - u32 :8; - u32 cd_count:8; - u32 count; - u8 cd[0]; -} __attribute__ ((packed)); - -#define TCCB_FORMAT_DEFAULT 0x7f -#define TCCB_MAX_DCW 30 -#define TCCB_MAX_SIZE (sizeof(struct tccb_tcah) + \ - TCCB_MAX_DCW * sizeof(struct dcw) + \ - sizeof(struct tccb_tcat)) -#define TCCB_SAC_DEFAULT 0xf901 -#define TCCB_SAC_INTRG 0xf902 - -/** - * struct tccb_tcah - Transport-Command-Area Header (TCAH) - * @format: Format. Should be %TCCB_FORMAT_DEFAULT - * @tcal: Transport-Command-Area Length - * @sac: Service-Action Code. Can be one of %TCCB_SAC_DEFAULT, %TCCB_SAC_INTRG - * @prio: Priority - */ -struct tccb_tcah { - u32 format:8; - u32 :24; - u32 :24; - u32 tcal:8; - u32 sac:16; - u32 :8; - u32 prio:8; - u32 :32; -} __attribute__ ((packed)); - -/** - * struct tccb_tcat - Transport-Command-Area Trailer (TCAT) - * @count: Transport Count - */ -struct tccb_tcat { - u32 :32; - u32 count; -} __attribute__ ((packed)); - -/** - * struct tccb - (partial) Transport-Command-Control Block (TCCB) - * @tcah: TCAH - * @tca: Transport-Command Area - */ -struct tccb { - struct tccb_tcah tcah; - u8 tca[0]; -} __attribute__ ((packed, aligned(8))); - -struct tcw *tcw_get_intrg(struct tcw *tcw); -void *tcw_get_data(struct tcw *tcw); -struct tccb *tcw_get_tccb(struct tcw *tcw); -struct tsb *tcw_get_tsb(struct tcw *tcw); - -void tcw_init(struct tcw *tcw, int r, int w); -void tcw_finalize(struct tcw *tcw, int num_tidaws); - -void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw); -void tcw_set_data(struct tcw *tcw, void *data, int use_tidal); -void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb); -void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb); - -void tccb_init(struct tccb *tccb, size_t tccb_size, u32 sac); -void tsb_init(struct tsb *tsb); -struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags, - void *cd, u8 cd_count, u32 count); -struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags, - void *addr, u32 count); - -#endif /* _ASM_S390_FCX_H */ diff --git a/trunk/include/asm-s390/ipl.h b/trunk/include/asm-s390/ipl.h index eaca6dff5405..c1b2e50392bb 100644 --- a/trunk/include/asm-s390/ipl.h +++ b/trunk/include/asm-s390/ipl.h @@ -56,19 +56,15 @@ struct ipl_block_fcp { u8 scp_data[]; } __attribute__((packed)); -#define DIAG308_VMPARM_SIZE 64 - struct ipl_block_ccw { - u8 load_parm[8]; + u8 load_param[8]; u8 reserved1[84]; u8 reserved2[2]; u16 devno; u8 vm_flags; u8 reserved3[3]; u32 vm_parm_len; - u8 nss_name[8]; - u8 vm_parm[DIAG308_VMPARM_SIZE]; - u8 reserved4[8]; + u8 reserved4[80]; } __attribute__((packed)); struct ipl_parameter_block { @@ -77,7 +73,7 @@ struct ipl_parameter_block { struct ipl_block_fcp fcp; struct ipl_block_ccw ccw; } ipl_info; -} __attribute__((packed,aligned(4096))); +} __attribute__((packed)); /* * IPL validity flags @@ -90,8 +86,6 @@ extern void do_reipl(void); extern void do_halt(void); extern void do_poff(void); extern void ipl_save_parameters(void); -extern void ipl_update_parameters(void); -extern void get_ipl_vmparm(char *); enum { IPL_DEVNO_VALID = 1, @@ -153,11 +147,6 @@ enum diag308_flags { DIAG308_FLAGS_LP_VALID = 0x80, }; -enum diag308_vm_flags { - DIAG308_VM_FLAGS_NSS_VALID = 0x80, - DIAG308_VM_FLAGS_VP_VALID = 0x40, -}; - enum diag308_rc { DIAG308_RC_OK = 1, }; diff --git a/trunk/include/asm-s390/isc.h b/trunk/include/asm-s390/isc.h deleted file mode 100644 index 34bb8916db4f..000000000000 --- a/trunk/include/asm-s390/isc.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _ASM_S390_ISC_H -#define _ASM_S390_ISC_H - -#include - -/* - * I/O interruption subclasses used by drivers. - * Please add all used iscs here so that it is possible to distribute - * isc usage between drivers. - * Reminder: 0 is highest priority, 7 lowest. - */ -#define MAX_ISC 7 - -/* Regular I/O interrupts. */ -#define IO_SCH_ISC 3 /* regular I/O subchannels */ -#define CONSOLE_ISC 1 /* console I/O subchannel */ -#define CHSC_SCH_ISC 7 /* CHSC subchannels */ -/* Adapter interrupts. */ -#define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */ - -/* Functions for registration of I/O interruption subclasses */ -void isc_register(unsigned int isc); -void isc_unregister(unsigned int isc); - -#endif /* _ASM_S390_ISC_H */ diff --git a/trunk/include/asm-s390/itcw.h b/trunk/include/asm-s390/itcw.h deleted file mode 100644 index a9bc5c36b32a..000000000000 --- a/trunk/include/asm-s390/itcw.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Functions for incremental construction of fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#ifndef _ASM_S390_ITCW_H -#define _ASM_S390_ITCW_H _ASM_S390_ITCW_H - -#include -#include - -#define ITCW_OP_READ 0 -#define ITCW_OP_WRITE 1 - -struct itcw; - -struct tcw *itcw_get_tcw(struct itcw *itcw); -size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws); -struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, - int max_tidaws, int intrg_max_tidaws); -struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd, - u8 cd_count, u32 count); -struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, - u32 count); -void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal); -void itcw_finalize(struct itcw *itcw); - -#endif /* _ASM_S390_ITCW_H */ diff --git a/trunk/include/asm-s390/pgtable.h b/trunk/include/asm-s390/pgtable.h index 0bdb704ae051..bd0ea191dfa9 100644 --- a/trunk/include/asm-s390/pgtable.h +++ b/trunk/include/asm-s390/pgtable.h @@ -29,7 +29,6 @@ * the S390 page table tree. */ #ifndef __ASSEMBLY__ -#include #include #include #include diff --git a/trunk/include/asm-s390/processor.h b/trunk/include/asm-s390/processor.h index 4af80af2a88f..a00f79dd323b 100644 --- a/trunk/include/asm-s390/processor.h +++ b/trunk/include/asm-s390/processor.h @@ -143,19 +143,11 @@ struct stack_frame { /* * Do necessary setup to start up a new thread. */ -#define start_thread(regs, new_psw, new_stackp) do { \ +#define start_thread(regs, new_psw, new_stackp) do { \ set_fs(USER_DS); \ regs->psw.mask = psw_user_bits; \ - regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ - regs->gprs[15] = new_stackp; \ -} while (0) - -#define start_thread31(regs, new_psw, new_stackp) do { \ - set_fs(USER_DS); \ - regs->psw.mask = psw_user32_bits; \ - regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ - regs->gprs[15] = new_stackp; \ - crst_table_downgrade(current->mm, 1UL << 31); \ + regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ + regs->gprs[15] = new_stackp ; \ } while (0) /* Forward declaration, a strange C thing */ @@ -336,6 +328,16 @@ extern void (*s390_base_mcck_handler_fn)(void); extern void (*s390_base_pgm_handler_fn)(void); extern void (*s390_base_ext_handler_fn)(void); +/* + * CPU idle notifier chain. + */ +#define S390_CPU_IDLE 0 +#define S390_CPU_NOT_IDLE 1 + +struct notifier_block; +int register_idle_notifier(struct notifier_block *nb); +int unregister_idle_notifier(struct notifier_block *nb); + #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL #endif diff --git a/trunk/include/asm-s390/ptrace.h b/trunk/include/asm-s390/ptrace.h index af2c9ac28a07..d7d4e2eb3e6f 100644 --- a/trunk/include/asm-s390/ptrace.h +++ b/trunk/include/asm-s390/ptrace.h @@ -215,12 +215,6 @@ typedef struct unsigned long addr; } __attribute__ ((aligned(8))) psw_t; -typedef struct -{ - __u32 mask; - __u32 addr; -} __attribute__ ((aligned(8))) psw_compat_t; - #ifndef __s390x__ #define PSW_MASK_PER 0x40000000UL @@ -298,15 +292,6 @@ typedef struct unsigned long orig_gpr2; } s390_regs; -typedef struct -{ - psw_compat_t psw; - __u32 gprs[NUM_GPRS]; - __u32 acrs[NUM_ACRS]; - __u32 orig_gpr2; -} s390_compat_regs; - - #ifdef __KERNEL__ #include #include diff --git a/trunk/include/asm-s390/sclp.h b/trunk/include/asm-s390/sclp.h index fed7bee650a0..b5f2843013a3 100644 --- a/trunk/include/asm-s390/sclp.h +++ b/trunk/include/asm-s390/sclp.h @@ -45,9 +45,9 @@ struct sclp_cpu_info { int sclp_get_cpu_info(struct sclp_cpu_info *info); int sclp_cpu_configure(u8 cpu); int sclp_cpu_deconfigure(u8 cpu); +void sclp_read_info_early(void); void sclp_facilities_detect(void); -unsigned long long sclp_get_rnmax(void); -unsigned long long sclp_get_rzm(void); +unsigned long long sclp_memory_detect(void); int sclp_sdias_blk_count(void); int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); int sclp_chp_configure(struct chp_id chpid); diff --git a/trunk/include/asm-s390/setup.h b/trunk/include/asm-s390/setup.h index f09ee3f72977..ba69674012a7 100644 --- a/trunk/include/asm-s390/setup.h +++ b/trunk/include/asm-s390/setup.h @@ -8,16 +8,14 @@ #ifndef _ASM_S390_SETUP_H #define _ASM_S390_SETUP_H -#define COMMAND_LINE_SIZE 1024 - -#define ARCH_COMMAND_LINE_SIZE 896 +#define COMMAND_LINE_SIZE 896 #ifdef __KERNEL__ #include #define PARMAREA 0x10400 -#define MEMORY_CHUNKS 256 +#define MEMORY_CHUNKS 16 /* max 0x7fff */ #ifndef __ASSEMBLY__ @@ -38,14 +36,12 @@ struct mem_chunk { unsigned long addr; unsigned long size; - int type; + unsigned long type; }; extern struct mem_chunk memory_chunk[]; extern unsigned long real_memory_size; -void detect_memory_layout(struct mem_chunk chunk[]); - #ifdef CONFIG_S390_SWITCH_AMODE extern unsigned int switch_amode; #else @@ -65,6 +61,7 @@ extern unsigned long machine_flags; #define MACHINE_FLAG_VM (1UL << 0) #define MACHINE_FLAG_IEEE (1UL << 1) +#define MACHINE_FLAG_P390 (1UL << 2) #define MACHINE_FLAG_CSP (1UL << 3) #define MACHINE_FLAG_MVPG (1UL << 4) #define MACHINE_FLAG_DIAG44 (1UL << 5) @@ -100,6 +97,7 @@ extern unsigned long machine_flags; #define MACHINE_HAS_PFMF (machine_flags & MACHINE_FLAG_PFMF) #endif /* __s390x__ */ +#define MACHINE_HAS_SCLP (!MACHINE_IS_P390) #define ZFCPDUMP_HSA_SIZE (32UL<<20) /* diff --git a/trunk/include/asm-s390/sparsemem.h b/trunk/include/asm-s390/sparsemem.h index 545d219e6a2d..06dfdab6c0e8 100644 --- a/trunk/include/asm-s390/sparsemem.h +++ b/trunk/include/asm-s390/sparsemem.h @@ -1,15 +1,15 @@ #ifndef _ASM_S390_SPARSEMEM_H #define _ASM_S390_SPARSEMEM_H +#define SECTION_SIZE_BITS 25 + #ifdef CONFIG_64BIT -#define SECTION_SIZE_BITS 28 #define MAX_PHYSADDR_BITS 42 #define MAX_PHYSMEM_BITS 42 #else -#define SECTION_SIZE_BITS 25 #define MAX_PHYSADDR_BITS 31 #define MAX_PHYSMEM_BITS 31 diff --git a/trunk/include/asm-s390/timer.h b/trunk/include/asm-s390/timer.h index d98d79e35cd6..adb34860a543 100644 --- a/trunk/include/asm-s390/timer.h +++ b/trunk/include/asm-s390/timer.h @@ -48,18 +48,6 @@ extern int del_virt_timer(struct vtimer_list *timer); extern void init_cpu_vtimer(void); extern void vtime_init(void); -#ifdef CONFIG_VIRT_TIMER - -extern void vtime_start_cpu_timer(void); -extern void vtime_stop_cpu_timer(void); - -#else - -static inline void vtime_start_cpu_timer(void) { } -static inline void vtime_stop_cpu_timer(void) { } - -#endif /* CONFIG_VIRT_TIMER */ - #endif /* __KERNEL__ */ #endif /* _ASM_S390_TIMER_H */ diff --git a/trunk/include/asm-s390/zcrypt.h b/trunk/include/asm-s390/zcrypt.h index 00d3bbd44117..f228f1b86877 100644 --- a/trunk/include/asm-s390/zcrypt.h +++ b/trunk/include/asm-s390/zcrypt.h @@ -29,7 +29,7 @@ #define ZCRYPT_VERSION 2 #define ZCRYPT_RELEASE 1 -#define ZCRYPT_VARIANT 1 +#define ZCRYPT_VARIANT 0 #include #include diff --git a/trunk/include/drm/Kbuild b/trunk/include/drm/Kbuild deleted file mode 100644 index 82b6983b7fbb..000000000000 --- a/trunk/include/drm/Kbuild +++ /dev/null @@ -1,10 +0,0 @@ -unifdef-y += drm.h drm_sarea.h -unifdef-y += i810_drm.h -unifdef-y += i830_drm.h -unifdef-y += i915_drm.h -unifdef-y += mga_drm.h -unifdef-y += r128_drm.h -unifdef-y += radeon_drm.h -unifdef-y += sis_drm.h -unifdef-y += savage_drm.h -unifdef-y += via_drm.h diff --git a/trunk/include/linux/bio.h b/trunk/include/linux/bio.h index 0933a14e6414..61c15eaf3fb3 100644 --- a/trunk/include/linux/bio.h +++ b/trunk/include/linux/bio.h @@ -64,7 +64,6 @@ struct bio_vec { struct bio_set; struct bio; -struct bio_integrity_payload; typedef void (bio_end_io_t) (struct bio *, int); typedef void (bio_destructor_t) (struct bio *); @@ -113,9 +112,6 @@ struct bio { atomic_t bi_cnt; /* pin count */ void *bi_private; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - struct bio_integrity_payload *bi_integrity; /* data integrity */ -#endif bio_destructor_t *bi_destructor; /* destructor */ }; @@ -275,29 +271,6 @@ static inline void *bio_data(struct bio *bio) */ #define bio_get(bio) atomic_inc(&(bio)->bi_cnt) -#if defined(CONFIG_BLK_DEV_INTEGRITY) -/* - * bio integrity payload - */ -struct bio_integrity_payload { - struct bio *bip_bio; /* parent bio */ - struct bio_vec *bip_vec; /* integrity data vector */ - - sector_t bip_sector; /* virtual start sector */ - - void *bip_buf; /* generated integrity data */ - bio_end_io_t *bip_end_io; /* saved I/O completion fn */ - - int bip_error; /* saved I/O error */ - unsigned int bip_size; - - unsigned short bip_pool; /* pool the ivec came from */ - unsigned short bip_vcnt; /* # of integrity bio_vecs */ - unsigned short bip_idx; /* current bip_vec index */ - - struct work_struct bip_work; /* I/O completion */ -}; -#endif /* CONFIG_BLK_DEV_INTEGRITY */ /* * A bio_pair is used when we need to split a bio. @@ -310,14 +283,10 @@ struct bio_integrity_payload { * in bio2.bi_private */ struct bio_pair { - struct bio bio1, bio2; - struct bio_vec bv1, bv2; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - struct bio_integrity_payload bip1, bip2; - struct bio_vec iv1, iv2; -#endif - atomic_t cnt; - int error; + struct bio bio1, bio2; + struct bio_vec bv1, bv2; + atomic_t cnt; + int error; }; extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors); @@ -364,39 +333,6 @@ extern struct bio *bio_copy_user_iov(struct request_queue *, struct sg_iovec *, int, int); extern int bio_uncopy_user(struct bio *); void zero_fill_bio(struct bio *bio); -extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *); -extern unsigned int bvec_nr_vecs(unsigned short idx); - -/* - * bio_set is used to allow other portions of the IO system to - * allocate their own private memory pools for bio and iovec structures. - * These memory pools in turn all allocate from the bio_slab - * and the bvec_slabs[]. - */ -#define BIO_POOL_SIZE 2 -#define BIOVEC_NR_POOLS 6 - -struct bio_set { - mempool_t *bio_pool; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - mempool_t *bio_integrity_pool; -#endif - mempool_t *bvec_pools[BIOVEC_NR_POOLS]; -}; - -struct biovec_slab { - int nr_vecs; - char *name; - struct kmem_cache *slab; -}; - -extern struct bio_set *fs_bio_set; - -/* - * a small number of entries is fine, not going to be performance critical. - * basically we just need to survive - */ -#define BIO_SPLIT_ENTRIES 2 #ifdef CONFIG_HIGHMEM /* @@ -445,63 +381,5 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, __bio_kmap_irq((bio), (bio)->bi_idx, (flags)) #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -#define bip_vec_idx(bip, idx) (&(bip->bip_vec[(idx)])) -#define bip_vec(bip) bip_vec_idx(bip, 0) - -#define __bip_for_each_vec(bvl, bip, i, start_idx) \ - for (bvl = bip_vec_idx((bip), (start_idx)), i = (start_idx); \ - i < (bip)->bip_vcnt; \ - bvl++, i++) - -#define bip_for_each_vec(bvl, bip, i) \ - __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx) - -static inline int bio_integrity(struct bio *bio) -{ -#if defined(CONFIG_BLK_DEV_INTEGRITY) - return bio->bi_integrity != NULL; -#else - return 0; -#endif -} - -extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *); -extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int); -extern void bio_integrity_free(struct bio *, struct bio_set *); -extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int); -extern int bio_integrity_enabled(struct bio *bio); -extern int bio_integrity_set_tag(struct bio *, void *, unsigned int); -extern int bio_integrity_get_tag(struct bio *, void *, unsigned int); -extern int bio_integrity_prep(struct bio *); -extern void bio_integrity_endio(struct bio *, int); -extern void bio_integrity_advance(struct bio *, unsigned int); -extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); -extern void bio_integrity_split(struct bio *, struct bio_pair *, int); -extern int bio_integrity_clone(struct bio *, struct bio *, struct bio_set *); -extern int bioset_integrity_create(struct bio_set *, int); -extern void bioset_integrity_free(struct bio_set *); -extern void bio_integrity_init_slab(void); - -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -#define bio_integrity(a) (0) -#define bioset_integrity_create(a, b) (0) -#define bio_integrity_prep(a) (0) -#define bio_integrity_enabled(a) (0) -#define bio_integrity_clone(a, b, c) (0) -#define bioset_integrity_free(a) do { } while (0) -#define bio_integrity_free(a, b) do { } while (0) -#define bio_integrity_endio(a, b) do { } while (0) -#define bio_integrity_advance(a, b) do { } while (0) -#define bio_integrity_trim(a, b, c) do { } while (0) -#define bio_integrity_split(a, b, c) do { } while (0) -#define bio_integrity_set_tag(a, b, c) do { } while (0) -#define bio_integrity_get_tag(a, b, c) do { } while (0) -#define bio_integrity_init_slab(a) do { } while (0) - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - #endif /* CONFIG_BLOCK */ #endif /* __LINUX_BIO_H */ diff --git a/trunk/include/linux/blkdev.h b/trunk/include/linux/blkdev.h index 1ffd8bfdc4c9..d2a1b71e93c3 100644 --- a/trunk/include/linux/blkdev.h +++ b/trunk/include/linux/blkdev.h @@ -23,6 +23,7 @@ struct scsi_ioctl_command; struct request_queue; +typedef struct request_queue request_queue_t __deprecated; struct elevator_queue; typedef struct elevator_queue elevator_t; struct request_pm_state; @@ -33,6 +34,12 @@ struct sg_io_hdr; #define BLKDEV_MIN_RQ 4 #define BLKDEV_MAX_RQ 128 /* Default maximum */ +int put_io_context(struct io_context *ioc); +void exit_io_context(void); +struct io_context *get_io_context(gfp_t gfp_flags, int node); +struct io_context *alloc_io_context(gfp_t gfp_flags, int node); +void copy_io_context(struct io_context **pdst, struct io_context **psrc); + struct request; typedef void (rq_end_io_fn)(struct request *, int); @@ -106,7 +113,6 @@ enum rq_flag_bits { __REQ_ALLOCED, /* request came from our alloc pool */ __REQ_RW_META, /* metadata io request */ __REQ_COPY_USER, /* contains copies of user pages */ - __REQ_INTEGRITY, /* integrity metadata has been remapped */ __REQ_NR_BITS, /* stops here */ }; @@ -129,7 +135,6 @@ enum rq_flag_bits { #define REQ_ALLOCED (1 << __REQ_ALLOCED) #define REQ_RW_META (1 << __REQ_RW_META) #define REQ_COPY_USER (1 << __REQ_COPY_USER) -#define REQ_INTEGRITY (1 << __REQ_INTEGRITY) #define BLK_MAX_CDB 16 @@ -254,14 +259,7 @@ typedef int (prep_rq_fn) (struct request_queue *, struct request *); typedef void (unplug_fn) (struct request_queue *); struct bio_vec; -struct bvec_merge_data { - struct block_device *bi_bdev; - sector_t bi_sector; - unsigned bi_size; - unsigned long bi_rw; -}; -typedef int (merge_bvec_fn) (struct request_queue *, struct bvec_merge_data *, - struct bio_vec *); +typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *); typedef void (prepare_flush_fn) (struct request_queue *, struct request *); typedef void (softirq_done_fn)(struct request *); typedef int (dma_drain_needed_fn)(struct request *); @@ -428,32 +426,6 @@ static inline void queue_flag_set_unlocked(unsigned int flag, __set_bit(flag, &q->queue_flags); } -static inline int queue_flag_test_and_clear(unsigned int flag, - struct request_queue *q) -{ - WARN_ON_ONCE(!queue_is_locked(q)); - - if (test_bit(flag, &q->queue_flags)) { - __clear_bit(flag, &q->queue_flags); - return 1; - } - - return 0; -} - -static inline int queue_flag_test_and_set(unsigned int flag, - struct request_queue *q) -{ - WARN_ON_ONCE(!queue_is_locked(q)); - - if (!test_bit(flag, &q->queue_flags)) { - __set_bit(flag, &q->queue_flags); - return 0; - } - - return 1; -} - static inline void queue_flag_set(unsigned int flag, struct request_queue *q) { WARN_ON_ONCE(!queue_is_locked(q)); @@ -704,6 +676,7 @@ extern int blk_execute_rq(struct request_queue *, struct gendisk *, struct request *, int); extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, struct request *, int, rq_end_io_fn *); +extern int blk_verify_command(unsigned char *, int); extern void blk_unplug(struct request_queue *q); static inline struct request_queue *bdev_get_queue(struct block_device *bdev) @@ -776,7 +749,6 @@ extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); extern void blk_queue_hardsect_size(struct request_queue *, unsigned short); extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b); extern void blk_queue_dma_pad(struct request_queue *, unsigned int); -extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int); extern int blk_queue_dma_drain(struct request_queue *q, dma_drain_needed_fn *dma_drain_needed, void *buf, unsigned int size); @@ -830,15 +802,6 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, extern int blkdev_issue_flush(struct block_device *, sector_t *); -/* -* command filter functions -*/ -extern int blk_verify_command(struct file *file, unsigned char *cmd); -extern int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter, - unsigned char *cmd, mode_t *f_mode); -extern int blk_register_filter(struct gendisk *disk); -extern void blk_unregister_filter(struct gendisk *disk); - #define MAX_PHYS_SEGMENTS 128 #define MAX_HW_SEGMENTS 128 #define SAFE_MAX_SECTORS 255 @@ -902,116 +865,28 @@ void kblockd_flush_work(struct work_struct *work); #define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \ MODULE_ALIAS("block-major-" __stringify(major) "-*") -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -#define INTEGRITY_FLAG_READ 2 /* verify data integrity on read */ -#define INTEGRITY_FLAG_WRITE 4 /* generate data integrity on write */ - -struct blk_integrity_exchg { - void *prot_buf; - void *data_buf; - sector_t sector; - unsigned int data_size; - unsigned short sector_size; - const char *disk_name; -}; - -typedef void (integrity_gen_fn) (struct blk_integrity_exchg *); -typedef int (integrity_vrfy_fn) (struct blk_integrity_exchg *); -typedef void (integrity_set_tag_fn) (void *, void *, unsigned int); -typedef void (integrity_get_tag_fn) (void *, void *, unsigned int); - -struct blk_integrity { - integrity_gen_fn *generate_fn; - integrity_vrfy_fn *verify_fn; - integrity_set_tag_fn *set_tag_fn; - integrity_get_tag_fn *get_tag_fn; - - unsigned short flags; - unsigned short tuple_size; - unsigned short sector_size; - unsigned short tag_size; - - const char *name; - - struct kobject kobj; -}; - -extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); -extern void blk_integrity_unregister(struct gendisk *); -extern int blk_integrity_compare(struct block_device *, struct block_device *); -extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *); -extern int blk_rq_count_integrity_sg(struct request *); - -static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi) -{ - if (bi) - return bi->tuple_size; - - return 0; -} -static inline struct blk_integrity *bdev_get_integrity(struct block_device *bdev) -{ - return bdev->bd_disk->integrity; -} +#else /* CONFIG_BLOCK */ +/* + * stubs for when the block layer is configured out + */ +#define buffer_heads_over_limit 0 -static inline unsigned int bdev_get_tag_size(struct block_device *bdev) +static inline long nr_blockdev_pages(void) { - struct blk_integrity *bi = bdev_get_integrity(bdev); - - if (bi) - return bi->tag_size; - return 0; } -static inline int bdev_integrity_enabled(struct block_device *bdev, int rw) +static inline void exit_io_context(void) { - struct blk_integrity *bi = bdev_get_integrity(bdev); - - if (bi == NULL) - return 0; - - if (rw == READ && bi->verify_fn != NULL && - (bi->flags & INTEGRITY_FLAG_READ)) - return 1; - - if (rw == WRITE && bi->generate_fn != NULL && - (bi->flags & INTEGRITY_FLAG_WRITE)) - return 1; - - return 0; } -static inline int blk_integrity_rq(struct request *rq) +struct io_context; +static inline int put_io_context(struct io_context *ioc) { - return bio_integrity(rq->bio); + return 1; } -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -#define blk_integrity_rq(rq) (0) -#define blk_rq_count_integrity_sg(a) (0) -#define blk_rq_map_integrity_sg(a, b) (0) -#define bdev_get_integrity(a) (0) -#define bdev_get_tag_size(a) (0) -#define blk_integrity_compare(a, b) (0) -#define blk_integrity_register(a, b) (0) -#define blk_integrity_unregister(a) do { } while (0); - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -#else /* CONFIG_BLOCK */ -/* - * stubs for when the block layer is configured out - */ -#define buffer_heads_over_limit 0 - -static inline long nr_blockdev_pages(void) -{ - return 0; -} #endif /* CONFIG_BLOCK */ diff --git a/trunk/include/linux/blktrace_api.h b/trunk/include/linux/blktrace_api.h index d084b8d227a5..e3ef903aae88 100644 --- a/trunk/include/linux/blktrace_api.h +++ b/trunk/include/linux/blktrace_api.h @@ -129,7 +129,6 @@ struct blk_trace { u32 dev; struct dentry *dir; struct dentry *dropped_file; - struct dentry *msg_file; atomic_t dropped; }; diff --git a/trunk/include/linux/genhd.h b/trunk/include/linux/genhd.h index e8787417f65a..ae7aec3cabee 100644 --- a/trunk/include/linux/genhd.h +++ b/trunk/include/linux/genhd.h @@ -110,14 +110,6 @@ struct hd_struct { #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 #define GENHD_FL_FAIL 64 -#define BLK_SCSI_MAX_CMDS (256) -#define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) - -struct blk_scsi_cmd_filter { - unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; - unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; - struct kobject kobj; -}; struct gendisk { int major; /* major number of driver */ @@ -128,7 +120,6 @@ struct gendisk { struct hd_struct **part; /* [indexed by minor] */ struct block_device_operations *fops; struct request_queue *queue; - struct blk_scsi_cmd_filter cmd_filter; void *private_data; sector_t capacity; @@ -150,9 +141,6 @@ struct gendisk { struct disk_stats dkstats; #endif struct work_struct async_notify; -#ifdef CONFIG_BLK_DEV_INTEGRITY - struct blk_integrity *integrity; -#endif }; /* diff --git a/trunk/include/linux/iocontext.h b/trunk/include/linux/iocontext.h index 08b987bccf89..2b7a1187cb29 100644 --- a/trunk/include/linux/iocontext.h +++ b/trunk/include/linux/iocontext.h @@ -99,22 +99,4 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc) return NULL; } -#ifdef CONFIG_BLOCK -int put_io_context(struct io_context *ioc); -void exit_io_context(void); -struct io_context *get_io_context(gfp_t gfp_flags, int node); -struct io_context *alloc_io_context(gfp_t gfp_flags, int node); -void copy_io_context(struct io_context **pdst, struct io_context **psrc); -#else -static inline void exit_io_context(void) -{ -} - -struct io_context; -static inline int put_io_context(struct io_context *ioc) -{ - return 1; -} -#endif - #endif diff --git a/trunk/include/linux/mod_devicetable.h b/trunk/include/linux/mod_devicetable.h index c4db5827963d..69b2342d5ebb 100644 --- a/trunk/include/linux/mod_devicetable.h +++ b/trunk/include/linux/mod_devicetable.h @@ -159,15 +159,6 @@ struct ap_device_id { #define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01 -/* s390 css bus devices (subchannels) */ -struct css_device_id { - __u8 match_flags; - __u8 type; /* subchannel type */ - __u16 pad2; - __u32 pad3; - kernel_ulong_t driver_data; -}; - #define ACPI_ID_LEN 16 /* only 9 bytes needed here, 16 bytes are used */ /* to workaround crosscompile issues */ diff --git a/trunk/include/pcmcia/bulkmem.h b/trunk/include/pcmcia/bulkmem.h new file mode 100644 index 000000000000..6bc7472293b2 --- /dev/null +++ b/trunk/include/pcmcia/bulkmem.h @@ -0,0 +1,41 @@ +/* + * bulkmem.h -- Definitions for bulk memory services + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + */ + +#ifndef _LINUX_BULKMEM_H +#define _LINUX_BULKMEM_H + +/* For GetFirstRegion and GetNextRegion */ +typedef struct region_info_t { + u_int Attributes; + u_int CardOffset; + u_int RegionSize; + u_int AccessSpeed; + u_int BlockSize; + u_int PartMultiple; + u_char JedecMfr, JedecInfo; + memory_handle_t next; +} region_info_t; + +#define REGION_TYPE 0x0001 +#define REGION_TYPE_CM 0x0000 +#define REGION_TYPE_AM 0x0001 +#define REGION_PREFETCH 0x0008 +#define REGION_CACHEABLE 0x0010 +#define REGION_BAR_MASK 0xe000 +#define REGION_BAR_SHIFT 13 + +int pcmcia_get_first_region(struct pcmcia_device *handle, region_info_t *rgn); +int pcmcia_get_next_region(struct pcmcia_device *handle, region_info_t *rgn); + +#endif /* _LINUX_BULKMEM_H */ diff --git a/trunk/include/pcmcia/cistpl.h b/trunk/include/pcmcia/cistpl.h index e2e10c1e9a06..d3bbb19caf81 100644 --- a/trunk/include/pcmcia/cistpl.h +++ b/trunk/include/pcmcia/cistpl.h @@ -595,7 +595,7 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse); -int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *count); +int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info); /* ... but use these wrappers instead */ #define pcmcia_get_first_tuple(p_dev, tuple) \ diff --git a/trunk/include/pcmcia/cs.h b/trunk/include/pcmcia/cs.h index 45d84b275789..87a260e3699e 100644 --- a/trunk/include/pcmcia/cs.h +++ b/trunk/include/pcmcia/cs.h @@ -373,6 +373,9 @@ struct pcmcia_socket; int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg); int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config); +int pcmcia_get_first_window(window_handle_t *win, win_req_t *req); +int pcmcia_get_next_window(window_handle_t *win, win_req_t *req); +int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status); int pcmcia_get_mem_page(window_handle_t win, memreq_t *req); int pcmcia_map_mem_page(window_handle_t win, memreq_t *req); int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod); diff --git a/trunk/include/pcmcia/cs_types.h b/trunk/include/pcmcia/cs_types.h index f402a0f435b4..9a6bcc4952f0 100644 --- a/trunk/include/pcmcia/cs_types.h +++ b/trunk/include/pcmcia/cs_types.h @@ -21,8 +21,7 @@ #include #endif -#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \ - defined(__bfin__) +#if defined(__arm__) || defined(__mips__) || defined(__avr32__) /* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */ typedef u_int ioaddr_t; #else @@ -34,6 +33,9 @@ typedef u_int event_t; typedef u_char cisdata_t; typedef u_short page_t; +struct pcmcia_device; +typedef struct pcmcia_device *client_handle_t; + struct window_t; typedef struct window_t *window_handle_t; diff --git a/trunk/include/pcmcia/ds.h b/trunk/include/pcmcia/ds.h index b316027c853d..f047a1fd64f8 100644 --- a/trunk/include/pcmcia/ds.h +++ b/trunk/include/pcmcia/ds.h @@ -20,6 +20,7 @@ #include #endif +#include #include #include @@ -50,24 +51,6 @@ typedef struct mtd_info_t { u_int CardOffset; } mtd_info_t; -typedef struct region_info_t { - u_int Attributes; - u_int CardOffset; - u_int RegionSize; - u_int AccessSpeed; - u_int BlockSize; - u_int PartMultiple; - u_char JedecMfr, JedecInfo; - memory_handle_t next; -} region_info_t; -#define REGION_TYPE 0x0001 -#define REGION_TYPE_CM 0x0000 -#define REGION_TYPE_AM 0x0001 -#define REGION_PREFETCH 0x0008 -#define REGION_CACHEABLE 0x0010 -#define REGION_BAR_MASK 0xe000 -#define REGION_BAR_SHIFT 13 - typedef union ds_ioctl_arg_t { adjust_t adjust; config_info_t config; diff --git a/trunk/include/pcmcia/ss.h b/trunk/include/pcmcia/ss.h index ed919dd9bb5c..f95dca077c1c 100644 --- a/trunk/include/pcmcia/ss.h +++ b/trunk/include/pcmcia/ss.h @@ -21,6 +21,7 @@ #include #include +#include #ifdef CONFIG_CARDBUS #include #endif @@ -135,14 +136,8 @@ struct pccard_resource_ops { struct resource* (*find_mem) (unsigned long base, unsigned long num, unsigned long align, int low, struct pcmcia_socket *s); - int (*add_io) (struct pcmcia_socket *s, - unsigned int action, - unsigned long r_start, - unsigned long r_end); - int (*add_mem) (struct pcmcia_socket *s, - unsigned int action, - unsigned long r_start, - unsigned long r_end); + int (*adjust_resource) (struct pcmcia_socket *s, + adjust_t *adj); int (*init) (struct pcmcia_socket *s); void (*exit) (struct pcmcia_socket *s); }; @@ -250,6 +245,7 @@ struct pcmcia_socket { struct task_struct *thread; struct completion thread_done; + wait_queue_head_t thread_wait; spinlock_t thread_lock; /* protects thread_events */ unsigned int thread_events; diff --git a/trunk/include/pcmcia/version.h b/trunk/include/pcmcia/version.h new file mode 100644 index 000000000000..5ad9c5e198b6 --- /dev/null +++ b/trunk/include/pcmcia/version.h @@ -0,0 +1,3 @@ +/* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */ + +/* This file will be removed, please don't include it */ diff --git a/trunk/include/sound/ad1843.h b/trunk/include/sound/ad1843.h deleted file mode 100644 index b236a9d1d6e4..000000000000 --- a/trunk/include/sound/ad1843.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright 2003 Vivien Chappelier - * Copyright 2008 Thomas Bogendoerfer - */ - -#ifndef __SOUND_AD1843_H -#define __SOUND_AD1843_H - -struct snd_ad1843 { - void *chip; - int (*read)(void *chip, int reg); - int (*write)(void *chip, int reg, int val); -}; - -#define AD1843_GAIN_RECLEV 0 -#define AD1843_GAIN_LINE 1 -#define AD1843_GAIN_LINE_2 2 -#define AD1843_GAIN_MIC 3 -#define AD1843_GAIN_PCM_0 4 -#define AD1843_GAIN_PCM_1 5 -#define AD1843_GAIN_SIZE (AD1843_GAIN_PCM_1+1) - -int ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id); -int ad1843_get_gain(struct snd_ad1843 *ad1843, int id); -int ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval); -int ad1843_get_recsrc(struct snd_ad1843 *ad1843); -int ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc); -void ad1843_setup_dac(struct snd_ad1843 *ad1843, - unsigned int id, - unsigned int framerate, - snd_pcm_format_t fmt, - unsigned int channels); -void ad1843_shutdown_dac(struct snd_ad1843 *ad1843, - unsigned int id); -void ad1843_setup_adc(struct snd_ad1843 *ad1843, - unsigned int framerate, - snd_pcm_format_t fmt, - unsigned int channels); -void ad1843_shutdown_adc(struct snd_ad1843 *ad1843); -int ad1843_init(struct snd_ad1843 *ad1843); - -#endif /* __SOUND_AD1843_H */ diff --git a/trunk/include/sound/control.h b/trunk/include/sound/control.h index 4721b4bba053..3dc1291f52db 100644 --- a/trunk/include/sound/control.h +++ b/trunk/include/sound/control.h @@ -129,6 +129,9 @@ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn); #define snd_ctl_unregister_ioctl_compat(fcn) #endif +int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control); +int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, struct snd_ctl_elem_value *control); + static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) { return id->numid - kctl->id.numid; diff --git a/trunk/include/sound/core.h b/trunk/include/sound/core.h index 558b96284bd2..695ee53488a3 100644 --- a/trunk/include/sound/core.h +++ b/trunk/include/sound/core.h @@ -412,13 +412,13 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) #endif /* CONFIG_SND_DEBUG */ -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT /** * snd_printdd - debug printk * @format: format string * * Works like snd_printk() for debugging purposes. - * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set. + * Ignored when CONFIG_SND_DEBUG_DETECT is not set. */ #define snd_printdd(format, args...) snd_printk(format, ##args) #else @@ -442,7 +442,7 @@ struct snd_pci_quirk { unsigned short subvendor; /* PCI subvendor ID */ unsigned short subdevice; /* PCI subdevice ID */ int value; /* value */ -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT const char *name; /* name of the device (optional) */ #endif }; @@ -450,7 +450,7 @@ struct snd_pci_quirk { #define _SND_PCI_QUIRK_ID(vend,dev) \ .subvendor = (vend), .subdevice = (dev) #define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)} -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT #define SND_PCI_QUIRK(vend,dev,xname,val) \ {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)} #else diff --git a/trunk/include/sound/cs4231-regs.h b/trunk/include/sound/cs4231-regs.h index 92647532c454..e8d1f3e31f9e 100644 --- a/trunk/include/sound/cs4231-regs.h +++ b/trunk/include/sound/cs4231-regs.h @@ -177,12 +177,4 @@ #define CS4236_RIGHT_WAVE 0x1c /* right wavetable serial port volume */ #define CS4236_VERSION 0x9c /* chip version and ID */ -/* definitions for extended registers - OPTI93X */ -#define OPTi931_AUX_LEFT_INPUT 0x10 -#define OPTi931_AUX_RIGHT_INPUT 0x11 -#define OPTi93X_MIC_LEFT_INPUT 0x14 -#define OPTi93X_MIC_RIGHT_INPUT 0x15 -#define OPTi93X_OUT_LEFT 0x16 -#define OPTi93X_OUT_RIGHT 0x17 - #endif /* __SOUND_CS4231_REGS_H */ diff --git a/trunk/include/sound/cs4231.h b/trunk/include/sound/cs4231.h index f0785f9f4ae4..66055d702aa3 100644 --- a/trunk/include/sound/cs4231.h +++ b/trunk/include/sound/cs4231.h @@ -58,7 +58,6 @@ /* compatible, but clones */ #define CS4231_HW_INTERWAVE 0x1000 /* InterWave chip */ #define CS4231_HW_OPL3SA2 0x1101 /* OPL3-SA2 chip, similar to cs4231 */ -#define CS4231_HW_OPTI93X 0x1102 /* Opti 930/931/933 */ /* defines for codec.hwshare */ #define CS4231_HWSHARE_IRQ (1<<0) @@ -121,8 +120,6 @@ unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg); void snd_cs4231_mce_up(struct snd_cs4231 *chip); void snd_cs4231_mce_down(struct snd_cs4231 *chip); -void snd_cs4231_overrange(struct snd_cs4231 *chip); - irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id); const char *snd_cs4231_chip_id(struct snd_cs4231 *chip); diff --git a/trunk/include/sound/emu10k1.h b/trunk/include/sound/emu10k1.h index 10ee28eac018..7b7b9b13b4dd 100644 --- a/trunk/include/sound/emu10k1.h +++ b/trunk/include/sound/emu10k1.h @@ -1670,7 +1670,6 @@ struct snd_emu_chip_details { unsigned char spi_dac; /* SPI interface for DAC */ unsigned char i2c_adc; /* I2C interface for ADC */ unsigned char adc_1361t; /* Use Philips 1361T ADC */ - unsigned char invert_shared_spdif; /* analog/digital switch inverted */ const char *driver; const char *name; const char *id; /* for backward compatibility - can be NULL if not needed */ diff --git a/trunk/include/sound/seq_kernel.h b/trunk/include/sound/seq_kernel.h index 3d9afb6a8c9c..f023c1b97f8c 100644 --- a/trunk/include/sound/seq_kernel.h +++ b/trunk/include/sound/seq_kernel.h @@ -105,7 +105,7 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp, int cap, int type, int midi_channels, int midi_voices, char *portname); int snd_seq_event_port_detach(int client, int port); -#ifdef CONFIG_MODULES +#ifdef CONFIG_KMOD void snd_seq_autoload_lock(void); void snd_seq_autoload_unlock(void); #else diff --git a/trunk/include/sound/soc-dapm.h b/trunk/include/sound/soc-dapm.h index 3030fdc6981d..a105b01e06d5 100644 --- a/trunk/include/sound/soc-dapm.h +++ b/trunk/include/sound/soc-dapm.h @@ -130,13 +130,6 @@ { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ .shift = wshift, .invert = winvert} -/* generic register modifier widget */ -#define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ -{ .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \ - .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \ - .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ - .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} - /* dapm kcontrol types */ #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -200,7 +193,6 @@ struct snd_soc_dapm_widget; enum snd_soc_dapm_type; struct snd_soc_dapm_path; struct snd_soc_dapm_pin; -struct snd_soc_dapm_route; /* dapm controls */ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, @@ -213,32 +205,25 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_dapm_new_control(struct snd_soc_codec *codec, const struct snd_soc_dapm_widget *widget); -int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, - const struct snd_soc_dapm_widget *widget, - int num); /* dapm path setup */ -int __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec, +int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink_name, const char *control_name, const char *src_name); int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); void snd_soc_dapm_free(struct snd_soc_device *socdev); -int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, - const struct snd_soc_dapm_route *route, int num); /* dapm events */ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, int event); -int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, - enum snd_soc_bias_level level); +int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event); /* dapm sys fs - used by the core */ int snd_soc_dapm_sys_add(struct device *dev); -/* dapm audio pin control and status */ -int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin); -int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin); -int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin); -int snd_soc_dapm_sync(struct snd_soc_codec *codec); +/* dapm audio endpoint control */ +int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, + char *pin, int status); +int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec); /* dapm widget types */ enum snd_soc_dapm_type { @@ -260,18 +245,6 @@ enum snd_soc_dapm_type { snd_soc_dapm_post, /* machine specific post widget - exec last */ }; -/* - * DAPM audio route definition. - * - * Defines an audio route originating at source via control and finishing - * at sink. - */ -struct snd_soc_dapm_route { - const char *sink; - const char *control; - const char *source; -}; - /* dapm audio path between two widgets */ struct snd_soc_dapm_path { char *name; @@ -304,9 +277,6 @@ struct snd_soc_dapm_widget { unsigned char shift; /* bits to shift */ unsigned int saved_value; /* widget saved value */ unsigned int value; /* widget current value */ - unsigned int mask; /* non-shifted mask */ - unsigned int on_val; /* on state value */ - unsigned int off_val; /* off state value */ unsigned char power:1; /* block power status */ unsigned char invert:1; /* invert the power bit */ unsigned char active:1; /* active stream on DAC, ADC's */ diff --git a/trunk/include/sound/soc.h b/trunk/include/sound/soc.h index 1890d87c5204..d3c8c033dff8 100644 --- a/trunk/include/sound/soc.h +++ b/trunk/include/sound/soc.h @@ -73,15 +73,6 @@ .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ .private_value = (reg_left) | ((shift) << 8) | \ ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) } -#define SOC_DOUBLE_S8_TLV(xname, reg, min, max, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ - .put = snd_soc_put_volsw_s8, \ - .private_value = (reg) | (((signed char)max) << 16) | \ - (((signed char)min) << 24) } #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ .mask = xmask, .texts = xtexts } @@ -100,15 +91,6 @@ .info = snd_soc_info_volsw, \ .get = xhandler_get, .put = xhandler_put, \ .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) } -#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmask, xinvert,\ - xhandler_get, xhandler_put, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, \ - .get = xhandler_get, .put = xhandler_put, \ - .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) } #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_bool_ext, \ @@ -120,24 +102,6 @@ .get = xhandler_get, .put = xhandler_put, \ .private_value = (unsigned long)&xenum } -/* - * Bias levels - * - * @ON: Bias is fully on for audio playback and capture operations. - * @PREPARE: Prepare for audio operations. Called before DAPM switching for - * stream start and stop operations. - * @STANDBY: Low power standby state when no playback/capture operations are - * in progress. NOTE: The transition time between STANDBY and ON - * should be as fast as possible and no longer than 10ms. - * @OFF: Power Off. No restrictions on transition times. - */ -enum snd_soc_bias_level { - SND_SOC_BIAS_ON, - SND_SOC_BIAS_PREPARE, - SND_SOC_BIAS_STANDBY, - SND_SOC_BIAS_OFF, -}; - /* * Digital Audio Interface (DAI) types */ @@ -221,7 +185,8 @@ struct snd_soc_pcm_stream; struct snd_soc_ops; struct snd_soc_dai_mode; struct snd_soc_pcm_runtime; -struct snd_soc_dai; +struct snd_soc_codec_dai; +struct snd_soc_cpu_dai; struct snd_soc_codec; struct snd_soc_machine_config; struct soc_enum; @@ -256,27 +221,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num); void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); -/* Digital Audio Interface clocking API.*/ -int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir); - -int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div); - -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out); - -/* Digital Audio interface formatting */ -int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); - -int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots); - -int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); - -/* Digital Audio Interface mute */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); - /* *Controls */ @@ -305,12 +249,6 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); /* SoC PCM stream information */ struct snd_soc_pcm_stream { @@ -334,45 +272,87 @@ struct snd_soc_ops { int (*trigger)(struct snd_pcm_substream *, int); }; -/* ASoC DAI ops */ -struct snd_soc_dai_ops { - /* DAI clocking configuration */ - int (*set_sysclk)(struct snd_soc_dai *dai, +/* ASoC codec DAI ops */ +struct snd_soc_codec_ops { + /* codec DAI clocking configuration */ + int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai, int clk_id, unsigned int freq, int dir); - int (*set_pll)(struct snd_soc_dai *dai, + int (*set_pll)(struct snd_soc_codec_dai *codec_dai, int pll_id, unsigned int freq_in, unsigned int freq_out); - int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); + int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai, + int div_id, int div); - /* DAI format configuration */ - int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); - int (*set_tdm_slot)(struct snd_soc_dai *dai, + /* CPU DAI format configuration */ + int (*set_fmt)(struct snd_soc_codec_dai *codec_dai, + unsigned int fmt); + int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai, unsigned int mask, int slots); - int (*set_tristate)(struct snd_soc_dai *dai, int tristate); + int (*set_tristate)(struct snd_soc_codec_dai *, int tristate); /* digital mute */ - int (*digital_mute)(struct snd_soc_dai *dai, int mute); + int (*digital_mute)(struct snd_soc_codec_dai *, int mute); +}; + +/* ASoC cpu DAI ops */ +struct snd_soc_cpu_ops { + /* CPU DAI clocking configuration */ + int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai, + int clk_id, unsigned int freq, int dir); + int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai, + int div_id, int div); + int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + + /* CPU DAI format configuration */ + int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai, + unsigned int fmt); + int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai, + unsigned int mask, int slots); + int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate); +}; + +/* SoC Codec DAI */ +struct snd_soc_codec_dai { + char *name; + int id; + unsigned char type; + + /* DAI capabilities */ + struct snd_soc_pcm_stream playback; + struct snd_soc_pcm_stream capture; + + /* DAI runtime info */ + struct snd_soc_codec *codec; + unsigned int active; + unsigned char pop_wait:1; + + /* ops */ + struct snd_soc_ops ops; + struct snd_soc_codec_ops dai_ops; + + /* DAI private data */ + void *private_data; }; -/* SoC DAI (Digital Audio Interface) */ -struct snd_soc_dai { +/* SoC CPU DAI */ +struct snd_soc_cpu_dai { + /* DAI description */ char *name; unsigned int id; unsigned char type; /* DAI callbacks */ - int (*probe)(struct platform_device *pdev, - struct snd_soc_dai *dai); - void (*remove)(struct platform_device *pdev, - struct snd_soc_dai *dai); + int (*probe)(struct platform_device *pdev); + void (*remove)(struct platform_device *pdev); int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); + struct snd_soc_cpu_dai *cpu_dai); int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); + struct snd_soc_cpu_dai *cpu_dai); /* ops */ struct snd_soc_ops ops; - struct snd_soc_dai_ops dai_ops; + struct snd_soc_cpu_ops dai_ops; /* DAI capabilities */ struct snd_soc_pcm_stream capture; @@ -380,9 +360,7 @@ struct snd_soc_dai { /* DAI runtime info */ struct snd_pcm_runtime *runtime; - struct snd_soc_codec *codec; - unsigned int active; - unsigned char pop_wait:1; + unsigned char active:1; void *dma_data; /* DAI private data */ @@ -396,8 +374,7 @@ struct snd_soc_codec { struct mutex mutex; /* callbacks */ - int (*set_bias_level)(struct snd_soc_codec *, - enum snd_soc_bias_level level); + int (*dapm_event)(struct snd_soc_codec *codec, int event); /* runtime */ struct snd_card *card; @@ -419,12 +396,12 @@ struct snd_soc_codec { /* dapm */ struct list_head dapm_widgets; struct list_head dapm_paths; - enum snd_soc_bias_level bias_level; - enum snd_soc_bias_level suspend_bias_level; + unsigned int dapm_state; + unsigned int suspend_dapm_state; struct delayed_work delayed_work; /* codec DAI's */ - struct snd_soc_dai *dai; + struct snd_soc_codec_dai *dai; unsigned int num_dai; }; @@ -443,12 +420,12 @@ struct snd_soc_platform { int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); + struct snd_soc_cpu_dai *cpu_dai); int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); + struct snd_soc_cpu_dai *cpu_dai); /* pcm creation and destruction */ - int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, + int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *); void (*pcm_free)(struct snd_pcm *); @@ -462,8 +439,8 @@ struct snd_soc_dai_link { char *stream_name; /* Stream name */ /* DAI */ - struct snd_soc_dai *codec_dai; - struct snd_soc_dai *cpu_dai; + struct snd_soc_codec_dai *codec_dai; + struct snd_soc_cpu_dai *cpu_dai; /* machine stream operations */ struct snd_soc_ops *ops; @@ -490,8 +467,7 @@ struct snd_soc_machine { int (*resume_post)(struct platform_device *pdev); /* callbacks */ - int (*set_bias_level)(struct snd_soc_machine *, - enum snd_soc_bias_level level); + int (*dapm_event)(struct snd_soc_machine *, int event); /* CPU <--> Codec DAI links */ struct snd_soc_dai_link *dai_link; @@ -506,7 +482,6 @@ struct snd_soc_device { struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; struct delayed_work delayed_work; - struct work_struct deferred_resume_work; void *codec_data; }; diff --git a/trunk/include/sound/uda1341.h b/trunk/include/sound/uda1341.h index 110d5dc3a2be..2e564bfb37fe 100644 --- a/trunk/include/sound/uda1341.h +++ b/trunk/include/sound/uda1341.h @@ -15,6 +15,8 @@ * features support */ +/* $Id: uda1341.h,v 1.8 2005/11/17 14:17:21 tiwai Exp $ */ + #define UDA1341_ALSA_NAME "snd-uda1341" /* diff --git a/trunk/include/sound/version.h b/trunk/include/sound/version.h index 6b78aff273a8..ed6fb2eb1eac 100644 --- a/trunk/include/sound/version.h +++ b/trunk/include/sound/version.h @@ -1,3 +1,3 @@ -/* include/version.h */ -#define CONFIG_SND_VERSION "1.0.17" +/* include/version.h. Generated by alsa/ksync script. */ +#define CONFIG_SND_VERSION "1.0.16" #define CONFIG_SND_DATE "" diff --git a/trunk/kernel/exit.c b/trunk/kernel/exit.c index ceb258782835..8f6185e69b69 100644 --- a/trunk/kernel/exit.c +++ b/trunk/kernel/exit.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index b71ccd09fc8d..19908b26cf80 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/mm/Kconfig b/trunk/mm/Kconfig index 4242743b981b..3aa819d628c1 100644 --- a/trunk/mm/Kconfig +++ b/trunk/mm/Kconfig @@ -129,7 +129,7 @@ config MEMORY_HOTPLUG bool "Allow for memory hot-add" depends on SPARSEMEM || X86_64_ACPI_NUMA depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG - depends on (IA64 || X86 || PPC64 || SUPERH || S390) + depends on (IA64 || X86 || PPC64 || SUPERH) comment "Memory hotplug is currently incompatible with Software Suspend" depends on SPARSEMEM && HOTPLUG && HIBERNATION diff --git a/trunk/mm/slub.c b/trunk/mm/slub.c index 5f6e2c4a2ba7..315c392253c7 100644 --- a/trunk/mm/slub.c +++ b/trunk/mm/slub.c @@ -431,8 +431,9 @@ static void print_track(const char *s, struct track *t) if (!t->addr) return; - printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n", - s, t->addr, jiffies - t->when, t->cpu, t->pid); + printk(KERN_ERR "INFO: %s in ", s); + __print_symbol("%s", (unsigned long)t->addr); + printk(" age=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid); } static void print_tracking(struct kmem_cache *s, void *object) diff --git a/trunk/net/iucv/af_iucv.c b/trunk/net/iucv/af_iucv.c index bda71015885c..7b0038f45b16 100644 --- a/trunk/net/iucv/af_iucv.c +++ b/trunk/net/iucv/af_iucv.c @@ -1135,7 +1135,8 @@ static void iucv_callback_txdone(struct iucv_path *path, if (this) kfree_skb(this); } - BUG_ON(!this); + if (!this) + printk(KERN_ERR "AF_IUCV msg tag %u not found\n", msg->tag); if (sk->sk_state == IUCV_CLOSING) { if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { @@ -1195,7 +1196,7 @@ static int __init afiucv_init(void) } cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err); if (unlikely(err)) { - WARN_ON(err); + printk(KERN_ERR "AF_IUCV needs the VM userid\n"); err = -EPROTONOSUPPORT; goto out; } @@ -1209,6 +1210,7 @@ static int __init afiucv_init(void) err = sock_register(&iucv_sock_family_ops); if (err) goto out_proto; + printk(KERN_INFO "AF_IUCV lowlevel driver initialized\n"); return 0; out_proto: @@ -1224,6 +1226,8 @@ static void __exit afiucv_exit(void) sock_unregister(PF_IUCV); proto_unregister(&iucv_proto); iucv_unregister(&af_iucv_handler, 0); + + printk(KERN_INFO "AF_IUCV lowlevel driver unloaded\n"); } module_init(afiucv_init); diff --git a/trunk/net/iucv/iucv.c b/trunk/net/iucv/iucv.c index 7f82b7616212..918970762131 100644 --- a/trunk/net/iucv/iucv.c +++ b/trunk/net/iucv/iucv.c @@ -1559,11 +1559,16 @@ static void iucv_external_interrupt(u16 code) p = iucv_irq_data[smp_processor_id()]; if (p->ippathid >= iucv_max_pathid) { - WARN_ON(p->ippathid >= iucv_max_pathid); + printk(KERN_WARNING "iucv_do_int: Got interrupt with " + "pathid %d > max_connections (%ld)\n", + p->ippathid, iucv_max_pathid - 1); iucv_sever_pathid(p->ippathid, iucv_error_no_listener); return; } - BUG_ON(p->iptype < 0x01 || p->iptype > 0x09); + if (p->iptype < 0x01 || p->iptype > 0x09) { + printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n"); + return; + } work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC); if (!work) { printk(KERN_WARNING "iucv_external_interrupt: out of memory\n"); diff --git a/trunk/scripts/mod/file2alias.c b/trunk/scripts/mod/file2alias.c index 37d5c363fbcd..cea4a790e1e9 100644 --- a/trunk/scripts/mod/file2alias.c +++ b/trunk/scripts/mod/file2alias.c @@ -304,14 +304,6 @@ static int do_ap_entry(const char *filename, return 1; } -/* looks like: "css:tN" */ -static int do_css_entry(const char *filename, - struct css_device_id *id, char *alias) -{ - sprintf(alias, "css:t%01X", id->type); - return 1; -} - /* Looks like: "serio:tyNprNidNexN" */ static int do_serio_entry(const char *filename, struct serio_device_id *id, char *alias) @@ -688,10 +680,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct ap_device_id), "ap", do_ap_entry, mod); - else if (sym_is(symname, "__mod_css_device_table")) - do_table(symval, sym->st_size, - sizeof(struct css_device_id), "css", - do_css_entry, mod); else if (sym_is(symname, "__mod_serio_device_table")) do_table(symval, sym->st_size, sizeof(struct serio_device_id), "serio", diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 1c864c0efe2b..59c6e98f7bea 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -2495,7 +2495,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, } if (value && len) { - rc = security_sid_to_context(newsid, &context, &clen); + rc = security_sid_to_context_force(newsid, &context, &clen); if (rc) { kfree(namep); return rc; @@ -2669,6 +2669,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, return rc; rc = security_context_to_sid(value, size, &newsid); + if (rc == -EINVAL) { + if (!capable(CAP_MAC_ADMIN)) + return rc; + rc = security_context_to_sid_force(value, size, &newsid); + } if (rc) return rc; @@ -2703,10 +2708,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, return; } - rc = security_context_to_sid(value, size, &newsid); + rc = security_context_to_sid_force(value, size, &newsid); if (rc) { - printk(KERN_WARNING "%s: unable to obtain SID for context " - "%s, rc=%d\n", __func__, (char *)value, -rc); + printk(KERN_ERR "SELinux: unable to map context to SID" + "for (%s, %lu), rc=%d\n", + inode->i_sb->s_id, inode->i_ino, -rc); return; } @@ -5153,6 +5159,12 @@ static int selinux_setprocattr(struct task_struct *p, size--; } error = security_context_to_sid(value, size, &sid); + if (error == -EINVAL && !strcmp(name, "fscreate")) { + if (!capable(CAP_MAC_ADMIN)) + return error; + error = security_context_to_sid_force(value, size, + &sid); + } if (error) return error; } diff --git a/trunk/security/selinux/include/security.h b/trunk/security/selinux/include/security.h index ad30ac4273d6..7c543003d653 100644 --- a/trunk/security/selinux/include/security.h +++ b/trunk/security/selinux/include/security.h @@ -93,12 +93,17 @@ int security_change_sid(u32 ssid, u32 tsid, int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len); +int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len); + int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *out_sid); int security_context_to_sid_default(const char *scontext, u32 scontext_len, u32 *out_sid, u32 def_sid, gfp_t gfp_flags); +int security_context_to_sid_force(const char *scontext, u32 scontext_len, + u32 *sid); + int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel); diff --git a/trunk/security/selinux/ss/context.h b/trunk/security/selinux/ss/context.h index b9a6f7fc62fc..658c2bd17da8 100644 --- a/trunk/security/selinux/ss/context.h +++ b/trunk/security/selinux/ss/context.h @@ -28,6 +28,8 @@ struct context { u32 role; u32 type; struct mls_range range; + char *str; /* string representation if context cannot be mapped. */ + u32 len; /* length of string in bytes */ }; static inline void mls_context_init(struct context *c) @@ -106,20 +108,43 @@ static inline void context_init(struct context *c) static inline int context_cpy(struct context *dst, struct context *src) { + int rc; + dst->user = src->user; dst->role = src->role; dst->type = src->type; - return mls_context_cpy(dst, src); + if (src->str) { + dst->str = kstrdup(src->str, GFP_ATOMIC); + if (!dst->str) + return -ENOMEM; + dst->len = src->len; + } else { + dst->str = NULL; + dst->len = 0; + } + rc = mls_context_cpy(dst, src); + if (rc) { + kfree(dst->str); + return rc; + } + return 0; } static inline void context_destroy(struct context *c) { c->user = c->role = c->type = 0; + kfree(c->str); + c->str = NULL; + c->len = 0; mls_context_destroy(c); } static inline int context_cmp(struct context *c1, struct context *c2) { + if (c1->len && c2->len) + return (c1->len == c2->len && !strcmp(c1->str, c2->str)); + if (c1->len || c2->len) + return 0; return ((c1->user == c2->user) && (c1->role == c2->role) && (c1->type == c2->type) && diff --git a/trunk/security/selinux/ss/mls.c b/trunk/security/selinux/ss/mls.c index 8b1706b7b3cc..a6ca0587e634 100644 --- a/trunk/security/selinux/ss/mls.c +++ b/trunk/security/selinux/ss/mls.c @@ -239,7 +239,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c) * Policy read-lock must be held for sidtab lookup. * */ -int mls_context_to_sid(char oldc, +int mls_context_to_sid(struct policydb *pol, + char oldc, char **scontext, struct context *context, struct sidtab *s, @@ -286,7 +287,7 @@ int mls_context_to_sid(char oldc, *p++ = 0; for (l = 0; l < 2; l++) { - levdatum = hashtab_search(policydb.p_levels.table, scontextp); + levdatum = hashtab_search(pol->p_levels.table, scontextp); if (!levdatum) { rc = -EINVAL; goto out; @@ -311,7 +312,7 @@ int mls_context_to_sid(char oldc, *rngptr++ = 0; } - catdatum = hashtab_search(policydb.p_cats.table, + catdatum = hashtab_search(pol->p_cats.table, scontextp); if (!catdatum) { rc = -EINVAL; @@ -327,7 +328,7 @@ int mls_context_to_sid(char oldc, if (rngptr) { int i; - rngdatum = hashtab_search(policydb.p_cats.table, rngptr); + rngdatum = hashtab_search(pol->p_cats.table, rngptr); if (!rngdatum) { rc = -EINVAL; goto out; @@ -395,7 +396,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) if (!tmpstr) { rc = -ENOMEM; } else { - rc = mls_context_to_sid(':', &tmpstr, context, + rc = mls_context_to_sid(&policydb, ':', &tmpstr, context, NULL, SECSID_NULL); kfree(freestr); } diff --git a/trunk/security/selinux/ss/mls.h b/trunk/security/selinux/ss/mls.h index 0fdf6257ef64..1276715aaa8b 100644 --- a/trunk/security/selinux/ss/mls.h +++ b/trunk/security/selinux/ss/mls.h @@ -30,7 +30,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c); int mls_range_isvalid(struct policydb *p, struct mls_range *r); int mls_level_isvalid(struct policydb *p, struct mls_level *l); -int mls_context_to_sid(char oldc, +int mls_context_to_sid(struct policydb *p, + char oldc, char **scontext, struct context *context, struct sidtab *s, diff --git a/trunk/security/selinux/ss/services.c b/trunk/security/selinux/ss/services.c index dcc2e1c4fd83..b86ac9da6cf3 100644 --- a/trunk/security/selinux/ss/services.c +++ b/trunk/security/selinux/ss/services.c @@ -616,6 +616,14 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 *scontext = NULL; *scontext_len = 0; + if (context->len) { + *scontext_len = context->len; + *scontext = kstrdup(context->str, GFP_ATOMIC); + if (!(*scontext)) + return -ENOMEM; + return 0; + } + /* Compute the size of the context. */ *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; @@ -655,17 +663,8 @@ const char *security_get_initial_sid_context(u32 sid) return initial_sid_to_string[sid]; } -/** - * security_sid_to_context - Obtain a context for a given SID. - * @sid: security identifier, SID - * @scontext: security context - * @scontext_len: length in bytes - * - * Write the string representation of the context associated with @sid - * into a dynamically allocated string of the correct size. Set @scontext - * to point to this string and set @scontext_len to the length of the string. - */ -int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) +static int security_sid_to_context_core(u32 sid, char **scontext, + u32 *scontext_len, int force) { struct context *context; int rc = 0; @@ -693,7 +692,10 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) goto out; } POLICY_RDLOCK; - context = sidtab_search(&sidtab, sid); + if (force) + context = sidtab_search_force(&sidtab, sid); + else + context = sidtab_search(&sidtab, sid); if (!context) { printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", __func__, sid); @@ -708,36 +710,44 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) } -static int security_context_to_sid_core(const char *scontext, u32 scontext_len, - u32 *sid, u32 def_sid, gfp_t gfp_flags) +/** + * security_sid_to_context - Obtain a context for a given SID. + * @sid: security identifier, SID + * @scontext: security context + * @scontext_len: length in bytes + * + * Write the string representation of the context associated with @sid + * into a dynamically allocated string of the correct size. Set @scontext + * to point to this string and set @scontext_len to the length of the string. + */ +int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) { - char *scontext2; - struct context context; + return security_sid_to_context_core(sid, scontext, scontext_len, 0); +} + +int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) +{ + return security_sid_to_context_core(sid, scontext, scontext_len, 1); +} + +static int string_to_context_struct(struct policydb *pol, + struct sidtab *sidtabp, + const char *scontext, + u32 scontext_len, + struct context *ctx, + u32 def_sid, + gfp_t gfp_flags) +{ + char *scontext2 = NULL; struct role_datum *role; struct type_datum *typdatum; struct user_datum *usrdatum; char *scontextp, *p, oldc; int rc = 0; - if (!ss_initialized) { - int i; + context_init(ctx); - for (i = 1; i < SECINITSID_NUM; i++) { - if (!strcmp(initial_sid_to_string[i], scontext)) { - *sid = i; - goto out; - } - } - *sid = SECINITSID_KERNEL; - goto out; - } - *sid = SECSID_NULL; - - /* Copy the string so that we can modify the copy as we parse it. - The string should already by null terminated, but we append a - null suffix to the copy to avoid problems with the existing - attr package, which doesn't view the null terminator as part - of the attribute value. */ + /* Copy the string so that we can modify the copy as we parse it. */ scontext2 = kmalloc(scontext_len+1, gfp_flags); if (!scontext2) { rc = -ENOMEM; @@ -746,11 +756,6 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, memcpy(scontext2, scontext, scontext_len); scontext2[scontext_len] = 0; - context_init(&context); - *sid = SECSID_NULL; - - POLICY_RDLOCK; - /* Parse the security context. */ rc = -EINVAL; @@ -762,15 +767,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, p++; if (*p == 0) - goto out_unlock; + goto out; *p++ = 0; - usrdatum = hashtab_search(policydb.p_users.table, scontextp); + usrdatum = hashtab_search(pol->p_users.table, scontextp); if (!usrdatum) - goto out_unlock; + goto out; - context.user = usrdatum->value; + ctx->user = usrdatum->value; /* Extract role. */ scontextp = p; @@ -778,14 +783,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, p++; if (*p == 0) - goto out_unlock; + goto out; *p++ = 0; - role = hashtab_search(policydb.p_roles.table, scontextp); + role = hashtab_search(pol->p_roles.table, scontextp); if (!role) - goto out_unlock; - context.role = role->value; + goto out; + ctx->role = role->value; /* Extract type. */ scontextp = p; @@ -794,33 +799,74 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, oldc = *p; *p++ = 0; - typdatum = hashtab_search(policydb.p_types.table, scontextp); + typdatum = hashtab_search(pol->p_types.table, scontextp); if (!typdatum) - goto out_unlock; + goto out; - context.type = typdatum->value; + ctx->type = typdatum->value; - rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid); + rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid); if (rc) - goto out_unlock; + goto out; if ((p - scontext2) < scontext_len) { rc = -EINVAL; - goto out_unlock; + goto out; } /* Check the validity of the new context. */ - if (!policydb_context_isvalid(&policydb, &context)) { + if (!policydb_context_isvalid(pol, ctx)) { rc = -EINVAL; - goto out_unlock; + context_destroy(ctx); + goto out; } - /* Obtain the new sid. */ - rc = sidtab_context_to_sid(&sidtab, &context, sid); -out_unlock: - POLICY_RDUNLOCK; - context_destroy(&context); + rc = 0; +out: kfree(scontext2); + return rc; +} + +static int security_context_to_sid_core(const char *scontext, u32 scontext_len, + u32 *sid, u32 def_sid, gfp_t gfp_flags, + int force) +{ + struct context context; + int rc = 0; + + if (!ss_initialized) { + int i; + + for (i = 1; i < SECINITSID_NUM; i++) { + if (!strcmp(initial_sid_to_string[i], scontext)) { + *sid = i; + goto out; + } + } + *sid = SECINITSID_KERNEL; + goto out; + } + *sid = SECSID_NULL; + + POLICY_RDLOCK; + rc = string_to_context_struct(&policydb, &sidtab, + scontext, scontext_len, + &context, def_sid, gfp_flags); + if (rc == -EINVAL && force) { + context.str = kmalloc(scontext_len+1, gfp_flags); + if (!context.str) { + rc = -ENOMEM; + goto out; + } + memcpy(context.str, scontext, scontext_len); + context.str[scontext_len] = 0; + context.len = scontext_len; + } else if (rc) + goto out; + rc = sidtab_context_to_sid(&sidtab, &context, sid); + if (rc) + context_destroy(&context); out: + POLICY_RDUNLOCK; return rc; } @@ -838,7 +884,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) { return security_context_to_sid_core(scontext, scontext_len, - sid, SECSID_NULL, GFP_KERNEL); + sid, SECSID_NULL, GFP_KERNEL, 0); } /** @@ -855,6 +901,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) * The default SID is passed to the MLS layer to be used to allow * kernel labeling of the MLS field if the MLS field is not present * (for upgrading to MLS without full relabel). + * Implicitly forces adding of the context even if it cannot be mapped yet. * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * memory is available, or 0 on success. */ @@ -862,7 +909,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len, u32 *sid, u32 def_sid, gfp_t gfp_flags) { return security_context_to_sid_core(scontext, scontext_len, - sid, def_sid, gfp_flags); + sid, def_sid, gfp_flags, 1); +} + +int security_context_to_sid_force(const char *scontext, u32 scontext_len, + u32 *sid) +{ + return security_context_to_sid_core(scontext, scontext_len, + sid, SECSID_NULL, GFP_KERNEL, 1); } static int compute_sid_handle_invalid_context( @@ -1246,9 +1300,12 @@ static inline int convert_context_handle_invalid_context(struct context *context char *s; u32 len; - context_struct_to_string(context, &s, &len); - printk(KERN_ERR "SELinux: context %s is invalid\n", s); - kfree(s); + if (!context_struct_to_string(context, &s, &len)) { + printk(KERN_WARNING + "SELinux: Context %s would be invalid if enforcing\n", + s); + kfree(s); + } } return rc; } @@ -1280,6 +1337,32 @@ static int convert_context(u32 key, args = p; + if (c->str) { + struct context ctx; + rc = string_to_context_struct(args->newp, NULL, c->str, + c->len, &ctx, SECSID_NULL, + GFP_KERNEL); + if (!rc) { + printk(KERN_INFO + "SELinux: Context %s became valid (mapped).\n", + c->str); + /* Replace string with mapped representation. */ + kfree(c->str); + memcpy(c, &ctx, sizeof(*c)); + goto out; + } else if (rc == -EINVAL) { + /* Retain string representation for later mapping. */ + rc = 0; + goto out; + } else { + /* Other error condition, e.g. ENOMEM. */ + printk(KERN_ERR + "SELinux: Unable to map context %s, rc = %d.\n", + c->str, -rc); + goto out; + } + } + rc = context_cpy(&oldc, c); if (rc) goto out; @@ -1319,13 +1402,21 @@ static int convert_context(u32 key, } context_destroy(&oldc); + rc = 0; out: return rc; bad: - context_struct_to_string(&oldc, &s, &len); + /* Map old representation to string and save it. */ + if (context_struct_to_string(&oldc, &s, &len)) + return -ENOMEM; context_destroy(&oldc); - printk(KERN_ERR "SELinux: invalidating context %s\n", s); - kfree(s); + context_destroy(c); + c->str = s; + c->len = len; + printk(KERN_INFO + "SELinux: Context %s became invalid (unmapped).\n", + c->str); + rc = 0; goto out; } @@ -1406,7 +1497,11 @@ int security_load_policy(void *data, size_t len) return -EINVAL; } - sidtab_init(&newsidtab); + if (sidtab_init(&newsidtab)) { + LOAD_UNLOCK; + policydb_destroy(&newpolicydb); + return -ENOMEM; + } /* Verify that the kernel defined classes are correct. */ if (validate_classes(&newpolicydb)) { @@ -1429,11 +1524,15 @@ int security_load_policy(void *data, size_t len) goto err; } - /* Convert the internal representations of contexts - in the new SID table and remove invalid SIDs. */ + /* + * Convert the internal representations of contexts + * in the new SID table. + */ args.oldp = &policydb; args.newp = &newpolicydb; - sidtab_map_remove_on_error(&newsidtab, convert_context, &args); + rc = sidtab_map(&newsidtab, convert_context, &args); + if (rc) + goto err; /* Save the old policydb and SID table to free later. */ memcpy(&oldpolicydb, &policydb, sizeof policydb); @@ -1673,6 +1772,8 @@ int security_get_user_sids(u32 fromsid, POLICY_RDLOCK; + context_init(&usercon); + fromcon = sidtab_search(&sidtab, fromsid); if (!fromcon) { rc = -EINVAL; diff --git a/trunk/security/selinux/ss/sidtab.c b/trunk/security/selinux/ss/sidtab.c index 4a516ff4bcde..ba3541640491 100644 --- a/trunk/security/selinux/ss/sidtab.c +++ b/trunk/security/selinux/ss/sidtab.c @@ -86,7 +86,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) return rc; } -struct context *sidtab_search(struct sidtab *s, u32 sid) +static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) { int hvalue; struct sidtab_node *cur; @@ -99,7 +99,10 @@ struct context *sidtab_search(struct sidtab *s, u32 sid) while (cur != NULL && sid > cur->sid) cur = cur->next; - if (cur == NULL || sid != cur->sid) { + if (force && cur && sid == cur->sid && cur->context.len) + return &cur->context; + + if (cur == NULL || sid != cur->sid || cur->context.len) { /* Remap invalid SIDs to the unlabeled SID. */ sid = SECINITSID_UNLABELED; hvalue = SIDTAB_HASH(sid); @@ -113,6 +116,16 @@ struct context *sidtab_search(struct sidtab *s, u32 sid) return &cur->context; } +struct context *sidtab_search(struct sidtab *s, u32 sid) +{ + return sidtab_search_core(s, sid, 0); +} + +struct context *sidtab_search_force(struct sidtab *s, u32 sid) +{ + return sidtab_search_core(s, sid, 1); +} + int sidtab_map(struct sidtab *s, int (*apply) (u32 sid, struct context *context, @@ -138,43 +151,6 @@ int sidtab_map(struct sidtab *s, return rc; } -void sidtab_map_remove_on_error(struct sidtab *s, - int (*apply) (u32 sid, - struct context *context, - void *args), - void *args) -{ - int i, ret; - struct sidtab_node *last, *cur, *temp; - - if (!s) - return; - - for (i = 0; i < SIDTAB_SIZE; i++) { - last = NULL; - cur = s->htable[i]; - while (cur != NULL) { - ret = apply(cur->sid, &cur->context, args); - if (ret) { - if (last) - last->next = cur->next; - else - s->htable[i] = cur->next; - temp = cur; - cur = cur->next; - context_destroy(&temp->context); - kfree(temp); - s->nel--; - } else { - last = cur; - cur = cur->next; - } - } - } - - return; -} - static inline u32 sidtab_search_context(struct sidtab *s, struct context *context) { @@ -215,6 +191,10 @@ int sidtab_context_to_sid(struct sidtab *s, goto unlock_out; } sid = s->next_sid++; + if (context->len) + printk(KERN_INFO + "SELinux: Context %s is not valid (left unmapped).\n", + context->str); ret = sidtab_insert(s, sid, context); if (ret) s->next_sid--; diff --git a/trunk/security/selinux/ss/sidtab.h b/trunk/security/selinux/ss/sidtab.h index 2fe9dfa3eb3a..64ea5b1cdea4 100644 --- a/trunk/security/selinux/ss/sidtab.h +++ b/trunk/security/selinux/ss/sidtab.h @@ -32,6 +32,7 @@ struct sidtab { int sidtab_init(struct sidtab *s); int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); struct context *sidtab_search(struct sidtab *s, u32 sid); +struct context *sidtab_search_force(struct sidtab *s, u32 sid); int sidtab_map(struct sidtab *s, int (*apply) (u32 sid, @@ -39,12 +40,6 @@ int sidtab_map(struct sidtab *s, void *args), void *args); -void sidtab_map_remove_on_error(struct sidtab *s, - int (*apply) (u32 sid, - struct context *context, - void *args), - void *args); - int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid); diff --git a/trunk/sound/Kconfig b/trunk/sound/Kconfig index a37bee094eba..4247406160e7 100644 --- a/trunk/sound/Kconfig +++ b/trunk/sound/Kconfig @@ -1,9 +1,11 @@ # sound/Config.in # -menuconfig SOUND - tristate "Sound card support" +menu "Sound" depends on HAS_IOMEM + +config SOUND + tristate "Sound card support" help If you have a sound card in your computer, i.e. if it can say more than an occasional beep, say Y. Be sure to have all the information @@ -26,22 +28,22 @@ menuconfig SOUND and read ; the module will be called soundcore. -if SOUND - source "sound/oss/dmasound/Kconfig" if !M68K -menuconfig SND +menu "Advanced Linux Sound Architecture" + depends on SOUND!=n + +config SND tristate "Advanced Linux Sound Architecture" + depends on SOUND help Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), the new base sound system. For more information, see -if SND - source "sound/core/Kconfig" source "sound/drivers/Kconfig" @@ -56,7 +58,9 @@ source "sound/aoa/Kconfig" source "sound/arm/Kconfig" +if SPI source "sound/spi/Kconfig" +endif source "sound/mips/Kconfig" @@ -76,20 +80,22 @@ source "sound/parisc/Kconfig" source "sound/soc/Kconfig" -endif # SND +endmenu -menuconfig SOUND_PRIME +menu "Open Sound System" + depends on SOUND!=n + +config SOUND_PRIME tristate "Open Sound System (DEPRECATED)" + depends on SOUND help Say 'Y' or 'M' to enable Open Sound System drivers. -if SOUND_PRIME - source "sound/oss/Kconfig" -endif # SOUND_PRIME +endmenu -endif # !M68K +endif config AC97_BUS tristate @@ -99,4 +105,4 @@ config AC97_BUS sound although they're sharing the AC97 bus. Concerned drivers should "select" this. -endif # SOUND +endmenu diff --git a/trunk/sound/aoa/Kconfig b/trunk/sound/aoa/Kconfig index c081e18b9540..5d5813cec4c8 100644 --- a/trunk/sound/aoa/Kconfig +++ b/trunk/sound/aoa/Kconfig @@ -1,17 +1,18 @@ -menuconfig SND_AOA +menu "Apple Onboard Audio driver" + depends on SND!=n && PPC_PMAC + +config SND_AOA tristate "Apple Onboard Audio driver" - depends on PPC_PMAC + depends on SND select SND_PCM ---help--- This option enables the new driver for the various Apple Onboard Audio components. -if SND_AOA - source "sound/aoa/fabrics/Kconfig" source "sound/aoa/codecs/Kconfig" source "sound/aoa/soundbus/Kconfig" -endif # SND_AOA +endmenu diff --git a/trunk/sound/aoa/codecs/Kconfig b/trunk/sound/aoa/codecs/Kconfig index 808eb11ebacd..d5fbd6016e93 100644 --- a/trunk/sound/aoa/codecs/Kconfig +++ b/trunk/sound/aoa/codecs/Kconfig @@ -1,5 +1,6 @@ config SND_AOA_ONYX tristate "support Onyx chip" + depends on SND_AOA select I2C select I2C_POWERMAC ---help--- @@ -9,6 +10,7 @@ config SND_AOA_ONYX #config SND_AOA_TOPAZ # tristate "support Topaz chips" +# depends on SND_AOA # ---help--- # This option enables support for the Topaz (CS84xx) # codec chips found in the latest Apple machines, @@ -17,6 +19,7 @@ config SND_AOA_ONYX config SND_AOA_TAS tristate "support TAS chips" + depends on SND_AOA select I2C select I2C_POWERMAC ---help--- @@ -26,6 +29,7 @@ config SND_AOA_TAS config SND_AOA_TOONIE tristate "support Toonie chip" + depends on SND_AOA ---help--- This option enables support for the toonie codec found in the Mac Mini. If you have a Mac Mini and diff --git a/trunk/sound/aoa/fabrics/Kconfig b/trunk/sound/aoa/fabrics/Kconfig index 3ca475a886b1..50d7021ff677 100644 --- a/trunk/sound/aoa/fabrics/Kconfig +++ b/trunk/sound/aoa/fabrics/Kconfig @@ -1,5 +1,6 @@ config SND_AOA_FABRIC_LAYOUT tristate "layout-id fabric" + depends on SND_AOA select SND_AOA_SOUNDBUS select SND_AOA_SOUNDBUS_I2S ---help--- diff --git a/trunk/sound/aoa/soundbus/Kconfig b/trunk/sound/aoa/soundbus/Kconfig index 839d1137b9b2..7368b7ddfe0d 100644 --- a/trunk/sound/aoa/soundbus/Kconfig +++ b/trunk/sound/aoa/soundbus/Kconfig @@ -1,5 +1,6 @@ config SND_AOA_SOUNDBUS tristate "Apple Soundbus support" + depends on SOUND select SND_PCM ---help--- This option enables the generic driver for the soundbus diff --git a/trunk/sound/arm/Kconfig b/trunk/sound/arm/Kconfig index 351e19ea3785..2e4a5e0d16db 100644 --- a/trunk/sound/arm/Kconfig +++ b/trunk/sound/arm/Kconfig @@ -1,19 +1,11 @@ # ALSA ARM drivers -menuconfig SND_ARM - bool "ARM sound devices" - depends on ARM - default y - help - Support for sound devices specific to ARM architectures. - Drivers that are implemented on ASoC can be found in - "ALSA for SoC audio support" section. - -if SND_ARM +menu "ALSA ARM devices" + depends on SND!=n && ARM config SND_SA11XX_UDA1341 tristate "SA11xx UDA1341TS driver (iPaq H3600)" - depends on ARCH_SA1100 && L3 + depends on ARCH_SA1100 && SND && L3 select SND_PCM help Say Y here if you have a Compaq iPaq H3x00 handheld computer @@ -24,7 +16,7 @@ config SND_SA11XX_UDA1341 config SND_ARMAACI tristate "ARM PrimeCell PL041 AC Link support" - depends on ARM_AMBA + depends on SND && ARM_AMBA select SND_PCM select SND_AC97_CODEC @@ -34,12 +26,11 @@ config SND_PXA2XX_PCM config SND_PXA2XX_AC97 tristate "AC97 driver for the Intel PXA2xx chip" - depends on ARCH_PXA + depends on ARCH_PXA && SND select SND_PXA2XX_PCM select SND_AC97_CODEC help Say Y or M if you want to support any AC97 codec attached to the PXA2xx AC97 interface. -endif # SND_ARM - +endmenu diff --git a/trunk/sound/arm/sa11xx-uda1341.c b/trunk/sound/arm/sa11xx-uda1341.c index faeddf3ecedb..0eff33ca0f79 100644 --- a/trunk/sound/arm/sa11xx-uda1341.c +++ b/trunk/sound/arm/sa11xx-uda1341.c @@ -21,6 +21,8 @@ * merged HAL layer (patches from Brian) */ +/* $Id: sa11xx-uda1341.c,v 1.27 2005/12/07 09:13:42 cladisch Exp $ */ + /*************************************************************************************************** * * To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai diff --git a/trunk/sound/core/Kconfig b/trunk/sound/core/Kconfig index 335d45ecde6a..a8d71c6c8e75 100644 --- a/trunk/sound/core/Kconfig +++ b/trunk/sound/core/Kconfig @@ -1,19 +1,24 @@ # ALSA soundcard-configuration config SND_TIMER tristate + depends on SND config SND_PCM tristate select SND_TIMER + depends on SND config SND_HWDEP tristate + depends on SND config SND_RAWMIDI tristate + depends on SND config SND_SEQUENCER tristate "Sequencer support" + depends on SND select SND_TIMER help Say Y or M to enable MIDI sequencer and router support. This @@ -39,9 +44,11 @@ config SND_SEQ_DUMMY config SND_OSSEMUL bool + depends on SND config SND_MIXER_OSS tristate "OSS Mixer API" + depends on SND select SND_OSSEMUL help To enable OSS mixer API emulation (/dev/mixer*), say Y here @@ -54,6 +61,7 @@ config SND_MIXER_OSS config SND_PCM_OSS tristate "OSS PCM (digital audio) API" + depends on SND select SND_OSSEMUL select SND_PCM help @@ -76,7 +84,7 @@ config SND_PCM_OSS_PLUGINS config SND_SEQUENCER_OSS bool "OSS Sequencer API" - depends on SND_SEQUENCER + depends on SND && SND_SEQUENCER select SND_OSSEMUL help Say Y here to enable OSS sequencer emulation (both @@ -90,7 +98,7 @@ config SND_SEQUENCER_OSS config SND_RTCTIMER tristate "RTC Timer support" - depends on RTC + depends on SND && RTC select SND_TIMER help Say Y here to enable RTC timer support for ALSA. ALSA uses @@ -115,6 +123,7 @@ config SND_SEQ_RTCTIMER_DEFAULT config SND_DYNAMIC_MINORS bool "Dynamic device file minor numbers" + depends on SND help If you say Y here, the minor numbers of ALSA device files in /dev/snd/ are allocated dynamically. This allows you to have @@ -125,6 +134,7 @@ config SND_DYNAMIC_MINORS config SND_SUPPORT_OLD_API bool "Support old ALSA API" + depends on SND default y help Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3 @@ -132,7 +142,7 @@ config SND_SUPPORT_OLD_API config SND_VERBOSE_PROCFS bool "Verbose procfs contents" - depends on PROC_FS + depends on SND && PROC_FS default y help Say Y here to include code for verbose procfs contents (provides @@ -141,6 +151,7 @@ config SND_VERBOSE_PROCFS config SND_VERBOSE_PRINTK bool "Verbose printk" + depends on SND help Say Y here to enable verbose log messages. These messages will help to identify source file and position containing @@ -150,17 +161,16 @@ config SND_VERBOSE_PRINTK config SND_DEBUG bool "Debug" + depends on SND help Say Y here to enable ALSA debug code. -config SND_DEBUG_VERBOSE - bool "More verbose debug" +config SND_DEBUG_DETECT + bool "Debug detection" depends on SND_DEBUG help - Say Y here to enable extra-verbose debugging messages. - - Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages. - So, say Y only if you are ready to be annoyed. + Say Y here to enable extra-verbose log messages printed when + detecting devices. config SND_PCM_XRUN_DEBUG bool "Enable PCM ring buffer overrun/underrun debugging" @@ -174,3 +184,4 @@ config SND_PCM_XRUN_DEBUG config SND_VMASTER bool + depends on SND diff --git a/trunk/sound/core/control.c b/trunk/sound/core/control.c index 281b2e2ef0ea..01a1a5af47bb 100644 --- a/trunk/sound/core/control.c +++ b/trunk/sound/core/control.c @@ -684,8 +684,7 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, return result; } -static int snd_ctl_elem_read(struct snd_card *card, - struct snd_ctl_elem_value *control) +int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control) { struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; @@ -735,8 +734,8 @@ static int snd_ctl_elem_read_user(struct snd_card *card, return result; } -static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, - struct snd_ctl_elem_value *control) +int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, + struct snd_ctl_elem_value *control) { struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; diff --git a/trunk/sound/core/init.c b/trunk/sound/core/init.c index 5c254d498ae0..ac0573416130 100644 --- a/trunk/sound/core/init.c +++ b/trunk/sound/core/init.c @@ -46,24 +46,17 @@ static char *slots[SNDRV_CARDS]; module_param_array(slots, charp, NULL, 0444); MODULE_PARM_DESC(slots, "Module names assigned to the slots."); -/* return non-zero if the given index is reserved for the given +/* return non-zero if the given index is already reserved for another * module via slots option */ -static int module_slot_match(struct module *module, int idx) +static int module_slot_mismatch(struct module *module, int idx) { - int match = 1; #ifdef MODULE - const char *s1, *s2; - + char *s1, *s2; if (!module || !module->name || !slots[idx]) return 0; - - s1 = module->name; - s2 = slots[idx]; - if (*s2 == '!') { - match = 0; /* negative match */ - s2++; - } + s1 = slots[idx]; + s2 = module->name; /* compare module name strings * hyphens are handled as equivalent with underscore */ @@ -75,12 +68,12 @@ static int module_slot_match(struct module *module, int idx) if (c2 == '-') c2 = '_'; if (c1 != c2) - return !match; + return 1; if (!c1) break; } -#endif /* MODULE */ - return match; +#endif + return 0; } #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) @@ -136,7 +129,7 @@ struct snd_card *snd_card_new(int idx, const char *xid, struct module *module, int extra_size) { struct snd_card *card; - int err, idx2; + int err; if (extra_size < 0) extra_size = 0; @@ -151,41 +144,35 @@ struct snd_card *snd_card_new(int idx, const char *xid, err = 0; mutex_lock(&snd_card_mutex); if (idx < 0) { + int idx2; for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) /* idx == -1 == 0xffff means: take any free slot */ if (~snd_cards_lock & idx & 1<= snd_ecards_limit) + snd_ecards_limit = idx + 1; + break; } + } else { + if (idx < snd_ecards_limit) { + if (snd_cards_lock & (1 << idx)) + err = -EBUSY; /* invalid */ + } else { + if (idx < SNDRV_CARDS) + snd_ecards_limit = idx + 1; /* increase the limit */ + else + err = -ENODEV; + } } - if (idx < 0) - err = -ENODEV; - else if (idx < snd_ecards_limit) { - if (snd_cards_lock & (1 << idx)) - err = -EBUSY; /* invalid */ - } else if (idx >= SNDRV_CARDS) - err = -ENODEV; - if (err < 0) { + if (idx < 0 || err < 0) { mutex_unlock(&snd_card_mutex); snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", idx, snd_ecards_limit - 1, err); goto __error; } snd_cards_lock |= 1 << idx; /* lock it */ - if (idx >= snd_ecards_limit) - snd_ecards_limit = idx + 1; /* increase the limit */ mutex_unlock(&snd_card_mutex); card->number = idx; card->module = module; diff --git a/trunk/sound/core/memalloc.c b/trunk/sound/core/memalloc.c index f5d6d8d12979..23b7bc02728b 100644 --- a/trunk/sound/core/memalloc.c +++ b/trunk/sound/core/memalloc.c @@ -79,6 +79,68 @@ struct snd_mem_list { #define snd_assert(expr, args...) /**/ #endif +/* + * Hacks + */ + +#if defined(__i386__) +/* + * A hack to allocate large buffers via dma_alloc_coherent() + * + * since dma_alloc_coherent always tries GFP_DMA when the requested + * pci memory region is below 32bit, it happens quite often that even + * 2 order of pages cannot be allocated. + * + * so in the following, we allocate at first without dma_mask, so that + * allocation will be done without GFP_DMA. if the area doesn't match + * with the requested region, then realloate with the original dma_mask + * again. + * + * Really, we want to move this type of thing into dma_alloc_coherent() + * so dma_mask doesn't have to be messed with. + */ + +static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, + gfp_t flags) +{ + void *ret; + u64 dma_mask, coherent_dma_mask; + + if (dev == NULL || !dev->dma_mask) + return dma_alloc_coherent(dev, size, dma_handle, flags); + dma_mask = *dev->dma_mask; + coherent_dma_mask = dev->coherent_dma_mask; + *dev->dma_mask = 0xffffffff; /* do without masking */ + dev->coherent_dma_mask = 0xffffffff; /* do without masking */ + ret = dma_alloc_coherent(dev, size, dma_handle, flags); + *dev->dma_mask = dma_mask; /* restore */ + dev->coherent_dma_mask = coherent_dma_mask; /* restore */ + if (ret) { + /* obtained address is out of range? */ + if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) { + /* reallocate with the proper mask */ + dma_free_coherent(dev, size, ret, *dma_handle); + ret = dma_alloc_coherent(dev, size, dma_handle, flags); + } + } else { + /* wish to success now with the proper mask... */ + if (dma_mask != 0xffffffffUL) { + /* allocation with GFP_ATOMIC to avoid the long stall */ + flags &= ~GFP_KERNEL; + flags |= GFP_ATOMIC; + ret = dma_alloc_coherent(dev, size, dma_handle, flags); + } + } + return ret; +} + +/* redefine dma_alloc_coherent for some architectures */ +#undef dma_alloc_coherent +#define dma_alloc_coherent snd_dma_hack_alloc_coherent + +#endif /* arch */ + /* * * Generic memory allocators diff --git a/trunk/sound/core/seq/seq_clientmgr.c b/trunk/sound/core/seq/seq_clientmgr.c index 7a1545d2d953..47cfa5186e34 100644 --- a/trunk/sound/core/seq/seq_clientmgr.c +++ b/trunk/sound/core/seq/seq_clientmgr.c @@ -148,7 +148,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) return NULL; } spin_unlock_irqrestore(&clients_lock, flags); -#ifdef CONFIG_MODULES +#ifdef CONFIG_KMOD if (!in_interrupt()) { static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; static char card_requested[SNDRV_CARDS]; diff --git a/trunk/sound/core/seq/seq_device.c b/trunk/sound/core/seq/seq_device.c index 05410e536a4f..2f00ad28a2b7 100644 --- a/trunk/sound/core/seq/seq_device.c +++ b/trunk/sound/core/seq/seq_device.c @@ -124,7 +124,7 @@ static void snd_seq_device_info(struct snd_info_entry *entry, * load all registered drivers (called from seq_clientmgr.c) */ -#ifdef CONFIG_MODULES +#ifdef CONFIG_KMOD /* avoid auto-loading during module_init() */ static int snd_seq_in_init; void snd_seq_autoload_lock(void) @@ -140,7 +140,7 @@ void snd_seq_autoload_unlock(void) void snd_seq_device_load_drivers(void) { -#ifdef CONFIG_MODULES +#ifdef CONFIG_KMOD struct ops_list *ops; /* Calling request_module during module_init() @@ -566,5 +566,7 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers); EXPORT_SYMBOL(snd_seq_device_new); EXPORT_SYMBOL(snd_seq_device_register_driver); EXPORT_SYMBOL(snd_seq_device_unregister_driver); +#ifdef CONFIG_KMOD EXPORT_SYMBOL(snd_seq_autoload_lock); EXPORT_SYMBOL(snd_seq_autoload_unlock); +#endif diff --git a/trunk/sound/core/sound.c b/trunk/sound/core/sound.c index 09a94953745a..6c8ab48c689a 100644 --- a/trunk/sound/core/sound.c +++ b/trunk/sound/core/sound.c @@ -60,14 +60,14 @@ EXPORT_SYMBOL(snd_ecards_limit); static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; static DEFINE_MUTEX(sound_mutex); -#ifdef CONFIG_MODULES +#ifdef CONFIG_KMOD /** * snd_request_card - try to load the card module * @card: the card number * * Tries to load the module "snd-card-X" for the given card number - * via request_module. Returns immediately if already loaded. + * via KMOD. Returns immediately if already loaded. */ void snd_request_card(int card) { @@ -92,7 +92,7 @@ static void snd_request_other(int minor) request_module(str); } -#endif /* modular kernel */ +#endif /* request_module support */ /** * snd_lookup_minor_data - get user data of a registered device @@ -132,7 +132,7 @@ static int snd_open(struct inode *inode, struct file *file) return -ENODEV; mptr = snd_minors[minor]; if (mptr == NULL) { -#ifdef CONFIG_MODULES +#ifdef CONFIG_KMOD int dev = SNDRV_MINOR_DEVICE(minor); if (dev == SNDRV_MINOR_CONTROL) { /* /dev/aloadC? */ diff --git a/trunk/sound/core/timer.c b/trunk/sound/core/timer.c index 0af337efc64e..9d8184a2c2d0 100644 --- a/trunk/sound/core/timer.c +++ b/trunk/sound/core/timer.c @@ -146,7 +146,7 @@ static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) return NULL; } -#ifdef CONFIG_MODULES +#ifdef CONFIG_KMOD static void snd_timer_request(struct snd_timer_id *tid) { @@ -259,8 +259,8 @@ int snd_timer_open(struct snd_timer_instance **ti, /* open a master instance */ mutex_lock(®ister_mutex); timer = snd_timer_find(tid); -#ifdef CONFIG_MODULES - if (!timer) { +#ifdef CONFIG_KMOD + if (timer == NULL) { mutex_unlock(®ister_mutex); snd_timer_request(tid); mutex_lock(®ister_mutex); diff --git a/trunk/sound/drivers/Kconfig b/trunk/sound/drivers/Kconfig index 255fd18b9aec..602b58e3b55d 100644 --- a/trunk/sound/drivers/Kconfig +++ b/trunk/sound/drivers/Kconfig @@ -1,41 +1,15 @@ -config SND_MPU401_UART - tristate - select SND_RAWMIDI +# ALSA generic drivers -config SND_OPL3_LIB - tristate - select SND_TIMER - select SND_HWDEP +menu "Generic devices" + depends on SND!=n -config SND_OPL4_LIB - tristate - select SND_TIMER - select SND_HWDEP - -config SND_VX_LIB - tristate - select SND_HWDEP - select SND_PCM - -config SND_AC97_CODEC - tristate - select SND_PCM - select AC97_BUS - select SND_VMASTER - -menuconfig SND_DRIVERS - bool "Generic sound devices" - default y - help - Support for generic sound devices. - -if SND_DRIVERS config SND_PCSP tristate "PC-Speaker support (READ HELP!)" depends on PCSPKR_PLATFORM && X86_PC && HIGH_RES_TIMERS depends on INPUT depends on EXPERIMENTAL + depends on SND select SND_PCM help If you don't have a sound card in your computer, you can include a @@ -61,8 +35,33 @@ config SND_PCSP Say M if you don't. Say Y only if you really know what you do. +config SND_MPU401_UART + tristate + select SND_RAWMIDI + +config SND_OPL3_LIB + tristate + select SND_TIMER + select SND_HWDEP + +config SND_OPL4_LIB + tristate + select SND_TIMER + select SND_HWDEP + +config SND_VX_LIB + tristate + select SND_HWDEP + select SND_PCM + +config SND_AC97_CODEC + tristate + select SND_PCM + select AC97_BUS + config SND_DUMMY tristate "Dummy (/dev/null) soundcard" + depends on SND select SND_PCM help Say Y here to include the dummy driver. This driver does @@ -91,6 +90,7 @@ config SND_VIRMIDI config SND_MTPAV tristate "MOTU MidiTimePiece AV multiport MIDI" + depends on SND select SND_RAWMIDI help To use a MOTU MidiTimePiece AV multiport MIDI adapter @@ -102,7 +102,7 @@ config SND_MTPAV config SND_MTS64 tristate "ESI Miditerminal 4140 driver" - depends on PARPORT + depends on SND && PARPORT select SND_RAWMIDI help The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with @@ -115,6 +115,7 @@ config SND_MTS64 config SND_SERIAL_U16550 tristate "UART16550 serial MIDI driver" + depends on SND select SND_RAWMIDI help To include support for MIDI serial port interfaces, say Y here @@ -130,6 +131,7 @@ config SND_SERIAL_U16550 config SND_MPU401 tristate "Generic MPU-401 UART driver" + depends on SND select SND_MPU401_UART help Say Y here to include support for MIDI ports compatible with @@ -140,7 +142,7 @@ config SND_MPU401 config SND_PORTMAN2X4 tristate "Portman 2x4 driver" - depends on PARPORT + depends on SND && PARPORT select SND_RAWMIDI help Say Y here to include support for Midiman Portman 2x4 parallel @@ -151,7 +153,7 @@ config SND_PORTMAN2X4 config SND_ML403_AC97CR tristate "Xilinx ML403 AC97 Controller Reference" - depends on XILINX_VIRTEX + depends on SND && XILINX_VIRTEX select SND_AC97_CODEC help Say Y here to include support for the @@ -161,25 +163,4 @@ config SND_ML403_AC97CR To compile this driver as a module, choose M here: the module will be called snd-ml403_ac97cr. -config SND_AC97_POWER_SAVE - bool "AC97 Power-Saving Mode" - depends on SND_AC97_CODEC && EXPERIMENTAL - default n - help - Say Y here to enable the aggressive power-saving support of - AC97 codecs. In this mode, the power-mode is dynamically - controlled at each open/close. - - The mode is activated by passing power_save=1 option to - snd-ac97-codec driver. You can toggle it dynamically over - sysfs, too. - -config SND_AC97_POWER_SAVE_DEFAULT - int "Default time-out for AC97 power-save mode" - depends on SND_AC97_POWER_SAVE - default 0 - help - The default time-out value in seconds for AC97 automatic - power-save mode. 0 means to disable the power-save mode. - -endif # SND_DRIVERS +endmenu diff --git a/trunk/sound/drivers/vx/vx_hwdep.c b/trunk/sound/drivers/vx/vx_hwdep.c index efd22e92bced..1dfe6948e6ff 100644 --- a/trunk/sound/drivers/vx/vx_hwdep.c +++ b/trunk/sound/drivers/vx/vx_hwdep.c @@ -183,7 +183,7 @@ static int vx_hwdep_dsp_load(struct snd_hwdep *hw, kfree(fw); return -ENOMEM; } - if (copy_from_user((void *)fw->data, dsp->image, dsp->length)) { + if (copy_from_user(fw->data, dsp->image, dsp->length)) { free_fw(fw); return -EFAULT; } diff --git a/trunk/sound/i2c/cs8427.c b/trunk/sound/i2c/cs8427.c index 9c3d361accfb..e57e9cbe6a0f 100644 --- a/trunk/sound/i2c/cs8427.c +++ b/trunk/sound/i2c/cs8427.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -265,7 +264,10 @@ int snd_cs8427_create(struct snd_i2c_bus *bus, goto __fail; } /* write default channel status bytes */ - put_unaligned_le32(SNDRV_PCM_DEFAULT_CON_SPDIF, buf); + buf[0] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 0)); + buf[1] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 8)); + buf[2] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 16)); + buf[3] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 24)); memset(buf + 4, 0, 24 - 4); if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0) goto __fail; diff --git a/trunk/sound/i2c/l3/uda1341.c b/trunk/sound/i2c/l3/uda1341.c index 1f4942ea1414..bfa5d2c3608b 100644 --- a/trunk/sound/i2c/l3/uda1341.c +++ b/trunk/sound/i2c/l3/uda1341.c @@ -17,6 +17,8 @@ * 2002-05-12 Tomas Kasparek another code cleanup */ +/* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */ + #include #include #include diff --git a/trunk/sound/isa/Kconfig b/trunk/sound/isa/Kconfig index 25347a25d63c..2639a6ab8f2e 100644 --- a/trunk/sound/isa/Kconfig +++ b/trunk/sound/isa/Kconfig @@ -21,17 +21,12 @@ config SND_SB16_DSP select SND_PCM select SND_SB_COMMON -menuconfig SND_ISA - bool "ISA sound devices" - depends on ISA && ISA_DMA_API - default y - help - Support for sound devices connected via the ISA bus. - -if SND_ISA +menu "ISA devices" + depends on SND!=n && ISA && ISA_DMA_API config SND_ADLIB tristate "AdLib FM card" + depends on SND select SND_OPL3_LIB help Say Y here to include support for AdLib FM cards. @@ -41,7 +36,7 @@ config SND_ADLIB config SND_AD1816A tristate "Analog Devices SoundPort AD1816A" - depends on PNP + depends on SND && PNP && ISA select ISAPNP select SND_OPL3_LIB select SND_MPU401_UART @@ -55,6 +50,7 @@ config SND_AD1816A config SND_AD1848 tristate "Generic AD1848/CS4248 driver" + depends on SND select SND_AD1848_LIB help Say Y here to include support for AD1848 (Analog Devices) or @@ -68,7 +64,7 @@ config SND_AD1848 config SND_ALS100 tristate "Avance Logic ALS100/ALS120" - depends on PNP + depends on SND && PNP && ISA select ISAPNP select SND_OPL3_LIB select SND_MPU401_UART @@ -82,7 +78,7 @@ config SND_ALS100 config SND_AZT2320 tristate "Aztech Systems AZT2320" - depends on PNP + depends on SND && PNP && ISA select ISAPNP select SND_OPL3_LIB select SND_MPU401_UART @@ -96,6 +92,7 @@ config SND_AZT2320 config SND_CMI8330 tristate "C-Media CMI8330" + depends on SND select SND_AD1848_LIB select SND_SB16_DSP help @@ -107,6 +104,7 @@ config SND_CMI8330 config SND_CS4231 tristate "Generic Cirrus Logic CS4231 driver" + depends on SND select SND_MPU401_UART select SND_CS4231_LIB help @@ -118,6 +116,7 @@ config SND_CS4231 config SND_CS4232 tristate "Generic Cirrus Logic CS4232 driver" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_CS4231_LIB @@ -130,6 +129,7 @@ config SND_CS4232 config SND_CS4236 tristate "Generic Cirrus Logic CS4236+ driver" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_CS4231_LIB @@ -142,7 +142,7 @@ config SND_CS4236 config SND_DT019X tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" - depends on PNP + depends on SND && PNP && ISA select ISAPNP select SND_OPL3_LIB select SND_MPU401_UART @@ -156,7 +156,7 @@ config SND_DT019X config SND_ES968 tristate "Generic ESS ES968 driver" - depends on PNP + depends on SND && PNP && ISA select ISAPNP select SND_MPU401_UART select SND_SB8_DSP @@ -168,6 +168,7 @@ config SND_ES968 config SND_ES1688 tristate "Generic ESS ES688/ES1688 driver" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM @@ -180,6 +181,7 @@ config SND_ES1688 config SND_ES18XX tristate "Generic ESS ES18xx driver" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM @@ -191,7 +193,7 @@ config SND_ES18XX config SND_SC6000 tristate "Gallant SC-6000, Audio Excel DSP 16" - depends on HAS_IOPORT + depends on SND && HAS_IOPORT select SND_AD1848_LIB select SND_OPL3_LIB select SND_MPU401_UART @@ -202,10 +204,15 @@ config SND_SC6000 To compile this driver as a module, choose M here: the module will be called snd-sc6000. +config SND_GUS_SYNTH + tristate + config SND_GUSCLASSIC tristate "Gravis UltraSound Classic" + depends on SND select SND_RAWMIDI select SND_PCM + select SND_GUS_SYNTH help Say Y here to include support for Gravis UltraSound Classic soundcards. @@ -215,9 +222,11 @@ config SND_GUSCLASSIC config SND_GUSEXTREME tristate "Gravis UltraSound Extreme" + depends on SND select SND_HWDEP select SND_MPU401_UART select SND_PCM + select SND_GUS_SYNTH help Say Y here to include support for Gravis UltraSound Extreme soundcards. @@ -227,8 +236,10 @@ config SND_GUSEXTREME config SND_GUSMAX tristate "Gravis UltraSound MAX" + depends on SND select SND_RAWMIDI select SND_CS4231_LIB + select SND_GUS_SYNTH help Say Y here to include support for Gravis UltraSound MAX soundcards. @@ -238,9 +249,10 @@ config SND_GUSMAX config SND_INTERWAVE tristate "AMD InterWave, Gravis UltraSound PnP" - depends on PNP + depends on SND && PNP && ISA select SND_RAWMIDI select SND_CS4231_LIB + select SND_GUS_SYNTH help Say Y here to include support for AMD InterWave based soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, @@ -251,9 +263,10 @@ config SND_INTERWAVE config SND_INTERWAVE_STB tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" - depends on PNP + depends on SND && PNP && ISA select SND_RAWMIDI select SND_CS4231_LIB + select SND_GUS_SYNTH help Say Y here to include support for AMD InterWave based soundcards with a TEA6330T bass and treble regulator @@ -264,6 +277,7 @@ config SND_INTERWAVE_STB config SND_OPL3SA2 tristate "Yamaha OPL3-SA2/SA3" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_CS4231_LIB @@ -276,6 +290,7 @@ config SND_OPL3SA2 config SND_OPTI92X_AD1848 tristate "OPTi 82C92x - AD1848" + depends on SND select SND_OPL3_LIB select SND_OPL4_LIB select SND_MPU401_UART @@ -289,6 +304,7 @@ config SND_OPTI92X_AD1848 config SND_OPTI92X_CS4231 tristate "OPTi 82C92x - CS4231" + depends on SND select SND_OPL3_LIB select SND_OPL4_LIB select SND_MPU401_UART @@ -302,9 +318,10 @@ config SND_OPTI92X_CS4231 config SND_OPTI93X tristate "OPTi 82C93x" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_PCM help Say Y here to include support for soundcards based on Opti 82C93x chips. @@ -314,6 +331,7 @@ config SND_OPTI93X config SND_MIRO tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver" + depends on SND select SND_OPL4_LIB select SND_CS4231_LIB select SND_MPU401_UART @@ -327,6 +345,7 @@ config SND_MIRO config SND_SB8 tristate "Sound Blaster 1.0/2.0/Pro (8-bit)" + depends on SND select SND_OPL3_LIB select SND_RAWMIDI select SND_SB8_DSP @@ -339,6 +358,7 @@ config SND_SB8 config SND_SB16 tristate "Sound Blaster 16 (PnP)" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_SB16_DSP @@ -351,6 +371,7 @@ config SND_SB16 config SND_SBAWE tristate "Sound Blaster AWE (32,64) (PnP)" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_SB16_DSP @@ -381,6 +402,7 @@ config SND_SB16_CSP_FIRMWARE_IN_KERNEL config SND_SGALAXY tristate "Aztech Sound Galaxy" + depends on SND select SND_AD1848_LIB help Say Y here to include support for Aztech Sound Galaxy @@ -391,6 +413,7 @@ config SND_SGALAXY config SND_SSCAPE tristate "Ensoniq SoundScape PnP driver" + depends on SND select SND_HWDEP select SND_MPU401_UART select SND_CS4231_LIB @@ -403,6 +426,7 @@ config SND_SSCAPE config SND_WAVEFRONT tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" + depends on SND select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART @@ -424,5 +448,4 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL you need to install the firmware files from the alsa-firmware package. -endif # SND_ISA - +endmenu diff --git a/trunk/sound/isa/cs423x/cs4231_lib.c b/trunk/sound/isa/cs423x/cs4231_lib.c index 521db705d179..0aa8649e5c7f 100644 --- a/trunk/sound/isa/cs423x/cs4231_lib.c +++ b/trunk/sound/isa/cs423x/cs4231_lib.c @@ -119,42 +119,6 @@ static unsigned char snd_cs4231_original_image[32] = 0x00, /* 1f/31 - cbrl */ }; -static unsigned char snd_opti93x_original_image[32] = -{ - 0x00, /* 00/00 - l_mixout_outctrl */ - 0x00, /* 01/01 - r_mixout_outctrl */ - 0x88, /* 02/02 - l_cd_inctrl */ - 0x88, /* 03/03 - r_cd_inctrl */ - 0x88, /* 04/04 - l_a1/fm_inctrl */ - 0x88, /* 05/05 - r_a1/fm_inctrl */ - 0x80, /* 06/06 - l_dac_inctrl */ - 0x80, /* 07/07 - r_dac_inctrl */ - 0x00, /* 08/08 - ply_dataform_reg */ - 0x00, /* 09/09 - if_conf */ - 0x00, /* 0a/10 - pin_ctrl */ - 0x00, /* 0b/11 - err_init_reg */ - 0x0a, /* 0c/12 - id_reg */ - 0x00, /* 0d/13 - reserved */ - 0x00, /* 0e/14 - ply_upcount_reg */ - 0x00, /* 0f/15 - ply_lowcount_reg */ - 0x88, /* 10/16 - reserved/l_a1_inctrl */ - 0x88, /* 11/17 - reserved/r_a1_inctrl */ - 0x88, /* 12/18 - l_line_inctrl */ - 0x88, /* 13/19 - r_line_inctrl */ - 0x88, /* 14/20 - l_mic_inctrl */ - 0x88, /* 15/21 - r_mic_inctrl */ - 0x80, /* 16/22 - l_out_outctrl */ - 0x80, /* 17/23 - r_out_outctrl */ - 0x00, /* 18/24 - reserved */ - 0x00, /* 19/25 - reserved */ - 0x00, /* 1a/26 - reserved */ - 0x00, /* 1b/27 - reserved */ - 0x00, /* 1c/28 - cap_dataform_reg */ - 0x00, /* 1d/29 - reserved */ - 0x00, /* 1e/30 - cap_upcount_reg */ - 0x00 /* 1f/31 - cap_lowcount_reg */ -}; - /* * Basic I/O functions */ @@ -931,7 +895,7 @@ static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream) return 0; } -void snd_cs4231_overrange(struct snd_cs4231 *chip) +static void snd_cs4231_overrange(struct snd_cs4231 *chip) { unsigned long flags; unsigned char res; @@ -1090,11 +1054,8 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip) chip->image[CS4231_IFACE_CTRL] = (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | (chip->single_dma ? CS4231_SINGLE_DMA : 0); - if (chip->hardware != CS4231_HW_OPTI93X) { - chip->image[CS4231_ALT_FEATURE_1] = 0x80; - chip->image[CS4231_ALT_FEATURE_2] = - chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; - } + chip->image[CS4231_ALT_FEATURE_1] = 0x80; + chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; ptr = (unsigned char *) &chip->image; snd_cs4231_mce_down(chip); spin_lock_irqsave(&chip->reg_lock, flags); @@ -1415,7 +1376,6 @@ const char *snd_cs4231_chip_id(struct snd_cs4231 *chip) case CS4231_HW_INTERWAVE: return "AMD InterWave"; case CS4231_HW_OPL3SA2: return chip->card->shortname; case CS4231_HW_AD1845: return "AD1845"; - case CS4231_HW_OPTI93X: return "OPTi 93x"; default: return "???"; } } @@ -1441,13 +1401,8 @@ static int snd_cs4231_new(struct snd_card *card, chip->rate_constraint = snd_cs4231_xrate; chip->set_playback_format = snd_cs4231_playback_format; chip->set_capture_format = snd_cs4231_capture_format; - if (chip->hardware == CS4231_HW_OPTI93X) - memcpy(&chip->image, &snd_opti93x_original_image, - sizeof(snd_opti93x_original_image)); - else - memcpy(&chip->image, &snd_cs4231_original_image, - sizeof(snd_cs4231_original_image)); - + memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); + *rchip = chip; return 0; } @@ -1835,48 +1790,6 @@ CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1) }; -static struct snd_kcontrol_new snd_opti93x_controls[] = { -CS4231_DOUBLE("Master Playback Switch", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), -CS4231_DOUBLE("Master Playback Volume", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), -CS4231_DOUBLE("PCM Playback Switch", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), -CS4231_DOUBLE("FM Playback Switch", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("FM Playback Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Line Playback Switch", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -CS4231_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), -CS4231_DOUBLE("Mic Playback Switch", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Mic Playback Volume", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Mic Boost", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -CS4231_DOUBLE("CD Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("CD Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Aux Playback Switch", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Playback Volume", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_cs4231_info_mux, - .get = snd_cs4231_get_mux, - .put = snd_cs4231_put_mux, -} -}; - int snd_cs4231_mixer(struct snd_cs4231 *chip) { struct snd_card *card; @@ -1889,22 +1802,10 @@ int snd_cs4231_mixer(struct snd_cs4231 *chip) strcpy(card->mixername, chip->pcm->name); - if (chip->hardware == CS4231_HW_OPTI93X) - for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_opti93x_controls[idx], - chip)); - if (err < 0) - return err; - } - else - for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_cs4231_controls[idx], - chip)); - if (err < 0) - return err; - } + for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { + if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip))) < 0) + return err; + } return 0; } @@ -1914,7 +1815,6 @@ EXPORT_SYMBOL(snd_cs4236_ext_out); EXPORT_SYMBOL(snd_cs4236_ext_in); EXPORT_SYMBOL(snd_cs4231_mce_up); EXPORT_SYMBOL(snd_cs4231_mce_down); -EXPORT_SYMBOL(snd_cs4231_overrange); EXPORT_SYMBOL(snd_cs4231_interrupt); EXPORT_SYMBOL(snd_cs4231_chip_id); EXPORT_SYMBOL(snd_cs4231_create); diff --git a/trunk/sound/isa/opti9xx/opti92x-ad1848.c b/trunk/sound/isa/opti9xx/opti92x-ad1848.c index 41c047e665ec..fe1afc13a01d 100644 --- a/trunk/sound/isa/opti9xx/opti92x-ad1848.c +++ b/trunk/sound/isa/opti9xx/opti92x-ad1848.c @@ -33,10 +33,15 @@ #include #include #include -#if defined(CS4231) || defined(OPTi93X) +#ifdef CS4231 #include #else +#ifndef OPTi93X #include +#else +#include +#include +#endif /* OPTi93X */ #endif /* CS4231 */ #include #include @@ -104,6 +109,7 @@ module_param(dma2, int, 0444); MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); #endif /* CS4231 || OPTi93X */ +#define OPTi9XX_HW_DETECT 0 #define OPTi9XX_HW_82C928 1 #define OPTi9XX_HW_82C929 2 #define OPTi9XX_HW_82C924 3 @@ -117,12 +123,105 @@ MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); #ifdef OPTi93X +#define OPTi93X_INDEX 0x00 +#define OPTi93X_DATA 0x01 #define OPTi93X_STATUS 0x02 +#define OPTi93X_DDATA 0x03 #define OPTi93X_PORT(chip, r) ((chip)->port + OPTi93X_##r) +#define OPTi93X_MIXOUT_LEFT 0x00 +#define OPTi93X_MIXOUT_RIGHT 0x01 +#define OPTi93X_CD_LEFT_INPUT 0x02 +#define OPTi93X_CD_RIGHT_INPUT 0x03 +#define OPTi930_AUX_LEFT_INPUT 0x04 +#define OPTi930_AUX_RIGHT_INPUT 0x05 +#define OPTi931_FM_LEFT_INPUT 0x04 +#define OPTi931_FM_RIGHT_INPUT 0x05 +#define OPTi93X_DAC_LEFT 0x06 +#define OPTi93X_DAC_RIGHT 0x07 +#define OPTi93X_PLAY_FORMAT 0x08 +#define OPTi93X_IFACE_CONF 0x09 +#define OPTi93X_PIN_CTRL 0x0a +#define OPTi93X_ERR_INIT 0x0b +#define OPTi93X_ID 0x0c +#define OPTi93X_PLAY_UPR_CNT 0x0e +#define OPTi93X_PLAY_LWR_CNT 0x0f +#define OPTi931_AUX_LEFT_INPUT 0x10 +#define OPTi931_AUX_RIGHT_INPUT 0x11 +#define OPTi93X_LINE_LEFT_INPUT 0x12 +#define OPTi93X_LINE_RIGHT_INPUT 0x13 +#define OPTi93X_MIC_LEFT_INPUT 0x14 +#define OPTi93X_MIC_RIGHT_INPUT 0x15 +#define OPTi93X_OUT_LEFT 0x16 +#define OPTi93X_OUT_RIGHT 0x17 +#define OPTi93X_CAPT_FORMAT 0x1c +#define OPTi93X_CAPT_UPR_CNT 0x1e +#define OPTi93X_CAPT_LWR_CNT 0x1f + +#define OPTi93X_TRD 0x20 +#define OPTi93X_MCE 0x40 +#define OPTi93X_INIT 0x80 + +#define OPTi93X_MIXOUT_MIC_GAIN 0x20 +#define OPTi93X_MIXOUT_LINE 0x00 +#define OPTi93X_MIXOUT_CD 0x40 +#define OPTi93X_MIXOUT_MIC 0x80 +#define OPTi93X_MIXOUT_MIXER 0xc0 + +#define OPTi93X_STEREO 0x10 +#define OPTi93X_LINEAR_8 0x00 +#define OPTi93X_ULAW_8 0x20 +#define OPTi93X_LINEAR_16_LIT 0x40 +#define OPTi93X_ALAW_8 0x60 +#define OPTi93X_ADPCM_16 0xa0 +#define OPTi93X_LINEAR_16_BIG 0xc0 + +#define OPTi93X_CAPTURE_PIO 0x80 +#define OPTi93X_PLAYBACK_PIO 0x40 +#define OPTi93X_AUTOCALIB 0x08 +#define OPTi93X_SINGLE_DMA 0x04 +#define OPTi93X_CAPTURE_ENABLE 0x02 +#define OPTi93X_PLAYBACK_ENABLE 0x01 + +#define OPTi93X_IRQ_ENABLE 0x02 + +#define OPTi93X_DMA_REQUEST 0x10 +#define OPTi93X_CALIB_IN_PROGRESS 0x20 + #define OPTi93X_IRQ_PLAYBACK 0x04 #define OPTi93X_IRQ_CAPTURE 0x08 + +struct snd_opti93x { + unsigned long port; + struct resource *res_port; + int irq; + int dma1; + int dma2; + + struct snd_opti9xx *chip; + unsigned short hardware; + unsigned char image[32]; + + unsigned char mce_bit; + unsigned short mode; + int mute; + + spinlock_t lock; + + struct snd_card *card; + struct snd_pcm *pcm; + struct snd_pcm_substream *playback_substream; + struct snd_pcm_substream *capture_substream; + unsigned int p_dma_size; + unsigned int c_dma_size; +}; + +#define OPTi93X_MODE_NONE 0x00 +#define OPTi93X_MODE_PLAY 0x01 +#define OPTi93X_MODE_CAPTURE 0x02 +#define OPTi93X_MODE_OPEN (OPTi93X_MODE_PLAY | OPTi93X_MODE_CAPTURE) + #endif /* OPTi93X */ struct snd_opti9xx { @@ -135,7 +234,6 @@ struct snd_opti9xx { unsigned long mc_base_size; #ifdef OPTi93X unsigned long mc_indir_index; - struct snd_cs4231 *codec; #endif /* OPTi93X */ unsigned long pwd_reg; @@ -393,9 +491,16 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) break; #else /* OPTi93X */ + case OPTi9XX_HW_82C930: case OPTi9XX_HW_82C931: case OPTi9XX_HW_82C933: - /* + snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); + snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); + snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | + (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), + 0x34); + snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); + /* * The BTC 1817DW has QS1000 wavetable which is connected * to the serial digital input of the OPTI931. */ @@ -405,13 +510,6 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) * or digital input signal. */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); - case OPTi9XX_HW_82C930: /* FALL THROUGH */ - snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); - snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); - snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | - (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), - 0x34); - snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); break; #endif /* OPTi93X */ @@ -556,23 +654,979 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) #ifdef OPTi93X +static unsigned char snd_opti93x_default_image[32] = +{ + 0x00, /* 00/00 - l_mixout_outctrl */ + 0x00, /* 01/01 - r_mixout_outctrl */ + 0x88, /* 02/02 - l_cd_inctrl */ + 0x88, /* 03/03 - r_cd_inctrl */ + 0x88, /* 04/04 - l_a1/fm_inctrl */ + 0x88, /* 05/05 - r_a1/fm_inctrl */ + 0x80, /* 06/06 - l_dac_inctrl */ + 0x80, /* 07/07 - r_dac_inctrl */ + 0x00, /* 08/08 - ply_dataform_reg */ + 0x00, /* 09/09 - if_conf */ + 0x00, /* 0a/10 - pin_ctrl */ + 0x00, /* 0b/11 - err_init_reg */ + 0x0a, /* 0c/12 - id_reg */ + 0x00, /* 0d/13 - reserved */ + 0x00, /* 0e/14 - ply_upcount_reg */ + 0x00, /* 0f/15 - ply_lowcount_reg */ + 0x88, /* 10/16 - reserved/l_a1_inctrl */ + 0x88, /* 11/17 - reserved/r_a1_inctrl */ + 0x88, /* 12/18 - l_line_inctrl */ + 0x88, /* 13/19 - r_line_inctrl */ + 0x88, /* 14/20 - l_mic_inctrl */ + 0x88, /* 15/21 - r_mic_inctrl */ + 0x80, /* 16/22 - l_out_outctrl */ + 0x80, /* 17/23 - r_out_outctrl */ + 0x00, /* 18/24 - reserved */ + 0x00, /* 19/25 - reserved */ + 0x00, /* 1a/26 - reserved */ + 0x00, /* 1b/27 - reserved */ + 0x00, /* 1c/28 - cap_dataform_reg */ + 0x00, /* 1d/29 - reserved */ + 0x00, /* 1e/30 - cap_upcount_reg */ + 0x00 /* 1f/31 - cap_lowcount_reg */ +}; + + +static int snd_opti93x_busy_wait(struct snd_opti93x *chip) +{ + int timeout; + + for (timeout = 250; timeout-- > 0; udelay(10)) + if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_INIT)) + return 0; + + snd_printk("chip still busy.\n"); + return -EBUSY; +} + +static unsigned char snd_opti93x_in(struct snd_opti93x *chip, unsigned char reg) +{ + snd_opti93x_busy_wait(chip); + outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); + return inb(OPTi93X_PORT(chip, DATA)); +} + +static void snd_opti93x_out(struct snd_opti93x *chip, unsigned char reg, + unsigned char value) +{ + snd_opti93x_busy_wait(chip); + outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); + outb(value, OPTi93X_PORT(chip, DATA)); +} + +static void snd_opti93x_out_image(struct snd_opti93x *chip, unsigned char reg, + unsigned char value) +{ + snd_opti93x_out(chip, reg, chip->image[reg] = value); +} + +static void snd_opti93x_out_mask(struct snd_opti93x *chip, unsigned char reg, + unsigned char mask, unsigned char value) +{ + snd_opti93x_out_image(chip, reg, + (chip->image[reg] & ~mask) | (value & mask)); +} + + +static void snd_opti93x_mce_up(struct snd_opti93x *chip) +{ + snd_opti93x_busy_wait(chip); + + chip->mce_bit = OPTi93X_MCE; + if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE)) + outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); +} + +static void snd_opti93x_mce_down(struct snd_opti93x *chip) +{ + snd_opti93x_busy_wait(chip); + + chip->mce_bit = 0; + if (inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE) + outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); +} + +#define snd_opti93x_mute_reg(chip, reg, mute) \ + snd_opti93x_out(chip, reg, mute ? 0x80 : chip->image[reg]); + +static void snd_opti93x_mute(struct snd_opti93x *chip, int mute) +{ + mute = mute ? 1 : 0; + if (chip->mute == mute) + return; + + chip->mute = mute; + + snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_CD_RIGHT_INPUT, mute); + switch (chip->hardware) { + case OPTi9XX_HW_82C930: + snd_opti93x_mute_reg(chip, OPTi930_AUX_LEFT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi930_AUX_RIGHT_INPUT, mute); + break; + case OPTi9XX_HW_82C931: + case OPTi9XX_HW_82C933: + snd_opti93x_mute_reg(chip, OPTi931_FM_LEFT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi931_FM_RIGHT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi931_AUX_LEFT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi931_AUX_RIGHT_INPUT, mute); + } + snd_opti93x_mute_reg(chip, OPTi93X_DAC_LEFT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_DAC_RIGHT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_LINE_LEFT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_LINE_RIGHT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_MIC_LEFT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute); + snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute); +} + + +static unsigned int snd_opti93x_get_count(unsigned char format, + unsigned int size) +{ + switch (format & 0xe0) { + case OPTi93X_LINEAR_16_LIT: + case OPTi93X_LINEAR_16_BIG: + size >>= 1; + break; + case OPTi93X_ADPCM_16: + return size >> 2; + } + return (format & OPTi93X_STEREO) ? (size >> 1) : size; +} + +static unsigned int rates[] = { 5512, 6615, 8000, 9600, 11025, 16000, + 18900, 22050, 27428, 32000, 33075, 37800, + 44100, 48000 }; +#define RATES ARRAY_SIZE(rates) + +static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + .count = RATES, + .list = rates, + .mask = 0, +}; + +static unsigned char bits[] = { 0x01, 0x0f, 0x00, 0x0e, 0x03, 0x02, + 0x05, 0x07, 0x04, 0x06, 0x0d, 0x09, + 0x0b, 0x0c}; + +static unsigned char snd_opti93x_get_freq(unsigned int rate) +{ + unsigned int i; + + for (i = 0; i < RATES; i++) { + if (rate == rates[i]) + return bits[i]; + } + snd_BUG(); + return bits[RATES-1]; +} + +static unsigned char snd_opti93x_get_format(struct snd_opti93x *chip, + unsigned int format, int channels) +{ + unsigned char retval = OPTi93X_LINEAR_8; + + switch (format) { + case SNDRV_PCM_FORMAT_MU_LAW: + retval = OPTi93X_ULAW_8; + break; + case SNDRV_PCM_FORMAT_A_LAW: + retval = OPTi93X_ALAW_8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + retval = OPTi93X_LINEAR_16_LIT; + break; + case SNDRV_PCM_FORMAT_S16_BE: + retval = OPTi93X_LINEAR_16_BIG; + break; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + retval = OPTi93X_ADPCM_16; + } + return (channels > 1) ? (retval | OPTi93X_STEREO) : retval; +} + + +static void snd_opti93x_playback_format(struct snd_opti93x *chip, unsigned char fmt) +{ + unsigned char mask; + + snd_opti93x_mute(chip, 1); + + snd_opti93x_mce_up(chip); + mask = (chip->mode & OPTi93X_MODE_CAPTURE) ? 0xf0 : 0xff; + snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, mask, fmt); + snd_opti93x_mce_down(chip); + + snd_opti93x_mute(chip, 0); +} + +static void snd_opti93x_capture_format(struct snd_opti93x *chip, unsigned char fmt) +{ + snd_opti93x_mute(chip, 1); + + snd_opti93x_mce_up(chip); + if (!(chip->mode & OPTi93X_MODE_PLAY)) + snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, 0x0f, fmt); + else + fmt = chip->image[OPTi93X_PLAY_FORMAT] & 0xf0; + snd_opti93x_out_image(chip, OPTi93X_CAPT_FORMAT, fmt); + snd_opti93x_mce_down(chip); + + snd_opti93x_mute(chip, 0); +} + + +static int snd_opti93x_open(struct snd_opti93x *chip, unsigned int mode) +{ + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + + if (chip->mode & mode) { + spin_unlock_irqrestore(&chip->lock, flags); + return -EAGAIN; + } + + if (!(chip->mode & OPTi93X_MODE_OPEN)) { + outb(0x00, OPTi93X_PORT(chip, STATUS)); + snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, + OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE); + chip->mode = mode; + } + else + chip->mode |= mode; + + spin_unlock_irqrestore(&chip->lock, flags); + return 0; +} + +static void snd_opti93x_close(struct snd_opti93x *chip, unsigned int mode) +{ + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + + chip->mode &= ~mode; + if (chip->mode & OPTi93X_MODE_OPEN) { + spin_unlock_irqrestore(&chip->lock, flags); + return; + } + + snd_opti93x_mute(chip, 1); + + outb(0, OPTi93X_PORT(chip, STATUS)); + snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, + ~OPTi93X_IRQ_ENABLE); + + snd_opti93x_mce_up(chip); + snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00); + snd_opti93x_mce_down(chip); + chip->mode = 0; + + snd_opti93x_mute(chip, 0); + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int snd_opti93x_trigger(struct snd_pcm_substream *substream, + unsigned char what, int cmd) +{ + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_STOP: + { + unsigned int what = 0; + struct snd_pcm_substream *s; + snd_pcm_group_for_each_entry(s, substream) { + if (s == chip->playback_substream) { + what |= OPTi93X_PLAYBACK_ENABLE; + snd_pcm_trigger_done(s, substream); + } else if (s == chip->capture_substream) { + what |= OPTi93X_CAPTURE_ENABLE; + snd_pcm_trigger_done(s, substream); + } + } + spin_lock(&chip->lock); + if (cmd == SNDRV_PCM_TRIGGER_START) { + snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what); + if (what & OPTi93X_CAPTURE_ENABLE) + udelay(50); + } else + snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00); + spin_unlock(&chip->lock); + break; + } + default: + return -EINVAL; + } + return 0; +} + +static int snd_opti93x_playback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + return snd_opti93x_trigger(substream, + OPTi93X_PLAYBACK_ENABLE, cmd); +} + +static int snd_opti93x_capture_trigger(struct snd_pcm_substream *substream, int cmd) +{ + return snd_opti93x_trigger(substream, + OPTi93X_CAPTURE_ENABLE, cmd); +} + +static int snd_opti93x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); +} + + +static int snd_opti93x_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_lib_free_pages(substream); + return 0; +} + + +static int snd_opti93x_playback_prepare(struct snd_pcm_substream *substream) +{ + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned long flags; + unsigned char format; + unsigned int count = snd_pcm_lib_period_bytes(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); + + spin_lock_irqsave(&chip->lock, flags); + + chip->p_dma_size = size; + snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, + OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO, + ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO)); + + snd_dma_program(chip->dma1, runtime->dma_addr, size, + DMA_MODE_WRITE | DMA_AUTOINIT); + + format = snd_opti93x_get_freq(runtime->rate); + format |= snd_opti93x_get_format(chip, runtime->format, + runtime->channels); + snd_opti93x_playback_format(chip, format); + format = chip->image[OPTi93X_PLAY_FORMAT]; + + count = snd_opti93x_get_count(format, count) - 1; + snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count); + snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8); + + spin_unlock_irqrestore(&chip->lock, flags); + return 0; +} + +static int snd_opti93x_capture_prepare(struct snd_pcm_substream *substream) +{ + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned long flags; + unsigned char format; + unsigned int count = snd_pcm_lib_period_bytes(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); + + spin_lock_irqsave(&chip->lock, flags); + + chip->c_dma_size = size; + snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, + OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0); + + snd_dma_program(chip->dma2, runtime->dma_addr, size, + DMA_MODE_READ | DMA_AUTOINIT); + + format = snd_opti93x_get_freq(runtime->rate); + format |= snd_opti93x_get_format(chip, runtime->format, + runtime->channels); + snd_opti93x_capture_format(chip, format); + format = chip->image[OPTi93X_CAPT_FORMAT]; + + count = snd_opti93x_get_count(format, count) - 1; + snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count); + snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8); + + spin_unlock_irqrestore(&chip->lock, flags); + return 0; +} + +static snd_pcm_uframes_t snd_opti93x_playback_pointer(struct snd_pcm_substream *substream) +{ + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + size_t ptr; + + if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE)) + return 0; + + ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); + return bytes_to_frames(substream->runtime, ptr); +} + +static snd_pcm_uframes_t snd_opti93x_capture_pointer(struct snd_pcm_substream *substream) +{ + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + size_t ptr; + + if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_CAPTURE_ENABLE)) + return 0; + + ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size); + return bytes_to_frames(substream->runtime, ptr); +} + + +static void snd_opti93x_overrange(struct snd_opti93x *chip) +{ + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + + if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02)) + chip->capture_substream->runtime->overrange++; + + spin_unlock_irqrestore(&chip->lock, flags); +} + static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) { - struct snd_cs4231 *codec = dev_id; - struct snd_opti9xx *chip = codec->card->private_data; + struct snd_opti93x *codec = dev_id; unsigned char status; - status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11)); + status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11)); if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) snd_pcm_period_elapsed(codec->playback_substream); if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { - snd_cs4231_overrange(codec); + snd_opti93x_overrange(codec); snd_pcm_period_elapsed(codec->capture_substream); } outb(0x00, OPTi93X_PORT(codec, STATUS)); return IRQ_HANDLED; } + +static struct snd_pcm_hardware snd_opti93x_playback = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), + .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), + .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, + .rate_min = 5512, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = 64, + .period_bytes_max = (128*1024), + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static struct snd_pcm_hardware snd_opti93x_capture = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), + .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 5512, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = 64, + .period_bytes_max = (128*1024), + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static int snd_opti93x_playback_open(struct snd_pcm_substream *substream) +{ + int error; + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0) + return error; + snd_pcm_set_sync(substream); + chip->playback_substream = substream; + runtime->hw = snd_opti93x_playback; + snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); + return error; +} + +static int snd_opti93x_capture_open(struct snd_pcm_substream *substream) +{ + int error; + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0) + return error; + runtime->hw = snd_opti93x_capture; + snd_pcm_set_sync(substream); + chip->capture_substream = substream; + snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); + return error; +} + +static int snd_opti93x_playback_close(struct snd_pcm_substream *substream) +{ + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + + chip->playback_substream = NULL; + snd_opti93x_close(chip, OPTi93X_MODE_PLAY); + return 0; +} + +static int snd_opti93x_capture_close(struct snd_pcm_substream *substream) +{ + struct snd_opti93x *chip = snd_pcm_substream_chip(substream); + + chip->capture_substream = NULL; + snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE); + return 0; +} + + +static void snd_opti93x_init(struct snd_opti93x *chip) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&chip->lock, flags); + snd_opti93x_mce_up(chip); + + for (i = 0; i < 32; i++) + snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]); + + snd_opti93x_mce_down(chip); + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int snd_opti93x_probe(struct snd_opti93x *chip) +{ + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&chip->lock, flags); + val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f; + spin_unlock_irqrestore(&chip->lock, flags); + + return (val == 0x0a) ? 0 : -ENODEV; +} + +static int snd_opti93x_free(struct snd_opti93x *chip) +{ + release_and_free_resource(chip->res_port); + if (chip->dma1 >= 0) { + disable_dma(chip->dma1); + free_dma(chip->dma1); + } + if (chip->dma2 >= 0) { + disable_dma(chip->dma2); + free_dma(chip->dma2); + } + if (chip->irq >= 0) { + free_irq(chip->irq, chip); + } + kfree(chip); + return 0; +} + +static int snd_opti93x_dev_free(struct snd_device *device) +{ + struct snd_opti93x *chip = device->device_data; + return snd_opti93x_free(chip); +} + +static const char *snd_opti93x_chip_id(struct snd_opti93x *codec) +{ + switch (codec->hardware) { + case OPTi9XX_HW_82C930: return "82C930"; + case OPTi9XX_HW_82C931: return "82C931"; + case OPTi9XX_HW_82C933: return "82C933"; + default: return "???"; + } +} + +static int snd_opti93x_create(struct snd_card *card, struct snd_opti9xx *chip, + int dma1, int dma2, + struct snd_opti93x **rcodec) +{ + static struct snd_device_ops ops = { + .dev_free = snd_opti93x_dev_free, + }; + int error; + struct snd_opti93x *codec; + + *rcodec = NULL; + codec = kzalloc(sizeof(*codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + codec->irq = -1; + codec->dma1 = -1; + codec->dma2 = -1; + + if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) { + snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4); + snd_opti93x_free(codec); + return -EBUSY; + } + if (request_dma(dma1, "OPTI93x - 1")) { + snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1); + snd_opti93x_free(codec); + return -EBUSY; + } + codec->dma1 = chip->dma1; + if (request_dma(dma2, "OPTI93x - 2")) { + snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2); + snd_opti93x_free(codec); + return -EBUSY; + } + codec->dma2 = chip->dma2; + + if (request_irq(chip->irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec)) { + snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); + snd_opti93x_free(codec); + return -EBUSY; + } + + codec->card = card; + codec->port = chip->wss_base + 4; + codec->irq = chip->irq; + + spin_lock_init(&codec->lock); + codec->hardware = chip->hardware; + codec->chip = chip; + + if ((error = snd_opti93x_probe(codec))) { + snd_opti93x_free(codec); + return error; + } + + snd_opti93x_init(codec); + + /* Register device */ + if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) { + snd_opti93x_free(codec); + return error; + } + + *rcodec = codec; + return 0; +} + +static struct snd_pcm_ops snd_opti93x_playback_ops = { + .open = snd_opti93x_playback_open, + .close = snd_opti93x_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_opti93x_hw_params, + .hw_free = snd_opti93x_hw_free, + .prepare = snd_opti93x_playback_prepare, + .trigger = snd_opti93x_playback_trigger, + .pointer = snd_opti93x_playback_pointer, +}; + +static struct snd_pcm_ops snd_opti93x_capture_ops = { + .open = snd_opti93x_capture_open, + .close = snd_opti93x_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_opti93x_hw_params, + .hw_free = snd_opti93x_hw_free, + .prepare = snd_opti93x_capture_prepare, + .trigger = snd_opti93x_capture_trigger, + .pointer = snd_opti93x_capture_pointer, +}; + +static int snd_opti93x_pcm(struct snd_opti93x *codec, int device, struct snd_pcm **rpcm) +{ + int error; + struct snd_pcm *pcm; + + if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm)) < 0) + return error; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops); + + pcm->private_data = codec; + pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; + + strcpy(pcm->name, snd_opti93x_chip_id(codec)); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024); + + codec->pcm = pcm; + if (rpcm) + *rpcm = pcm; + return 0; +} + +/* + * MIXER part + */ + +static int snd_opti93x_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + static char *texts[4] = { + "Line1", "Aux", "Mic", "Mix" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 2; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item > 3) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_opti93x_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6; + ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6; + spin_unlock_irqrestore(&chip->lock, flags); + return 0; +} + +static int snd_opti93x_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + unsigned short left, right; + int change; + + if (ucontrol->value.enumerated.item[0] > 3 || + ucontrol->value.enumerated.item[1] > 3) + return -EINVAL; + left = ucontrol->value.enumerated.item[0] << 6; + right = ucontrol->value.enumerated.item[1] << 6; + spin_lock_irqsave(&chip->lock, flags); + left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left; + right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right; + change = left != chip->image[OPTi93X_MIXOUT_LEFT] || + right != chip->image[OPTi93X_MIXOUT_RIGHT]; + snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left); + snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right); + spin_unlock_irqrestore(&chip->lock, flags); + return change; +} + +#if 0 + +#define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_opti93x_info_single, \ + .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } + +static int snd_opti93x_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 16) & 0xff; + + uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} + +static int snd_opti93x_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + + spin_lock_irqsave(&chip->lock, flags); + ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; + spin_unlock_irqrestore(&chip->lock, flags); + if (invert) + ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; + return 0; +} + +static int snd_opti93x_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + int change; + unsigned short val; + + val = (ucontrol->value.integer.value[0] & mask); + if (invert) + val = mask - val; + val <<= shift; + spin_lock_irqsave(&chip->lock, flags); + val = (chip->image[reg] & ~(mask << shift)) | val; + change = val != chip->image[reg]; + snd_opti93x_out(chip, reg, val); + spin_unlock_irqrestore(&chip->lock, flags); + return change; +} + +#endif /* single */ + +#define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_opti93x_info_double, \ + .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } + +#define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \ + do { xctl.private_value ^= 22; } while (0) +#define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \ + do { xctl.private_value &= ~0x0000ffff; \ + xctl.private_value |= left_reg | (right_reg << 8); } while (0) + +static int snd_opti93x_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 24) & 0xff; + + uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} + +static int snd_opti93x_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + + spin_lock_irqsave(&chip->lock, flags); + ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; + ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; + spin_unlock_irqrestore(&chip->lock, flags); + if (invert) { + ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; + ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; + } + return 0; +} + +static int snd_opti93x_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + int change; + unsigned short val1, val2; + + val1 = ucontrol->value.integer.value[0] & mask; + val2 = ucontrol->value.integer.value[1] & mask; + if (invert) { + val1 = mask - val1; + val2 = mask - val2; + } + val1 <<= shift_left; + val2 <<= shift_right; + spin_lock_irqsave(&chip->lock, flags); + val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; + val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; + change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; + snd_opti93x_out_image(chip, left_reg, val1); + snd_opti93x_out_image(chip, right_reg, val2); + spin_unlock_irqrestore(&chip->lock, flags); + return change; +} + +static struct snd_kcontrol_new snd_opti93x_controls[] __devinitdata = { +OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), +OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), +OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1), +OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1), +OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1), +OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1), +OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1), +OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), +OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), +OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), +OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1), +OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1), +OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1), +OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), +OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), +OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = snd_opti93x_info_mux, + .get = snd_opti93x_get_mux, + .put = snd_opti93x_put_mux, +} +}; + +static int __devinit snd_opti93x_mixer(struct snd_opti93x *chip) +{ + struct snd_card *card; + struct snd_kcontrol_new knew; + int err; + unsigned int idx; + + snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); + + card = chip->card; + + strcpy(card->mixername, snd_opti93x_chip_id(chip)); + + for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { + knew = snd_opti93x_controls[idx]; + if (chip->hardware == OPTi9XX_HW_82C930) { + if (strstr(knew.name, "FM")) /* skip FM controls */ + continue; + else if (strcmp(knew.name, "Mic Playback Volume")) + OPTi93X_DOUBLE_INVERT_INVERT(knew); + else if (strstr(knew.name, "Aux")) + OPTi93X_DOUBLE_CHANGE_REGS(knew, OPTi930_AUX_LEFT_INPUT, OPTi930_AUX_RIGHT_INPUT); + else if (strcmp(knew.name, "PCM Playback Volume")) + OPTi93X_DOUBLE_INVERT_INVERT(knew); + else if (strcmp(knew.name, "Master Playback Volume")) + OPTi93X_DOUBLE_INVERT_INVERT(knew); + } + if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opti93x_controls[idx], chip))) < 0) + return err; + } + return 0; +} + #endif /* OPTi93X */ static int __devinit snd_card_opti9xx_detect(struct snd_card *card, @@ -685,16 +1739,8 @@ static void snd_card_opti9xx_free(struct snd_card *card) { struct snd_opti9xx *chip = card->private_data; - if (chip) { -#ifdef OPTi93X - struct snd_cs4231 *codec = chip->codec; - if (codec->irq > 0) { - disable_irq(codec->irq); - free_irq(codec->irq, codec); - } -#endif + if (chip) release_and_free_resource(chip->res_mc_base); - } } static int __devinit snd_opti9xx_probe(struct snd_card *card) @@ -702,11 +1748,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; int error; struct snd_opti9xx *chip = card->private_data; -#if defined(CS4231) || defined(OPTi93X) +#if defined(OPTi93X) + struct snd_opti93x *codec; +#elif defined(CS4231) struct snd_cs4231 *codec; -#ifdef CS4231 struct snd_timer *timer; -#endif #else struct snd_ad1848 *codec; #endif @@ -738,34 +1784,26 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) if ((error = snd_opti9xx_configure(chip))) return error; -#if defined(CS4231) || defined(OPTi93X) +#if defined(OPTi93X) + if ((error = snd_opti93x_create(card, chip, chip->dma1, chip->dma2, &codec))) + return error; + if ((error = snd_opti93x_pcm(codec, 0, &pcm)) < 0) + return error; + if ((error = snd_opti93x_mixer(codec)) < 0) + return error; +#elif defined(CS4231) if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1, chip->irq, chip->dma1, chip->dma2, -#ifdef CS4231 - CS4231_HW_DETECT, 0, -#else /* OPTi93x */ - CS4231_HW_OPTI93X, CS4231_HWSHARE_IRQ, -#endif + CS4231_HW_DETECT, + 0, &codec)) < 0) return error; -#ifdef OPTi93X - chip->codec = codec; -#endif if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) return error; if ((error = snd_cs4231_mixer(codec)) < 0) return error; -#ifdef CS4231 if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) return error; -#else /* OPTI93X */ - error = request_irq(chip->irq, snd_opti93x_interrupt, - IRQF_DISABLED, DEV_NAME" - WSS", codec); - if (error < 0) { - snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); - return error; - } -#endif #else if ((error = snd_ad1848_create(card, chip->wss_base + 4, chip->irq, chip->dma1, diff --git a/trunk/sound/isa/sb/Makefile b/trunk/sound/isa/sb/Makefile index 1098a56b2f4b..c9d1c986d70e 100644 --- a/trunk/sound/isa/sb/Makefile +++ b/trunk/sound/isa/sb/Makefile @@ -34,3 +34,5 @@ ifeq ($(CONFIG_SND_SB16_CSP),y) obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o endif obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o + +obj-m := $(sort $(obj-m)) diff --git a/trunk/sound/isa/wavefront/wavefront_synth.c b/trunk/sound/isa/wavefront/wavefront_synth.c index 0bb9b9256601..95eeca163354 100644 --- a/trunk/sound/isa/wavefront/wavefront_synth.c +++ b/trunk/sound/isa/wavefront/wavefront_synth.c @@ -1939,7 +1939,7 @@ static int __devinit wavefront_download_firmware (snd_wavefront_t *dev, char *path) { - const unsigned char *buf; + unsigned char *buf; int len, err; int section_cnt_downloaded = 0; const struct firmware *firmware; diff --git a/trunk/sound/mips/Kconfig b/trunk/sound/mips/Kconfig index a9823fad85c2..531f8ba96a71 100644 --- a/trunk/sound/mips/Kconfig +++ b/trunk/sound/mips/Kconfig @@ -1,34 +1,15 @@ # ALSA MIPS drivers -menuconfig SND_MIPS - bool "MIPS sound devices" - depends on MIPS - default y - help - Support for sound devices of MIPS architectures. - -if SND_MIPS - -config SND_SGI_O2 - tristate "SGI O2 Audio" - depends on SGI_IP32 - help - Sound support for the SGI O2 Workstation. - -config SND_SGI_HAL2 - tristate "SGI HAL2 Audio" - depends on SGI_HAS_HAL2 - help - Sound support for the SGI Indy and Indigo2 Workstation. - +menu "ALSA MIPS devices" + depends on SND!=n && MIPS config SND_AU1X00 tristate "Au1x00 AC97 Port Driver" - depends on SOC_AU1000 || SOC_AU1100 || SOC_AU1500 + depends on (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SND select SND_PCM select SND_AC97_CODEC help ALSA Sound driver for the Au1x00's AC97 port. -endif # SND_MIPS +endmenu diff --git a/trunk/sound/mips/Makefile b/trunk/sound/mips/Makefile index 861ec0a574b4..47afed971fba 100644 --- a/trunk/sound/mips/Makefile +++ b/trunk/sound/mips/Makefile @@ -3,10 +3,6 @@ # snd-au1x00-objs := au1x00.o -snd-sgi-o2-objs := sgio2audio.o ad1843.o -snd-sgi-hal2-objs := hal2.o # Toplevel Module Dependency obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o -obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o -obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o diff --git a/trunk/sound/mips/ad1843.c b/trunk/sound/mips/ad1843.c deleted file mode 100644 index c624510ec374..000000000000 --- a/trunk/sound/mips/ad1843.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * AD1843 low level driver - * - * Copyright 2003 Vivien Chappelier - * Copyright 2008 Thomas Bogendoerfer - * - * inspired from vwsnd.c (SGI VW audio driver) - * Copyright 1999 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include - -/* - * AD1843 bitfield definitions. All are named as in the AD1843 data - * sheet, with ad1843_ prepended and individual bit numbers removed. - * - * E.g., bits LSS0 through LSS2 become ad1843_LSS. - * - * Only the bitfields we need are defined. - */ - -struct ad1843_bitfield { - char reg; - char lo_bit; - char nbits; -}; - -static const struct ad1843_bitfield - ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */ - ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */ - ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */ - ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */ - ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */ - ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */ - ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */ - ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */ - ad1843_RD2M = { 3, 0, 5 }, /* Right DAC 2 Mix Gain/Atten */ - ad1843_RD2MM = { 3, 7, 1 }, /* Right DAC 2 Mix Mute */ - ad1843_LD2M = { 3, 8, 5 }, /* Left DAC 2 Mix Gain/Atten */ - ad1843_LD2MM = { 3, 15, 1 }, /* Left DAC 2 Mix Mute */ - ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */ - ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */ - ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */ - ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */ - ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */ - ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */ - ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */ - ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */ - ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */ - ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */ - ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */ - ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */ - ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */ - ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */ - ad1843_MPOM = { 8, 6, 1 }, /* Mono Output Mute */ - ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */ - ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */ - ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */ - ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */ - ad1843_RDA2G = { 10, 0, 6 }, /* Right DAC2 Analog/Digital Gain */ - ad1843_RDA2GM = { 10, 7, 1 }, /* Right DAC2 Analog Mute */ - ad1843_LDA2G = { 10, 8, 6 }, /* Left DAC2 Analog/Digital Gain */ - ad1843_LDA2GM = { 10, 15, 1 }, /* Left DAC2 Analog Mute */ - ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */ - ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */ - ad1843_RDA2AM = { 12, 7, 1 }, /* Right DAC2 Digital Mute */ - ad1843_LDA2AM = { 12, 15, 1 }, /* Left DAC2 Digital Mute */ - ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */ - ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */ - ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */ - ad1843_DA2C = { 15, 10, 2 }, /* DAC2 Sample Rate Source */ - ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */ - ad1843_C2C = { 20, 0, 16 }, /* Clock 2 Sample Rate Select */ - ad1843_C3C = { 23, 0, 16 }, /* Clock 3 Sample Rate Select */ - ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */ - ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */ - ad1843_DAMIX = { 25, 14, 1 }, /* DAC Digital Mix Enable */ - ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */ - ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */ - ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */ - ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */ - ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */ - ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */ - ad1843_DA2F = { 26, 10, 2 }, /* DAC2 Data Format Select */ - ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */ - ad1843_DA2SM = { 26, 15, 1 }, /* DAC2 Stereo/Mono Mode Select */ - ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */ - ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */ - ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */ - ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */ - ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */ - ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */ - ad1843_DDMEN = { 27, 12, 1 }, /* DAC2 to DAC1 Mix Enable */ - ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */ - ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */ - ad1843_C3EN = { 28, 13, 1 }, /* Clock Generator 3 Enable */ - ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */ - -/* - * The various registers of the AD1843 use three different formats for - * specifying gain. The ad1843_gain structure parameterizes the - * formats. - */ - -struct ad1843_gain { - int negative; /* nonzero if gain is negative. */ - const struct ad1843_bitfield *lfield; - const struct ad1843_bitfield *rfield; - const struct ad1843_bitfield *lmute; - const struct ad1843_bitfield *rmute; -}; - -static const struct ad1843_gain ad1843_gain_RECLEV = { - .negative = 0, - .lfield = &ad1843_LIG, - .rfield = &ad1843_RIG -}; -static const struct ad1843_gain ad1843_gain_LINE = { - .negative = 1, - .lfield = &ad1843_LX1M, - .rfield = &ad1843_RX1M, - .lmute = &ad1843_LX1MM, - .rmute = &ad1843_RX1MM -}; -static const struct ad1843_gain ad1843_gain_LINE_2 = { - .negative = 1, - .lfield = &ad1843_LDA2G, - .rfield = &ad1843_RDA2G, - .lmute = &ad1843_LDA2GM, - .rmute = &ad1843_RDA2GM -}; -static const struct ad1843_gain ad1843_gain_MIC = { - .negative = 1, - .lfield = &ad1843_LMCM, - .rfield = &ad1843_RMCM, - .lmute = &ad1843_LMCMM, - .rmute = &ad1843_RMCMM -}; -static const struct ad1843_gain ad1843_gain_PCM_0 = { - .negative = 1, - .lfield = &ad1843_LDA1G, - .rfield = &ad1843_RDA1G, - .lmute = &ad1843_LDA1GM, - .rmute = &ad1843_RDA1GM -}; -static const struct ad1843_gain ad1843_gain_PCM_1 = { - .negative = 1, - .lfield = &ad1843_LD2M, - .rfield = &ad1843_RD2M, - .lmute = &ad1843_LD2MM, - .rmute = &ad1843_RD2MM -}; - -static const struct ad1843_gain *ad1843_gain[AD1843_GAIN_SIZE] = -{ - &ad1843_gain_RECLEV, - &ad1843_gain_LINE, - &ad1843_gain_LINE_2, - &ad1843_gain_MIC, - &ad1843_gain_PCM_0, - &ad1843_gain_PCM_1, -}; - -/* read the current value of an AD1843 bitfield. */ - -static int ad1843_read_bits(struct snd_ad1843 *ad1843, - const struct ad1843_bitfield *field) -{ - int w; - - w = ad1843->read(ad1843->chip, field->reg); - return w >> field->lo_bit & ((1 << field->nbits) - 1); -} - -/* - * write a new value to an AD1843 bitfield and return the old value. - */ - -static int ad1843_write_bits(struct snd_ad1843 *ad1843, - const struct ad1843_bitfield *field, - int newval) -{ - int w, mask, oldval, newbits; - - w = ad1843->read(ad1843->chip, field->reg); - mask = ((1 << field->nbits) - 1) << field->lo_bit; - oldval = (w & mask) >> field->lo_bit; - newbits = (newval << field->lo_bit) & mask; - w = (w & ~mask) | newbits; - ad1843->write(ad1843->chip, field->reg, w); - - return oldval; -} - -/* - * ad1843_read_multi reads multiple bitfields from the same AD1843 - * register. It uses a single read cycle to do it. (Reading the - * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 - * microseconds.) - * - * Called like this. - * - * ad1843_read_multi(ad1843, nfields, - * &ad1843_FIELD1, &val1, - * &ad1843_FIELD2, &val2, ...); - */ - -static void ad1843_read_multi(struct snd_ad1843 *ad1843, int argcount, ...) -{ - va_list ap; - const struct ad1843_bitfield *fp; - int w = 0, mask, *value, reg = -1; - - va_start(ap, argcount); - while (--argcount >= 0) { - fp = va_arg(ap, const struct ad1843_bitfield *); - value = va_arg(ap, int *); - if (reg == -1) { - reg = fp->reg; - w = ad1843->read(ad1843->chip, reg); - } - - mask = (1 << fp->nbits) - 1; - *value = w >> fp->lo_bit & mask; - } - va_end(ap); -} - -/* - * ad1843_write_multi stores multiple bitfields into the same AD1843 - * register. It uses one read and one write cycle to do it. - * - * Called like this. - * - * ad1843_write_multi(ad1843, nfields, - * &ad1843_FIELD1, val1, - * &ad1843_FIELF2, val2, ...); - */ - -static void ad1843_write_multi(struct snd_ad1843 *ad1843, int argcount, ...) -{ - va_list ap; - int reg; - const struct ad1843_bitfield *fp; - int value; - int w, m, mask, bits; - - mask = 0; - bits = 0; - reg = -1; - - va_start(ap, argcount); - while (--argcount >= 0) { - fp = va_arg(ap, const struct ad1843_bitfield *); - value = va_arg(ap, int); - if (reg == -1) - reg = fp->reg; - else - BUG_ON(reg != fp->reg); - m = ((1 << fp->nbits) - 1) << fp->lo_bit; - mask |= m; - bits |= (value << fp->lo_bit) & m; - } - va_end(ap); - - if (~mask & 0xFFFF) - w = ad1843->read(ad1843->chip, reg); - else - w = 0; - w = (w & ~mask) | bits; - ad1843->write(ad1843->chip, reg, w); -} - -int ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id) -{ - const struct ad1843_gain *gp = ad1843_gain[id]; - int ret; - - ret = (1 << gp->lfield->nbits); - if (!gp->lmute) - ret -= 1; - return ret; -} - -/* - * ad1843_get_gain reads the specified register and extracts the gain value - * using the supplied gain type. - */ - -int ad1843_get_gain(struct snd_ad1843 *ad1843, int id) -{ - int lg, rg, lm, rm; - const struct ad1843_gain *gp = ad1843_gain[id]; - unsigned short mask = (1 << gp->lfield->nbits) - 1; - - ad1843_read_multi(ad1843, 2, gp->lfield, &lg, gp->rfield, &rg); - if (gp->negative) { - lg = mask - lg; - rg = mask - rg; - } - if (gp->lmute) { - ad1843_read_multi(ad1843, 2, gp->lmute, &lm, gp->rmute, &rm); - if (lm) - lg = 0; - if (rm) - rg = 0; - } - return lg << 0 | rg << 8; -} - -/* - * Set an audio channel's gain. - * - * Returns the new gain, which may be lower than the old gain. - */ - -int ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval) -{ - const struct ad1843_gain *gp = ad1843_gain[id]; - unsigned short mask = (1 << gp->lfield->nbits) - 1; - - int lg = (newval >> 0) & mask; - int rg = (newval >> 8) & mask; - int lm = (lg == 0) ? 1 : 0; - int rm = (rg == 0) ? 1 : 0; - - if (gp->negative) { - lg = mask - lg; - rg = mask - rg; - } - if (gp->lmute) - ad1843_write_multi(ad1843, 2, gp->lmute, lm, gp->rmute, rm); - ad1843_write_multi(ad1843, 2, gp->lfield, lg, gp->rfield, rg); - return ad1843_get_gain(ad1843, id); -} - -/* Returns the current recording source */ - -int ad1843_get_recsrc(struct snd_ad1843 *ad1843) -{ - int val = ad1843_read_bits(ad1843, &ad1843_LSS); - - if (val < 0 || val > 2) { - val = 2; - ad1843_write_multi(ad1843, 2, - &ad1843_LSS, val, &ad1843_RSS, val); - } - return val; -} - -/* - * Set recording source. - * - * Returns newsrc on success, -errno on failure. - */ - -int ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc) -{ - if (newsrc < 0 || newsrc > 2) - return -EINVAL; - - ad1843_write_multi(ad1843, 2, &ad1843_LSS, newsrc, &ad1843_RSS, newsrc); - return newsrc; -} - -/* Setup ad1843 for D/A conversion. */ - -void ad1843_setup_dac(struct snd_ad1843 *ad1843, - unsigned int id, - unsigned int framerate, - snd_pcm_format_t fmt, - unsigned int channels) -{ - int ad_fmt = 0, ad_mode = 0; - - switch (fmt) { - case SNDRV_PCM_FORMAT_S8: - ad_fmt = 0; - break; - case SNDRV_PCM_FORMAT_U8: - ad_fmt = 0; - break; - case SNDRV_PCM_FORMAT_S16_LE: - ad_fmt = 1; - break; - case SNDRV_PCM_FORMAT_MU_LAW: - ad_fmt = 2; - break; - case SNDRV_PCM_FORMAT_A_LAW: - ad_fmt = 3; - break; - default: - break; - } - - switch (channels) { - case 2: - ad_mode = 0; - break; - case 1: - ad_mode = 1; - break; - default: - break; - } - - if (id) { - ad1843_write_bits(ad1843, &ad1843_C2C, framerate); - ad1843_write_multi(ad1843, 2, - &ad1843_DA2SM, ad_mode, - &ad1843_DA2F, ad_fmt); - } else { - ad1843_write_bits(ad1843, &ad1843_C1C, framerate); - ad1843_write_multi(ad1843, 2, - &ad1843_DA1SM, ad_mode, - &ad1843_DA1F, ad_fmt); - } -} - -void ad1843_shutdown_dac(struct snd_ad1843 *ad1843, unsigned int id) -{ - if (id) - ad1843_write_bits(ad1843, &ad1843_DA2F, 1); - else - ad1843_write_bits(ad1843, &ad1843_DA1F, 1); -} - -void ad1843_setup_adc(struct snd_ad1843 *ad1843, - unsigned int framerate, - snd_pcm_format_t fmt, - unsigned int channels) -{ - int da_fmt = 0; - - switch (fmt) { - case SNDRV_PCM_FORMAT_S8: da_fmt = 0; break; - case SNDRV_PCM_FORMAT_U8: da_fmt = 0; break; - case SNDRV_PCM_FORMAT_S16_LE: da_fmt = 1; break; - case SNDRV_PCM_FORMAT_MU_LAW: da_fmt = 2; break; - case SNDRV_PCM_FORMAT_A_LAW: da_fmt = 3; break; - default: break; - } - - ad1843_write_bits(ad1843, &ad1843_C3C, framerate); - ad1843_write_multi(ad1843, 2, - &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt); -} - -void ad1843_shutdown_adc(struct snd_ad1843 *ad1843) -{ - /* nothing to do */ -} - -/* - * Fully initialize the ad1843. As described in the AD1843 data - * sheet, section "START-UP SEQUENCE". The numbered comments are - * subsection headings from the data sheet. See the data sheet, pages - * 52-54, for more info. - * - * return 0 on success, -errno on failure. */ - -int ad1843_init(struct snd_ad1843 *ad1843) -{ - unsigned long later; - - if (ad1843_read_bits(ad1843, &ad1843_INIT) != 0) { - printk(KERN_ERR "ad1843: AD1843 won't initialize\n"); - return -EIO; - } - - ad1843_write_bits(ad1843, &ad1843_SCF, 1); - - /* 4. Put the conversion resources into standby. */ - ad1843_write_bits(ad1843, &ad1843_PDNI, 0); - later = jiffies + msecs_to_jiffies(500); - - while (ad1843_read_bits(ad1843, &ad1843_PDNO)) { - if (time_after(jiffies, later)) { - printk(KERN_ERR - "ad1843: AD1843 won't power up\n"); - return -EIO; - } - schedule_timeout_interruptible(5); - } - - /* 5. Power up the clock generators and enable clock output pins. */ - ad1843_write_multi(ad1843, 3, - &ad1843_C1EN, 1, - &ad1843_C2EN, 1, - &ad1843_C3EN, 1); - - /* 6. Configure conversion resources while they are in standby. */ - - /* DAC1/2 use clock 1/2 as source, ADC uses clock 3. Always. */ - ad1843_write_multi(ad1843, 4, - &ad1843_DA1C, 1, - &ad1843_DA2C, 2, - &ad1843_ADLC, 3, - &ad1843_ADRC, 3); - - /* 7. Enable conversion resources. */ - ad1843_write_bits(ad1843, &ad1843_ADTLK, 1); - ad1843_write_multi(ad1843, 7, - &ad1843_ANAEN, 1, - &ad1843_AAMEN, 1, - &ad1843_DA1EN, 1, - &ad1843_DA2EN, 1, - &ad1843_DDMEN, 1, - &ad1843_ADLEN, 1, - &ad1843_ADREN, 1); - - /* 8. Configure conversion resources while they are enabled. */ - - /* set gain to 0 for all channels */ - ad1843_set_gain(ad1843, AD1843_GAIN_RECLEV, 0); - ad1843_set_gain(ad1843, AD1843_GAIN_LINE, 0); - ad1843_set_gain(ad1843, AD1843_GAIN_LINE_2, 0); - ad1843_set_gain(ad1843, AD1843_GAIN_MIC, 0); - ad1843_set_gain(ad1843, AD1843_GAIN_PCM_0, 0); - ad1843_set_gain(ad1843, AD1843_GAIN_PCM_1, 0); - - /* Unmute all channels. */ - /* DAC1 */ - ad1843_write_multi(ad1843, 2, &ad1843_LDA1GM, 0, &ad1843_RDA1GM, 0); - /* DAC2 */ - ad1843_write_multi(ad1843, 2, &ad1843_LDA2GM, 0, &ad1843_RDA2GM, 0); - - /* Set default recording source to Line In and set - * mic gain to +20 dB. - */ - ad1843_set_recsrc(ad1843, 2); - ad1843_write_multi(ad1843, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1); - - /* Set Speaker Out level to +/- 4V and unmute it. */ - ad1843_write_multi(ad1843, 3, - &ad1843_HPOS, 1, - &ad1843_HPOM, 0, - &ad1843_MPOM, 0); - - return 0; -} diff --git a/trunk/sound/mips/hal2.c b/trunk/sound/mips/hal2.c deleted file mode 100644 index db495be01861..000000000000 --- a/trunk/sound/mips/hal2.c +++ /dev/null @@ -1,947 +0,0 @@ -/* - * Driver for A2 audio system used in SGI machines - * Copyright (c) 2008 Thomas Bogendoerfer - * - * Based on OSS code from Ladislav Michl , which - * was based on code from Ulf Carlsson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "hal2.h" - -static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ -static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ - -module_param(index, int, 0444); -MODULE_PARM_DESC(index, "Index value for SGI HAL2 soundcard."); -module_param(id, charp, 0444); -MODULE_PARM_DESC(id, "ID string for SGI HAL2 soundcard."); -MODULE_DESCRIPTION("ALSA driver for SGI HAL2 audio"); -MODULE_AUTHOR("Thomas Bogendoerfer"); -MODULE_LICENSE("GPL"); - - -#define H2_BLOCK_SIZE 1024 -#define H2_BUF_SIZE 16384 - -struct hal2_pbus { - struct hpc3_pbus_dmacregs *pbus; - int pbusnr; - unsigned int ctrl; /* Current state of pbus->pbdma_ctrl */ -}; - -struct hal2_desc { - struct hpc_dma_desc desc; - u32 pad; /* padding */ -}; - -struct hal2_codec { - struct snd_pcm_indirect pcm_indirect; - struct snd_pcm_substream *substream; - - unsigned char *buffer; - dma_addr_t buffer_dma; - struct hal2_desc *desc; - dma_addr_t desc_dma; - int desc_count; - struct hal2_pbus pbus; - int voices; /* mono/stereo */ - unsigned int sample_rate; - unsigned int master; /* Master frequency */ - unsigned short mod; /* MOD value */ - unsigned short inc; /* INC value */ -}; - -#define H2_MIX_OUTPUT_ATT 0 -#define H2_MIX_INPUT_GAIN 1 - -struct snd_hal2 { - struct snd_card *card; - - struct hal2_ctl_regs *ctl_regs; /* HAL2 ctl registers */ - struct hal2_aes_regs *aes_regs; /* HAL2 aes registers */ - struct hal2_vol_regs *vol_regs; /* HAL2 vol registers */ - struct hal2_syn_regs *syn_regs; /* HAL2 syn registers */ - - struct hal2_codec dac; - struct hal2_codec adc; -}; - -#define H2_INDIRECT_WAIT(regs) while (hal2_read(®s->isr) & H2_ISR_TSTATUS); - -#define H2_READ_ADDR(addr) (addr | (1<<7)) -#define H2_WRITE_ADDR(addr) (addr) - -static inline u32 hal2_read(u32 *reg) -{ - return __raw_readl(reg); -} - -static inline void hal2_write(u32 val, u32 *reg) -{ - __raw_writel(val, reg); -} - - -static u32 hal2_i_read32(struct snd_hal2 *hal2, u16 addr) -{ - u32 ret; - struct hal2_ctl_regs *regs = hal2->ctl_regs; - - hal2_write(H2_READ_ADDR(addr), ®s->iar); - H2_INDIRECT_WAIT(regs); - ret = hal2_read(®s->idr0) & 0xffff; - hal2_write(H2_READ_ADDR(addr) | 0x1, ®s->iar); - H2_INDIRECT_WAIT(regs); - ret |= (hal2_read(®s->idr0) & 0xffff) << 16; - return ret; -} - -static void hal2_i_write16(struct snd_hal2 *hal2, u16 addr, u16 val) -{ - struct hal2_ctl_regs *regs = hal2->ctl_regs; - - hal2_write(val, ®s->idr0); - hal2_write(0, ®s->idr1); - hal2_write(0, ®s->idr2); - hal2_write(0, ®s->idr3); - hal2_write(H2_WRITE_ADDR(addr), ®s->iar); - H2_INDIRECT_WAIT(regs); -} - -static void hal2_i_write32(struct snd_hal2 *hal2, u16 addr, u32 val) -{ - struct hal2_ctl_regs *regs = hal2->ctl_regs; - - hal2_write(val & 0xffff, ®s->idr0); - hal2_write(val >> 16, ®s->idr1); - hal2_write(0, ®s->idr2); - hal2_write(0, ®s->idr3); - hal2_write(H2_WRITE_ADDR(addr), ®s->iar); - H2_INDIRECT_WAIT(regs); -} - -static void hal2_i_setbit16(struct snd_hal2 *hal2, u16 addr, u16 bit) -{ - struct hal2_ctl_regs *regs = hal2->ctl_regs; - - hal2_write(H2_READ_ADDR(addr), ®s->iar); - H2_INDIRECT_WAIT(regs); - hal2_write((hal2_read(®s->idr0) & 0xffff) | bit, ®s->idr0); - hal2_write(0, ®s->idr1); - hal2_write(0, ®s->idr2); - hal2_write(0, ®s->idr3); - hal2_write(H2_WRITE_ADDR(addr), ®s->iar); - H2_INDIRECT_WAIT(regs); -} - -static void hal2_i_clearbit16(struct snd_hal2 *hal2, u16 addr, u16 bit) -{ - struct hal2_ctl_regs *regs = hal2->ctl_regs; - - hal2_write(H2_READ_ADDR(addr), ®s->iar); - H2_INDIRECT_WAIT(regs); - hal2_write((hal2_read(®s->idr0) & 0xffff) & ~bit, ®s->idr0); - hal2_write(0, ®s->idr1); - hal2_write(0, ®s->idr2); - hal2_write(0, ®s->idr3); - hal2_write(H2_WRITE_ADDR(addr), ®s->iar); - H2_INDIRECT_WAIT(regs); -} - -static int hal2_gain_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - switch ((int)kcontrol->private_value) { - case H2_MIX_OUTPUT_ATT: - uinfo->value.integer.max = 31; - break; - case H2_MIX_INPUT_GAIN: - uinfo->value.integer.max = 15; - break; - } - return 0; -} - -static int hal2_gain_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol); - u32 tmp; - int l, r; - - switch ((int)kcontrol->private_value) { - case H2_MIX_OUTPUT_ATT: - tmp = hal2_i_read32(hal2, H2I_DAC_C2); - if (tmp & H2I_C2_MUTE) { - l = 0; - r = 0; - } else { - l = 31 - ((tmp >> H2I_C2_L_ATT_SHIFT) & 31); - r = 31 - ((tmp >> H2I_C2_R_ATT_SHIFT) & 31); - } - break; - case H2_MIX_INPUT_GAIN: - tmp = hal2_i_read32(hal2, H2I_ADC_C2); - l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15; - r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15; - break; - } - ucontrol->value.integer.value[0] = l; - ucontrol->value.integer.value[1] = r; - - return 0; -} - -static int hal2_gain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol); - u32 old, new; - int l, r; - - l = ucontrol->value.integer.value[0]; - r = ucontrol->value.integer.value[1]; - - switch ((int)kcontrol->private_value) { - case H2_MIX_OUTPUT_ATT: - old = hal2_i_read32(hal2, H2I_DAC_C2); - new = old & ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE); - if (l | r) { - l = 31 - l; - r = 31 - r; - new |= (l << H2I_C2_L_ATT_SHIFT); - new |= (r << H2I_C2_R_ATT_SHIFT); - } else - new |= H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE; - hal2_i_write32(hal2, H2I_DAC_C2, new); - break; - case H2_MIX_INPUT_GAIN: - old = hal2_i_read32(hal2, H2I_ADC_C2); - new = old & ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M); - new |= (l << H2I_C2_L_GAIN_SHIFT); - new |= (r << H2I_C2_R_GAIN_SHIFT); - hal2_i_write32(hal2, H2I_ADC_C2, new); - break; - } - return old != new; -} - -static struct snd_kcontrol_new hal2_ctrl_headphone __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Headphone Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = H2_MIX_OUTPUT_ATT, - .info = hal2_gain_info, - .get = hal2_gain_get, - .put = hal2_gain_put, -}; - -static struct snd_kcontrol_new hal2_ctrl_mic __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = H2_MIX_INPUT_GAIN, - .info = hal2_gain_info, - .get = hal2_gain_get, - .put = hal2_gain_put, -}; - -static int __devinit hal2_mixer_create(struct snd_hal2 *hal2) -{ - int err; - - /* mute DAC */ - hal2_i_write32(hal2, H2I_DAC_C2, - H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE); - /* mute ADC */ - hal2_i_write32(hal2, H2I_ADC_C2, 0); - - err = snd_ctl_add(hal2->card, - snd_ctl_new1(&hal2_ctrl_headphone, hal2)); - if (err < 0) - return err; - - err = snd_ctl_add(hal2->card, - snd_ctl_new1(&hal2_ctrl_mic, hal2)); - if (err < 0) - return err; - - return 0; -} - -static irqreturn_t hal2_interrupt(int irq, void *dev_id) -{ - struct snd_hal2 *hal2 = dev_id; - irqreturn_t ret = IRQ_NONE; - - /* decide what caused this interrupt */ - if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) { - snd_pcm_period_elapsed(hal2->dac.substream); - ret = IRQ_HANDLED; - } - if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) { - snd_pcm_period_elapsed(hal2->adc.substream); - ret = IRQ_HANDLED; - } - return ret; -} - -static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate) -{ - unsigned short mod; - - if (44100 % rate < 48000 % rate) { - mod = 4 * 44100 / rate; - codec->master = 44100; - } else { - mod = 4 * 48000 / rate; - codec->master = 48000; - } - - codec->inc = 4; - codec->mod = mod; - rate = 4 * codec->master / mod; - - return rate; -} - -static void hal2_set_dac_rate(struct snd_hal2 *hal2) -{ - unsigned int master = hal2->dac.master; - int inc = hal2->dac.inc; - int mod = hal2->dac.mod; - - hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0); - hal2_i_write32(hal2, H2I_BRES1_C2, - ((0xffff & (inc - mod - 1)) << 16) | inc); -} - -static void hal2_set_adc_rate(struct snd_hal2 *hal2) -{ - unsigned int master = hal2->adc.master; - int inc = hal2->adc.inc; - int mod = hal2->adc.mod; - - hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0); - hal2_i_write32(hal2, H2I_BRES2_C2, - ((0xffff & (inc - mod - 1)) << 16) | inc); -} - -static void hal2_setup_dac(struct snd_hal2 *hal2) -{ - unsigned int fifobeg, fifoend, highwater, sample_size; - struct hal2_pbus *pbus = &hal2->dac.pbus; - - /* Now we set up some PBUS information. The PBUS needs information about - * what portion of the fifo it will use. If it's receiving or - * transmitting, and finally whether the stream is little endian or big - * endian. The information is written later, on the start call. - */ - sample_size = 2 * hal2->dac.voices; - /* Fifo should be set to hold exactly four samples. Highwater mark - * should be set to two samples. */ - highwater = (sample_size * 2) >> 1; /* halfwords */ - fifobeg = 0; /* playback is first */ - fifoend = (sample_size * 4) >> 3; /* doublewords */ - pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD | - (highwater << 8) | (fifobeg << 16) | (fifoend << 24); - /* We disable everything before we do anything at all */ - pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; - hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); - /* Setup the HAL2 for playback */ - hal2_set_dac_rate(hal2); - /* Set endianess */ - hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX); - /* Set DMA bus */ - hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); - /* We are using 1st Bresenham clock generator for playback */ - hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) - | (1 << H2I_C1_CLKID_SHIFT) - | (hal2->dac.voices << H2I_C1_DATAT_SHIFT)); -} - -static void hal2_setup_adc(struct snd_hal2 *hal2) -{ - unsigned int fifobeg, fifoend, highwater, sample_size; - struct hal2_pbus *pbus = &hal2->adc.pbus; - - sample_size = 2 * hal2->adc.voices; - highwater = (sample_size * 2) >> 1; /* halfwords */ - fifobeg = (4 * 4) >> 3; /* record is second */ - fifoend = (4 * 4 + sample_size * 4) >> 3; /* doublewords */ - pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD | - (highwater << 8) | (fifobeg << 16) | (fifoend << 24); - pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; - hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); - /* Setup the HAL2 for record */ - hal2_set_adc_rate(hal2); - /* Set endianess */ - hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR); - /* Set DMA bus */ - hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); - /* We are using 2nd Bresenham clock generator for record */ - hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) - | (2 << H2I_C1_CLKID_SHIFT) - | (hal2->adc.voices << H2I_C1_DATAT_SHIFT)); -} - -static void hal2_start_dac(struct snd_hal2 *hal2) -{ - struct hal2_pbus *pbus = &hal2->dac.pbus; - - pbus->pbus->pbdma_dptr = hal2->dac.desc_dma; - pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; - /* enable DAC */ - hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); -} - -static void hal2_start_adc(struct snd_hal2 *hal2) -{ - struct hal2_pbus *pbus = &hal2->adc.pbus; - - pbus->pbus->pbdma_dptr = hal2->adc.desc_dma; - pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; - /* enable ADC */ - hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); -} - -static inline void hal2_stop_dac(struct snd_hal2 *hal2) -{ - hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; - /* The HAL2 itself may remain enabled safely */ -} - -static inline void hal2_stop_adc(struct snd_hal2 *hal2) -{ - hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; -} - -static int hal2_alloc_dmabuf(struct hal2_codec *codec) -{ - struct hal2_desc *desc; - dma_addr_t desc_dma, buffer_dma; - int count = H2_BUF_SIZE / H2_BLOCK_SIZE; - int i; - - codec->buffer = dma_alloc_noncoherent(NULL, H2_BUF_SIZE, - &buffer_dma, GFP_KERNEL); - if (!codec->buffer) - return -ENOMEM; - desc = dma_alloc_noncoherent(NULL, count * sizeof(struct hal2_desc), - &desc_dma, GFP_KERNEL); - if (!desc) { - dma_free_noncoherent(NULL, H2_BUF_SIZE, - codec->buffer, buffer_dma); - return -ENOMEM; - } - codec->buffer_dma = buffer_dma; - codec->desc_dma = desc_dma; - codec->desc = desc; - for (i = 0; i < count; i++) { - desc->desc.pbuf = buffer_dma + i * H2_BLOCK_SIZE; - desc->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE; - desc->desc.pnext = (i == count - 1) ? - desc_dma : desc_dma + (i + 1) * sizeof(struct hal2_desc); - desc++; - } - dma_cache_sync(NULL, codec->desc, count * sizeof(struct hal2_desc), - DMA_TO_DEVICE); - codec->desc_count = count; - return 0; -} - -static void hal2_free_dmabuf(struct hal2_codec *codec) -{ - dma_free_noncoherent(NULL, codec->desc_count * sizeof(struct hal2_desc), - codec->desc, codec->desc_dma); - dma_free_noncoherent(NULL, H2_BUF_SIZE, codec->buffer, - codec->buffer_dma); -} - -static struct snd_pcm_hardware hal2_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER), - .formats = SNDRV_PCM_FMTBIT_S16_BE, - .rates = SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 65536, - .period_bytes_min = 1024, - .period_bytes_max = 65536, - .periods_min = 2, - .periods_max = 1024, -}; - -static int hal2_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - int err; - - err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); - if (err < 0) - return err; - - return 0; -} - -static int hal2_pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int hal2_playback_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - int err; - - runtime->hw = hal2_pcm_hw; - - err = hal2_alloc_dmabuf(&hal2->dac); - if (err) - return err; - return 0; -} - -static int hal2_playback_close(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - - hal2_free_dmabuf(&hal2->dac); - return 0; -} - -static int hal2_playback_prepare(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct hal2_codec *dac = &hal2->dac; - - dac->voices = runtime->channels; - dac->sample_rate = hal2_compute_rate(dac, runtime->rate); - memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect)); - dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; - dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); - dac->substream = substream; - hal2_setup_dac(hal2); - return 0; -} - -static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma; - hal2->dac.pcm_indirect.hw_data = 0; - substream->ops->ack(substream); - hal2_start_dac(hal2); - break; - case SNDRV_PCM_TRIGGER_STOP: - hal2_stop_dac(hal2); - break; - default: - return -EINVAL; - } - return 0; -} - -static snd_pcm_uframes_t -hal2_playback_pointer(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct hal2_codec *dac = &hal2->dac; - - return snd_pcm_indirect_playback_pointer(substream, &dac->pcm_indirect, - dac->pbus.pbus->pbdma_bptr); -} - -static void hal2_playback_transfer(struct snd_pcm_substream *substream, - struct snd_pcm_indirect *rec, size_t bytes) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - unsigned char *buf = hal2->dac.buffer + rec->hw_data; - - memcpy(buf, substream->runtime->dma_area + rec->sw_data, bytes); - dma_cache_sync(NULL, buf, bytes, DMA_TO_DEVICE); - -} - -static int hal2_playback_ack(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct hal2_codec *dac = &hal2->dac; - - dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; - snd_pcm_indirect_playback_transfer(substream, - &dac->pcm_indirect, - hal2_playback_transfer); - return 0; -} - -static int hal2_capture_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct hal2_codec *adc = &hal2->adc; - int err; - - runtime->hw = hal2_pcm_hw; - - err = hal2_alloc_dmabuf(adc); - if (err) - return err; - return 0; -} - -static int hal2_capture_close(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - - hal2_free_dmabuf(&hal2->adc); - return 0; -} - -static int hal2_capture_prepare(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct hal2_codec *adc = &hal2->adc; - - adc->voices = runtime->channels; - adc->sample_rate = hal2_compute_rate(adc, runtime->rate); - memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect)); - adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; - adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; - adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); - adc->substream = substream; - hal2_setup_adc(hal2); - return 0; -} - -static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma; - hal2->adc.pcm_indirect.hw_data = 0; - printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma); - hal2_start_adc(hal2); - break; - case SNDRV_PCM_TRIGGER_STOP: - hal2_stop_adc(hal2); - break; - default: - return -EINVAL; - } - return 0; -} - -static snd_pcm_uframes_t -hal2_capture_pointer(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct hal2_codec *adc = &hal2->adc; - - return snd_pcm_indirect_capture_pointer(substream, &adc->pcm_indirect, - adc->pbus.pbus->pbdma_bptr); -} - -static void hal2_capture_transfer(struct snd_pcm_substream *substream, - struct snd_pcm_indirect *rec, size_t bytes) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - unsigned char *buf = hal2->adc.buffer + rec->hw_data; - - dma_cache_sync(NULL, buf, bytes, DMA_FROM_DEVICE); - memcpy(substream->runtime->dma_area + rec->sw_data, buf, bytes); -} - -static int hal2_capture_ack(struct snd_pcm_substream *substream) -{ - struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct hal2_codec *adc = &hal2->adc; - - snd_pcm_indirect_capture_transfer(substream, - &adc->pcm_indirect, - hal2_capture_transfer); - return 0; -} - -static struct snd_pcm_ops hal2_playback_ops = { - .open = hal2_playback_open, - .close = hal2_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = hal2_pcm_hw_params, - .hw_free = hal2_pcm_hw_free, - .prepare = hal2_playback_prepare, - .trigger = hal2_playback_trigger, - .pointer = hal2_playback_pointer, - .ack = hal2_playback_ack, -}; - -static struct snd_pcm_ops hal2_capture_ops = { - .open = hal2_capture_open, - .close = hal2_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = hal2_pcm_hw_params, - .hw_free = hal2_pcm_hw_free, - .prepare = hal2_capture_prepare, - .trigger = hal2_capture_trigger, - .pointer = hal2_capture_pointer, - .ack = hal2_capture_ack, -}; - -static int __devinit hal2_pcm_create(struct snd_hal2 *hal2) -{ - struct snd_pcm *pcm; - int err; - - /* create first pcm device with one outputs and one input */ - err = snd_pcm_new(hal2->card, "SGI HAL2 Audio", 0, 1, 1, &pcm); - if (err < 0) - return err; - - pcm->private_data = hal2; - strcpy(pcm->name, "SGI HAL2"); - - /* set operators */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &hal2_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &hal2_capture_ops); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 0, 1024 * 1024); - - return 0; -} - -static int hal2_dev_free(struct snd_device *device) -{ - struct snd_hal2 *hal2 = device->device_data; - - free_irq(SGI_HPCDMA_IRQ, hal2); - kfree(hal2); - return 0; -} - -static struct snd_device_ops hal2_ops = { - .dev_free = hal2_dev_free, -}; - -static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3, - int index) -{ - codec->pbus.pbusnr = index; - codec->pbus.pbus = &hpc3->pbdma[index]; -} - -static int hal2_detect(struct snd_hal2 *hal2) -{ - unsigned short board, major, minor; - unsigned short rev; - - /* reset HAL2 */ - hal2_write(0, &hal2->ctl_regs->isr); - - /* release reset */ - hal2_write(H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N, - &hal2->ctl_regs->isr); - - - hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE); - rev = hal2_read(&hal2->ctl_regs->rev); - if (rev & H2_REV_AUDIO_PRESENT) - return -ENODEV; - - board = (rev & H2_REV_BOARD_M) >> 12; - major = (rev & H2_REV_MAJOR_CHIP_M) >> 4; - minor = (rev & H2_REV_MINOR_CHIP_M); - - printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n", - board, major, minor); - - return 0; -} - -static int hal2_create(struct snd_card *card, struct snd_hal2 **rchip) -{ - struct snd_hal2 *hal2; - struct hpc3_regs *hpc3 = hpc3c0; - int err; - - hal2 = kzalloc(sizeof(struct snd_hal2), GFP_KERNEL); - if (!hal2) - return -ENOMEM; - - hal2->card = card; - - if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED, - "SGI HAL2", hal2)) { - printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ); - kfree(hal2); - return -EAGAIN; - } - - hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0]; - hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1]; - hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2]; - hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3]; - - if (hal2_detect(hal2) < 0) { - kfree(hal2); - return -ENODEV; - } - - hal2_init_codec(&hal2->dac, hpc3, 0); - hal2_init_codec(&hal2->adc, hpc3, 1); - - /* - * All DMA channel interfaces in HAL2 are designed to operate with - * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles - * in D5. HAL2 is a 16-bit device which can accept both big and little - * endian format. It assumes that even address bytes are on high - * portion of PBUS (15:8) and assumes that HPC3 is programmed to - * accept a live (unsynchronized) version of P_DREQ_N from HAL2. - */ -#define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \ - (2 << HPC3_DMACFG_D4R_SHIFT) | \ - (2 << HPC3_DMACFG_D5R_SHIFT) | \ - (0 << HPC3_DMACFG_D3W_SHIFT) | \ - (2 << HPC3_DMACFG_D4W_SHIFT) | \ - (2 << HPC3_DMACFG_D5W_SHIFT) | \ - HPC3_DMACFG_DS16 | \ - HPC3_DMACFG_EVENHI | \ - HPC3_DMACFG_RTIME | \ - (8 << HPC3_DMACFG_BURST_SHIFT) | \ - HPC3_DMACFG_DRQLIVE) - /* - * Ignore what's mentioned in the specification and write value which - * works in The Real World (TM) - */ - hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844; - hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844; - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, hal2, &hal2_ops); - if (err < 0) { - free_irq(SGI_HPCDMA_IRQ, hal2); - kfree(hal2); - return err; - } - *rchip = hal2; - return 0; -} - -static int __devinit hal2_probe(struct platform_device *pdev) -{ - struct snd_card *card; - struct snd_hal2 *chip; - int err; - - card = snd_card_new(index, id, THIS_MODULE, 0); - if (card == NULL) - return -ENOMEM; - - err = hal2_create(card, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } - snd_card_set_dev(card, &pdev->dev); - - err = hal2_pcm_create(chip); - if (err < 0) { - snd_card_free(card); - return err; - } - err = hal2_mixer_create(chip); - if (err < 0) { - snd_card_free(card); - return err; - } - - strcpy(card->driver, "SGI HAL2 Audio"); - strcpy(card->shortname, "SGI HAL2 Audio"); - sprintf(card->longname, "%s irq %i", - card->shortname, - SGI_HPCDMA_IRQ); - - err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } - platform_set_drvdata(pdev, card); - return 0; -} - -static int __exit hal2_remove(struct platform_device *pdev) -{ - struct snd_card *card = platform_get_drvdata(pdev); - - snd_card_free(card); - platform_set_drvdata(pdev, NULL); - return 0; -} - -static struct platform_driver hal2_driver = { - .probe = hal2_probe, - .remove = __devexit_p(hal2_remove), - .driver = { - .name = "sgihal2", - .owner = THIS_MODULE, - } -}; - -static int __init alsa_card_hal2_init(void) -{ - return platform_driver_register(&hal2_driver); -} - -static void __exit alsa_card_hal2_exit(void) -{ - platform_driver_unregister(&hal2_driver); -} - -module_init(alsa_card_hal2_init); -module_exit(alsa_card_hal2_exit); diff --git a/trunk/sound/mips/hal2.h b/trunk/sound/mips/hal2.h deleted file mode 100644 index f19828bc64e0..000000000000 --- a/trunk/sound/mips/hal2.h +++ /dev/null @@ -1,245 +0,0 @@ -#ifndef __HAL2_H -#define __HAL2_H - -/* - * Driver for HAL2 sound processors - * Copyright (c) 1999 Ulf Carlsson - * Copyright (c) 2001, 2002, 2003 Ladislav Michl - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include - -/* Indirect status register */ - -#define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */ -#define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */ -#define H2_ISR_QUAD_MODE 0x04 /* codec mode 0=indigo 1=quad */ -#define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */ -#define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */ - -/* Revision register */ - -#define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */ -#define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */ -#define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */ -#define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */ - -/* Indirect address register */ - -/* - * Address of indirect internal register to be accessed. A write to this - * register initiates read or write access to the indirect registers in the - * HAL2. Note that there af four indirect data registers for write access to - * registers larger than 16 byte. - */ - -#define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */ - /* block the register resides in */ - /* 1=DMA Port */ - /* 9=Global DMA Control */ - /* 2=Bresenham */ - /* 3=Unix Timer */ -#define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */ - /* blockin which the indirect */ - /* register resides */ - /* If IAR_TYPE_M=DMA Port: */ - /* 1=Synth In */ - /* 2=AES In */ - /* 3=AES Out */ - /* 4=DAC Out */ - /* 5=ADC Out */ - /* 6=Synth Control */ - /* If IAR_TYPE_M=Global DMA Control: */ - /* 1=Control */ - /* If IAR_TYPE_M=Bresenham: */ - /* 1=Bresenham Clock Gen 1 */ - /* 2=Bresenham Clock Gen 2 */ - /* 3=Bresenham Clock Gen 3 */ - /* If IAR_TYPE_M=Unix Timer: */ - /* 1=Unix Timer */ -#define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */ -#define H2_IAR_PARAM 0x000C /* Parameter Select */ -#define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */ - /* 00:word0 */ - /* 01:word1 */ - /* 10:word2 */ - /* 11:word3 */ -/* - * HAL2 internal addressing - * - * The HAL2 has "indirect registers" (idr) which are accessed by writing to the - * Indirect Data registers. Write the address to the Indirect Address register - * to transfer the data. - * - * We define the H2IR_* to the read address and H2IW_* to the write address and - * H2I_* to be fields in whatever register is referred to. - * - * When we write to indirect registers which are larger than one word (16 bit) - * we have to fill more than one indirect register before writing. When we read - * back however we have to read several times, each time with different Read - * Back Indexes (there are defs for doing this easily). - */ - -/* - * Relay Control - */ -#define H2I_RELAY_C 0x9100 -#define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */ - -/* DMA port enable */ - -#define H2I_DMA_PORT_EN 0x9104 -#define H2I_DMA_PORT_EN_SY_IN 0x01 /* Synth_in DMA port */ -#define H2I_DMA_PORT_EN_AESRX 0x02 /* AES receiver DMA port */ -#define H2I_DMA_PORT_EN_AESTX 0x04 /* AES transmitter DMA port */ -#define H2I_DMA_PORT_EN_CODECTX 0x08 /* CODEC transmit DMA port */ -#define H2I_DMA_PORT_EN_CODECR 0x10 /* CODEC receive DMA port */ - -#define H2I_DMA_END 0x9108 /* global dma endian select */ -#define H2I_DMA_END_SY_IN 0x01 /* Synth_in DMA port */ -#define H2I_DMA_END_AESRX 0x02 /* AES receiver DMA port */ -#define H2I_DMA_END_AESTX 0x04 /* AES transmitter DMA port */ -#define H2I_DMA_END_CODECTX 0x08 /* CODEC transmit DMA port */ -#define H2I_DMA_END_CODECR 0x10 /* CODEC receive DMA port */ - /* 0=b_end 1=l_end */ - -#define H2I_DMA_DRV 0x910C /* global PBUS DMA enable */ - -#define H2I_SYNTH_C 0x1104 /* Synth DMA control */ - -#define H2I_AESRX_C 0x1204 /* AES RX dma control */ - -#define H2I_C_TS_EN 0x20 /* Timestamp enable */ -#define H2I_C_TS_FRMT 0x40 /* Timestamp format */ -#define H2I_C_NAUDIO 0x80 /* Sign extend */ - -/* AESRX CTL, 16 bit */ - -#define H2I_AESTX_C 0x1304 /* AES TX DMA control */ -#define H2I_AESTX_C_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ -#define H2I_AESTX_C_CLKID_M 0x18 -#define H2I_AESTX_C_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ -#define H2I_AESTX_C_DATAT_M 0x300 - -/* CODEC registers */ - -#define H2I_DAC_C1 0x1404 /* DAC DMA control, 16 bit */ -#define H2I_DAC_C2 0x1408 /* DAC DMA control, 32 bit */ -#define H2I_ADC_C1 0x1504 /* ADC DMA control, 16 bit */ -#define H2I_ADC_C2 0x1508 /* ADC DMA control, 32 bit */ - -/* Bits in CTL1 register */ - -#define H2I_C1_DMA_SHIFT 0 /* DMA channel */ -#define H2I_C1_DMA_M 0x7 -#define H2I_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ -#define H2I_C1_CLKID_M 0x18 -#define H2I_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ -#define H2I_C1_DATAT_M 0x300 - -/* Bits in CTL2 register */ - -#define H2I_C2_R_GAIN_SHIFT 0 /* right a/d input gain */ -#define H2I_C2_R_GAIN_M 0xf -#define H2I_C2_L_GAIN_SHIFT 4 /* left a/d input gain */ -#define H2I_C2_L_GAIN_M 0xf0 -#define H2I_C2_R_SEL 0x100 /* right input select */ -#define H2I_C2_L_SEL 0x200 /* left input select */ -#define H2I_C2_MUTE 0x400 /* mute */ -#define H2I_C2_DO1 0x00010000 /* digital output port bit 0 */ -#define H2I_C2_DO2 0x00020000 /* digital output port bit 1 */ -#define H2I_C2_R_ATT_SHIFT 18 /* right d/a output - */ -#define H2I_C2_R_ATT_M 0x007c0000 /* attenuation */ -#define H2I_C2_L_ATT_SHIFT 23 /* left d/a output - */ -#define H2I_C2_L_ATT_M 0x0f800000 /* attenuation */ - -#define H2I_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl */ - -/* Clock generator CTL 1, 16 bit */ - -#define H2I_BRES1_C1 0x2104 -#define H2I_BRES2_C1 0x2204 -#define H2I_BRES3_C1 0x2304 - -#define H2I_BRES_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */ -#define H2I_BRES_C1_M 0x03 - -/* Clock generator CTL 2, 32 bit */ - -#define H2I_BRES1_C2 0x2108 -#define H2I_BRES2_C2 0x2208 -#define H2I_BRES3_C2 0x2308 - -#define H2I_BRES_C2_INC_SHIFT 0 /* increment value */ -#define H2I_BRES_C2_INC_M 0xffff -#define H2I_BRES_C2_MOD_SHIFT 16 /* modcontrol value */ -#define H2I_BRES_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */ - -/* Unix timer, 64 bit */ - -#define H2I_UTIME 0x3104 -#define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */ -#define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */ -#define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */ -#define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */ -#define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */ - -struct hal2_ctl_regs { - u32 _unused0[4]; - u32 isr; /* 0x10 Status Register */ - u32 _unused1[3]; - u32 rev; /* 0x20 Revision Register */ - u32 _unused2[3]; - u32 iar; /* 0x30 Indirect Address Register */ - u32 _unused3[3]; - u32 idr0; /* 0x40 Indirect Data Register 0 */ - u32 _unused4[3]; - u32 idr1; /* 0x50 Indirect Data Register 1 */ - u32 _unused5[3]; - u32 idr2; /* 0x60 Indirect Data Register 2 */ - u32 _unused6[3]; - u32 idr3; /* 0x70 Indirect Data Register 3 */ -}; - -struct hal2_aes_regs { - u32 rx_stat[2]; /* Status registers */ - u32 rx_cr[2]; /* Control registers */ - u32 rx_ud[4]; /* User data window */ - u32 rx_st[24]; /* Channel status data */ - - u32 tx_stat[1]; /* Status register */ - u32 tx_cr[3]; /* Control registers */ - u32 tx_ud[4]; /* User data window */ - u32 tx_st[24]; /* Channel status data */ -}; - -struct hal2_vol_regs { - u32 right; /* Right volume */ - u32 left; /* Left volume */ -}; - -struct hal2_syn_regs { - u32 _unused0[2]; - u32 page; /* DOC Page register */ - u32 regsel; /* DOC Register selection */ - u32 dlow; /* DOC Data low */ - u32 dhigh; /* DOC Data high */ - u32 irq; /* IRQ Status */ - u32 dram; /* DRAM Access */ -}; - -#endif /* __HAL2_H */ diff --git a/trunk/sound/mips/sgio2audio.c b/trunk/sound/mips/sgio2audio.c deleted file mode 100644 index 4c63504348dc..000000000000 --- a/trunk/sound/mips/sgio2audio.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * Sound driver for Silicon Graphics O2 Workstations A/V board audio. - * - * Copyright 2003 Vivien Chappelier - * Copyright 2008 Thomas Bogendoerfer - * Mxier part taken from mace_audio.c: - * Copyright 2007 Thorben Jändling - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#define SNDRV_GET_ID -#include -#include - - -MODULE_AUTHOR("Vivien Chappelier "); -MODULE_DESCRIPTION("SGI O2 Audio"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Silicon Graphics, O2 Audio}}"); - -static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ -static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ - -module_param(index, int, 0444); -MODULE_PARM_DESC(index, "Index value for SGI O2 soundcard."); -module_param(id, charp, 0444); -MODULE_PARM_DESC(id, "ID string for SGI O2 soundcard."); - - -#define AUDIO_CONTROL_RESET BIT(0) /* 1: reset audio interface */ -#define AUDIO_CONTROL_CODEC_PRESENT BIT(1) /* 1: codec detected */ - -#define CODEC_CONTROL_WORD_SHIFT 0 -#define CODEC_CONTROL_READ BIT(16) -#define CODEC_CONTROL_ADDRESS_SHIFT 17 - -#define CHANNEL_CONTROL_RESET BIT(10) /* 1: reset channel */ -#define CHANNEL_DMA_ENABLE BIT(9) /* 1: enable DMA transfer */ -#define CHANNEL_INT_THRESHOLD_DISABLED (0 << 5) /* interrupt disabled */ -#define CHANNEL_INT_THRESHOLD_25 (1 << 5) /* int on buffer >25% full */ -#define CHANNEL_INT_THRESHOLD_50 (2 << 5) /* int on buffer >50% full */ -#define CHANNEL_INT_THRESHOLD_75 (3 << 5) /* int on buffer >75% full */ -#define CHANNEL_INT_THRESHOLD_EMPTY (4 << 5) /* int on buffer empty */ -#define CHANNEL_INT_THRESHOLD_NOT_EMPTY (5 << 5) /* int on buffer !empty */ -#define CHANNEL_INT_THRESHOLD_FULL (6 << 5) /* int on buffer empty */ -#define CHANNEL_INT_THRESHOLD_NOT_FULL (7 << 5) /* int on buffer !empty */ - -#define CHANNEL_RING_SHIFT 12 -#define CHANNEL_RING_SIZE (1 << CHANNEL_RING_SHIFT) -#define CHANNEL_RING_MASK (CHANNEL_RING_SIZE - 1) - -#define CHANNEL_LEFT_SHIFT 40 -#define CHANNEL_RIGHT_SHIFT 8 - -struct snd_sgio2audio_chan { - int idx; - struct snd_pcm_substream *substream; - int pos; - snd_pcm_uframes_t size; - spinlock_t lock; -}; - -/* definition of the chip-specific record */ -struct snd_sgio2audio { - struct snd_card *card; - - /* codec */ - struct snd_ad1843 ad1843; - spinlock_t ad1843_lock; - - /* channels */ - struct snd_sgio2audio_chan channel[3]; - - /* resources */ - void *ring_base; - dma_addr_t ring_base_dma; -}; - -/* AD1843 access */ - -/* - * read_ad1843_reg returns the current contents of a 16 bit AD1843 register. - * - * Returns unsigned register value on success, -errno on failure. - */ -static int read_ad1843_reg(void *priv, int reg) -{ - struct snd_sgio2audio *chip = priv; - int val; - unsigned long flags; - - spin_lock_irqsave(&chip->ad1843_lock, flags); - - writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | - CODEC_CONTROL_READ, &mace->perif.audio.codec_control); - wmb(); - val = readq(&mace->perif.audio.codec_control); /* flush bus */ - udelay(200); - - val = readq(&mace->perif.audio.codec_read); - - spin_unlock_irqrestore(&chip->ad1843_lock, flags); - return val; -} - -/* - * write_ad1843_reg writes the specified value to a 16 bit AD1843 register. - */ -static int write_ad1843_reg(void *priv, int reg, int word) -{ - struct snd_sgio2audio *chip = priv; - int val; - unsigned long flags; - - spin_lock_irqsave(&chip->ad1843_lock, flags); - - writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | - (word << CODEC_CONTROL_WORD_SHIFT), - &mace->perif.audio.codec_control); - wmb(); - val = readq(&mace->perif.audio.codec_control); /* flush bus */ - udelay(200); - - spin_unlock_irqrestore(&chip->ad1843_lock, flags); - return 0; -} - -static int sgio2audio_gain_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = ad1843_get_gain_max(&chip->ad1843, - (int)kcontrol->private_value); - return 0; -} - -static int sgio2audio_gain_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); - int vol; - - vol = ad1843_get_gain(&chip->ad1843, (int)kcontrol->private_value); - - ucontrol->value.integer.value[0] = (vol >> 8) & 0xFF; - ucontrol->value.integer.value[1] = vol & 0xFF; - - return 0; -} - -static int sgio2audio_gain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); - int newvol, oldvol; - - oldvol = ad1843_get_gain(&chip->ad1843, kcontrol->private_value); - newvol = (ucontrol->value.integer.value[0] << 8) | - ucontrol->value.integer.value[1]; - - newvol = ad1843_set_gain(&chip->ad1843, kcontrol->private_value, - newvol); - - return newvol != oldvol; -} - -static int sgio2audio_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char *texts[3] = { - "Cam Mic", "Mic", "Line" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int sgio2audio_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); - - ucontrol->value.enumerated.item[0] = ad1843_get_recsrc(&chip->ad1843); - return 0; -} - -static int sgio2audio_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); - int newsrc, oldsrc; - - oldsrc = ad1843_get_recsrc(&chip->ad1843); - newsrc = ad1843_set_recsrc(&chip->ad1843, - ucontrol->value.enumerated.item[0]); - - return newsrc != oldsrc; -} - -/* dac1/pcm0 mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = AD1843_GAIN_PCM_0, - .info = sgio2audio_gain_info, - .get = sgio2audio_gain_get, - .put = sgio2audio_gain_put, -}; - -/* dac2/pcm1 mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .index = 1, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = AD1843_GAIN_PCM_1, - .info = sgio2audio_gain_info, - .get = sgio2audio_gain_get, - .put = sgio2audio_gain_put, -}; - -/* record level mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_reclevel __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = AD1843_GAIN_RECLEV, - .info = sgio2audio_gain_info, - .get = sgio2audio_gain_get, - .put = sgio2audio_gain_put, -}; - -/* record level source control */ -static struct snd_kcontrol_new sgio2audio_ctrl_recsource __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = sgio2audio_source_info, - .get = sgio2audio_source_get, - .put = sgio2audio_source_put, -}; - -/* line mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_line __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line Playback Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = AD1843_GAIN_LINE, - .info = sgio2audio_gain_info, - .get = sgio2audio_gain_get, - .put = sgio2audio_gain_put, -}; - -/* cd mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_cd __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line Playback Volume", - .index = 1, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = AD1843_GAIN_LINE_2, - .info = sgio2audio_gain_info, - .get = sgio2audio_gain_get, - .put = sgio2audio_gain_put, -}; - -/* mic mixer control */ -static struct snd_kcontrol_new sgio2audio_ctrl_mic __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = AD1843_GAIN_MIC, - .info = sgio2audio_gain_info, - .get = sgio2audio_gain_get, - .put = sgio2audio_gain_put, -}; - - -static int __devinit snd_sgio2audio_new_mixer(struct snd_sgio2audio *chip) -{ - int err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&sgio2audio_ctrl_pcm0, chip)); - if (err < 0) - return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&sgio2audio_ctrl_pcm1, chip)); - if (err < 0) - return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&sgio2audio_ctrl_reclevel, chip)); - if (err < 0) - return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&sgio2audio_ctrl_recsource, chip)); - if (err < 0) - return err; - err = snd_ctl_add(chip->card, - snd_ctl_new1(&sgio2audio_ctrl_line, chip)); - if (err < 0) - return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&sgio2audio_ctrl_cd, chip)); - if (err < 0) - return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&sgio2audio_ctrl_mic, chip)); - if (err < 0) - return err; - - return 0; -} - -/* low-level audio interface DMA */ - -/* get data out of bounce buffer, count must be a multiple of 32 */ -/* returns 1 if a period has elapsed */ -static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip, - unsigned int ch, unsigned int count) -{ - int ret; - unsigned long src_base, src_pos, dst_mask; - unsigned char *dst_base; - int dst_pos; - u64 *src; - s16 *dst; - u64 x; - unsigned long flags; - struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; - - spin_lock_irqsave(&chip->channel[ch].lock, flags); - - src_base = (unsigned long) chip->ring_base | (ch << CHANNEL_RING_SHIFT); - src_pos = readq(&mace->perif.audio.chan[ch].read_ptr); - dst_base = runtime->dma_area; - dst_pos = chip->channel[ch].pos; - dst_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1; - - /* check if a period has elapsed */ - chip->channel[ch].size += (count >> 3); /* in frames */ - ret = chip->channel[ch].size >= runtime->period_size; - chip->channel[ch].size %= runtime->period_size; - - while (count) { - src = (u64 *)(src_base + src_pos); - dst = (s16 *)(dst_base + dst_pos); - - x = *src; - dst[0] = (x >> CHANNEL_LEFT_SHIFT) & 0xffff; - dst[1] = (x >> CHANNEL_RIGHT_SHIFT) & 0xffff; - - src_pos = (src_pos + sizeof(u64)) & CHANNEL_RING_MASK; - dst_pos = (dst_pos + 2 * sizeof(s16)) & dst_mask; - count -= sizeof(u64); - } - - writeq(src_pos, &mace->perif.audio.chan[ch].read_ptr); /* in bytes */ - chip->channel[ch].pos = dst_pos; - - spin_unlock_irqrestore(&chip->channel[ch].lock, flags); - return ret; -} - -/* put some DMA data in bounce buffer, count must be a multiple of 32 */ -/* returns 1 if a period has elapsed */ -static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip, - unsigned int ch, unsigned int count) -{ - int ret; - s64 l, r; - unsigned long dst_base, dst_pos, src_mask; - unsigned char *src_base; - int src_pos; - u64 *dst; - s16 *src; - unsigned long flags; - struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; - - spin_lock_irqsave(&chip->channel[ch].lock, flags); - - dst_base = (unsigned long)chip->ring_base | (ch << CHANNEL_RING_SHIFT); - dst_pos = readq(&mace->perif.audio.chan[ch].write_ptr); - src_base = runtime->dma_area; - src_pos = chip->channel[ch].pos; - src_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1; - - /* check if a period has elapsed */ - chip->channel[ch].size += (count >> 3); /* in frames */ - ret = chip->channel[ch].size >= runtime->period_size; - chip->channel[ch].size %= runtime->period_size; - - while (count) { - src = (s16 *)(src_base + src_pos); - dst = (u64 *)(dst_base + dst_pos); - - l = src[0]; /* sign extend */ - r = src[1]; /* sign extend */ - - *dst = ((l & 0x00ffffff) << CHANNEL_LEFT_SHIFT) | - ((r & 0x00ffffff) << CHANNEL_RIGHT_SHIFT); - - dst_pos = (dst_pos + sizeof(u64)) & CHANNEL_RING_MASK; - src_pos = (src_pos + 2 * sizeof(s16)) & src_mask; - count -= sizeof(u64); - } - - writeq(dst_pos, &mace->perif.audio.chan[ch].write_ptr); /* in bytes */ - chip->channel[ch].pos = src_pos; - - spin_unlock_irqrestore(&chip->channel[ch].lock, flags); - return ret; -} - -static int snd_sgio2audio_dma_start(struct snd_pcm_substream *substream) -{ - struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); - struct snd_sgio2audio_chan *chan = substream->runtime->private_data; - int ch = chan->idx; - - /* reset DMA channel */ - writeq(CHANNEL_CONTROL_RESET, &mace->perif.audio.chan[ch].control); - udelay(10); - writeq(0, &mace->perif.audio.chan[ch].control); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* push a full buffer */ - snd_sgio2audio_dma_push_frag(chip, ch, CHANNEL_RING_SIZE - 32); - } - /* set DMA to wake on 50% empty and enable interrupt */ - writeq(CHANNEL_DMA_ENABLE | CHANNEL_INT_THRESHOLD_50, - &mace->perif.audio.chan[ch].control); - return 0; -} - -static int snd_sgio2audio_dma_stop(struct snd_pcm_substream *substream) -{ - struct snd_sgio2audio_chan *chan = substream->runtime->private_data; - - writeq(0, &mace->perif.audio.chan[chan->idx].control); - return 0; -} - -static irqreturn_t snd_sgio2audio_dma_in_isr(int irq, void *dev_id) -{ - struct snd_sgio2audio_chan *chan = dev_id; - struct snd_pcm_substream *substream; - struct snd_sgio2audio *chip; - int count, ch; - - substream = chan->substream; - chip = snd_pcm_substream_chip(substream); - ch = chan->idx; - - /* empty the ring */ - count = CHANNEL_RING_SIZE - - readq(&mace->perif.audio.chan[ch].depth) - 32; - if (snd_sgio2audio_dma_pull_frag(chip, ch, count)) - snd_pcm_period_elapsed(substream); - - return IRQ_HANDLED; -} - -static irqreturn_t snd_sgio2audio_dma_out_isr(int irq, void *dev_id) -{ - struct snd_sgio2audio_chan *chan = dev_id; - struct snd_pcm_substream *substream; - struct snd_sgio2audio *chip; - int count, ch; - - substream = chan->substream; - chip = snd_pcm_substream_chip(substream); - ch = chan->idx; - /* fill the ring */ - count = CHANNEL_RING_SIZE - - readq(&mace->perif.audio.chan[ch].depth) - 32; - if (snd_sgio2audio_dma_push_frag(chip, ch, count)) - snd_pcm_period_elapsed(substream); - - return IRQ_HANDLED; -} - -static irqreturn_t snd_sgio2audio_error_isr(int irq, void *dev_id) -{ - struct snd_sgio2audio_chan *chan = dev_id; - struct snd_pcm_substream *substream; - - substream = chan->substream; - snd_sgio2audio_dma_stop(substream); - snd_sgio2audio_dma_start(substream); - return IRQ_HANDLED; -} - -/* PCM part */ -/* PCM hardware definition */ -static struct snd_pcm_hardware snd_sgio2audio_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER), - .formats = SNDRV_PCM_FMTBIT_S16_BE, - .rates = SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 65536, - .period_bytes_min = 32768, - .period_bytes_max = 65536, - .periods_min = 1, - .periods_max = 1024, -}; - -/* PCM playback open callback */ -static int snd_sgio2audio_playback1_open(struct snd_pcm_substream *substream) -{ - struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw = snd_sgio2audio_pcm_hw; - runtime->private_data = &chip->channel[1]; - return 0; -} - -static int snd_sgio2audio_playback2_open(struct snd_pcm_substream *substream) -{ - struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw = snd_sgio2audio_pcm_hw; - runtime->private_data = &chip->channel[2]; - return 0; -} - -/* PCM capture open callback */ -static int snd_sgio2audio_capture_open(struct snd_pcm_substream *substream) -{ - struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw = snd_sgio2audio_pcm_hw; - runtime->private_data = &chip->channel[0]; - return 0; -} - -/* PCM close callback */ -static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->private_data = NULL; - return 0; -} - - -/* hw_params callback */ -static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int size = params_buffer_bytes(hw_params); - - /* alloc virtual 'dma' area */ - if (runtime->dma_area) - vfree(runtime->dma_area); - runtime->dma_area = vmalloc(size); - if (runtime->dma_area == NULL) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} - -/* hw_free callback */ -static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) -{ - if (substream->runtime->dma_area) - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - return 0; -} - -/* prepare callback */ -static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_sgio2audio_chan *chan = substream->runtime->private_data; - int ch = chan->idx; - unsigned long flags; - - spin_lock_irqsave(&chip->channel[ch].lock, flags); - - /* Setup the pseudo-dma transfer pointers. */ - chip->channel[ch].pos = 0; - chip->channel[ch].size = 0; - chip->channel[ch].substream = substream; - - /* set AD1843 format */ - /* hardware format is always S16_LE */ - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - ad1843_setup_dac(&chip->ad1843, - ch - 1, - runtime->rate, - SNDRV_PCM_FORMAT_S16_LE, - runtime->channels); - break; - case SNDRV_PCM_STREAM_CAPTURE: - ad1843_setup_adc(&chip->ad1843, - runtime->rate, - SNDRV_PCM_FORMAT_S16_LE, - runtime->channels); - break; - } - spin_unlock_irqrestore(&chip->channel[ch].lock, flags); - return 0; -} - -/* trigger callback */ -static int snd_sgio2audio_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - /* start the PCM engine */ - snd_sgio2audio_dma_start(substream); - break; - case SNDRV_PCM_TRIGGER_STOP: - /* stop the PCM engine */ - snd_sgio2audio_dma_stop(substream); - break; - default: - return -EINVAL; - } - return 0; -} - -/* pointer callback */ -static snd_pcm_uframes_t -snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); - struct snd_sgio2audio_chan *chan = substream->runtime->private_data; - - /* get the current hardware pointer */ - return bytes_to_frames(substream->runtime, - chip->channel[chan->idx].pos); -} - -/* get the physical page pointer on the given offset */ -static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - return vmalloc_to_page(substream->runtime->dma_area + offset); -} - -/* operators */ -static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { - .open = snd_sgio2audio_playback1_open, - .close = snd_sgio2audio_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_sgio2audio_pcm_hw_params, - .hw_free = snd_sgio2audio_pcm_hw_free, - .prepare = snd_sgio2audio_pcm_prepare, - .trigger = snd_sgio2audio_pcm_trigger, - .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, -}; - -static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { - .open = snd_sgio2audio_playback2_open, - .close = snd_sgio2audio_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_sgio2audio_pcm_hw_params, - .hw_free = snd_sgio2audio_pcm_hw_free, - .prepare = snd_sgio2audio_pcm_prepare, - .trigger = snd_sgio2audio_pcm_trigger, - .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, -}; - -static struct snd_pcm_ops snd_sgio2audio_capture_ops = { - .open = snd_sgio2audio_capture_open, - .close = snd_sgio2audio_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_sgio2audio_pcm_hw_params, - .hw_free = snd_sgio2audio_pcm_hw_free, - .prepare = snd_sgio2audio_pcm_prepare, - .trigger = snd_sgio2audio_pcm_trigger, - .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, -}; - -/* - * definitions of capture are omitted here... - */ - -/* create a pcm device */ -static int __devinit snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) -{ - struct snd_pcm *pcm; - int err; - - /* create first pcm device with one outputs and one input */ - err = snd_pcm_new(chip->card, "SGI O2 Audio", 0, 1, 1, &pcm); - if (err < 0) - return err; - - pcm->private_data = chip; - strcpy(pcm->name, "SGI O2 DAC1"); - - /* set operators */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_sgio2audio_playback1_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_sgio2audio_capture_ops); - - /* create second pcm device with one outputs and no input */ - err = snd_pcm_new(chip->card, "SGI O2 Audio", 1, 1, 0, &pcm); - if (err < 0) - return err; - - pcm->private_data = chip; - strcpy(pcm->name, "SGI O2 DAC2"); - - /* set operators */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_sgio2audio_playback2_ops); - - return 0; -} - -static struct { - int idx; - int irq; - irqreturn_t (*isr)(int, void *); - const char *desc; -} snd_sgio2_isr_table[] = { - { - .idx = 0, - .irq = MACEISA_AUDIO1_DMAT_IRQ, - .isr = snd_sgio2audio_dma_in_isr, - .desc = "Capture DMA Channel 0" - }, { - .idx = 0, - .irq = MACEISA_AUDIO1_OF_IRQ, - .isr = snd_sgio2audio_error_isr, - .desc = "Capture Overflow" - }, { - .idx = 1, - .irq = MACEISA_AUDIO2_DMAT_IRQ, - .isr = snd_sgio2audio_dma_out_isr, - .desc = "Playback DMA Channel 1" - }, { - .idx = 1, - .irq = MACEISA_AUDIO2_MERR_IRQ, - .isr = snd_sgio2audio_error_isr, - .desc = "Memory Error Channel 1" - }, { - .idx = 2, - .irq = MACEISA_AUDIO3_DMAT_IRQ, - .isr = snd_sgio2audio_dma_out_isr, - .desc = "Playback DMA Channel 2" - }, { - .idx = 2, - .irq = MACEISA_AUDIO3_MERR_IRQ, - .isr = snd_sgio2audio_error_isr, - .desc = "Memory Error Channel 2" - } -}; - -/* ALSA driver */ - -static int snd_sgio2audio_free(struct snd_sgio2audio *chip) -{ - int i; - - /* reset interface */ - writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control); - udelay(1); - writeq(0, &mace->perif.audio.control); - - /* release IRQ's */ - for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) - free_irq(snd_sgio2_isr_table[i].irq, - &chip->channel[snd_sgio2_isr_table[i].idx]); - - dma_free_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, - chip->ring_base, chip->ring_base_dma); - - /* release card data */ - kfree(chip); - return 0; -} - -static int snd_sgio2audio_dev_free(struct snd_device *device) -{ - struct snd_sgio2audio *chip = device->device_data; - - return snd_sgio2audio_free(chip); -} - -static struct snd_device_ops ops = { - .dev_free = snd_sgio2audio_dev_free, -}; - -static int __devinit snd_sgio2audio_create(struct snd_card *card, - struct snd_sgio2audio **rchip) -{ - struct snd_sgio2audio *chip; - int i, err; - - *rchip = NULL; - - /* check if a codec is attached to the interface */ - /* (Audio or Audio/Video board present) */ - if (!(readq(&mace->perif.audio.control) & AUDIO_CONTROL_CODEC_PRESENT)) - return -ENOENT; - - chip = kzalloc(sizeof(struct snd_sgio2audio), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->card = card; - - chip->ring_base = dma_alloc_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, - &chip->ring_base_dma, GFP_USER); - if (chip->ring_base == NULL) { - printk(KERN_ERR - "sgio2audio: could not allocate ring buffers\n"); - kfree(chip); - return -ENOMEM; - } - - spin_lock_init(&chip->ad1843_lock); - - /* initialize channels */ - for (i = 0; i < 3; i++) { - spin_lock_init(&chip->channel[i].lock); - chip->channel[i].idx = i; - } - - /* allocate IRQs */ - for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) { - if (request_irq(snd_sgio2_isr_table[i].irq, - snd_sgio2_isr_table[i].isr, - 0, - snd_sgio2_isr_table[i].desc, - &chip->channel[snd_sgio2_isr_table[i].idx])) { - snd_sgio2audio_free(chip); - printk(KERN_ERR "sgio2audio: cannot allocate irq %d\n", - snd_sgio2_isr_table[i].irq); - return -EBUSY; - } - } - - /* reset the interface */ - writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control); - udelay(1); - writeq(0, &mace->perif.audio.control); - msleep_interruptible(1); /* give time to recover */ - - /* set ring base */ - writeq(chip->ring_base_dma, &mace->perif.ctrl.ringbase); - - /* attach the AD1843 codec */ - chip->ad1843.read = read_ad1843_reg; - chip->ad1843.write = write_ad1843_reg; - chip->ad1843.chip = chip; - - /* initialize the AD1843 codec */ - err = ad1843_init(&chip->ad1843); - if (err < 0) { - snd_sgio2audio_free(chip); - return err; - } - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) { - snd_sgio2audio_free(chip); - return err; - } - *rchip = chip; - return 0; -} - -static int __devinit snd_sgio2audio_probe(struct platform_device *pdev) -{ - struct snd_card *card; - struct snd_sgio2audio *chip; - int err; - - card = snd_card_new(index, id, THIS_MODULE, 0); - if (card == NULL) - return -ENOMEM; - - err = snd_sgio2audio_create(card, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } - snd_card_set_dev(card, &pdev->dev); - - err = snd_sgio2audio_new_pcm(chip); - if (err < 0) { - snd_card_free(card); - return err; - } - err = snd_sgio2audio_new_mixer(chip); - if (err < 0) { - snd_card_free(card); - return err; - } - - strcpy(card->driver, "SGI O2 Audio"); - strcpy(card->shortname, "SGI O2 Audio"); - sprintf(card->longname, "%s irq %i-%i", - card->shortname, - MACEISA_AUDIO1_DMAT_IRQ, - MACEISA_AUDIO3_MERR_IRQ); - - err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } - platform_set_drvdata(pdev, card); - return 0; -} - -static int __exit snd_sgio2audio_remove(struct platform_device *pdev) -{ - struct snd_card *card = platform_get_drvdata(pdev); - - snd_card_free(card); - platform_set_drvdata(pdev, NULL); - return 0; -} - -static struct platform_driver sgio2audio_driver = { - .probe = snd_sgio2audio_probe, - .remove = __devexit_p(snd_sgio2audio_remove), - .driver = { - .name = "sgio2audio", - .owner = THIS_MODULE, - } -}; - -static int __init alsa_card_sgio2audio_init(void) -{ - return platform_driver_register(&sgio2audio_driver); -} - -static void __exit alsa_card_sgio2audio_exit(void) -{ - platform_driver_unregister(&sgio2audio_driver); -} - -module_init(alsa_card_sgio2audio_init) -module_exit(alsa_card_sgio2audio_exit) diff --git a/trunk/sound/oss/Kconfig b/trunk/sound/oss/Kconfig index 33940139844b..3be2dc1025b5 100644 --- a/trunk/sound/oss/Kconfig +++ b/trunk/sound/oss/Kconfig @@ -7,7 +7,7 @@ config SOUND_BCM_CS4297A tristate "Crystal Sound CS4297a (for Swarm)" - depends on SIBYTE_SWARM + depends on SOUND_PRIME && SIBYTE_SWARM help The BCM91250A has a Crystal CS4297a on synchronous serial port B (in addition to the DB-9 serial port). Say Y or M @@ -17,7 +17,7 @@ config SOUND_BCM_CS4297A config SOUND_VWSND tristate "SGI Visual Workstation Sound" - depends on X86_VISWS + depends on SOUND_PRIME && X86_VISWS help Say Y or M if you have an SGI Visual Workstation and you want to be able to use its on-board audio. Read @@ -26,18 +26,19 @@ config SOUND_VWSND config SOUND_HAL2 tristate "SGI HAL2 sound (EXPERIMENTAL)" - depends on SGI_IP22 && EXPERIMENTAL + depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL help Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to use its on-board A2 audio system. config SOUND_AU1550_AC97 tristate "Au1550/Au1200 AC97 Sound" - depends on SOC_AU1550 || SOC_AU1200 + select SND_AC97_CODEC + depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200) config SOUND_TRIDENT tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" - depends on PCI + depends on SOUND_PRIME && PCI ---help--- Say Y or M if you have a PCI sound card utilizing the Trident 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 @@ -78,7 +79,7 @@ config SOUND_TRIDENT config SOUND_MSNDCLAS tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on (m || !STANDALONE) && ISA + depends on SOUND_PRIME && (m || !STANDALONE) && ISA help Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or Monterey (not for the Pinnacle or Fiji). @@ -142,7 +143,7 @@ config MSNDCLAS_IO config SOUND_MSNDPIN tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" - depends on (m || !STANDALONE) && ISA + depends on SOUND_PRIME && (m || !STANDALONE) && ISA help Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. See for important information @@ -228,7 +229,7 @@ config MSNDPIN_NONPNP configure the card's resources. comment "MSND Pinnacle DSP section will be configured to above parameters." - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP + depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP config MSNDPIN_CFG hex "MSND Pinnacle config port 250,260,270" @@ -241,7 +242,7 @@ config MSNDPIN_CFG Mode". comment "Pinnacle-specific Device Configuration (0 disables)" - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP + depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP config MSNDPIN_MPU_IO hex "MSND Pinnacle MPU I/O (e.g. 330)" @@ -293,7 +294,7 @@ config MSNDPIN_JOYSTICK_IO config MSND_FIFOSIZE int "MSND buffer size (kB)" - depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y + depends on SOUND_PRIME && (SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y) default "128" help Configures the size of each audio buffer, in kilobytes, for @@ -301,9 +302,9 @@ config MSND_FIFOSIZE and Pinnacle). Larger values reduce the chance of data overruns at the expense of overall latency. If unsure, use the default. -menuconfig SOUND_OSS +config SOUND_OSS tristate "OSS sound modules" - depends on ISA_DMA_API && VIRT_TO_BUS + depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS help OSS is the Open Sound System suite of sound card drivers. They make sound programming easier since they provide a common API. Say Y or @@ -311,16 +312,16 @@ menuconfig SOUND_OSS driver for your sound card above, then pick your driver from the list below. -if SOUND_OSS - config SOUND_TRACEINIT bool "Verbose initialisation" + depends on SOUND_OSS help Verbose soundcard initialization -- affects the format of autoprobe and initialization messages at boot time. config SOUND_DMAP bool "Persistent DMA buffers" + depends on SOUND_OSS ---help--- Linux can often have problems allocating DMA buffers for ISA sound cards on machines with more than 16MB of RAM. This is because ISA @@ -337,6 +338,8 @@ config SOUND_DMAP config SOUND_SSCAPE tristate "Ensoniq SoundScape support" + depends on SOUND_OSS + depends on VIRT_TO_BUS help Answer Y if you have a sound card based on the Ensoniq SoundScape chipset. Such cards are being manufactured at least by Ensoniq, Spea @@ -349,11 +352,13 @@ config SOUND_SSCAPE config SOUND_VMIDI tristate "Loopback MIDI device support" + depends on SOUND_OSS help Support for MIDI loopback on port 1 or 2. config SOUND_TRIX tristate "MediaTrix AudioTrix Pro support" + depends on SOUND_OSS help Answer Y if you have the AudioTriX Pro sound card manufactured by MediaTrix. @@ -377,6 +382,7 @@ config TRIX_BOOT_FILE config SOUND_MSS tristate "Microsoft Sound System support" + depends on SOUND_OSS ---help--- Again think carefully before answering Y to this question. It's safe to answer Y if you have the original Windows Sound System card @@ -408,6 +414,7 @@ config SOUND_MSS config SOUND_MPU401 tristate "MPU-401 support (NOT for SB16)" + depends on SOUND_OSS ---help--- Be careful with this question. The MPU401 interface is supported by all sound cards. However, some natively supported cards have their @@ -423,6 +430,7 @@ config SOUND_MPU401 config SOUND_PAS tristate "ProAudioSpectrum 16 support" + depends on SOUND_OSS ---help--- Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio 16 or Logitech SoundMan 16 sound card. Answer N if you have some @@ -444,6 +452,7 @@ config PAS_JOYSTICK config SOUND_PSS tristate "PSS (AD1848, ADSP-2115, ESC614) support" + depends on SOUND_OSS help Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven ADSP-16 or some other card based on the PSS chipset (AD1848 codec + @@ -486,6 +495,7 @@ config PSS_BOOT_FILE config SOUND_SB tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" + depends on SOUND_OSS ---help--- Answer Y if you have an original Sound Blaster card made by Creative Labs or a 100% hardware compatible clone (like the Thunderboard or @@ -512,6 +522,7 @@ config SOUND_SB config SOUND_YM3812 tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" + depends on SOUND_OSS ---help--- Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). Answering Y is usually a safe and recommended choice, however some @@ -527,6 +538,7 @@ config SOUND_YM3812 config SOUND_UART6850 tristate "6850 UART support" + depends on SOUND_OSS help This option enables support for MIDI interfaces based on the 6850 UART chip. This interface is rarely found on sound cards. It's safe @@ -537,6 +549,7 @@ config SOUND_UART6850 config SOUND_AEDSP16 tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" + depends on SOUND_OSS ---help--- Answer Y if you have a Gallant's Audio Excel DSP 16 card. This driver supports Audio Excel DSP 16 but not the III nor PnP versions @@ -617,14 +630,14 @@ endchoice config SOUND_VIDC tristate "VIDC 16-bit sound" - depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) + depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) && SOUND_OSS help 16-bit support for the VIDC onboard sound hardware found on Acorn machines. config SOUND_WAVEARTIST tristate "Netwinder WaveArtist" - depends on ARM && ARCH_NETWINDER + depends on ARM && SOUND_OSS && ARCH_NETWINDER help Say Y here to include support for the Rockwell WaveArtist sound system. This driver is mainly for the NetWinder. @@ -633,11 +646,9 @@ config SOUND_KAHLUA tristate "XpressAudio Sound Blaster emulation" depends on SOUND_SB -endif # SOUND_OSS - config SOUND_SH_DAC_AUDIO tristate "SuperH DAC audio support" - depends on CPU_SH3 + depends on SOUND_PRIME && CPU_SH3 config SOUND_SH_DAC_AUDIO_CHANNEL int "DAC channel" diff --git a/trunk/sound/oss/dmasound/dmasound_core.c b/trunk/sound/oss/dmasound/dmasound_core.c index 95fc5c681755..a003c0ea9303 100644 --- a/trunk/sound/oss/dmasound/dmasound_core.c +++ b/trunk/sound/oss/dmasound/dmasound_core.c @@ -211,6 +211,10 @@ static int state_unit = -1; static int irq_installed; #endif /* MODULE */ +/* software implemented recording volume! */ +uint software_input_volume = SW_INPUT_VOLUME_SCALE * SW_INPUT_VOLUME_DEFAULT; +EXPORT_SYMBOL(software_input_volume); + /* control over who can modify resources shared between play/record */ static mode_t shared_resource_owner; static int shared_resources_initialised; @@ -1184,7 +1188,7 @@ static struct { /* publish this function for use by low-level code, if required */ -static char *get_afmt_string(int afmt) +char *get_afmt_string(int afmt) { switch(afmt) { case AFMT_MU_LAW: @@ -1547,3 +1551,4 @@ EXPORT_SYMBOL(dmasound_catchRadius); EXPORT_SYMBOL(dmasound_ulaw2dma8); EXPORT_SYMBOL(dmasound_alaw2dma8); #endif +EXPORT_SYMBOL(get_afmt_string) ; diff --git a/trunk/sound/oss/dmasound/dmasound_paula.c b/trunk/sound/oss/dmasound/dmasound_paula.c index 06e9e88e4c05..202e8103dc4d 100644 --- a/trunk/sound/oss/dmasound/dmasound_paula.c +++ b/trunk/sound/oss/dmasound/dmasound_paula.c @@ -710,7 +710,7 @@ static MACHINE machAmiga = { /*** Config & Setup **********************************************************/ -static int __init dmasound_paula_init(void) +int __init dmasound_paula_init(void) { int err; diff --git a/trunk/sound/oss/dmasound/dmasound_q40.c b/trunk/sound/oss/dmasound/dmasound_q40.c index 1855b14d90c3..b3379dd7ca5e 100644 --- a/trunk/sound/oss/dmasound/dmasound_q40.c +++ b/trunk/sound/oss/dmasound/dmasound_q40.c @@ -611,7 +611,7 @@ static MACHINE machQ40 = { /*** Config & Setup **********************************************************/ -static int __init dmasound_q40_init(void) +int __init dmasound_q40_init(void) { if (MACH_IS_Q40) { dmasound.mach = machQ40; diff --git a/trunk/sound/oss/msnd.c b/trunk/sound/oss/msnd.c index e4282d93a1aa..ba38d6200099 100644 --- a/trunk/sound/oss/msnd.c +++ b/trunk/sound/oss/msnd.c @@ -20,6 +20,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $ + * ********************************************************************/ #include diff --git a/trunk/sound/oss/msnd.h b/trunk/sound/oss/msnd.h index 61b3955481c5..d0ca582c4583 100644 --- a/trunk/sound/oss/msnd.h +++ b/trunk/sound/oss/msnd.h @@ -24,6 +24,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * $Id: msnd.h,v 1.36 1999/03/21 17:05:42 andrewtv Exp $ + * ********************************************************************/ #ifndef __MSND_H #define __MSND_H diff --git a/trunk/sound/oss/msnd_classic.h b/trunk/sound/oss/msnd_classic.h index 1a17dde2f650..7ffea5267f96 100644 --- a/trunk/sound/oss/msnd_classic.h +++ b/trunk/sound/oss/msnd_classic.h @@ -24,6 +24,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * $Id: msnd_classic.h,v 1.10 1999/03/21 17:36:09 andrewtv Exp $ + * ********************************************************************/ #ifndef __MSND_CLASSIC_H #define __MSND_CLASSIC_H diff --git a/trunk/sound/oss/msnd_pinnacle.c b/trunk/sound/oss/msnd_pinnacle.c index bf27e008f465..f1f49ebf752e 100644 --- a/trunk/sound/oss/msnd_pinnacle.c +++ b/trunk/sound/oss/msnd_pinnacle.c @@ -29,8 +29,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * $Id: msnd_pinnacle.c,v 1.8 2000/12/30 00:33:21 sycamore Exp $ + * * 12-3-2000 Modified IO port validation Steve Sycamore * + * + * $$$: msnd_pinnacle.c,v 1.75 1999/03/21 16:50:09 andrewtv $$$ $ + * ********************************************************************/ #include diff --git a/trunk/sound/oss/msnd_pinnacle.h b/trunk/sound/oss/msnd_pinnacle.h index c18d66cbbe3f..cce911487004 100644 --- a/trunk/sound/oss/msnd_pinnacle.h +++ b/trunk/sound/oss/msnd_pinnacle.h @@ -24,6 +24,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * $Id: msnd_pinnacle.h,v 1.11 1999/03/21 17:36:09 andrewtv Exp $ + * ********************************************************************/ #ifndef __MSND_PINNACLE_H #define __MSND_PINNACLE_H diff --git a/trunk/sound/parisc/Kconfig b/trunk/sound/parisc/Kconfig index 9b61d95010f0..a5a7f9d75d05 100644 --- a/trunk/sound/parisc/Kconfig +++ b/trunk/sound/parisc/Kconfig @@ -1,20 +1,15 @@ # ALSA PA-RISC drivers -menuconfig SND_GSC - bool "GSC sound devices" - depends on GSC - default y - help - Support for GSC sound devices on PA-RISC architectures. - -if SND_GSC +menu "GSC devices" + depends on SND!=n && GSC config SND_HARMONY tristate "Harmony/Vivace sound chip" + depends on SND select SND_PCM help Say 'Y' or 'M' to include support for the Harmony/Vivace sound chip found in most GSC-based PA-RISC workstations. It's frequently provided as part of the Lasi multi-function IC. -endif # SND_GSC +endmenu diff --git a/trunk/sound/pci/Kconfig b/trunk/sound/pci/Kconfig index 8fe5dac39428..7e4742109572 100644 --- a/trunk/sound/pci/Kconfig +++ b/trunk/sound/pci/Kconfig @@ -1,16 +1,11 @@ # ALSA PCI drivers -menuconfig SND_PCI - bool "PCI sound devices" - depends on PCI - default y - help - Support for sound devices connected via the PCI bus. - -if SND_PCI +menu "PCI devices" + depends on SND!=n && PCI config SND_AD1889 tristate "Analog Devices AD1889" + depends on SND select SND_AC97_CODEC help Say Y here to include support for the integrated AC97 sound @@ -22,6 +17,7 @@ config SND_AD1889 config SND_ALS300 tristate "Avance Logic ALS300/ALS300+" + depends on SND select SND_PCM select SND_AC97_CODEC select SND_OPL3_LIB @@ -33,7 +29,7 @@ config SND_ALS300 config SND_ALS4000 tristate "Avance Logic ALS4000" - depends on ISA_DMA_API + depends on SND && ISA_DMA_API select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM @@ -47,6 +43,7 @@ config SND_ALS4000 config SND_ALI5451 tristate "ALi M5451 PCI Audio Controller" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -60,6 +57,7 @@ config SND_ALI5451 config SND_ATIIXP tristate "ATI IXP AC97 Controller" + depends on SND select SND_AC97_CODEC help Say Y here to include support for the integrated AC97 sound @@ -71,6 +69,7 @@ config SND_ATIIXP config SND_ATIIXP_MODEM tristate "ATI IXP Modem" + depends on SND select SND_AC97_CODEC help Say Y here to include support for the integrated MC97 modem on @@ -81,6 +80,7 @@ config SND_ATIIXP_MODEM config SND_AU8810 tristate "Aureal Advantage" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -95,6 +95,7 @@ config SND_AU8810 config SND_AU8820 tristate "Aureal Vortex" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -108,6 +109,7 @@ config SND_AU8820 config SND_AU8830 tristate "Aureal Vortex 2" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -122,6 +124,7 @@ config SND_AU8830 config SND_AW2 tristate "Emagic Audiowerk 2" + depends on SND help Say Y here to include support for Emagic Audiowerk 2 soundcards. @@ -136,7 +139,7 @@ config SND_AW2 config SND_AZT3328 tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on SND && EXPERIMENTAL select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM @@ -149,6 +152,7 @@ config SND_AZT3328 config SND_BT87X tristate "Bt87x Audio Capture" + depends on SND select SND_PCM help If you want to record audio from TV cards based on @@ -170,6 +174,7 @@ config SND_BT87X_OVERCLOCK config SND_CA0106 tristate "SB Audigy LS / Live 24bit" + depends on SND select SND_AC97_CODEC select SND_RAWMIDI select SND_VMASTER @@ -182,6 +187,7 @@ config SND_CA0106 config SND_CMIPCI tristate "C-Media 8338, 8738, 8768, 8770" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM @@ -195,11 +201,13 @@ config SND_CMIPCI config SND_OXYGEN_LIB tristate + depends on SND select SND_PCM select SND_MPU401_UART config SND_OXYGEN tristate "C-Media 8788 (Oxygen)" + depends on SND select SND_OXYGEN_LIB help Say Y here to include support for sound cards based on the @@ -217,6 +225,7 @@ config SND_OXYGEN config SND_CS4281 tristate "Cirrus Logic (Sound Fusion) CS4281" + depends on SND select SND_OPL3_LIB select SND_RAWMIDI select SND_AC97_CODEC @@ -228,6 +237,7 @@ config SND_CS4281 config SND_CS46XX tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" + depends on SND select SND_RAWMIDI select SND_AC97_CODEC help @@ -248,7 +258,7 @@ config SND_CS46XX_NEW_DSP config SND_CS5530 tristate "CS5530 Audio" - depends on ISA_DMA_API + depends on SND && ISA_DMA_API select SND_SB16_DSP help Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips. @@ -258,7 +268,7 @@ config SND_CS5530 config SND_CS5535AUDIO tristate "CS5535/CS5536 Audio" - depends on X86 && !X86_64 + depends on SND && X86 && !X86_64 select SND_PCM select SND_AC97_CODEC help @@ -276,6 +286,7 @@ config SND_CS5535AUDIO config SND_DARLA20 tristate "(Echoaudio) Darla20" + depends on SND select FW_LOADER select SND_PCM help @@ -286,6 +297,7 @@ config SND_DARLA20 config SND_GINA20 tristate "(Echoaudio) Gina20" + depends on SND select FW_LOADER select SND_PCM help @@ -296,6 +308,7 @@ config SND_GINA20 config SND_LAYLA20 tristate "(Echoaudio) Layla20" + depends on SND select FW_LOADER select SND_RAWMIDI select SND_PCM @@ -307,6 +320,7 @@ config SND_LAYLA20 config SND_DARLA24 tristate "(Echoaudio) Darla24" + depends on SND select FW_LOADER select SND_PCM help @@ -317,6 +331,7 @@ config SND_DARLA24 config SND_GINA24 tristate "(Echoaudio) Gina24" + depends on SND select FW_LOADER select SND_PCM help @@ -327,6 +342,7 @@ config SND_GINA24 config SND_LAYLA24 tristate "(Echoaudio) Layla24" + depends on SND select FW_LOADER select SND_RAWMIDI select SND_PCM @@ -338,6 +354,7 @@ config SND_LAYLA24 config SND_MONA tristate "(Echoaudio) Mona" + depends on SND select FW_LOADER select SND_RAWMIDI select SND_PCM @@ -349,6 +366,7 @@ config SND_MONA config SND_MIA tristate "(Echoaudio) Mia" + depends on SND select FW_LOADER select SND_RAWMIDI select SND_PCM @@ -360,6 +378,7 @@ config SND_MIA config SND_ECHO3G tristate "(Echoaudio) 3G cards" + depends on SND select FW_LOADER select SND_RAWMIDI select SND_PCM @@ -371,6 +390,7 @@ config SND_ECHO3G config SND_INDIGO tristate "(Echoaudio) Indigo" + depends on SND select FW_LOADER select SND_PCM help @@ -381,6 +401,7 @@ config SND_INDIGO config SND_INDIGOIO tristate "(Echoaudio) Indigo IO" + depends on SND select FW_LOADER select SND_PCM help @@ -391,6 +412,7 @@ config SND_INDIGOIO config SND_INDIGODJ tristate "(Echoaudio) Indigo DJ" + depends on SND select FW_LOADER select SND_PCM help @@ -401,6 +423,7 @@ config SND_INDIGODJ config SND_EMU10K1 tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" + depends on SND select FW_LOADER select SND_HWDEP select SND_RAWMIDI @@ -418,6 +441,7 @@ config SND_EMU10K1 config SND_EMU10K1X tristate "Emu10k1X (Dell OEM Version)" + depends on SND select SND_AC97_CODEC select SND_RAWMIDI help @@ -429,6 +453,7 @@ config SND_EMU10K1X config SND_ENS1370 tristate "(Creative) Ensoniq AudioPCI 1370" + depends on SND select SND_RAWMIDI select SND_PCM help @@ -439,6 +464,7 @@ config SND_ENS1370 config SND_ENS1371 tristate "(Creative) Ensoniq AudioPCI 1371/1373" + depends on SND select SND_RAWMIDI select SND_AC97_CODEC help @@ -450,6 +476,7 @@ config SND_ENS1371 config SND_ES1938 tristate "ESS ES1938/1946/1969 (Solo-1)" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC @@ -462,6 +489,7 @@ config SND_ES1938 config SND_ES1968 tristate "ESS ES1968/1978 (Maestro-1/2/2E)" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -473,6 +501,7 @@ config SND_ES1968 config SND_FM801 tristate "ForteMedia FM801" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC @@ -499,6 +528,7 @@ config SND_FM801_TEA575X config SND_HDA_INTEL tristate "Intel HD Audio" + depends on SND select SND_PCM select SND_VMASTER help @@ -607,6 +637,7 @@ config SND_HDA_POWER_SAVE_DEFAULT config SND_HDSP tristate "RME Hammerfall DSP Audio" + depends on SND select SND_HWDEP select SND_RAWMIDI select SND_PCM @@ -619,6 +650,7 @@ config SND_HDSP config SND_HDSPM tristate "RME Hammerfall DSP MADI" + depends on SND select SND_HWDEP select SND_RAWMIDI select SND_PCM @@ -631,6 +663,7 @@ config SND_HDSPM config SND_HIFIER tristate "TempoTec HiFier Fantasia" + depends on SND select SND_OXYGEN_LIB help Say Y here to include support for the MediaTek/TempoTec HiFier @@ -641,6 +674,7 @@ config SND_HIFIER config SND_ICE1712 tristate "ICEnsemble ICE1712 (Envy24)" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -657,7 +691,8 @@ config SND_ICE1712 config SND_ICE1724 tristate "ICE/VT1724/1720 (Envy24HT/PT)" - select SND_RAWMIDI + depends on SND + select SND_MPU401_UART select SND_AC97_CODEC select SND_VMASTER help @@ -674,6 +709,7 @@ config SND_ICE1724 config SND_INTEL8X0 tristate "Intel/SiS/nVidia/AMD/ALi AC97 Controller" + depends on SND select SND_AC97_CODEC help Say Y here to include support for the integrated AC97 sound @@ -686,6 +722,7 @@ config SND_INTEL8X0 config SND_INTEL8X0M tristate "Intel/SiS/nVidia/AMD MC97 Modem" + depends on SND select SND_AC97_CODEC help Say Y here to include support for the integrated MC97 modem on @@ -696,6 +733,7 @@ config SND_INTEL8X0M config SND_KORG1212 tristate "Korg 1212 IO" + depends on SND select FW_LOADER if !SND_KORG1212_FIRMWARE_IN_KERNEL select SND_PCM help @@ -715,6 +753,7 @@ config SND_KORG1212_FIRMWARE_IN_KERNEL config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" + depends on SND select FW_LOADER if !SND_MAESTRO3_FIRMWARE_IN_KERNEL select SND_AC97_CODEC help @@ -735,6 +774,7 @@ config SND_MAESTRO3_FIRMWARE_IN_KERNEL config SND_MIXART tristate "Digigram miXart" + depends on SND select SND_HWDEP select SND_PCM help @@ -746,6 +786,7 @@ config SND_MIXART config SND_NM256 tristate "NeoMagic NM256AV/ZX" + depends on SND select SND_AC97_CODEC help Say Y here to include support for NeoMagic NM256AV/ZX chips. @@ -755,6 +796,7 @@ config SND_NM256 config SND_PCXHR tristate "Digigram PCXHR" + depends on SND select SND_PCM select SND_HWDEP help @@ -765,6 +807,7 @@ config SND_PCXHR config SND_RIPTIDE tristate "Conexant Riptide" + depends on SND select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART @@ -777,6 +820,7 @@ config SND_RIPTIDE config SND_RME32 tristate "RME Digi32, 32/8, 32 PRO" + depends on SND select SND_PCM help Say Y to include support for RME Digi32, Digi32 PRO and @@ -788,6 +832,7 @@ config SND_RME32 config SND_RME96 tristate "RME Digi96, 96/8, 96/8 PRO" + depends on SND select SND_PCM help Say Y here to include support for RME Digi96, Digi96/8 and @@ -798,6 +843,7 @@ config SND_RME96 config SND_RME9652 tristate "RME Digi9652 (Hammerfall)" + depends on SND select SND_PCM help Say Y here to include support for RME Hammerfall (RME @@ -808,7 +854,7 @@ config SND_RME9652 config SND_SIS7019 tristate "SiS 7019 Audio Accelerator" - depends on X86 && !X86_64 + depends on SND && X86 && !X86_64 select SND_AC97_CODEC help Say Y here to include support for the SiS 7019 Audio Accelerator. @@ -818,6 +864,7 @@ config SND_SIS7019 config SND_SONICVIBES tristate "S3 SonicVibes" + depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC @@ -830,6 +877,7 @@ config SND_SONICVIBES config SND_TRIDENT tristate "Trident 4D-Wave DX/NX; SiS 7018" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -841,6 +889,7 @@ config SND_TRIDENT config SND_VIA82XX tristate "VIA 82C686A/B, 8233/8235 AC97 Controller" + depends on SND select SND_MPU401_UART select SND_AC97_CODEC help @@ -852,6 +901,7 @@ config SND_VIA82XX config SND_VIA82XX_MODEM tristate "VIA 82C686A/B, 8233 based Modems" + depends on SND select SND_AC97_CODEC help Say Y here to include support for the integrated MC97 modem on @@ -862,6 +912,7 @@ config SND_VIA82XX_MODEM config SND_VIRTUOSO tristate "Asus Virtuoso 100/200 (Xonar)" + depends on SND select SND_OXYGEN_LIB help Say Y here to include support for sound cards based on the @@ -872,6 +923,7 @@ config SND_VIRTUOSO config SND_VX222 tristate "Digigram VX222" + depends on SND select SND_VX_LIB help Say Y here to include support for Digigram VX222 soundcards. @@ -881,6 +933,7 @@ config SND_VX222 config SND_YMFPCI tristate "Yamaha YMF724/740/744/754" + depends on SND select FW_LOADER if !SND_YMFPCI_FIRMWARE_IN_KERNEL select SND_OPL3_LIB select SND_MPU401_UART @@ -901,4 +954,25 @@ config SND_YMFPCI_FIRMWARE_IN_KERNEL for the YMFPCI driver. If you choose N here, you need to install the firmware files from the alsa-firmware package. -endif # SND_PCI +config SND_AC97_POWER_SAVE + bool "AC97 Power-Saving Mode" + depends on SND_AC97_CODEC && EXPERIMENTAL + default n + help + Say Y here to enable the aggressive power-saving support of + AC97 codecs. In this mode, the power-mode is dynamically + controlled at each open/close. + + The mode is activated by passing power_save=1 option to + snd-ac97-codec driver. You can toggle it dynamically over + sysfs, too. + +config SND_AC97_POWER_SAVE_DEFAULT + int "Default time-out for AC97 power-save mode" + depends on SND_AC97_POWER_SAVE + default 0 + help + The default time-out value in seconds for AC97 automatic + power-save mode. 0 means to disable the power-save mode. + +endmenu diff --git a/trunk/sound/pci/Makefile b/trunk/sound/pci/Makefile index 65b25d221cd2..85ef14bc8056 100644 --- a/trunk/sound/pci/Makefile +++ b/trunk/sound/pci/Makefile @@ -13,7 +13,7 @@ snd-bt87x-objs := bt87x.o snd-cmipci-objs := cmipci.o snd-cs4281-objs := cs4281.o snd-cs5530-objs := cs5530.o -snd-ens1370-objs := ens1370.o ak4531_codec.o +snd-ens1370-objs := ens1370.o snd-ens1371-objs := ens1371.o snd-es1938-objs := es1938.o snd-es1968-objs := es1968.o diff --git a/trunk/sound/pci/ac97/Makefile b/trunk/sound/pci/ac97/Makefile index 41fa322f0971..0be48b1a22d0 100644 --- a/trunk/sound/pci/ac97/Makefile +++ b/trunk/sound/pci/ac97/Makefile @@ -3,8 +3,16 @@ # Copyright (c) 2001 by Jaroslav Kysela # -snd-ac97-codec-y := ac97_codec.o ac97_pcm.o -snd-ac97-codec-$(CONFIG_PROC_FS) += ac97_proc.o +snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o + +ifneq ($(CONFIG_PROC_FS),) +snd-ac97-codec-objs += ac97_proc.o +endif + +snd-ak4531-codec-objs := ak4531_codec.o # Toplevel Module Dependency obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o +obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o + +obj-m := $(sort $(obj-m)) diff --git a/trunk/sound/pci/ac97/ac97_codec.c b/trunk/sound/pci/ac97/ac97_codec.c index 07364c00768a..45fd29017ddd 100644 --- a/trunk/sound/pci/ac97/ac97_codec.c +++ b/trunk/sound/pci/ac97/ac97_codec.c @@ -49,9 +49,8 @@ MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); #ifdef CONFIG_SND_AC97_POWER_SAVE static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT; -module_param(power_save, int, 0644); -MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " - "(in second, 0 = disable)."); +module_param(power_save, bool, 0644); +MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); #endif /* @@ -2295,11 +2294,9 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ snd_ac97_write(ac97, AC97_POWERDOWN, power); udelay(100); - power |= AC97_PD_PR2; /* Analog Mixer powerdown (Vref on) */ + power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ snd_ac97_write(ac97, AC97_POWERDOWN, power); if (ac97_is_power_save_mode(ac97)) { - power |= AC97_PD_PR3; /* Analog Mixer powerdown */ - snd_ac97_write(ac97, AC97_POWERDOWN, power); udelay(100); /* AC-link powerdown, internal Clk disable */ /* FIXME: this may cause click noises on some boards */ @@ -2365,7 +2362,7 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) * that open/close frequently) */ schedule_delayed_work(&ac97->power_work, - msecs_to_jiffies(power_save * 1000)); + msecs_to_jiffies(2000)); else { cancel_delayed_work(&ac97->power_work); update_power_regs(ac97); diff --git a/trunk/sound/pci/ac97/ac97_patch.c b/trunk/sound/pci/ac97/ac97_patch.c index 0746e9ccc20b..1292dcee072d 100644 --- a/trunk/sound/pci/ac97/ac97_patch.c +++ b/trunk/sound/pci/ac97/ac97_patch.c @@ -669,7 +669,6 @@ AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), -AC97_SINGLE("Master Left Inv Switch", AC97_MASTER, 6, 1, 0), AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0), AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0), AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0), @@ -3353,66 +3352,8 @@ AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), }; -static const char *slave_vols_vt1616[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - NULL -}; - -static const char *slave_sws_vt1616[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - NULL -}; - -/* find a mixer control element with the given name */ -static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, - const char *name) -{ - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(id.name, name); - return snd_ctl_find_id(ac97->bus->card, &id); -} - -/* create a virtual master control and add slaves */ -int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, - const unsigned int *tlv, const char **slaves) -{ - struct snd_kcontrol *kctl; - const char **s; - int err; - - kctl = snd_ctl_make_virtual_master(name, tlv); - if (!kctl) - return -ENOMEM; - err = snd_ctl_add(ac97->bus->card, kctl); - if (err < 0) - return err; - - for (s = slaves; *s; s++) { - struct snd_kcontrol *sctl; - - sctl = snd_ac97_find_mixer_ctl(ac97, *s); - if (!sctl) { - snd_printdd("Cannot find slave %s, skipped\n", *s); - continue; - } - err = snd_ctl_add_slave(kctl, sctl); - if (err < 0) - return err; - } - return 0; -} - static int patch_vt1616_specific(struct snd_ac97 * ac97) { - struct snd_kcontrol *kctl; int err; if (snd_ac97_try_bit(ac97, 0x5a, 9)) @@ -3420,24 +3361,6 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97) return err; if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) return err; - - /* There is already a misnamed master switch. Rename it. */ - kctl = snd_ac97_find_mixer_ctl(ac97, "Master Playback Volume"); - if (!kctl) - return -EINVAL; - - snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Front Playback"); - - err = snd_ac97_add_vmaster(ac97, "Master Playback Volume", - kctl->tlv.p, slave_vols_vt1616); - if (err < 0) - return err; - - err = snd_ac97_add_vmaster(ac97, "Master Playback Switch", - NULL, slave_sws_vt1616); - if (err < 0) - return err; - return 0; } @@ -3710,7 +3633,7 @@ static int patch_ucb1400(struct snd_ac97 * ac97) { ac97->build_ops = &patch_ucb1400_ops; /* enable headphone driver and smart low power mode by default */ - snd_ac97_write_cache(ac97, 0x6a, 0x0050); - snd_ac97_write_cache(ac97, 0x6c, 0x0030); + snd_ac97_write(ac97, 0x6a, 0x0050); + snd_ac97_write(ac97, 0x6c, 0x0030); return 0; } diff --git a/trunk/sound/pci/ak4531_codec.c b/trunk/sound/pci/ac97/ak4531_codec.c similarity index 96% rename from trunk/sound/pci/ak4531_codec.c rename to trunk/sound/pci/ac97/ak4531_codec.c index 33d37b1c42fc..c0c1633999ea 100644 --- a/trunk/sound/pci/ak4531_codec.c +++ b/trunk/sound/pci/ac97/ak4531_codec.c @@ -28,11 +28,9 @@ #include #include -/* MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Universal routines for AK4531 codec"); MODULE_LICENSE("GPL"); -*/ #ifdef CONFIG_PROC_FS static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531); @@ -272,7 +270,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); -static struct snd_kcontrol_new snd_ak4531_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ak4531_controls[] = { AK4531_DOUBLE_TLV("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, @@ -381,9 +379,8 @@ static u8 snd_ak4531_initial_map[0x19 + 1] = { 0x01 /* 19: Mic Amp Setup */ }; -int __devinit snd_ak4531_mixer(struct snd_card *card, - struct snd_ak4531 *_ak4531, - struct snd_ak4531 **rak4531) +int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531, + struct snd_ak4531 **rak4531) { unsigned int idx; int err; @@ -479,8 +476,7 @@ static void snd_ak4531_proc_read(struct snd_info_entry *entry, ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); } -static void __devinit -snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) +static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) { struct snd_info_entry *entry; @@ -488,3 +484,25 @@ snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); } #endif + +EXPORT_SYMBOL(snd_ak4531_mixer); +#ifdef CONFIG_PM +EXPORT_SYMBOL(snd_ak4531_suspend); +EXPORT_SYMBOL(snd_ak4531_resume); +#endif + +/* + * INIT part + */ + +static int __init alsa_ak4531_init(void) +{ + return 0; +} + +static void __exit alsa_ak4531_exit(void) +{ +} + +module_init(alsa_ak4531_init) +module_exit(alsa_ak4531_exit) diff --git a/trunk/sound/pci/au88x0/au88x0_game.c b/trunk/sound/pci/au88x0/au88x0_game.c index e291aa59742e..bc212f41a38a 100644 --- a/trunk/sound/pci/au88x0/au88x0_game.c +++ b/trunk/sound/pci/au88x0/au88x0_game.c @@ -1,4 +1,6 @@ /* + * $Id: au88x0_game.c,v 1.9 2003/09/22 03:51:28 mjander Exp $ + * * Manuel Jander. * * Based on the work of: diff --git a/trunk/sound/pci/azt3328.c b/trunk/sound/pci/azt3328.c index 22f18f3cfbc9..5f63af6b88a2 100644 --- a/trunk/sound/pci/azt3328.c +++ b/trunk/sound/pci/azt3328.c @@ -1,6 +1,6 @@ /* * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). - * Copyright (C) 2002, 2005 - 2008 by Andreas Mohr + * Copyright (C) 2002, 2005, 2006, 2007 by Andreas Mohr * * Framework borrowed from Bart Hartgers's als4000.c. * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), @@ -35,20 +35,9 @@ * (3 weeks' worth of evenings filled with driver work). * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros) * - * It is quite likely that the AZF3328 chip is the PCI cousin of the - * AZF3318 ("azt1020 pnp", "MM Pro 16") ISA chip, given very similar specs. - * * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name - * for compatibility reasons) from Azfin (joint-venture of Aztech and Fincitec, - * Fincitec acquired by National Semiconductor in 2002, together with the - * Fincitec-related company ARSmikro) has the following features: + * for compatibility reasons) has the following features: * - * - compatibility & compliance: - * - Microsoft PC 97 ("PC 97 Hardware Design Guide", - * http://www.microsoft.com/whdc/archive/pcguides.mspx) - * - Microsoft PC 98 Baseline Audio - * - MPU401 UART - * - Sound Blaster Emulation (DOS Box) * - builtin AC97 conformant codec (SNR over 80dB) * Note that "conformant" != "compliant"!! this chip's mixer register layout * *differs* from the standard AC97 layout: @@ -59,28 +48,21 @@ * addresses illegally. So far unfortunately it looks like the very flexible * ALSA AC97 support is still not enough to easily compensate for such a * grave layout violation despite all tweaks and quirks mechanisms it offers. - * - builtin genuine OPL3 - verified to work fine, 20080506 + * - builtin genuine OPL3 * - full duplex 16bit playback/record at independent sampling rate - * - MPU401 (+ legacy address support, claimed by one official spec sheet) - * FIXME: how to enable legacy addr?? + * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? * - game port (legacy address support) - * - builtin DirectInput support, helps reduce CPU overhead (interrupt-driven - * features supported). - See common term "Digital Enhanced Game Port"... - * (probably DirectInput 3.0 spec - confirm) * - builtin 3D enhancement (said to be YAMAHA Ymersion) + * - builtin DirectInput support, helps reduce CPU overhead (interrupt-driven + * features supported) * - built-in General DirectX timer having a 20 bits counter * with 1us resolution (see below!) - * - I2S serial output port for external DAC + * - I2S serial port for external DAC * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI * - supports hardware volume control * - single chip low cost solution (128 pin QFP) * - supports programmable Sub-vendor and Sub-system ID * required for Microsoft's logo compliance (FIXME: where?) - * At least the Trident 4D Wave DX has one bit somewhere - * to enable writes to PCI subsystem VID registers, that should be it. - * This might easily be in extended PCI reg space, since PCI168 also has - * some custom data starting at 0x80. What kind of config settings - * are located in our extended PCI space anyway?? * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms * * Note that this driver now is actually *better* than the Windows driver, @@ -92,24 +74,6 @@ * - "timidity -iAv -B2,8 -Os -EFreverb=0" * - "pmidi -p 128:0 jazz.mid" * - * OPL3 hardware playback testing, try something like: - * cat /proc/asound/hwdep - * and - * aconnect -o - * Then use - * sbiload -Dhw:x,y --opl3 /usr/share/sounds/opl3/std.o3 ......./drums.o3 - * where x,y is the xx-yy number as given in hwdep. - * Then try - * pmidi -p a:b jazz.mid - * where a:b is the client number plus 0 usually, as given by aconnect above. - * Oh, and make sure to unmute the FM mixer control (doh!) - * NOTE: power use during OPL3 playback is _VERY_ high (70W --> 90W!) - * despite no CPU activity, possibly due to hindering ACPI idling somehow. - * Shouldn't be a problem of the AZF3328 chip itself, I'd hope. - * Higher PCM / FM mixer levels seem to conflict (causes crackling), - * at least sometimes. Maybe even use with hardware sequencer timer above :) - * adplay/adplug-utils might soon offer hardware-based OPL3 playback, too. - * * Certain PCI versions of this card are susceptible to DMA traffic underruns * in some systems (resulting in sound crackling/clicking/popping), * probably because they don't have a DMA FIFO buffer or so. @@ -123,8 +87,6 @@ * better than a VIA, yet ironically I still get crackling, like many other * people with the same chipset. * Possible remedies: - * - use speaker (amplifier) output instead of headphone output - * (in case crackling is due to overloaded output clipping) * - plug card into a different PCI slot, preferrably one that isn't shared * too much (this helps a lot, but not completely!) * - get rid of PCI VGA card, use AGP instead @@ -132,23 +94,18 @@ * - fiddle with PCI latency settings (setpci -v -s BUSID latency_timer=XX) * Not too helpful. * - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS - * + * * BUGS - * - full-duplex might *still* be problematic, however a recent test was fine + * - full-duplex might *still* be problematic, not fully tested recently * - (non-bug) "Bass/Treble or 3D settings don't work" - they do get evaluated * if you set PCM output switch to "pre 3D" instead of "post 3D". * If this can't be set, then get a mixer application that Isn't Stupid (tm) * (e.g. kmix, gamix) - unfortunately several are!! - * - locking is not entirely clean, especially the audio stream activity - * ints --> may be racy - * - an _unconnected_ secondary joystick at the gameport will be reported - * to be "active" (floating values, not precisely -1) due to the way we need - * to read the Digital Enhanced Game Port. Not sure whether it is fixable. - * + * * TODO * - test MPU401 MIDI playback etc. - * - add more power micro-management (disable various units of the card - * as long as they're unused). However this requires more I/O ports which I + * - add some power micro-management (disable various units of the card + * as long as they're unused). However this requires I/O ports which I * haven't figured out yet and which thus might not even exist... * The standard suspend/resume functionality could probably make use of * some improvement, too... @@ -156,7 +113,6 @@ * - figure out some cleverly evil scheme to possibly make ALSA AC97 code * fully accept our quite incompatible ""AC97"" mixer and thus save some * code (but I'm not too optimistic that doing this is possible at all) - * - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport. */ #include @@ -182,7 +138,7 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_GAMEPORT 1 +#define SUPPORT_JOYSTICK 1 #endif #define DEBUG_MISC 0 @@ -191,14 +147,13 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define DEBUG_PLAY_REC 0 #define DEBUG_IO 0 #define DEBUG_TIMER 0 -#define DEBUG_GAME 0 #define MIXER_TESTING 0 #if DEBUG_MISC #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) #else #define snd_azf3328_dbgmisc(format, args...) -#endif +#endif #if DEBUG_CALLS #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) @@ -208,31 +163,25 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define snd_azf3328_dbgcalls(format, args...) #define snd_azf3328_dbgcallenter() #define snd_azf3328_dbgcallleave() -#endif +#endif #if DEBUG_MIXER #define snd_azf3328_dbgmixer(format, args...) printk(format, ##args) #else #define snd_azf3328_dbgmixer(format, args...) -#endif +#endif #if DEBUG_PLAY_REC #define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args) #else #define snd_azf3328_dbgplay(format, args...) -#endif +#endif #if DEBUG_MISC #define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args) #else #define snd_azf3328_dbgtimer(format, args...) -#endif - -#if DEBUG_GAME -#define snd_azf3328_dbggame(format, args...) printk(KERN_ERR format, ##args) -#else -#define snd_azf3328_dbggame(format, args...) -#endif +#endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ module_param_array(index, int, NULL, 0444); @@ -246,62 +195,51 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +module_param_array(joystick, bool, NULL, 0444); +MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard."); +#endif + static int seqtimer_scaling = 128; module_param(seqtimer_scaling, int, 0444); MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); -struct snd_azf3328_audio_stream { - struct snd_pcm_substream *substream; - int enabled; - int running; - unsigned long portbase; -}; - -enum snd_azf3328_stream_index { - AZF_PLAYBACK = 0, - AZF_CAPTURE = 1, -}; - struct snd_azf3328 { /* often-used fields towards beginning, then grouped */ - - unsigned long codec_io; /* usually 0xb000, size 128 */ - unsigned long game_io; /* usually 0xb400, size 8 */ - unsigned long mpu_io; /* usually 0xb800, size 4 */ - unsigned long opl3_io; /* usually 0xbc00, size 8 */ - unsigned long mixer_io; /* usually 0xc000, size 64 */ + unsigned long codec_port; + unsigned long io2_port; + unsigned long mpu_port; + unsigned long synth_port; + unsigned long mixer_port; spinlock_t reg_lock; struct snd_timer *timer; - + struct snd_pcm *pcm; - struct snd_azf3328_audio_stream audio_stream[2]; + struct snd_pcm_substream *playback_substream; + struct snd_pcm_substream *capture_substream; + unsigned int is_playing; + unsigned int is_recording; struct snd_card *card; struct snd_rawmidi *rmidi; -#ifdef SUPPORT_GAMEPORT +#ifdef SUPPORT_JOYSTICK struct gameport *gameport; - int axes[4]; #endif struct pci_dev *pci; int irq; - /* register 0x6a is write-only, thus need to remember setting. - * If we need to add more registers here, then we might try to fold this - * into some transparent combined shadow register handling with - * CONFIG_PM register storage below, but that's slightly difficult. */ - u16 shadow_reg_codec_6AH; - #ifdef CONFIG_PM /* register value containers for power management * Note: not always full I/O range preserved (just like Win driver!) */ - u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2]; - u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; - u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; - u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; + u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2]; + u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2]; + u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; + u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2]; u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; #endif }; @@ -314,166 +252,126 @@ static const struct pci_device_id snd_azf3328_ids[] = { MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); - -static int -snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) -{ - u8 prev = inb(reg), new; - - new = (do_set) ? (prev|mask) : (prev & ~mask); - /* we need to always write the new value no matter whether it differs - * or not, since some register bits don't indicate their setting */ - outb(new, reg); - if (new != prev) - return 1; - - return 0; -} - static inline void -snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) +snd_azf3328_codec_outb(const struct snd_azf3328 *chip, int reg, u8 value) { - outb(value, chip->codec_io + reg); + outb(value, chip->codec_port + reg); } static inline u8 -snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg) +snd_azf3328_codec_inb(const struct snd_azf3328 *chip, int reg) { - return inb(chip->codec_io + reg); + return inb(chip->codec_port + reg); } static inline void -snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) +snd_azf3328_codec_outw(const struct snd_azf3328 *chip, int reg, u16 value) { - outw(value, chip->codec_io + reg); + outw(value, chip->codec_port + reg); } static inline u16 -snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg) -{ - return inw(chip->codec_io + reg); -} - -static inline void -snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) -{ - outl(value, chip->codec_io + reg); -} - -static inline u32 -snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg) +snd_azf3328_codec_inw(const struct snd_azf3328 *chip, int reg) { - return inl(chip->codec_io + reg); + return inw(chip->codec_port + reg); } static inline void -snd_azf3328_game_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) +snd_azf3328_codec_outl(const struct snd_azf3328 *chip, int reg, u32 value) { - outb(value, chip->game_io + reg); + outl(value, chip->codec_port + reg); } static inline void -snd_azf3328_game_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) +snd_azf3328_io2_outb(const struct snd_azf3328 *chip, int reg, u8 value) { - outw(value, chip->game_io + reg); + outb(value, chip->io2_port + reg); } static inline u8 -snd_azf3328_game_inb(const struct snd_azf3328 *chip, unsigned reg) +snd_azf3328_io2_inb(const struct snd_azf3328 *chip, int reg) { - return inb(chip->game_io + reg); -} - -static inline u16 -snd_azf3328_game_inw(const struct snd_azf3328 *chip, unsigned reg) -{ - return inw(chip->game_io + reg); + return inb(chip->io2_port + reg); } static inline void -snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) +snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, int reg, u16 value) { - outw(value, chip->mixer_io + reg); + outw(value, chip->mixer_port + reg); } static inline u16 -snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg) +snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, int reg) { - return inw(chip->mixer_io + reg); + return inw(chip->mixer_port + reg); } -#define AZF_MUTE_BIT 0x80 - -static int -snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, - unsigned reg, int do_mute -) +static void +snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, int reg, int do_mute) { - unsigned long portbase = chip->mixer_io + reg + 1; - int updated; + unsigned long portbase = chip->mixer_port + reg + 1; + unsigned char oldval; /* the mute bit is on the *second* (i.e. right) register of a * left/right channel setting */ - updated = snd_azf3328_io_reg_setb(portbase, AZF_MUTE_BIT, do_mute); - - /* indicate whether it was muted before */ - return (do_mute) ? !updated : updated; + oldval = inb(portbase); + if (do_mute) + oldval |= 0x80; + else + oldval &= ~0x80; + outb(oldval, portbase); } static void -snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, - unsigned reg, - unsigned char dst_vol_left, - unsigned char dst_vol_right, - int chan_sel, int delay -) +snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg, unsigned char dst_vol_left, unsigned char dst_vol_right, int chan_sel, int delay) { - unsigned long portbase = chip->mixer_io + reg; + unsigned long portbase = chip->mixer_port + reg; unsigned char curr_vol_left = 0, curr_vol_right = 0; - int left_change = 0, right_change = 0; - + int left_done = 0, right_done = 0; + snd_azf3328_dbgcallenter(); - - if (chan_sel & SET_CHAN_LEFT) { + if (chan_sel & SET_CHAN_LEFT) curr_vol_left = inb(portbase + 1); - - /* take care of muting flag contained in left channel */ - if (curr_vol_left & AZF_MUTE_BIT) - dst_vol_left |= AZF_MUTE_BIT; - else - dst_vol_left &= ~AZF_MUTE_BIT; - - left_change = (curr_vol_left > dst_vol_left) ? -1 : 1; - } - - if (chan_sel & SET_CHAN_RIGHT) { + else + left_done = 1; + if (chan_sel & SET_CHAN_RIGHT) curr_vol_right = inb(portbase + 0); - - right_change = (curr_vol_right > dst_vol_right) ? -1 : 1; - } + else + right_done = 1; + + /* take care of muting flag (0x80) contained in left channel */ + if (curr_vol_left & 0x80) + dst_vol_left |= 0x80; + else + dst_vol_left &= ~0x80; do { - if (left_change) { - if (curr_vol_left != dst_vol_left) { - curr_vol_left += left_change; - outb(curr_vol_left, portbase + 1); - } else - left_change = 0; + if (!left_done) { + if (curr_vol_left > dst_vol_left) + curr_vol_left--; + else + if (curr_vol_left < dst_vol_left) + curr_vol_left++; + else + left_done = 1; + outb(curr_vol_left, portbase + 1); } - if (right_change) { - if (curr_vol_right != dst_vol_right) { - curr_vol_right += right_change; - + if (!right_done) { + if (curr_vol_right > dst_vol_right) + curr_vol_right--; + else + if (curr_vol_right < dst_vol_right) + curr_vol_right++; + else + right_done = 1; /* during volume change, the right channel is crackling * somewhat more than the left channel, unfortunately. * This seems to be a hardware issue. */ - outb(curr_vol_right, portbase + 0); - } else - right_change = 0; + outb(curr_vol_right, portbase + 0); } if (delay) mdelay(delay); - } while ((left_change) || (right_change)); + } while ((!left_done) || (!right_done)); snd_azf3328_dbgcallleave(); } @@ -481,7 +379,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, * general mixer element */ struct azf3328_mixer_reg { - unsigned reg; + unsigned int reg; unsigned int lchan_shift, rchan_shift; unsigned int mask; unsigned int invert: 1; @@ -646,14 +544,13 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, "Mix", "Mic" }; static const char * const texts3[] = { - "Mic", "CD", "Video", "Aux", + "Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone" }; static const char * const texts4[] = { "pre 3D", "post 3D" }; struct azf3328_mixer_reg reg; - const char * const *p = NULL; snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -664,20 +561,18 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, if (reg.reg == IDX_MIXER_ADVCTL2) { switch(reg.lchan_shift) { case 8: /* modem out sel */ - p = texts1; + strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); break; case 9: /* mono sel source */ - p = texts2; + strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); break; case 15: /* PCM Out Path */ - p = texts4; + strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]); break; } } else - if (reg.reg == IDX_MIXER_REC_SELECT) - p = texts3; - - strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]); + strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] +); return 0; } @@ -688,7 +583,7 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol, struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); struct azf3328_mixer_reg reg; unsigned short val; - + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); val = snd_azf3328_mixer_inw(chip, reg.reg); if (reg.reg == IDX_MIXER_REC_SELECT) { @@ -710,7 +605,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); struct azf3328_mixer_reg reg; unsigned int oreg, nreg, val; - + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); oreg = snd_azf3328_mixer_inw(chip, reg.reg); val = oreg; @@ -736,11 +631,9 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), - AZF3328_MIXER_SWITCH("PCM Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), - AZF3328_MIXER_VOL_STEREO("PCM Playback Volume", - IDX_MIXER_WAVEOUT, 0x1f, 1), - AZF3328_MIXER_SWITCH("PCM 3D Bypass Playback Switch", - IDX_MIXER_ADVCTL2, 7, 1), + AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), + AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1), + AZF3328_MIXER_SWITCH("Wave 3D Bypass Playback Switch", IDX_MIXER_ADVCTL2, 7, 1), AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), @@ -824,16 +717,15 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); /* mute and zero volume channels */ - for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); ++idx) { + for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); idx++) { snd_azf3328_mixer_outw(chip, snd_azf3328_init_values[idx][0], snd_azf3328_init_values[idx][1]); } - + /* add mixer controls */ sw = snd_azf3328_mixer_controls; - for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); - ++idx, ++sw) { + for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); idx++, sw++) { if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0) return err; } @@ -865,9 +757,9 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) } static void -snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, - unsigned reg, - enum azf_freq_t bitrate, +snd_azf3328_setfmt(struct snd_azf3328 *chip, + unsigned int reg, + unsigned int bitrate, unsigned int format_width, unsigned int channels ) @@ -877,25 +769,24 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, snd_azf3328_dbgcallenter(); switch (bitrate) { - case AZF_FREQ_4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; - case AZF_FREQ_4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; - case AZF_FREQ_5512: - /* the AZF3328 names it "5510" for some strange reason */ - val |= SOUNDFORMAT_FREQ_5510; break; - case AZF_FREQ_6620: val |= SOUNDFORMAT_FREQ_6620; break; - case AZF_FREQ_8000: val |= SOUNDFORMAT_FREQ_8000; break; - case AZF_FREQ_9600: val |= SOUNDFORMAT_FREQ_9600; break; - case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break; - case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; - case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break; - case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break; - case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break; + case 4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; + case 4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; + case 5512: val |= SOUNDFORMAT_FREQ_5510; break; /* the AZF3328 names it "5510" for some strange reason */ + case 6620: val |= SOUNDFORMAT_FREQ_6620; break; + case 8000: val |= SOUNDFORMAT_FREQ_8000; break; + case 9600: val |= SOUNDFORMAT_FREQ_9600; break; + case 11025: val |= SOUNDFORMAT_FREQ_11025; break; + case 13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; + case 16000: val |= SOUNDFORMAT_FREQ_16000; break; + case 22050: val |= SOUNDFORMAT_FREQ_22050; break; + case 32000: val |= SOUNDFORMAT_FREQ_32000; break; + case 44100: val |= SOUNDFORMAT_FREQ_44100; break; + case 48000: val |= SOUNDFORMAT_FREQ_48000; break; + case 66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; default: snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); - /* fall-through */ - case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break; - case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break; - case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; + val |= SOUNDFORMAT_FREQ_44100; + break; } /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ @@ -914,10 +805,10 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, val |= SOUNDFORMAT_FLAG_16BIT; spin_lock_irqsave(&chip->reg_lock, flags); - + /* set bitrate/format */ snd_azf3328_codec_outw(chip, reg, val); - + /* changing the bitrate/format settings switches off the * audio output with an annoying click in case of 8/16bit format change * (maybe shutting down DAC/ADC?), thus immediately @@ -939,95 +830,31 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, snd_azf3328_dbgcallleave(); } -static inline void -snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, - unsigned reg -) -{ - /* choose lowest frequency for low power consumption. - * While this will cause louder noise due to rather coarse frequency, - * it should never matter since output should always - * get disabled properly when idle anyway. */ - snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1); -} - -static void -snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip, - unsigned bitmask, - int enable -) -{ - if (enable) - chip->shadow_reg_codec_6AH &= ~bitmask; - else - chip->shadow_reg_codec_6AH |= bitmask; - snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", - bitmask, enable, chip->shadow_reg_codec_6AH); - snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH); -} - -static inline void -snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable) -{ - snd_azf3328_dbgplay("codec_enable %d\n", enable); - /* no idea what exactly is being done here, but I strongly assume it's - * PM related */ - snd_azf3328_codec_reg_6AH_update( - chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable - ); -} - -static void -snd_azf3328_codec_activity(struct snd_azf3328 *chip, - enum snd_azf3328_stream_index stream_type, - int enable -) -{ - int need_change = (chip->audio_stream[stream_type].running != enable); - - snd_azf3328_dbgplay( - "codec_activity: type %d, enable %d, need_change %d\n", - stream_type, enable, need_change - ); - if (need_change) { - enum snd_azf3328_stream_index other = - (stream_type == AZF_PLAYBACK) ? - AZF_CAPTURE : AZF_PLAYBACK; - /* small check to prevent shutting down the other party - * in case it's active */ - if ((enable) || !(chip->audio_stream[other].running)) - snd_azf3328_codec_enable(chip, enable); - - /* ...and adjust clock, too - * (reduce noise and power consumption) */ - if (!enable) - snd_azf3328_codec_setfmt_lowpower( - chip, - chip->audio_stream[stream_type].portbase - + IDX_IO_PLAY_SOUNDFORMAT - ); - } - chip->audio_stream[stream_type].running = enable; -} - static void snd_azf3328_setdmaa(struct snd_azf3328 *chip, long unsigned int addr, unsigned int count, unsigned int size, - enum snd_azf3328_stream_index stream_type -) + int do_recording) { - snd_azf3328_dbgcallenter(); - if (!chip->audio_stream[stream_type].running) { - /* AZF3328 uses a two buffer pointer DMA playback approach */ - - unsigned long flags, portbase, addr_area2; + unsigned long flags, portbase; + unsigned int is_running; - /* width 32bit (prevent overflow): */ - unsigned long count_areas, count_tmp; + snd_azf3328_dbgcallenter(); + if (do_recording) { + /* access capture registers, i.e. skip playback reg section */ + portbase = chip->codec_port + 0x20; + is_running = chip->is_recording; + } else { + /* access the playback register section */ + portbase = chip->codec_port + 0x00; + is_running = chip->is_playing; + } - portbase = chip->audio_stream[stream_type].portbase; + /* AZF3328 uses a two buffer pointer DMA playback approach */ + if (!is_running) { + unsigned long addr_area2; + unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ count_areas = size/2; addr_area2 = addr+count_areas; count_areas--; /* max. index */ @@ -1057,11 +884,11 @@ snd_azf3328_playback_prepare(struct snd_pcm_substream *substream) snd_azf3328_dbgcallenter(); #if 0 - snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); - snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK); + snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 0); #endif snd_azf3328_dbgcallleave(); return 0; @@ -1079,11 +906,11 @@ snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) snd_azf3328_dbgcallenter(); #if 0 - snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, + snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); - snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE); + snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 1); #endif snd_azf3328_dbgcallleave(); return 0; @@ -1096,7 +923,6 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_pcm_runtime *runtime = substream->runtime; int result = 0; unsigned int status1; - int previously_muted; snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); @@ -1104,23 +930,20 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: snd_azf3328_dbgplay("START PLAYBACK\n"); - /* mute WaveOut (avoid clicking during setup) */ - previously_muted = - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); + /* mute WaveOut */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); - snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); spin_lock(&chip->reg_lock); - /* first, remember current value: */ - status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); - /* stop playback */ + status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); - + /* FIXME: clear interrupts or what??? */ snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); spin_unlock(&chip->reg_lock); @@ -1128,7 +951,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), - AZF_PLAYBACK); + 0); spin_lock(&chip->reg_lock); #ifdef WIN9X @@ -1155,35 +978,30 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) DMA_SOMETHING_ELSE); #endif spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1); /* now unmute WaveOut */ - if (!previously_muted) - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); + chip->is_playing = 1; snd_azf3328_dbgplay("STARTED PLAYBACK\n"); break; case SNDRV_PCM_TRIGGER_RESUME: snd_azf3328_dbgplay("RESUME PLAYBACK\n"); /* resume playback if we were active */ - spin_lock(&chip->reg_lock); - if (chip->audio_stream[AZF_PLAYBACK].running) + if (chip->is_playing) snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); - spin_unlock(&chip->reg_lock); break; case SNDRV_PCM_TRIGGER_STOP: snd_azf3328_dbgplay("STOP PLAYBACK\n"); - /* mute WaveOut (avoid clicking during setup) */ - previously_muted = - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); + /* mute WaveOut */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); spin_lock(&chip->reg_lock); - /* first, remember current value: */ + /* stop playback */ status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); - /* stop playback */ status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); @@ -1195,12 +1013,10 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) status1 &= ~DMA_PLAY_SOMETHING1; snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); - + /* now unmute WaveOut */ - if (!previously_muted) - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); - + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); + chip->is_playing = 0; snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); break; case SNDRV_PCM_TRIGGER_SUSPEND: @@ -1219,7 +1035,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) printk(KERN_ERR "FIXME: unknown trigger mode!\n"); return -EINVAL; } - + snd_azf3328_dbgcallleave(); return result; } @@ -1241,19 +1057,17 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) snd_azf3328_dbgplay("START CAPTURE\n"); - snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, + snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); spin_lock(&chip->reg_lock); - /* first, remember current value: */ - status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); - /* stop recording */ + status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); - + /* FIXME: clear interrupts or what??? */ snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); spin_unlock(&chip->reg_lock); @@ -1261,7 +1075,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), - AZF_CAPTURE); + 1); spin_lock(&chip->reg_lock); #ifdef WIN9X @@ -1288,27 +1102,24 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) DMA_SOMETHING_ELSE); #endif spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_CAPTURE, 1); + chip->is_recording = 1; snd_azf3328_dbgplay("STARTED CAPTURE\n"); break; case SNDRV_PCM_TRIGGER_RESUME: snd_azf3328_dbgplay("RESUME CAPTURE\n"); /* resume recording if we were active */ - spin_lock(&chip->reg_lock); - if (chip->audio_stream[AZF_CAPTURE].running) + if (chip->is_recording) snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); - spin_unlock(&chip->reg_lock); break; case SNDRV_PCM_TRIGGER_STOP: snd_azf3328_dbgplay("STOP CAPTURE\n"); spin_lock(&chip->reg_lock); - /* first, remember current value: */ + /* stop recording */ status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); - /* stop recording */ status1 &= ~DMA_RESUME; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); @@ -1318,8 +1129,8 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) status1 &= ~DMA_PLAY_SOMETHING1; snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_CAPTURE, 0); - + + chip->is_recording = 0; snd_azf3328_dbgplay("STOPPED CAPTURE\n"); break; case SNDRV_PCM_TRIGGER_SUSPEND: @@ -1338,7 +1149,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) printk(KERN_ERR "FIXME: unknown trigger mode!\n"); return -EINVAL; } - + snd_azf3328_dbgcallleave(); return result; } @@ -1351,11 +1162,11 @@ snd_azf3328_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frmres; #ifdef QUERY_HARDWARE - bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1); + bufptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_START_1); #else bufptr = substream->runtime->dma_addr; #endif - result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS); + result = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS); /* calculate offset */ result -= bufptr; @@ -1372,11 +1183,11 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frmres; #ifdef QUERY_HARDWARE - bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1); + bufptr = inl(chip->codec_port+IDX_IO_REC_DMA_START_1); #else bufptr = substream->runtime->dma_addr; #endif - result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS); + result = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS); /* calculate offset */ result -= bufptr; @@ -1385,241 +1196,27 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) return frmres; } -/******************************************************************/ - -#ifdef SUPPORT_GAMEPORT -static inline void -snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) -{ - snd_azf3328_io_reg_setb( - chip->game_io+IDX_GAME_HWCONFIG, - GAME_HWCFG_IRQ_ENABLE, - enable - ); -} - -static inline void -snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) -{ - snd_azf3328_io_reg_setb( - chip->game_io+IDX_GAME_HWCONFIG, - GAME_HWCFG_LEGACY_ADDRESS_ENABLE, - enable - ); -} - -static inline void -snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable) -{ - snd_azf3328_codec_reg_6AH_update( - chip, IO_6A_SOMETHING2_GAMEPORT, enable - ); -} - -static inline void -snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) -{ - /* - * skeleton handler only - * (we do not want axis reading in interrupt handler - too much load!) - */ - snd_azf3328_dbggame("gameport irq\n"); - - /* this should ACK the gameport IRQ properly, hopefully. */ - snd_azf3328_game_inw(chip, IDX_GAME_AXIS_VALUE); -} - -static int -snd_azf3328_gameport_open(struct gameport *gameport, int mode) -{ - struct snd_azf3328 *chip = gameport_get_port_data(gameport); - int res; - - snd_azf3328_dbggame("gameport_open, mode %d\n", mode); - switch (mode) { - case GAMEPORT_MODE_COOKED: - case GAMEPORT_MODE_RAW: - res = 0; - break; - default: - res = -1; - break; - } - - snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); - - return res; -} - -static void -snd_azf3328_gameport_close(struct gameport *gameport) -{ - struct snd_azf3328 *chip = gameport_get_port_data(gameport); - - snd_azf3328_dbggame("gameport_close\n"); - snd_azf3328_gameport_axis_circuit_enable(chip, 0); -} - -static int -snd_azf3328_gameport_cooked_read(struct gameport *gameport, - int *axes, - int *buttons -) -{ - struct snd_azf3328 *chip = gameport_get_port_data(gameport); - int i; - u8 val; - unsigned long flags; - - snd_assert(chip, return 0); - - spin_lock_irqsave(&chip->reg_lock, flags); - val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE); - *buttons = (~(val) >> 4) & 0xf; - - /* ok, this one is a bit dirty: cooked_read is being polled by a timer, - * thus we're atomic and cannot actively wait in here - * (which would be useful for us since it probably would be better - * to trigger a measurement in here, then wait a short amount of - * time until it's finished, then read values of _this_ measurement). - * - * Thus we simply resort to reading values if they're available already - * and trigger the next measurement. - */ - - val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); - if (val & GAME_AXES_SAMPLING_READY) { - for (i = 0; i < 4; ++i) { - /* configure the axis to read */ - val = (i << 4) | 0x0f; - snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); - - chip->axes[i] = snd_azf3328_game_inw( - chip, IDX_GAME_AXIS_VALUE - ); - } - } - - /* trigger next axes sampling, to be evaluated the next time we - * enter this function */ - - /* for some very, very strange reason we cannot enable - * Measurement Ready monitoring for all axes here, - * at least not when only one joystick connected */ - val = 0x03; /* we're able to monitor axes 1 and 2 only */ - snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); - - snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - for (i = 0; i < 4; i++) { - axes[i] = chip->axes[i]; - if (axes[i] == 0xffff) - axes[i] = -1; - } - - snd_azf3328_dbggame("cooked_read: axes %d %d %d %d buttons %d\n", - axes[0], axes[1], axes[2], axes[3], *buttons - ); - - return 0; -} - -static int __devinit -snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) -{ - struct gameport *gp; - - chip->gameport = gp = gameport_allocate_port(); - if (!gp) { - printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n"); - return -ENOMEM; - } - - gameport_set_name(gp, "AZF3328 Gameport"); - gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); - gameport_set_dev_parent(gp, &chip->pci->dev); - gp->io = chip->game_io; - gameport_set_port_data(gp, chip); - - gp->open = snd_azf3328_gameport_open; - gp->close = snd_azf3328_gameport_close; - gp->fuzz = 16; /* seems ok */ - gp->cooked_read = snd_azf3328_gameport_cooked_read; - - /* DISABLE legacy address: we don't need it! */ - snd_azf3328_gameport_legacy_address_enable(chip, 0); - - snd_azf3328_gameport_axis_circuit_enable(chip, 0); - - gameport_register_port(chip->gameport); - - return 0; -} - -static void -snd_azf3328_gameport_free(struct snd_azf3328 *chip) -{ - if (chip->gameport) { - gameport_unregister_port(chip->gameport); - chip->gameport = NULL; - } - snd_azf3328_gameport_irq_enable(chip, 0); -} -#else -static inline int -snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) { return -ENOSYS; } -static inline void -snd_azf3328_gameport_free(struct snd_azf3328 *chip) { } -static inline void -snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) -{ - printk(KERN_WARNING "huh, game port IRQ occurred!?\n"); -} -#endif /* SUPPORT_GAMEPORT */ - -/******************************************************************/ - -static inline void -snd_azf3328_irq_log_unknown_type(u8 which) -{ - snd_azf3328_dbgplay( - "azt3328: unknown IRQ type (%x) occurred, please report!\n", - which - ); -} - static irqreturn_t snd_azf3328_interrupt(int irq, void *dev_id) { struct snd_azf3328 *chip = dev_id; u8 status, which; -#if DEBUG_PLAY_REC static unsigned long irq_count; -#endif status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); /* fast path out, to ease interrupt sharing */ - if (!(status & - (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) - )) + if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_TIMER))) return IRQ_NONE; /* must be interrupt for another device */ - snd_azf3328_dbgplay( - "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, " - "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", - irq_count++ /* debug-only */, - snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), - snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), - status - ); - + snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", + irq_count, + snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), + snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), + status); + if (status & IRQ_TIMER) { - /* snd_azf3328_dbgplay("timer %ld\n", - snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) - & TIMER_VALUE_MASK - ); */ + /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ if (chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); /* ACK timer */ @@ -1635,20 +1232,15 @@ snd_azf3328_interrupt(int irq, void *dev_id) snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); spin_unlock(&chip->reg_lock); - if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) { - snd_pcm_period_elapsed( - chip->audio_stream[AZF_PLAYBACK].substream - ); + if (chip->pcm && chip->playback_substream) { + snd_pcm_period_elapsed(chip->playback_substream); snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", which, - snd_azf3328_codec_inl( - chip, IDX_IO_PLAY_DMA_CURRPOS - ) - ); + inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); } else - printk(KERN_WARNING "azt3328: irq handler problem!\n"); + snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); if (which & IRQ_PLAY_SOMETHING) - snd_azf3328_irq_log_unknown_type(which); + snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); } if (status & IRQ_RECORDING) { spin_lock(&chip->reg_lock); @@ -1657,23 +1249,16 @@ snd_azf3328_interrupt(int irq, void *dev_id) snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); spin_unlock(&chip->reg_lock); - if (chip->pcm && chip->audio_stream[AZF_CAPTURE].substream) { - snd_pcm_period_elapsed( - chip->audio_stream[AZF_CAPTURE].substream - ); + if (chip->pcm && chip->capture_substream) { + snd_pcm_period_elapsed(chip->capture_substream); snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", which, - snd_azf3328_codec_inl( - chip, IDX_IO_REC_DMA_CURRPOS - ) - ); + inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); } else - printk(KERN_WARNING "azt3328: irq handler problem!\n"); + snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); if (which & IRQ_REC_SOMETHING) - snd_azf3328_irq_log_unknown_type(which); + snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); } - if (status & IRQ_GAMEPORT) - snd_azf3328_gameport_interrupt(chip); /* MPU401 has less critical IRQ requirements * than timer and playback/recording, right? */ if (status & IRQ_MPU401) { @@ -1683,6 +1268,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) * If so, then I don't know how... */ snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); } + irq_count++; return IRQ_HANDLED; } @@ -1701,8 +1287,8 @@ static const struct snd_pcm_hardware snd_azf3328_playback = .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT, - .rate_min = AZF_FREQ_4000, - .rate_max = AZF_FREQ_66200, + .rate_min = 4000, + .rate_max = 66200, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, @@ -1729,8 +1315,8 @@ static const struct snd_pcm_hardware snd_azf3328_capture = .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT, - .rate_min = AZF_FREQ_4000, - .rate_max = AZF_FREQ_66200, + .rate_min = 4000, + .rate_max = 66200, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, @@ -1743,24 +1329,10 @@ static const struct snd_pcm_hardware snd_azf3328_capture = static unsigned int snd_azf3328_fixed_rates[] = { - AZF_FREQ_4000, - AZF_FREQ_4800, - AZF_FREQ_5512, - AZF_FREQ_6620, - AZF_FREQ_8000, - AZF_FREQ_9600, - AZF_FREQ_11025, - AZF_FREQ_13240, - AZF_FREQ_16000, - AZF_FREQ_22050, - AZF_FREQ_32000, - AZF_FREQ_44100, - AZF_FREQ_48000, - AZF_FREQ_66200 -}; - + 4000, 4800, 5512, 6620, 8000, 9600, 11025, 13240, 16000, 22050, 32000, + 44100, 48000, 66200 }; static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { - .count = ARRAY_SIZE(snd_azf3328_fixed_rates), + .count = ARRAY_SIZE(snd_azf3328_fixed_rates), .list = snd_azf3328_fixed_rates, .mask = 0, }; @@ -1774,7 +1346,7 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_PLAYBACK].substream = substream; + chip->playback_substream = substream; runtime->hw = snd_azf3328_playback; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_azf3328_hw_constraints_rates); @@ -1789,7 +1361,7 @@ snd_azf3328_capture_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_CAPTURE].substream = substream; + chip->capture_substream = substream; runtime->hw = snd_azf3328_capture; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_azf3328_hw_constraints_rates); @@ -1803,7 +1375,7 @@ snd_azf3328_playback_close(struct snd_pcm_substream *substream) struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_PLAYBACK].substream = NULL; + chip->playback_substream = NULL; snd_azf3328_dbgcallleave(); return 0; } @@ -1814,7 +1386,7 @@ snd_azf3328_capture_close(struct snd_pcm_substream *substream) struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_CAPTURE].substream = NULL; + chip->capture_substream = NULL; snd_azf3328_dbgcallleave(); return 0; } @@ -1869,8 +1441,102 @@ snd_azf3328_pcm(struct snd_azf3328 *chip, int device) /******************************************************************/ -/*** NOTE: the physical timer resolution actually is 1024000 ticks per second - *** (probably derived from main crystal via a divider of 24), +#ifdef SUPPORT_JOYSTICK +static int __devinit +snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) +{ + struct gameport *gp; + struct resource *r; + + if (!joystick[dev]) + return -ENODEV; + + if (!(r = request_region(0x200, 8, "AZF3328 gameport"))) { + printk(KERN_WARNING "azt3328: cannot reserve joystick ports\n"); + return -EBUSY; + } + + chip->gameport = gp = gameport_allocate_port(); + if (!gp) { + printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n"); + release_and_free_resource(r); + return -ENOMEM; + } + + gameport_set_name(gp, "AZF3328 Gameport"); + gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); + gameport_set_dev_parent(gp, &chip->pci->dev); + gp->io = 0x200; + gameport_set_port_data(gp, r); + + snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY); + + gameport_register_port(chip->gameport); + + return 0; +} + +static void +snd_azf3328_free_joystick(struct snd_azf3328 *chip) +{ + if (chip->gameport) { + struct resource *r = gameport_get_port_data(chip->gameport); + + gameport_unregister_port(chip->gameport); + chip->gameport = NULL; + /* disable gameport */ + snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); + release_and_free_resource(r); + } +} +#else +static inline int +snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) { return -ENOSYS; } +static inline void +snd_azf3328_free_joystick(struct snd_azf3328 *chip) { } +#endif + +/******************************************************************/ + +static int +snd_azf3328_free(struct snd_azf3328 *chip) +{ + if (chip->irq < 0) + goto __end_hw; + + /* reset (close) mixer */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */ + snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); + + /* interrupt setup - mask everything (FIXME!) */ + /* well, at least we know how to disable the timer IRQ */ + snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); + + if (chip->irq >= 0) + synchronize_irq(chip->irq); +__end_hw: + snd_azf3328_free_joystick(chip); + if (chip->irq >= 0) + free_irq(chip->irq, chip); + pci_release_regions(chip->pci); + pci_disable_device(chip->pci); + + kfree(chip); + return 0; +} + +static int +snd_azf3328_dev_free(struct snd_device *device) +{ + struct snd_azf3328 *chip = device->device_data; + return snd_azf3328_free(chip); +} + +/******************************************************************/ + +/*** NOTE: the physical timer resolution actually is 1024000 ticks per second, *** but announcing those attributes to user-space would make programs *** configure the timer to a 1 tick value, resulting in an absolutely fatal *** timer IRQ storm. @@ -1898,7 +1564,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) delay = 49; /* minimum time is 49 ticks */ } snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); - delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; + delay |= TIMER_ENABLE_COUNTDOWN | TIMER_ENABLE_IRQ; spin_lock_irqsave(&chip->reg_lock, flags); snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -1916,7 +1582,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer) chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->reg_lock, flags); /* disable timer countdown and interrupt */ - /* FIXME: should we write TIMER_IRQ_ACK here? */ + /* FIXME: should we write TIMER_ACK_IRQ here? */ snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_azf3328_dbgcallleave(); @@ -1960,10 +1626,9 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) snd_azf3328_timer_hw.resolution *= seqtimer_scaling; snd_azf3328_timer_hw.ticks /= seqtimer_scaling; - - err = snd_timer_new(chip->card, "AZF3328", &tid, &timer); - if (err < 0) + if ((err = snd_timer_new(chip->card, "AZF3328", &tid, &timer)) < 0) { goto out; + } strcpy(timer->name, "AZF3328 timer"); timer->private_data = chip; @@ -1971,8 +1636,6 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) chip->timer = timer; - snd_azf3328_timer_stop(timer); - err = 0; out: @@ -1982,44 +1645,10 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) /******************************************************************/ -static int -snd_azf3328_free(struct snd_azf3328 *chip) -{ - if (chip->irq < 0) - goto __end_hw; - - /* reset (close) mixer: - * first mute master volume, then reset - */ - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); - snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); - - snd_azf3328_timer_stop(chip->timer); - snd_azf3328_gameport_free(chip); - - if (chip->irq >= 0) - synchronize_irq(chip->irq); -__end_hw: - if (chip->irq >= 0) - free_irq(chip->irq, chip); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - - kfree(chip); - return 0; -} - -static int -snd_azf3328_dev_free(struct snd_device *device) -{ - struct snd_azf3328 *chip = device->device_data; - return snd_azf3328_free(chip); -} - #if 0 /* check whether a bit can be modified */ static void -snd_azf3328_test_bit(unsigned unsigned reg, int bit) +snd_azf3328_test_bit(unsigned int reg, int bit) { unsigned char val, valoff, valon; @@ -2030,74 +1659,42 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit) outb(val|(1 << bit), reg); valon = inb(reg); - + outb(val, reg); - printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", - reg, bit, val, valoff, valon - ); + printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", reg, bit, val, valoff, valon); } #endif -static inline void +#if DEBUG_MISC +static void snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) { -#if DEBUG_MISC u16 tmp; - snd_azf3328_dbgmisc( - "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " - "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", - chip->codec_io, chip->game_io, chip->mpu_io, - chip->opl3_io, chip->mixer_io, chip->irq - ); - - snd_azf3328_dbgmisc("game %02x %02x %02x %02x %02x %02x\n", - snd_azf3328_game_inb(chip, 0), - snd_azf3328_game_inb(chip, 1), - snd_azf3328_game_inb(chip, 2), - snd_azf3328_game_inb(chip, 3), - snd_azf3328_game_inb(chip, 4), - snd_azf3328_game_inb(chip, 5) - ); - - for (tmp = 0; tmp < 0x07; tmp += 1) - snd_azf3328_dbgmisc("mpu_io 0x%04x\n", inb(chip->mpu_io + tmp)); - - for (tmp = 0; tmp <= 0x07; tmp += 1) - snd_azf3328_dbgmisc("0x%02x: game200 0x%04x, game208 0x%04x\n", - tmp, inb(0x200 + tmp), inb(0x208 + tmp)); - - for (tmp = 0; tmp <= 0x01; tmp += 1) - snd_azf3328_dbgmisc( - "0x%02x: mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, " - "mpu330 0x%04x opl388 0x%04x opl38c 0x%04x\n", - tmp, - inb(0x300 + tmp), - inb(0x310 + tmp), - inb(0x320 + tmp), - inb(0x330 + tmp), - inb(0x388 + tmp), - inb(0x38c + tmp) - ); + snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq); + + snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_inb(chip, 0), snd_azf3328_io2_inb(chip, 1), snd_azf3328_io2_inb(chip, 2), snd_azf3328_io2_inb(chip, 3), snd_azf3328_io2_inb(chip, 4), snd_azf3328_io2_inb(chip, 5)); + + for (tmp=0; tmp <= 0x01; tmp += 1) + snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) - snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", - tmp, snd_azf3328_codec_inw(chip, tmp) - ); + snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", tmp, snd_azf3328_codec_inw(chip, tmp)); for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) - snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", - tmp, snd_azf3328_mixer_inw(chip, tmp) - ); -#endif /* DEBUG_MISC */ + snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", tmp, snd_azf3328_mixer_inw(chip, tmp)); } +#else +static inline void +snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) {} +#endif static int __devinit snd_azf3328_create(struct snd_card *card, - struct pci_dev *pci, - unsigned long device_type, - struct snd_azf3328 **rchip) + struct pci_dev *pci, + unsigned long device_type, + struct snd_azf3328 ** rchip) { struct snd_azf3328 *chip; int err; @@ -2108,8 +1705,7 @@ snd_azf3328_create(struct snd_card *card, *rchip = NULL; - err = pci_enable_device(pci); - if (err < 0) + if ((err = pci_enable_device(pci)) < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -2125,25 +1721,20 @@ snd_azf3328_create(struct snd_card *card, /* check if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) { - snd_printk(KERN_ERR "architecture does not support " - "24bit PCI busmaster DMA\n" - ); + snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); err = -ENXIO; goto out_err; } - err = pci_request_regions(pci, "Aztech AZF3328"); - if (err < 0) + if ((err = pci_request_regions(pci, "Aztech AZF3328")) < 0) { goto out_err; + } - chip->codec_io = pci_resource_start(pci, 0); - chip->game_io = pci_resource_start(pci, 1); - chip->mpu_io = pci_resource_start(pci, 2); - chip->opl3_io = pci_resource_start(pci, 3); - chip->mixer_io = pci_resource_start(pci, 4); - - chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00; - chip->audio_stream[AZF_CAPTURE].portbase = chip->codec_io + 0x20; + chip->codec_port = pci_resource_start(pci, 0); + chip->io2_port = pci_resource_start(pci, 1); + chip->mpu_port = pci_resource_start(pci, 2); + chip->synth_port = pci_resource_start(pci, 3); + chip->mixer_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_azf3328_interrupt, IRQF_SHARED, card->shortname, chip)) { @@ -2156,29 +1747,29 @@ snd_azf3328_create(struct snd_card *card, synchronize_irq(chip->irq); snd_azf3328_debug_show_ports(chip); - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { goto out_err; + } /* create mixer interface & switches */ - err = snd_azf3328_mixer_new(chip); - if (err < 0) + if ((err = snd_azf3328_mixer_new(chip)) < 0) goto out_err; - /* shutdown codecs to save power */ - /* have snd_azf3328_codec_activity() act properly */ - chip->audio_stream[AZF_PLAYBACK].running = 1; - snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); +#if 0 + /* set very low bitrate to reduce noise and power consumption? */ + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, 5512, 8, 1); +#endif /* standard chip init stuff */ - /* default IRQ init value */ + /* default IRQ init value */ tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; spin_lock_irq(&chip->reg_lock); snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); + snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); /* disable timer */ spin_unlock_irq(&chip->reg_lock); snd_card_set_dev(card, &pci->dev); @@ -2214,61 +1805,52 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return -ENOENT; } - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0 ); if (card == NULL) return -ENOMEM; strcpy(card->driver, "AZF3328"); strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); - err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip); - if (err < 0) + if ((err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip)) < 0) { goto out_err; + } card->private_data = chip; - err = snd_mpu401_uart_new( - card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED, - pci->irq, 0, &chip->rmidi - ); - if (err < 0) { - snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", - chip->mpu_io - ); + if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, + chip->mpu_port, MPU401_INFO_INTEGRATED, + pci->irq, 0, &chip->rmidi)) < 0) { + snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); goto out_err; } - err = snd_azf3328_timer(chip, 0); - if (err < 0) + if ((err = snd_azf3328_timer(chip, 0)) < 0) { goto out_err; + } - err = snd_azf3328_pcm(chip, 0); - if (err < 0) + if ((err = snd_azf3328_pcm(chip, 0)) < 0) { goto out_err; + } - if (snd_opl3_create(card, chip->opl3_io, chip->opl3_io+2, + if (snd_opl3_create(card, chip->synth_port, chip->synth_port+2, OPL3_HW_AUTO, 1, &opl3) < 0) { snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", - chip->opl3_io, chip->opl3_io+2 - ); + chip->synth_port, chip->synth_port+2 ); } else { - /* need to use IDs 1, 2 since ID 0 is snd_azf3328_timer above */ - err = snd_opl3_timer_new(opl3, 1, 2); - if (err < 0) - goto out_err; - err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); - if (err < 0) + if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { goto out_err; + } } opl3->private_data = chip; sprintf(card->longname, "%s at 0x%lx, irq %i", - card->shortname, chip->codec_io, chip->irq); + card->shortname, chip->codec_port, chip->irq); - err = snd_card_register(card); - if (err < 0) + if ((err = snd_card_register(card)) < 0) { goto out_err; + } #ifdef MODULE printk( @@ -2279,18 +1861,19 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) 1024000 / seqtimer_scaling, seqtimer_scaling); #endif - snd_azf3328_gameport(chip, dev); + if (snd_azf3328_config_joystick(chip, dev) < 0) + snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); pci_set_drvdata(pci, card); dev++; err = 0; goto out; - + out_err: - snd_printk(KERN_ERR "azf3328: something failed, exiting\n"); snd_card_free(card); - + out: snd_azf3328_dbgcallleave(); return err; @@ -2311,31 +1894,27 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct snd_azf3328 *chip = card->private_data; - unsigned reg; + int reg; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - + snd_pcm_suspend_all(chip->pcm); - for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) - chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) + chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2); /* make sure to disable master volume etc. to prevent looping sound */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); - - for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) - chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2); - - /* manually store the one currently relevant write-only reg, too */ - chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH; - - for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) - chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) - chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) - chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2); + + for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) + chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) + chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) + chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) + chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2); pci_disable_device(pci); pci_save_state(pci); @@ -2348,7 +1927,7 @@ snd_azf3328_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct snd_azf3328 *chip = card->private_data; - unsigned reg; + int reg; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); @@ -2360,21 +1939,23 @@ snd_azf3328_resume(struct pci_dev *pci) } pci_set_master(pci); - for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) - outw(chip->saved_regs_game[reg], chip->game_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) - outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) - outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) - outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) - outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) + outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) + outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) + outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) + outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) + outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } -#endif /* CONFIG_PM */ +#endif + + static struct pci_driver driver = { diff --git a/trunk/sound/pci/azt3328.h b/trunk/sound/pci/azt3328.h index 7e3e8942d073..679fa992e2bc 100644 --- a/trunk/sound/pci/azt3328.h +++ b/trunk/sound/pci/azt3328.h @@ -1,8 +1,7 @@ #ifndef __SOUND_AZT3328_H #define __SOUND_AZT3328_H -/* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 - * "WRITE_ONLY" == register does not indicate actual bit values */ +/* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 */ /*** main I/O area port indices ***/ /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ @@ -55,10 +54,7 @@ #define SOUNDFORMAT_XTAL1 0x00 #define SOUNDFORMAT_XTAL2 0x01 /* all _SUSPECTED_ values are not used by Windows drivers, so we don't - * have any hard facts, only rough measurements. - * All we know is that the crystal used on the board has 24.576MHz, - * like many soundcards (which results in the frequencies below when - * using certain divider values selected by the values below) */ + * have any hard facts, only rough measurements */ #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 @@ -76,26 +72,6 @@ #define SOUNDFORMAT_FLAG_16BIT 0x0010 #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 -/* define frequency helpers, for maximum value safety */ -enum azf_freq_t { -#define AZF_FREQ(rate) AZF_FREQ_##rate = rate - AZF_FREQ(4000), - AZF_FREQ(4800), - AZF_FREQ(5512), - AZF_FREQ(6620), - AZF_FREQ(8000), - AZF_FREQ(9600), - AZF_FREQ(11025), - AZF_FREQ(13240), - AZF_FREQ(16000), - AZF_FREQ(22050), - AZF_FREQ(32000), - AZF_FREQ(44100), - AZF_FREQ(48000), - AZF_FREQ(66200), -#undef AZF_FREQ -} AZF_FREQUENCIES; - /** recording area (see also: playback bit flag definitions) **/ #define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ #define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ @@ -121,171 +97,40 @@ enum azf_freq_t { /** DirectX timer, main interrupt area (FIXME: and something else?) **/ #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ - /* timer countdown value; triggers IRQ when timer is finished */ - #define TIMER_VALUE_MASK 0x000fffffUL - /* activate timer countdown */ - #define TIMER_COUNTDOWN_ENABLE 0x01000000UL - /* trigger timer IRQ on zero transition */ - #define TIMER_IRQ_ENABLE 0x02000000UL - /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) - * had 0x0020 set upon IRQ handler */ - #define TIMER_IRQ_ACK 0x04000000UL + #define TIMER_VALUE_MASK 0x000fffffUL /* timer countdown value; triggers IRQ when timer is finished */ + #define TIMER_ENABLE_COUNTDOWN 0x01000000UL /* activate the timer countdown */ + #define TIMER_ENABLE_IRQ 0x02000000UL /* trigger timer IRQ on zero transition */ + #define TIMER_ACK_IRQ 0x04000000UL /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) had 0x0020 set upon IRQ handler */ #define IDX_IO_IRQSTATUS 0x64 - /* some IRQ bit in here might also be used to signal a power-management timer - * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing). - * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which - * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */ - - #define IRQ_PLAYBACK 0x0001 - #define IRQ_RECORDING 0x0002 - #define IRQ_UNKNOWN1 0x0004 /* most probably I2S port */ - #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ - #define IRQ_MPU401 0x0010 - #define IRQ_TIMER 0x0020 /* DirectX timer */ - #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */ - #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */ + #define IRQ_PLAYBACK 0x0001 + #define IRQ_RECORDING 0x0002 + #define IRQ_MPU401 0x0010 + #define IRQ_TIMER 0x0020 /* DirectX timer */ + #define IRQ_UNKNOWN1 0x0040 /* probably unused, or possibly I2S port? or gameport IRQ? */ + #define IRQ_UNKNOWN2 0x0080 /* probably unused, or possibly I2S port? or gameport IRQ? */ #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ - /* this is set to e.g. 0x3ff or 0x300, and writable; - * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ -#define IDX_IO_SOME_VALUE 0x68 - #define IO_68_RANDOM_TOGGLE1 0x0100 /* toggles randomly */ - #define IO_68_RANDOM_TOGGLE2 0x0200 /* toggles randomly */ - /* umm, nope, behaviour of these bits changes depending on what we wrote - * to 0x6b!! - * And they change upon playback/stop, too: - * Writing a value to 0x68 will display this exact value during playback, - * too but when stopped it can fall back to a rather different - * seemingly random value). Hmm, possibly this is a register which - * has a remote shadow which needs proper device supply which only exists - * in case playback is active? Or is this driver-induced? - */ - -/* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); - * actually inhibits PCM playback!!! maybe power management??: */ -#define IDX_IO_6AH 0x6A /* WRITE_ONLY! */ - /* bit 5: enabling this will activate permanent counting of bytes 2/3 - * at gameport I/O (0xb402/3) (equal values each) and cause - * gameport legacy I/O at 0x0200 to be _DISABLED_! - * Is this Digital Enhanced Game Port Enable??? Or maybe it's Testmode - * for Enhanced Digital Gameport (see 4D Wave DX card): */ - #define IO_6A_SOMETHING1_GAMEPORT 0x0020 - /* bit 8; sure, this _pauses_ playback (later resumes at same spot!), - * but what the heck is this really about??: */ - #define IO_6A_PAUSE_PLAYBACK_BIT8 0x0100 - /* bit 9; sure, this _pauses_ playback (later resumes at same spot!), - * but what the heck is this really about??: */ - #define IO_6A_PAUSE_PLAYBACK_BIT9 0x0200 - /* BIT8 and BIT9 are _NOT_ able to affect OPL3 MIDI playback, - * thus it suggests influence on PCM only!! - * However OTOH there seems to be no bit anywhere around here - * which is able to disable OPL3... */ - /* bit 10: enabling this actually changes values at legacy gameport - * I/O address (0x200); is this enabling of the Digital Enhanced Game Port??? - * Or maybe this simply switches off the NE558 circuit, since enabling this - * still lets us evaluate button states, but not axis states */ - #define IO_6A_SOMETHING2_GAMEPORT 0x0400 - /* writing 0x0300: causes quite some crackling during - * PC activity such as switching windows (PCI traffic?? - * --> FIFO/timing settings???) */ - /* writing 0x0100 plus/or 0x0200 inhibits playback */ - /* since the Windows .INF file has Flag_Enable_JoyStick and - * Flag_Enable_SB_DOS_Emulation directly together, it stands to reason - * that some other bit in this same register might be responsible - * for SB DOS Emulation activation (note that the file did NOT define - * a switch for OPL3!) */ -#define IDX_IO_6CH 0x6C /* unknown; fully read-writable */ -#define IDX_IO_6EH 0x6E - /* writing 0xffff returns 0x83fe (or 0x03fe only). - * writing 0x83 (and only 0x83!!) to 0x6f will cause 0x6c to switch - * from 0000 to ffff. */ +#define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ +#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */ + #define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */ +#define IDX_IO_6CH 0x6C +#define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ +/* further I/O indices not saved/restored, so probably not used */ -/* further I/O indices not saved/restored and not readable after writing, - * so probably not used */ - -/*** Gameport area port indices ***/ +/*** I/O 2 area port indices ***/ /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ -#define AZF_IO_SIZE_GAME 0x08 -#define AZF_IO_SIZE_GAME_PM 0x06 - -enum { - AZF_GAME_LEGACY_IO_PORT = 0x200 -} AZF_GAME_CONFIGS; - -#define IDX_GAME_LEGACY_COMPATIBLE 0x00 - /* in some operation mode, writing anything to this port - * triggers an interrupt: - * yup, that's in case IDX_GAME_01H has one of the - * axis measurement bits enabled - * (and of course one needs to have GAME_HWCFG_IRQ_ENABLE, too) */ - -#define IDX_GAME_AXES_CONFIG 0x01 - /* NOTE: layout of this register awfully similar (read: "identical??") - * to AD1815JS.pdf (p.29) */ - - /* enables axis 1 (X axis) measurement: */ - #define GAME_AXES_ENABLE_1 0x01 - /* enables axis 2 (Y axis) measurement: */ - #define GAME_AXES_ENABLE_2 0x02 - /* enables axis 3 (X axis) measurement: */ - #define GAME_AXES_ENABLE_3 0x04 - /* enables axis 4 (Y axis) measurement: */ - #define GAME_AXES_ENABLE_4 0x08 - /* selects the current axis to read the measured value of - * (at IDX_GAME_AXIS_VALUE): - * 00 = axis 1, 01 = axis 2, 10 = axis 3, 11 = axis 4: */ - #define GAME_AXES_READ_MASK 0x30 - /* enable to have the latch continuously accept ADC values - * (and continuously cause interrupts in case interrupts are enabled); - * AD1815JS.pdf says it's ~16ms interval there: */ - #define GAME_AXES_LATCH_ENABLE 0x40 - /* joystick data (measured axes) ready for reading: */ - #define GAME_AXES_SAMPLING_READY 0x80 - - /* NOTE: other card specs (SiS960 and others!) state that the - * game position latches should be frozen when reading and be freed - * (== reset?) after reading!!! - * Freezing most likely means disabling 0x40 (GAME_AXES_LATCH_ENABLE), - * but how to free the value? */ - /* An internet search for "gameport latch ADC" should provide some insight - * into how to program such a gameport system. */ - - /* writing 0xf0 to 01H once reset both counters to 0, in some special mode!? - * yup, in case 6AH 0x20 is not enabled - * (and 0x40 is sufficient, 0xf0 is not needed) */ - -#define IDX_GAME_AXIS_VALUE 0x02 - /* R: value of currently configured axis (word value!); - * W: trigger axis measurement */ - -#define IDX_GAME_HWCONFIG 0x04 - /* note: bits 4 to 7 are never set (== 0) when reading! - * --> reserved bits? */ - /* enables IRQ notification upon axes measurement ready: */ - #define GAME_HWCFG_IRQ_ENABLE 0x01 - /* these bits choose a different frequency for the - * internal ADC counter increment. - * hmm, seems to be a combo of bits: - * 00 --> standard frequency - * 10 --> 1/2 - * 01 --> 1/20 - * 11 --> 1/200: */ - #define GAME_HWCFG_ADC_COUNTER_FREQ_MASK 0x06 +#define AZF_IO_SIZE_IO2 0x08 +#define AZF_IO_SIZE_IO2_PM 0x06 - /* enable gameport legacy I/O address (0x200) - * I was unable to locate any configurability for a different address: */ - #define GAME_HWCFG_LEGACY_ADDRESS_ENABLE 0x08 +#define IDX_IO2_LEGACY_ADDR 0x04 + #define LEGACY_SOMETHING 0x01 /* OPL3?? */ + #define LEGACY_JOY 0x08 -/*** MPU401 ***/ #define AZF_IO_SIZE_MPU 0x04 #define AZF_IO_SIZE_MPU_PM 0x04 -/*** OPL3 synth ***/ -#define AZF_IO_SIZE_OPL3 0x08 -#define AZF_IO_SIZE_OPL3_PM 0x06 -/* hmm, given that a standard OPL3 has 4 registers only, - * there might be some enhanced functionality lurking at the end - * (especially since register 0x04 has a "non-empty" value 0xfe) */ +#define AZF_IO_SIZE_SYNTH 0x08 +#define AZF_IO_SIZE_SYNTH_PM 0x06 /*** mixer I/O area port indices ***/ /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) diff --git a/trunk/sound/pci/ca0106/ca0106_main.c b/trunk/sound/pci/ca0106/ca0106_main.c index 2f8b28add276..ecbe79b67e43 100644 --- a/trunk/sound/pci/ca0106/ca0106_main.c +++ b/trunk/sound/pci/ca0106/ca0106_main.c @@ -249,11 +249,6 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .name = "MSI K8N Diamond MB [SB0438]", .gpio_type = 2, .i2c_adc = 1 } , - /* Another MSI K8N Diamond MB, which has apprently a different SSID */ - { .serial = 0x10091102, - .name = "MSI K8N Diamond MB", - .gpio_type = 2, - .i2c_adc = 1 } , /* Shuttle XPC SD31P which has an onboard Creative Labs * Sound Blaster Live! 24-bit EAX * high-definition 7.1 audio processor". diff --git a/trunk/sound/pci/emu10k1/emu10k1_main.c b/trunk/sound/pci/emu10k1/emu10k1_main.c index 2f283ea6ad9a..548c9cc81af5 100644 --- a/trunk/sound/pci/emu10k1/emu10k1_main.c +++ b/trunk/sound/pci/emu10k1/emu10k1_main.c @@ -1528,7 +1528,6 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0151_chip = 1, .spk71 = 1, .spdif_bug = 1, - .invert_shared_spdif = 1, /* digital/analog switch swapped */ .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, diff --git a/trunk/sound/pci/emu10k1/emumixer.c b/trunk/sound/pci/emu10k1/emumixer.c index f34bbfb705f5..fd221209abcb 100644 --- a/trunk/sound/pci/emu10k1/emumixer.c +++ b/trunk/sound/pci/emu10k1/emumixer.c @@ -1578,10 +1578,6 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; else ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; - if (emu->card_capabilities->invert_shared_spdif) - ucontrol->value.integer.value[0] = - !ucontrol->value.integer.value[0]; - return 0; } @@ -1590,18 +1586,15 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, { unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int reg, val, sw; + unsigned int reg, val; int change = 0; - sw = ucontrol->value.integer.value[0]; - if (emu->card_capabilities->invert_shared_spdif) - sw = !sw; spin_lock_irqsave(&emu->reg_lock, flags); if ( emu->card_capabilities->i2c_adc) { /* Do nothing for Audigy 2 ZS Notebook */ } else if (emu->audigy) { reg = inl(emu->port + A_IOCFG); - val = sw ? A_IOCFG_GPOUT0 : 0; + val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; change = (reg & A_IOCFG_GPOUT0) != val; if (change) { reg &= ~A_IOCFG_GPOUT0; @@ -1610,7 +1603,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, } } reg = inl(emu->port + HCFG); - val = sw ? HCFG_GPOUT0 : 0; + val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; change |= (reg & HCFG_GPOUT0) != val; if (change) { reg &= ~HCFG_GPOUT0; diff --git a/trunk/sound/pci/emu10k1/memory.c b/trunk/sound/pci/emu10k1/memory.c index 7d379f5131fb..916c1dbcd53c 100644 --- a/trunk/sound/pci/emu10k1/memory.c +++ b/trunk/sound/pci/emu10k1/memory.c @@ -437,49 +437,43 @@ static void get_single_page_range(struct snd_util_memhdr *hdr, *last_page_ret = last_page; } -/* release allocated pages */ -static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page, - int last_page) -{ - int page; - - for (page = first_page; page <= last_page; page++) { - free_page((unsigned long)emu->page_ptr_table[page]); - emu->page_addr_table[page] = 0; - emu->page_ptr_table[page] = NULL; - } -} - /* * allocate kernel pages */ static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) { int page, first_page, last_page; + struct snd_dma_buffer dmab; emu10k1_memblk_init(blk); get_single_page_range(emu->memhdr, blk, &first_page, &last_page); /* allocate kernel pages */ for (page = first_page; page <= last_page; page++) { - /* first try to allocate from <4GB zone */ - struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 | - __GFP_NOWARN); - if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) { - if (p) - __free_page(p); - /* try to allocate from <16MB zone */ - p = alloc_page(GFP_ATOMIC | GFP_DMA | - __GFP_NORETRY | /* no OOM-killer */ - __GFP_NOWARN); - } - if (!p) { - __synth_free_pages(emu, first_page, page - 1); - return -ENOMEM; + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), + PAGE_SIZE, &dmab) < 0) + goto __fail; + if (! is_valid_page(emu, dmab.addr)) { + snd_dma_free_pages(&dmab); + goto __fail; } - emu->page_addr_table[page] = page_to_phys(p); - emu->page_ptr_table[page] = page_address(p); + emu->page_addr_table[page] = dmab.addr; + emu->page_ptr_table[page] = dmab.area; } return 0; + +__fail: + /* release allocated pages */ + last_page = page - 1; + for (page = first_page; page <= last_page; page++) { + dmab.area = emu->page_ptr_table[page]; + dmab.addr = emu->page_addr_table[page]; + dmab.bytes = PAGE_SIZE; + snd_dma_free_pages(&dmab); + emu->page_addr_table[page] = 0; + emu->page_ptr_table[page] = NULL; + } + + return -ENOMEM; } /* @@ -487,10 +481,23 @@ static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk */ static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) { - int first_page, last_page; + int page, first_page, last_page; + struct snd_dma_buffer dmab; get_single_page_range(emu->memhdr, blk, &first_page, &last_page); - __synth_free_pages(emu, first_page, last_page); + dmab.dev.type = SNDRV_DMA_TYPE_DEV; + dmab.dev.dev = snd_dma_pci_data(emu->pci); + for (page = first_page; page <= last_page; page++) { + if (emu->page_ptr_table[page] == NULL) + continue; + dmab.area = emu->page_ptr_table[page]; + dmab.addr = emu->page_addr_table[page]; + dmab.bytes = PAGE_SIZE; + snd_dma_free_pages(&dmab); + emu->page_addr_table[page] = 0; + emu->page_ptr_table[page] = NULL; + } + return 0; } diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index d2e1093f8e97..a6be6e3e8716 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -2335,7 +2335,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, if (!tbl) return -1; if (tbl->value >= 0 && tbl->value < num_configs) { -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT char tmp[10]; const char *model = NULL; if (models) diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index efc682888b31..dcd390b2bbaa 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -78,7 +78,7 @@ enum { #define AC_VERB_GET_BEEP_CONTROL 0x0f0a #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d -#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ +#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f /* f10-f1a: GPIO */ #define AC_VERB_GET_GPIO_DATA 0x0f15 diff --git a/trunk/sound/pci/hda/hda_hwdep.c b/trunk/sound/pci/hda/hda_hwdep.c index 6e18a422d993..2177d9af5334 100644 --- a/trunk/sound/pci/hda/hda_hwdep.c +++ b/trunk/sound/pci/hda/hda_hwdep.c @@ -88,7 +88,7 @@ static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) { -#ifndef CONFIG_SND_DEBUG_VERBOSE +#ifndef CONFIG_SND_DEBUG_DETECT if (!capable(CAP_SYS_RAWIO)) return -EACCES; #endif diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index 16715a68ba5e..b3a618eb42cd 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -55,7 +55,6 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; static char *model[SNDRV_CARDS]; static int position_fix[SNDRV_CARDS]; -static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int single_cmd; static int enable_msi; @@ -70,9 +69,7 @@ module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param_array(position_fix, int, NULL, 0444); MODULE_PARM_DESC(position_fix, "Fix DMA pointer " - "(0 = auto, 1 = none, 2 = POSBUF)."); -module_param_array(bdl_pos_adj, int, NULL, 0644); -MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); + "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); module_param_array(probe_mask, int, NULL, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); module_param(single_cmd, bool, 0444); @@ -200,10 +197,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define ATIHDMI_NUM_CAPTURE 0 #define ATIHDMI_NUM_PLAYBACK 1 -/* TERA has 4 playback and 3 capture */ -#define TERA_NUM_CAPTURE 3 -#define TERA_NUM_PLAYBACK 4 - /* this number is statically defined for simplicity */ #define MAX_AZX_DEV 16 @@ -266,8 +259,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* position fix mode */ enum { POS_FIX_AUTO, - POS_FIX_LPIB, + POS_FIX_NONE, POS_FIX_POSBUF, + POS_FIX_FIFO, }; /* Defines for ATI HD Audio support in SB450 south bridge */ @@ -291,7 +285,6 @@ struct azx_dev { u32 *posbuf; /* position buffer pointer */ unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int period_bytes; /* size of the period in bytes */ unsigned int frags; /* number for period in the play buffer */ unsigned int fifo_size; /* FIFO size */ @@ -308,11 +301,11 @@ struct azx_dev { */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ + /* for sanity check of position buffer */ + unsigned int period_intr; unsigned int opened :1; unsigned int running :1; - unsigned int irq_pending :1; - unsigned int irq_ignore :1; }; /* CORB/RIRB */ @@ -330,7 +323,6 @@ struct azx_rb { struct azx { struct snd_card *card; struct pci_dev *pci; - int dev_index; /* chip type specific */ int driver_type; @@ -374,13 +366,9 @@ struct azx { unsigned int single_cmd :1; unsigned int polling_mode :1; unsigned int msi :1; - unsigned int irq_pending_warned :1; /* for debugging */ unsigned int last_cmd; /* last issued command (to sync) */ - - /* for pending irqs */ - struct work_struct irq_pending_work; }; /* driver types */ @@ -393,7 +381,6 @@ enum { AZX_DRIVER_SIS, AZX_DRIVER_ULI, AZX_DRIVER_NVIDIA, - AZX_DRIVER_TERA, }; static char *driver_short_names[] __devinitdata = { @@ -405,7 +392,6 @@ static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_SIS] = "HDA SIS966", [AZX_DRIVER_ULI] = "HDA ULI M5461", [AZX_DRIVER_NVIDIA] = "HDA NVidia", - [AZX_DRIVER_TERA] = "HDA Teradici", }; /* @@ -440,6 +426,11 @@ static char *driver_short_names[] __devinitdata = { /* for pcm support */ #define get_azx_dev(substream) (substream->runtime->private_data) +/* Get the upper 32bit of the given dma_addr_t + * Compiler should optimize and eliminate the code if dma_addr_t is 32bit + */ +#define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0) + static int azx_acquire_irq(struct azx *chip, int do_disconnect); /* @@ -470,7 +461,7 @@ static void azx_init_cmd_io(struct azx *chip) chip->corb.addr = chip->rb.addr; chip->corb.buf = (u32 *)chip->rb.area; azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); - azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr)); + azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr)); /* set the corb size to 256 entries (ULI requires explicitly) */ azx_writeb(chip, CORBSIZE, 0x02); @@ -485,7 +476,7 @@ static void azx_init_cmd_io(struct azx *chip) chip->rirb.addr = chip->rb.addr + 2048; chip->rirb.buf = (u32 *)(chip->rb.area + 2048); azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); - azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); + azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr)); /* set the rirb size to 256 entries (ULI requires explicitly) */ azx_writeb(chip, RIRBSIZE, 0x02); @@ -856,7 +847,7 @@ static void azx_init_chip(struct azx *chip) /* program the position buffer */ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr)); + azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); chip->initialized = 1; } @@ -917,8 +908,6 @@ static void azx_init_pci(struct azx *chip) } -static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); - /* * interrupt handler */ @@ -941,23 +930,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) azx_dev = &chip->azx_dev[i]; if (status & azx_dev->sd_int_sta_mask) { azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); - if (!azx_dev->substream || !azx_dev->running) - continue; - /* ignore the first dummy IRQ (due to pos_adj) */ - if (azx_dev->irq_ignore) { - azx_dev->irq_ignore = 0; - continue; - } - /* check whether this IRQ is really acceptable */ - if (azx_position_ok(chip, azx_dev)) { - azx_dev->irq_pending = 0; + if (azx_dev->substream && azx_dev->running) { + azx_dev->period_intr++; spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(azx_dev->substream); spin_lock(&chip->reg_lock); - } else { - /* bogus IRQ, process it later */ - azx_dev->irq_pending = 1; - schedule_work(&chip->irq_pending_work); } } } @@ -981,108 +958,60 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) } -/* - * set up a BDL entry - */ -static int setup_bdle(struct snd_pcm_substream *substream, - struct azx_dev *azx_dev, u32 **bdlp, - int ofs, int size, int with_ioc) -{ - struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - u32 *bdl = *bdlp; - - while (size > 0) { - dma_addr_t addr; - int chunk; - - if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) - return -EINVAL; - - addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); - /* program the address field of the BDL entry */ - bdl[0] = cpu_to_le32((u32)addr); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - /* program the size field of the BDL entry */ - chunk = PAGE_SIZE - (ofs % PAGE_SIZE); - if (size < chunk) - chunk = size; - bdl[2] = cpu_to_le32(chunk); - /* program the IOC to enable interrupt - * only when the whole fragment is processed - */ - size -= chunk; - bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); - bdl += 4; - azx_dev->frags++; - ofs += chunk; - } - *bdlp = bdl; - return ofs; -} - /* * set up BDL entries */ -static int azx_setup_periods(struct azx *chip, - struct snd_pcm_substream *substream, +static int azx_setup_periods(struct snd_pcm_substream *substream, struct azx_dev *azx_dev) { + struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); u32 *bdl; int i, ofs, periods, period_bytes; - int pos_adj; /* reset BDL address */ azx_sd_writel(azx_dev, SD_BDLPL, 0); azx_sd_writel(azx_dev, SD_BDLPU, 0); period_bytes = snd_pcm_lib_period_bytes(substream); - azx_dev->period_bytes = period_bytes; periods = azx_dev->bufsize / period_bytes; /* program the initial BDL entries */ bdl = (u32 *)azx_dev->bdl.area; ofs = 0; azx_dev->frags = 0; - azx_dev->irq_ignore = 0; - pos_adj = bdl_pos_adj[chip->dev_index]; - if (pos_adj > 0) { - struct snd_pcm_runtime *runtime = substream->runtime; - pos_adj = (pos_adj * runtime->rate + 47999) / 48000; - if (!pos_adj) - pos_adj = 1; - pos_adj = frames_to_bytes(runtime, pos_adj); - if (pos_adj >= period_bytes) { - snd_printk(KERN_WARNING "Too big adjustment %d\n", - bdl_pos_adj[chip->dev_index]); - pos_adj = 0; - } else { - ofs = setup_bdle(substream, azx_dev, - &bdl, ofs, pos_adj, 1); - if (ofs < 0) - goto error; - azx_dev->irq_ignore = 1; - } - } else - pos_adj = 0; for (i = 0; i < periods; i++) { - if (i == periods - 1 && pos_adj) - ofs = setup_bdle(substream, azx_dev, &bdl, ofs, - period_bytes - pos_adj, 0); - else - ofs = setup_bdle(substream, azx_dev, &bdl, ofs, - period_bytes, 1); - if (ofs < 0) - goto error; + int size, rest; + if (i >= AZX_MAX_BDL_ENTRIES) { + snd_printk(KERN_ERR "Too many BDL entries: " + "buffer=%d, period=%d\n", + azx_dev->bufsize, period_bytes); + /* reset */ + azx_sd_writel(azx_dev, SD_BDLPL, 0); + azx_sd_writel(azx_dev, SD_BDLPU, 0); + return -EINVAL; + } + rest = period_bytes; + do { + dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); + /* program the address field of the BDL entry */ + bdl[0] = cpu_to_le32((u32)addr); + bdl[1] = cpu_to_le32(upper_32bit(addr)); + /* program the size field of the BDL entry */ + size = PAGE_SIZE - (ofs % PAGE_SIZE); + if (rest < size) + size = rest; + bdl[2] = cpu_to_le32(size); + /* program the IOC to enable interrupt + * only when the whole fragment is processed + */ + rest -= size; + bdl[3] = rest ? 0 : cpu_to_le32(0x01); + bdl += 4; + azx_dev->frags++; + ofs += size; + } while (rest > 0); } return 0; - - error: - snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", - azx_dev->bufsize, period_bytes); - /* reset */ - azx_sd_writel(azx_dev, SD_BDLPL, 0); - azx_sd_writel(azx_dev, SD_BDLPU, 0); - return -EINVAL; } /* @@ -1133,7 +1062,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) /* lower BDL address */ azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); /* upper BDL address */ - azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); + azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr)); /* enable the position buffer */ if (chip->position_fix == POS_FIX_POSBUF || @@ -1156,7 +1085,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) */ static unsigned int azx_max_codecs[] __devinitdata = { - [AZX_DRIVER_ICH] = 4, /* Some ICH9 boards use SD3 */ + [AZX_DRIVER_ICH] = 3, [AZX_DRIVER_SCH] = 3, [AZX_DRIVER_ATI] = 4, [AZX_DRIVER_ATIHDMI] = 4, @@ -1164,7 +1093,6 @@ static unsigned int azx_max_codecs[] __devinitdata = { [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */ [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */ [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ - [AZX_DRIVER_TERA] = 1, }; static int __devinit azx_codec_create(struct azx *chip, const char *model, @@ -1388,7 +1316,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", azx_dev->bufsize, azx_dev->format_val); - if (azx_setup_periods(chip, substream, azx_dev) < 0) + if (azx_setup_periods(substream, azx_dev) < 0) return -EINVAL; azx_setup_controller(chip, azx_dev); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1493,113 +1421,35 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev) +static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) { + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev = get_azx_dev(substream); unsigned int pos; if (chip->position_fix == POS_FIX_POSBUF || chip->position_fix == POS_FIX_AUTO) { /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); + if (chip->position_fix == POS_FIX_AUTO && + azx_dev->period_intr == 1 && !pos) { + printk(KERN_WARNING + "hda-intel: Invalid position buffer, " + "using LPIB read method instead.\n"); + chip->position_fix = POS_FIX_NONE; + goto read_lpib; + } } else { + read_lpib: /* read LPIB */ pos = azx_sd_readl(azx_dev, SD_LPIB); + if (chip->position_fix == POS_FIX_FIFO) + pos += azx_dev->fifo_size; } if (pos >= azx_dev->bufsize) pos = 0; - return pos; -} - -static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev = get_azx_dev(substream); - return bytes_to_frames(substream->runtime, - azx_get_position(chip, azx_dev)); -} - -/* - * Check whether the current DMA position is acceptable for updating - * periods. Returns non-zero if it's OK. - * - * Many HD-audio controllers appear pretty inaccurate about - * the update-IRQ timing. The IRQ is issued before actually the - * data is processed. So, we need to process it afterwords in a - * workqueue. - */ -static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned int pos; - - pos = azx_get_position(chip, azx_dev); - if (chip->position_fix == POS_FIX_AUTO) { - if (!pos) { - printk(KERN_WARNING - "hda-intel: Invalid position buffer, " - "using LPIB read method instead.\n"); - chip->position_fix = POS_FIX_LPIB; - pos = azx_get_position(chip, azx_dev); - } else - chip->position_fix = POS_FIX_POSBUF; - } - - if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) - return 0; /* NG - it's below the period boundary */ - return 1; /* OK, it's fine */ -} - -/* - * The work for pending PCM period updates. - */ -static void azx_irq_pending_work(struct work_struct *work) -{ - struct azx *chip = container_of(work, struct azx, irq_pending_work); - int i, pending; - - if (!chip->irq_pending_warned) { - printk(KERN_WARNING - "hda-intel: IRQ timing workaround is activated " - "for card #%d. Suggest a bigger bdl_pos_adj.\n", - chip->card->number); - chip->irq_pending_warned = 1; - } - - for (;;) { - pending = 0; - spin_lock_irq(&chip->reg_lock); - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - if (!azx_dev->irq_pending || - !azx_dev->substream || - !azx_dev->running) - continue; - if (azx_position_ok(chip, azx_dev)) { - azx_dev->irq_pending = 0; - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(azx_dev->substream); - spin_lock(&chip->reg_lock); - } else - pending++; - } - spin_unlock_irq(&chip->reg_lock); - if (!pending) - return; - cond_resched(); - } -} - -/* clear irq_pending flags and assure no on-going workq */ -static void azx_clear_irq_pending(struct azx *chip) -{ - int i; - - spin_lock_irq(&chip->reg_lock); - for (i = 0; i < chip->num_streams; i++) - chip->azx_dev[i].irq_pending = 0; - spin_unlock_irq(&chip->reg_lock); - flush_scheduled_work(); + return bytes_to_frames(substream->runtime, pos); } static struct snd_pcm_ops azx_pcm_ops = { @@ -1826,7 +1676,6 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - azx_clear_irq_pending(chip); for (i = 0; i < AZX_MAX_PCMS; i++) snd_pcm_suspend_all(chip->pcm[i]); if (chip->initialized) @@ -1883,7 +1732,6 @@ static int azx_free(struct azx *chip) int i; if (chip->initialized) { - azx_clear_irq_pending(chip); for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); azx_stop_chip(chip); @@ -1922,9 +1770,9 @@ static int azx_dev_free(struct snd_device *device) * white/black-listing for position_fix */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { - SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), - SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), - SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), + SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE), + SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_NONE), {} }; @@ -2009,25 +1857,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->irq = -1; chip->driver_type = driver_type; chip->msi = enable_msi; - chip->dev_index = dev; - INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); chip->position_fix = check_position_fix(chip, position_fix[dev]); check_probe_mask(chip, dev); chip->single_cmd = single_cmd; - if (bdl_pos_adj[dev] < 0) { - switch (chip->driver_type) { - case AZX_DRIVER_ICH: - bdl_pos_adj[dev] = 1; - break; - default: - bdl_pos_adj[dev] = 32; - break; - } - } - #if BITS_PER_LONG != 64 /* Fix up base address on ULI M5461 */ if (chip->driver_type == AZX_DRIVER_ULI) { @@ -2254,7 +2089,6 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH }, { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH }, { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH }, { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH }, { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH }, @@ -2307,8 +2141,6 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, - /* Teradici */ - { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/trunk/sound/pci/hda/hda_proc.c b/trunk/sound/pci/hda/hda_proc.c index 1e5aff5c48d1..5633f77f8f3b 100644 --- a/trunk/sound/pci/hda/hda_proc.c +++ b/trunk/sound/pci/hda/hda_proc.c @@ -366,6 +366,8 @@ static void print_digital_conv(struct snd_info_buffer *buffer, { unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); + unsigned int digi2 = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_2, 0); snd_iprintf(buffer, " Digital:"); if (digi1 & AC_DIG1_ENABLE) snd_iprintf(buffer, " Enabled"); @@ -384,8 +386,7 @@ static void print_digital_conv(struct snd_info_buffer *buffer, if (digi1 & AC_DIG1_LEVEL) snd_iprintf(buffer, " GenLevel"); snd_iprintf(buffer, "\n"); - snd_iprintf(buffer, " Digital category: 0x%x\n", - (digi1 >> 8) & AC_DIG2_CC); + snd_iprintf(buffer, " Digital category: 0x%x\n", digi2 & AC_DIG2_CC); } static const char *get_pwr_state(u32 state) diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index e8003d99f0bf..a99e86d74278 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "hda_codec.h" @@ -63,6 +64,7 @@ struct ad198x_spec { /* PCM information */ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ + struct mutex amp_mutex; /* PCM volume/mute control mutex */ unsigned int spdif_route; /* dynamic controls, init_verbs and input_mux */ @@ -1616,7 +1618,6 @@ static const char *ad1981_models[AD1981_MODELS] = { static struct snd_pci_quirk ad1981_cfg_tbl[] = { SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), - SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), /* All HP models */ SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), @@ -2622,7 +2623,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, { struct ad198x_spec *spec = codec->spec; hda_nid_t nid; - int i, idx, err; + int idx, err; char name[32]; if (! pin) @@ -2630,26 +2631,16 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, idx = ad1988_pin_idx(pin); nid = ad1988_idx_to_dac(codec, idx); - /* check whether the corresponding DAC was already taken */ - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t pin = spec->autocfg.line_out_pins[i]; - hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin)); - if (dac == nid) - break; - } - if (i >= spec->autocfg.line_outs) { - /* specify the DAC as the extra output */ - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else - spec->multiout.extra_out_nid[0] = nid; - /* control HP volume/switch on the output mixer amp */ - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } + /* specify the DAC as the extra output */ + if (! spec->multiout.hp_nid) + spec->multiout.hp_nid = nid; + else + spec->multiout.extra_out_nid[0] = nid; + /* control HP volume/switch on the output mixer amp */ + sprintf(name, "%s Playback Volume", pfx); + if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) + return err; nid = ad1988_mixer_nids[idx]; sprintf(name, "%s Playback Switch", pfx); if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, @@ -3186,6 +3177,7 @@ static int patch_ad1884(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -3855,6 +3847,7 @@ static int patch_ad1884a(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -4159,6 +4152,7 @@ static int patch_ad1882(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 6; diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index 7c1eb23f0cec..36fd85260035 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -82,6 +82,7 @@ struct conexant_spec { /* PCM information */ struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ + struct mutex amp_mutex; /* PCM volume/mute control mutex */ unsigned int spdif_route; /* dynamic controls, init_verbs and input_mux */ @@ -686,7 +687,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { static struct hda_verb cxt5045_init_verbs[] = { /* Line in, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, /* HP, Amp */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -906,12 +907,10 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", - CXT5045_LAPTOP_HPMICSENSE), + SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE), SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), @@ -929,6 +928,7 @@ static int patch_cxt5045(struct hda_codec *codec) spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -963,7 +963,6 @@ static int patch_cxt5045(struct hda_codec *codec) codec->patch_ops.init = cxt5045_init; break; case CXT5045_LAPTOP_MICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; spec->input_mux = &cxt5045_capture_source; spec->num_init_verbs = 2; spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; @@ -1008,19 +1007,15 @@ static int patch_cxt5045(struct hda_codec *codec) #endif } - switch (codec->subsystem_id >> 16) { - case 0x103c: - /* HP laptop has a really bad sound over 0dB on NID 0x17. - * Fix max PCM level to 0 dB - * (originall it has 0x2b steps with 0dB offset 0x14) - */ - snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, - (0x14 << AC_AMPCAP_OFFSET_SHIFT) | - (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } + /* + * Fix max PCM level to 0 dB + * (originall it has 0x2b steps with 0dB offset 0x14) + */ + snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, + (0x14 << AC_AMPCAP_OFFSET_SHIFT) | + (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); return 0; } @@ -1482,6 +1477,7 @@ static int patch_cxt5047(struct hda_codec *codec) spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; + mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -1740,6 +1736,7 @@ static int patch_cxt5051(struct hda_codec *codec) spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; + mutex_init(&spec->amp_mutex); codec->spec = spec; codec->patch_ops = conexant_patch_ops; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 2807bc840d26..b0a2a262ece2 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -163,10 +163,6 @@ enum { ALC662_LENOVO_101E, ALC662_ASUS_EEEPC_P701, ALC662_ASUS_EEEPC_EP20, - ALC663_ASUS_M51VA, - ALC663_ASUS_G71V, - ALC663_ASUS_H13, - ALC663_ASUS_G50V, ALC662_AUTO, ALC662_MODEL_LAST, }; @@ -209,7 +205,6 @@ enum { ALC883_MITAC, ALC883_CLEVO_M720, ALC883_FUJITSU_PI2515, - ALC883_3ST_6ch_INTEL, ALC883_AUTO, ALC883_MODEL_LAST, }; @@ -285,10 +280,6 @@ struct alc_spec { #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif - - /* for PLL fix */ - hda_nid_t pll_nid; - unsigned int pll_coef_idx, pll_coef_bit; }; /* @@ -756,38 +747,6 @@ static struct hda_verb alc_gpio3_init_verbs[] = { { } }; -/* - * Fix hardware PLL issue - * On some codecs, the analog PLL gating control must be off while - * the default value is 1. - */ -static void alc_fix_pll(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int val; - - if (!spec->pll_nid) - return; - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, - spec->pll_coef_idx); - val = snd_hda_codec_read(codec, spec->pll_nid, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, - spec->pll_coef_idx); - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, - val & ~(1 << spec->pll_coef_bit)); -} - -static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, unsigned int coef_bit) -{ - struct alc_spec *spec = codec->spec; - spec->pll_nid = nid; - spec->pll_coef_idx = coef_idx; - spec->pll_coef_bit = coef_bit; - alc_fix_pll(codec); -} - static void alc_sku_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -817,24 +776,6 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) alc_sku_automute(codec); } -/* additional initialization for ALC888 variants */ -static void alc888_coef_init(struct hda_codec *codec) -{ - unsigned int tmp; - - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - if ((tmp & 0xf0) == 2) - /* alc888S-VC */ - snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x830); - else - /* alc888-VB */ - snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x3030); -} - /* 32-bit subsystem ID for BIOS loading in HD Audio codec. * 31 ~ 16 : Manufacture ID * 15 ~ 8 : SKU ID @@ -910,10 +851,8 @@ static void alc_subsystem_id(struct hda_codec *codec, case 0x10ec0267: case 0x10ec0268: case 0x10ec0269: - case 0x10ec0660: - case 0x10ec0662: - case 0x10ec0663: case 0x10ec0862: + case 0x10ec0662: case 0x10ec0889: snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_EAPD_BTLENABLE, 2); @@ -938,6 +877,7 @@ static void alc_subsystem_id(struct hda_codec *codec, case 0x10ec0882: case 0x10ec0883: case 0x10ec0885: + case 0x10ec0888: case 0x10ec0889: snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); @@ -949,9 +889,6 @@ static void alc_subsystem_id(struct hda_codec *codec, AC_VERB_SET_PROC_COEF, tmp | 0x2010); break; - case 0x10ec0888: - alc888_coef_init(codec); - break; case 0x10ec0267: case 0x10ec0268: snd_hda_codec_write(codec, 0x20, 0, @@ -2436,8 +2373,6 @@ static int alc_init(struct hda_codec *codec) struct alc_spec *spec = codec->spec; unsigned int i; - alc_fix_pll(codec); - for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); @@ -3074,7 +3009,6 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), @@ -5167,7 +5101,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP), SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), @@ -6193,7 +6127,6 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x106b, 0x00a0, "Apple iMac 24''", ALC885_IMAC24), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), @@ -6420,9 +6353,7 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) continue; vref = PIN_IN; if (1 /*i <= AUTO_PIN_FRONT_MIC*/) { - unsigned int pincap; - pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); - if ((pincap >> AC_PINCAP_VREF_SHIFT) & + if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) & AC_PINCAP_VREF_80) vref = PIN_VREF80; } @@ -6519,9 +6450,8 @@ static int patch_alc882(struct hda_codec *codec) case 0x106b1000: /* iMac 24 */ board_config = ALC885_IMAC24; break; - case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ + case 0x106b00a1: /* Macbook */ case 0x106b2c00: /* Macbook Pro rev3 */ - case 0x106b3600: /* Macbook 3.1 */ board_config = ALC885_MBP3; break; default: @@ -6555,20 +6485,14 @@ static int patch_alc882(struct hda_codec *codec) if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); - if (codec->vendor_id == 0x10ec0885) { - spec->stream_name_analog = "ALC885 Analog"; - spec->stream_name_digital = "ALC885 Digital"; - } else { - spec->stream_name_analog = "ALC882 Analog"; - spec->stream_name_digital = "ALC882 Digital"; - } - + spec->stream_name_analog = "ALC882 Analog"; spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; /* FIXME: setup DAC5 */ /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; + spec->stream_name_digital = "ALC882 Digital"; spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; @@ -6645,16 +6569,6 @@ static struct hda_input_mux alc883_capture_source = { }, }; -static struct hda_input_mux alc883_3stack_6ch_intel = { - .num_items = 4, - .items = { - { "Mic", 0x1 }, - { "Front Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - static struct hda_input_mux alc883_lenovo_101e_capture_source = { .num_items = 2, .items = { @@ -6735,48 +6649,6 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { { 6, alc883_3ST_ch6_init }, }; -/* - * 2ch mode - */ -static struct hda_verb alc883_3ST_ch2_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static struct hda_verb alc883_3ST_ch4_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static struct hda_verb alc883_3ST_ch6_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { - { 2, alc883_3ST_ch2_intel_init }, - { 4, alc883_3ST_ch4_intel_init }, - { 6, alc883_3ST_ch6_intel_init }, -}; - /* * 6ch mode */ @@ -7009,54 +6881,15 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -7896,7 +7729,6 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_MITAC] = "mitac", [ALC883_CLEVO_M720] = "clevo-m720", [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", - [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", [ALC883_AUTO] = "auto", }; @@ -7954,8 +7786,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), - SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), - SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), {} }; @@ -7994,18 +7824,6 @@ static struct alc_config_preset alc883_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, }, - [ALC883_3ST_6ch_INTEL] = { - .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), - .channel_mode = alc883_3ST_6ch_intel_modes, - .need_dac_fix = 1, - .input_mux = &alc883_3stack_6ch_intel, - }, [ALC883_6ST_DIG] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs }, @@ -8327,8 +8145,6 @@ static int patch_alc883(struct hda_codec *codec) codec->spec = spec; - alc_fix_pll_init(codec, 0x20, 0x0a, 10); - board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, alc883_models, alc883_cfg_tbl); @@ -8355,25 +8171,12 @@ static int patch_alc883(struct hda_codec *codec) if (board_config != ALC883_AUTO) setup_preset(spec, &alc883_presets[board_config]); - switch (codec->vendor_id) { - case 0x10ec0888: - spec->stream_name_analog = "ALC888 Analog"; - spec->stream_name_digital = "ALC888 Digital"; - break; - case 0x10ec0889: - spec->stream_name_analog = "ALC889 Analog"; - spec->stream_name_digital = "ALC889 Digital"; - break; - default: - spec->stream_name_analog = "ALC883 Analog"; - spec->stream_name_digital = "ALC883 Digital"; - break; - } - + spec->stream_name_analog = "ALC883 Analog"; spec->stream_analog_playback = &alc883_pcm_analog_playback; spec->stream_analog_capture = &alc883_pcm_analog_capture; spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; + spec->stream_name_digital = "ALC883 Digital"; spec->stream_digital_playback = &alc883_pcm_digital_playback; spec->stream_digital_capture = &alc883_pcm_digital_capture; @@ -8386,9 +8189,6 @@ static int patch_alc883(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC883_AUTO) spec->init_hook = alc883_auto_init; - else if (codec->vendor_id == 0x10ec0888) - spec->init_hook = alc888_coef_init; - #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc883_loopbacks; @@ -9722,8 +9522,6 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", - ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), @@ -9931,8 +9729,6 @@ static int patch_alc262(struct hda_codec *codec) } #endif - alc_fix_pll_init(codec, 0x20, 0x0a, 10); - board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, alc262_models, alc262_cfg_tbl); @@ -10878,18 +10674,12 @@ static int patch_alc268(struct hda_codec *codec) if (board_config != ALC268_AUTO) setup_preset(spec, &alc268_presets[board_config]); - if (codec->vendor_id == 0x10ec0267) { - spec->stream_name_analog = "ALC267 Analog"; - spec->stream_name_digital = "ALC267 Digital"; - } else { - spec->stream_name_analog = "ALC268 Analog"; - spec->stream_name_digital = "ALC268 Digital"; - } - + spec->stream_name_analog = "ALC268 Analog"; spec->stream_analog_playback = &alc268_pcm_analog_playback; spec->stream_analog_capture = &alc268_pcm_analog_capture; spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; + spec->stream_name_digital = "ALC268 Digital"; spec->stream_digital_playback = &alc268_pcm_digital_playback; if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) @@ -11243,8 +11033,6 @@ static int patch_alc269(struct hda_codec *codec) codec->spec = spec; - alc_fix_pll_init(codec, 0x20, 0x04, 15); - board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, alc269_models, alc269_cfg_tbl); @@ -12843,12 +12631,6 @@ static struct hda_verb alc861vd_eapd_verbs[] = { { } }; -static struct hda_verb alc660vd_eapd_verbs[] = { - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } -}; - static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -13004,7 +12786,6 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), - SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), {} }; @@ -13387,19 +13168,11 @@ static int patch_alc861vd(struct hda_codec *codec) if (board_config != ALC861VD_AUTO) setup_preset(spec, &alc861vd_presets[board_config]); - if (codec->vendor_id == 0x10ec0660) { - spec->stream_name_analog = "ALC660-VD Analog"; - spec->stream_name_digital = "ALC660-VD Digital"; - /* always turn on EAPD */ - spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs; - } else { - spec->stream_name_analog = "ALC861VD Analog"; - spec->stream_name_digital = "ALC861VD Digital"; - } - + spec->stream_name_analog = "ALC861VD Analog"; spec->stream_analog_playback = &alc861vd_pcm_analog_playback; spec->stream_analog_capture = &alc861vd_pcm_analog_capture; + spec->stream_name_digital = "ALC861VD Digital"; spec->stream_digital_playback = &alc861vd_pcm_digital_playback; spec->stream_digital_capture = &alc861vd_pcm_digital_capture; @@ -13478,23 +13251,6 @@ static struct hda_input_mux alc662_eeepc_capture_source = { }, }; -static struct hda_input_mux alc663_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static struct hda_input_mux alc663_m51va_capture_source = { - .num_items = 2, - .items = { - { "Ext-Mic", 0x0 }, - { "D-Mic", 0x9 }, - }, -}; - #define alc662_mux_enum_info alc_mux_enum_info #define alc662_mux_enum_get alc_mux_enum_get #define alc662_mux_enum_put alc882_mux_enum_put @@ -13675,44 +13431,6 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_m51va_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc663_g71v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc663_g50v_mixer[] = { - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - static struct snd_kcontrol_new alc662_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -13783,11 +13501,6 @@ static struct hda_verb alc662_init_verbs[] = { {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* always trun on EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } }; @@ -13858,43 +13571,6 @@ static struct hda_verb alc662_auto_init_verbs[] = { { } }; -static struct hda_verb alc663_m51va_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, - - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - {} -}; - -static struct hda_verb alc663_g71v_init_verbs[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ - - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, - {} -}; - -static struct hda_verb alc663_g50v_init_verbs[] = { - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ - - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - {} -}; - /* capture mixer elements */ static struct snd_kcontrol_new alc662_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), @@ -14016,125 +13692,6 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) alc662_eeepc_ep20_automute(codec); } -static void alc663_m51va_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc663_m51va_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); - snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); -} - -static void alc663_m51va_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_m51va_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc663_m51va_mic_automute(codec); - break; - } -} - -static void alc663_m51va_inithook(struct hda_codec *codec) -{ - alc663_m51va_speaker_automute(codec); - alc663_m51va_mic_automute(codec); -} - -static void alc663_g71v_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc663_g71v_front_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc663_g71v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_g71v_hp_automute(codec); - break; - case ALC880_FRONT_EVENT: - alc663_g71v_front_automute(codec); - break; - case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); - break; - } -} - -static void alc663_g71v_inithook(struct hda_codec *codec) -{ - alc663_g71v_front_automute(codec); - alc663_g71v_hp_automute(codec); - alc662_eeepc_mic_automute(codec); -} - -static void alc663_g50v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_m51va_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); - break; - } -} - -static void alc663_g50v_inithook(struct hda_codec *codec) -{ - alc663_m51va_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); -} - #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc662_loopbacks alc880_loopbacks #endif @@ -14157,24 +13714,14 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { [ALC662_LENOVO_101E] = "lenovo-101e", [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", - [ALC663_ASUS_M51VA] = "m51va", - [ALC663_ASUS_G71V] = "g71v", - [ALC663_ASUS_H13] = "h13", - [ALC663_ASUS_G50V] = "g50v", [ALC662_AUTO] = "auto", }; static struct snd_pci_quirk alc662_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V), - SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), - SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V), SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), - SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13), {} }; @@ -14262,53 +13809,7 @@ static struct alc_config_preset alc662_presets[] = { .unsol_event = alc662_eeepc_ep20_unsol_event, .init_hook = alc662_eeepc_ep20_inithook, }, - [ALC663_ASUS_M51VA] = { - .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc663_m51va_capture_source, - .unsol_event = alc663_m51va_unsol_event, - .init_hook = alc663_m51va_inithook, - }, - [ALC663_ASUS_G71V] = { - .mixers = { alc663_g71v_mixer, alc662_capture_mixer}, - .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, - .unsol_event = alc663_g71v_unsol_event, - .init_hook = alc663_g71v_inithook, - }, - [ALC663_ASUS_H13] = { - .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc663_m51va_capture_source, - .unsol_event = alc663_m51va_unsol_event, - .init_hook = alc663_m51va_inithook, - }, - [ALC663_ASUS_G50V] = { - .mixers = { alc663_g50v_mixer, alc662_capture_mixer}, - .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .input_mux = &alc663_capture_source, - .unsol_event = alc663_g50v_unsol_event, - .init_hook = alc663_g50v_inithook, - }, + }; @@ -14581,8 +14082,6 @@ static int patch_alc662(struct hda_codec *codec) codec->spec = spec; - alc_fix_pll_init(codec, 0x20, 0x04, 15); - board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, alc662_models, alc662_cfg_tbl); @@ -14609,17 +14108,11 @@ static int patch_alc662(struct hda_codec *codec) if (board_config != ALC662_AUTO) setup_preset(spec, &alc662_presets[board_config]); - if (codec->vendor_id == 0x10ec0663) { - spec->stream_name_analog = "ALC663 Analog"; - spec->stream_name_digital = "ALC663 Digital"; - } else { - spec->stream_name_analog = "ALC662 Analog"; - spec->stream_name_digital = "ALC662 Digital"; - } - + spec->stream_name_analog = "ALC662 Analog"; spec->stream_analog_playback = &alc662_pcm_analog_playback; spec->stream_analog_capture = &alc662_pcm_analog_capture; + spec->stream_name_digital = "ALC662 Digital"; spec->stream_digital_playback = &alc662_pcm_digital_playback; spec->stream_digital_capture = &alc662_pcm_digital_capture; @@ -14658,7 +14151,6 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc883 }, { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", .patch = patch_alc662 }, - { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 08cb77f51880..a4f44a00bae8 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -636,28 +636,21 @@ static struct hda_verb stac92hd71bxx_core_init[] = { { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, }; -#define HD_DISABLE_PORTF 3 static struct hda_verb stac92hd71bxx_analog_core_init[] = { - /* start of config #1 */ - - /* connect port 0f to audio mixer */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ - /* unmute right and left channels for node 0x0f */ - { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* start of config #2 */ - /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* connect headphone jack to dac1 */ { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* connect port 0d to audio mixer */ + /* connect ports 0d and 0f to audio mixer */ { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ /* unmute dac0 input in audio mixer */ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, - /* unmute right and left channels for nodes 0x0a, 0xd */ + /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {} }; @@ -825,9 +818,6 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), { } /* end */ @@ -1327,13 +1317,13 @@ static unsigned int ref92hd71bxx_pin_configs[10] = { 0x90a000f0, 0x01452050, }; -static unsigned int dell_m4_1_pin_configs[10] = { +static unsigned int dell_m4_1_pin_configs[13] = { 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, 0x40f000f0, 0x4f0000f0, }; -static unsigned int dell_m4_2_pin_configs[10] = { +static unsigned int dell_m4_2_pin_configs[13] = { 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x044413b0, @@ -1764,8 +1754,12 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { "unknown Dell", STAC_9205_DELL_M42), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, + "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, + "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, @@ -1776,14 +1770,18 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, "Dell Precision M4300", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, - "unknown Dell", STAC_9205_DELL_M42), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, - "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, + "unknown Dell", STAC_9205_DELL_M42), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, "Dell Inspiron", STAC_9205_DELL_M44), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, @@ -3105,16 +3103,13 @@ static int stac92xx_init(struct hda_codec *codec) 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i], 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - def_conf = get_defcfg_connect(def_conf); /* outputs are only ports capable of power management * any attempts on powering down a input port cause the * referenced VREF to act quirky. */ if (pinctl & AC_PINCTL_IN_EN) continue; - /* skip any ports that don't have jacks since presence - * detection is useless */ - if (def_conf && def_conf != AC_JACK_PORT_FIXED) + if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) continue; enable_pin_detect(codec, spec->pwr_nids[i], event | i); codec->patch_ops.unsol_event(codec, (event | i) << 26); @@ -3619,7 +3614,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) codec->spec = spec; spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); - spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); spec->pin_nids = stac92hd71bxx_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_92HD71BXX_MODELS, @@ -3648,19 +3642,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->mixer = stac92hd71bxx_mixer; spec->init = stac92hd71bxx_core_init; break; - case 0x111d7608: /* 5 Port with Analog Mixer */ - /* no output amps */ - spec->num_pwrs = 0; - spec->mixer = stac92hd71bxx_analog_mixer; - - /* disable VSW */ - spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; - stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); - break; - case 0x111d7603: /* 6 Port with Analog Mixer */ - /* no output amps */ - spec->num_pwrs = 0; - /* fallthru */ default: spec->mixer = stac92hd71bxx_analog_mixer; spec->init = stac92hd71bxx_analog_core_init; @@ -3672,19 +3653,22 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) /* GPIO0 High = EAPD */ spec->gpio_mask = 0x01; spec->gpio_dir = 0x01; + spec->gpio_mask = 0x01; spec->gpio_data = 0x01; spec->mux_nids = stac92hd71bxx_mux_nids; spec->adc_nids = stac92hd71bxx_adc_nids; spec->dmic_nids = stac92hd71bxx_dmic_nids; spec->dmux_nids = stac92hd71bxx_dmux_nids; - spec->pwr_nids = stac92hd71bxx_pwr_nids; spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); spec->num_dmics = STAC92HD71BXX_NUM_DMICS; spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); + spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); + spec->pwr_nids = stac92hd71bxx_pwr_nids; + spec->multiout.num_dacs = 1; spec->multiout.hp_nid = 0x11; spec->multiout.dac_nids = stac92hd71bxx_dac_nids; @@ -4322,11 +4306,10 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, - { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, - { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, + { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, diff --git a/trunk/sound/pci/ice1712/envy24ht.h b/trunk/sound/pci/ice1712/envy24ht.h index a0c5e009bb4a..43b9e3e858be 100644 --- a/trunk/sound/pci/ice1712/envy24ht.h +++ b/trunk/sound/pci/ice1712/envy24ht.h @@ -93,13 +93,9 @@ enum { #define VT1724_REG_MPU_TXFIFO 0x0a /*byte ro. number of bytes in TX fifo*/ #define VT1724_REG_MPU_RXFIFO 0x0b /*byte ro. number of bytes in RX fifo*/ -#define VT1724_REG_MPU_DATA 0x0c /* byte */ -#define VT1724_REG_MPU_CTRL 0x0d /* byte */ -#define VT1724_MPU_UART 0x01 -#define VT1724_MPU_TX_EMPTY 0x02 -#define VT1724_MPU_TX_FULL 0x04 -#define VT1724_MPU_RX_EMPTY 0x08 -#define VT1724_MPU_RX_FULL 0x10 +//are these 2 the wrong way around? they don't seem to be used yet anyway +#define VT1724_REG_MPU_CTRL 0x0c /* byte */ +#define VT1724_REG_MPU_DATA 0x0d /* byte */ #define VT1724_REG_MPU_FIFO_WM 0x0e /*byte set the high/low watermarks for RX/TX fifos*/ #define VT1724_MPU_RX_FIFO 0x20 //1=rx fifo watermark 0=tx fifo watermark diff --git a/trunk/sound/pci/ice1712/ice1712.h b/trunk/sound/pci/ice1712/ice1712.h index 762fbd7a7507..3208901c740e 100644 --- a/trunk/sound/pci/ice1712/ice1712.h +++ b/trunk/sound/pci/ice1712/ice1712.h @@ -333,8 +333,6 @@ struct snd_ice1712 { unsigned int has_spdif: 1; /* VT1720/4 - has SPDIF I/O */ unsigned int force_pdma4: 1; /* VT1720/4 - PDMA4 as non-spdif */ unsigned int force_rdma1: 1; /* VT1720/4 - RDMA1 as non-spdif */ - unsigned int midi_output: 1; /* VT1720/4: MIDI output triggered */ - unsigned int midi_input: 1; /* VT1720/4: MIDI input triggered */ unsigned int num_total_dacs; /* total DACs */ unsigned int num_total_adcs; /* total ADCs */ unsigned int cur_rate; /* current rate */ diff --git a/trunk/sound/pci/ice1712/ice1724.c b/trunk/sound/pci/ice1712/ice1724.c index e596d777d9dd..67350901772c 100644 --- a/trunk/sound/pci/ice1712/ice1724.c +++ b/trunk/sound/pci/ice1712/ice1724.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include @@ -223,153 +223,30 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice) } /* - * MIDI + * MPU401 accessor */ - -static void vt1724_midi_clear_rx(struct snd_ice1712 *ice) -{ - unsigned int count; - - for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count) - inb(ICEREG1724(ice, MPU_DATA)); -} - -static inline struct snd_rawmidi_substream * -get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream) +static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu, + unsigned long addr) { - return list_first_entry(&ice->rmidi[0]->streams[stream].substreams, - struct snd_rawmidi_substream, list); -} - -static void vt1724_midi_write(struct snd_ice1712 *ice) -{ - struct snd_rawmidi_substream *s; - int count, i; - u8 buffer[32]; - - s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT); - count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO)); - if (count > 0) { - count = snd_rawmidi_transmit(s, buffer, count); - for (i = 0; i < count; ++i) - outb(buffer[i], ICEREG1724(ice, MPU_DATA)); - } -} - -static void vt1724_midi_read(struct snd_ice1712 *ice) -{ - struct snd_rawmidi_substream *s; - int count, i; - u8 buffer[32]; - - s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT); - count = inb(ICEREG1724(ice, MPU_RXFIFO)); - if (count > 0) { - count = min(count, 32); - for (i = 0; i < count; ++i) - buffer[i] = inb(ICEREG1724(ice, MPU_DATA)); - snd_rawmidi_receive(s, buffer, count); - } -} - -static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, - u8 flag, int enable) -{ - struct snd_ice1712 *ice = substream->rmidi->private_data; - u8 mask; - - spin_lock_irq(&ice->reg_lock); - mask = inb(ICEREG1724(ice, IRQMASK)); - if (enable) - mask &= ~flag; + /* fix status bits to the standard position */ + /* only RX_EMPTY and TX_FULL are checked */ + if (addr == MPU401C(mpu)) + return (inb(addr) & 0x0c) << 4; else - mask |= flag; - outb(mask, ICEREG1724(ice, IRQMASK)); - spin_unlock_irq(&ice->reg_lock); -} - -static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) -{ - vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1); - return 0; -} - -static int vt1724_midi_output_close(struct snd_rawmidi_substream *s) -{ - vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0); - return 0; + return inb(addr); } -static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) +static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu, + unsigned char data, unsigned long addr) { - struct snd_ice1712 *ice = s->rmidi->private_data; - unsigned long flags; - - spin_lock_irqsave(&ice->reg_lock, flags); - if (up) { - ice->midi_output = 1; - vt1724_midi_write(ice); - } else { - ice->midi_output = 0; - } - spin_unlock_irqrestore(&ice->reg_lock, flags); -} - -static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) -{ - struct snd_ice1712 *ice = s->rmidi->private_data; - unsigned long timeout; - - /* 32 bytes should be transmitted in less than about 12 ms */ - timeout = jiffies + msecs_to_jiffies(15); - do { - if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY) - break; - schedule_timeout_uninterruptible(1); - } while (time_after(timeout, jiffies)); -} - -static struct snd_rawmidi_ops vt1724_midi_output_ops = { - .open = vt1724_midi_output_open, - .close = vt1724_midi_output_close, - .trigger = vt1724_midi_output_trigger, - .drain = vt1724_midi_output_drain, -}; - -static int vt1724_midi_input_open(struct snd_rawmidi_substream *s) -{ - vt1724_midi_clear_rx(s->rmidi->private_data); - vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1); - return 0; -} - -static int vt1724_midi_input_close(struct snd_rawmidi_substream *s) -{ - vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0); - return 0; -} - -static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) -{ - struct snd_ice1712 *ice = s->rmidi->private_data; - unsigned long flags; - - spin_lock_irqsave(&ice->reg_lock, flags); - if (up) { - ice->midi_input = 1; - vt1724_midi_read(ice); - } else { - ice->midi_input = 0; - } - spin_unlock_irqrestore(&ice->reg_lock, flags); + if (addr == MPU401C(mpu)) { + if (data == MPU401_ENTER_UART) + outb(0x01, addr); + /* what else? */ + } else + outb(data, addr); } -static struct snd_rawmidi_ops vt1724_midi_input_ops = { - .open = vt1724_midi_input_open, - .close = vt1724_midi_input_close, - .trigger = vt1724_midi_input_trigger, -}; - /* * Interrupt handler @@ -401,10 +278,13 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) #endif handled = 1; if (status & VT1724_IRQ_MPU_TX) { - spin_lock(&ice->reg_lock); - if (ice->midi_output) - vt1724_midi_write(ice); - spin_unlock(&ice->reg_lock); + if (ice->rmidi[0]) + snd_mpu401_uart_interrupt_tx(irq, + ice->rmidi[0]->private_data); + else /* disable TX to be sure */ + outb(inb(ICEREG1724(ice, IRQMASK)) | + VT1724_IRQ_MPU_TX, + ICEREG1724(ice, IRQMASK)); /* Due to mysterical reasons, MPU_TX is always * generated (and can't be cleared) when a PCM * playback is going. So let's ignore at the @@ -413,12 +293,13 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) status_mask &= ~VT1724_IRQ_MPU_TX; } if (status & VT1724_IRQ_MPU_RX) { - spin_lock(&ice->reg_lock); - if (ice->midi_input) - vt1724_midi_read(ice); - else - vt1724_midi_clear_rx(ice); - spin_unlock(&ice->reg_lock); + if (ice->rmidi[0]) + snd_mpu401_uart_interrupt(irq, + ice->rmidi[0]->private_data); + else /* disable RX to be sure */ + outb(inb(ICEREG1724(ice, IRQMASK)) | + VT1724_IRQ_MPU_RX, + ICEREG1724(ice, IRQMASK)); } /* ack MPU irq */ outb(status, ICEREG1724(ice, IRQSTAT)); @@ -2544,30 +2425,28 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, if (! c->no_mpu401) { if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { - struct snd_rawmidi *rmidi; - - err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi); - if (err < 0) { + struct snd_mpu401 *mpu; + if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, + ICEREG1724(ice, MPU_CTRL), + (MPU401_INFO_INTEGRATED | + MPU401_INFO_NO_ACK | + MPU401_INFO_TX_IRQ), + ice->irq, 0, + &ice->rmidi[0])) < 0) { snd_card_free(card); return err; } - ice->rmidi[0] = rmidi; - rmidi->private_data = ice; - strcpy(rmidi->name, "ICE1724 MIDI"); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, - &vt1724_midi_output_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &vt1724_midi_input_ops); - + mpu = ice->rmidi[0]->private_data; + mpu->read = snd_vt1724_mpu401_read; + mpu->write = snd_vt1724_mpu401_write; + /* unmask MPU RX/TX irqs */ + outb(inb(ICEREG1724(ice, IRQMASK)) & + ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX), + ICEREG1724(ice, IRQMASK)); /* set watermarks */ outb(VT1724_MPU_RX_FIFO | 0x1, ICEREG1724(ice, MPU_FIFO_WM)); outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); - /* set UART mode */ - outb(VT1724_MPU_UART, ICEREG1724(ice, MPU_CTRL)); } } diff --git a/trunk/sound/pci/maestro3.c b/trunk/sound/pci/maestro3.c index f4788dee05c3..a536c59fbea1 100644 --- a/trunk/sound/pci/maestro3.c +++ b/trunk/sound/pci/maestro3.c @@ -2427,29 +2427,6 @@ snd_m3_amp_enable(struct snd_m3 *chip, int enable) outw(0xffff, io + GPIO_MASK); } -static void -snd_m3_hv_init(struct snd_m3 *chip) -{ - unsigned long io = chip->iobase; - u16 val = GPI_VOL_DOWN | GPI_VOL_UP; - - if (!chip->is_omnibook) - return; - - /* - * Volume buttons on some HP OmniBook laptops - * require some GPIO magic to work correctly. - */ - outw(0xffff, io + GPIO_MASK); - outw(0x0000, io + GPIO_DATA); - - outw(~val, io + GPIO_MASK); - outw(inw(io + GPIO_DIRECTION) & ~val, io + GPIO_DIRECTION); - outw(val, io + GPIO_MASK); - - outw(0xffff, io + GPIO_MASK); -} - static int snd_m3_chip_init(struct snd_m3 *chip) { @@ -2465,6 +2442,21 @@ snd_m3_chip_init(struct snd_m3 *chip) DISABLE_LEGACY); pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); + if (chip->is_omnibook) { + /* + * Volume buttons on some HP OmniBook laptops don't work + * correctly. This makes them work for the most part. + * + * Volume up and down buttons on the laptop side work. + * Fn+cursor_up (volme up) works. + * Fn+cursor_down (volume down) doesn't work. + * Fn+F7 (mute) works acts as volume up. + */ + outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); + outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); + outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); + outw(0xffff, io + GPIO_MASK); + } pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); n |= chip->hv_config; @@ -2650,8 +2642,6 @@ static int m3_resume(struct pci_dev *pci) snd_m3_enable_ints(chip); snd_m3_amp_enable(chip, 1); - snd_m3_hv_init(chip); - snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -2791,8 +2781,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, snd_m3_amp_enable(chip, 1); - snd_m3_hv_init(chip); - tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, diff --git a/trunk/sound/pci/nm256/nm256.c b/trunk/sound/pci/nm256/nm256.c index 06d13e717114..7efb838d18a6 100644 --- a/trunk/sound/pci/nm256/nm256.c +++ b/trunk/sound/pci/nm256/nm256.c @@ -1302,8 +1302,8 @@ snd_nm256_mixer(struct nm256 *chip) .read = snd_nm256_ac97_read, }; - chip->ac97_regs = kcalloc(ARRAY_SIZE(nm256_ac97_init_val), - sizeof(short), GFP_KERNEL); + chip->ac97_regs = kcalloc(sizeof(short), + ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL); if (! chip->ac97_regs) return -ENOMEM; diff --git a/trunk/sound/pci/oxygen/hifier.c b/trunk/sound/pci/oxygen/hifier.c index 7442460583dd..090dd4354a28 100644 --- a/trunk/sound/pci/oxygen/hifier.c +++ b/trunk/sound/pci/oxygen/hifier.c @@ -28,7 +28,7 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("TempoTec HiFier driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -62,28 +62,16 @@ static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) AK4396_WRITE | (reg << 8) | value); } -static void update_ak4396_volume(struct oxygen *chip) -{ - ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); - ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); -} - -static void hifier_registers_init(struct oxygen *chip) +static void hifier_init(struct oxygen *chip) { struct hifier_data *data = chip->model_data; + data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); - update_ak4396_volume(chip); -} - -static void hifier_init(struct oxygen *chip) -{ - struct hifier_data *data = chip->model_data; - - data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; - hifier_registers_init(chip); + ak4396_write(chip, AK4396_LCH_ATT, 0); + ak4396_write(chip, AK4396_RCH_ATT, 0); snd_component_add(chip->card, "AK4396"); snd_component_add(chip->card, "CS5340"); @@ -112,6 +100,12 @@ static void set_ak4396_params(struct oxygen *chip, ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); } +static void update_ak4396_volume(struct oxygen *chip) +{ + ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); + ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); +} + static void update_ak4396_mute(struct oxygen *chip) { struct hifier_data *data = chip->model_data; @@ -146,7 +140,6 @@ static const struct oxygen_model model_hifier = { .init = hifier_init, .control_filter = hifier_control_filter, .cleanup = hifier_cleanup, - .resume = hifier_registers_init, .set_dac_params = set_ak4396_params, .set_adc_params = set_cs5340_params, .update_dac_volume = update_ak4396_volume, @@ -187,10 +180,6 @@ static struct pci_driver hifier_driver = { .id_table = hifier_ids, .probe = hifier_probe, .remove = __devexit_p(oxygen_pci_remove), -#ifdef CONFIG_PM - .suspend = oxygen_pci_suspend, - .resume = oxygen_pci_resume, -#endif }; static int __init alsa_card_hifier_init(void) diff --git a/trunk/sound/pci/oxygen/oxygen.c b/trunk/sound/pci/oxygen/oxygen.c index 7c8ae31eb468..63f185c1ed1e 100644 --- a/trunk/sound/pci/oxygen/oxygen.c +++ b/trunk/sound/pci/oxygen/oxygen.c @@ -43,7 +43,7 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("C-Media CMI8788 driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -80,7 +80,6 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); struct generic_data { u8 ak4396_ctl2; - u16 saved_wm8785_registers[2]; }; static void ak4396_write(struct oxygen *chip, unsigned int codec, @@ -100,35 +99,20 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec, static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) { - struct generic_data *data = chip->model_data; - oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | OXYGEN_SPI_DATA_LENGTH_2 | OXYGEN_SPI_CLOCK_160 | (3 << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, (reg << 9) | value); - if (reg < ARRAY_SIZE(data->saved_wm8785_registers)) - data->saved_wm8785_registers[reg] = value; -} - -static void update_ak4396_volume(struct oxygen *chip) -{ - unsigned int i; - - for (i = 0; i < 4; ++i) { - ak4396_write(chip, i, - AK4396_LCH_ATT, chip->dac_volume[i * 2]); - ak4396_write(chip, i, - AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); - } } -static void ak4396_registers_init(struct oxygen *chip) +static void ak4396_init(struct oxygen *chip) { struct generic_data *data = chip->model_data; unsigned int i; + data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; for (i = 0; i < 4; ++i) { ak4396_write(chip, i, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); @@ -136,16 +120,9 @@ static void ak4396_registers_init(struct oxygen *chip) AK4396_CONTROL_2, data->ak4396_ctl2); ak4396_write(chip, i, AK4396_CONTROL_3, AK4396_PCM); + ak4396_write(chip, i, AK4396_LCH_ATT, 0); + ak4396_write(chip, i, AK4396_RCH_ATT, 0); } - update_ak4396_volume(chip); -} - -static void ak4396_init(struct oxygen *chip) -{ - struct generic_data *data = chip->model_data; - - data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; - ak4396_registers_init(chip); snd_component_add(chip->card, "AK4396"); } @@ -156,23 +133,12 @@ static void ak5385_init(struct oxygen *chip) snd_component_add(chip->card, "AK5385"); } -static void wm8785_registers_init(struct oxygen *chip) -{ - struct generic_data *data = chip->model_data; - - wm8785_write(chip, WM8785_R7, 0); - wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]); - wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]); -} - static void wm8785_init(struct oxygen *chip) { - struct generic_data *data = chip->model_data; - - data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE | - WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST; - data->saved_wm8785_registers[1] = WM8785_WL_24; - wm8785_registers_init(chip); + wm8785_write(chip, WM8785_R7, 0); + wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE | + WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST); + wm8785_write(chip, WM8785_R1, WM8785_WL_24); snd_component_add(chip->card, "WM8785"); } @@ -192,12 +158,6 @@ static void generic_cleanup(struct oxygen *chip) { } -static void generic_resume(struct oxygen *chip) -{ - ak4396_registers_init(chip); - wm8785_registers_init(chip); -} - static void set_ak4396_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { @@ -223,6 +183,18 @@ static void set_ak4396_params(struct oxygen *chip, } } +static void update_ak4396_volume(struct oxygen *chip) +{ + unsigned int i; + + for (i = 0; i < 4; ++i) { + ak4396_write(chip, i, + AK4396_LCH_ATT, chip->dac_volume[i * 2]); + ak4396_write(chip, i, + AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); + } +} + static void update_ak4396_mute(struct oxygen *chip) { struct generic_data *data = chip->model_data; @@ -284,7 +256,6 @@ static const struct oxygen_model model_generic = { .owner = THIS_MODULE, .init = generic_init, .cleanup = generic_cleanup, - .resume = generic_resume, .set_dac_params = set_ak4396_params, .set_adc_params = set_wm8785_params, .update_dac_volume = update_ak4396_volume, @@ -312,7 +283,6 @@ static const struct oxygen_model model_meridian = { .owner = THIS_MODULE, .init = meridian_init, .cleanup = generic_cleanup, - .resume = ak4396_registers_init, .set_dac_params = set_ak4396_params, .set_adc_params = set_ak5385_params, .update_dac_volume = update_ak4396_volume, @@ -361,10 +331,6 @@ static struct pci_driver oxygen_driver = { .id_table = oxygen_ids, .probe = generic_oxygen_probe, .remove = __devexit_p(oxygen_pci_remove), -#ifdef CONFIG_PM - .suspend = oxygen_pci_suspend, - .resume = oxygen_pci_resume, -#endif }; static int __init alsa_card_oxygen_init(void) diff --git a/trunk/sound/pci/oxygen/oxygen.h b/trunk/sound/pci/oxygen/oxygen.h index 74a644880074..a71c6e059260 100644 --- a/trunk/sound/pci/oxygen/oxygen.h +++ b/trunk/sound/pci/oxygen/oxygen.h @@ -16,8 +16,6 @@ #define PCM_AC97 5 #define PCM_COUNT 6 -#define OXYGEN_IO_SIZE 0x100 - /* model-specific configuration of outputs/inputs */ #define PLAYBACK_0_TO_I2S 0x001 #define PLAYBACK_1_TO_SPDIF 0x004 @@ -80,12 +78,6 @@ struct oxygen { struct work_struct spdif_input_bits_work; struct work_struct gpio_work; wait_queue_head_t ac97_waitqueue; - union { - u8 _8[OXYGEN_IO_SIZE]; - __le16 _16[OXYGEN_IO_SIZE / 2]; - __le32 _32[OXYGEN_IO_SIZE / 4]; - } saved_registers; - u16 saved_ac97_registers[2][0x40]; }; struct oxygen_model { @@ -97,8 +89,6 @@ struct oxygen_model { int (*control_filter)(struct snd_kcontrol_new *template); int (*mixer_init)(struct oxygen *chip); void (*cleanup)(struct oxygen *chip); - void (*suspend)(struct oxygen *chip); - void (*resume)(struct oxygen *chip); void (*pcm_hardware_filter)(unsigned int channel, struct snd_pcm_hardware *hardware); void (*set_dac_params)(struct oxygen *chip, @@ -127,10 +117,6 @@ struct oxygen_model { int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, const struct oxygen_model *model); void oxygen_pci_remove(struct pci_dev *pci); -#ifdef CONFIG_PM -int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state); -int oxygen_pci_resume(struct pci_dev *pci); -#endif /* oxygen_mixer.c */ diff --git a/trunk/sound/pci/oxygen/oxygen_io.c b/trunk/sound/pci/oxygen/oxygen_io.c index 83f135f80df4..5569606ee87f 100644 --- a/trunk/sound/pci/oxygen/oxygen_io.c +++ b/trunk/sound/pci/oxygen/oxygen_io.c @@ -44,21 +44,18 @@ EXPORT_SYMBOL(oxygen_read32); void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) { outb(value, chip->addr + reg); - chip->saved_registers._8[reg] = value; } EXPORT_SYMBOL(oxygen_write8); void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) { outw(value, chip->addr + reg); - chip->saved_registers._16[reg / 2] = cpu_to_le16(value); } EXPORT_SYMBOL(oxygen_write16); void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) { outl(value, chip->addr + reg); - chip->saved_registers._32[reg / 4] = cpu_to_le32(value); } EXPORT_SYMBOL(oxygen_write32); @@ -66,10 +63,7 @@ void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, u8 value, u8 mask) { u8 tmp = inb(chip->addr + reg); - tmp &= ~mask; - tmp |= value & mask; - outb(tmp, chip->addr + reg); - chip->saved_registers._8[reg] = tmp; + outb((tmp & ~mask) | (value & mask), chip->addr + reg); } EXPORT_SYMBOL(oxygen_write8_masked); @@ -77,10 +71,7 @@ void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, u16 value, u16 mask) { u16 tmp = inw(chip->addr + reg); - tmp &= ~mask; - tmp |= value & mask; - outw(tmp, chip->addr + reg); - chip->saved_registers._16[reg / 2] = cpu_to_le16(tmp); + outw((tmp & ~mask) | (value & mask), chip->addr + reg); } EXPORT_SYMBOL(oxygen_write16_masked); @@ -88,10 +79,7 @@ void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, u32 value, u32 mask) { u32 tmp = inl(chip->addr + reg); - tmp &= ~mask; - tmp |= value & mask; - outl(tmp, chip->addr + reg); - chip->saved_registers._32[reg / 4] = cpu_to_le32(tmp); + outl((tmp & ~mask) | (value & mask), chip->addr + reg); } EXPORT_SYMBOL(oxygen_write32_masked); @@ -140,10 +128,8 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, oxygen_write32(chip, OXYGEN_AC97_REGS, reg); /* require two "completed" writes, just to be sure */ if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && - ++succeeded >= 2) { - chip->saved_ac97_registers[codec][index / 2] = data; + ++succeeded >= 2) return; - } } snd_printk(KERN_ERR "AC'97 write timeout\n"); } diff --git a/trunk/sound/pci/oxygen/oxygen_lib.c b/trunk/sound/pci/oxygen/oxygen_lib.c index 22f37851045e..897697d43506 100644 --- a/trunk/sound/pci/oxygen/oxygen_lib.c +++ b/trunk/sound/pci/oxygen/oxygen_lib.c @@ -32,7 +32,7 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("C-Media CMI8788 helper library"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) @@ -173,7 +173,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, int i, j; snd_iprintf(buffer, "CMI8788\n\n"); - for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { + for (i = 0; i < 0x100; i += 0x10) { snd_iprintf(buffer, "%02x:", i); for (j = 0; j < 0x10; ++j) snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j)); @@ -314,10 +314,6 @@ static void oxygen_init(struct oxygen *chip) OXYGEN_SPDIF_LOCK_MASK | OXYGEN_SPDIF_RATE_MASK); oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); - oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, - OXYGEN_2WIRE_LENGTH_8 | - OXYGEN_2WIRE_INTERRUPT_MASK | - OXYGEN_2WIRE_SPEED_STANDARD); oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); @@ -459,7 +455,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, } if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || - pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) { + pci_resource_len(pci, 0) < 0x100) { snd_printk(KERN_ERR "invalid PCI I/O range\n"); err = -ENXIO; goto err_pci_regions; @@ -538,99 +534,3 @@ void oxygen_pci_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } EXPORT_SYMBOL(oxygen_pci_remove); - -#ifdef CONFIG_PM -int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state) -{ - struct snd_card *card = pci_get_drvdata(pci); - struct oxygen *chip = card->private_data; - unsigned int i, saved_interrupt_mask; - - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - - for (i = 0; i < PCM_COUNT; ++i) - if (chip->streams[i]) - snd_pcm_suspend(chip->streams[i]); - - if (chip->model->suspend) - chip->model->suspend(chip); - - spin_lock_irq(&chip->reg_lock); - saved_interrupt_mask = chip->interrupt_mask; - chip->interrupt_mask = 0; - oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); - spin_unlock_irq(&chip->reg_lock); - - synchronize_irq(chip->irq); - flush_scheduled_work(); - chip->interrupt_mask = saved_interrupt_mask; - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, pci_choose_state(pci, state)); - return 0; -} -EXPORT_SYMBOL(oxygen_pci_suspend); - -static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = { - 0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff, - 0x00300000, 0x00000fe4, 0x0ff7001f, 0x00000000 -}; -static const u32 ac97_registers_to_restore[2][0x40 / 32] = { - { 0x18284fa2, 0x03060000 }, - { 0x00007fa6, 0x00200000 } -}; - -static inline int is_bit_set(const u32 *bitmap, unsigned int bit) -{ - return bitmap[bit / 32] & (1 << (bit & 31)); -} - -static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec) -{ - unsigned int i; - - oxygen_write_ac97(chip, codec, AC97_RESET, 0); - msleep(1); - for (i = 1; i < 0x40; ++i) - if (is_bit_set(ac97_registers_to_restore[codec], i)) - oxygen_write_ac97(chip, codec, i * 2, - chip->saved_ac97_registers[codec][i]); -} - -int oxygen_pci_resume(struct pci_dev *pci) -{ - struct snd_card *card = pci_get_drvdata(pci); - struct oxygen *chip = card->private_data; - unsigned int i; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - snd_printk(KERN_ERR "cannot reenable device"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - - oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); - for (i = 0; i < OXYGEN_IO_SIZE; ++i) - if (is_bit_set(registers_to_restore, i)) - oxygen_write8(chip, i, chip->saved_registers._8[i]); - if (chip->has_ac97_0) - oxygen_restore_ac97(chip, 0); - if (chip->has_ac97_1) - oxygen_restore_ac97(chip, 1); - - if (chip->model->resume) - chip->model->resume(chip); - - oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); - - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - return 0; -} -EXPORT_SYMBOL(oxygen_pci_resume); -#endif /* CONFIG_PM */ diff --git a/trunk/sound/pci/oxygen/oxygen_pcm.c b/trunk/sound/pci/oxygen/oxygen_pcm.c index c4ad65a3406f..b17c405e069d 100644 --- a/trunk/sound/pci/oxygen/oxygen_pcm.c +++ b/trunk/sound/pci/oxygen/oxygen_pcm.c @@ -24,16 +24,6 @@ #include #include "oxygen.h" -/* most DMA channels have a 16-bit counter for 32-bit words */ -#define BUFFER_BYTES_MAX ((1 << 16) * 4) -/* the multichannel DMA channel has a 24-bit counter */ -#define BUFFER_BYTES_MAX_MULTICH ((1 << 24) * 4) - -#define PERIOD_BYTES_MIN 64 - -#define DEFAULT_BUFFER_BYTES (BUFFER_BYTES_MAX / 2) -#define DEFAULT_BUFFER_BYTES_MULTICH (1024 * 1024) - static const struct snd_pcm_hardware oxygen_stereo_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -54,11 +44,11 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { .rate_max = 192000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = BUFFER_BYTES_MAX, - .period_bytes_min = PERIOD_BYTES_MIN, - .period_bytes_max = BUFFER_BYTES_MAX / 2, + .buffer_bytes_max = 256 * 1024, + .period_bytes_min = 128, + .period_bytes_max = 128 * 1024, .periods_min = 2, - .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, + .periods_max = 2048, }; static const struct snd_pcm_hardware oxygen_multichannel_hardware = { .info = SNDRV_PCM_INFO_MMAP | @@ -80,11 +70,11 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { .rate_max = 192000, .channels_min = 2, .channels_max = 8, - .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, - .period_bytes_min = PERIOD_BYTES_MIN, - .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, + .buffer_bytes_max = 2048 * 1024, + .period_bytes_min = 128, + .period_bytes_max = 256 * 1024, .periods_min = 2, - .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, + .periods_max = 16384, }; static const struct snd_pcm_hardware oxygen_ac97_hardware = { .info = SNDRV_PCM_INFO_MMAP | @@ -98,11 +88,11 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = BUFFER_BYTES_MAX, - .period_bytes_min = PERIOD_BYTES_MIN, - .period_bytes_max = BUFFER_BYTES_MAX / 2, + .buffer_bytes_max = 256 * 1024, + .period_bytes_min = 128, + .period_bytes_max = 128 * 1024, .periods_min = 2, - .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, + .periods_max = 2048, }; static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { @@ -165,12 +155,6 @@ static int oxygen_open(struct snd_pcm_substream *substream, if (err < 0) return err; } - if (channel == PCM_MULTICH) { - err = snd_pcm_hw_constraint_minmax - (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000); - if (err < 0) - return err; - } snd_pcm_set_sync(substream); chip->streams[channel] = substream; @@ -533,7 +517,6 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_SUSPEND: pausing = 0; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -680,14 +663,12 @@ int oxygen_pcm_init(struct oxygen *chip) snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - DEFAULT_BUFFER_BYTES_MULTICH, - BUFFER_BYTES_MAX_MULTICH); + 512 * 1024, 2048 * 1024); if (ins) snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - DEFAULT_BUFFER_BYTES, - BUFFER_BYTES_MAX); + 128 * 1024, 256 * 1024); } outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF); @@ -707,8 +688,7 @@ int oxygen_pcm_init(struct oxygen *chip) strcpy(pcm->name, "Digital"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - DEFAULT_BUFFER_BYTES, - BUFFER_BYTES_MAX); + 128 * 1024, 256 * 1024); } if (chip->has_ac97_1) { @@ -738,8 +718,7 @@ int oxygen_pcm_init(struct oxygen *chip) strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - DEFAULT_BUFFER_BYTES, - BUFFER_BYTES_MAX); + 128 * 1024, 256 * 1024); } return 0; } diff --git a/trunk/sound/pci/oxygen/virtuoso.c b/trunk/sound/pci/oxygen/virtuoso.c index 9a2c16bf94e0..7f84fa5deca2 100644 --- a/trunk/sound/pci/oxygen/virtuoso.c +++ b/trunk/sound/pci/oxygen/virtuoso.c @@ -79,7 +79,7 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("Asus AVx00 driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -132,9 +132,6 @@ struct xonar_data { u8 ext_power_int_reg; u8 ext_power_bit; u8 has_power; - u8 pcm1796_oversampling; - u8 cs4398_fm; - u8 cs4362a_fm; }; static void pcm1796_write(struct oxygen *chip, unsigned int codec, @@ -162,14 +159,6 @@ static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); } -static void xonar_enable_output(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - msleep(data->anti_pop_delay); - oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); -} - static void xonar_common_init(struct oxygen *chip) { struct xonar_data *data = chip->model_data; @@ -181,59 +170,32 @@ static void xonar_common_init(struct oxygen *chip) data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) & data->ext_power_bit); } - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_CS53x1_M_MASK | data->output_enable_bit); + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); - xonar_enable_output(chip); -} - -static void update_pcm1796_volume(struct oxygen *chip) -{ - unsigned int i; - - for (i = 0; i < 4; ++i) { - pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); - pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); - } -} - -static void update_pcm1796_mute(struct oxygen *chip) -{ - unsigned int i; - u8 value; - - value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; - if (chip->dac_mute) - value |= PCM1796_MUTE; - for (i = 0; i < 4; ++i) - pcm1796_write(chip, i, 18, value); + msleep(data->anti_pop_delay); + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); + oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); } -static void pcm1796_init(struct oxygen *chip) +static void xonar_d2_init(struct oxygen *chip) { struct xonar_data *data = chip->model_data; unsigned int i; + data->anti_pop_delay = 300; + data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; + for (i = 0; i < 4; ++i) { + pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED | + PCM1796_FMT_24_LJUST | PCM1796_ATLD); pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); - pcm1796_write(chip, i, 20, data->pcm1796_oversampling); + pcm1796_write(chip, i, 20, PCM1796_OS_64); pcm1796_write(chip, i, 21, 0); + pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */ + pcm1796_write(chip, i, 17, 0x0f); } - update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */ - update_pcm1796_volume(chip); -} - -static void xonar_d2_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->anti_pop_delay = 300; - data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; - data->pcm1796_oversampling = PCM1796_OS_64; - - pcm1796_init(chip); oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); @@ -255,47 +217,31 @@ static void xonar_d2x_init(struct oxygen *chip) xonar_d2_init(chip); } -static void update_cs4362a_volumes(struct oxygen *chip) -{ - u8 mute; - - mute = chip->dac_mute ? CS4362A_MUTE : 0; - cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); - cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); - cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); - cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); - cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); - cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); -} - -static void update_cs43xx_volume(struct oxygen *chip) -{ - cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); - cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); - update_cs4362a_volumes(chip); -} - -static void update_cs43xx_mute(struct oxygen *chip) +static void xonar_dx_init(struct oxygen *chip) { - u8 reg; + struct xonar_data *data = chip->model_data; - reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; - if (chip->dac_mute) - reg |= CS4398_MUTE_B | CS4398_MUTE_A; - cs4398_write(chip, 4, reg); - update_cs4362a_volumes(chip); -} + data->anti_pop_delay = 800; + data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; + data->ext_power_reg = OXYGEN_GPI_DATA; + data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->ext_power_bit = GPI_DX_EXT_POWER; -static void cs43xx_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; + oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, + OXYGEN_2WIRE_LENGTH_8 | + OXYGEN_2WIRE_INTERRUPT_MASK | + OXYGEN_2WIRE_SPEED_FAST); /* set CPEN (control port mode) and power down */ cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); /* configure */ - cs4398_write(chip, 2, data->cs4398_fm); + cs4398_write(chip, 2, CS4398_FM_SINGLE | + CS4398_DEM_NONE | CS4398_DIF_LJUST); cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); + cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE); + cs4398_write(chip, 5, 0xfe); + cs4398_write(chip, 6, 0xfe); cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); @@ -303,35 +249,21 @@ static void cs43xx_init(struct oxygen *chip) CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); cs4362a_write(chip, 0x05, 0); - cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); - cs4362a_write(chip, 0x0c, data->cs4362a_fm); - update_cs43xx_volume(chip); - update_cs43xx_mute(chip); + cs4362a_write(chip, 0x06, CS4362A_FM_SINGLE | + CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); + cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE); + cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE); + cs4362a_write(chip, 0x09, CS4362A_FM_SINGLE | + CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); + cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE); + cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE); + cs4362a_write(chip, 0x0c, CS4362A_FM_SINGLE | + CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); + cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE); + cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE); /* clear power down */ cs4398_write(chip, 8, CS4398_CPEN); cs4362a_write(chip, 0x01, CS4362A_CPEN); -} - -static void xonar_dx_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->anti_pop_delay = 800; - data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; - data->ext_power_reg = OXYGEN_GPI_DATA; - data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; - data->ext_power_bit = GPI_DX_EXT_POWER; - data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; - data->cs4362a_fm = CS4362A_FM_SINGLE | - CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; - - oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, - OXYGEN_2WIRE_LENGTH_8 | - OXYGEN_2WIRE_INTERRUPT_MASK | - OXYGEN_2WIRE_SPEED_FAST); - - cs43xx_init(chip); oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); @@ -359,28 +291,37 @@ static void xonar_dx_cleanup(struct oxygen *chip) oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); } -static void xonar_d2_resume(struct oxygen *chip) +static void set_pcm1796_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) { - pcm1796_init(chip); - xonar_enable_output(chip); + unsigned int i; + u8 value; + + value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; + for (i = 0; i < 4; ++i) + pcm1796_write(chip, i, 20, value); } -static void xonar_dx_resume(struct oxygen *chip) +static void update_pcm1796_volume(struct oxygen *chip) { - cs43xx_init(chip); - xonar_enable_output(chip); + unsigned int i; + + for (i = 0; i < 4; ++i) { + pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); + pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); + } } -static void set_pcm1796_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) +static void update_pcm1796_mute(struct oxygen *chip) { - struct xonar_data *data = chip->model_data; unsigned int i; + u8 value; - data->pcm1796_oversampling = - params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; + value = PCM1796_FMT_24_LJUST | PCM1796_ATLD; + if (chip->dac_mute) + value |= PCM1796_MUTE; for (i = 0; i < 4; ++i) - pcm1796_write(chip, i, 20, data->pcm1796_oversampling); + pcm1796_write(chip, i, 18, value); } static void set_cs53x1_params(struct oxygen *chip, @@ -401,24 +342,55 @@ static void set_cs53x1_params(struct oxygen *chip, static void set_cs43xx_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { - struct xonar_data *data = chip->model_data; + u8 fm_cs4398, fm_cs4362a; - data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; - data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + fm_cs4398 = CS4398_DEM_NONE | CS4398_DIF_LJUST; + fm_cs4362a = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; if (params_rate(params) <= 50000) { - data->cs4398_fm |= CS4398_FM_SINGLE; - data->cs4362a_fm |= CS4362A_FM_SINGLE; + fm_cs4398 |= CS4398_FM_SINGLE; + fm_cs4362a |= CS4362A_FM_SINGLE; } else if (params_rate(params) <= 100000) { - data->cs4398_fm |= CS4398_FM_DOUBLE; - data->cs4362a_fm |= CS4362A_FM_DOUBLE; + fm_cs4398 |= CS4398_FM_DOUBLE; + fm_cs4362a |= CS4362A_FM_DOUBLE; } else { - data->cs4398_fm |= CS4398_FM_QUAD; - data->cs4362a_fm |= CS4362A_FM_QUAD; + fm_cs4398 |= CS4398_FM_QUAD; + fm_cs4362a |= CS4362A_FM_QUAD; } - cs4398_write(chip, 2, data->cs4398_fm); - cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); - cs4362a_write(chip, 0x0c, data->cs4362a_fm); + cs4398_write(chip, 2, fm_cs4398); + cs4362a_write(chip, 0x06, fm_cs4362a); + cs4362a_write(chip, 0x09, fm_cs4362a); + cs4362a_write(chip, 0x0c, fm_cs4362a); +} + +static void update_cs4362a_volumes(struct oxygen *chip) +{ + u8 mute; + + mute = chip->dac_mute ? CS4362A_MUTE : 0; + cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); + cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); + cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); + cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); + cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); + cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); +} + +static void update_cs43xx_volume(struct oxygen *chip) +{ + cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); + cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); + update_cs4362a_volumes(chip); +} + +static void update_cs43xx_mute(struct oxygen *chip) +{ + u8 reg; + + reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; + if (chip->dac_mute) + reg |= CS4398_MUTE_B | CS4398_MUTE_A; + cs4398_write(chip, 4, reg); + update_cs4362a_volumes(chip); } static void xonar_gpio_changed(struct oxygen *chip) @@ -563,8 +535,6 @@ static const struct oxygen_model xonar_models[] = { .control_filter = xonar_d2_control_filter, .mixer_init = xonar_mixer_init, .cleanup = xonar_cleanup, - .suspend = xonar_cleanup, - .resume = xonar_d2_resume, .set_dac_params = set_pcm1796_params, .set_adc_params = set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -593,8 +563,6 @@ static const struct oxygen_model xonar_models[] = { .control_filter = xonar_d2_control_filter, .mixer_init = xonar_mixer_init, .cleanup = xonar_cleanup, - .suspend = xonar_cleanup, - .resume = xonar_d2_resume, .set_dac_params = set_pcm1796_params, .set_adc_params = set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -624,8 +592,6 @@ static const struct oxygen_model xonar_models[] = { .control_filter = xonar_dx_control_filter, .mixer_init = xonar_dx_mixer_init, .cleanup = xonar_dx_cleanup, - .suspend = xonar_dx_cleanup, - .resume = xonar_dx_resume, .set_dac_params = set_cs43xx_params, .set_adc_params = set_cs53x1_params, .update_dac_volume = update_cs43xx_volume, @@ -670,10 +636,6 @@ static struct pci_driver xonar_driver = { .id_table = xonar_ids, .probe = xonar_probe, .remove = __devexit_p(oxygen_pci_remove), -#ifdef CONFIG_PM - .suspend = oxygen_pci_suspend, - .resume = oxygen_pci_resume, -#endif }; static int __init alsa_card_xonar_init(void) diff --git a/trunk/sound/pci/pcxhr/pcxhr.c b/trunk/sound/pci/pcxhr/pcxhr.c index 2c7e25336795..7fdcdc8c6b64 100644 --- a/trunk/sound/pci/pcxhr/pcxhr.c +++ b/trunk/sound/pci/pcxhr/pcxhr.c @@ -516,7 +516,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) int capture_mask = 0; int playback_mask = 0; -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT struct timeval my_tv1, my_tv2; do_gettimeofday(&my_tv1); #endif @@ -623,7 +623,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) mutex_unlock(&mgr->setup_mutex); -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT do_gettimeofday(&my_tv2); snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); diff --git a/trunk/sound/pci/pcxhr/pcxhr_core.c b/trunk/sound/pci/pcxhr/pcxhr_core.c index abe5c59b72df..78aa81feaa4a 100644 --- a/trunk/sound/pci/pcxhr/pcxhr_core.c +++ b/trunk/sound/pci/pcxhr/pcxhr_core.c @@ -473,7 +473,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = { [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, }; -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT static char* cmd_names[] = { [CMD_VERSION] = "CMD_VERSION", [CMD_SUPPORTED] = "CMD_SUPPORTED", @@ -549,7 +549,7 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) } } } -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT if (rmh->cmd_idx < CMD_LAST_INDEX) snd_printdd(" stat[%d]=%x\n", i, data); #endif @@ -597,7 +597,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data |= 0x008000; /* MASK_MORE_THAN_1_WORD_COMMAND */ else data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT if (rmh->cmd_idx < CMD_LAST_INDEX) snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); #endif @@ -624,7 +624,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) for (i=1; i < rmh->cmd_len; i++) { /* send other words */ data = rmh->cmd[i]; -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT if (rmh->cmd_idx < CMD_LAST_INDEX) snd_printdd(" cmd[%d]=%x\n", i, data); #endif @@ -847,7 +847,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m int state, i, err; int audio_mask; -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT struct timeval my_tv1, my_tv2; do_gettimeofday(&my_tv1); #endif @@ -894,7 +894,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m if (err) return err; } -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT do_gettimeofday(&my_tv2); snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n", (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); @@ -951,7 +951,7 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, enum pcxhr_async_err_src err_src, int pipe, int is_capture) { -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT static char* err_src_name[] = { [PCXHR_ERR_PIPE] = "Pipe", [PCXHR_ERR_STREAM] = "Stream", @@ -1169,7 +1169,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) mgr->dsp_time_last, dsp_time_new); mgr->dsp_time_err++; } -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT if (dsp_time_diff == 0) snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) @@ -1208,7 +1208,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) mgr->src_it_dsp = reg; tasklet_hi_schedule(&mgr->msg_taskq); } -#ifdef CONFIG_SND_DEBUG_VERBOSE +#ifdef CONFIG_SND_DEBUG_DETECT if (reg & PCXHR_FATAL_DSP_ERR) snd_printdd("FATAL DSP ERROR : %x\n", reg); #endif diff --git a/trunk/sound/pci/trident/trident_main.c b/trunk/sound/pci/trident/trident_main.c index a69b4206c69e..bbcee2c09ae4 100644 --- a/trunk/sound/pci/trident/trident_main.c +++ b/trunk/sound/pci/trident/trident_main.c @@ -1590,10 +1590,7 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream, if (spdif_flag) { if (trident->device != TRIDENT_DEVICE_ID_SI7018) { outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); - val = trident->spdif_pcm_ctrl; - if (!go) - val &= ~(0x28); - outb(val, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); + outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); } else { outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS)); val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN; diff --git a/trunk/sound/pci/trident/trident_memory.c b/trunk/sound/pci/trident/trident_memory.c index 3fd7f1b29b0f..df9b487fa17e 100644 --- a/trunk/sound/pci/trident/trident_memory.c +++ b/trunk/sound/pci/trident/trident_memory.c @@ -310,3 +310,181 @@ int snd_trident_free_pages(struct snd_trident *trident, mutex_unlock(&hdr->block_mutex); return 0; } + + +/*---------------------------------------------------------------- + * memory allocation using multiple pages (for synth) + *---------------------------------------------------------------- + * Unlike the DMA allocation above, non-contiguous pages are + * assigned to TLB. + *----------------------------------------------------------------*/ + +/* + */ +static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk); +static int synth_free_pages(struct snd_trident *hw, struct snd_util_memblk *blk); + +/* + * allocate a synth sample area + */ +struct snd_util_memblk * +snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size) +{ + struct snd_util_memblk *blk; + struct snd_util_memhdr *hdr = hw->tlb.memhdr; + + mutex_lock(&hdr->block_mutex); + blk = __snd_util_mem_alloc(hdr, size); + if (blk == NULL) { + mutex_unlock(&hdr->block_mutex); + return NULL; + } + if (synth_alloc_pages(hw, blk)) { + __snd_util_mem_free(hdr, blk); + mutex_unlock(&hdr->block_mutex); + return NULL; + } + mutex_unlock(&hdr->block_mutex); + return blk; +} + +EXPORT_SYMBOL(snd_trident_synth_alloc); + +/* + * free a synth sample area + */ +int +snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk) +{ + struct snd_util_memhdr *hdr = hw->tlb.memhdr; + + mutex_lock(&hdr->block_mutex); + synth_free_pages(hw, blk); + __snd_util_mem_free(hdr, blk); + mutex_unlock(&hdr->block_mutex); + return 0; +} + +EXPORT_SYMBOL(snd_trident_synth_free); + +/* + * reset TLB entry and free kernel page + */ +static void clear_tlb(struct snd_trident *trident, int page) +{ + void *ptr = page_to_ptr(trident, page); + dma_addr_t addr = page_to_addr(trident, page); + set_silent_tlb(trident, page); + if (ptr) { + struct snd_dma_buffer dmab; + dmab.dev.type = SNDRV_DMA_TYPE_DEV; + dmab.dev.dev = snd_dma_pci_data(trident->pci); + dmab.area = ptr; + dmab.addr = addr; + dmab.bytes = ALIGN_PAGE_SIZE; + snd_dma_free_pages(&dmab); + } +} + +/* check new allocation range */ +static void get_single_page_range(struct snd_util_memhdr *hdr, + struct snd_util_memblk *blk, + int *first_page_ret, int *last_page_ret) +{ + struct list_head *p; + struct snd_util_memblk *q; + int first_page, last_page; + first_page = firstpg(blk); + if ((p = blk->list.prev) != &hdr->block) { + q = list_entry(p, struct snd_util_memblk, list); + if (lastpg(q) == first_page) + first_page++; /* first page was already allocated */ + } + last_page = lastpg(blk); + if ((p = blk->list.next) != &hdr->block) { + q = list_entry(p, struct snd_util_memblk, list); + if (firstpg(q) == last_page) + last_page--; /* last page was already allocated */ + } + *first_page_ret = first_page; + *last_page_ret = last_page; +} + +/* + * allocate kernel pages and assign them to TLB + */ +static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk) +{ + int page, first_page, last_page; + struct snd_dma_buffer dmab; + + firstpg(blk) = get_aligned_page(blk->offset); + lastpg(blk) = get_aligned_page(blk->offset + blk->size - 1); + get_single_page_range(hw->tlb.memhdr, blk, &first_page, &last_page); + + /* allocate a kernel page for each Trident page - + * fortunately Trident page size and kernel PAGE_SIZE is identical! + */ + for (page = first_page; page <= last_page; page++) { + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(hw->pci), + ALIGN_PAGE_SIZE, &dmab) < 0) + goto __fail; + if (! is_valid_page(dmab.addr)) { + snd_dma_free_pages(&dmab); + goto __fail; + } + set_tlb_bus(hw, page, (unsigned long)dmab.area, dmab.addr); + } + return 0; + +__fail: + /* release allocated pages */ + last_page = page - 1; + for (page = first_page; page <= last_page; page++) + clear_tlb(hw, page); + + return -ENOMEM; +} + +/* + * free pages + */ +static int synth_free_pages(struct snd_trident *trident, struct snd_util_memblk *blk) +{ + int page, first_page, last_page; + + get_single_page_range(trident->tlb.memhdr, blk, &first_page, &last_page); + for (page = first_page; page <= last_page; page++) + clear_tlb(trident, page); + + return 0; +} + +/* + * copy_from_user(blk + offset, data, size) + */ +int snd_trident_synth_copy_from_user(struct snd_trident *trident, + struct snd_util_memblk *blk, + int offset, const char __user *data, int size) +{ + int page, nextofs, end_offset, temp, temp1; + + offset += blk->offset; + end_offset = offset + size; + page = get_aligned_page(offset) + 1; + do { + nextofs = aligned_page_offset(page); + temp = nextofs - offset; + temp1 = end_offset - offset; + if (temp1 < temp) + temp = temp1; + if (copy_from_user(offset_ptr(trident, offset), data, temp)) + return -EFAULT; + offset = nextofs; + data += temp; + page++; + } while (offset < end_offset); + return 0; +} + +EXPORT_SYMBOL(snd_trident_synth_copy_from_user); diff --git a/trunk/sound/pci/via82xx.c b/trunk/sound/pci/via82xx.c index 6781be9e3078..b585cc3e4c47 100644 --- a/trunk/sound/pci/via82xx.c +++ b/trunk/sound/pci/via82xx.c @@ -1756,12 +1756,6 @@ static struct ac97_quirk ac97_quirks[] = { .name = "ECS L7VMM2", .type = AC97_TUNE_HP_ONLY }, - { - .subvendor = 0x1019, - .subdevice = 0x1841, - .name = "ECS K7VTA3", - .type = AC97_TUNE_HP_ONLY - }, { .subvendor = 0x1849, .subdevice = 0x3059, diff --git a/trunk/sound/pci/ymfpci/ymfpci_main.c b/trunk/sound/pci/ymfpci/ymfpci_main.c index 7129df5f315b..29b3056c5109 100644 --- a/trunk/sound/pci/ymfpci/ymfpci_main.c +++ b/trunk/sound/pci/ymfpci/ymfpci_main.c @@ -2205,7 +2205,6 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip) for (reg = 0x80; reg < 0xc0; reg += 4) snd_ymfpci_writel(chip, reg, 0); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); - snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); @@ -2325,7 +2324,6 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state) chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); - snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); snd_ymfpci_disable_dsp(chip); pci_disable_device(pci); pci_save_state(pci); diff --git a/trunk/sound/pcmcia/Kconfig b/trunk/sound/pcmcia/Kconfig index 7fbb190adf6d..c9fa1a2bc58b 100644 --- a/trunk/sound/pcmcia/Kconfig +++ b/trunk/sound/pcmcia/Kconfig @@ -1,16 +1,11 @@ # ALSA PCMCIA drivers -menuconfig SND_PCMCIA - bool "PCMCIA sound devices" - depends on PCMCIA - default y - help - Support for sound devices connected via the PCMCIA bus. - -if SND_PCMCIA && PCMCIA +menu "PCMCIA devices" + depends on SND!=n && PCMCIA config SND_VXPOCKET tristate "Digigram VXpocket" + depends on SND && PCMCIA select SND_VX_LIB help Say Y here to include support for Digigram VXpocket and @@ -21,6 +16,7 @@ config SND_VXPOCKET config SND_PDAUDIOCF tristate "Sound Core PDAudioCF" + depends on SND && PCMCIA select SND_PCM help Say Y here to include support for Sound Core PDAudioCF @@ -29,5 +25,4 @@ config SND_PDAUDIOCF To compile this driver as a module, choose M here: the module will be called snd-pdaudiocf. -endif # SND_PCMCIA - +endmenu diff --git a/trunk/sound/pcmcia/vx/vxp_ops.c b/trunk/sound/pcmcia/vx/vxp_ops.c index 99bf2a65a6f5..157b0b539f39 100644 --- a/trunk/sound/pcmcia/vx/vxp_ops.c +++ b/trunk/sound/pcmcia/vx/vxp_ops.c @@ -151,7 +151,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware * unsigned int i; int c; int regCSUER, regRUER; - const unsigned char *image; + unsigned char *image; unsigned char data; /* Switch to programmation mode */ diff --git a/trunk/sound/ppc/Kconfig b/trunk/sound/ppc/Kconfig index 777de2b17178..cacb0b136883 100644 --- a/trunk/sound/ppc/Kconfig +++ b/trunk/sound/ppc/Kconfig @@ -1,17 +1,17 @@ # ALSA PowerMac drivers -menuconfig SND_PPC - bool "PowerPC sound devices" - depends on PPC64 || PPC32 - default y - help - Support for sound devices specific to PowerPC architectures. +menu "ALSA PowerMac devices" + depends on SND!=n && PPC + +comment "ALSA PowerMac requires I2C" + depends on SND && I2C=n -if SND_PPC +comment "ALSA PowerMac requires INPUT" + depends on SND && INPUT=n config SND_POWERMAC tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" - depends on I2C && INPUT && PPC_PMAC + depends on SND && I2C && INPUT && PPC_PMAC select SND_PCM help Say Y here to include support for the integrated sound device. @@ -32,9 +32,14 @@ config SND_POWERMAC_AUTO_DRC Note that you can turn on/off DRC manually even without this option. +endmenu + +menu "ALSA PowerPC devices" + depends on SND!=n && ( PPC64 || PPC32 ) + config SND_PS3 tristate "PS3 Audio support" - depends on PS3_PS3AV + depends on SND && PS3_PS3AV select SND_PCM default m help @@ -47,5 +52,4 @@ config SND_PS3_DEFAULT_START_DELAY int "Startup delay time in ms" depends on SND_PS3 default "2000" - -endif # SND_PPC +endmenu diff --git a/trunk/sound/ppc/daca.c b/trunk/sound/ppc/daca.c index 8a5b29031933..ca9452901a50 100644 --- a/trunk/sound/ppc/daca.c +++ b/trunk/sound/ppc/daca.c @@ -249,7 +249,9 @@ int __init snd_pmac_daca_init(struct snd_pmac *chip) int i, err; struct pmac_daca *mix; +#ifdef CONFIG_KMOD request_module("i2c-powermac"); +#endif /* CONFIG_KMOD */ mix = kzalloc(sizeof(*mix), GFP_KERNEL); if (! mix) diff --git a/trunk/sound/ppc/tumbler.c b/trunk/sound/ppc/tumbler.c index 009df8dd37a8..3f8d7164cef9 100644 --- a/trunk/sound/ppc/tumbler.c +++ b/trunk/sound/ppc/tumbler.c @@ -1350,7 +1350,9 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip) struct device_node *tas_node, *np; char *chipname; +#ifdef CONFIG_KMOD request_module("i2c-powermac"); +#endif /* CONFIG_KMOD */ mix = kzalloc(sizeof(*mix), GFP_KERNEL); if (! mix) diff --git a/trunk/sound/sh/Kconfig b/trunk/sound/sh/Kconfig index cfc143985802..b7e08ef22a94 100644 --- a/trunk/sound/sh/Kconfig +++ b/trunk/sound/sh/Kconfig @@ -1,22 +1,14 @@ # ALSA SH drivers -menuconfig SND_SUPERH - bool "SUPERH sound devices" - depends on SUPERH - default y - help - Support for sound devices specific to SUPERH architectures. - Drivers that are implemented on ASoC can be found in - "ALSA for SoC audio support" section. - -if SND_SUPERH +menu "SUPERH devices" + depends on SND!=n && SUPERH config SND_AICA tristate "Dreamcast Yamaha AICA sound" - depends on SH_DREAMCAST + depends on SH_DREAMCAST && SND select SND_PCM help ALSA Sound driver for the SEGA Dreamcast console. -endif # SND_SUPERH +endmenu diff --git a/trunk/sound/soc/Kconfig b/trunk/sound/soc/Kconfig index f743530add8f..18f28ac4bfe8 100644 --- a/trunk/sound/soc/Kconfig +++ b/trunk/sound/soc/Kconfig @@ -2,8 +2,15 @@ # SoC audio configuration # -menuconfig SND_SOC +menu "System on Chip audio support" + depends on SND!=n + +config SND_SOC_AC97_BUS + bool + +config SND_SOC tristate "ALSA for SoC audio support" + depends on SND select SND_PCM ---help--- @@ -16,15 +23,8 @@ menuconfig SND_SOC This ASoC audio support can also be built as a module. If so, the module will be called snd-soc-core. -if SND_SOC - -config SND_SOC_AC97_BUS - bool - # All the supported Soc's -source "sound/soc/at32/Kconfig" source "sound/soc/at91/Kconfig" -source "sound/soc/au1x/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" source "sound/soc/sh/Kconfig" @@ -35,5 +35,4 @@ source "sound/soc/omap/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" -endif # SND_SOC - +endmenu diff --git a/trunk/sound/soc/Makefile b/trunk/sound/soc/Makefile index 933a66d30804..782db2127108 100644 --- a/trunk/sound/soc/Makefile +++ b/trunk/sound/soc/Makefile @@ -1,5 +1,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ -obj-$(CONFIG_SND_SOC) += omap/ au1x/ +obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ omap/ diff --git a/trunk/sound/soc/at32/Kconfig b/trunk/sound/soc/at32/Kconfig deleted file mode 100644 index b0765e86c085..000000000000 --- a/trunk/sound/soc/at32/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config SND_AT32_SOC - tristate "SoC Audio for the Atmel AT32 System-on-a-Chip" - depends on AVR32 && SND_SOC - help - Say Y or M if you want to add support for codecs attached to - the AT32 SSC interface. You will also need to - to select the audio interfaces to support below. - - -config SND_AT32_SOC_SSC - tristate - - - -config SND_AT32_SOC_PLAYPAQ - tristate "SoC Audio support for PlayPaq with WM8510" - depends on SND_AT32_SOC && BOARD_PLAYPAQ - select SND_AT32_SOC_SSC - select SND_SOC_WM8510 - help - Say Y or M here if you want to add support for SoC audio - on the LRS PlayPaq. - - - -config SND_AT32_SOC_PLAYPAQ_SLAVE - bool "Run CODEC on PlayPaq in slave mode" - depends on SND_AT32_SOC_PLAYPAQ - default n - help - Say Y if you want to run with the AT32 SSC generating the BCLK - and FRAME signals on the PlayPaq. Unless you want to play - with the AT32 as the SSC master, you probably want to say N here, - as this will give you better sound quality. diff --git a/trunk/sound/soc/at32/Makefile b/trunk/sound/soc/at32/Makefile deleted file mode 100644 index c03e55ececeb..000000000000 --- a/trunk/sound/soc/at32/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# AT32 Platform Support -snd-soc-at32-objs := at32-pcm.o -snd-soc-at32-ssc-objs := at32-ssc.o - -obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o -obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o - -# AT32 Machine Support -snd-soc-playpaq-objs := playpaq_wm8510.o - -obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/trunk/sound/soc/at32/at32-pcm.c b/trunk/sound/soc/at32/at32-pcm.c deleted file mode 100644 index 435f1daf177c..000000000000 --- a/trunk/sound/soc/at32/at32-pcm.c +++ /dev/null @@ -1,491 +0,0 @@ -/* sound/soc/at32/at32-pcm.c - * ASoC PCM interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Note that this is basically a port of the sound/soc/at91-pcm.c to - * the AVR32 kernel. Thanks to Frank Mandarino for that code. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "at32-pcm.h" - - - -/*--------------------------------------------------------------------------*\ - * Hardware definition -\*--------------------------------------------------------------------------*/ -/* TODO: These values were taken from the AT91 platform driver, check - * them against real values for AT32 - */ -static const struct snd_pcm_hardware at32_pcm_hardware = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE), - - .formats = SNDRV_PCM_FMTBIT_S16, - .period_bytes_min = 32, - .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */ - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - - - -/*--------------------------------------------------------------------------*\ - * Data types -\*--------------------------------------------------------------------------*/ -struct at32_runtime_data { - struct at32_pcm_dma_params *params; - dma_addr_t dma_buffer; /* physical address of DMA buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - - dma_addr_t period_ptr; /* physical address of next period */ - int periods; /* period index of period_ptr */ - - /* Save PDC registers (for power management) */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - - - -/*--------------------------------------------------------------------------*\ - * Helper functions -\*--------------------------------------------------------------------------*/ -static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *dmabuf = &substream->dma_buffer; - size_t size = at32_pcm_hardware.buffer_bytes_max; - - dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; - dmabuf->dev.dev = pcm->card->dev; - dmabuf->private_data = NULL; - dmabuf->area = dma_alloc_coherent(pcm->card->dev, size, - &dmabuf->addr, GFP_KERNEL); - pr_debug("at32_pcm: preallocate_dma_buffer: " - "area=%p, addr=%p, size=%ld\n", - (void *)dmabuf->area, (void *)dmabuf->addr, size); - - if (!dmabuf->area) - return -ENOMEM; - - dmabuf->bytes = size; - return 0; -} - - - -/*--------------------------------------------------------------------------*\ - * ISR -\*--------------------------------------------------------------------------*/ -static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct at32_runtime_data *prtd = rtd->private_data; - struct at32_pcm_dma_params *params = prtd->params; - static int count; - - count++; - if (ssc_sr & params->mask->ssc_endbuf) { - pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "underrun" : "overrun", params->name, ssc_sr, count); - - /* re-start the PDC */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - } - - - if (ssc_sr & params->mask->ssc_endx) { - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - - snd_pcm_period_elapsed(substream); -} - - - -/*--------------------------------------------------------------------------*\ - * PCM operations -\*--------------------------------------------------------------------------*/ -static int at32_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params - */ - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = rtd->dai->cpu_dai->dma_data; - prtd->params->dma_intr_handler = at32_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - pr_debug("hw_params: DMA for %s initialized " - "(dma_bytes=%ld, period_size=%ld)\n", - prtd->params->name, runtime->dma_bytes, prtd->period_size); - - return 0; -} - - - -static int at32_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct at32_runtime_data *prtd = substream->runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - - - -static int at32_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct at32_runtime_data *prtd = substream->runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; - - ssc_writex(params->ssc->regs, SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - - return 0; -} - - -static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct at32_runtime_data *prtd = rtd->private_data; - struct at32_pcm_dma_params *params = prtd->params; - int ret = 0; - - pr_debug("at32_pcm_trigger: buffer_size = %ld, " - "dma_area = %p, dma_bytes = %ld\n", - rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - pr_debug("trigger: period_ptr=%lx, xpr=%x, " - "xcr=%d, xnpr=%x, xncr=%d\n", - (unsigned long)prtd->period_ptr, - ssc_readx(params->ssc->regs, params->pdc->xpr), - ssc_readx(params->ssc->regs, params->pdc->xcr), - ssc_readx(params->ssc->regs, params->pdc->xnpr), - ssc_readx(params->ssc->regs, params->pdc->xncr)); - - ssc_writex(params->ssc->regs, SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_enable); - - pr_debug("sr=%x, imr=%x\n", - ssc_readx(params->ssc->regs, SSC_SR), - ssc_readx(params->ssc->regs, SSC_IER)); - break; /* SNDRV_PCM_TRIGGER_START */ - - - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - break; - - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - - - -static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd = runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - - return x; -} - - - -static int at32_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - -out: - return ret; -} - - - -static int at32_pcm_close(struct snd_pcm_substream *substream) -{ - struct at32_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - - -static int at32_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - return remap_pfn_range(vma, vma->vm_start, - substream->dma_buffer.addr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); -} - - - -static struct snd_pcm_ops at32_pcm_ops = { - .open = at32_pcm_open, - .close = at32_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = at32_pcm_hw_params, - .hw_free = at32_pcm_hw_free, - .prepare = at32_pcm_prepare, - .trigger = at32_pcm_trigger, - .pointer = at32_pcm_pointer, - .mmap = at32_pcm_mmap, -}; - - - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ -static u64 at32_pcm_dmamask = 0xffffffff; - -static int at32_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &at32_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = at32_pcm_preallocate_dma_buffer( - pcm, SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n"); - ret = at32_pcm_preallocate_dma_buffer( - pcm, SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - - -out: - return ret; -} - - - -static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (substream == NULL) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - dma_free_coherent(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - - - -#ifdef CONFIG_PM -static int at32_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at32_runtime_data *prtd; - struct at32_pcm_dma_params *params; - - if (runtime == NULL) - return 0; - prtd = runtime->private_data; - params = prtd->params; - - /* Disable the PDC and save the PDC registers */ - ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); - prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); - prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); - prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); - - return 0; -} - - - -static int at32_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at32_runtime_data *prtd; - struct at32_pcm_dma_params *params; - - if (runtime == NULL) - return 0; - prtd = runtime->private_data; - params = prtd->params; - - /* Restore the PDC registers and enable the PDC */ - ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); - ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); - ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); - ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); - - ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else /* CONFIG_PM */ -# define at32_pcm_suspend NULL -# define at32_pcm_resume NULL -#endif /* CONFIG_PM */ - - - -struct snd_soc_platform at32_soc_platform = { - .name = "at32-audio", - .pcm_ops = &at32_pcm_ops, - .pcm_new = at32_pcm_new, - .pcm_free = at32_pcm_free_dma_buffers, - .suspend = at32_pcm_suspend, - .resume = at32_pcm_resume, -}; -EXPORT_SYMBOL_GPL(at32_soc_platform); - - - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("Atmel AT32 PCM module"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/at32/at32-pcm.h b/trunk/sound/soc/at32/at32-pcm.h deleted file mode 100644 index 2a52430417da..000000000000 --- a/trunk/sound/soc/at32/at32-pcm.h +++ /dev/null @@ -1,79 +0,0 @@ -/* sound/soc/at32/at32-pcm.h - * ASoC PCM interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __SOUND_SOC_AT32_AT32_PCM_H -#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__ - -#include - - -/* - * Registers and status bits that are required by the PCM driver - * TODO: Is ptcr really used? - */ -struct at32_pdc_regs { - u32 xpr; /* PDC RX/TX pointer */ - u32 xcr; /* PDC RX/TX counter */ - u32 xnpr; /* PDC next RX/TX pointer */ - u32 xncr; /* PDC next RX/TX counter */ - u32 ptcr; /* PDC transfer control */ -}; - - - -/* - * SSC mask info - */ -struct at32_ssc_mask { - u32 ssc_enable; /* SSC RX/TX enable */ - u32 ssc_disable; /* SSC RX/TX disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFF or RXBUFF */ - u32 pdc_enable; /* PDC RX/TX enable */ - u32 pdc_disable; /* PDC RX/TX disable */ -}; - - - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -struct at32_pcm_dma_params { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - struct ssc_device *ssc; /* SSC device for stream */ - struct at32_pdc_regs *pdc; /* PDC register info */ - struct at32_ssc_mask *mask; /* SSC mask info */ - struct snd_pcm_substream *substream; - void (*dma_intr_handler) (u32, struct snd_pcm_substream *); -}; - - - -/* - * The AT32 ASoC platform driver - */ -extern struct snd_soc_platform at32_soc_platform; - - - -/* - * SSC register access (since ssc_writel() / ssc_readl() require literal name) - */ -#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) -#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) - -#endif /* __SOUND_SOC_AT32_AT32_PCM_H */ diff --git a/trunk/sound/soc/at32/at32-ssc.c b/trunk/sound/soc/at32/at32-ssc.c deleted file mode 100644 index 4ef6492c902e..000000000000 --- a/trunk/sound/soc/at32/at32-ssc.c +++ /dev/null @@ -1,849 +0,0 @@ -/* sound/soc/at32/at32-ssc.c - * ASoC platform driver for AT32 using SSC as DAI - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Note that this is basically a port of the sound/soc/at91-ssc.c to - * the AVR32 kernel. Thanks to Frank Mandarino for that code. - */ - -/* #define DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "at32-pcm.h" -#include "at32-ssc.h" - - - -/*-------------------------------------------------------------------------*\ - * Constants -\*-------------------------------------------------------------------------*/ -#define NUM_SSC_DEVICES 3 - -/* - * SSC direction masks - */ -#define SSC_DIR_MASK_UNUSED 0 -#define SSC_DIR_MASK_PLAYBACK 1 -#define SSC_DIR_MASK_CAPTURE 2 - -/* - * SSC register values that Atmel left out of . These - * are expected to be used with SSC_BF - */ -/* START bit field values */ -#define SSC_START_CONTINUOUS 0 -#define SSC_START_TX_RX 1 -#define SSC_START_LOW_RF 2 -#define SSC_START_HIGH_RF 3 -#define SSC_START_FALLING_RF 4 -#define SSC_START_RISING_RF 5 -#define SSC_START_LEVEL_RF 6 -#define SSC_START_EDGE_RF 7 -#define SSS_START_COMPARE_0 8 - -/* CKI bit field values */ -#define SSC_CKI_FALLING 0 -#define SSC_CKI_RISING 1 - -/* CKO bit field values */ -#define SSC_CKO_NONE 0 -#define SSC_CKO_CONTINUOUS 1 -#define SSC_CKO_TRANSFER 2 - -/* CKS bit field values */ -#define SSC_CKS_DIV 0 -#define SSC_CKS_CLOCK 1 -#define SSC_CKS_PIN 2 - -/* FSEDGE bit field values */ -#define SSC_FSEDGE_POSITIVE 0 -#define SSC_FSEDGE_NEGATIVE 1 - -/* FSOS bit field values */ -#define SSC_FSOS_NONE 0 -#define SSC_FSOS_NEGATIVE 1 -#define SSC_FSOS_POSITIVE 2 -#define SSC_FSOS_LOW 3 -#define SSC_FSOS_HIGH 4 -#define SSC_FSOS_TOGGLE 5 - -#define START_DELAY 1 - - - -/*-------------------------------------------------------------------------*\ - * Module data -\*-------------------------------------------------------------------------*/ -/* - * SSC PDC registered required by the PCM DMA engine - */ -static struct at32_pdc_regs pdc_tx_reg = { - .xpr = SSC_PDC_TPR, - .xcr = SSC_PDC_TCR, - .xnpr = SSC_PDC_TNPR, - .xncr = SSC_PDC_TNCR, -}; - - - -static struct at32_pdc_regs pdc_rx_reg = { - .xpr = SSC_PDC_RPR, - .xcr = SSC_PDC_RCR, - .xnpr = SSC_PDC_RNPR, - .xncr = SSC_PDC_RNCR, -}; - - - -/* - * SSC and PDC status bits for transmit and receive - */ -static struct at32_ssc_mask ssc_tx_mask = { - .ssc_enable = SSC_BIT(CR_TXEN), - .ssc_disable = SSC_BIT(CR_TXDIS), - .ssc_endx = SSC_BIT(SR_ENDTX), - .ssc_endbuf = SSC_BIT(SR_TXBUFE), - .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN), - .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS), -}; - - - -static struct at32_ssc_mask ssc_rx_mask = { - .ssc_enable = SSC_BIT(CR_RXEN), - .ssc_disable = SSC_BIT(CR_RXDIS), - .ssc_endx = SSC_BIT(SR_ENDRX), - .ssc_endbuf = SSC_BIT(SR_RXBUFF), - .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN), - .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS), -}; - - - -/* - * DMA parameters for each SSC - */ -static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - { - { - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, - { - { - .name = "SSC1 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, - { - { - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, -}; - - - -static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -}; - - - - -/*-------------------------------------------------------------------------*\ - * ISR -\*-------------------------------------------------------------------------*/ -/* - * SSC interrupt handler. Passes PDC interrupts to the DMA interrupt - * handler in the PCM driver. - */ -static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id) -{ - struct at32_ssc_info *ssc_p = dev_id; - struct at32_pcm_dma_params *dma_params; - u32 ssc_sr; - u32 ssc_substream_mask; - int i; - - ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) & - ssc_readl(ssc_p->ssc->regs, IMR)); - - /* - * Loop through substreams attached to this SSC. If a DMA-related - * interrupt occured on that substream, call the DMA interrupt - * handler function, if one has been registered in the dma_param - * structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if ((dma_params != NULL) && - (dma_params->dma_intr_handler != NULL)) { - ssc_substream_mask = (dma_params->mask->ssc_endx | - dma_params->mask->ssc_endbuf); - if (ssc_sr & ssc_substream_mask) { - dma_params->dma_intr_handler(ssc_sr, - dma_params-> - substream); - } - } - } - - - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*\ - * DAI functions -\*-------------------------------------------------------------------------*/ -/* - * Startup. Only that one substream allowed in each direction. - */ -static int at32_ssc_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - int dir_mask; - - dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE); - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - - - -/* - * Shutdown. Clear DMA parameters and shutdown the SSC if there - * are no other substreams open. - */ -static void at32_ssc_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at32_pcm_dma_params *dma_params; - int dir_mask; - - dma_params = ssc_p->dma_params[substream->stream]; - - if (dma_params != NULL) { - ssc_writel(dma_params->ssc->regs, CR, - dma_params->mask->ssc_disable); - pr_debug("%s disabled SSC_SR=0x%08x\n", - (substream->stream ? "receiver" : "transmit"), - ssc_readl(ssc_p->ssc->regs, SR)); - - dma_params->ssc = NULL; - dma_params->substream = NULL; - ssc_p->dma_params[substream->stream] = NULL; - } - - - dir_mask = 1 << substream->stream; - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - /* Shutdown the SSC clock */ - pr_debug("at32-ssc: Stopping user %d clock\n", - ssc_p->ssc->user); - clk_disable(ssc_p->ssc->clk); - - if (ssc_p->initialized) { - free_irq(ssc_p->ssc->irq, ssc_p); - ssc_p->initialized = 0; - } - - /* Reset the SSC */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - /* clear the SSC dividers */ - ssc_p->cmr_div = 0; - ssc_p->tcmr_period = 0; - ssc_p->rcmr_period = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - - - -/* - * Set the SSC system clock rate - */ -static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - /* TODO: What the heck do I do here? */ - return 0; -} - - - -/* - * Record DAI format for use by hw_params() - */ -static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - ssc_p->daifmt = fmt; - return 0; -} - - - -/* - * Record SSC clock dividers for use in hw_params() - */ -static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - switch (div_id) { - case AT32_SSC_CMR_DIV: - /* - * The same master clock divider is used for both - * transmit and receive, so if a value has already - * been set, it must match this value - */ - if (ssc_p->cmr_div == 0) - ssc_p->cmr_div = div; - else if (div != ssc_p->cmr_div) - return -EBUSY; - break; - - case AT32_SSC_TCMR_PERIOD: - ssc_p->tcmr_period = div; - break; - - case AT32_SSC_RCMR_PERIOD: - ssc_p->rcmr_period = div; - break; - - default: - return -EINVAL; - } - - return 0; -} - - - -/* - * Configure the SSC - */ -static int at32_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int id = rtd->dai->cpu_dai->id; - struct at32_ssc_info *ssc_p = &ssc_info[id]; - struct at32_pcm_dma_params *dma_params; - int channels, bits; - u32 tfmr, rfmr, tcmr, rcmr; - int start_event; - int ret; - - - /* - * Currently, there is only one set of dma_params for each direction. - * If more are added, this code will have to be changed to select - * the proper set - */ - dma_params = &ssc_dma_params[id][substream->stream]; - dma_params->ssc = ssc_p->ssc; - dma_params->substream = substream; - - ssc_p->dma_params[substream->stream] = dma_params; - - - /* - * The cpu_dai->dma_data field is only used to communicate the - * appropriate DMA parameters to the PCM driver's hw_params() - * function. It should not be used for other purposes as it - * is common to all substreams. - */ - rtd->dai->cpu_dai->dma_data = dma_params; - - channels = params_channels(params); - - - /* - * Determine sample size in bits and the PDC increment - */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - bits = 8; - dma_params->pdc_xfer_size = 1; - break; - - case SNDRV_PCM_FORMAT_S16: - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - - case SNDRV_PCM_FORMAT_S24: - bits = 24; - dma_params->pdc_xfer_size = 4; - break; - - case SNDRV_PCM_FORMAT_S32: - bits = 32; - dma_params->pdc_xfer_size = 4; - break; - - default: - pr_warning("at32-ssc: Unsupported PCM format %d", - params_format(params)); - return -EINVAL; - } - pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", - bits, dma_params->pdc_xfer_size, channels); - - - /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) - if (bits > 16) { - pr_warning("at32-ssc: " - "sample size %d is too large for I2S\n", - bits); - return -EINVAL; - } - - - /* - * Compute the SSC register settings - */ - switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | - SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRS clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line - */ - pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); - rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | - SSC_BF(RCMR_STTDLY, START_DELAY) | - SSC_BF(RCMR_START, SSC_START_FALLING_RF) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_DIV)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | - SSC_BF(RFMR_FSLEN, bits - 1) | - SSC_BF(RFMR_DATNB, channels - 1) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | - SSC_BF(TCMR_STTDLY, START_DELAY) | - SSC_BF(TCMR_START, SSC_START_FALLING_RF) | - SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | - SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | - SSC_BF(TCMR_CKS, SSC_CKS_DIV)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | - SSC_BF(TFMR_FSLEN, bits - 1) | - SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | - SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* - * I2S format, CODEC supplies BCLK and LRC clock. - * - * The SSC transmit clock is obtained from the BCLK signal - * on the TK line, and the SSC receive clock is generated from - * the transmit clock. - * - * For single channel data, one sample is transferred on the - * falling edge of the LRC clock. For two channel data, one - * sample is transferred on both edges of the LRC clock. - */ - pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); - start_event = ((channels == 1) ? - SSC_START_FALLING_RF : SSC_START_EDGE_RF); - - rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | - SSC_BF(RCMR_START, start_event) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_CLOCK)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | - SSC_BF(TCMR_START, start_event) | - SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | - SSC_BF(TCMR_CKO, SSC_CKO_NONE) | - SSC_BF(TCMR_CKS, SSC_CKS_PIN)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | - SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line - */ - pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); - rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | - SSC_BF(RCMR_STTDLY, 1) | - SSC_BF(RCMR_START, SSC_START_RISING_RF) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_DIV)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | - SSC_BF(RFMR_DATNB, channels - 1) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | - SSC_BF(TCMR_STTDLY, 1) | - SSC_BF(TCMR_START, SSC_START_RISING_RF) | - SSC_BF(TCMR_CKI, SSC_CKI_RISING) | - SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | - SSC_BF(TCMR_CKS, SSC_CKS_DIV)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | - SSC_BF(TFMR_DATNB, channels - 1) | - SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - default: - pr_warning("at32-ssc: unsupported DAI format 0x%x\n", - ssc_p->daifmt); - return -EINVAL; - break; - } - pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", - rcmr, rfmr, tcmr, tfmr); - - - if (!ssc_p->initialized) { - /* enable peripheral clock */ - pr_debug("at32-ssc: Starting clock\n"); - clk_enable(ssc_p->ssc->clk); - - /* Reset the SSC and its PDC registers */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); - - ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); - - ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, - ssc_p->name, ssc_p); - if (ret < 0) { - pr_warning("at32-ssc: request irq failed (%d)\n", ret); - pr_debug("at32-ssc: Stopping clock\n"); - clk_disable(ssc_p->ssc->clk); - return ret; - } - - ssc_p->initialized = 1; - } - - /* Set SSC clock mode register */ - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); - - /* set receive clock mode and format */ - ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); - - /* set transmit clock mode and format */ - ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); - ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); - - pr_debug("at32-ssc: SSC initialized\n"); - return 0; -} - - - -static int at32_ssc_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at32_pcm_dma_params *dma_params; - - dma_params = ssc_p->dma_params[substream->stream]; - - ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable); - - return 0; -} - - - -#ifdef CONFIG_PM -static int at32_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* Save the status register before disabling transmit and receive */ - ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); - - /* Save the current interrupt mask, then disable unmasked interrupts */ - ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); - ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); - ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); - ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); - ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); - ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); - - return 0; -} - - - -static int at32_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p; - u32 cr; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* restore SSC register settings */ - ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); - ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); - ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); - - /* re-enable interrupts */ - ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); - - /* Re-enable recieve and transmit as appropriate */ - cr = 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; - ssc_writel(ssc_p->ssc->regs, CR, cr); - - return 0; -} -#else /* CONFIG_PM */ -# define at32_ssc_suspend NULL -# define at32_ssc_resume NULL -#endif /* CONFIG_PM */ - - -#define AT32_SSC_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - - -#define AT32_SSC_FORMATS \ - (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16 | \ - SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32) - - -struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = { - { - .name = "at32-ssc0", - .id = 0, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[0], - }, - { - .name = "at32-ssc1", - .id = 1, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[1], - }, - { - .name = "at32-ssc2", - .id = 2, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[2], - }, -}; -EXPORT_SYMBOL_GPL(at32_ssc_dai); - - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("AT32 SSC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/at32/at32-ssc.h b/trunk/sound/soc/at32/at32-ssc.h deleted file mode 100644 index 3c052dbbe460..000000000000 --- a/trunk/sound/soc/at32/at32-ssc.h +++ /dev/null @@ -1,59 +0,0 @@ -/* sound/soc/at32/at32-ssc.h - * ASoC SSC interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __SOUND_SOC_AT32_AT32_SSC_H -#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__ - -#include -#include - -#include "at32-pcm.h" - - - -struct at32_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - - - -struct at32_ssc_info { - char *name; - struct ssc_device *ssc; - spinlock_t lock; /* lock for dir_mask */ - unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ - unsigned short initialized; /* true if SSC has been initialized */ - unsigned short daifmt; - unsigned short cmr_div; - unsigned short tcmr_period; - unsigned short rcmr_period; - struct at32_pcm_dma_params *dma_params[2]; - struct at32_ssc_state ssc_state; -}; - - -/* SSC divider ids */ -#define AT32_SSC_CMR_DIV 0 /* MCK divider for BCLK */ -#define AT32_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ -#define AT32_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ - - -extern struct snd_soc_dai at32_ssc_dai[]; - - - -#endif /* __SOUND_SOC_AT32_AT32_SSC_H */ diff --git a/trunk/sound/soc/at32/playpaq_wm8510.c b/trunk/sound/soc/at32/playpaq_wm8510.c deleted file mode 100644 index fee5f8e58957..000000000000 --- a/trunk/sound/soc/at32/playpaq_wm8510.c +++ /dev/null @@ -1,522 +0,0 @@ -/* sound/soc/at32/playpaq_wm8510.c - * ASoC machine driver for PlayPaq using WM8510 codec - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c - * - * NOTE: If you don't have the AT32 enhanced portmux configured (which - * isn't currently in the mainline or Atmel patched kernel), you will - * need to set the MCLK pin (PA30) to peripheral A in your board initialization - * code. Something like: - * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); - * - */ - -/* #define DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "../codecs/wm8510.h" -#include "at32-pcm.h" -#include "at32-ssc.h" - - -/*-------------------------------------------------------------------------*\ - * constants -\*-------------------------------------------------------------------------*/ -#define MCLK_PIN GPIO_PIN_PA(30) -#define MCLK_PERIPH GPIO_PERIPH_A - - -/*-------------------------------------------------------------------------*\ - * data types -\*-------------------------------------------------------------------------*/ -/* SSC clocking data */ -struct ssc_clock_data { - /* CMR div */ - unsigned int cmr_div; - - /* Frame period (as needed by xCMR.PERIOD) */ - unsigned int period; - - /* The SSC clock rate these settings where calculated for */ - unsigned long ssc_rate; -}; - - -/*-------------------------------------------------------------------------*\ - * module data -\*-------------------------------------------------------------------------*/ -static struct clk *_gclk0; -static struct clk *_pll0; - -#define CODEC_CLK (_gclk0) - - -/*-------------------------------------------------------------------------*\ - * Sound SOC operations -\*-------------------------------------------------------------------------*/ -#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE -static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( - struct snd_pcm_hw_params *params, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p = cpu_dai->private_data; - struct ssc_device *ssc = ssc_p->ssc; - struct ssc_clock_data cd; - unsigned int rate, width_bits, channels; - unsigned int bitrate, ssc_div; - unsigned actual_rate; - - - /* - * Figure out required bitrate - */ - rate = params_rate(params); - channels = params_channels(params); - width_bits = snd_pcm_format_physical_width(params_format(params)); - bitrate = rate * width_bits * channels; - - - /* - * Figure out required SSC divider and period for required bitrate - */ - cd.ssc_rate = clk_get_rate(ssc->clk); - ssc_div = cd.ssc_rate / bitrate; - cd.cmr_div = ssc_div / 2; - if (ssc_div & 1) { - /* round cmr_div up */ - cd.cmr_div++; - } - cd.period = width_bits - 1; - - - /* - * Find actual rate, compare to requested rate - */ - actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); - pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", - rate, actual_rate); - - - return cd; -} -#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ - - - -static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct at32_ssc_info *ssc_p = cpu_dai->private_data; - struct ssc_device *ssc = ssc_p->ssc; - unsigned int pll_out = 0, bclk = 0, mclk_div = 0; - int ret; - - - /* Due to difficulties with getting the correct clocks from the AT32's - * PLL0, we're going to let the CODEC be in charge of all the clocks - */ -#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE - const unsigned int fmt = (SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); -#else - struct ssc_clock_data cd; - const unsigned int fmt = (SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); -#endif - - if (ssc == NULL) { - pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); - return -EINVAL; - } - - - /* - * Figure out PLL and BCLK dividers for WM8510 - */ - switch (params_rate(params)) { - case 48000: - pll_out = 12288000; - mclk_div = WM8510_MCLKDIV_1; - bclk = WM8510_BCLKDIV_8; - break; - - case 44100: - pll_out = 11289600; - mclk_div = WM8510_MCLKDIV_1; - bclk = WM8510_BCLKDIV_8; - break; - - case 22050: - pll_out = 11289600; - mclk_div = WM8510_MCLKDIV_2; - bclk = WM8510_BCLKDIV_8; - break; - - case 16000: - pll_out = 12288000; - mclk_div = WM8510_MCLKDIV_3; - bclk = WM8510_BCLKDIV_8; - break; - - case 11025: - pll_out = 11289600; - mclk_div = WM8510_MCLKDIV_4; - bclk = WM8510_BCLKDIV_8; - break; - - case 8000: - pll_out = 12288000; - mclk_div = WM8510_MCLKDIV_6; - bclk = WM8510_BCLKDIV_8; - break; - - default: - pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", - params_rate(params)); - return -EINVAL; - } - - - /* - * set CPU and CODEC DAI configuration - */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt); - if (ret < 0) { - pr_warning("playpaq_wm8510: " - "Failed to set CODEC DAI format (%d)\n", - ret); - return ret; - } - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret < 0) { - pr_warning("playpaq_wm8510: " - "Failed to set CPU DAI format (%d)\n", - ret); - return ret; - } - - - /* - * Set CPU clock configuration - */ -#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE - cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); - pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", - cd.cmr_div, cd.period); - ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); - if (ret < 0) { - pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", - ret); - return ret; - } - ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, - cd.period); - if (ret < 0) { - pr_warning("playpaq_wm8510: " - "Failed to set CPU transmit period (%d)\n", - ret); - return ret; - } -#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ - - - /* - * Set CODEC clock configuration - */ - pr_debug("playpaq_wm8510: " - "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", - clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); - - -#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); - if (ret < 0) { - pr_warning - ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", - ret); - return ret; - } -#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ - - - ret = snd_soc_dai_set_pll(codec_dai, 0, - clk_get_rate(CODEC_CLK), pll_out); - if (ret < 0) { - pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", - ret); - return ret; - } - - - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); - if (ret < 0) { - pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", - ret); - return ret; - } - - - return 0; -} - - - -static struct snd_soc_ops playpaq_wm8510_ops = { - .hw_params = playpaq_wm8510_hw_params, -}; - - - -static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), -}; - - - -static const char *intercon[][3] = { - /* speaker connected to SPKOUT */ - {"Ext Spk", NULL, "SPKOUTP"}, - {"Ext Spk", NULL, "SPKOUTN"}, - - {"Mic Bias", NULL, "Int Mic"}, - {"MICN", NULL, "Mic Bias"}, - {"MICP", NULL, "Mic Bias"}, - - /* Terminator */ - {NULL, NULL, NULL}, -}; - - - -static int playpaq_wm8510_init(struct snd_soc_codec *codec) -{ - int i; - - /* - * Add DAPM widgets - */ - for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) - snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]); - - - - /* - * Setup audio path interconnects - */ - for (i = 0; intercon[i][0] != NULL; i++) { - snd_soc_dapm_connect_input(codec, - intercon[i][0], - intercon[i][1], intercon[i][2]); - } - - - /* always connected pins */ - snd_soc_dapm_enable_pin(codec, "Int Mic"); - snd_soc_dapm_enable_pin(codec, "Ext Spk"); - snd_soc_dapm_sync(codec); - - - - /* Make CSB show PLL rate */ - snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV, - WM8510_OPCLKDIV_1 | 4); - - return 0; -} - - - -static struct snd_soc_dai_link playpaq_wm8510_dai = { - .name = "WM8510", - .stream_name = "WM8510 PCM", - .cpu_dai = &at32_ssc_dai[0], - .codec_dai = &wm8510_dai, - .init = playpaq_wm8510_init, - .ops = &playpaq_wm8510_ops, -}; - - - -static struct snd_soc_machine snd_soc_machine_playpaq = { - .name = "LRS_PlayPaq_WM8510", - .dai_link = &playpaq_wm8510_dai, - .num_links = 1, -}; - - - -static struct wm8510_setup_data playpaq_wm8510_setup = { - .i2c_address = 0x1a, -}; - - - -static struct snd_soc_device playpaq_wm8510_snd_devdata = { - .machine = &snd_soc_machine_playpaq, - .platform = &at32_soc_platform, - .codec_dev = &soc_codec_dev_wm8510, - .codec_data = &playpaq_wm8510_setup, -}; - -static struct platform_device *playpaq_snd_device; - - -static int __init playpaq_asoc_init(void) -{ - int ret = 0; - struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; - struct ssc_device *ssc = NULL; - - - /* - * Request SSC device - */ - ssc = ssc_request(0); - if (IS_ERR(ssc)) { - ret = PTR_ERR(ssc); - ssc = NULL; - goto err_ssc; - } - ssc_p->ssc = ssc; - - - /* - * Configure MCLK for WM8510 - */ - _gclk0 = clk_get(NULL, "gclk0"); - if (IS_ERR(_gclk0)) { - _gclk0 = NULL; - goto err_gclk0; - } - _pll0 = clk_get(NULL, "pll0"); - if (IS_ERR(_pll0)) { - _pll0 = NULL; - goto err_pll0; - } - if (clk_set_parent(_gclk0, _pll0)) { - pr_warning("snd-soc-playpaq: " - "Failed to set PLL0 as parent for DAC clock\n"); - goto err_set_clk; - } - clk_set_rate(CODEC_CLK, 12000000); - clk_enable(CODEC_CLK); - -#if defined CONFIG_AT32_ENHANCED_PORTMUX - at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); -#endif - - - /* - * Create and register platform device - */ - playpaq_snd_device = platform_device_alloc("soc-audio", 0); - if (playpaq_snd_device == NULL) { - ret = -ENOMEM; - goto err_device_alloc; - } - - platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata); - playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev; - - ret = platform_device_add(playpaq_snd_device); - if (ret) { - pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", - ret); - goto err_device_add; - } - - return 0; - - -err_device_add: - if (playpaq_snd_device != NULL) { - platform_device_put(playpaq_snd_device); - playpaq_snd_device = NULL; - } -err_device_alloc: -err_set_clk: - if (_pll0 != NULL) { - clk_put(_pll0); - _pll0 = NULL; - } -err_pll0: - if (_gclk0 != NULL) { - clk_put(_gclk0); - _gclk0 = NULL; - } -err_gclk0: - if (ssc != NULL) { - ssc_free(ssc); - ssc = NULL; - } -err_ssc: - return ret; -} - - -static void __exit playpaq_asoc_exit(void) -{ - struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; - struct ssc_device *ssc; - - if (ssc_p != NULL) { - ssc = ssc_p->ssc; - if (ssc != NULL) - ssc_free(ssc); - ssc_p->ssc = NULL; - } - - if (_gclk0 != NULL) { - clk_put(_gclk0); - _gclk0 = NULL; - } - if (_pll0 != NULL) { - clk_put(_pll0); - _pll0 = NULL; - } - -#if defined CONFIG_AT32_ENHANCED_PORTMUX - at32_free_pin(MCLK_PIN); -#endif - - platform_device_unregister(playpaq_snd_device); - playpaq_snd_device = NULL; -} - -module_init(playpaq_asoc_init); -module_exit(playpaq_asoc_exit); - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/at91/Kconfig b/trunk/sound/soc/at91/Kconfig index 905186502e00..5cb93fd3a407 100644 --- a/trunk/sound/soc/at91/Kconfig +++ b/trunk/sound/soc/at91/Kconfig @@ -1,6 +1,6 @@ config SND_AT91_SOC tristate "SoC Audio for the Atmel AT91 System-on-Chip" - depends on ARCH_AT91 + depends on ARCH_AT91 && SND_SOC help Say Y or M if you want to add support for codecs attached to the AT91 SSC interface. You will also need diff --git a/trunk/sound/soc/at91/at91-pcm.c b/trunk/sound/soc/at91/at91-pcm.c index d47492b2b6e5..ccac6bd2889c 100644 --- a/trunk/sound/soc/at91/at91-pcm.c +++ b/trunk/sound/soc/at91/at91-pcm.c @@ -318,7 +318,7 @@ static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, static u64 at91_pcm_dmamask = 0xffffffff; static int at91_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) + struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) { int ret = 0; @@ -367,7 +367,7 @@ static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) #ifdef CONFIG_PM static int at91_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; struct at91_runtime_data *prtd; @@ -392,7 +392,7 @@ static int at91_pcm_suspend(struct platform_device *pdev, } static int at91_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; struct at91_runtime_data *prtd; diff --git a/trunk/sound/soc/at91/at91-ssc.c b/trunk/sound/soc/at91/at91-ssc.c index c3625b665c5a..bc35d00a38f8 100644 --- a/trunk/sound/soc/at91/at91-ssc.c +++ b/trunk/sound/soc/at91/at91-ssc.c @@ -281,7 +281,7 @@ static void at91_ssc_shutdown(struct snd_pcm_substream *substream) /* * Record the SSC system clock rate. */ -static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, +static int at91_ssc_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { /* @@ -303,7 +303,7 @@ static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, /* * Record the DAI format for use in hw_params(). */ -static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, +static int at91_ssc_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int fmt) { struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; @@ -315,7 +315,7 @@ static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* * Record SSC clock dividers for use in hw_params(). */ -static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, +static int at91_ssc_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai, int div_id, int div) { struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; @@ -634,7 +634,7 @@ static int at91_ssc_prepare(struct snd_pcm_substream *substream) #ifdef CONFIG_PM static int at91_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) + struct snd_soc_cpu_dai *cpu_dai) { struct at91_ssc_info *ssc_p; @@ -662,7 +662,7 @@ static int at91_ssc_suspend(struct platform_device *pdev, } static int at91_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) + struct snd_soc_cpu_dai *cpu_dai) { struct at91_ssc_info *ssc_p; @@ -700,7 +700,7 @@ static int at91_ssc_resume(struct platform_device *pdev, #define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = { +struct snd_soc_cpu_dai at91_ssc_dai[NUM_SSC_DEVICES] = { { .name = "at91-ssc0", .id = 0, .type = SND_SOC_DAI_PCM, diff --git a/trunk/sound/soc/at91/at91-ssc.h b/trunk/sound/soc/at91/at91-ssc.h index 6b7bf382d06f..b188f973df9f 100644 --- a/trunk/sound/soc/at91/at91-ssc.h +++ b/trunk/sound/soc/at91/at91-ssc.h @@ -21,7 +21,7 @@ #define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ #define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ -extern struct snd_soc_dai at91_ssc_dai[]; +extern struct snd_soc_cpu_dai at91_ssc_dai[]; #endif /* _AT91_SSC_H */ diff --git a/trunk/sound/soc/at91/eti_b1_wm8731.c b/trunk/sound/soc/at91/eti_b1_wm8731.c index d532de954241..1347dcf3f80b 100644 --- a/trunk/sound/soc/at91/eti_b1_wm8731.c +++ b/trunk/sound/soc/at91/eti_b1_wm8731.c @@ -53,18 +53,18 @@ static struct clk *pllb_clk; static int eti_b1_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; int ret; /* cpu clock is the AT91 master clock sent to the SSC */ - ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK, + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK, 60000000, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* codec system clock is supplied by PCK1, set to 12MHz */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, 12000000, SND_SOC_CLOCK_IN); if (ret < 0) return ret; @@ -87,8 +87,8 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; int ret; #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE @@ -96,13 +96,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, int cmr_div, period; /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; @@ -141,17 +141,17 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, } /* set the MCK divider for BCLK */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); if (ret < 0) return ret; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* set the BCLK divider for DACLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_TCMR_PERIOD, period); } else { /* set the BCLK divider for ADCLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_RCMR_PERIOD, period); } if (ret < 0) @@ -163,13 +163,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, */ /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; @@ -191,7 +191,7 @@ static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = { SND_SOC_DAPM_SPK("Ext Spk", NULL), }; -static const struct snd_soc_dapm_route intercon[] = { +static const char *intercon[][3] = { /* speaker connected to LHPOUT */ {"Ext Spk", NULL, "LHPOUT"}, @@ -199,6 +199,9 @@ static const struct snd_soc_dapm_route intercon[] = { /* mic is connected to Mic Jack, with WM8731 Mic Bias */ {"MICIN", NULL, "Mic Bias"}, {"Mic Bias", NULL, "Int Mic"}, + + /* terminator */ + {NULL, NULL, NULL}, }; /* @@ -206,24 +209,30 @@ static const struct snd_soc_dapm_route intercon[] = { */ static int eti_b1_wm8731_init(struct snd_soc_codec *codec) { + int i; + DBG("eti_b1_wm8731_init() called\n"); /* Add specific widgets */ - snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets, - ARRAY_SIZE(eti_b1_dapm_widgets)); + for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]); + } /* Set up specific audio path interconnects */ - snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon)); + for(i = 0; intercon[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, intercon[i][0], + intercon[i][1], intercon[i][2]); + } /* not connected */ - snd_soc_dapm_disable_pin(codec, "RLINEIN"); - snd_soc_dapm_disable_pin(codec, "LLINEIN"); + snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); /* always connected */ - snd_soc_dapm_enable_pin(codec, "Int Mic"); - snd_soc_dapm_enable_pin(codec, "Ext Spk"); + snd_soc_dapm_set_endpoint(codec, "Int Mic", 1); + snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } diff --git a/trunk/sound/soc/au1x/Kconfig b/trunk/sound/soc/au1x/Kconfig deleted file mode 100644 index 410a893aa66b..000000000000 --- a/trunk/sound/soc/au1x/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -## -## Au1200/Au1550 PSC + DBDMA -## -config SND_SOC_AU1XPSC - tristate "SoC Audio for Au1200/Au1250/Au1550" - depends on SOC_AU1200 || SOC_AU1550 - help - This option enables support for the Programmable Serial - Controllers in AC97 and I2S mode, and the Descriptor-Based DMA - Controller (DBDMA) as found on the Au1200/Au1250/Au1550 SoC. - -config SND_SOC_AU1XPSC_I2S - tristate - -config SND_SOC_AU1XPSC_AC97 - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - - -## -## Boards -## -config SND_SOC_SAMPLE_PSC_AC97 - tristate "Sample Au12x0/Au1550 PSC AC97 sound machine" - depends on SND_SOC_AU1XPSC - select SND_SOC_AU1XPSC_AC97 - select SND_SOC_AC97_CODEC - help - This is a sample AC97 sound machine for use in Au12x0/Au1550 - based systems which have audio on PSC1 (e.g. Db1200 demoboard). diff --git a/trunk/sound/soc/au1x/Makefile b/trunk/sound/soc/au1x/Makefile deleted file mode 100644 index 6c6950b8003a..000000000000 --- a/trunk/sound/soc/au1x/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Au1200/Au1550 PSC audio -snd-soc-au1xpsc-dbdma-objs := dbdma2.o -snd-soc-au1xpsc-i2s-objs := psc-i2s.o -snd-soc-au1xpsc-ac97-objs := psc-ac97.o - -obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o -obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o -obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o - -# Boards -snd-soc-sample-ac97-objs := sample-ac97.o - -obj-$(CONFIG_SND_SOC_SAMPLE_PSC_AC97) += snd-soc-sample-ac97.o diff --git a/trunk/sound/soc/au1x/dbdma2.c b/trunk/sound/soc/au1x/dbdma2.c deleted file mode 100644 index 1466d9328800..000000000000 --- a/trunk/sound/soc/au1x/dbdma2.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Au12x0/Au1550 PSC ALSA ASoC audio support. - * - * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * DMA glue for Au1x-PSC audio. - * - * NOTE: all of these drivers can only work with a SINGLE instance - * of a PSC. Multiple independent audio devices are impossible - * with ASoC v1. - */ - - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "psc.h" - -/*#define PCM_DEBUG*/ - -#define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x) -#ifdef PCM_DEBUG -#define DBG MSG -#else -#define DBG(x...) do {} while (0) -#endif - -struct au1xpsc_audio_dmadata { - /* DDMA control data */ - unsigned int ddma_id; /* DDMA direction ID for this PSC */ - u32 ddma_chan; /* DDMA context */ - - /* PCM context (for irq handlers) */ - struct snd_pcm_substream *substream; - unsigned long curr_period; /* current segment DDMA is working on */ - unsigned long q_period; /* queue period(s) */ - unsigned long dma_area; /* address of queued DMA area */ - unsigned long dma_area_s; /* start address of DMA area */ - unsigned long pos; /* current byte position being played */ - unsigned long periods; /* number of SG segments in total */ - unsigned long period_bytes; /* size in bytes of one SG segment */ - - /* runtime data */ - int msbits; -}; - -/* instance data. There can be only one, MacLeod!!!! */ -static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2]; - -/* - * These settings are somewhat okay, at least on my machine audio plays - * almost skip-free. Especially the 64kB buffer seems to help a LOT. - */ -#define AU1XPSC_PERIOD_MIN_BYTES 1024 -#define AU1XPSC_BUFFER_MIN_BYTES 65536 - -#define AU1XPSC_PCM_FMTS \ - (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \ - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \ - 0) - -/* PCM hardware DMA capabilities - platform specific */ -static const struct snd_pcm_hardware au1xpsc_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED, - .formats = AU1XPSC_PCM_FMTS, - .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES, - .period_bytes_max = 4096 * 1024 - 1, - .periods_min = 2, - .periods_max = 4096, /* 2 to as-much-as-you-like */ - .buffer_bytes_max = 4096 * 1024 - 1, - .fifo_size = 16, /* fifo entries of AC97/I2S PSC */ -}; - -static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) -{ - au1xxx_dbdma_put_source_flags(cd->ddma_chan, - (void *)phys_to_virt(cd->dma_area), - cd->period_bytes, DDMA_FLAGS_IE); - - /* update next-to-queue period */ - ++cd->q_period; - cd->dma_area += cd->period_bytes; - if (cd->q_period >= cd->periods) { - cd->q_period = 0; - cd->dma_area = cd->dma_area_s; - } -} - -static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) -{ - au1xxx_dbdma_put_dest_flags(cd->ddma_chan, - (void *)phys_to_virt(cd->dma_area), - cd->period_bytes, DDMA_FLAGS_IE); - - /* update next-to-queue period */ - ++cd->q_period; - cd->dma_area += cd->period_bytes; - if (cd->q_period >= cd->periods) { - cd->q_period = 0; - cd->dma_area = cd->dma_area_s; - } -} - -static void au1x_pcm_dmatx_cb(int irq, void *dev_id) -{ - struct au1xpsc_audio_dmadata *cd = dev_id; - - cd->pos += cd->period_bytes; - if (++cd->curr_period >= cd->periods) { - cd->pos = 0; - cd->curr_period = 0; - } - snd_pcm_period_elapsed(cd->substream); - au1x_pcm_queue_tx(cd); -} - -static void au1x_pcm_dmarx_cb(int irq, void *dev_id) -{ - struct au1xpsc_audio_dmadata *cd = dev_id; - - cd->pos += cd->period_bytes; - if (++cd->curr_period >= cd->periods) { - cd->pos = 0; - cd->curr_period = 0; - } - snd_pcm_period_elapsed(cd->substream); - au1x_pcm_queue_rx(cd); -} - -static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd) -{ - if (pcd->ddma_chan) { - au1xxx_dbdma_stop(pcd->ddma_chan); - au1xxx_dbdma_reset(pcd->ddma_chan); - au1xxx_dbdma_chan_free(pcd->ddma_chan); - pcd->ddma_chan = 0; - pcd->msbits = 0; - } -} - -/* in case of missing DMA ring or changed TX-source / RX-dest bit widths, - * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according - * to ALSA-supplied sample depth. This is due to limitations in the dbdma api - * (cannot adjust source/dest widths of already allocated descriptor ring). - */ -static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd, - int stype, int msbits) -{ - /* DMA only in 8/16/32 bit widths */ - if (msbits == 24) - msbits = 32; - - /* check current config: correct bits and descriptors allocated? */ - if ((pcd->ddma_chan) && (msbits == pcd->msbits)) - goto out; /* all ok! */ - - au1x_pcm_dbdma_free(pcd); - - if (stype == PCM_RX) - pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id, - DSCR_CMD0_ALWAYS, - au1x_pcm_dmarx_cb, (void *)pcd); - else - pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS, - pcd->ddma_id, - au1x_pcm_dmatx_cb, (void *)pcd); - - if (!pcd->ddma_chan) - return -ENOMEM;; - - au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits); - au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2); - - pcd->msbits = msbits; - - au1xxx_dbdma_stop(pcd->ddma_chan); - au1xxx_dbdma_reset(pcd->ddma_chan); - -out: - return 0; -} - -static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct au1xpsc_audio_dmadata *pcd; - int stype, ret; - - ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); - if (ret < 0) - goto out; - - stype = SUBSTREAM_TYPE(substream); - pcd = au1xpsc_audio_pcmdma[stype]; - - DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " - "runtime->min_align %d\n", - (unsigned long)runtime->dma_area, - (unsigned long)runtime->dma_addr, runtime->dma_bytes, - runtime->min_align); - - DBG("bits %d frags %d frag_bytes %d is_rx %d\n", params->msbits, - params_periods(params), params_period_bytes(params), stype); - - ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits); - if (ret) { - MSG("DDMA channel (re)alloc failed!\n"); - goto out; - } - - pcd->substream = substream; - pcd->period_bytes = params_period_bytes(params); - pcd->periods = params_periods(params); - pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr; - pcd->q_period = 0; - pcd->curr_period = 0; - pcd->pos = 0; - - ret = 0; -out: - return ret; -} - -static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream) -{ - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct au1xpsc_audio_dmadata *pcd = - au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]; - - au1xxx_dbdma_reset(pcd->ddma_chan); - - if (SUBSTREAM_TYPE(substream) == PCM_RX) { - au1x_pcm_queue_rx(pcd); - au1x_pcm_queue_rx(pcd); - } else { - au1x_pcm_queue_tx(pcd); - au1x_pcm_queue_tx(pcd); - } - - return 0; -} - -static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - au1xxx_dbdma_start(c); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - au1xxx_dbdma_stop(c); - break; - default: - return -EINVAL; - } - return 0; -} - -static snd_pcm_uframes_t -au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) -{ - return bytes_to_frames(substream->runtime, - au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos); -} - -static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) -{ - snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware); - return 0; -} - -static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) -{ - au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]); - return 0; -} - -struct snd_pcm_ops au1xpsc_pcm_ops = { - .open = au1xpsc_pcm_open, - .close = au1xpsc_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = au1xpsc_pcm_hw_params, - .hw_free = au1xpsc_pcm_hw_free, - .prepare = au1xpsc_pcm_prepare, - .trigger = au1xpsc_pcm_trigger, - .pointer = au1xpsc_pcm_pointer, -}; - -static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - -static int au1xpsc_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); - - return 0; -} - -static int au1xpsc_pcm_probe(struct platform_device *pdev) -{ - struct resource *r; - int ret; - - if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX]) - return -EBUSY; - - /* TX DMA */ - au1xpsc_audio_pcmdma[PCM_TX] - = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); - if (!au1xpsc_audio_pcmdma[PCM_TX]) - return -ENOMEM; - - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!r) { - ret = -ENODEV; - goto out1; - } - (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start; - - /* RX DMA */ - au1xpsc_audio_pcmdma[PCM_RX] - = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); - if (!au1xpsc_audio_pcmdma[PCM_RX]) - return -ENOMEM; - - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!r) { - ret = -ENODEV; - goto out2; - } - (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start; - - return 0; - -out2: - kfree(au1xpsc_audio_pcmdma[PCM_RX]); - au1xpsc_audio_pcmdma[PCM_RX] = NULL; -out1: - kfree(au1xpsc_audio_pcmdma[PCM_TX]); - au1xpsc_audio_pcmdma[PCM_TX] = NULL; - return ret; -} - -static int au1xpsc_pcm_remove(struct platform_device *pdev) -{ - int i; - - for (i = 0; i < 2; i++) { - if (au1xpsc_audio_pcmdma[i]) { - au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]); - kfree(au1xpsc_audio_pcmdma[i]); - au1xpsc_audio_pcmdma[i] = NULL; - } - } - - return 0; -} - -/* au1xpsc audio platform */ -struct snd_soc_platform au1xpsc_soc_platform = { - .name = "au1xpsc-pcm-dbdma", - .probe = au1xpsc_pcm_probe, - .remove = au1xpsc_pcm_remove, - .pcm_ops = &au1xpsc_pcm_ops, - .pcm_new = au1xpsc_pcm_new, - .pcm_free = au1xpsc_pcm_free_dma_buffers, -}; -EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); - -static int __init au1xpsc_audio_dbdma_init(void) -{ - au1xpsc_audio_pcmdma[PCM_TX] = NULL; - au1xpsc_audio_pcmdma[PCM_RX] = NULL; - return 0; -} - -static void __exit au1xpsc_audio_dbdma_exit(void) -{ -} - -module_init(au1xpsc_audio_dbdma_init); -module_exit(au1xpsc_audio_dbdma_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/trunk/sound/soc/au1x/psc-ac97.c b/trunk/sound/soc/au1x/psc-ac97.c deleted file mode 100644 index 57facbad6825..000000000000 --- a/trunk/sound/soc/au1x/psc-ac97.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Au12x0/Au1550 PSC ALSA ASoC audio support. - * - * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Au1xxx-PSC AC97 glue. - * - * NOTE: all of these drivers can only work with a SINGLE instance - * of a PSC. Multiple independent audio devices are impossible - * with ASoC v1. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "psc.h" - -#define AC97_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define AC97_RATES \ - SNDRV_PCM_RATE_8000_48000 - -#define AC97_FMTS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE) - -#define AC97PCR_START(stype) \ - ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS) -#define AC97PCR_STOP(stype) \ - ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP) -#define AC97PCR_CLRFIFO(stype) \ - ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) - -/* instance data. There can be only one, MacLeod!!!! */ -static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; - -/* AC97 controller reads codec register */ -static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - /* FIXME */ - struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - unsigned short data, tmo; - - au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata)); - au_sync(); - - tmo = 1000; - while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) - udelay(2); - - if (!tmo) - data = 0xffff; - else - data = au_readl(AC97_CDC(pscdata)) & 0xffff; - - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); - - return data; -} - -/* AC97 controller writes to codec register */ -static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - /* FIXME */ - struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - unsigned int tmo; - - au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata)); - au_sync(); - tmo = 1000; - while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) - au_sync(); - - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); -} - -/* AC97 controller asserts a warm reset */ -static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97) -{ - /* FIXME */ - struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - - au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); - au_sync(); - msleep(10); - au_writel(0, AC97_RST(pscdata)); - au_sync(); -} - -static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) -{ - /* FIXME */ - struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - int i; - - /* disable PSC during cold reset */ - au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); - au_sync(); - - /* issue cold reset */ - au_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); - au_sync(); - msleep(500); - au_writel(0, AC97_RST(pscdata)); - au_sync(); - - /* enable PSC */ - au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); - au_sync(); - - /* wait for PSC to indicate it's ready */ - i = 100000; - while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) - au_sync(); - - if (i == 0) { - printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n"); - return; - } - - /* enable the ac97 function */ - au_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); - - /* wait for AC97 core to become ready */ - i = 100000; - while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) - au_sync(); - if (i == 0) - printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); -} - -/* AC97 controller operations */ -struct snd_ac97_bus_ops soc_ac97_ops = { - .read = au1xpsc_ac97_read, - .write = au1xpsc_ac97_write, - .reset = au1xpsc_ac97_cold_reset, - .warm_reset = au1xpsc_ac97_warm_reset, -}; -EXPORT_SYMBOL_GPL(soc_ac97_ops); - -static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - /* FIXME */ - struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - unsigned long r, stat; - int chans, stype = SUBSTREAM_TYPE(substream); - - chans = params_channels(params); - - r = au_readl(AC97_CFG(pscdata)); - stat = au_readl(AC97_STAT(pscdata)); - - /* already active? */ - if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) { - /* reject parameters not currently set up */ - if ((PSC_AC97CFG_GET_LEN(r) != params->msbits) || - (pscdata->rate != params_rate(params))) - return -EINVAL; - } else { - /* disable AC97 device controller first */ - au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); - - /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */ - r &= ~PSC_AC97CFG_LEN_MASK; - r |= PSC_AC97CFG_SET_LEN(params->msbits); - - /* channels: enable slots for front L/R channel */ - if (stype == PCM_TX) { - r &= ~PSC_AC97CFG_TXSLOT_MASK; - r |= PSC_AC97CFG_TXSLOT_ENA(3); - r |= PSC_AC97CFG_TXSLOT_ENA(4); - } else { - r &= ~PSC_AC97CFG_RXSLOT_MASK; - r |= PSC_AC97CFG_RXSLOT_ENA(3); - r |= PSC_AC97CFG_RXSLOT_ENA(4); - } - - /* finally enable the AC97 controller again */ - au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); - - pscdata->cfg = r; - pscdata->rate = params_rate(params); - } - - return 0; -} - -static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - /* FIXME */ - struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - int ret, stype = SUBSTREAM_TYPE(substream); - - ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); - au_sync(); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); - au_sync(); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int au1xpsc_ac97_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - int ret; - struct resource *r; - unsigned long sel; - - if (au1xpsc_ac97_workdata) - return -EBUSY; - - au1xpsc_ac97_workdata = - kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); - if (!au1xpsc_ac97_workdata) - return -ENOMEM; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - ret = -ENODEV; - goto out0; - } - - ret = -EBUSY; - au1xpsc_ac97_workdata->ioarea = - request_mem_region(r->start, r->end - r->start + 1, - "au1xpsc_ac97"); - if (!au1xpsc_ac97_workdata->ioarea) - goto out0; - - au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff); - if (!au1xpsc_ac97_workdata->mmio) - goto out1; - - /* configuration: max dma trigger threshold, enable ac97 */ - au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | - PSC_AC97CFG_TT_FIFO8 | - PSC_AC97CFG_DE_ENABLE; - - /* preserve PSC clock source set up by platform (dev.platform_data - * is already occupied by soc layer) - */ - sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); - au_sync(); - au_writel(0, PSC_SEL(au1xpsc_ac97_workdata)); - au_sync(); - au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata)); - au_sync(); - /* next up: cold reset. Dont check for PSC-ready now since - * there may not be any codec clock yet. - */ - - return 0; - -out1: - release_resource(au1xpsc_ac97_workdata->ioarea); - kfree(au1xpsc_ac97_workdata->ioarea); -out0: - kfree(au1xpsc_ac97_workdata); - au1xpsc_ac97_workdata = NULL; - return ret; -} - -static void au1xpsc_ac97_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - /* disable PSC completely */ - au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); - au_sync(); - - iounmap(au1xpsc_ac97_workdata->mmio); - release_resource(au1xpsc_ac97_workdata->ioarea); - kfree(au1xpsc_ac97_workdata->ioarea); - kfree(au1xpsc_ac97_workdata); - au1xpsc_ac97_workdata = NULL; -} - -static int au1xpsc_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - /* save interesting registers and disable PSC */ - au1xpsc_ac97_workdata->pm[0] = - au_readl(PSC_SEL(au1xpsc_ac97_workdata)); - - au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); - au_sync(); - - return 0; -} - -static int au1xpsc_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - /* restore PSC clock config */ - au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, - PSC_SEL(au1xpsc_ac97_workdata)); - au_sync(); - - /* after this point the ac97 core will cold-reset the codec. - * During cold-reset the PSC is reinitialized and the last - * configuration set up in hw_params() is restored. - */ - return 0; -} - -struct snd_soc_dai au1xpsc_ac97_dai = { - .name = "au1xpsc_ac97", - .type = SND_SOC_DAI_AC97, - .probe = au1xpsc_ac97_probe, - .remove = au1xpsc_ac97_remove, - .suspend = au1xpsc_ac97_suspend, - .resume = au1xpsc_ac97_resume, - .playback = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .capture = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .ops = { - .trigger = au1xpsc_ac97_trigger, - .hw_params = au1xpsc_ac97_hw_params, - }, -}; -EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); - -static int __init au1xpsc_ac97_init(void) -{ - au1xpsc_ac97_workdata = NULL; - return 0; -} - -static void __exit au1xpsc_ac97_exit(void) -{ -} - -module_init(au1xpsc_ac97_init); -module_exit(au1xpsc_ac97_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/trunk/sound/soc/au1x/psc-i2s.c b/trunk/sound/soc/au1x/psc-i2s.c deleted file mode 100644 index ba4b5c199f21..000000000000 --- a/trunk/sound/soc/au1x/psc-i2s.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Au12x0/Au1550 PSC ALSA ASoC audio support. - * - * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Au1xxx-PSC I2S glue. - * - * NOTE: all of these drivers can only work with a SINGLE instance - * of a PSC. Multiple independent audio devices are impossible - * with ASoC v1. - * NOTE: so far only PSC slave mode (bit- and frameclock) is supported. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "psc.h" - -/* supported I2S DAI hardware formats */ -#define AU1XPSC_I2S_DAIFMT \ - (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | \ - SND_SOC_DAIFMT_NB_NF) - -/* supported I2S direction */ -#define AU1XPSC_I2S_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define AU1XPSC_I2S_RATES \ - SNDRV_PCM_RATE_8000_192000 - -#define AU1XPSC_I2S_FMTS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) - -#define I2SSTAT_BUSY(stype) \ - ((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB) -#define I2SPCR_START(stype) \ - ((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS) -#define I2SPCR_STOP(stype) \ - ((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP) -#define I2SPCR_CLRFIFO(stype) \ - ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC) - - -/* instance data. There can be only one, MacLeod!!!! */ -static struct au1xpsc_audio_data *au1xpsc_i2s_workdata; - -static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; - unsigned long ct; - int ret; - - ret = -EINVAL; - - ct = pscdata->cfg; - - ct &= ~(PSC_I2SCFG_XM | PSC_I2SCFG_MLJ); /* left-justified */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - ct |= PSC_I2SCFG_XM; /* enable I2S mode */ - break; - case SND_SOC_DAIFMT_MSB: - break; - case SND_SOC_DAIFMT_LSB: - ct |= PSC_I2SCFG_MLJ; /* LSB (right-) justified */ - break; - default: - goto out; - } - - ct &= ~(PSC_I2SCFG_BI | PSC_I2SCFG_WI); /* IB-IF */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - ct |= PSC_I2SCFG_BI | PSC_I2SCFG_WI; - break; - case SND_SOC_DAIFMT_NB_IF: - ct |= PSC_I2SCFG_BI; - break; - case SND_SOC_DAIFMT_IB_NF: - ct |= PSC_I2SCFG_WI; - break; - case SND_SOC_DAIFMT_IB_IF: - break; - default: - goto out; - } - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: /* CODEC master */ - ct |= PSC_I2SCFG_MS; /* PSC I2S slave mode */ - break; - case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */ - ct &= ~PSC_I2SCFG_MS; /* PSC I2S Master mode */ - break; - default: - goto out; - } - - pscdata->cfg = ct; - ret = 0; -out: - return ret; -} - -static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; - - int cfgbits; - unsigned long stat; - - /* check if the PSC is already streaming data */ - stat = au_readl(I2S_STAT(pscdata)); - if (stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB)) { - /* reject parameters not currently set up in hardware */ - cfgbits = au_readl(I2S_CFG(pscdata)); - if ((PSC_I2SCFG_GET_LEN(cfgbits) != params->msbits) || - (params_rate(params) != pscdata->rate)) - return -EINVAL; - } else { - /* set sample bitdepth */ - pscdata->cfg &= ~(0x1f << 4); - pscdata->cfg |= PSC_I2SCFG_SET_LEN(params->msbits); - /* remember current rate for other stream */ - pscdata->rate = params_rate(params); - } - return 0; -} - -/* Configure PSC late: on my devel systems the codec is I2S master and - * supplies the i2sbitclock __AND__ i2sMclk (!) to the PSC unit. ASoC - * uses aggressive PM and switches the codec off when it is not in use - * which also means the PSC unit doesn't get any clocks and is therefore - * dead. That's why this chunk here gets called from the trigger callback - * because I can be reasonably certain the codec is driving the clocks. - */ -static int au1xpsc_i2s_configure(struct au1xpsc_audio_data *pscdata) -{ - unsigned long tmo; - - /* bring PSC out of sleep, and configure I2S unit */ - au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); - au_sync(); - - tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo) - tmo--; - - if (!tmo) - goto psc_err; - - au_writel(0, I2S_CFG(pscdata)); - au_sync(); - au_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata)); - au_sync(); - - /* wait for I2S controller to become ready */ - tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo) - tmo--; - - if (tmo) - return 0; - -psc_err: - au_writel(0, I2S_CFG(pscdata)); - au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); - au_sync(); - return -ETIMEDOUT; -} - -static int au1xpsc_i2s_start(struct au1xpsc_audio_data *pscdata, int stype) -{ - unsigned long tmo, stat; - int ret; - - ret = 0; - - /* if both TX and RX are idle, configure the PSC */ - stat = au_readl(I2S_STAT(pscdata)); - if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) { - ret = au1xpsc_i2s_configure(pscdata); - if (ret) - goto out; - } - - au_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata)); - au_sync(); - au_writel(I2SPCR_START(stype), I2S_PCR(pscdata)); - au_sync(); - - /* wait for start confirmation */ - tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) - tmo--; - - if (!tmo) { - au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); - au_sync(); - ret = -ETIMEDOUT; - } -out: - return ret; -} - -static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) -{ - unsigned long tmo, stat; - - au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); - au_sync(); - - /* wait for stop confirmation */ - tmo = 1000000; - while ((au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) - tmo--; - - /* if both TX and RX are idle, disable PSC */ - stat = au_readl(I2S_STAT(pscdata)); - if (!(stat & (PSC_I2SSTAT_RB | PSC_I2SSTAT_RB))) { - au_writel(0, I2S_CFG(pscdata)); - au_sync(); - au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); - au_sync(); - } - return 0; -} - -static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; - int ret, stype = SUBSTREAM_TYPE(substream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - ret = au1xpsc_i2s_start(pscdata, stype); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - ret = au1xpsc_i2s_stop(pscdata, stype); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int au1xpsc_i2s_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct resource *r; - unsigned long sel; - int ret; - - if (au1xpsc_i2s_workdata) - return -EBUSY; - - au1xpsc_i2s_workdata = - kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); - if (!au1xpsc_i2s_workdata) - return -ENOMEM; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - ret = -ENODEV; - goto out0; - } - - ret = -EBUSY; - au1xpsc_i2s_workdata->ioarea = - request_mem_region(r->start, r->end - r->start + 1, - "au1xpsc_i2s"); - if (!au1xpsc_i2s_workdata->ioarea) - goto out0; - - au1xpsc_i2s_workdata->mmio = ioremap(r->start, 0xffff); - if (!au1xpsc_i2s_workdata->mmio) - goto out1; - - /* preserve PSC clock source set up by platform (dev.platform_data - * is already occupied by soc layer) - */ - sel = au_readl(PSC_SEL(au1xpsc_i2s_workdata)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); - au_sync(); - au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(au1xpsc_i2s_workdata)); - au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); - au_sync(); - - /* preconfigure: set max rx/tx fifo depths */ - au1xpsc_i2s_workdata->cfg |= - PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8; - - /* don't wait for I2S core to become ready now; clocks may not - * be running yet; depending on clock input for PSC a wait might - * time out. - */ - - return 0; - -out1: - release_resource(au1xpsc_i2s_workdata->ioarea); - kfree(au1xpsc_i2s_workdata->ioarea); -out0: - kfree(au1xpsc_i2s_workdata); - au1xpsc_i2s_workdata = NULL; - return ret; -} - -static void au1xpsc_i2s_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); - au_sync(); - - iounmap(au1xpsc_i2s_workdata->mmio); - release_resource(au1xpsc_i2s_workdata->ioarea); - kfree(au1xpsc_i2s_workdata->ioarea); - kfree(au1xpsc_i2s_workdata); - au1xpsc_i2s_workdata = NULL; -} - -static int au1xpsc_i2s_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - /* save interesting register and disable PSC */ - au1xpsc_i2s_workdata->pm[0] = - au_readl(PSC_SEL(au1xpsc_i2s_workdata)); - - au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); - au_sync(); - - return 0; -} - -static int au1xpsc_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - /* select I2S mode and PSC clock */ - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); - au_sync(); - au_writel(0, PSC_SEL(au1xpsc_i2s_workdata)); - au_sync(); - au_writel(au1xpsc_i2s_workdata->pm[0], - PSC_SEL(au1xpsc_i2s_workdata)); - au_sync(); - - return 0; -} - -struct snd_soc_dai au1xpsc_i2s_dai = { - .name = "au1xpsc_i2s", - .type = SND_SOC_DAI_I2S, - .probe = au1xpsc_i2s_probe, - .remove = au1xpsc_i2s_remove, - .suspend = au1xpsc_i2s_suspend, - .resume = au1xpsc_i2s_resume, - .playback = { - .rates = AU1XPSC_I2S_RATES, - .formats = AU1XPSC_I2S_FMTS, - .channels_min = 2, - .channels_max = 8, /* 2 without external help */ - }, - .capture = { - .rates = AU1XPSC_I2S_RATES, - .formats = AU1XPSC_I2S_FMTS, - .channels_min = 2, - .channels_max = 8, /* 2 without external help */ - }, - .ops = { - .trigger = au1xpsc_i2s_trigger, - .hw_params = au1xpsc_i2s_hw_params, - }, - .dai_ops = { - .set_fmt = au1xpsc_i2s_set_fmt, - }, -}; -EXPORT_SYMBOL(au1xpsc_i2s_dai); - -static int __init au1xpsc_i2s_init(void) -{ - au1xpsc_i2s_workdata = NULL; - return 0; -} - -static void __exit au1xpsc_i2s_exit(void) -{ -} - -module_init(au1xpsc_i2s_init); -module_exit(au1xpsc_i2s_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/trunk/sound/soc/au1x/psc.h b/trunk/sound/soc/au1x/psc.h deleted file mode 100644 index 8fdb1a04a07b..000000000000 --- a/trunk/sound/soc/au1x/psc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Au12x0/Au1550 PSC ALSA ASoC audio support. - * - * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * NOTE: all of these drivers can only work with a SINGLE instance - * of a PSC. Multiple independent audio devices are impossible - * with ASoC v1. - */ - -#ifndef _AU1X_PCM_H -#define _AU1X_PCM_H - -extern struct snd_soc_dai au1xpsc_ac97_dai; -extern struct snd_soc_dai au1xpsc_i2s_dai; -extern struct snd_soc_platform au1xpsc_soc_platform; -extern struct snd_ac97_bus_ops soc_ac97_ops; - -struct au1xpsc_audio_data { - void __iomem *mmio; - - unsigned long cfg; - unsigned long rate; - - unsigned long pm[2]; - struct resource *ioarea; -}; - -#define PCM_TX 0 -#define PCM_RX 1 - -#define SUBSTREAM_TYPE(substream) \ - ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) - -/* easy access macros */ -#define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET) -#define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET) -#define I2S_STAT(x) ((unsigned long)((x)->mmio) + PSC_I2SSTAT_OFFSET) -#define I2S_CFG(x) ((unsigned long)((x)->mmio) + PSC_I2SCFG_OFFSET) -#define I2S_PCR(x) ((unsigned long)((x)->mmio) + PSC_I2SPCR_OFFSET) -#define AC97_CFG(x) ((unsigned long)((x)->mmio) + PSC_AC97CFG_OFFSET) -#define AC97_CDC(x) ((unsigned long)((x)->mmio) + PSC_AC97CDC_OFFSET) -#define AC97_EVNT(x) ((unsigned long)((x)->mmio) + PSC_AC97EVNT_OFFSET) -#define AC97_PCR(x) ((unsigned long)((x)->mmio) + PSC_AC97PCR_OFFSET) -#define AC97_RST(x) ((unsigned long)((x)->mmio) + PSC_AC97RST_OFFSET) -#define AC97_STAT(x) ((unsigned long)((x)->mmio) + PSC_AC97STAT_OFFSET) - -#endif diff --git a/trunk/sound/soc/au1x/sample-ac97.c b/trunk/sound/soc/au1x/sample-ac97.c deleted file mode 100644 index f75ae7f62c3d..000000000000 --- a/trunk/sound/soc/au1x/sample-ac97.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Sample Au12x0/Au1550 PSC AC97 sound machine. - * - * Copyright (c) 2007-2008 Manuel Lauss - * - * This program is free software; you can redistribute it and/or modify - * it under the terms outlined in the file COPYING at the root of this - * source archive. - * - * This is a very generic AC97 sound machine driver for boards which - * have (AC97) audio at PSC1 (e.g. DB1200 demoboards). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../codecs/ac97.h" -#include "psc.h" - -static int au1xpsc_sample_ac97_init(struct snd_soc_codec *codec) -{ - snd_soc_dapm_sync(codec); - return 0; -} - -static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai = &au1xpsc_ac97_dai, /* see psc-ac97.c */ - .codec_dai = &ac97_dai, /* see codecs/ac97.c */ - .init = au1xpsc_sample_ac97_init, - .ops = NULL, -}; - -static struct snd_soc_machine au1xpsc_sample_ac97_machine = { - .name = "Au1xxx PSC AC97 Audio", - .dai_link = &au1xpsc_sample_ac97_dai, - .num_links = 1, -}; - -static struct snd_soc_device au1xpsc_sample_ac97_devdata = { - .machine = &au1xpsc_sample_ac97_machine, - .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ - .codec_dev = &soc_codec_dev_ac97, -}; - -static struct resource au1xpsc_psc1_res[] = { - [0] = { - .start = CPHYSADDR(PSC1_BASE_ADDR), - .end = CPHYSADDR(PSC1_BASE_ADDR) + 0x000fffff, - .flags = IORESOURCE_MEM, - }, - [1] = { -#ifdef CONFIG_SOC_AU1200 - .start = AU1200_PSC1_INT, - .end = AU1200_PSC1_INT, -#elif defined(CONFIG_SOC_AU1550) - .start = AU1550_PSC1_INT, - .end = AU1550_PSC1_INT, -#endif - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = DSCR_CMD0_PSC1_TX, - .end = DSCR_CMD0_PSC1_TX, - .flags = IORESOURCE_DMA, - }, - [3] = { - .start = DSCR_CMD0_PSC1_RX, - .end = DSCR_CMD0_PSC1_RX, - .flags = IORESOURCE_DMA, - }, -}; - -static struct platform_device *au1xpsc_sample_ac97_dev; - -static int __init au1xpsc_sample_ac97_load(void) -{ - int ret; - -#ifdef CONFIG_SOC_AU1200 - unsigned long io; - - /* modify sys_pinfunc for AC97 on PSC1 */ - io = au_readl(SYS_PINFUNC); - io |= SYS_PINFUNC_P1C; - io &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B); - au_writel(io, SYS_PINFUNC); - au_sync(); -#endif - - ret = -ENOMEM; - - /* setup PSC clock source for AC97 part: external clock provided - * by codec. The psc-ac97.c driver depends on this setting! - */ - au_writel(PSC_SEL_CLK_SERCLK, PSC1_BASE_ADDR + PSC_SEL_OFFSET); - au_sync(); - - au1xpsc_sample_ac97_dev = platform_device_alloc("soc-audio", -1); - if (!au1xpsc_sample_ac97_dev) - goto out; - - au1xpsc_sample_ac97_dev->resource = - kmemdup(au1xpsc_psc1_res, sizeof(struct resource) * - ARRAY_SIZE(au1xpsc_psc1_res), GFP_KERNEL); - au1xpsc_sample_ac97_dev->num_resources = ARRAY_SIZE(au1xpsc_psc1_res); - au1xpsc_sample_ac97_dev->id = 1; - - platform_set_drvdata(au1xpsc_sample_ac97_dev, - &au1xpsc_sample_ac97_devdata); - au1xpsc_sample_ac97_devdata.dev = &au1xpsc_sample_ac97_dev->dev; - ret = platform_device_add(au1xpsc_sample_ac97_dev); - - if (ret) { - platform_device_put(au1xpsc_sample_ac97_dev); - au1xpsc_sample_ac97_dev = NULL; - } - -out: - return ret; -} - -static void __exit au1xpsc_sample_ac97_exit(void) -{ - platform_device_unregister(au1xpsc_sample_ac97_dev); -} - -module_init(au1xpsc_sample_ac97_load); -module_exit(au1xpsc_sample_ac97_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Au1xxx PSC sample AC97 machine"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index 1db04a28a53d..3903ab7dfa4a 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -1,37 +1,31 @@ config SND_SOC_AC97_CODEC tristate - select SND_AC97_CODEC - -config SND_SOC_AK4535 - tristate - -config SND_SOC_UDA1380 - tristate - -config SND_SOC_WM8510 - tristate + depends on SND_SOC config SND_SOC_WM8731 tristate + depends on SND_SOC config SND_SOC_WM8750 tristate + depends on SND_SOC config SND_SOC_WM8753 tristate - -config SND_SOC_WM8990 - tristate + depends on SND_SOC config SND_SOC_WM9712 tristate + depends on SND_SOC config SND_SOC_WM9713 tristate + depends on SND_SOC # Cirrus Logic CS4270 Codec config SND_SOC_CS4270 tristate + depends on SND_SOC # Cirrus Logic CS4270 Codec Hardware Mute Support # Select if you have external muting circuitry attached to your CS4270. @@ -49,4 +43,4 @@ config SND_SOC_CS4270_VD33_ERRATA config SND_SOC_TLV320AIC3X tristate - depends on I2C + depends on SND_SOC && I2C diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index d7b97abcf729..4e1314c9d3ec 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -1,24 +1,16 @@ snd-soc-ac97-objs := ac97.o -snd-soc-ak4535-objs := ak4535.o -snd-soc-uda1380-objs := uda1380.o -snd-soc-wm8510-objs := wm8510.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o -snd-soc-wm8990-objs := wm8990.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-cs4270-objs := cs4270.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o -obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o -obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o -obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o -obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o diff --git a/trunk/sound/soc/codecs/ac97.c b/trunk/sound/soc/codecs/ac97.c index 61fd96ca7bc7..2a1ffe396908 100644 --- a/trunk/sound/soc/codecs/ac97.c +++ b/trunk/sound/soc/codecs/ac97.c @@ -10,6 +10,9 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 17th Oct 2005 Initial version. + * * Generic AC97 support. */ @@ -21,7 +24,6 @@ #include #include #include -#include "ac97.h" #define AC97_VERSION "0.6" @@ -41,7 +43,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream) SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000) -struct snd_soc_dai ac97_dai = { +struct snd_soc_codec_dai ac97_dai = { .name = "AC97 HiFi", .type = SND_SOC_DAI_AC97, .playback = { @@ -144,34 +146,9 @@ static int ac97_soc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - snd_ac97_suspend(socdev->codec->ac97); - - return 0; -} - -static int ac97_soc_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - snd_ac97_resume(socdev->codec->ac97); - - return 0; -} -#else -#define ac97_soc_suspend NULL -#define ac97_soc_resume NULL -#endif - struct snd_soc_codec_device soc_codec_dev_ac97 = { .probe = ac97_soc_probe, .remove = ac97_soc_remove, - .suspend = ac97_soc_suspend, - .resume = ac97_soc_resume, }; EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); diff --git a/trunk/sound/soc/codecs/ac97.h b/trunk/sound/soc/codecs/ac97.h index 281aa42e2bbb..2bf6d69fd069 100644 --- a/trunk/sound/soc/codecs/ac97.h +++ b/trunk/sound/soc/codecs/ac97.h @@ -14,6 +14,6 @@ #define __LINUX_SND_SOC_AC97_H extern struct snd_soc_codec_device soc_codec_dev_ac97; -extern struct snd_soc_dai ac97_dai; +extern struct snd_soc_codec_dai ac97_dai; #endif diff --git a/trunk/sound/soc/codecs/ak4535.c b/trunk/sound/soc/codecs/ak4535.c deleted file mode 100644 index b26003c4f3e8..000000000000 --- a/trunk/sound/soc/codecs/ak4535.c +++ /dev/null @@ -1,696 +0,0 @@ -/* - * ak4535.c -- AK4535 ALSA Soc Audio driver - * - * Copyright 2005 Openedhand Ltd. - * - * Author: Richard Purdie - * - * Based on wm8753.c by Liam Girdwood - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ak4535.h" - -#define AUDIO_NAME "ak4535" -#define AK4535_VERSION "0.3" - -struct snd_soc_codec_device soc_codec_dev_ak4535; - -/* codec private data */ -struct ak4535_priv { - unsigned int sysclk; -}; - -/* - * ak4535 register cache - */ -static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { - 0x0000, 0x0080, 0x0000, 0x0003, - 0x0002, 0x0000, 0x0011, 0x0001, - 0x0000, 0x0040, 0x0036, 0x0010, - 0x0000, 0x0000, 0x0057, 0x0000, -}; - -/* - * read ak4535 register cache - */ -static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg >= AK4535_CACHEREGNUM) - return -1; - return cache[reg]; -} - -static inline unsigned int ak4535_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 data; - data = reg; - - if (codec->hw_write(codec->control_data, &data, 1) != 1) - return -EIO; - - if (codec->hw_read(codec->control_data, &data, 1) != 1) - return -EIO; - - return data; -}; - -/* - * write ak4535 register cache - */ -static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= AK4535_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the AK4535 register space - */ -static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D8 AK4535 register offset - * D7...D0 register data - */ - data[0] = reg & 0xff; - data[1] = value & 0xff; - - ak4535_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -static int ak4535_sync(struct snd_soc_codec *codec) -{ - u16 *cache = codec->reg_cache; - int i, r = 0; - - for (i = 0; i < AK4535_CACHEREGNUM; i++) - r |= ak4535_write(codec, i, cache[i]); - - return r; -}; - -static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; -static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"}; -static const char *ak4535_hp_out[] = {"Stereo", "Mono"}; -static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"}; -static const char *ak4535_mic_select[] = {"Internal", "External"}; - -static const struct soc_enum ak4535_enum[] = { - SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain), - SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out), - SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out), - SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp), - SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select), -}; - -static const struct snd_kcontrol_new ak4535_snd_controls[] = { - SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0), - SOC_ENUM("Mono 1 Output", ak4535_enum[1]), - SOC_ENUM("Mono 1 Gain", ak4535_enum[0]), - SOC_ENUM("Headphone Output", ak4535_enum[2]), - SOC_ENUM("Playback Deemphasis", ak4535_enum[3]), - SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0), - SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0), - SOC_ENUM("Mic Select", ak4535_enum[4]), - SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0), - SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0), - SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0), - SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0), - SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0), - SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0), - SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0), - SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1), - SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1), - SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0), - SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), -}; - -/* add non dapm controls */ -static int ak4535_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -/* Mono 1 Mixer */ -static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { - SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), - SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0), -}; - -/* Stereo Mixer */ -static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = { - SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0), - SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0), - SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0), -}; - -/* Input Mixer */ -static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = { - SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0), - SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0), -}; - -/* Input mux */ -static const struct snd_kcontrol_new ak4535_input_mux_control = - SOC_DAPM_ENUM("Input Select", ak4535_enum[4]); - -/* HP L switch */ -static const struct snd_kcontrol_new ak4535_hpl_control = - SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1); - -/* HP R switch */ -static const struct snd_kcontrol_new ak4535_hpr_control = - SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1); - -/* mono 2 switch */ -static const struct snd_kcontrol_new ak4535_mono2_control = - SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0); - -/* Line out switch */ -static const struct snd_kcontrol_new ak4535_line_control = - SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0); - -/* ak4535 dapm widgets */ -static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = { - SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0, - &ak4535_stereo_mixer_controls[0], - ARRAY_SIZE(ak4535_stereo_mixer_controls)), - SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, - &ak4535_mono1_mixer_controls[0], - ARRAY_SIZE(ak4535_mono1_mixer_controls)), - SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, - &ak4535_input_mixer_controls[0], - ARRAY_SIZE(ak4535_input_mixer_controls)), - SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, - &ak4535_input_mux_control), - SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0), - SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, - &ak4535_mono2_control), - /* speaker powersave bit */ - SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0), - SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0, - &ak4535_line_control), - SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0, - &ak4535_hpl_control), - SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0, - &ak4535_hpr_control), - SND_SOC_DAPM_OUTPUT("LOUT"), - SND_SOC_DAPM_OUTPUT("HPL"), - SND_SOC_DAPM_OUTPUT("ROUT"), - SND_SOC_DAPM_OUTPUT("HPR"), - SND_SOC_DAPM_OUTPUT("SPP"), - SND_SOC_DAPM_OUTPUT("SPN"), - SND_SOC_DAPM_OUTPUT("MOUT1"), - SND_SOC_DAPM_OUTPUT("MOUT2"), - SND_SOC_DAPM_OUTPUT("MICOUT"), - SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0), - SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0), - - SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0), - SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0), - SND_SOC_DAPM_INPUT("MICIN"), - SND_SOC_DAPM_INPUT("MICEXT"), - SND_SOC_DAPM_INPUT("AUX"), - SND_SOC_DAPM_INPUT("MIN"), - SND_SOC_DAPM_INPUT("AIN"), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /*stereo mixer */ - {"Stereo Mixer", "Playback Switch", "DAC"}, - {"Stereo Mixer", "Mic Sidetone Switch", "Mic"}, - {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, - - /* mono1 mixer */ - {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"}, - {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, - - /* Mic */ - {"Mic", NULL, "AIN"}, - {"Input Mux", "Internal", "Mic Int Bias"}, - {"Input Mux", "External", "Mic Ext Bias"}, - {"Mic Int Bias", NULL, "MICIN"}, - {"Mic Ext Bias", NULL, "MICEXT"}, - {"MICOUT", NULL, "Input Mux"}, - - /* line out */ - {"LOUT", NULL, "Line Out Enable"}, - {"ROUT", NULL, "Line Out Enable"}, - {"Line Out Enable", "Switch", "Line Out"}, - {"Line Out", NULL, "Stereo Mixer"}, - - /* mono1 out */ - {"MOUT1", NULL, "Mono Out"}, - {"Mono Out", NULL, "Mono1 Mixer"}, - - /* left HP */ - {"HPL", NULL, "Left HP Enable"}, - {"Left HP Enable", "Switch", "HP L Amp"}, - {"HP L Amp", NULL, "Stereo Mixer"}, - - /* right HP */ - {"HPR", NULL, "Right HP Enable"}, - {"Right HP Enable", "Switch", "HP R Amp"}, - {"HP R Amp", NULL, "Stereo Mixer"}, - - /* speaker */ - {"SPP", NULL, "Speaker Enable"}, - {"SPN", NULL, "Speaker Enable"}, - {"Speaker Enable", "Switch", "Spk Amp"}, - {"Spk Amp", NULL, "MIN"}, - - /* mono 2 */ - {"MOUT2", NULL, "Mono 2 Enable"}, - {"Mono 2 Enable", "Switch", "Stereo Mixer"}, - - /* Aux In */ - {"Aux In", NULL, "AUX"}, - - /* ADC */ - {"ADC", NULL, "Input Mixer"}, - {"Input Mixer", "Mic Capture Switch", "Mic"}, - {"Input Mixer", "Aux Capture Switch", "Aux In"}, -}; - -static int ak4535_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets, - ARRAY_SIZE(ak4535_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_new_widgets(codec); - return 0; -} - -static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct ak4535_priv *ak4535 = codec->private_data; - - ak4535->sysclk = freq; - return 0; -} - -static int ak4535_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - struct ak4535_priv *ak4535 = codec->private_data; - u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); - int rate = params_rate(params), fs = 256; - - if (rate) - fs = ak4535->sysclk / rate; - - /* set fs */ - switch (fs) { - case 1024: - mode2 |= (0x2 << 5); - break; - case 512: - mode2 |= (0x1 << 5); - break; - case 256: - break; - } - - /* set rate */ - ak4535_write(codec, AK4535_MODE2, mode2); - return 0; -} - -static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u8 mode1 = 0; - - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - mode1 = 0x0002; - break; - case SND_SOC_DAIFMT_LEFT_J: - mode1 = 0x0001; - break; - default: - return -EINVAL; - } - - /* use 32 fs for BCLK to save power */ - mode1 |= 0x4; - - ak4535_write(codec, AK4535_MODE1, mode1); - return 0; -} - -static int ak4535_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf; - if (!mute) - ak4535_write(codec, AK4535_DAC, mute_reg); - else - ak4535_write(codec, AK4535_DAC, mute_reg | 0x20); - return 0; -} - -static int ak4535_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u16 i; - - switch (level) { - case SND_SOC_BIAS_ON: - ak4535_mute(codec->dai, 0); - break; - case SND_SOC_BIAS_PREPARE: - ak4535_mute(codec->dai, 1); - break; - case SND_SOC_BIAS_STANDBY: - i = ak4535_read_reg_cache(codec, AK4535_PM1); - ak4535_write(codec, AK4535_PM1, i | 0x80); - i = ak4535_read_reg_cache(codec, AK4535_PM2); - ak4535_write(codec, AK4535_PM2, i & (~0x80)); - break; - case SND_SOC_BIAS_OFF: - i = ak4535_read_reg_cache(codec, AK4535_PM1); - ak4535_write(codec, AK4535_PM1, i & (~0x80)); - break; - } - codec->bias_level = level; - return 0; -} - -#define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) - -struct snd_soc_dai ak4535_dai = { - .name = "AK4535", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = AK4535_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = AK4535_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .ops = { - .hw_params = ak4535_hw_params, - }, - .dai_ops = { - .set_fmt = ak4535_set_dai_fmt, - .digital_mute = ak4535_mute, - .set_sysclk = ak4535_set_dai_sysclk, - }, -}; -EXPORT_SYMBOL_GPL(ak4535_dai); - -static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int ak4535_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - ak4535_sync(codec); - ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ak4535_set_bias_level(codec, codec->suspend_bias_level); - return 0; -} - -/* - * initialise the AK4535 driver - * register the mixer and dsp interfaces with the kernel - */ -static int ak4535_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; - - codec->name = "AK4535"; - codec->owner = THIS_MODULE; - codec->read = ak4535_read_reg_cache; - codec->write = ak4535_write; - codec->set_bias_level = ak4535_set_bias_level; - codec->dai = &ak4535_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(ak4535_reg); - codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL); - - if (codec->reg_cache == NULL) - return -ENOMEM; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "ak4535: failed to create pcms\n"); - goto pcm_err; - } - - /* power on device */ - ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - ak4535_add_controls(codec); - ak4535_add_widgets(codec); - ret = snd_soc_register_card(socdev); - if (ret < 0) { - printk(KERN_ERR "ak4535: failed to register card\n"); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - - return ret; -} - -static struct snd_soc_device *ak4535_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -#define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ - -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; - -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver ak4535_i2c_driver; -static struct i2c_client client_template; - -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ -static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) -{ - struct snd_soc_device *socdev = ak4535_socdev; - struct ak4535_setup_data *setup = socdev->codec_data; - struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; - int ret; - - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = i2c_attach_client(i2c); - if (ret < 0) { - printk(KERN_ERR "failed to attach codec at addr %x\n", addr); - goto err; - } - - ret = ak4535_init(socdev); - if (ret < 0) { - printk(KERN_ERR "failed to initialise AK4535\n"); - goto err; - } - return ret; - -err: - kfree(codec); - kfree(i2c); - return ret; -} - -static int ak4535_i2c_detach(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); - kfree(codec->reg_cache); - kfree(client); - return 0; -} - -static int ak4535_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, ak4535_codec_probe); -} - -/* corgi i2c codec control layer */ -static struct i2c_driver ak4535_i2c_driver = { - .driver = { - .name = "AK4535 I2C Codec", - .owner = THIS_MODULE, - }, - .id = I2C_DRIVERID_AK4535, - .attach_adapter = ak4535_i2c_attach, - .detach_client = ak4535_i2c_detach, - .command = NULL, -}; - -static struct i2c_client client_template = { - .name = "AK4535", - .driver = &ak4535_i2c_driver, -}; -#endif - -static int ak4535_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct ak4535_setup_data *setup; - struct snd_soc_codec *codec; - struct ak4535_priv *ak4535; - int ret = 0; - - printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL); - if (ak4535 == NULL) { - kfree(codec); - return -ENOMEM; - } - - codec->private_data = ak4535; - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - ak4535_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; - codec->hw_write = (hw_write_t)i2c_master_send; - codec->hw_read = (hw_read_t)i2c_master_recv; - ret = i2c_add_driver(&ak4535_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); - } -#else - /* Add other interfaces here */ -#endif - return ret; -} - -/* power down chip */ -static int ak4535_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&ak4535_i2c_driver); -#endif - kfree(codec->private_data); - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_ak4535 = { - .probe = ak4535_probe, - .remove = ak4535_remove, - .suspend = ak4535_suspend, - .resume = ak4535_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); - -MODULE_DESCRIPTION("Soc AK4535 driver"); -MODULE_AUTHOR("Richard Purdie"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/ak4535.h b/trunk/sound/soc/codecs/ak4535.h deleted file mode 100644 index e9fe30e2c056..000000000000 --- a/trunk/sound/soc/codecs/ak4535.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ak4535.h -- AK4535 Soc Audio driver - * - * Copyright 2005 Openedhand Ltd. - * - * Author: Richard Purdie - * - * Based on wm8753.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _AK4535_H -#define _AK4535_H - -/* AK4535 register space */ - -#define AK4535_PM1 0x0 -#define AK4535_PM2 0x1 -#define AK4535_SIG1 0x2 -#define AK4535_SIG2 0x3 -#define AK4535_MODE1 0x4 -#define AK4535_MODE2 0x5 -#define AK4535_DAC 0x6 -#define AK4535_MIC 0x7 -#define AK4535_TIMER 0x8 -#define AK4535_ALC1 0x9 -#define AK4535_ALC2 0xa -#define AK4535_PGA 0xb -#define AK4535_LATT 0xc -#define AK4535_RATT 0xd -#define AK4535_VOL 0xe -#define AK4535_STATUS 0xf - -#define AK4535_CACHEREGNUM 0x10 - -struct ak4535_setup_data { - unsigned short i2c_address; -}; - -extern struct snd_soc_dai ak4535_dai; -extern struct snd_soc_codec_device soc_codec_dev_ak4535; - -#endif diff --git a/trunk/sound/soc/codecs/cs4270.c b/trunk/sound/soc/codecs/cs4270.c index 9deb8c74fdfd..e73fcfd9f5cd 100644 --- a/trunk/sound/soc/codecs/cs4270.c +++ b/trunk/sound/soc/codecs/cs4270.c @@ -201,7 +201,7 @@ static struct { * driver what the input settings can be. This would need to be implemented * for stand-alone mode to work. */ -static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, +static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; @@ -251,7 +251,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, * data for playback only, but ASoC currently does not support different * formats for playback vs. record. */ -static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int format) { struct snd_soc_codec *codec = codec_dai->codec; @@ -471,7 +471,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, * board does not have the MUTEA or MUTEB pins connected to such circuitry, * then this function will do nothing. */ -static int cs4270_mute(struct snd_soc_dai *dai, int mute) +static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; int reg6; @@ -667,7 +667,7 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) #endif /* USE_I2C*/ -struct snd_soc_dai cs4270_dai = { +struct snd_soc_codec_dai cs4270_dai = { .name = "CS4270", .playback = { .stream_name = "Playback", diff --git a/trunk/sound/soc/codecs/cs4270.h b/trunk/sound/soc/codecs/cs4270.h index adc6cd9667d4..0ced49b7804d 100644 --- a/trunk/sound/soc/codecs/cs4270.h +++ b/trunk/sound/soc/codecs/cs4270.h @@ -16,7 +16,7 @@ * The ASoC codec DAI structure for the CS4270. Assign this structure to * the .codec_dai field of your machine driver's snd_soc_dai_link structure. */ -extern struct snd_soc_dai cs4270_dai; +extern struct snd_soc_codec_dai cs4270_dai; /* * The ASoC codec device structure for the CS4270. Assign this structure diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index b1dce5f459db..09b1661b8a3a 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -29,7 +29,7 @@ * --------------------------------------- * * Hence the machine layer should disable unsupported inputs/outputs by - * snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc. + * snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0), etc. */ #include @@ -49,7 +49,7 @@ #include "tlv320aic3x.h" #define AUDIO_NAME "aic3x" -#define AIC3X_VERSION "0.2" +#define AIC3X_VERSION "0.1" /* codec private data */ struct aic3x_priv { @@ -138,20 +138,6 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; } -/* - * read from the aic3x register space - */ -static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, - u8 *value) -{ - *value = reg & 0xff; - if (codec->hw_read(codec->control_data, value, 1) != 1) - return -EIO; - - aic3x_write_reg_cache(codec, reg, *value); - return 0; -} - #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \ @@ -206,7 +192,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, } if (found) - snd_soc_dapm_sync(widget->codec); + snd_soc_dapm_sync_endpoints(widget->codec); } ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); @@ -223,8 +209,6 @@ static const char *aic3x_right_hpcom_mux[] = { "differential of HPROUT", "constant VCM", "single-ended", "differential of HPLCOM", "external feedback" }; static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; -static const char *aic3x_adc_hpf[] = - { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; #define LDAC_ENUM 0 #define RDAC_ENUM 1 @@ -234,7 +218,6 @@ static const char *aic3x_adc_hpf[] = #define LINE1R_ENUM 5 #define LINE2L_ENUM 6 #define LINE2R_ENUM 7 -#define ADC_HPF_ENUM 8 static const struct soc_enum aic3x_enum[] = { SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), @@ -245,7 +228,6 @@ static const struct soc_enum aic3x_enum[] = { SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), }; static const struct snd_kcontrol_new aic3x_snd_controls[] = { @@ -296,8 +278,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { /* Input */ SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), - - SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), }; /* add non dapm controls */ @@ -461,34 +441,11 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line2_mux_controls), - /* - * Not a real mic bias widget but similar function. This is for dynamic - * control of GPIO1 digital mic modulator clock output function when - * using digital mic. - */ - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk", - AIC3X_GPIO1_REG, 4, 0xf, - AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK, - AIC3X_GPIO1_FUNC_DISABLED), - - /* - * Also similar function like mic bias. Selects digital mic with - * configurable oversampling rate instead of ADC converter. - */ - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128", - AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64", - AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", - AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), - /* Mic Bias */ - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", - MICBIAS_CTRL, 6, 3, 1, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", - MICBIAS_CTRL, 6, 3, 2, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", - MICBIAS_CTRL, 6, 3, 3, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0), /* Left PGA to Left Output bypass */ SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, @@ -526,7 +483,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_INPUT("LINE2R"), }; -static const struct snd_soc_dapm_route intercon[] = { +static const char *intercon[][3] = { /* Left Output */ {"Left DAC Mux", "DAC_L1", "Left DAC"}, {"Left DAC Mux", "DAC_L2", "Left DAC"}, @@ -597,7 +554,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, {"Left ADC", NULL, "Left PGA Mixer"}, - {"Left ADC", NULL, "GPIO1 dmic modclk"}, /* Right Input */ {"Right Line1R Mux", "single-ended", "LINE1R"}, @@ -611,7 +567,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Right ADC", NULL, "Right PGA Mixer"}, - {"Right ADC", NULL, "GPIO1 dmic modclk"}, /* Left PGA Bypass */ {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, @@ -673,27 +628,101 @@ static const struct snd_soc_dapm_route intercon[] = { {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, - /* - * Logical path between digital mic enable and GPIO1 modulator clock - * output function - */ - {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, - {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, - {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, + /* terminator */ + {NULL, NULL, NULL}, }; static int aic3x_add_widgets(struct snd_soc_codec *codec) { - snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, - ARRAY_SIZE(aic3x_dapm_widgets)); + int i; + + for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); /* set up audio path interconnects */ - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + for (i = 0; intercon[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, intercon[i][0], + intercon[i][1], intercon[i][2]); snd_soc_dapm_new_widgets(codec); return 0; } +struct aic3x_rate_divs { + u32 mclk; + u32 rate; + u32 fsref_reg; + u8 sr_reg:4; + u8 pllj_reg; + u16 plld_reg; +}; + +/* AIC3X codec mclk clock divider coefficients */ +static const struct aic3x_rate_divs aic3x_divs[] = { + /* 8k */ + {12000000, 8000, 48000, 0xa, 16, 3840}, + {19200000, 8000, 48000, 0xa, 10, 2400}, + {22579200, 8000, 48000, 0xa, 8, 7075}, + {33868800, 8000, 48000, 0xa, 5, 8049}, + /* 11.025k */ + {12000000, 11025, 44100, 0x6, 15, 528}, + {19200000, 11025, 44100, 0x6, 9, 4080}, + {22579200, 11025, 44100, 0x6, 8, 0}, + {33868800, 11025, 44100, 0x6, 5, 3333}, + /* 16k */ + {12000000, 16000, 48000, 0x4, 16, 3840}, + {19200000, 16000, 48000, 0x4, 10, 2400}, + {22579200, 16000, 48000, 0x4, 8, 7075}, + {33868800, 16000, 48000, 0x4, 5, 8049}, + /* 22.05k */ + {12000000, 22050, 44100, 0x2, 15, 528}, + {19200000, 22050, 44100, 0x2, 9, 4080}, + {22579200, 22050, 44100, 0x2, 8, 0}, + {33868800, 22050, 44100, 0x2, 5, 3333}, + /* 32k */ + {12000000, 32000, 48000, 0x1, 16, 3840}, + {19200000, 32000, 48000, 0x1, 10, 2400}, + {22579200, 32000, 48000, 0x1, 8, 7075}, + {33868800, 32000, 48000, 0x1, 5, 8049}, + /* 44.1k */ + {12000000, 44100, 44100, 0x0, 15, 528}, + {19200000, 44100, 44100, 0x0, 9, 4080}, + {22579200, 44100, 44100, 0x0, 8, 0}, + {33868800, 44100, 44100, 0x0, 5, 3333}, + /* 48k */ + {12000000, 48000, 48000, 0x0, 16, 3840}, + {19200000, 48000, 48000, 0x0, 10, 2400}, + {22579200, 48000, 48000, 0x0, 8, 7075}, + {33868800, 48000, 48000, 0x0, 5, 8049}, + /* 64k */ + {12000000, 64000, 96000, 0x1, 16, 3840}, + {19200000, 64000, 96000, 0x1, 10, 2400}, + {22579200, 64000, 96000, 0x1, 8, 7075}, + {33868800, 64000, 96000, 0x1, 5, 8049}, + /* 88.2k */ + {12000000, 88200, 88200, 0x0, 15, 528}, + {19200000, 88200, 88200, 0x0, 9, 4080}, + {22579200, 88200, 88200, 0x0, 8, 0}, + {33868800, 88200, 88200, 0x0, 5, 3333}, + /* 96k */ + {12000000, 96000, 96000, 0x0, 16, 3840}, + {19200000, 96000, 96000, 0x0, 10, 2400}, + {22579200, 96000, 96000, 0x0, 8, 7075}, + {33868800, 96000, 96000, 0x0, 5, 8049}, +}; + +static inline int aic3x_get_divs(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) { + if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk) + return i; + } + + return 0; +} + static int aic3x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -701,107 +730,49 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct aic3x_priv *aic3x = codec->private_data; - int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; - u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; - u16 pll_d = 1; + int i; + u8 data, pll_p, pll_r, pll_j; + u16 pll_d; - /* select data word length */ - data = - aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + i = aic3x_get_divs(aic3x->sysclk, params_rate(params)); + + /* Route Left DAC to left channel input and + * right DAC to right channel input */ + data = (LDAC2LCH | RDAC2RCH); + switch (aic3x_divs[i].fsref_reg) { + case 44100: + data |= FSREF_44100; break; - case SNDRV_PCM_FORMAT_S20_3LE: - data |= (0x01 << 4); + case 48000: + data |= FSREF_48000; break; - case SNDRV_PCM_FORMAT_S24_LE: - data |= (0x02 << 4); + case 88200: + data |= FSREF_44100 | DUAL_RATE_MODE; break; - case SNDRV_PCM_FORMAT_S32_LE: - data |= (0x03 << 4); + case 96000: + data |= FSREF_48000 | DUAL_RATE_MODE; break; } - aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); - - /* Fsref can be 44100 or 48000 */ - fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; - - /* Try to find a value for Q which allows us to bypass the PLL and - * generate CODEC_CLK directly. */ - for (pll_q = 2; pll_q < 18; pll_q++) - if (aic3x->sysclk / (128 * pll_q) == fsref) { - bypass_pll = 1; - break; - } - - if (bypass_pll) { - pll_q &= 0xf; - aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); - aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); - } else - aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); - - /* Route Left DAC to left channel input and - * right DAC to right channel input */ - data = (LDAC2LCH | RDAC2RCH); - data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; - if (params_rate(params) >= 64000) - data |= DUAL_RATE_MODE; aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); /* codec sample rate select */ - data = (fsref * 20) / params_rate(params); - if (params_rate(params) < 64000) - data /= 2; - data /= 5; - data -= 2; + data = aic3x_divs[i].sr_reg; data |= (data << 4); aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); - if (bypass_pll) - return 0; - - /* Use PLL - * find an apropriate setup for j, d, r and p by iterating over - * p and r - j and d are calculated for each fraction. - * Up to 128 values are probed, the closest one wins the game. - * The sysclk is divided by 1000 to prevent integer overflows. + /* Use PLL for generation Fsref by equation: + * Fsref = (MCLK * K * R)/(2048 * P); + * Fix P = 2 and R = 1 and calculate K, if + * K = J.D, i.e. J - an interger portion of K and D is the fractional + * one with 4 digits of precision; + * Example: + * For MCLK = 22.5792 MHz and Fsref = 48kHz: + * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074 */ - codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); - - for (r = 1; r <= 16; r++) - for (p = 1; p <= 8; p++) { - int clk, tmp = (codec_clk * pll_r * 10) / pll_p; - u8 j = tmp / 10000; - u16 d = tmp % 10000; - - if (j > 63) - continue; - - if (d != 0 && aic3x->sysclk < 10000000) - continue; - - /* This is actually 1000 * ((j + (d/10000)) * r) / p - * The term had to be converted to get rid of the - * division by 10000 */ - clk = ((10000 * j * r) + (d * r)) / (10 * p); - - /* check whether this values get closer than the best - * ones we had before */ - if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { - pll_j = j; pll_d = d; pll_r = r; pll_p = p; - last_clk = clk; - } - - /* Early exit for exact matches */ - if (clk == codec_clk) - break; - } - - if (last_clk == 0) { - printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); - return -EINVAL; - } + pll_p = 2; + pll_r = 1; + pll_j = aic3x_divs[i].pllj_reg; + pll_d = aic3x_divs[i].plld_reg; data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); @@ -811,10 +782,28 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, aic3x_write(codec, AIC3X_PLL_PROGD_REG, (pll_d & 0x3F) << PLLD_LSB_SHIFT); + /* select data word length */ + data = + aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + data |= (0x01 << 4); + break; + case SNDRV_PCM_FORMAT_S24_LE: + data |= (0x02 << 4); + break; + case SNDRV_PCM_FORMAT_S32_LE: + data |= (0x03 << 4); + break; + } + aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); + return 0; } -static int aic3x_mute(struct snd_soc_dai *dai, int mute) +static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; @@ -831,25 +820,31 @@ static int aic3x_mute(struct snd_soc_dai *dai, int mute) return 0; } -static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, +static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; struct aic3x_priv *aic3x = codec->private_data; - aic3x->sysclk = freq; - return 0; + switch (freq) { + case 12000000: + case 19200000: + case 22579200: + case 33868800: + aic3x->sysclk = freq; + return 0; + } + + return -EINVAL; } -static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; struct aic3x_priv *aic3x = codec->private_data; - u8 iface_areg, iface_breg; - - iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; - iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; + u8 iface_areg = 0; + u8 iface_breg = 0; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -888,14 +883,13 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -static int aic3x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) { struct aic3x_priv *aic3x = codec->private_data; u8 reg; - switch (level) { - case SND_SOC_BIAS_ON: + switch (event) { + case SNDRV_CTL_POWER_D0: /* all power is driven by DAPM system */ if (aic3x->master) { /* enable pll */ @@ -904,9 +898,10 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, reg | PLL_ENABLE); } break; - case SND_SOC_BIAS_PREPARE: + case SNDRV_CTL_POWER_D1: + case SNDRV_CTL_POWER_D2: break; - case SND_SOC_BIAS_STANDBY: + case SNDRV_CTL_POWER_D3hot: /* * all power is driven by DAPM system, * so output power is safe if bypass was set @@ -918,7 +913,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, reg & ~PLL_ENABLE); } break; - case SND_SOC_BIAS_OFF: + case SNDRV_CTL_POWER_D3cold: /* force all power off */ reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); @@ -954,43 +949,16 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, } break; } - codec->bias_level = level; + codec->dapm_state = event; return 0; } -void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) -{ - u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; - u8 bit = gpio ? 3: 0; - u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); - aic3x_write(codec, reg, val | (!!state << bit)); -} -EXPORT_SYMBOL_GPL(aic3x_set_gpio); - -int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) -{ - u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; - u8 val, bit = gpio ? 2: 1; - - aic3x_read(codec, reg, &val); - return (val >> bit) & 1; -} -EXPORT_SYMBOL_GPL(aic3x_get_gpio); - -int aic3x_headset_detected(struct snd_soc_codec *codec) -{ - u8 val; - aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); - return (val >> 2) & 1; -} -EXPORT_SYMBOL_GPL(aic3x_headset_detected); - #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) -struct snd_soc_dai aic3x_dai = { +struct snd_soc_codec_dai aic3x_dai = { .name = "aic3x", .playback = { .stream_name = "Playback", @@ -1020,7 +988,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; - aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); + aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold); return 0; } @@ -1040,7 +1008,7 @@ static int aic3x_resume(struct platform_device *pdev) codec->hw_write(codec->control_data, data, 2); } - aic3x_set_bias_level(codec, codec->suspend_bias_level); + aic3x_dapm_event(codec, codec->suspend_dapm_state); return 0; } @@ -1052,17 +1020,16 @@ static int aic3x_resume(struct platform_device *pdev) static int aic3x_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; - struct aic3x_setup_data *setup = socdev->codec_data; int reg, ret = 0; codec->name = "aic3x"; codec->owner = THIS_MODULE; codec->read = aic3x_read_reg_cache; codec->write = aic3x_write; - codec->set_bias_level = aic3x_set_bias_level; + codec->dapm_event = aic3x_dapm_event; codec->dai = &aic3x_dai; codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); + codec->reg_cache_size = sizeof(aic3x_reg); codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); if (codec->reg_cache == NULL) return -ENOMEM; @@ -1141,11 +1108,7 @@ static int aic3x_init(struct snd_soc_device *socdev) aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); /* off, with power on */ - aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* setup GPIO functions */ - aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); - aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); + aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot); aic3x_add_controls(codec); aic3x_add_widgets(codec); @@ -1254,12 +1217,6 @@ static struct i2c_client client_template = { .name = "AIC3X", .driver = &aic3x_i2c_driver, }; - -static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) -{ - value[0] = i2c_smbus_read_byte_data(client, value[0]); - return (len == 1); -} #endif static int aic3x_probe(struct platform_device *pdev) @@ -1294,7 +1251,6 @@ static int aic3x_probe(struct platform_device *pdev) if (setup->i2c_address) { normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t) i2c_master_send; - codec->hw_read = (hw_read_t) aic3x_i2c_read; ret = i2c_add_driver(&aic3x_i2c_driver); if (ret != 0) printk(KERN_ERR "can't add i2c driver"); @@ -1312,7 +1268,7 @@ static int aic3x_remove(struct platform_device *pdev) /* power down chip */ if (codec->control_data) - aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); + aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); diff --git a/trunk/sound/soc/codecs/tlv320aic3x.h b/trunk/sound/soc/codecs/tlv320aic3x.h index d76c079b86e7..d0cdeeb629de 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.h +++ b/trunk/sound/soc/codecs/tlv320aic3x.h @@ -37,8 +37,6 @@ #define AIC3X_ASD_INTF_CTRLB 9 /* Audio overflow status and PLL R value programming register */ #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 -/* Audio codec digital filter control register */ -#define AIC3X_CODEC_DFILT_CTRL 12 /* ADC PGA Gain control registers */ #define LADC_VOL 15 @@ -110,13 +108,6 @@ #define DACR1_2_RLOPM_VOL 92 #define LLOPM_CTRL 86 #define RLOPM_CTRL 93 -/* GPIO/IRQ registers */ -#define AIC3X_STICKY_IRQ_FLAGS_REG 96 -#define AIC3X_RT_IRQ_FLAGS_REG 97 -#define AIC3X_GPIO1_REG 98 -#define AIC3X_GPIO2_REG 99 -#define AIC3X_GPIOA_REG 100 -#define AIC3X_GPIOB_REG 101 /* Clock generation control register */ #define AIC3X_CLKGEN_CTRL_REG 102 @@ -137,15 +128,12 @@ /* PLL registers bitfields */ #define PLLP_SHIFT 0 -#define PLLQ_SHIFT 3 #define PLLR_SHIFT 0 #define PLLJ_SHIFT 2 #define PLLD_MSB_SHIFT 0 #define PLLD_LSB_SHIFT 2 /* Clock generation register bits */ -#define CODEC_CLKIN_PLLDIV 0 -#define CODEC_CLKIN_CLKDIV 1 #define PLL_CLKIN_SHIFT 4 #define MCLK_SOURCE 0x0 #define PLL_CLKDIV_SHIFT 0 @@ -183,52 +171,11 @@ /* Default input volume */ #define DEFAULT_GAIN 0x20 -/* GPIO API */ -enum { - AIC3X_GPIO1_FUNC_DISABLED = 0, - AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1, - AIC3X_GPIO1_FUNC_CLOCK_MUX = 2, - AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3, - AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4, - AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5, - AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6, - AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7, - AIC3X_GPIO1_FUNC_INPUT = 8, - AIC3X_GPIO1_FUNC_OUTPUT = 9, - AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10, - AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11, - AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12, - AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13, - AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14, - AIC3X_GPIO1_FUNC_ALL_IRQ = 16 -}; - -enum { - AIC3X_GPIO2_FUNC_DISABLED = 0, - AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2, - AIC3X_GPIO2_FUNC_INPUT = 3, - AIC3X_GPIO2_FUNC_OUTPUT = 4, - AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5, - AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8, - AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9, - AIC3X_GPIO2_FUNC_ALL_IRQ = 10, - AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11, - AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12, - AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13, - AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14, - AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 -}; - -void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); -int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); -int aic3x_headset_detected(struct snd_soc_codec *codec); - struct aic3x_setup_data { unsigned short i2c_address; - unsigned int gpio_func[2]; }; -extern struct snd_soc_dai aic3x_dai; +extern struct snd_soc_codec_dai aic3x_dai; extern struct snd_soc_codec_device soc_codec_dev_aic3x; #endif /* _AIC3X_H */ diff --git a/trunk/sound/soc/codecs/uda1380.c b/trunk/sound/soc/codecs/uda1380.c deleted file mode 100644 index a52d6d9e007a..000000000000 --- a/trunk/sound/soc/codecs/uda1380.c +++ /dev/null @@ -1,852 +0,0 @@ -/* - * uda1380.c - Philips UDA1380 ALSA SoC audio driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Copyright (c) 2007 Philipp Zabel - * Improved support for DAPM and audio routing/mixing capabilities, - * added TLV support. - * - * Modified by Richard Purdie to fit into SoC - * codec model. - * - * Copyright (c) 2005 Giorgio Padrin - * Copyright 2005 Openedhand Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "uda1380.h" - -#define UDA1380_VERSION "0.6" -#define AUDIO_NAME "uda1380" - -/* - * uda1380 register cache - */ -static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { - 0x0502, 0x0000, 0x0000, 0x3f3f, - 0x0202, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0xff00, 0x0000, 0x4800, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x8000, 0x0002, 0x0000, -}; - -/* - * read uda1380 register cache - */ -static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == UDA1380_RESET) - return 0; - if (reg >= UDA1380_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write uda1380 register cache - */ -static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= UDA1380_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the UDA1380 register space - */ -static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - - /* data is - * data[0] is register offset - * data[1] is MS byte - * data[2] is LS byte - */ - data[0] = reg; - data[1] = (value & 0xff00) >> 8; - data[2] = value & 0x00ff; - - uda1380_write_reg_cache(codec, reg, value); - - /* the interpolator & decimator regs must only be written when the - * codec DAI is active. - */ - if (!codec->active && (reg >= UDA1380_MVOL)) - return 0; - pr_debug("uda1380: hw write %x val %x\n", reg, value); - if (codec->hw_write(codec->control_data, data, 3) == 3) { - unsigned int val; - i2c_master_send(codec->control_data, data, 1); - i2c_master_recv(codec->control_data, data, 2); - val = (data[0]<<8) | data[1]; - if (val != value) { - pr_debug("uda1380: READ BACK VAL %x\n", - (data[0]<<8) | data[1]); - return -EIO; - } - return 0; - } else - return -EIO; -} - -#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) - -/* declarations of ALSA reg_elem_REAL controls */ -static const char *uda1380_deemp[] = { - "None", - "32kHz", - "44.1kHz", - "48kHz", - "96kHz", -}; -static const char *uda1380_input_sel[] = { - "Line", - "Mic + Line R", - "Line L", - "Mic", -}; -static const char *uda1380_output_sel[] = { - "DAC", - "Analog Mixer", -}; -static const char *uda1380_spf_mode[] = { - "Flat", - "Minimum1", - "Minimum2", - "Maximum" -}; -static const char *uda1380_capture_sel[] = { - "ADC", - "Digital Mixer" -}; -static const char *uda1380_sel_ns[] = { - "3rd-order", - "5th-order" -}; -static const char *uda1380_mix_control[] = { - "off", - "PCM only", - "before sound processing", - "after sound processing" -}; -static const char *uda1380_sdet_setting[] = { - "3200", - "4800", - "9600", - "19200" -}; -static const char *uda1380_os_setting[] = { - "single-speed", - "double-speed (no mixing)", - "quad-speed (no mixing)" -}; - -static const struct soc_enum uda1380_deemp_enum[] = { - SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), - SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), -}; -static const struct soc_enum uda1380_input_sel_enum = - SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ -static const struct soc_enum uda1380_output_sel_enum = - SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */ -static const struct soc_enum uda1380_spf_enum = - SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */ -static const struct soc_enum uda1380_capture_sel_enum = - SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */ -static const struct soc_enum uda1380_sel_ns_enum = - SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */ -static const struct soc_enum uda1380_mix_enum = - SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */ -static const struct soc_enum uda1380_sdet_enum = - SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */ -static const struct soc_enum uda1380_os_enum = - SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */ - -/* - * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) - */ -static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); - -/* - * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored), - * from -66 dB in 0.5 dB steps (2 dB steps, really) and - * from -52 dB in 0.25 dB steps - */ -static const unsigned int mvol_tlv[] = { - TLV_DB_RANGE_HEAD(3), - 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), - 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), - 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0), -}; - -/* - * from -72 dB in 1.5 dB steps (6 dB steps really), - * from -66 dB in 0.75 dB steps (3 dB steps really), - * from -60 dB in 0.5 dB steps (2 dB steps really) and - * from -46 dB in 0.25 dB steps - */ -static const unsigned int vc_tlv[] = { - TLV_DB_RANGE_HEAD(4), - 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), - 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), - 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), - 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0), -}; - -/* from 0 to 6 dB in 2 dB steps if SPF mode != flat */ -static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0); - -/* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts - * off at 18 dB max) */ -static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0); - -/* from -63 to 24 dB in 0.5 dB steps (-128...48) */ -static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1); - -/* from 0 to 24 dB in 3 dB steps */ -static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); - -/* from 0 to 30 dB in 2 dB steps */ -static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0); - -static const struct snd_kcontrol_new uda1380_snd_controls[] = { - SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv), /* AVCR, AVCL */ - SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv), /* MVCL, MVCR */ - SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv), /* VC2 */ - SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv), /* VC1 */ - SOC_ENUM("Sound Processing Filter", uda1380_spf_enum), /* M */ - SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv), /* TRL, TRR */ - SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv), /* BBL, BBR */ -/**/ SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1), /* MTM */ - SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1), /* MT2 from decimation filter */ - SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]), /* DE2 */ - SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1), /* MT1, from digital data input */ - SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]), /* DE1 */ - SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ - SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ - SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ - SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */ - SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ - SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ - SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ - SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv), /* ML_DEC, MR_DEC */ -/**/ SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1), /* MT_ADC */ - SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */ - SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0), /* ADCPOL_INV */ - SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv), /* VGA_CTRL */ - SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0), /* SKIP_DCFIL (before decimator) */ - SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0), /* EN_DCFIL (at output of decimator) */ - SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0), /* TODO: enum, see table 62 */ - SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1), /* AGC_LEVEL */ - /* -5.5, -8, -11.5, -14 dBFS */ - SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), -}; - -/* add non dapm controls */ -static int uda1380_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -/* Input mux */ -static const struct snd_kcontrol_new uda1380_input_mux_control = - SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); - -/* Output mux */ -static const struct snd_kcontrol_new uda1380_output_mux_control = - SOC_DAPM_ENUM("Route", uda1380_output_sel_enum); - -/* Capture mux */ -static const struct snd_kcontrol_new uda1380_capture_mux_control = - SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum); - - -static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { - SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, - &uda1380_input_mux_control), - SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0, - &uda1380_output_mux_control), - SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, - &uda1380_capture_mux_control), - SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0), - SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0), - SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0), - SND_SOC_DAPM_INPUT("VINM"), - SND_SOC_DAPM_INPUT("VINL"), - SND_SOC_DAPM_INPUT("VINR"), - SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0), - SND_SOC_DAPM_OUTPUT("VOUTLHP"), - SND_SOC_DAPM_OUTPUT("VOUTRHP"), - SND_SOC_DAPM_OUTPUT("VOUTL"), - SND_SOC_DAPM_OUTPUT("VOUTR"), - SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0), - SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - - /* output mux */ - {"HeadPhone Driver", NULL, "Output Mux"}, - {"VOUTR", NULL, "Output Mux"}, - {"VOUTL", NULL, "Output Mux"}, - - {"Analog Mixer", NULL, "VINR"}, - {"Analog Mixer", NULL, "VINL"}, - {"Analog Mixer", NULL, "DAC"}, - - {"Output Mux", "DAC", "DAC"}, - {"Output Mux", "Analog Mixer", "Analog Mixer"}, - - /* {"DAC", "Digital Mixer", "I2S" } */ - - /* headphone driver */ - {"VOUTLHP", NULL, "HeadPhone Driver"}, - {"VOUTRHP", NULL, "HeadPhone Driver"}, - - /* input mux */ - {"Left ADC", NULL, "Input Mux"}, - {"Input Mux", "Mic", "Mic LNA"}, - {"Input Mux", "Mic + Line R", "Mic LNA"}, - {"Input Mux", "Line L", "Left PGA"}, - {"Input Mux", "Line", "Left PGA"}, - - /* right input */ - {"Right ADC", "Mic + Line R", "Right PGA"}, - {"Right ADC", "Line", "Right PGA"}, - - /* inputs */ - {"Mic LNA", NULL, "VINM"}, - {"Left PGA", NULL, "VINL"}, - {"Right PGA", NULL, "VINR"}, -}; - -static int uda1380_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets, - ARRAY_SIZE(uda1380_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_new_widgets(codec); - return 0; -} - -static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - int iface; - - /* set up DAI based upon fmt */ - iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); - iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); - - /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - iface |= R01_SFORI_I2S | R01_SFORO_I2S; - break; - case SND_SOC_DAIFMT_LSB: - iface |= R01_SFORI_LSB16 | R01_SFORO_I2S; - break; - case SND_SOC_DAIFMT_MSB: - iface |= R01_SFORI_MSB | R01_SFORO_I2S; - } - - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) - iface |= R01_SIM; - - uda1380_write(codec, UDA1380_IFACE, iface); - - return 0; -} - -/* - * Flush reg cache - * We can only write the interpolator and decimator registers - * when the DAI is being clocked by the CPU DAI. It's up to the - * machine and cpu DAI driver to do this before we are called. - */ -static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - int reg, reg_start, reg_end, clk; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - reg_start = UDA1380_MVOL; - reg_end = UDA1380_MIXER; - } else { - reg_start = UDA1380_DEC; - reg_end = UDA1380_AGC; - } - - /* FIXME disable DAC_CLK */ - clk = uda1380_read_reg_cache(codec, UDA1380_CLK); - uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); - - for (reg = reg_start; reg <= reg_end; reg++) { - pr_debug("uda1380: flush reg %x val %x:", reg, - uda1380_read_reg_cache(codec, reg)); - uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg)); - } - - /* FIXME enable DAC_CLK */ - uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK); - - return 0; -} - -static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); - - /* set WSPLL power and divider if running from this clock */ - if (clk & R00_DAC_CLK) { - int rate = params_rate(params); - u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); - clk &= ~0x3; /* clear SEL_LOOP_DIV */ - switch (rate) { - case 6250 ... 12500: - clk |= 0x0; - break; - case 12501 ... 25000: - clk |= 0x1; - break; - case 25001 ... 50000: - clk |= 0x2; - break; - case 50001 ... 100000: - clk |= 0x3; - break; - } - uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm); - } - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - clk |= R00_EN_DAC | R00_EN_INT; - else - clk |= R00_EN_ADC | R00_EN_DEC; - - uda1380_write(codec, UDA1380_CLK, clk); - return 0; -} - -static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); - - /* shut down WSPLL power if running from this clock */ - if (clk & R00_DAC_CLK) { - u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); - uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm); - } - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - clk &= ~(R00_EN_DAC | R00_EN_INT); - else - clk &= ~(R00_EN_ADC | R00_EN_DEC); - - uda1380_write(codec, UDA1380_CLK, clk); -} - -static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM; - - /* FIXME: mute(codec,0) is called when the magician clock is already - * set to WSPLL, but for some unknown reason writing to interpolator - * registers works only when clocked by SYSCLK */ - u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); - uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk); - if (mute) - uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM); - else - uda1380_write(codec, UDA1380_DEEMP, mute_reg); - uda1380_write(codec, UDA1380_CLK, clk); - return 0; -} - -static int uda1380_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - int pm = uda1380_read_reg_cache(codec, UDA1380_PM); - - switch (level) { - case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: - uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); - break; - case SND_SOC_BIAS_STANDBY: - uda1380_write(codec, UDA1380_PM, R02_PON_BIAS); - break; - case SND_SOC_BIAS_OFF: - uda1380_write(codec, UDA1380_PM, 0x0); - break; - } - codec->bias_level = level; - return 0; -} - -#define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) - -struct snd_soc_dai uda1380_dai[] = { -{ - .name = "UDA1380", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = UDA1380_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = UDA1380_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .ops = { - .hw_params = uda1380_pcm_hw_params, - .shutdown = uda1380_pcm_shutdown, - .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { - .digital_mute = uda1380_mute, - .set_fmt = uda1380_set_dai_fmt, - }, -}, -{ /* playback only - dual interface */ - .name = "UDA1380", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = UDA1380_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = { - .hw_params = uda1380_pcm_hw_params, - .shutdown = uda1380_pcm_shutdown, - .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { - .digital_mute = uda1380_mute, - .set_fmt = uda1380_set_dai_fmt, - }, -}, -{ /* capture only - dual interface*/ - .name = "UDA1380", - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = UDA1380_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = { - .hw_params = uda1380_pcm_hw_params, - .shutdown = uda1380_pcm_shutdown, - .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { - .set_fmt = uda1380_set_dai_fmt, - }, -}, -}; -EXPORT_SYMBOL_GPL(uda1380_dai); - -static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int uda1380_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - int i; - u8 data[2]; - u16 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) { - data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); - data[1] = cache[i] & 0x00ff; - codec->hw_write(codec->control_data, data, 2); - } - uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - uda1380_set_bias_level(codec, codec->suspend_bias_level); - return 0; -} - -/* - * initialise the UDA1380 driver - * register mixer and dsp interfaces with the kernel - */ -static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) -{ - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; - - codec->name = "UDA1380"; - codec->owner = THIS_MODULE; - codec->read = uda1380_read_reg_cache; - codec->write = uda1380_write; - codec->set_bias_level = uda1380_set_bias_level; - codec->dai = uda1380_dai; - codec->num_dai = ARRAY_SIZE(uda1380_dai); - codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); - codec->reg_cache_step = 1; - uda1380_reset(codec); - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - pr_err("uda1380: failed to create pcms\n"); - goto pcm_err; - } - - /* power on device */ - uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* set clock input */ - switch (dac_clk) { - case UDA1380_DAC_CLK_SYSCLK: - uda1380_write(codec, UDA1380_CLK, 0); - break; - case UDA1380_DAC_CLK_WSPLL: - uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK); - break; - } - - /* uda1380 init */ - uda1380_add_controls(codec); - uda1380_add_widgets(codec); - ret = snd_soc_register_card(socdev); - if (ret < 0) { - pr_err("uda1380: failed to register card\n"); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -static struct snd_soc_device *uda1380_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -#define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ - -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; - -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver uda1380_i2c_driver; -static struct i2c_client client_template; - -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ - -static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) -{ - struct snd_soc_device *socdev = uda1380_socdev; - struct uda1380_setup_data *setup = socdev->codec_data; - struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; - int ret; - - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = i2c_attach_client(i2c); - if (ret < 0) { - pr_err("uda1380: failed to attach codec at addr %x\n", addr); - goto err; - } - - ret = uda1380_init(socdev, setup->dac_clk); - if (ret < 0) { - pr_err("uda1380: failed to initialise UDA1380\n"); - goto err; - } - return ret; - -err: - kfree(codec); - kfree(i2c); - return ret; -} - -static int uda1380_i2c_detach(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); - kfree(codec->reg_cache); - kfree(client); - return 0; -} - -static int uda1380_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, uda1380_codec_probe); -} - -static struct i2c_driver uda1380_i2c_driver = { - .driver = { - .name = "UDA1380 I2C Codec", - .owner = THIS_MODULE, - }, - .id = I2C_DRIVERID_UDA1380, - .attach_adapter = uda1380_i2c_attach, - .detach_client = uda1380_i2c_detach, - .command = NULL, -}; - -static struct i2c_client client_template = { - .name = "UDA1380", - .driver = &uda1380_i2c_driver, -}; -#endif - -static int uda1380_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct uda1380_setup_data *setup; - struct snd_soc_codec *codec; - int ret = 0; - - pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - uda1380_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; - codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&uda1380_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); - } -#else - /* Add other interfaces here */ -#endif - return ret; -} - -/* power down chip */ -static int uda1380_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&uda1380_i2c_driver); -#endif - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_uda1380 = { - .probe = uda1380_probe, - .remove = uda1380_remove, - .suspend = uda1380_suspend, - .resume = uda1380_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); - -MODULE_AUTHOR("Giorgio Padrin"); -MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/uda1380.h b/trunk/sound/soc/codecs/uda1380.h deleted file mode 100644 index 50c603e2c9f2..000000000000 --- a/trunk/sound/soc/codecs/uda1380.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Audio support for Philips UDA1380 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Copyright (c) 2005 Giorgio Padrin - */ - -#ifndef _UDA1380_H -#define _UDA1380_H - -#define UDA1380_CLK 0x00 -#define UDA1380_IFACE 0x01 -#define UDA1380_PM 0x02 -#define UDA1380_AMIX 0x03 -#define UDA1380_HP 0x04 -#define UDA1380_MVOL 0x10 -#define UDA1380_MIXVOL 0x11 -#define UDA1380_MODE 0x12 -#define UDA1380_DEEMP 0x13 -#define UDA1380_MIXER 0x14 -#define UDA1380_INTSTAT 0x18 -#define UDA1380_DEC 0x20 -#define UDA1380_PGA 0x21 -#define UDA1380_ADC 0x22 -#define UDA1380_AGC 0x23 -#define UDA1380_DECSTAT 0x28 -#define UDA1380_RESET 0x7f - -#define UDA1380_CACHEREGNUM 0x24 - -/* Register flags */ -#define R00_EN_ADC 0x0800 -#define R00_EN_DEC 0x0400 -#define R00_EN_DAC 0x0200 -#define R00_EN_INT 0x0100 -#define R00_DAC_CLK 0x0010 -#define R01_SFORI_I2S 0x0000 -#define R01_SFORI_LSB16 0x0100 -#define R01_SFORI_LSB18 0x0200 -#define R01_SFORI_LSB20 0x0300 -#define R01_SFORI_MSB 0x0500 -#define R01_SFORI_MASK 0x0700 -#define R01_SFORO_I2S 0x0000 -#define R01_SFORO_LSB16 0x0001 -#define R01_SFORO_LSB18 0x0002 -#define R01_SFORO_LSB20 0x0003 -#define R01_SFORO_LSB24 0x0004 -#define R01_SFORO_MSB 0x0005 -#define R01_SFORO_MASK 0x0007 -#define R01_SEL_SOURCE 0x0040 -#define R01_SIM 0x0010 -#define R02_PON_PLL 0x8000 -#define R02_PON_HP 0x2000 -#define R02_PON_DAC 0x0400 -#define R02_PON_BIAS 0x0100 -#define R02_EN_AVC 0x0080 -#define R02_PON_AVC 0x0040 -#define R02_PON_LNA 0x0010 -#define R02_PON_PGAL 0x0008 -#define R02_PON_ADCL 0x0004 -#define R02_PON_PGAR 0x0002 -#define R02_PON_ADCR 0x0001 -#define R13_MTM 0x4000 -#define R14_SILENCE 0x0080 -#define R14_SDET_ON 0x0040 -#define R21_MT_ADC 0x8000 -#define R22_SEL_LNA 0x0008 -#define R22_SEL_MIC 0x0004 -#define R22_SKIP_DCFIL 0x0002 -#define R23_AGC_EN 0x0001 - -struct uda1380_setup_data { - unsigned short i2c_address; - int dac_clk; -#define UDA1380_DAC_CLK_SYSCLK 0 -#define UDA1380_DAC_CLK_WSPLL 1 -}; - -#define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ -#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ -#define UDA1380_DAI_CAPTURE 2 /* capture DAI */ - -extern struct snd_soc_dai uda1380_dai[3]; -extern struct snd_soc_codec_device soc_codec_dev_uda1380; - -#endif /* _UDA1380_H */ diff --git a/trunk/sound/soc/codecs/wm8510.c b/trunk/sound/soc/codecs/wm8510.c deleted file mode 100644 index 67325fd95447..000000000000 --- a/trunk/sound/soc/codecs/wm8510.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * wm8510.c -- WM8510 ALSA Soc Audio driver - * - * Copyright 2006 Wolfson Microelectronics PLC. - * - * Author: Liam Girdwood - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wm8510.h" - -#define AUDIO_NAME "wm8510" -#define WM8510_VERSION "0.6" - -struct snd_soc_codec_device soc_codec_dev_wm8510; - -/* - * wm8510 register cache - * We can't read the WM8510 register space when we are - * using 2 wire for device control, so we cache them instead. - */ -static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0050, 0x0000, 0x0140, 0x0000, - 0x0000, 0x0000, 0x0000, 0x00ff, - 0x0000, 0x0000, 0x0100, 0x00ff, - 0x0000, 0x0000, 0x012c, 0x002c, - 0x002c, 0x002c, 0x002c, 0x0000, - 0x0032, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0038, 0x000b, 0x0032, 0x0000, - 0x0008, 0x000c, 0x0093, 0x00e9, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0003, 0x0010, 0x0000, 0x0000, - 0x0000, 0x0002, 0x0001, 0x0000, - 0x0000, 0x0000, 0x0039, 0x0000, - 0x0001, -}; - -/* - * read wm8510 register cache - */ -static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == WM8510_RESET) - return 0; - if (reg >= WM8510_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8510 register cache - */ -static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8510_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the WM8510 register space - */ -static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8510 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8510_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) - -static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; -static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; -static const char *wm8510_alc[] = { "ALC", "Limiter" }; - -static const struct soc_enum wm8510_enum[] = { - SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */ - SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */ - SOC_ENUM_SINGLE(WM8510_DAC, 4, 4, wm8510_deemp), - SOC_ENUM_SINGLE(WM8510_ALC3, 8, 2, wm8510_alc), -}; - -static const struct snd_kcontrol_new wm8510_snd_controls[] = { - -SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0), - -SOC_ENUM("DAC Companding", wm8510_enum[1]), -SOC_ENUM("ADC Companding", wm8510_enum[0]), - -SOC_ENUM("Playback De-emphasis", wm8510_enum[2]), -SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0), - -SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0), - -SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0), -SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0), -SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0), - -SOC_SINGLE("Capture Volume", WM8510_ADCVOL, 0, 127, 0), - -SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1, 8, 1, 0), -SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1, 4, 15, 0), -SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1, 0, 15, 0), - -SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2, 4, 7, 0), -SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2, 0, 15, 0), - -SOC_SINGLE("ALC Enable Switch", WM8510_ALC1, 8, 1, 0), -SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1, 3, 7, 0), -SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1, 0, 7, 0), - -SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2, 8, 1, 0), -SOC_SINGLE("ALC Capture Hold", WM8510_ALC2, 4, 7, 0), -SOC_SINGLE("ALC Capture Target", WM8510_ALC2, 0, 15, 0), - -SOC_ENUM("ALC Capture Mode", wm8510_enum[3]), -SOC_SINGLE("ALC Capture Decay", WM8510_ALC3, 4, 15, 0), -SOC_SINGLE("ALC Capture Attack", WM8510_ALC3, 0, 15, 0), - -SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE, 3, 1, 0), -SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE, 0, 7, 0), - -SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA, 7, 1, 0), -SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA, 0, 63, 0), - -SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL, 7, 1, 0), -SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL, 6, 1, 1), -SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL, 0, 63, 0), -SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0), - -SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), -SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), -}; - -/* add non dapm controls */ -static int wm8510_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8510_snd_controls[i], codec, - NULL)); - if (err < 0) - return err; - } - - return 0; -} - -/* Speaker Output Mixer */ -static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { -SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), -SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0), -SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0), -}; - -/* Mono Output Mixer */ -static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = { -SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0), -SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0), -SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), -}; - -static const struct snd_kcontrol_new wm8510_boost_controls[] = { -SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), -SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), -SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), -}; - -static const struct snd_kcontrol_new wm8510_micpga_controls[] = { -SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0), -SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0), -SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0), -}; - -static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = { -SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0, - &wm8510_speaker_mixer_controls[0], - ARRAY_SIZE(wm8510_speaker_mixer_controls)), -SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0, - &wm8510_mono_mixer_controls[0], - ARRAY_SIZE(wm8510_mono_mixer_controls)), -SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0), -SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0), -SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0), -SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), - -SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, - &wm8510_micpga_controls[0], - ARRAY_SIZE(wm8510_micpga_controls)), -SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, - &wm8510_boost_controls[0], - ARRAY_SIZE(wm8510_boost_controls)), - -SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0), - -SND_SOC_DAPM_INPUT("MICN"), -SND_SOC_DAPM_INPUT("MICP"), -SND_SOC_DAPM_INPUT("AUX"), -SND_SOC_DAPM_OUTPUT("MONOOUT"), -SND_SOC_DAPM_OUTPUT("SPKOUTP"), -SND_SOC_DAPM_OUTPUT("SPKOUTN"), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Mono output mixer */ - {"Mono Mixer", "PCM Playback Switch", "DAC"}, - {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, - {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, - - /* Speaker output mixer */ - {"Speaker Mixer", "PCM Playback Switch", "DAC"}, - {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, - {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, - - /* Outputs */ - {"Mono Out", NULL, "Mono Mixer"}, - {"MONOOUT", NULL, "Mono Out"}, - {"SpkN Out", NULL, "Speaker Mixer"}, - {"SpkP Out", NULL, "Speaker Mixer"}, - {"SPKOUTN", NULL, "SpkN Out"}, - {"SPKOUTP", NULL, "SpkP Out"}, - - /* Microphone PGA */ - {"Mic PGA", "MICN Switch", "MICN"}, - {"Mic PGA", "MICP Switch", "MICP"}, - { "Mic PGA", "AUX Switch", "Aux Input" }, - - /* Boost Mixer */ - {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, - {"Boost Mixer", "Mic Volume", "MICP"}, - {"Boost Mixer", "Aux Volume", "Aux Input"}, - - {"ADC", NULL, "Boost Mixer"}, -}; - -static int wm8510_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets, - ARRAY_SIZE(wm8510_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_new_widgets(codec); - return 0; -} - -struct pll_ { - unsigned int pre_div:4; /* prescale - 1 */ - unsigned int n:4; - unsigned int k; -}; - -static struct pll_ pll_div; - -/* The size in bits of the pll divide multiplied by 10 - * to allow rounding later */ -#define FIXED_PLL_SIZE ((1 << 24) * 10) - -static void pll_factors(unsigned int target, unsigned int source) -{ - unsigned long long Kpart; - unsigned int K, Ndiv, Nmod; - - Ndiv = target / source; - if (Ndiv < 6) { - source >>= 1; - pll_div.pre_div = 1; - Ndiv = target / source; - } else - pll_div.pre_div = 0; - - if ((Ndiv < 6) || (Ndiv > 12)) - printk(KERN_WARNING - "WM8510 N value %d outwith recommended range!d\n", - Ndiv); - - pll_div.n = Ndiv; - Nmod = target % source; - Kpart = FIXED_PLL_SIZE * (long long)Nmod; - - do_div(Kpart, source); - - K = Kpart & 0xFFFFFFFF; - - /* Check if we need to round */ - if ((K % 10) >= 5) - K += 5; - - /* Move down to proper range now rounding is done */ - K /= 10; - - pll_div.k = K; -} - -static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - - if (freq_in == 0 || freq_out == 0) { - /* Clock CODEC directly from MCLK */ - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); - wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); - - /* Turn off PLL */ - reg = wm8510_read_reg_cache(codec, WM8510_POWER1); - wm8510_write(codec, WM8510_POWER1, reg & 0x1df); - return 0; - } - - pll_factors(freq_out*8, freq_in); - - wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); - wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); - wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); - wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); - reg = wm8510_read_reg_cache(codec, WM8510_POWER1); - wm8510_write(codec, WM8510_POWER1, reg | 0x020); - - /* Run CODEC from PLL instead of MCLK */ - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); - wm8510_write(codec, WM8510_CLOCK, reg | 0x100); - - return 0; -} - -/* - * Configure WM8510 clock dividers. - */ -static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, - int div_id, int div) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - - switch (div_id) { - case WM8510_OPCLKDIV: - reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; - wm8510_write(codec, WM8510_GPIO, reg | div); - break; - case WM8510_MCLKDIV: - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; - wm8510_write(codec, WM8510_CLOCK, reg | div); - break; - case WM8510_ADCCLK: - reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; - wm8510_write(codec, WM8510_ADC, reg | div); - break; - case WM8510_DACCLK: - reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; - wm8510_write(codec, WM8510_DAC, reg | div); - break; - case WM8510_BCLKDIV: - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; - wm8510_write(codec, WM8510_CLOCK, reg | div); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = 0; - u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - clk |= 0x0001; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - iface |= 0x0010; - break; - case SND_SOC_DAIFMT_RIGHT_J: - break; - case SND_SOC_DAIFMT_LEFT_J: - iface |= 0x0008; - break; - case SND_SOC_DAIFMT_DSP_A: - iface |= 0x00018; - break; - default: - return -EINVAL; - } - - /* clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - iface |= 0x0180; - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= 0x0100; - break; - case SND_SOC_DAIFMT_NB_IF: - iface |= 0x0080; - break; - default: - return -EINVAL; - } - - wm8510_write(codec, WM8510_IFACE, iface); - wm8510_write(codec, WM8510_CLOCK, clk); - return 0; -} - -static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; - u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; - - /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - iface |= 0x0020; - break; - case SNDRV_PCM_FORMAT_S24_LE: - iface |= 0x0040; - break; - case SNDRV_PCM_FORMAT_S32_LE: - iface |= 0x0060; - break; - } - - /* filter coefficient */ - switch (params_rate(params)) { - case SNDRV_PCM_RATE_8000: - adn |= 0x5 << 1; - break; - case SNDRV_PCM_RATE_11025: - adn |= 0x4 << 1; - break; - case SNDRV_PCM_RATE_16000: - adn |= 0x3 << 1; - break; - case SNDRV_PCM_RATE_22050: - adn |= 0x2 << 1; - break; - case SNDRV_PCM_RATE_32000: - adn |= 0x1 << 1; - break; - case SNDRV_PCM_RATE_44100: - case SNDRV_PCM_RATE_48000: - break; - } - - wm8510_write(codec, WM8510_IFACE, iface); - wm8510_write(codec, WM8510_ADD, adn); - return 0; -} - -static int wm8510_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; - - if (mute) - wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); - else - wm8510_write(codec, WM8510_DAC, mute_reg); - return 0; -} - -/* liam need to make this lower power with dapm */ -static int wm8510_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - - switch (level) { - case SND_SOC_BIAS_ON: - wm8510_write(codec, WM8510_POWER1, 0x1ff); - wm8510_write(codec, WM8510_POWER2, 0x1ff); - wm8510_write(codec, WM8510_POWER3, 0x1ff); - break; - case SND_SOC_BIAS_PREPARE: - case SND_SOC_BIAS_STANDBY: - break; - case SND_SOC_BIAS_OFF: - /* everything off, dac mute, inactive */ - wm8510_write(codec, WM8510_POWER1, 0x0); - wm8510_write(codec, WM8510_POWER2, 0x0); - wm8510_write(codec, WM8510_POWER3, 0x0); - break; - } - codec->bias_level = level; - return 0; -} - -#define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) - -#define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -struct snd_soc_dai wm8510_dai = { - .name = "WM8510 HiFi", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = WM8510_RATES, - .formats = WM8510_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - .rates = WM8510_RATES, - .formats = WM8510_FORMATS,}, - .ops = { - .hw_params = wm8510_pcm_hw_params, - }, - .dai_ops = { - .digital_mute = wm8510_mute, - .set_fmt = wm8510_set_dai_fmt, - .set_clkdiv = wm8510_set_dai_clkdiv, - .set_pll = wm8510_set_dai_pll, - }, -}; -EXPORT_SYMBOL_GPL(wm8510_dai); - -static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8510_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - int i; - u8 data[2]; - u16 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) { - data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); - data[1] = cache[i] & 0x00ff; - codec->hw_write(codec->control_data, data, 2); - } - wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - wm8510_set_bias_level(codec, codec->suspend_bias_level); - return 0; -} - -/* - * initialise the WM8510 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8510_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; - - codec->name = "WM8510"; - codec->owner = THIS_MODULE; - codec->read = wm8510_read_reg_cache; - codec->write = wm8510_write; - codec->set_bias_level = wm8510_set_bias_level; - codec->dai = &wm8510_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8510_reg); - codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL); - - if (codec->reg_cache == NULL) - return -ENOMEM; - - wm8510_reset(codec); - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "wm8510: failed to create pcms\n"); - goto pcm_err; - } - - /* power on device */ - wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - wm8510_add_controls(codec); - wm8510_add_widgets(codec); - ret = snd_soc_register_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8510: failed to register card\n"); - goto card_err; - } - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -static struct snd_soc_device *wm8510_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* - * WM8510 2 wire address is 0x1a - */ -#define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ - -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; - -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver wm8510_i2c_driver; -static struct i2c_client client_template; - -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ - -static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) -{ - struct snd_soc_device *socdev = wm8510_socdev; - struct wm8510_setup_data *setup = socdev->codec_data; - struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; - int ret; - - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = i2c_attach_client(i2c); - if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); - goto err; - } - - ret = wm8510_init(socdev); - if (ret < 0) { - pr_err("failed to initialise WM8510\n"); - goto err; - } - return ret; - -err: - kfree(codec); - kfree(i2c); - return ret; -} - -static int wm8510_i2c_detach(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); - kfree(codec->reg_cache); - kfree(client); - return 0; -} - -static int wm8510_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, wm8510_codec_probe); -} - -/* corgi i2c codec control layer */ -static struct i2c_driver wm8510_i2c_driver = { - .driver = { - .name = "WM8510 I2C Codec", - .owner = THIS_MODULE, - }, - .id = I2C_DRIVERID_WM8510, - .attach_adapter = wm8510_i2c_attach, - .detach_client = wm8510_i2c_detach, - .command = NULL, -}; - -static struct i2c_client client_template = { - .name = "WM8510", - .driver = &wm8510_i2c_driver, -}; -#endif - -static int wm8510_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8510_setup_data *setup; - struct snd_soc_codec *codec; - int ret = 0; - - pr_info("WM8510 Audio Codec %s", WM8510_VERSION); - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - wm8510_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; - codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8510_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); - } -#else - /* Add other interfaces here */ -#endif - return ret; -} - -/* power down chip */ -static int wm8510_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8510_i2c_driver); -#endif - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_wm8510 = { - .probe = wm8510_probe, - .remove = wm8510_remove, - .suspend = wm8510_suspend, - .resume = wm8510_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); - -MODULE_DESCRIPTION("ASoC WM8510 driver"); -MODULE_AUTHOR("Liam Girdwood"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8510.h b/trunk/sound/soc/codecs/wm8510.h deleted file mode 100644 index f5d2e42eb3f4..000000000000 --- a/trunk/sound/soc/codecs/wm8510.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * wm8510.h -- WM8510 Soc Audio driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _WM8510_H -#define _WM8510_H - -/* WM8510 register space */ - -#define WM8510_RESET 0x0 -#define WM8510_POWER1 0x1 -#define WM8510_POWER2 0x2 -#define WM8510_POWER3 0x3 -#define WM8510_IFACE 0x4 -#define WM8510_COMP 0x5 -#define WM8510_CLOCK 0x6 -#define WM8510_ADD 0x7 -#define WM8510_GPIO 0x8 -#define WM8510_DAC 0xa -#define WM8510_DACVOL 0xb -#define WM8510_ADC 0xe -#define WM8510_ADCVOL 0xf -#define WM8510_EQ1 0x12 -#define WM8510_EQ2 0x13 -#define WM8510_EQ3 0x14 -#define WM8510_EQ4 0x15 -#define WM8510_EQ5 0x16 -#define WM8510_DACLIM1 0x18 -#define WM8510_DACLIM2 0x19 -#define WM8510_NOTCH1 0x1b -#define WM8510_NOTCH2 0x1c -#define WM8510_NOTCH3 0x1d -#define WM8510_NOTCH4 0x1e -#define WM8510_ALC1 0x20 -#define WM8510_ALC2 0x21 -#define WM8510_ALC3 0x22 -#define WM8510_NGATE 0x23 -#define WM8510_PLLN 0x24 -#define WM8510_PLLK1 0x25 -#define WM8510_PLLK2 0x26 -#define WM8510_PLLK3 0x27 -#define WM8510_ATTEN 0x28 -#define WM8510_INPUT 0x2c -#define WM8510_INPPGA 0x2d -#define WM8510_ADCBOOST 0x2f -#define WM8510_OUTPUT 0x31 -#define WM8510_SPKMIX 0x32 -#define WM8510_SPKVOL 0x36 -#define WM8510_MONOMIX 0x38 - -#define WM8510_CACHEREGNUM 57 - -/* Clock divider Id's */ -#define WM8510_OPCLKDIV 0 -#define WM8510_MCLKDIV 1 -#define WM8510_ADCCLK 2 -#define WM8510_DACCLK 3 -#define WM8510_BCLKDIV 4 - -/* DAC clock dividers */ -#define WM8510_DACCLK_F2 (1 << 3) -#define WM8510_DACCLK_F4 (0 << 3) - -/* ADC clock dividers */ -#define WM8510_ADCCLK_F2 (1 << 3) -#define WM8510_ADCCLK_F4 (0 << 3) - -/* PLL Out dividers */ -#define WM8510_OPCLKDIV_1 (0 << 4) -#define WM8510_OPCLKDIV_2 (1 << 4) -#define WM8510_OPCLKDIV_3 (2 << 4) -#define WM8510_OPCLKDIV_4 (3 << 4) - -/* BCLK clock dividers */ -#define WM8510_BCLKDIV_1 (0 << 2) -#define WM8510_BCLKDIV_2 (1 << 2) -#define WM8510_BCLKDIV_4 (2 << 2) -#define WM8510_BCLKDIV_8 (3 << 2) -#define WM8510_BCLKDIV_16 (4 << 2) -#define WM8510_BCLKDIV_32 (5 << 2) - -/* MCLK clock dividers */ -#define WM8510_MCLKDIV_1 (0 << 5) -#define WM8510_MCLKDIV_1_5 (1 << 5) -#define WM8510_MCLKDIV_2 (2 << 5) -#define WM8510_MCLKDIV_3 (3 << 5) -#define WM8510_MCLKDIV_4 (4 << 5) -#define WM8510_MCLKDIV_6 (5 << 5) -#define WM8510_MCLKDIV_8 (6 << 5) -#define WM8510_MCLKDIV_12 (7 << 5) - -struct wm8510_setup_data { - unsigned short i2c_address; -}; - -extern struct snd_soc_dai wm8510_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm8510; - -#endif diff --git a/trunk/sound/soc/codecs/wm8731.c b/trunk/sound/soc/codecs/wm8731.c index 369d39c3f745..0cf9265fca8f 100644 --- a/trunk/sound/soc/codecs/wm8731.c +++ b/trunk/sound/soc/codecs/wm8731.c @@ -31,6 +31,25 @@ #define AUDIO_NAME "wm8731" #define WM8731_VERSION "0.13" +/* + * Debug + */ + +#define WM8731_DEBUG 0 + +#ifdef WM8731_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + struct snd_soc_codec_device soc_codec_dev_wm8731; /* codec private data */ @@ -174,7 +193,7 @@ SND_SOC_DAPM_INPUT("RLINEIN"), SND_SOC_DAPM_INPUT("LLINEIN"), }; -static const struct snd_soc_dapm_route intercon[] = { +static const char *intercon[][3] = { /* output mixer */ {"Output Mixer", "Line Bypass Switch", "Line Input"}, {"Output Mixer", "HiFi Playback Switch", "DAC"}, @@ -195,14 +214,22 @@ static const struct snd_soc_dapm_route intercon[] = { {"Line Input", NULL, "LLINEIN"}, {"Line Input", NULL, "RLINEIN"}, {"Mic Bias", NULL, "MICIN"}, + + /* terminator */ + {NULL, NULL, NULL}, }; static int wm8731_add_widgets(struct snd_soc_codec *codec) { - snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, - ARRAY_SIZE(wm8731_dapm_widgets)); + int i; + + for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + /* set up audio path interconnects */ + for (i = 0; intercon[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, intercon[i][0], + intercon[i][1], intercon[i][2]); snd_soc_dapm_new_widgets(codec); return 0; @@ -318,7 +345,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream) } } -static int wm8731_mute(struct snd_soc_dai *dai, int mute) +static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; @@ -330,7 +357,7 @@ static int wm8731_mute(struct snd_soc_dai *dai, int mute) return 0; } -static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, +static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; @@ -349,7 +376,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, } -static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -408,29 +435,29 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -static int wm8731_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) { u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; - switch (level) { - case SND_SOC_BIAS_ON: + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ /* vref/mid, osc on, dac unmute */ wm8731_write(codec, WM8731_PWR, reg); break; - case SND_SOC_BIAS_PREPARE: + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ break; - case SND_SOC_BIAS_STANDBY: + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ /* everything off except vref/vmid, */ wm8731_write(codec, WM8731_PWR, reg | 0x0040); break; - case SND_SOC_BIAS_OFF: + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ /* everything off, dac mute, inactive */ wm8731_write(codec, WM8731_ACTIVE, 0x0); wm8731_write(codec, WM8731_PWR, 0xffff); break; } - codec->bias_level = level; + codec->dapm_state = event; return 0; } @@ -443,7 +470,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) -struct snd_soc_dai wm8731_dai = { +struct snd_soc_codec_dai wm8731_dai = { .name = "WM8731", .playback = { .stream_name = "Playback", @@ -476,7 +503,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_codec *codec = socdev->codec; wm8731_write(codec, WM8731_ACTIVE, 0x0); - wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); return 0; } @@ -494,8 +521,8 @@ static int wm8731_resume(struct platform_device *pdev) data[1] = cache[i] & 0x00ff; codec->hw_write(codec->control_data, data, 2); } - wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - wm8731_set_bias_level(codec, codec->suspend_bias_level); + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + wm8731_dapm_event(codec, codec->suspend_dapm_state); return 0; } @@ -512,10 +539,10 @@ static int wm8731_init(struct snd_soc_device *socdev) codec->owner = THIS_MODULE; codec->read = wm8731_read_reg_cache; codec->write = wm8731_write; - codec->set_bias_level = wm8731_set_bias_level; + codec->dapm_event = wm8731_dapm_event; codec->dai = &wm8731_dai; codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); + codec->reg_cache_size = sizeof(wm8731_reg); codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); if (codec->reg_cache == NULL) return -ENOMEM; @@ -530,7 +557,7 @@ static int wm8731_init(struct snd_soc_device *socdev) } /* power on device */ - wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); /* set the update bits */ reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); @@ -605,13 +632,13 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) ret = i2c_attach_client(i2c); if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); + err("failed to attach codec at addr %x\n", addr); goto err; } ret = wm8731_init(socdev); if (ret < 0) { - pr_err("failed to initialise WM8731\n"); + err("failed to initialise WM8731\n"); goto err; } return ret; @@ -662,7 +689,7 @@ static int wm8731_probe(struct platform_device *pdev) struct wm8731_priv *wm8731; int ret = 0; - pr_info("WM8731 Audio Codec %s", WM8731_VERSION); + info("WM8731 Audio Codec %s", WM8731_VERSION); setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); @@ -703,7 +730,7 @@ static int wm8731_remove(struct platform_device *pdev) struct snd_soc_codec *codec = socdev->codec; if (codec->control_data) - wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); diff --git a/trunk/sound/soc/codecs/wm8731.h b/trunk/sound/soc/codecs/wm8731.h index 99f2e3c60e33..5bcab6a7afb4 100644 --- a/trunk/sound/soc/codecs/wm8731.h +++ b/trunk/sound/soc/codecs/wm8731.h @@ -38,7 +38,7 @@ struct wm8731_setup_data { unsigned short i2c_address; }; -extern struct snd_soc_dai wm8731_dai; +extern struct snd_soc_codec_dai wm8731_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8731; #endif diff --git a/trunk/sound/soc/codecs/wm8750.c b/trunk/sound/soc/codecs/wm8750.c index e23cb09f0d14..16cd5d4d5ad9 100644 --- a/trunk/sound/soc/codecs/wm8750.c +++ b/trunk/sound/soc/codecs/wm8750.c @@ -31,6 +31,25 @@ #define AUDIO_NAME "WM8750" #define WM8750_VERSION "0.12" +/* + * Debug + */ + +#define WM8750_DEBUG 0 + +#ifdef WM8750_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + /* codec private data */ struct wm8750_priv { unsigned int sysclk; @@ -359,7 +378,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { SND_SOC_DAPM_INPUT("RINPUT3"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* left mixer */ {"Left Mixer", "Playback Switch", "Left DAC"}, {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, @@ -451,14 +470,22 @@ static const struct snd_soc_dapm_route audio_map[] = { /* ADC */ {"Left ADC", NULL, "Left ADC Mux"}, {"Right ADC", NULL, "Right ADC Mux"}, + + /* terminator */ + {NULL, NULL, NULL}, }; static int wm8750_add_widgets(struct snd_soc_codec *codec) { - snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, - ARRAY_SIZE(wm8750_dapm_widgets)); + int i; + + for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + /* set up audio path audio_mapnects */ + for (i = 0; audio_map[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); snd_soc_dapm_new_widgets(codec); return 0; @@ -536,7 +563,7 @@ static inline int get_coeff(int mclk, int rate) return -EINVAL; } -static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, +static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; @@ -554,7 +581,7 @@ static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, return -EINVAL; } -static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -647,7 +674,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wm8750_mute(struct snd_soc_dai *dai, int mute) +static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; @@ -659,29 +686,29 @@ static int wm8750_mute(struct snd_soc_dai *dai, int mute) return 0; } -static int wm8750_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) { u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; - switch (level) { - case SND_SOC_BIAS_ON: + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ /* set vmid to 50k and unmute dac */ wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); break; - case SND_SOC_BIAS_PREPARE: + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ /* set vmid to 5k for quick power up */ wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); break; - case SND_SOC_BIAS_STANDBY: + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ /* mute dac and set vmid to 500k, enable VREF */ wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); break; - case SND_SOC_BIAS_OFF: + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ wm8750_write(codec, WM8750_PWR1, 0x0001); break; } - codec->bias_level = level; + codec->dapm_state = event; return 0; } @@ -692,7 +719,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec, #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) -struct snd_soc_dai wm8750_dai = { +struct snd_soc_codec_dai wm8750_dai = { .name = "WM8750", .playback = { .stream_name = "Playback", @@ -721,7 +748,7 @@ static void wm8750_work(struct work_struct *work) { struct snd_soc_codec *codec = container_of(work, struct snd_soc_codec, delayed_work.work); - wm8750_set_bias_level(codec, codec->bias_level); + wm8750_dapm_event(codec, codec->dapm_state); } static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) @@ -729,7 +756,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; - wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); return 0; } @@ -750,12 +777,12 @@ static int wm8750_resume(struct platform_device *pdev) codec->hw_write(codec->control_data, data, 2); } - wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot); /* charge wm8750 caps */ - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { - wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_ON; + if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D0; schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); } @@ -776,10 +803,10 @@ static int wm8750_init(struct snd_soc_device *socdev) codec->owner = THIS_MODULE; codec->read = wm8750_read_reg_cache; codec->write = wm8750_write; - codec->set_bias_level = wm8750_set_bias_level; + codec->dapm_event = wm8750_dapm_event; codec->dai = &wm8750_dai; codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); + codec->reg_cache_size = sizeof(wm8750_reg); codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); if (codec->reg_cache == NULL) return -ENOMEM; @@ -794,8 +821,8 @@ static int wm8750_init(struct snd_soc_device *socdev) } /* charge output caps */ - wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_STANDBY; + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D3hot; schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); /* set the update bits */ @@ -877,13 +904,13 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) ret = i2c_attach_client(i2c); if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); + err("failed to attach codec at addr %x\n", addr); goto err; } ret = wm8750_init(socdev); if (ret < 0) { - pr_err("failed to initialise WM8750\n"); + err("failed to initialise WM8750\n"); goto err; } return ret; @@ -934,7 +961,7 @@ static int wm8750_probe(struct platform_device *pdev) struct wm8750_priv *wm8750; int ret = 0; - pr_info("WM8750 Audio Codec %s", WM8750_VERSION); + info("WM8750 Audio Codec %s", WM8750_VERSION); codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; @@ -994,7 +1021,7 @@ static int wm8750_remove(struct platform_device *pdev) struct snd_soc_codec *codec = socdev->codec; if (codec->control_data) - wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); run_delayed_work(&codec->delayed_work); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); diff --git a/trunk/sound/soc/codecs/wm8750.h b/trunk/sound/soc/codecs/wm8750.h index 8ef30e628b21..a97a54a6348e 100644 --- a/trunk/sound/soc/codecs/wm8750.h +++ b/trunk/sound/soc/codecs/wm8750.h @@ -61,7 +61,7 @@ struct wm8750_setup_data { unsigned short i2c_address; }; -extern struct snd_soc_dai wm8750_dai; +extern struct snd_soc_codec_dai wm8750_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8750; #endif diff --git a/trunk/sound/soc/codecs/wm8753.c b/trunk/sound/soc/codecs/wm8753.c index 8604809f0c36..fb41826c4c4c 100644 --- a/trunk/sound/soc/codecs/wm8753.c +++ b/trunk/sound/soc/codecs/wm8753.c @@ -55,6 +55,25 @@ #define AUDIO_NAME "wm8753" #define WM8753_VERSION "0.16" +/* + * Debug + */ + +#define WM8753_DEBUG 0 + +#ifdef WM8753_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + static int caps_charge = 2000; module_param(caps_charge, int, 0); MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); @@ -241,50 +260,28 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, return 1; } -static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); -static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); -static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); -static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); -static const unsigned int out_tlv[] = { - TLV_DB_RANGE_HEAD(2), - /* 0000000 - 0101111 = "Analogue mute" */ - 0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0), - 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0), -}; -static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0); -static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0); -static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); static const struct snd_kcontrol_new wm8753_snd_controls[] = { -SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv), - -SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0, - adc_tlv), - -SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, - 0, 127, 0, out_tlv), -SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, - 127, 0, out_tlv), - -SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv), - -SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, - 1, mix_tlv), -SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, - 7, 1, mix_tlv), -SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, - 1, voice_mix_tlv), - -SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, - 1, 0), -SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, - 1, 0), - -SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv), -SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1, - mix_tlv), -SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1, - voice_mix_tlv), +SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0), + +SOC_DOUBLE_R("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0), + +SOC_DOUBLE_R("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, 0, 127, 0), +SOC_DOUBLE_R("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, 127, 0), + +SOC_SINGLE("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0), + +SOC_DOUBLE_R("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, 1), +SOC_DOUBLE_R("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, 7, 1), +SOC_DOUBLE_R("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, 1), + +SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, 1, 0), +SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, 1, 0), + +SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1), +SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1), +SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1), SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), SOC_ENUM("Bass Boost", wm8753_enum[0]), @@ -294,13 +291,10 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1), SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), SOC_ENUM("Treble Cut-off", wm8753_enum[2]), -SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, - rec_mix_tlv), -SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, - rec_mix_tlv), +SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv), +SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv), -SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0, - pga_tlv), +SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0), SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), @@ -332,8 +326,8 @@ SOC_ENUM("De-emphasis", wm8753_enum[8]), SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), SOC_ENUM("Playback Phase", wm8753_enum[10]), -SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv), -SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv), +SOC_SINGLE("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0), +SOC_SINGLE("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0), SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), @@ -529,7 +523,7 @@ SND_SOC_DAPM_INPUT("MIC2"), SND_SOC_DAPM_VMID("VREF"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* left mixer */ {"Left Mixer", "Left Playback Switch", "Left DAC"}, {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, @@ -680,14 +674,23 @@ static const struct snd_soc_dapm_route audio_map[] = { /* ACOP */ {"ACOP", NULL, "ALC Mixer"}, + + /* terminator */ + {NULL, NULL, NULL}, }; static int wm8753_add_widgets(struct snd_soc_codec *codec) { - snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, - ARRAY_SIZE(wm8753_dapm_widgets)); + int i; - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]); + + /* set up the WM8753 audio map */ + for (i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } snd_soc_dapm_new_widgets(codec); return 0; @@ -740,7 +743,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, pll_div->k = K; } -static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, +static int wm8753_set_dai_pll(struct snd_soc_codec_dai *codec_dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { u16 reg, enable; @@ -863,7 +866,7 @@ static int get_coeff(int mclk, int rate) /* * Clock after PLL and dividers */ -static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, +static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; @@ -890,7 +893,7 @@ static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, /* * Set's ADC and Voice DAC format. */ -static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -960,7 +963,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, /* * Set's PCM dai fmt and BCLK. */ -static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1026,7 +1029,7 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, +static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, int div_id, int div) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1054,7 +1057,7 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, /* * Set's HiFi DAC format. */ -static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1087,7 +1090,7 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, /* * Set's I2S DAI format. */ -static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1195,7 +1198,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1210,7 +1213,7 @@ static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, return wm8753_pcm_set_dai_fmt(codec_dai, fmt); } -static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) @@ -1218,7 +1221,7 @@ static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, return wm8753_i2s_set_dai_fmt(codec_dai, fmt); } -static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1233,7 +1236,7 @@ static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, return wm8753_i2s_set_dai_fmt(codec_dai, fmt); } -static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -1250,7 +1253,7 @@ static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, return wm8753_i2s_set_dai_fmt(codec_dai, fmt); } -static int wm8753_mute(struct snd_soc_dai *dai, int mute) +static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; @@ -1271,29 +1274,29 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) return 0; } -static int wm8753_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static int wm8753_dapm_event(struct snd_soc_codec *codec, int event) { u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; - switch (level) { - case SND_SOC_BIAS_ON: + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ /* set vmid to 50k and unmute dac */ wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); break; - case SND_SOC_BIAS_PREPARE: + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ /* set vmid to 5k for quick power up */ wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); break; - case SND_SOC_BIAS_STANDBY: + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ /* mute dac and set vmid to 500k, enable VREF */ wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); break; - case SND_SOC_BIAS_OFF: + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ wm8753_write(codec, WM8753_PWR1, 0x0001); break; } - codec->bias_level = level; + codec->dapm_state = event; return 0; } @@ -1316,7 +1319,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, * 3. Voice disabled - HIFI over HIFI * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture */ -static const struct snd_soc_dai wm8753_all_dai[] = { +static const struct snd_soc_codec_dai wm8753_all_dai[] = { /* DAI HiFi mode 1 */ { .name = "WM8753 HiFi", .id = 1, @@ -1456,7 +1459,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { }, }; -struct snd_soc_dai wm8753_dai[2]; +struct snd_soc_codec_dai wm8753_dai[2]; EXPORT_SYMBOL_GPL(wm8753_dai); static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) @@ -1497,7 +1500,7 @@ static void wm8753_work(struct work_struct *work) { struct snd_soc_codec *codec = container_of(work, struct snd_soc_codec, delayed_work.work); - wm8753_set_bias_level(codec, codec->bias_level); + wm8753_dapm_event(codec, codec->dapm_state); } static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) @@ -1509,7 +1512,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) if (!codec->card) return 0; - wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); + wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); return 0; } @@ -1534,12 +1537,12 @@ static int wm8753_resume(struct platform_device *pdev) codec->hw_write(codec->control_data, data, 2); } - wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3hot); /* charge wm8753 caps */ - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { - wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_ON; + if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { + wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D0; schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(caps_charge)); } @@ -1560,10 +1563,10 @@ static int wm8753_init(struct snd_soc_device *socdev) codec->owner = THIS_MODULE; codec->read = wm8753_read_reg_cache; codec->write = wm8753_write; - codec->set_bias_level = wm8753_set_bias_level; + codec->dapm_event = wm8753_dapm_event; codec->dai = wm8753_dai; codec->num_dai = 2; - codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); + codec->reg_cache_size = sizeof(wm8753_reg); codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); if (codec->reg_cache == NULL) @@ -1581,8 +1584,8 @@ static int wm8753_init(struct snd_soc_device *socdev) } /* charge output caps */ - wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_STANDBY; + wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D3hot; schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(caps_charge)); @@ -1670,13 +1673,13 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) ret = i2c_attach_client(i2c); if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); + err("failed to attach codec at addr %x\n", addr); goto err; } ret = wm8753_init(socdev); if (ret < 0) { - pr_err("failed to initialise WM8753\n"); + err("failed to initialise WM8753\n"); goto err; } @@ -1728,7 +1731,7 @@ static int wm8753_probe(struct platform_device *pdev) struct wm8753_priv *wm8753; int ret = 0; - pr_info("WM8753 Audio Codec %s", WM8753_VERSION); + info("WM8753 Audio Codec %s", WM8753_VERSION); setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); @@ -1789,7 +1792,7 @@ static int wm8753_remove(struct platform_device *pdev) struct snd_soc_codec *codec = socdev->codec; if (codec->control_data) - wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); + wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); run_delayed_work(&codec->delayed_work); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); diff --git a/trunk/sound/soc/codecs/wm8753.h b/trunk/sound/soc/codecs/wm8753.h index 44f5f1ff0cc7..95e2a1f53169 100644 --- a/trunk/sound/soc/codecs/wm8753.h +++ b/trunk/sound/soc/codecs/wm8753.h @@ -120,7 +120,7 @@ struct wm8753_setup_data { #define WM8753_DAI_HIFI 0 #define WM8753_DAI_VOICE 1 -extern struct snd_soc_dai wm8753_dai[2]; +extern struct snd_soc_codec_dai wm8753_dai[2]; extern struct snd_soc_codec_device soc_codec_dev_wm8753; #endif diff --git a/trunk/sound/soc/codecs/wm8990.c b/trunk/sound/soc/codecs/wm8990.c deleted file mode 100644 index 3ecce5168e94..000000000000 --- a/trunk/sound/soc/codecs/wm8990.c +++ /dev/null @@ -1,1626 +0,0 @@ -/* - * wm8990.c -- WM8990 ALSA Soc Audio driver - * - * Copyright 2008 Wolfson Microelectronics PLC. - * Author: Liam Girdwood - * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wm8990.h" - -#define AUDIO_NAME "wm8990" -#define WM8990_VERSION "0.2" - -/* codec private data */ -struct wm8990_priv { - unsigned int sysclk; - unsigned int pcmclk; -}; - -/* - * wm8990 register cache. Note that register 0 is not included in the - * cache. - */ -static const u16 wm8990_reg[] = { - 0x8990, /* R0 - Reset */ - 0x0000, /* R1 - Power Management (1) */ - 0x6000, /* R2 - Power Management (2) */ - 0x0000, /* R3 - Power Management (3) */ - 0x4050, /* R4 - Audio Interface (1) */ - 0x4000, /* R5 - Audio Interface (2) */ - 0x01C8, /* R6 - Clocking (1) */ - 0x0000, /* R7 - Clocking (2) */ - 0x0040, /* R8 - Audio Interface (3) */ - 0x0040, /* R9 - Audio Interface (4) */ - 0x0004, /* R10 - DAC CTRL */ - 0x00C0, /* R11 - Left DAC Digital Volume */ - 0x00C0, /* R12 - Right DAC Digital Volume */ - 0x0000, /* R13 - Digital Side Tone */ - 0x0100, /* R14 - ADC CTRL */ - 0x00C0, /* R15 - Left ADC Digital Volume */ - 0x00C0, /* R16 - Right ADC Digital Volume */ - 0x0000, /* R17 */ - 0x0000, /* R18 - GPIO CTRL 1 */ - 0x1000, /* R19 - GPIO1 & GPIO2 */ - 0x1010, /* R20 - GPIO3 & GPIO4 */ - 0x1010, /* R21 - GPIO5 & GPIO6 */ - 0x8000, /* R22 - GPIOCTRL 2 */ - 0x0800, /* R23 - GPIO_POL */ - 0x008B, /* R24 - Left Line Input 1&2 Volume */ - 0x008B, /* R25 - Left Line Input 3&4 Volume */ - 0x008B, /* R26 - Right Line Input 1&2 Volume */ - 0x008B, /* R27 - Right Line Input 3&4 Volume */ - 0x0000, /* R28 - Left Output Volume */ - 0x0000, /* R29 - Right Output Volume */ - 0x0066, /* R30 - Line Outputs Volume */ - 0x0022, /* R31 - Out3/4 Volume */ - 0x0079, /* R32 - Left OPGA Volume */ - 0x0079, /* R33 - Right OPGA Volume */ - 0x0003, /* R34 - Speaker Volume */ - 0x0003, /* R35 - ClassD1 */ - 0x0000, /* R36 */ - 0x0100, /* R37 - ClassD3 */ - 0x0000, /* R38 */ - 0x0000, /* R39 - Input Mixer1 */ - 0x0000, /* R40 - Input Mixer2 */ - 0x0000, /* R41 - Input Mixer3 */ - 0x0000, /* R42 - Input Mixer4 */ - 0x0000, /* R43 - Input Mixer5 */ - 0x0000, /* R44 - Input Mixer6 */ - 0x0000, /* R45 - Output Mixer1 */ - 0x0000, /* R46 - Output Mixer2 */ - 0x0000, /* R47 - Output Mixer3 */ - 0x0000, /* R48 - Output Mixer4 */ - 0x0000, /* R49 - Output Mixer5 */ - 0x0000, /* R50 - Output Mixer6 */ - 0x0180, /* R51 - Out3/4 Mixer */ - 0x0000, /* R52 - Line Mixer1 */ - 0x0000, /* R53 - Line Mixer2 */ - 0x0000, /* R54 - Speaker Mixer */ - 0x0000, /* R55 - Additional Control */ - 0x0000, /* R56 - AntiPOP1 */ - 0x0000, /* R57 - AntiPOP2 */ - 0x0000, /* R58 - MICBIAS */ - 0x0000, /* R59 */ - 0x0008, /* R60 - PLL1 */ - 0x0031, /* R61 - PLL2 */ - 0x0026, /* R62 - PLL3 */ -}; - -/* - * read wm8990 register cache - */ -static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); - return cache[reg]; -} - -/* - * write wm8990 register cache - */ -static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); - - /* Reset register is uncached */ - if (reg == 0) - return; - - cache[reg] = value; -} - -/* - * write to the wm8990 register space - */ -static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - - data[0] = reg & 0xFF; - data[1] = (value >> 8) & 0xFF; - data[2] = value & 0xFF; - - wm8990_write_reg_cache(codec, reg, value); - - if (codec->hw_write(codec->control_data, data, 3) == 2) - return 0; - else - return -EIO; -} - -#define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) - -static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); - -static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); - -static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); - -static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); - -static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); - -static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); - -static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); - -static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); - -static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value & 0xff; - int ret; - u16 val; - - ret = snd_soc_put_volsw(kcontrol, ucontrol); - if (ret < 0) - return ret; - - /* now hit the volume update bits (always bit 8) */ - val = wm8990_read_reg_cache(codec, reg); - return wm8990_write(codec, reg, val | 0x0100); -} - -#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ - tlv_array) {\ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, \ - .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ - .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } - - -static const char *wm8990_digital_sidetone[] = - {"None", "Left ADC", "Right ADC", "Reserved"}; - -static const struct soc_enum wm8990_left_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, - WM8990_ADC_TO_DACL_SHIFT, - WM8990_ADC_TO_DACL_MASK, - wm8990_digital_sidetone); - -static const struct soc_enum wm8990_right_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, - WM8990_ADC_TO_DACR_SHIFT, - WM8990_ADC_TO_DACR_MASK, - wm8990_digital_sidetone); - -static const char *wm8990_adcmode[] = - {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; - -static const struct soc_enum wm8990_right_adcmode_enum = -SOC_ENUM_SINGLE(WM8990_ADC_CTRL, - WM8990_ADC_HPF_CUT_SHIFT, - WM8990_ADC_HPF_CUT_MASK, - wm8990_adcmode); - -static const struct snd_kcontrol_new wm8990_snd_controls[] = { -/* INMIXL */ -SOC_SINGLE("LIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L12MNBST_BIT, 1, 0), -SOC_SINGLE("LIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L34MNBST_BIT, 1, 0), -/* INMIXR */ -SOC_SINGLE("RIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R12MNBST_BIT, 1, 0), -SOC_SINGLE("RIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R34MNBST_BIT, 1, 0), - -/* LOMIX */ -SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3, - WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, - WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, - WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5, - WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5, - WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5, - WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), - -/* ROMIX */ -SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4, - WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, - WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, - WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6, - WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6, - WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv), -SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6, - WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv), - -/* LOUT */ -SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME, - WM8990_LOUTVOL_SHIFT, WM8990_LOUTVOL_MASK, 0, out_pga_tlv), -SOC_SINGLE("LOUT ZC", WM8990_LEFT_OUTPUT_VOLUME, WM8990_LOZC_BIT, 1, 0), - -/* ROUT */ -SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME, - WM8990_ROUTVOL_SHIFT, WM8990_ROUTVOL_MASK, 0, out_pga_tlv), -SOC_SINGLE("ROUT ZC", WM8990_RIGHT_OUTPUT_VOLUME, WM8990_ROZC_BIT, 1, 0), - -/* LOPGA */ -SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME, - WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv), -SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME, - WM8990_LOPGAZC_BIT, 1, 0), - -/* ROPGA */ -SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME, - WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv), -SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME, - WM8990_ROPGAZC_BIT, 1, 0), - -SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, - WM8990_LONMUTE_BIT, 1, 0), -SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, - WM8990_LOPMUTE_BIT, 1, 0), -SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, - WM8990_LOATTN_BIT, 1, 0), -SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, - WM8990_RONMUTE_BIT, 1, 0), -SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, - WM8990_ROPMUTE_BIT, 1, 0), -SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, - WM8990_ROATTN_BIT, 1, 0), - -SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME, - WM8990_OUT3MUTE_BIT, 1, 0), -SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME, - WM8990_OUT3ATTN_BIT, 1, 0), - -SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME, - WM8990_OUT4MUTE_BIT, 1, 0), -SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME, - WM8990_OUT4ATTN_BIT, 1, 0), - -SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1, - WM8990_CDMODE_BIT, 1, 0), - -SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME, - WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0), -SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3, - WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0), -SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3, - WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", - WM8990_LEFT_DAC_DIGITAL_VOLUME, - WM8990_DACL_VOL_SHIFT, - WM8990_DACL_VOL_MASK, - 0, - out_dac_tlv), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", - WM8990_RIGHT_DAC_DIGITAL_VOLUME, - WM8990_DACR_VOL_SHIFT, - WM8990_DACR_VOL_MASK, - 0, - out_dac_tlv), - -SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum), -SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum), - -SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, - WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0, - out_sidetone_tlv), -SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, - WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0, - out_sidetone_tlv), - -SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL, - WM8990_ADC_HPF_ENA_BIT, 1, 0), - -SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", - WM8990_LEFT_ADC_DIGITAL_VOLUME, - WM8990_ADCL_VOL_SHIFT, - WM8990_ADCL_VOL_MASK, - 0, - in_adc_tlv), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", - WM8990_RIGHT_ADC_DIGITAL_VOLUME, - WM8990_ADCR_VOL_SHIFT, - WM8990_ADCR_VOL_MASK, - 0, - in_adc_tlv), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume", - WM8990_LEFT_LINE_INPUT_1_2_VOLUME, - WM8990_LIN12VOL_SHIFT, - WM8990_LIN12VOL_MASK, - 0, - in_pga_tlv), - -SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, - WM8990_LI12ZC_BIT, 1, 0), - -SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, - WM8990_LI12MUTE_BIT, 1, 0), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume", - WM8990_LEFT_LINE_INPUT_3_4_VOLUME, - WM8990_LIN34VOL_SHIFT, - WM8990_LIN34VOL_MASK, - 0, - in_pga_tlv), - -SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, - WM8990_LI34ZC_BIT, 1, 0), - -SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, - WM8990_LI34MUTE_BIT, 1, 0), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume", - WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, - WM8990_RIN12VOL_SHIFT, - WM8990_RIN12VOL_MASK, - 0, - in_pga_tlv), - -SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, - WM8990_RI12ZC_BIT, 1, 0), - -SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, - WM8990_RI12MUTE_BIT, 1, 0), - -SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume", - WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, - WM8990_RIN34VOL_SHIFT, - WM8990_RIN34VOL_MASK, - 0, - in_pga_tlv), - -SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, - WM8990_RI34ZC_BIT, 1, 0), - -SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, - WM8990_RI34MUTE_BIT, 1, 0), - -}; - -/* add non dapm controls */ -static int wm8990_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8990_snd_controls[i], codec, - NULL)); - if (err < 0) - return err; - } - return 0; -} - -/* - * _DAPM_ Controls - */ - -static int inmixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - u16 reg, fakepower; - - reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); - fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); - - if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | - (1 << WM8990_AINLMUX_PWR_BIT))) { - reg |= WM8990_AINL_ENA; - } else { - reg &= ~WM8990_AINL_ENA; - } - - if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | - (1 << WM8990_AINRMUX_PWR_BIT))) { - reg |= WM8990_AINR_ENA; - } else { - reg &= ~WM8990_AINL_ENA; - } - wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); - - return 0; -} - -static int outmixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - u32 reg_shift = kcontrol->private_value & 0xfff; - int ret = 0; - u16 reg; - - switch (reg_shift) { - case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : - reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); - if (reg & WM8990_LDLO) { - printk(KERN_WARNING - "Cannot set as Output Mixer 1 LDLO Set\n"); - ret = -1; - } - break; - case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): - reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); - if (reg & WM8990_RDRO) { - printk(KERN_WARNING - "Cannot set as Output Mixer 2 RDRO Set\n"); - ret = -1; - } - break; - case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): - reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); - if (reg & WM8990_LDSPK) { - printk(KERN_WARNING - "Cannot set as Speaker Mixer LDSPK Set\n"); - ret = -1; - } - break; - case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): - reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); - if (reg & WM8990_RDSPK) { - printk(KERN_WARNING - "Cannot set as Speaker Mixer RDSPK Set\n"); - ret = -1; - } - break; - } - - return ret; -} - -/* INMIX dB values */ -static const unsigned int in_mix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), -}; - -/* Left In PGA Connections */ -static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { -SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0), -SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0), -}; - -static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = { -SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0), -SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0), -}; - -/* Right In PGA Connections */ -static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = { -SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0), -SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0), -}; - -static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = { -SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0), -SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0), -}; - -/* INMIXL */ -static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = { -SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3, - WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv), -SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT, - 7, 0, in_mix_tlv), -SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, - 1, 0), -SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, - 1, 0), -}; - -/* INMIXR */ -static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = { -SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4, - WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv), -SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT, - 7, 0, in_mix_tlv), -SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, - 1, 0), -SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, - 1, 0), -}; - -/* AINLMUX */ -static const char *wm8990_ainlmux[] = - {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; - -static const struct soc_enum wm8990_ainlmux_enum = -SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, - ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); - -static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = -SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); - -/* DIFFINL */ - -/* AINRMUX */ -static const char *wm8990_ainrmux[] = - {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; - -static const struct soc_enum wm8990_ainrmux_enum = -SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, - ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); - -static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = -SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); - -/* RXVOICE */ -static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { -SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, - WM8990_LR4BVOL_MASK, 0, in_mix_tlv), -SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, - WM8990_RL4BVOL_MASK, 0, in_mix_tlv), -}; - -/* LOMIX */ -static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { -SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, - WM8990_LRBLO_BIT, 1, 0), -SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1, - WM8990_LLBLO_BIT, 1, 0), -SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, - WM8990_LRI3LO_BIT, 1, 0), -SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, - WM8990_LLI3LO_BIT, 1, 0), -SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, - WM8990_LR12LO_BIT, 1, 0), -SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, - WM8990_LL12LO_BIT, 1, 0), -SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1, - WM8990_LDLO_BIT, 1, 0), -}; - -/* ROMIX */ -static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = { -SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2, - WM8990_RLBRO_BIT, 1, 0), -SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2, - WM8990_RRBRO_BIT, 1, 0), -SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, - WM8990_RLI3RO_BIT, 1, 0), -SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, - WM8990_RRI3RO_BIT, 1, 0), -SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, - WM8990_RL12RO_BIT, 1, 0), -SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, - WM8990_RR12RO_BIT, 1, 0), -SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2, - WM8990_RDRO_BIT, 1, 0), -}; - -/* LONMIX */ -static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = { -SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, - WM8990_LLOPGALON_BIT, 1, 0), -SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1, - WM8990_LROPGALON_BIT, 1, 0), -SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1, - WM8990_LOPLON_BIT, 1, 0), -}; - -/* LOPMIX */ -static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = { -SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1, - WM8990_LR12LOP_BIT, 1, 0), -SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1, - WM8990_LL12LOP_BIT, 1, 0), -SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, - WM8990_LLOPGALOP_BIT, 1, 0), -}; - -/* RONMIX */ -static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = { -SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, - WM8990_RROPGARON_BIT, 1, 0), -SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2, - WM8990_RLOPGARON_BIT, 1, 0), -SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2, - WM8990_ROPRON_BIT, 1, 0), -}; - -/* ROPMIX */ -static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = { -SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2, - WM8990_RL12ROP_BIT, 1, 0), -SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2, - WM8990_RR12ROP_BIT, 1, 0), -SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, - WM8990_RROPGAROP_BIT, 1, 0), -}; - -/* OUT3MIX */ -static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = { -SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, - WM8990_LI4O3_BIT, 1, 0), -SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER, - WM8990_LPGAO3_BIT, 1, 0), -}; - -/* OUT4MIX */ -static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = { -SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER, - WM8990_RPGAO4_BIT, 1, 0), -SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, - WM8990_RI4O4_BIT, 1, 0), -}; - -/* SPKMIX */ -static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = { -SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER, - WM8990_LI2SPK_BIT, 1, 0), -SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER, - WM8990_LB2SPK_BIT, 1, 0), -SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER, - WM8990_LOPGASPK_BIT, 1, 0), -SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER, - WM8990_LDSPK_BIT, 1, 0), -SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER, - WM8990_RDSPK_BIT, 1, 0), -SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER, - WM8990_ROPGASPK_BIT, 1, 0), -SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER, - WM8990_RL12ROP_BIT, 1, 0), -SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER, - WM8990_RI2SPK_BIT, 1, 0), -}; - -static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = { -/* Input Side */ -/* Input Lines */ -SND_SOC_DAPM_INPUT("LIN1"), -SND_SOC_DAPM_INPUT("LIN2"), -SND_SOC_DAPM_INPUT("LIN3"), -SND_SOC_DAPM_INPUT("LIN4/RXN"), -SND_SOC_DAPM_INPUT("RIN3"), -SND_SOC_DAPM_INPUT("RIN4/RXP"), -SND_SOC_DAPM_INPUT("RIN1"), -SND_SOC_DAPM_INPUT("RIN2"), -SND_SOC_DAPM_INPUT("Internal ADC Source"), - -/* DACs */ -SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, - WM8990_ADCL_ENA_BIT, 0), -SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2, - WM8990_ADCR_ENA_BIT, 0), - -/* Input PGAs */ -SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT, - 0, &wm8990_dapm_lin12_pga_controls[0], - ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)), -SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT, - 0, &wm8990_dapm_lin34_pga_controls[0], - ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)), -SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT, - 0, &wm8990_dapm_rin12_pga_controls[0], - ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)), -SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT, - 0, &wm8990_dapm_rin34_pga_controls[0], - ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), - -/* INMIXL */ -SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, - &wm8990_dapm_inmixl_controls[0], - ARRAY_SIZE(wm8990_dapm_inmixl_controls), - inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - -/* AINLMUX */ -SND_SOC_DAPM_MUX_E("AILNMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, - &wm8990_dapm_ainlmux_controls, inmixer_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - -/* INMIXR */ -SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, - &wm8990_dapm_inmixr_controls[0], - ARRAY_SIZE(wm8990_dapm_inmixr_controls), - inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - -/* AINRMUX */ -SND_SOC_DAPM_MUX_E("AIRNMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, - &wm8990_dapm_ainrmux_controls, inmixer_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - -/* Output Side */ -/* DACs */ -SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3, - WM8990_DACL_ENA_BIT, 0), -SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3, - WM8990_DACR_ENA_BIT, 0), - -/* LOMIX */ -SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT, - 0, &wm8990_dapm_lomix_controls[0], - ARRAY_SIZE(wm8990_dapm_lomix_controls), - outmixer_event, SND_SOC_DAPM_PRE_REG), - -/* LONMIX */ -SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0, - &wm8990_dapm_lonmix_controls[0], - ARRAY_SIZE(wm8990_dapm_lonmix_controls)), - -/* LOPMIX */ -SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0, - &wm8990_dapm_lopmix_controls[0], - ARRAY_SIZE(wm8990_dapm_lopmix_controls)), - -/* OUT3MIX */ -SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0, - &wm8990_dapm_out3mix_controls[0], - ARRAY_SIZE(wm8990_dapm_out3mix_controls)), - -/* SPKMIX */ -SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0, - &wm8990_dapm_spkmix_controls[0], - ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event, - SND_SOC_DAPM_PRE_REG), - -/* OUT4MIX */ -SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0, - &wm8990_dapm_out4mix_controls[0], - ARRAY_SIZE(wm8990_dapm_out4mix_controls)), - -/* ROPMIX */ -SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0, - &wm8990_dapm_ropmix_controls[0], - ARRAY_SIZE(wm8990_dapm_ropmix_controls)), - -/* RONMIX */ -SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0, - &wm8990_dapm_ronmix_controls[0], - ARRAY_SIZE(wm8990_dapm_ronmix_controls)), - -/* ROMIX */ -SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT, - 0, &wm8990_dapm_romix_controls[0], - ARRAY_SIZE(wm8990_dapm_romix_controls), - outmixer_event, SND_SOC_DAPM_PRE_REG), - -/* LOUT PGA */ -SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0, - NULL, 0), - -/* ROUT PGA */ -SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0, - NULL, 0), - -/* LOPGA */ -SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0, - NULL, 0), - -/* ROPGA */ -SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0, - NULL, 0), - -/* MICBIAS */ -SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1, - WM8990_MICBIAS_ENA_BIT, 0), - -SND_SOC_DAPM_OUTPUT("LON"), -SND_SOC_DAPM_OUTPUT("LOP"), -SND_SOC_DAPM_OUTPUT("OUT3"), -SND_SOC_DAPM_OUTPUT("LOUT"), -SND_SOC_DAPM_OUTPUT("SPKN"), -SND_SOC_DAPM_OUTPUT("SPKP"), -SND_SOC_DAPM_OUTPUT("ROUT"), -SND_SOC_DAPM_OUTPUT("OUT4"), -SND_SOC_DAPM_OUTPUT("ROP"), -SND_SOC_DAPM_OUTPUT("RON"), - -SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Make DACs turn on when playing even if not mixed into any outputs */ - {"Internal DAC Sink", NULL, "Left DAC"}, - {"Internal DAC Sink", NULL, "Right DAC"}, - - /* Make ADCs turn on when recording even if not mixed from any inputs */ - {"Left ADC", NULL, "Internal ADC Source"}, - {"Right ADC", NULL, "Internal ADC Source"}, - - /* Input Side */ - /* LIN12 PGA */ - {"LIN12 PGA", "LIN1 Switch", "LIN1"}, - {"LIN12 PGA", "LIN2 Switch", "LIN2"}, - /* LIN34 PGA */ - {"LIN34 PGA", "LIN3 Switch", "LIN3"}, - {"LIN34 PGA", "LIN4 Switch", "LIN4"}, - /* INMIXL */ - {"INMIXL", "Record Left Volume", "LOMIX"}, - {"INMIXL", "LIN2 Volume", "LIN2"}, - {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, - {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, - /* AILNMUX */ - {"AILNMUX", "INMIXL Mix", "INMIXL"}, - {"AILNMUX", "DIFFINL Mix", "LIN12PGA"}, - {"AILNMUX", "DIFFINL Mix", "LIN34PGA"}, - {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, - {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, - /* ADC */ - {"Left ADC", NULL, "AILNMUX"}, - - /* RIN12 PGA */ - {"RIN12 PGA", "RIN1 Switch", "RIN1"}, - {"RIN12 PGA", "RIN2 Switch", "RIN2"}, - /* RIN34 PGA */ - {"RIN34 PGA", "RIN3 Switch", "RIN3"}, - {"RIN34 PGA", "RIN4 Switch", "RIN4"}, - /* INMIXL */ - {"INMIXR", "Record Right Volume", "ROMIX"}, - {"INMIXR", "RIN2 Volume", "RIN2"}, - {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, - {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, - /* AIRNMUX */ - {"AIRNMUX", "INMIXR Mix", "INMIXR"}, - {"AIRNMUX", "DIFFINR Mix", "RIN12PGA"}, - {"AIRNMUX", "DIFFINR Mix", "RIN34PGA"}, - {"AIRNMUX", "RXVOICE Mix", "RIN4/RXN"}, - {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, - /* ADC */ - {"Right ADC", NULL, "AIRNMUX"}, - - /* LOMIX */ - {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, - {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, - {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, - {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, - {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"}, - {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"}, - {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, - - /* ROMIX */ - {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, - {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, - {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, - {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, - {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"}, - {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"}, - {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, - - /* SPKMIX */ - {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, - {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, - {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"}, - {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"}, - {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, - {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, - {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, - {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"}, - - /* LONMIX */ - {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, - {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, - {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, - - /* LOPMIX */ - {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, - {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, - {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, - - /* OUT3MIX */ - {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXP"}, - {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, - - /* OUT4MIX */ - {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, - {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, - - /* RONMIX */ - {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, - {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, - {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, - - /* ROPMIX */ - {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, - {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, - {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, - - /* Out Mixer PGAs */ - {"LOPGA", NULL, "LOMIX"}, - {"ROPGA", NULL, "ROMIX"}, - - {"LOUT PGA", NULL, "LOMIX"}, - {"ROUT PGA", NULL, "ROMIX"}, - - /* Output Pins */ - {"LON", NULL, "LONMIX"}, - {"LOP", NULL, "LOPMIX"}, - {"OUT", NULL, "OUT3MIX"}, - {"LOUT", NULL, "LOUT PGA"}, - {"SPKN", NULL, "SPKMIX"}, - {"ROUT", NULL, "ROUT PGA"}, - {"OUT4", NULL, "OUT4MIX"}, - {"ROP", NULL, "ROPMIX"}, - {"RON", NULL, "RONMIX"}, -}; - -static int wm8990_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets, - ARRAY_SIZE(wm8990_dapm_widgets)); - - /* set up the WM8990 audio map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_new_widgets(codec); - return 0; -} - -/* PLL divisors */ -struct _pll_div { - u32 div2; - u32 n; - u32 k; -}; - -/* The size in bits of the pll divide multiplied by 10 - * to allow rounding later */ -#define FIXED_PLL_SIZE ((1 << 16) * 10) - -static void pll_factors(struct _pll_div *pll_div, unsigned int target, - unsigned int source) -{ - u64 Kpart; - unsigned int K, Ndiv, Nmod; - - - Ndiv = target / source; - if (Ndiv < 6) { - source >>= 1; - pll_div->div2 = 1; - Ndiv = target / source; - } else - pll_div->div2 = 0; - - if ((Ndiv < 6) || (Ndiv > 12)) - printk(KERN_WARNING - "WM8990 N value outwith recommended range! N = %d\n", Ndiv); - - pll_div->n = Ndiv; - Nmod = target % source; - Kpart = FIXED_PLL_SIZE * (long long)Nmod; - - do_div(Kpart, source); - - K = Kpart & 0xFFFFFFFF; - - /* Check if we need to round */ - if ((K % 10) >= 5) - K += 5; - - /* Move down to proper range now rounding is done */ - K /= 10; - - pll_div->k = K; -} - -static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) -{ - u16 reg; - struct snd_soc_codec *codec = codec_dai->codec; - struct _pll_div pll_div; - - if (freq_in && freq_out) { - pll_factors(&pll_div, freq_out * 4, freq_in); - - /* Turn on PLL */ - reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); - reg |= WM8990_PLL_ENA; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); - - /* sysclk comes from PLL */ - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); - wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); - - /* set up N , fractional mode and pre-divisor if neccessary */ - wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | - (pll_div.div2?WM8990_PRESCALE:0)); - wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); - wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); - } else { - /* Turn on PLL */ - reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); - reg &= ~WM8990_PLL_ENA; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); - } - return 0; -} - -/* - * Clock after PLL and dividers - */ -static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct wm8990_priv *wm8990 = codec->private_data; - - wm8990->sysclk = freq; - return 0; -} - -/* - * Set's ADC and Voice DAC format. - */ -static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 audio1, audio3; - - audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); - audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - audio3 &= ~WM8990_AIF_MSTR1; - break; - case SND_SOC_DAIFMT_CBM_CFM: - audio3 |= WM8990_AIF_MSTR1; - break; - default: - return -EINVAL; - } - - audio1 &= ~WM8990_AIF_FMT_MASK; - - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - audio1 |= WM8990_AIF_TMF_I2S; - audio1 &= ~WM8990_AIF_LRCLK_INV; - break; - case SND_SOC_DAIFMT_RIGHT_J: - audio1 |= WM8990_AIF_TMF_RIGHTJ; - audio1 &= ~WM8990_AIF_LRCLK_INV; - break; - case SND_SOC_DAIFMT_LEFT_J: - audio1 |= WM8990_AIF_TMF_LEFTJ; - audio1 &= ~WM8990_AIF_LRCLK_INV; - break; - case SND_SOC_DAIFMT_DSP_A: - audio1 |= WM8990_AIF_TMF_DSP; - audio1 &= ~WM8990_AIF_LRCLK_INV; - break; - case SND_SOC_DAIFMT_DSP_B: - audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV; - break; - default: - return -EINVAL; - } - - wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); - wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); - return 0; -} - -static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, - int div_id, int div) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - - switch (div_id) { - case WM8990_MCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & - ~WM8990_MCLK_DIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_2, reg | div); - break; - case WM8990_DACCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & - ~WM8990_DAC_CLKDIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_2, reg | div); - break; - case WM8990_ADCCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & - ~WM8990_ADC_CLKDIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_2, reg | div); - break; - case WM8990_BCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & - ~WM8990_BCLK_DIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_1, reg | div); - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * Set PCM DAI bit size and sample rate. - */ -static int wm8990_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); - - audio1 &= ~WM8990_AIF_WL_MASK; - /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - audio1 |= WM8990_AIF_WL_20BITS; - break; - case SNDRV_PCM_FORMAT_S24_LE: - audio1 |= WM8990_AIF_WL_24BITS; - break; - case SNDRV_PCM_FORMAT_S32_LE: - audio1 |= WM8990_AIF_WL_32BITS; - break; - } - - wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); - return 0; -} - -static int wm8990_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 val; - - val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; - - if (mute) - wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); - else - wm8990_write(codec, WM8990_DAC_CTRL, val); - - return 0; -} - -static int wm8990_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u16 val; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - if (codec->bias_level == SND_SOC_BIAS_OFF) { - /* Enable all output discharge bits */ - wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | - WM8990_DIS_RLINE | WM8990_DIS_OUT3 | - WM8990_DIS_OUT4 | WM8990_DIS_LOUT | - WM8990_DIS_ROUT); - - /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | - WM8990_BUFDCOPEN | WM8990_POBCTRL | - WM8990_VMIDTOG); - - /* Delay to allow output caps to discharge */ - msleep(msecs_to_jiffies(300)); - - /* Disable VMIDTOG */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | - WM8990_BUFDCOPEN | WM8990_POBCTRL); - - /* disable all output discharge bits */ - wm8990_write(codec, WM8990_ANTIPOP1, 0); - - /* Enable outputs */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); - - msleep(msecs_to_jiffies(50)); - - /* Enable VMID at 2x50k */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); - - msleep(msecs_to_jiffies(100)); - - /* Enable VREF */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); - - msleep(msecs_to_jiffies(600)); - - /* Enable BUFIOEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | - WM8990_BUFDCOPEN | WM8990_POBCTRL | - WM8990_BUFIOEN); - - /* Disable outputs */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); - - /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); - } else { - /* ON -> standby */ - - } - break; - - case SND_SOC_BIAS_OFF: - /* Enable POBCTRL and SOFT_ST */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | - WM8990_POBCTRL | WM8990_BUFIOEN); - - /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | - WM8990_BUFDCOPEN | WM8990_POBCTRL | - WM8990_BUFIOEN); - - /* mute DAC */ - val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); - wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); - - /* Enable any disabled outputs */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); - - /* Disable VMID */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); - - msleep(msecs_to_jiffies(300)); - - /* Enable all output discharge bits */ - wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | - WM8990_DIS_RLINE | WM8990_DIS_OUT3 | - WM8990_DIS_OUT4 | WM8990_DIS_LOUT | - WM8990_DIS_ROUT); - - /* Disable VREF */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); - - /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, 0x0); - break; - } - - codec->bias_level = level; - return 0; -} - -#define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) - -#define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -/* - * The WM8990 supports 2 different and mutually exclusive DAI - * configurations. - * - * 1. ADC/DAC on Primary Interface - * 2. ADC on Primary Interface/DAC on secondary - */ -struct snd_soc_dai wm8990_dai = { -/* ADC/DAC on primary */ - .name = "WM8990 ADC/DAC Primary", - .id = 1, - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM8990_RATES, - .formats = WM8990_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8990_RATES, - .formats = WM8990_FORMATS,}, - .ops = { - .hw_params = wm8990_hw_params,}, - .dai_ops = { - .digital_mute = wm8990_mute, - .set_fmt = wm8990_set_dai_fmt, - .set_clkdiv = wm8990_set_dai_clkdiv, - .set_pll = wm8990_set_dai_pll, - .set_sysclk = wm8990_set_dai_sysclk, - }, -}; -EXPORT_SYMBOL_GPL(wm8990_dai); - -static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - /* we only need to suspend if we are a valid card */ - if (!codec->card) - return 0; - - wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8990_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - int i; - u8 data[2]; - u16 *cache = codec->reg_cache; - - /* we only need to resume if we are a valid card */ - if (!codec->card) - return 0; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { - if (i + 1 == WM8990_RESET) - continue; - data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); - data[1] = cache[i] & 0x00ff; - codec->hw_write(codec->control_data, data, 2); - } - - wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - -/* - * initialise the WM8990 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8990_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->codec; - u16 reg; - int ret = 0; - - codec->name = "WM8990"; - codec->owner = THIS_MODULE; - codec->read = wm8990_read_reg_cache; - codec->write = wm8990_write; - codec->set_bias_level = wm8990_set_bias_level; - codec->dai = &wm8990_dai; - codec->num_dai = 2; - codec->reg_cache_size = ARRAY_SIZE(wm8990_reg); - codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL); - - if (codec->reg_cache == NULL) - return -ENOMEM; - - wm8990_reset(codec); - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "wm8990: failed to create pcms\n"); - goto pcm_err; - } - - /* charge output caps */ - codec->bias_level = SND_SOC_BIAS_OFF; - wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); - wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); - - reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & - ~WM8990_GPIO1_SEL_MASK; - wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); - - reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); - wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); - - wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); - wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); - - wm8990_add_controls(codec); - wm8990_add_widgets(codec); - ret = snd_soc_register_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8990: failed to register card\n"); - goto card_err; - } - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ -static struct snd_soc_device *wm8990_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* - * WM891 2 wire address is determined by GPIO5 - * state during powerup. - * low = 0x34 - * high = 0x36 - */ -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; - -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver wm8990_i2c_driver; -static struct i2c_client client_template; - -static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) -{ - struct snd_soc_device *socdev = wm8990_socdev; - struct wm8990_setup_data *setup = socdev->codec_data; - struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; - int ret; - - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = i2c_attach_client(i2c); - if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); - goto err; - } - - ret = wm8990_init(socdev); - if (ret < 0) { - pr_err("failed to initialise WM8990\n"); - goto err; - } - return ret; - -err: - kfree(codec); - kfree(i2c); - return ret; -} - -static int wm8990_i2c_detach(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); - kfree(codec->reg_cache); - kfree(client); - return 0; -} - -static int wm8990_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, wm8990_codec_probe); -} - -static struct i2c_driver wm8990_i2c_driver = { - .driver = { - .name = "WM8990 I2C Codec", - .owner = THIS_MODULE, - }, - .attach_adapter = wm8990_i2c_attach, - .detach_client = wm8990_i2c_detach, - .command = NULL, -}; - -static struct i2c_client client_template = { - .name = "WM8990", - .driver = &wm8990_i2c_driver, -}; -#endif - -static int wm8990_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8990_setup_data *setup; - struct snd_soc_codec *codec; - struct wm8990_priv *wm8990; - int ret = 0; - - pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL); - if (wm8990 == NULL) { - kfree(codec); - return -ENOMEM; - } - - codec->private_data = wm8990; - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - wm8990_socdev = socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; - codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8990_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); - } -#else - /* Add other interfaces here */ -#endif - return ret; -} - -/* power down chip */ -static int wm8990_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8990_i2c_driver); -#endif - kfree(codec->private_data); - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_wm8990 = { - .probe = wm8990_probe, - .remove = wm8990_remove, - .suspend = wm8990_suspend, - .resume = wm8990_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); - -MODULE_DESCRIPTION("ASoC WM8990 driver"); -MODULE_AUTHOR("Liam Girdwood"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8990.h b/trunk/sound/soc/codecs/wm8990.h deleted file mode 100644 index 6bea57485283..000000000000 --- a/trunk/sound/soc/codecs/wm8990.h +++ /dev/null @@ -1,832 +0,0 @@ -/* - * wm8990.h -- audio driver for WM8990 - * - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __WM8990REGISTERDEFS_H__ -#define __WM8990REGISTERDEFS_H__ - -/* - * Register values. - */ -#define WM8990_RESET 0x00 -#define WM8990_POWER_MANAGEMENT_1 0x01 -#define WM8990_POWER_MANAGEMENT_2 0x02 -#define WM8990_POWER_MANAGEMENT_3 0x03 -#define WM8990_AUDIO_INTERFACE_1 0x04 -#define WM8990_AUDIO_INTERFACE_2 0x05 -#define WM8990_CLOCKING_1 0x06 -#define WM8990_CLOCKING_2 0x07 -#define WM8990_AUDIO_INTERFACE_3 0x08 -#define WM8990_AUDIO_INTERFACE_4 0x09 -#define WM8990_DAC_CTRL 0x0A -#define WM8990_LEFT_DAC_DIGITAL_VOLUME 0x0B -#define WM8990_RIGHT_DAC_DIGITAL_VOLUME 0x0C -#define WM8990_DIGITAL_SIDE_TONE 0x0D -#define WM8990_ADC_CTRL 0x0E -#define WM8990_LEFT_ADC_DIGITAL_VOLUME 0x0F -#define WM8990_RIGHT_ADC_DIGITAL_VOLUME 0x10 -#define WM8990_GPIO_CTRL_1 0x12 -#define WM8990_GPIO1_GPIO2 0x13 -#define WM8990_GPIO3_GPIO4 0x14 -#define WM8990_GPIO5_GPIO6 0x15 -#define WM8990_GPIOCTRL_2 0x16 -#define WM8990_GPIO_POL 0x17 -#define WM8990_LEFT_LINE_INPUT_1_2_VOLUME 0x18 -#define WM8990_LEFT_LINE_INPUT_3_4_VOLUME 0x19 -#define WM8990_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A -#define WM8990_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B -#define WM8990_LEFT_OUTPUT_VOLUME 0x1C -#define WM8990_RIGHT_OUTPUT_VOLUME 0x1D -#define WM8990_LINE_OUTPUTS_VOLUME 0x1E -#define WM8990_OUT3_4_VOLUME 0x1F -#define WM8990_LEFT_OPGA_VOLUME 0x20 -#define WM8990_RIGHT_OPGA_VOLUME 0x21 -#define WM8990_SPEAKER_VOLUME 0x22 -#define WM8990_CLASSD1 0x23 -#define WM8990_CLASSD3 0x25 -#define WM8990_INPUT_MIXER1 0x27 -#define WM8990_INPUT_MIXER2 0x28 -#define WM8990_INPUT_MIXER3 0x29 -#define WM8990_INPUT_MIXER4 0x2A -#define WM8990_INPUT_MIXER5 0x2B -#define WM8990_INPUT_MIXER6 0x2C -#define WM8990_OUTPUT_MIXER1 0x2D -#define WM8990_OUTPUT_MIXER2 0x2E -#define WM8990_OUTPUT_MIXER3 0x2F -#define WM8990_OUTPUT_MIXER4 0x30 -#define WM8990_OUTPUT_MIXER5 0x31 -#define WM8990_OUTPUT_MIXER6 0x32 -#define WM8990_OUT3_4_MIXER 0x33 -#define WM8990_LINE_MIXER1 0x34 -#define WM8990_LINE_MIXER2 0x35 -#define WM8990_SPEAKER_MIXER 0x36 -#define WM8990_ADDITIONAL_CONTROL 0x37 -#define WM8990_ANTIPOP1 0x38 -#define WM8990_ANTIPOP2 0x39 -#define WM8990_MICBIAS 0x3A -#define WM8990_PLL1 0x3C -#define WM8990_PLL2 0x3D -#define WM8990_PLL3 0x3E -#define WM8990_INTDRIVBITS 0x3F - -#define WM8990_REGISTER_COUNT 60 -#define WM8990_MAX_REGISTER 0x3F - -/* - * Field Definitions. - */ - -/* - * R0 (0x00) - Reset - */ -#define WM8990_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET_CHIP_ID */ - -/* - * R1 (0x01) - Power Management (1) - */ -#define WM8990_SPK_ENA 0x1000 /* SPK_ENA */ -#define WM8990_SPK_ENA_BIT 12 -#define WM8990_OUT3_ENA 0x0800 /* OUT3_ENA */ -#define WM8990_OUT3_ENA_BIT 11 -#define WM8990_OUT4_ENA 0x0400 /* OUT4_ENA */ -#define WM8990_OUT4_ENA_BIT 10 -#define WM8990_LOUT_ENA 0x0200 /* LOUT_ENA */ -#define WM8990_LOUT_ENA_BIT 9 -#define WM8990_ROUT_ENA 0x0100 /* ROUT_ENA */ -#define WM8990_ROUT_ENA_BIT 8 -#define WM8990_MICBIAS_ENA 0x0010 /* MICBIAS_ENA */ -#define WM8990_MICBIAS_ENA_BIT 4 -#define WM8990_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */ -#define WM8990_VREF_ENA 0x0001 /* VREF_ENA */ -#define WM8990_VREF_ENA_BIT 0 - -/* - * R2 (0x02) - Power Management (2) - */ -#define WM8990_PLL_ENA 0x8000 /* PLL_ENA */ -#define WM8990_PLL_ENA_BIT 15 -#define WM8990_TSHUT_ENA 0x4000 /* TSHUT_ENA */ -#define WM8990_TSHUT_ENA_BIT 14 -#define WM8990_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */ -#define WM8990_TSHUT_OPDIS_BIT 13 -#define WM8990_OPCLK_ENA 0x0800 /* OPCLK_ENA */ -#define WM8990_OPCLK_ENA_BIT 11 -#define WM8990_AINL_ENA 0x0200 /* AINL_ENA */ -#define WM8990_AINL_ENA_BIT 9 -#define WM8990_AINR_ENA 0x0100 /* AINR_ENA */ -#define WM8990_AINR_ENA_BIT 8 -#define WM8990_LIN34_ENA 0x0080 /* LIN34_ENA */ -#define WM8990_LIN34_ENA_BIT 7 -#define WM8990_LIN12_ENA 0x0040 /* LIN12_ENA */ -#define WM8990_LIN12_ENA_BIT 6 -#define WM8990_RIN34_ENA 0x0020 /* RIN34_ENA */ -#define WM8990_RIN34_ENA_BIT 5 -#define WM8990_RIN12_ENA 0x0010 /* RIN12_ENA */ -#define WM8990_RIN12_ENA_BIT 4 -#define WM8990_ADCL_ENA 0x0002 /* ADCL_ENA */ -#define WM8990_ADCL_ENA_BIT 1 -#define WM8990_ADCR_ENA 0x0001 /* ADCR_ENA */ -#define WM8990_ADCR_ENA_BIT 0 - -/* - * R3 (0x03) - Power Management (3) - */ -#define WM8990_LON_ENA 0x2000 /* LON_ENA */ -#define WM8990_LON_ENA_BIT 13 -#define WM8990_LOP_ENA 0x1000 /* LOP_ENA */ -#define WM8990_LOP_ENA_BIT 12 -#define WM8990_RON_ENA 0x0800 /* RON_ENA */ -#define WM8990_RON_ENA_BIT 11 -#define WM8990_ROP_ENA 0x0400 /* ROP_ENA */ -#define WM8990_ROP_ENA_BIT 10 -#define WM8990_LOPGA_ENA 0x0080 /* LOPGA_ENA */ -#define WM8990_LOPGA_ENA_BIT 7 -#define WM8990_ROPGA_ENA 0x0040 /* ROPGA_ENA */ -#define WM8990_ROPGA_ENA_BIT 6 -#define WM8990_LOMIX_ENA 0x0020 /* LOMIX_ENA */ -#define WM8990_LOMIX_ENA_BIT 5 -#define WM8990_ROMIX_ENA 0x0010 /* ROMIX_ENA */ -#define WM8990_ROMIX_ENA_BIT 4 -#define WM8990_DACL_ENA 0x0002 /* DACL_ENA */ -#define WM8990_DACL_ENA_BIT 1 -#define WM8990_DACR_ENA 0x0001 /* DACR_ENA */ -#define WM8990_DACR_ENA_BIT 0 - -/* - * R4 (0x04) - Audio Interface (1) - */ -#define WM8990_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */ -#define WM8990_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */ -#define WM8990_AIFADC_TDM 0x2000 /* AIFADC_TDM */ -#define WM8990_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */ -#define WM8990_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */ -#define WM8990_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */ -#define WM8990_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */ -#define WM8990_AIF_WL_16BITS (0 << 5) -#define WM8990_AIF_WL_20BITS (1 << 5) -#define WM8990_AIF_WL_24BITS (2 << 5) -#define WM8990_AIF_WL_32BITS (3 << 5) -#define WM8990_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */ -#define WM8990_AIF_TMF_RIGHTJ (0 << 3) -#define WM8990_AIF_TMF_LEFTJ (1 << 3) -#define WM8990_AIF_TMF_I2S (2 << 3) -#define WM8990_AIF_TMF_DSP (3 << 3) - -/* - * R5 (0x05) - Audio Interface (2) - */ -#define WM8990_DACL_SRC 0x8000 /* DACL_SRC */ -#define WM8990_DACR_SRC 0x4000 /* DACR_SRC */ -#define WM8990_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ -#define WM8990_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ -#define WM8990_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST */ -#define WM8990_DAC_COMP 0x0010 /* DAC_COMP */ -#define WM8990_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */ -#define WM8990_ADC_COMP 0x0004 /* ADC_COMP */ -#define WM8990_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */ -#define WM8990_LOOPBACK 0x0001 /* LOOPBACK */ - -/* - * R6 (0x06) - Clocking (1) - */ -#define WM8990_TOCLK_RATE 0x8000 /* TOCLK_RATE */ -#define WM8990_TOCLK_ENA 0x4000 /* TOCLK_ENA */ -#define WM8990_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */ -#define WM8990_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */ -#define WM8990_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */ -#define WM8990_BCLK_DIV_1 (0x0 << 1) -#define WM8990_BCLK_DIV_1_5 (0x1 << 1) -#define WM8990_BCLK_DIV_2 (0x2 << 1) -#define WM8990_BCLK_DIV_3 (0x3 << 1) -#define WM8990_BCLK_DIV_4 (0x4 << 1) -#define WM8990_BCLK_DIV_5_5 (0x5 << 1) -#define WM8990_BCLK_DIV_6 (0x6 << 1) -#define WM8990_BCLK_DIV_8 (0x7 << 1) -#define WM8990_BCLK_DIV_11 (0x8 << 1) -#define WM8990_BCLK_DIV_12 (0x9 << 1) -#define WM8990_BCLK_DIV_16 (0xA << 1) -#define WM8990_BCLK_DIV_22 (0xB << 1) -#define WM8990_BCLK_DIV_24 (0xC << 1) -#define WM8990_BCLK_DIV_32 (0xD << 1) -#define WM8990_BCLK_DIV_44 (0xE << 1) -#define WM8990_BCLK_DIV_48 (0xF << 1) - -/* - * R7 (0x07) - Clocking (2) - */ -#define WM8990_MCLK_SRC 0x8000 /* MCLK_SRC */ -#define WM8990_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ -#define WM8990_CLK_FORCE 0x2000 /* CLK_FORCE */ -#define WM8990_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */ -#define WM8990_MCLK_DIV_1 (0 << 11) -#define WM8990_MCLK_DIV_2 (2 << 11) -#define WM8990_MCLK_INV 0x0400 /* MCLK_INV */ -#define WM8990_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV */ -#define WM8990_ADC_CLKDIV_1 (0 << 5) -#define WM8990_ADC_CLKDIV_1_5 (1 << 5) -#define WM8990_ADC_CLKDIV_2 (2 << 5) -#define WM8990_ADC_CLKDIV_3 (3 << 5) -#define WM8990_ADC_CLKDIV_4 (4 << 5) -#define WM8990_ADC_CLKDIV_5_5 (5 << 5) -#define WM8990_ADC_CLKDIV_6 (6 << 5) -#define WM8990_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */ -#define WM8990_DAC_CLKDIV_1 (0 << 2) -#define WM8990_DAC_CLKDIV_1_5 (1 << 2) -#define WM8990_DAC_CLKDIV_2 (2 << 2) -#define WM8990_DAC_CLKDIV_3 (3 << 2) -#define WM8990_DAC_CLKDIV_4 (4 << 2) -#define WM8990_DAC_CLKDIV_5_5 (5 << 2) -#define WM8990_DAC_CLKDIV_6 (6 << 2) - -/* - * R8 (0x08) - Audio Interface (3) - */ -#define WM8990_AIF_MSTR1 0x8000 /* AIF_MSTR1 */ -#define WM8990_AIF_MSTR2 0x4000 /* AIF_MSTR2 */ -#define WM8990_AIF_SEL 0x2000 /* AIF_SEL */ -#define WM8990_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */ -#define WM8990_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE */ - -/* - * R9 (0x09) - Audio Interface (4) - */ -#define WM8990_ALRCGPIO1 0x8000 /* ALRCGPIO1 */ -#define WM8990_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */ -#define WM8990_AIF_TRIS 0x2000 /* AIF_TRIS */ -#define WM8990_DACLRC_DIR 0x0800 /* DACLRC_DIR */ -#define WM8990_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE */ - -/* - * R10 (0x0A) - DAC CTRL - */ -#define WM8990_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */ -#define WM8990_DAC_MONO 0x0200 /* DAC_MONO */ -#define WM8990_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */ -#define WM8990_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */ -#define WM8990_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */ -#define WM8990_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */ -#define WM8990_DAC_MUTE 0x0004 /* DAC_MUTE */ -#define WM8990_DACL_DATINV 0x0002 /* DACL_DATINV */ -#define WM8990_DACR_DATINV 0x0001 /* DACR_DATINV */ - -/* - * R11 (0x0B) - Left DAC Digital Volume - */ -#define WM8990_DAC_VU 0x0100 /* DAC_VU */ -#define WM8990_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ -#define WM8990_DACL_VOL_SHIFT 0 -/* - * R12 (0x0C) - Right DAC Digital Volume - */ -#define WM8990_DAC_VU 0x0100 /* DAC_VU */ -#define WM8990_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ -#define WM8990_DACR_VOL_SHIFT 0 -/* - * R13 (0x0D) - Digital Side Tone - */ -#define WM8990_ADCL_DAC_SVOL_MASK 0x0F /* ADCL_DAC_SVOL */ -#define WM8990_ADCL_DAC_SVOL_SHIFT 9 -#define WM8990_ADCR_DAC_SVOL_MASK 0x0F /* ADCR_DAC_SVOL */ -#define WM8990_ADCR_DAC_SVOL_SHIFT 5 -#define WM8990_ADC_TO_DACL_MASK 0x03 /* ADC_TO_DACL - [3:2] */ -#define WM8990_ADC_TO_DACL_SHIFT 2 -#define WM8990_ADC_TO_DACR_MASK 0x03 /* ADC_TO_DACR - [1:0] */ -#define WM8990_ADC_TO_DACR_SHIFT 0 - -/* - * R14 (0x0E) - ADC CTRL - */ -#define WM8990_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */ -#define WM8990_ADC_HPF_ENA_BIT 8 -#define WM8990_ADC_HPF_CUT_MASK 0x03 /* ADC_HPF_CUT - [6:5] */ -#define WM8990_ADC_HPF_CUT_SHIFT 5 -#define WM8990_ADCL_DATINV 0x0002 /* ADCL_DATINV */ -#define WM8990_ADCL_DATINV_BIT 1 -#define WM8990_ADCR_DATINV 0x0001 /* ADCR_DATINV */ -#define WM8990_ADCR_DATINV_BIT 0 - -/* - * R15 (0x0F) - Left ADC Digital Volume - */ -#define WM8990_ADC_VU 0x0100 /* ADC_VU */ -#define WM8990_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ -#define WM8990_ADCL_VOL_SHIFT 0 - -/* - * R16 (0x10) - Right ADC Digital Volume - */ -#define WM8990_ADC_VU 0x0100 /* ADC_VU */ -#define WM8990_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ -#define WM8990_ADCR_VOL_SHIFT 0 - -/* - * R18 (0x12) - GPIO CTRL 1 - */ -#define WM8990_IRQ 0x1000 /* IRQ */ -#define WM8990_TEMPOK 0x0800 /* TEMPOK */ -#define WM8990_MICSHRT 0x0400 /* MICSHRT */ -#define WM8990_MICDET 0x0200 /* MICDET */ -#define WM8990_PLL_LCK 0x0100 /* PLL_LCK */ -#define WM8990_GPI8_STATUS 0x0080 /* GPI8_STATUS */ -#define WM8990_GPI7_STATUS 0x0040 /* GPI7_STATUS */ -#define WM8990_GPIO6_STATUS 0x0020 /* GPIO6_STATUS */ -#define WM8990_GPIO5_STATUS 0x0010 /* GPIO5_STATUS */ -#define WM8990_GPIO4_STATUS 0x0008 /* GPIO4_STATUS */ -#define WM8990_GPIO3_STATUS 0x0004 /* GPIO3_STATUS */ -#define WM8990_GPIO2_STATUS 0x0002 /* GPIO2_STATUS */ -#define WM8990_GPIO1_STATUS 0x0001 /* GPIO1_STATUS */ - -/* - * R19 (0x13) - GPIO1 & GPIO2 - */ -#define WM8990_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */ -#define WM8990_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */ -#define WM8990_GPIO2_PU 0x2000 /* GPIO2_PU */ -#define WM8990_GPIO2_PD 0x1000 /* GPIO2_PD */ -#define WM8990_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */ -#define WM8990_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */ -#define WM8990_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */ -#define WM8990_GPIO1_PU 0x0020 /* GPIO1_PU */ -#define WM8990_GPIO1_PD 0x0010 /* GPIO1_PD */ -#define WM8990_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ - -/* - * R20 (0x14) - GPIO3 & GPIO4 - */ -#define WM8990_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */ -#define WM8990_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */ -#define WM8990_GPIO4_PU 0x2000 /* GPIO4_PU */ -#define WM8990_GPIO4_PD 0x1000 /* GPIO4_PD */ -#define WM8990_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */ -#define WM8990_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */ -#define WM8990_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */ -#define WM8990_GPIO3_PU 0x0020 /* GPIO3_PU */ -#define WM8990_GPIO3_PD 0x0010 /* GPIO3_PD */ -#define WM8990_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */ - -/* - * R21 (0x15) - GPIO5 & GPIO6 - */ -#define WM8990_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */ -#define WM8990_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */ -#define WM8990_GPIO6_PU 0x2000 /* GPIO6_PU */ -#define WM8990_GPIO6_PD 0x1000 /* GPIO6_PD */ -#define WM8990_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */ -#define WM8990_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */ -#define WM8990_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */ -#define WM8990_GPIO5_PU 0x0020 /* GPIO5_PU */ -#define WM8990_GPIO5_PD 0x0010 /* GPIO5_PD */ -#define WM8990_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */ - -/* - * R22 (0x16) - GPIOCTRL 2 - */ -#define WM8990_RD_3W_ENA 0x8000 /* RD_3W_ENA */ -#define WM8990_MODE_3W4W 0x4000 /* MODE_3W4W */ -#define WM8990_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */ -#define WM8990_MICSHRT_IRQ_ENA 0x0400 /* MICSHRT_IRQ_ENA */ -#define WM8990_MICDET_IRQ_ENA 0x0200 /* MICDET_IRQ_ENA */ -#define WM8990_PLL_LCK_IRQ_ENA 0x0100 /* PLL_LCK_IRQ_ENA */ -#define WM8990_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */ -#define WM8990_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */ -#define WM8990_GPI8_ENA 0x0010 /* GPI8_ENA */ -#define WM8990_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */ -#define WM8990_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */ -#define WM8990_GPI7_ENA 0x0001 /* GPI7_ENA */ - -/* - * R23 (0x17) - GPIO_POL - */ -#define WM8990_IRQ_INV 0x1000 /* IRQ_INV */ -#define WM8990_TEMPOK_POL 0x0800 /* TEMPOK_POL */ -#define WM8990_MICSHRT_POL 0x0400 /* MICSHRT_POL */ -#define WM8990_MICDET_POL 0x0200 /* MICDET_POL */ -#define WM8990_PLL_LCK_POL 0x0100 /* PLL_LCK_POL */ -#define WM8990_GPI8_POL 0x0080 /* GPI8_POL */ -#define WM8990_GPI7_POL 0x0040 /* GPI7_POL */ -#define WM8990_GPIO6_POL 0x0020 /* GPIO6_POL */ -#define WM8990_GPIO5_POL 0x0010 /* GPIO5_POL */ -#define WM8990_GPIO4_POL 0x0008 /* GPIO4_POL */ -#define WM8990_GPIO3_POL 0x0004 /* GPIO3_POL */ -#define WM8990_GPIO2_POL 0x0002 /* GPIO2_POL */ -#define WM8990_GPIO1_POL 0x0001 /* GPIO1_POL */ - -/* - * R24 (0x18) - Left Line Input 1&2 Volume - */ -#define WM8990_IPVU 0x0100 /* IPVU */ -#define WM8990_LI12MUTE 0x0080 /* LI12MUTE */ -#define WM8990_LI12MUTE_BIT 7 -#define WM8990_LI12ZC 0x0040 /* LI12ZC */ -#define WM8990_LI12ZC_BIT 6 -#define WM8990_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */ -#define WM8990_LIN12VOL_SHIFT 0 -/* - * R25 (0x19) - Left Line Input 3&4 Volume - */ -#define WM8990_IPVU 0x0100 /* IPVU */ -#define WM8990_LI34MUTE 0x0080 /* LI34MUTE */ -#define WM8990_LI34MUTE_BIT 7 -#define WM8990_LI34ZC 0x0040 /* LI34ZC */ -#define WM8990_LI34ZC_BIT 6 -#define WM8990_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */ -#define WM8990_LIN34VOL_SHIFT 0 - -/* - * R26 (0x1A) - Right Line Input 1&2 Volume - */ -#define WM8990_IPVU 0x0100 /* IPVU */ -#define WM8990_RI12MUTE 0x0080 /* RI12MUTE */ -#define WM8990_RI12MUTE_BIT 7 -#define WM8990_RI12ZC 0x0040 /* RI12ZC */ -#define WM8990_RI12ZC_BIT 6 -#define WM8990_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */ -#define WM8990_RIN12VOL_SHIFT 0 - -/* - * R27 (0x1B) - Right Line Input 3&4 Volume - */ -#define WM8990_IPVU 0x0100 /* IPVU */ -#define WM8990_RI34MUTE 0x0080 /* RI34MUTE */ -#define WM8990_RI34MUTE_BIT 7 -#define WM8990_RI34ZC 0x0040 /* RI34ZC */ -#define WM8990_RI34ZC_BIT 6 -#define WM8990_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */ -#define WM8990_RIN34VOL_SHIFT 0 - -/* - * R28 (0x1C) - Left Output Volume - */ -#define WM8990_OPVU 0x0100 /* OPVU */ -#define WM8990_LOZC 0x0080 /* LOZC */ -#define WM8990_LOZC_BIT 7 -#define WM8990_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */ -#define WM8990_LOUTVOL_SHIFT 0 -/* - * R29 (0x1D) - Right Output Volume - */ -#define WM8990_OPVU 0x0100 /* OPVU */ -#define WM8990_ROZC 0x0080 /* ROZC */ -#define WM8990_ROZC_BIT 7 -#define WM8990_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */ -#define WM8990_ROUTVOL_SHIFT 0 -/* - * R30 (0x1E) - Line Outputs Volume - */ -#define WM8990_LONMUTE 0x0040 /* LONMUTE */ -#define WM8990_LONMUTE_BIT 6 -#define WM8990_LOPMUTE 0x0020 /* LOPMUTE */ -#define WM8990_LOPMUTE_BIT 5 -#define WM8990_LOATTN 0x0010 /* LOATTN */ -#define WM8990_LOATTN_BIT 4 -#define WM8990_RONMUTE 0x0004 /* RONMUTE */ -#define WM8990_RONMUTE_BIT 2 -#define WM8990_ROPMUTE 0x0002 /* ROPMUTE */ -#define WM8990_ROPMUTE_BIT 1 -#define WM8990_ROATTN 0x0001 /* ROATTN */ -#define WM8990_ROATTN_BIT 0 - -/* - * R31 (0x1F) - Out3/4 Volume - */ -#define WM8990_OUT3MUTE 0x0020 /* OUT3MUTE */ -#define WM8990_OUT3MUTE_BIT 5 -#define WM8990_OUT3ATTN 0x0010 /* OUT3ATTN */ -#define WM8990_OUT3ATTN_BIT 4 -#define WM8990_OUT4MUTE 0x0002 /* OUT4MUTE */ -#define WM8990_OUT4MUTE_BIT 1 -#define WM8990_OUT4ATTN 0x0001 /* OUT4ATTN */ -#define WM8990_OUT4ATTN_BIT 0 - -/* - * R32 (0x20) - Left OPGA Volume - */ -#define WM8990_OPVU 0x0100 /* OPVU */ -#define WM8990_LOPGAZC 0x0080 /* LOPGAZC */ -#define WM8990_LOPGAZC_BIT 7 -#define WM8990_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */ -#define WM8990_LOPGAVOL_SHIFT 0 - -/* - * R33 (0x21) - Right OPGA Volume - */ -#define WM8990_OPVU 0x0100 /* OPVU */ -#define WM8990_ROPGAZC 0x0080 /* ROPGAZC */ -#define WM8990_ROPGAZC_BIT 7 -#define WM8990_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */ -#define WM8990_ROPGAVOL_SHIFT 0 -/* - * R34 (0x22) - Speaker Volume - */ -#define WM8990_SPKVOL_MASK 0x0003 /* SPKVOL - [1:0] */ -#define WM8990_SPKVOL_SHIFT 0 - -/* - * R35 (0x23) - ClassD1 - */ -#define WM8990_CDMODE 0x0100 /* CDMODE */ -#define WM8990_CDMODE_BIT 8 - -/* - * R37 (0x25) - ClassD3 - */ -#define WM8990_DCGAIN_MASK 0x0007 /* DCGAIN - [5:3] */ -#define WM8990_DCGAIN_SHIFT 3 -#define WM8990_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */ -#define WM8990_ACGAIN_SHIFT 0 -/* - * R39 (0x27) - Input Mixer1 - */ -#define WM8990_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */ -#define WM8990_AINLMODE_SHIFT 2 -#define WM8990_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */ -#define WM8990_AINRMODE_SHIFT 0 - -/* - * R40 (0x28) - Input Mixer2 - */ -#define WM8990_LMP4 0x0080 /* LMP4 */ -#define WM8990_LMP4_BIT 7 /* LMP4 */ -#define WM8990_LMN3 0x0040 /* LMN3 */ -#define WM8990_LMN3_BIT 6 /* LMN3 */ -#define WM8990_LMP2 0x0020 /* LMP2 */ -#define WM8990_LMP2_BIT 5 /* LMP2 */ -#define WM8990_LMN1 0x0010 /* LMN1 */ -#define WM8990_LMN1_BIT 4 /* LMN1 */ -#define WM8990_RMP4 0x0008 /* RMP4 */ -#define WM8990_RMP4_BIT 3 /* RMP4 */ -#define WM8990_RMN3 0x0004 /* RMN3 */ -#define WM8990_RMN3_BIT 2 /* RMN3 */ -#define WM8990_RMP2 0x0002 /* RMP2 */ -#define WM8990_RMP2_BIT 1 /* RMP2 */ -#define WM8990_RMN1 0x0001 /* RMN1 */ -#define WM8990_RMN1_BIT 0 /* RMN1 */ - -/* - * R41 (0x29) - Input Mixer3 - */ -#define WM8990_L34MNB 0x0100 /* L34MNB */ -#define WM8990_L34MNB_BIT 8 -#define WM8990_L34MNBST 0x0080 /* L34MNBST */ -#define WM8990_L34MNBST_BIT 7 -#define WM8990_L12MNB 0x0020 /* L12MNB */ -#define WM8990_L12MNB_BIT 5 -#define WM8990_L12MNBST 0x0010 /* L12MNBST */ -#define WM8990_L12MNBST_BIT 4 -#define WM8990_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */ -#define WM8990_LDBVOL_SHIFT 0 - -/* - * R42 (0x2A) - Input Mixer4 - */ -#define WM8990_R34MNB 0x0100 /* R34MNB */ -#define WM8990_R34MNB_BIT 8 -#define WM8990_R34MNBST 0x0080 /* R34MNBST */ -#define WM8990_R34MNBST_BIT 7 -#define WM8990_R12MNB 0x0020 /* R12MNB */ -#define WM8990_R12MNB_BIT 5 -#define WM8990_R12MNBST 0x0010 /* R12MNBST */ -#define WM8990_R12MNBST_BIT 4 -#define WM8990_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */ -#define WM8990_RDBVOL_SHIFT 0 - -/* - * R43 (0x2B) - Input Mixer5 - */ -#define WM8990_LI2BVOL_MASK 0x07 /* LI2BVOL - [8:6] */ -#define WM8990_LI2BVOL_SHIFT 6 -#define WM8990_LR4BVOL_MASK 0x07 /* LR4BVOL - [5:3] */ -#define WM8990_LR4BVOL_SHIFT 3 -#define WM8990_LL4BVOL_MASK 0x07 /* LL4BVOL - [2:0] */ -#define WM8990_LL4BVOL_SHIFT 0 - -/* - * R44 (0x2C) - Input Mixer6 - */ -#define WM8990_RI2BVOL_MASK 0x07 /* RI2BVOL - [8:6] */ -#define WM8990_RI2BVOL_SHIFT 6 -#define WM8990_RL4BVOL_MASK 0x07 /* RL4BVOL - [5:3] */ -#define WM8990_RL4BVOL_SHIFT 3 -#define WM8990_RR4BVOL_MASK 0x07 /* RR4BVOL - [2:0] */ -#define WM8990_RR4BVOL_SHIFT 0 - -/* - * R45 (0x2D) - Output Mixer1 - */ -#define WM8990_LRBLO 0x0080 /* LRBLO */ -#define WM8990_LRBLO_BIT 7 -#define WM8990_LLBLO 0x0040 /* LLBLO */ -#define WM8990_LLBLO_BIT 6 -#define WM8990_LRI3LO 0x0020 /* LRI3LO */ -#define WM8990_LRI3LO_BIT 5 -#define WM8990_LLI3LO 0x0010 /* LLI3LO */ -#define WM8990_LLI3LO_BIT 4 -#define WM8990_LR12LO 0x0008 /* LR12LO */ -#define WM8990_LR12LO_BIT 3 -#define WM8990_LL12LO 0x0004 /* LL12LO */ -#define WM8990_LL12LO_BIT 2 -#define WM8990_LDLO 0x0001 /* LDLO */ -#define WM8990_LDLO_BIT 0 - -/* - * R46 (0x2E) - Output Mixer2 - */ -#define WM8990_RLBRO 0x0080 /* RLBRO */ -#define WM8990_RLBRO_BIT 7 -#define WM8990_RRBRO 0x0040 /* RRBRO */ -#define WM8990_RRBRO_BIT 6 -#define WM8990_RLI3RO 0x0020 /* RLI3RO */ -#define WM8990_RLI3RO_BIT 5 -#define WM8990_RRI3RO 0x0010 /* RRI3RO */ -#define WM8990_RRI3RO_BIT 4 -#define WM8990_RL12RO 0x0008 /* RL12RO */ -#define WM8990_RL12RO_BIT 3 -#define WM8990_RR12RO 0x0004 /* RR12RO */ -#define WM8990_RR12RO_BIT 2 -#define WM8990_RDRO 0x0001 /* RDRO */ -#define WM8990_RDRO_BIT 0 - -/* - * R47 (0x2F) - Output Mixer3 - */ -#define WM8990_LLI3LOVOL_MASK 0x07 /* LLI3LOVOL - [8:6] */ -#define WM8990_LLI3LOVOL_SHIFT 6 -#define WM8990_LR12LOVOL_MASK 0x07 /* LR12LOVOL - [5:3] */ -#define WM8990_LR12LOVOL_SHIFT 3 -#define WM8990_LL12LOVOL_MASK 0x07 /* LL12LOVOL - [2:0] */ -#define WM8990_LL12LOVOL_SHIFT 0 - -/* - * R48 (0x30) - Output Mixer4 - */ -#define WM8990_RRI3ROVOL_MASK 0x07 /* RRI3ROVOL - [8:6] */ -#define WM8990_RRI3ROVOL_SHIFT 6 -#define WM8990_RL12ROVOL_MASK 0x07 /* RL12ROVOL - [5:3] */ -#define WM8990_RL12ROVOL_SHIFT 3 -#define WM8990_RR12ROVOL_MASK 0x07 /* RR12ROVOL - [2:0] */ -#define WM8990_RR12ROVOL_SHIFT 0 - -/* - * R49 (0x31) - Output Mixer5 - */ -#define WM8990_LRI3LOVOL_MASK 0x07 /* LRI3LOVOL - [8:6] */ -#define WM8990_LRI3LOVOL_SHIFT 6 -#define WM8990_LRBLOVOL_MASK 0x07 /* LRBLOVOL - [5:3] */ -#define WM8990_LRBLOVOL_SHIFT 3 -#define WM8990_LLBLOVOL_MASK 0x07 /* LLBLOVOL - [2:0] */ -#define WM8990_LLBLOVOL_SHIFT 0 - -/* - * R50 (0x32) - Output Mixer6 - */ -#define WM8990_RLI3ROVOL_MASK 0x07 /* RLI3ROVOL - [8:6] */ -#define WM8990_RLI3ROVOL_SHIFT 6 -#define WM8990_RLBROVOL_MASK 0x07 /* RLBROVOL - [5:3] */ -#define WM8990_RLBROVOL_SHIFT 3 -#define WM8990_RRBROVOL_MASK 0x07 /* RRBROVOL - [2:0] */ -#define WM8990_RRBROVOL_SHIFT 0 - -/* - * R51 (0x33) - Out3/4 Mixer - */ -#define WM8990_VSEL_MASK 0x0180 /* VSEL - [8:7] */ -#define WM8990_LI4O3 0x0020 /* LI4O3 */ -#define WM8990_LI4O3_BIT 5 -#define WM8990_LPGAO3 0x0010 /* LPGAO3 */ -#define WM8990_LPGAO3_BIT 4 -#define WM8990_RI4O4 0x0002 /* RI4O4 */ -#define WM8990_RI4O4_BIT 1 -#define WM8990_RPGAO4 0x0001 /* RPGAO4 */ -#define WM8990_RPGAO4_BIT 0 -/* - * R52 (0x34) - Line Mixer1 - */ -#define WM8990_LLOPGALON 0x0040 /* LLOPGALON */ -#define WM8990_LLOPGALON_BIT 6 -#define WM8990_LROPGALON 0x0020 /* LROPGALON */ -#define WM8990_LROPGALON_BIT 5 -#define WM8990_LOPLON 0x0010 /* LOPLON */ -#define WM8990_LOPLON_BIT 4 -#define WM8990_LR12LOP 0x0004 /* LR12LOP */ -#define WM8990_LR12LOP_BIT 2 -#define WM8990_LL12LOP 0x0002 /* LL12LOP */ -#define WM8990_LL12LOP_BIT 1 -#define WM8990_LLOPGALOP 0x0001 /* LLOPGALOP */ -#define WM8990_LLOPGALOP_BIT 0 -/* - * R53 (0x35) - Line Mixer2 - */ -#define WM8990_RROPGARON 0x0040 /* RROPGARON */ -#define WM8990_RROPGARON_BIT 6 -#define WM8990_RLOPGARON 0x0020 /* RLOPGARON */ -#define WM8990_RLOPGARON_BIT 5 -#define WM8990_ROPRON 0x0010 /* ROPRON */ -#define WM8990_ROPRON_BIT 4 -#define WM8990_RL12ROP 0x0004 /* RL12ROP */ -#define WM8990_RL12ROP_BIT 2 -#define WM8990_RR12ROP 0x0002 /* RR12ROP */ -#define WM8990_RR12ROP_BIT 1 -#define WM8990_RROPGAROP 0x0001 /* RROPGAROP */ -#define WM8990_RROPGAROP_BIT 0 - -/* - * R54 (0x36) - Speaker Mixer - */ -#define WM8990_LB2SPK 0x0080 /* LB2SPK */ -#define WM8990_LB2SPK_BIT 7 -#define WM8990_RB2SPK 0x0040 /* RB2SPK */ -#define WM8990_RB2SPK_BIT 6 -#define WM8990_LI2SPK 0x0020 /* LI2SPK */ -#define WM8990_LI2SPK_BIT 5 -#define WM8990_RI2SPK 0x0010 /* RI2SPK */ -#define WM8990_RI2SPK_BIT 4 -#define WM8990_LOPGASPK 0x0008 /* LOPGASPK */ -#define WM8990_LOPGASPK_BIT 3 -#define WM8990_ROPGASPK 0x0004 /* ROPGASPK */ -#define WM8990_ROPGASPK_BIT 2 -#define WM8990_LDSPK 0x0002 /* LDSPK */ -#define WM8990_LDSPK_BIT 1 -#define WM8990_RDSPK 0x0001 /* RDSPK */ -#define WM8990_RDSPK_BIT 0 - -/* - * R55 (0x37) - Additional Control - */ -#define WM8990_VROI 0x0001 /* VROI */ - -/* - * R56 (0x38) - AntiPOP1 - */ -#define WM8990_DIS_LLINE 0x0020 /* DIS_LLINE */ -#define WM8990_DIS_RLINE 0x0010 /* DIS_RLINE */ -#define WM8990_DIS_OUT3 0x0008 /* DIS_OUT3 */ -#define WM8990_DIS_OUT4 0x0004 /* DIS_OUT4 */ -#define WM8990_DIS_LOUT 0x0002 /* DIS_LOUT */ -#define WM8990_DIS_ROUT 0x0001 /* DIS_ROUT */ - -/* - * R57 (0x39) - AntiPOP2 - */ -#define WM8990_SOFTST 0x0040 /* SOFTST */ -#define WM8990_BUFIOEN 0x0008 /* BUFIOEN */ -#define WM8990_BUFDCOPEN 0x0004 /* BUFDCOPEN */ -#define WM8990_POBCTRL 0x0002 /* POBCTRL */ -#define WM8990_VMIDTOG 0x0001 /* VMIDTOG */ - -/* - * R58 (0x3A) - MICBIAS - */ -#define WM8990_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */ -#define WM8990_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */ -#define WM8990_MCD 0x0004 /* MCD */ -#define WM8990_MBSEL 0x0001 /* MBSEL */ - -/* - * R60 (0x3C) - PLL1 - */ -#define WM8990_SDM 0x0080 /* SDM */ -#define WM8990_PRESCALE 0x0040 /* PRESCALE */ -#define WM8990_PLLN_MASK 0x000F /* PLLN - [3:0] */ - -/* - * R61 (0x3D) - PLL2 - */ -#define WM8990_PLLK1_MASK 0x00FF /* PLLK1 - [7:0] */ - -/* - * R62 (0x3E) - PLL3 - */ -#define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */ - -/* - * R63 (0x3F) - Internal Driver Bits - */ -#define WM8990_INMIXL_PWR_BIT 0 -#define WM8990_AINLMUX_PWR_BIT 1 -#define WM8990_INMIXR_PWR_BIT 2 -#define WM8990_AINRMUX_PWR_BIT 3 - -struct wm8990_setup_data { - unsigned short i2c_address; -}; - -#define WM8990_MCLK_DIV 0 -#define WM8990_DACCLK_DIV 1 -#define WM8990_ADCCLK_DIV 2 -#define WM8990_BCLK_DIV 3 - -extern struct snd_soc_dai wm8990_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm8990; - -#endif /* __WM8990REGISTERDEFS_H__ */ -/*------------------------------ END OF FILE ---------------------------------*/ diff --git a/trunk/sound/soc/codecs/wm9712.c b/trunk/sound/soc/codecs/wm9712.c index 9fc8edd82225..76c1e2d33e7d 100644 --- a/trunk/sound/soc/codecs/wm9712.c +++ b/trunk/sound/soc/codecs/wm9712.c @@ -9,6 +9,9 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * Revision history + * 4th Feb 2006 Initial version. */ #include @@ -22,7 +25,6 @@ #include #include #include -#include "wm9712.h" #define WM9712_VERSION "0.4" @@ -349,7 +351,7 @@ SND_SOC_DAPM_INPUT("MIC1"), SND_SOC_DAPM_INPUT("MIC2"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* virtual mixer - mixes left & right channels for spk and mono */ {"AC97 Mixer", NULL, "Left DAC"}, {"AC97 Mixer", NULL, "Right DAC"}, @@ -444,14 +446,21 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Speaker PGA", NULL, "Speaker Mux"}, {"LOUT2", NULL, "Speaker PGA"}, {"ROUT2", NULL, "Speaker PGA"}, + + {NULL, NULL, NULL}, }; static int wm9712_add_widgets(struct snd_soc_codec *codec) { - snd_soc_dapm_new_controls(codec, wm9712_dapm_widgets, - ARRAY_SIZE(wm9712_dapm_widgets)); + int i; + + for (i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]); - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + /* set up audio path connects */ + for (i = 0; audio_map[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); snd_soc_dapm_new_widgets(codec); return 0; @@ -532,7 +541,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000) -struct snd_soc_dai wm9712_dai[] = { +struct snd_soc_codec_dai wm9712_dai[] = { { .name = "AC97 HiFi", .type = SND_SOC_DAI_AC97_BUS, @@ -565,23 +574,23 @@ struct snd_soc_dai wm9712_dai[] = { }; EXPORT_SYMBOL_GPL(wm9712_dai); -static int wm9712_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static int wm9712_dapm_event(struct snd_soc_codec *codec, int event) { - switch (level) { - case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ break; - case SND_SOC_BIAS_STANDBY: + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ ac97_write(codec, AC97_POWERDOWN, 0x0000); break; - case SND_SOC_BIAS_OFF: + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ /* disable everything including AC link */ ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); ac97_write(codec, AC97_POWERDOWN, 0xffff); break; } - codec->bias_level = level; + codec->dapm_state = event; return 0; } @@ -589,12 +598,12 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) { if (try_warm && soc_ac97_ops.warm_reset) { soc_ac97_ops.warm_reset(codec->ac97); - if (ac97_read(codec, 0) == wm9712_reg[0]) + if (!(ac97_read(codec, 0) & 0x8000)) return 1; } soc_ac97_ops.reset(codec->ac97); - if (ac97_read(codec, 0) != wm9712_reg[0]) + if (ac97_read(codec, 0) & 0x8000) goto err; return 0; @@ -609,7 +618,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev, struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; - wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF); + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold); return 0; } @@ -626,7 +635,7 @@ static int wm9712_soc_resume(struct platform_device *pdev) return ret; } - wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); if (ret == 0) { /* Sync reg_cache with the hardware after cold reset */ @@ -638,8 +647,8 @@ static int wm9712_soc_resume(struct platform_device *pdev) } } - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) - wm9712_set_bias_level(codec, SND_SOC_BIAS_ON); + if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0); return ret; } @@ -673,7 +682,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) codec->num_dai = ARRAY_SIZE(wm9712_dai); codec->write = ac97_write; codec->read = ac97_read; - codec->set_bias_level = wm9712_set_bias_level; + codec->dapm_event = wm9712_dapm_event; INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); @@ -697,7 +706,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) /* set alc mux to none */ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); - wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); wm9712_add_controls(codec); wm9712_add_widgets(codec); ret = snd_soc_register_card(socdev); diff --git a/trunk/sound/soc/codecs/wm9712.h b/trunk/sound/soc/codecs/wm9712.h index d29e8a18ca6d..719105d61e65 100644 --- a/trunk/sound/soc/codecs/wm9712.h +++ b/trunk/sound/soc/codecs/wm9712.h @@ -8,7 +8,7 @@ #define WM9712_DAI_AC97_HIFI 0 #define WM9712_DAI_AC97_AUX 1 -extern struct snd_soc_dai wm9712_dai[2]; +extern struct snd_soc_codec_dai wm9712_dai[2]; extern struct snd_soc_codec_device soc_codec_dev_wm9712; #endif diff --git a/trunk/sound/soc/codecs/wm9713.c b/trunk/sound/soc/codecs/wm9713.c index 38d1fe0971fc..1f241161445c 100644 --- a/trunk/sound/soc/codecs/wm9713.c +++ b/trunk/sound/soc/codecs/wm9713.c @@ -10,6 +10,9 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 4th Feb 2006 Initial version. + * * Features:- * * o Support for AC97 Codec, Voice DAC and Aux DAC @@ -453,7 +456,7 @@ SND_SOC_DAPM_INPUT("MIC2B"), SND_SOC_DAPM_VMID("VMID"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* left HP mixer */ {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, @@ -604,14 +607,21 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Capture Mono Mux", "Stereo", "Capture Mixer"}, {"Capture Mono Mux", "Left", "Left Capture Source"}, {"Capture Mono Mux", "Right", "Right Capture Source"}, + + {NULL, NULL, NULL}, }; static int wm9713_add_widgets(struct snd_soc_codec *codec) { - snd_soc_dapm_new_controls(codec, wm9713_dapm_widgets, - ARRAY_SIZE(wm9713_dapm_widgets)); + int i; + + for (i = 0; i < ARRAY_SIZE(wm9713_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm9713_dapm_widgets[i]); - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + /* set up audio path audio_mapnects */ + for (i = 0; audio_map[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); snd_soc_dapm_new_widgets(codec); return 0; @@ -789,7 +799,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, return 0; } -static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, +static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; @@ -800,7 +810,7 @@ static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, * Tristate the PCM DAI lines, tristate can be disabled by calling * wm9713_set_dai_fmt() */ -static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai, +static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai, int tristate) { struct snd_soc_codec *codec = codec_dai->codec; @@ -816,7 +826,7 @@ static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai, * Configure WM9713 clock dividers. * Voice DAC needs 256 FS */ -static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai, +static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, int div_id, int div) { struct snd_soc_codec *codec = codec_dai->codec; @@ -858,7 +868,7 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai, return 0; } -static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; @@ -876,7 +886,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, gpio |= 0x0018; break; case SND_SOC_DAIFMT_CBS_CFS: - reg |= 0x2000; + reg |= 0x0200; gpio |= 0x001a; break; case SND_SOC_DAIFMT_CBS_CFM: @@ -1001,24 +1011,15 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); } -#define WM9713_RATES (SNDRV_PCM_RATE_8000 | \ - SNDRV_PCM_RATE_11025 | \ - SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) - -#define WM9713_PCM_RATES (SNDRV_PCM_RATE_8000 | \ - SNDRV_PCM_RATE_11025 | \ - SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) +#define WM9713_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000) #define WM9713_PCM_FORMATS \ (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ SNDRV_PCM_FORMAT_S24_LE) -struct snd_soc_dai wm9713_dai[] = { +struct snd_soc_codec_dai wm9713_dai[] = { { .name = "AC97 HiFi", .type = SND_SOC_DAI_AC97_BUS, @@ -1060,13 +1061,13 @@ struct snd_soc_dai wm9713_dai[] = { .stream_name = "Voice Playback", .channels_min = 1, .channels_max = 1, - .rates = WM9713_PCM_RATES, + .rates = WM9713_RATES, .formats = WM9713_PCM_FORMATS,}, .capture = { .stream_name = "Voice Capture", .channels_min = 1, .channels_max = 2, - .rates = WM9713_PCM_RATES, + .rates = WM9713_RATES, .formats = WM9713_PCM_FORMATS,}, .ops = { .hw_params = wm9713_pcm_hw_params, @@ -1085,44 +1086,44 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) { if (try_warm && soc_ac97_ops.warm_reset) { soc_ac97_ops.warm_reset(codec->ac97); - if (ac97_read(codec, 0) == wm9713_reg[0]) + if (!(ac97_read(codec, 0) & 0x8000)) return 1; } soc_ac97_ops.reset(codec->ac97); - if (ac97_read(codec, 0) != wm9713_reg[0]) + if (ac97_read(codec, 0) & 0x8000) return -EIO; return 0; } EXPORT_SYMBOL_GPL(wm9713_reset); -static int wm9713_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) +static int wm9713_dapm_event(struct snd_soc_codec *codec, int event) { u16 reg; - switch (level) { - case SND_SOC_BIAS_ON: + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ /* enable thermal shutdown */ reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; ac97_write(codec, AC97_EXTENDED_MID, reg); break; - case SND_SOC_BIAS_PREPARE: + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ break; - case SND_SOC_BIAS_STANDBY: + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ /* enable master bias and vmid */ reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; ac97_write(codec, AC97_EXTENDED_MID, reg); ac97_write(codec, AC97_POWERDOWN, 0x0000); break; - case SND_SOC_BIAS_OFF: + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ /* disable everything including AC link */ ac97_write(codec, AC97_EXTENDED_MID, 0xffff); ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); ac97_write(codec, AC97_POWERDOWN, 0xffff); break; } - codec->bias_level = level; + codec->dapm_state = event; return 0; } @@ -1159,7 +1160,7 @@ static int wm9713_soc_resume(struct platform_device *pdev) return ret; } - wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); /* do we need to re-start the PLL ? */ if (wm9713->pll_out) @@ -1175,8 +1176,8 @@ static int wm9713_soc_resume(struct platform_device *pdev) } } - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) - wm9713_set_bias_level(codec, SND_SOC_BIAS_ON); + if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) + wm9713_dapm_event(codec, SNDRV_CTL_POWER_D0); return ret; } @@ -1215,7 +1216,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) codec->num_dai = ARRAY_SIZE(wm9713_dai); codec->write = ac97_write; codec->read = ac97_read; - codec->set_bias_level = wm9713_set_bias_level; + codec->dapm_event = wm9713_dapm_event; INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); @@ -1237,7 +1238,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) goto reset_err; } - wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); /* unmute the adc - move to kcontrol */ reg = ac97_read(codec, AC97_CD) & 0x7fff; diff --git a/trunk/sound/soc/codecs/wm9713.h b/trunk/sound/soc/codecs/wm9713.h index 63b8d81756e3..d357b6c8134b 100644 --- a/trunk/sound/soc/codecs/wm9713.h +++ b/trunk/sound/soc/codecs/wm9713.h @@ -46,7 +46,7 @@ #define WM9713_DAI_PCM_VOICE 2 extern struct snd_soc_codec_device soc_codec_dev_wm9713; -extern struct snd_soc_dai wm9713_dai[3]; +extern struct snd_soc_codec_dai wm9713_dai[3]; int wm9713_reset(struct snd_soc_codec *codec, int try_warm); diff --git a/trunk/sound/soc/davinci/Kconfig b/trunk/sound/soc/davinci/Kconfig index 8f7e33834902..20680c551aab 100644 --- a/trunk/sound/soc/davinci/Kconfig +++ b/trunk/sound/soc/davinci/Kconfig @@ -1,6 +1,6 @@ config SND_DAVINCI_SOC tristate "SoC Audio for the TI DAVINCI chip" - depends on ARCH_DAVINCI + depends on ARCH_DAVINCI && SND_SOC help Say Y or M if you want to add support for codecs attached to the DAVINCI AC97 or I2S interface. You will also need diff --git a/trunk/sound/soc/davinci/davinci-evm.c b/trunk/sound/soc/davinci/davinci-evm.c index 5e2c306399ed..fcd165240333 100644 --- a/trunk/sound/soc/davinci/davinci-evm.c +++ b/trunk/sound/soc/davinci/davinci-evm.c @@ -33,24 +33,24 @@ static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; int ret = 0; /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF); if (ret < 0) return ret; /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, SND_SOC_CLOCK_OUT); if (ret < 0) return ret; @@ -71,7 +71,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { }; /* davinci-evm machine audio_mapnections to the codec pins */ -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* Headphone connected to HPLOUT, HPROUT */ {"Headphone Jack", NULL, "HPLOUT"}, {"Headphone Jack", NULL, "HPROUT"}, @@ -90,30 +90,36 @@ static const struct snd_soc_dapm_route audio_map[] = { {"LINE2L", NULL, "Line In"}, {"LINE1R", NULL, "Line In"}, {"LINE2R", NULL, "Line In"}, + + {NULL, NULL, NULL}, }; /* Logic for a aic3x as connected on a davinci-evm */ static int evm_aic3x_init(struct snd_soc_codec *codec) { + int i; + /* Add davinci-evm specific widgets */ - snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, - ARRAY_SIZE(aic3x_dapm_widgets)); + for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); /* Set up davinci-evm specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + for (i = 0; audio_map[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); /* not connected */ - snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); - snd_soc_dapm_disable_pin(codec, "HPLCOM"); - snd_soc_dapm_disable_pin(codec, "HPRCOM"); + snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0); + snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0); + snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0); /* always connected */ - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - snd_soc_dapm_enable_pin(codec, "Line Out"); - snd_soc_dapm_enable_pin(codec, "Mic Jack"); - snd_soc_dapm_enable_pin(codec, "Line In"); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); + snd_soc_dapm_set_endpoint(codec, "Line Out", 1); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); + snd_soc_dapm_set_endpoint(codec, "Line In", 1); - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } diff --git a/trunk/sound/soc/davinci/davinci-i2s.c b/trunk/sound/soc/davinci/davinci-i2s.c index 5ebf1ff71c4c..c421774b33ee 100644 --- a/trunk/sound/soc/davinci/davinci-i2s.c +++ b/trunk/sound/soc/davinci/davinci-i2s.c @@ -147,7 +147,7 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) static int davinci_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; cpu_dai->dma_data = dev->dma_params[substream->stream]; @@ -155,7 +155,7 @@ static int davinci_i2s_startup(struct snd_pcm_substream *substream) return 0; } -static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, +static int davinci_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int fmt) { struct davinci_mcbsp_dev *dev = cpu_dai->private_data; @@ -295,12 +295,11 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static int davinci_i2s_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int davinci_i2s_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea; struct evm_snd_platform_data *pdata; @@ -357,12 +356,11 @@ static int davinci_i2s_probe(struct platform_device *pdev, return ret; } -static void davinci_i2s_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static void davinci_i2s_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev = cpu_dai->private_data; struct resource *mem; @@ -378,7 +376,7 @@ static void davinci_i2s_remove(struct platform_device *pdev, #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 -struct snd_soc_dai davinci_i2s_dai = { +struct snd_soc_cpu_dai davinci_i2s_dai = { .name = "davinci-i2s", .id = 0, .type = SND_SOC_DAI_I2S, diff --git a/trunk/sound/soc/davinci/davinci-i2s.h b/trunk/sound/soc/davinci/davinci-i2s.h index c5b091807eec..9592d17db320 100644 --- a/trunk/sound/soc/davinci/davinci-i2s.h +++ b/trunk/sound/soc/davinci/davinci-i2s.h @@ -12,6 +12,6 @@ #ifndef _DAVINCI_I2S_H #define _DAVINCI_I2S_H -extern struct snd_soc_dai davinci_i2s_dai; +extern struct snd_soc_cpu_dai davinci_i2s_dai; #endif diff --git a/trunk/sound/soc/davinci/davinci-pcm.c b/trunk/sound/soc/davinci/davinci-pcm.c index 6a5e56a782bb..6a76927c9971 100644 --- a/trunk/sound/soc/davinci/davinci-pcm.c +++ b/trunk/sound/soc/davinci/davinci-pcm.c @@ -350,7 +350,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) static u64 davinci_pcm_dmamask = 0xffffffff; static int davinci_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) + struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) { int ret; diff --git a/trunk/sound/soc/fsl/Kconfig b/trunk/sound/soc/fsl/Kconfig index 3368ace60977..257101f44e9e 100644 --- a/trunk/sound/soc/fsl/Kconfig +++ b/trunk/sound/soc/fsl/Kconfig @@ -1,6 +1,8 @@ +menu "ALSA SoC audio for Freescale SOCs" + config SND_SOC_MPC8610 bool "ALSA SoC support for the MPC8610 SOC" - depends on MPC8610_HPCD + depends on SND_SOC && MPC8610_HPCD default y if MPC8610 help Say Y if you want to add support for codecs attached to the SSI @@ -14,3 +16,5 @@ config SND_SOC_MPC8610_HPCD default y if MPC8610_HPCD help Say Y if you want to enable audio on the Freescale MPC8610 HPCD. + +endmenu diff --git a/trunk/sound/soc/fsl/fsl_dma.c b/trunk/sound/soc/fsl/fsl_dma.c index da2bc5902864..78de7168d2ba 100644 --- a/trunk/sound/soc/fsl/fsl_dma.c +++ b/trunk/sound/soc/fsl/fsl_dma.c @@ -282,7 +282,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * once for each .dai_link in the machine driver's snd_soc_machine * structure. */ -static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, +static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) { static u64 fsl_dma_dmamask = DMA_BIT_MASK(32); diff --git a/trunk/sound/soc/fsl/fsl_dma.h b/trunk/sound/soc/fsl/fsl_dma.h index 385d4a42603c..430a6ce8b0d0 100644 --- a/trunk/sound/soc/fsl/fsl_dma.h +++ b/trunk/sound/soc/fsl/fsl_dma.h @@ -126,7 +126,7 @@ struct fsl_dma_link_descriptor { u8 res[4]; /* Reserved */ } __attribute__ ((aligned(32), packed)); -/* DMA information needed to create a snd_soc_dai object +/* DMA information needed to create a snd_soc_cpu_dai object * * ssi_stx_phys: bus address of SSI STX register to use * ssi_srx_phys: bus address of SSI SRX register to use diff --git a/trunk/sound/soc/fsl/fsl_ssi.c b/trunk/sound/soc/fsl/fsl_ssi.c index 71bff33f5528..f588545698f3 100644 --- a/trunk/sound/soc/fsl/fsl_ssi.c +++ b/trunk/sound/soc/fsl/fsl_ssi.c @@ -82,7 +82,7 @@ struct fsl_ssi_private { struct device *dev; unsigned int playback; unsigned int capture; - struct snd_soc_dai cpu_dai; + struct snd_soc_cpu_dai cpu_dai; struct device_attribute dev_attr; struct { @@ -479,7 +479,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) * @freq: the frequency of the given clock ID, currently ignored * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) */ -static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai, +static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { @@ -497,7 +497,7 @@ static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai, * * @format: one of SND_SOC_DAIFMT_xxx */ -static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) +static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format) { return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; } @@ -505,7 +505,7 @@ static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) /** * fsl_ssi_dai_template: template CPU DAI for the SSI */ -static struct snd_soc_dai fsl_ssi_dai_template = { +static struct snd_soc_cpu_dai fsl_ssi_dai_template = { .playback = { /* The SSI does not support monaural audio. */ .channels_min = 2, @@ -569,15 +569,15 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev, } /** - * fsl_ssi_create_dai: create a snd_soc_dai structure + * fsl_ssi_create_dai: create a snd_soc_cpu_dai structure * - * This function is called by the machine driver to create a snd_soc_dai + * This function is called by the machine driver to create a snd_soc_cpu_dai * structure. The function creates an ssi_private object, which contains - * the snd_soc_dai. It also creates the sysfs statistics device. + * the snd_soc_cpu_dai. It also creates the sysfs statistics device. */ -struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) +struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) { - struct snd_soc_dai *fsl_ssi_dai; + struct snd_soc_cpu_dai *fsl_ssi_dai; struct fsl_ssi_private *ssi_private; int ret = 0; struct device_attribute *dev_attr; @@ -588,7 +588,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) return NULL; } memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template, - sizeof(struct snd_soc_dai)); + sizeof(struct snd_soc_cpu_dai)); fsl_ssi_dai = &ssi_private->cpu_dai; dev_attr = &ssi_private->dev_attr; @@ -623,11 +623,11 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) EXPORT_SYMBOL_GPL(fsl_ssi_create_dai); /** - * fsl_ssi_destroy_dai: destroy the snd_soc_dai object + * fsl_ssi_destroy_dai: destroy the snd_soc_cpu_dai object * * This function undoes the operations of fsl_ssi_create_dai() */ -void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) +void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai) { struct fsl_ssi_private *ssi_private = container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai); diff --git a/trunk/sound/soc/fsl/fsl_ssi.h b/trunk/sound/soc/fsl/fsl_ssi.h index 83b44d700e33..c5ce88e15651 100644 --- a/trunk/sound/soc/fsl/fsl_ssi.h +++ b/trunk/sound/soc/fsl/fsl_ssi.h @@ -217,8 +217,8 @@ struct fsl_ssi_info { struct device *dev; }; -struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); -void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai); +struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); +void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai); #endif diff --git a/trunk/sound/soc/fsl/mpc8610_hpcd.c b/trunk/sound/soc/fsl/mpc8610_hpcd.c index 4bdc9d8fc90e..a00aac7a71f1 100644 --- a/trunk/sound/soc/fsl/mpc8610_hpcd.c +++ b/trunk/sound/soc/fsl/mpc8610_hpcd.c @@ -58,9 +58,9 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) sound_device->dev.platform_data; /* Program the signal routing between the SSI and the DMA */ - guts_set_dmacr(machine_data->guts, machine_data->dma_id, + guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI); - guts_set_dmacr(machine_data->guts, machine_data->dma_id, + guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI); guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, @@ -96,52 +96,62 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; struct mpc8610_hpcd_data *machine_data = rtd->socdev->dev->platform_data; int ret = 0; /* Tell the CPU driver what the serial protocol is. */ - ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format); - if (ret < 0) { - dev_err(substream->pcm->card->dev, - "could not set CPU driver audio format\n"); - return ret; + if (cpu_dai->dai_ops.set_fmt) { + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, + machine_data->dai_format); + if (ret < 0) { + dev_err(substream->pcm->card->dev, + "could not set CPU driver audio format\n"); + return ret; + } } /* Tell the codec driver what the serial protocol is. */ - ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format); - if (ret < 0) { - dev_err(substream->pcm->card->dev, - "could not set codec driver audio format\n"); - return ret; + if (codec_dai->dai_ops.set_fmt) { + ret = codec_dai->dai_ops.set_fmt(codec_dai, + machine_data->dai_format); + if (ret < 0) { + dev_err(substream->pcm->card->dev, + "could not set codec driver audio format\n"); + return ret; + } } /* * Tell the CPU driver what the clock frequency is, and whether it's a * slave or master. */ - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, - machine_data->clk_frequency, - machine_data->cpu_clk_direction); - if (ret < 0) { - dev_err(substream->pcm->card->dev, - "could not set CPU driver clock parameters\n"); - return ret; + if (cpu_dai->dai_ops.set_sysclk) { + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0, + machine_data->clk_frequency, + machine_data->cpu_clk_direction); + if (ret < 0) { + dev_err(substream->pcm->card->dev, + "could not set CPU driver clock parameters\n"); + return ret; + } } /* * Tell the codec driver what the MCLK frequency is, and whether it's * a slave or master. */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, - machine_data->clk_frequency, - machine_data->codec_clk_direction); - if (ret < 0) { - dev_err(substream->pcm->card->dev, - "could not set codec driver clock params\n"); - return ret; + if (codec_dai->dai_ops.set_sysclk) { + ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, + machine_data->clk_frequency, + machine_data->codec_clk_direction); + if (ret < 0) { + dev_err(substream->pcm->card->dev, + "could not set codec driver clock params\n"); + return ret; + } } return 0; @@ -160,9 +170,9 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) /* Restore the signal routing */ - guts_set_dmacr(machine_data->guts, machine_data->dma_id, + guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, machine_data->dma_channel_id[0], 0); - guts_set_dmacr(machine_data->guts, machine_data->dma_id, + guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, machine_data->dma_channel_id[1], 0); switch (machine_data->ssi_id) { @@ -172,7 +182,7 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) break; case 1: clrsetbits_be32(&machine_data->guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA); + CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); break; } diff --git a/trunk/sound/soc/omap/Kconfig b/trunk/sound/soc/omap/Kconfig index aea27e70043c..0230d83e8e5e 100644 --- a/trunk/sound/soc/omap/Kconfig +++ b/trunk/sound/soc/omap/Kconfig @@ -1,3 +1,5 @@ +menu "SoC Audio for the Texas Instruments OMAP" + config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" depends on ARCH_OMAP && SND_SOC @@ -13,3 +15,5 @@ config SND_OMAP_SOC_N810 select SND_SOC_TLV320AIC3X help Say Y if you want to add support for SoC audio on Nokia N810. + +endmenu diff --git a/trunk/sound/soc/omap/n810.c b/trunk/sound/soc/omap/n810.c index 02cec96859b8..6533563a6011 100644 --- a/trunk/sound/soc/omap/n810.c +++ b/trunk/sound/soc/omap/n810.c @@ -30,15 +30,15 @@ #include #include -#include +#include #include #include "omap-mcbsp.h" #include "omap-pcm.h" #include "../codecs/tlv320aic3x.h" -#define N810_HEADSET_AMP_GPIO 10 -#define N810_SPEAKER_AMP_GPIO 101 +#define RX44_HEADSET_AMP_GPIO 10 +#define RX44_SPEAKER_AMP_GPIO 101 static struct clk *sys_clkout2; static struct clk *sys_clkout2_src; @@ -46,26 +46,13 @@ static struct clk *func96m_clk; static int n810_spk_func; static int n810_jack_func; -static int n810_dmic_func; static void n810_ext_control(struct snd_soc_codec *codec) { - if (n810_spk_func) - snd_soc_dapm_enable_pin(codec, "Ext Spk"); - else - snd_soc_dapm_disable_pin(codec, "Ext Spk"); - - if (n810_jack_func) - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - else - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_set_endpoint(codec, "Ext Spk", n810_spk_func); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", n810_jack_func); - if (n810_dmic_func) - snd_soc_dapm_enable_pin(codec, "DMic"); - else - snd_soc_dapm_disable_pin(codec, "DMic"); - - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); } static int n810_startup(struct snd_pcm_substream *substream) @@ -86,12 +73,12 @@ static int n810_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; int err; /* Set codec DAI configuration */ - err = snd_soc_dai_set_fmt(codec_dai, + err = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); @@ -99,7 +86,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream, return err; /* Set cpu DAI configuration */ - err = snd_soc_dai_set_fmt(cpu_dai, + err = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); @@ -107,7 +94,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream, return err; /* Set the codec system clock for DAC and ADC */ - err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, + err = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 12000000, SND_SOC_CLOCK_IN); return err; @@ -163,35 +150,13 @@ static int n810_set_jack(struct snd_kcontrol *kcontrol, return 1; } -static int n810_get_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = n810_dmic_func; - - return 0; -} - -static int n810_set_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - if (n810_dmic_func == ucontrol->value.integer.value[0]) - return 0; - - n810_dmic_func = ucontrol->value.integer.value[0]; - n810_ext_control(codec); - - return 1; -} - static int n810_spk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); + omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 1); else - gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); + omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 0); return 0; } @@ -200,9 +165,9 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(N810_HEADSET_AMP_GPIO, 1); + omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 1); else - gpio_set_value(N810_HEADSET_AMP_GPIO, 0); + omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 0); return 0; } @@ -210,27 +175,21 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), - SND_SOC_DAPM_MIC("DMic", NULL), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { {"Headphone Jack", NULL, "HPLOUT"}, {"Headphone Jack", NULL, "HPROUT"}, {"Ext Spk", NULL, "LLOUT"}, {"Ext Spk", NULL, "RLOUT"}, - - {"DMic Rate 64", NULL, "Mic Bias 2V"}, - {"Mic Bias 2V", NULL, "DMic"}, }; static const char *spk_function[] = {"Off", "On"}; static const char *jack_function[] = {"Off", "Headphone"}; -static const char *input_function[] = {"ADC", "Digital Mic"}; static const struct soc_enum n810_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), }; static const struct snd_kcontrol_new aic33_n810_controls[] = { @@ -238,8 +197,6 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = { n810_get_spk, n810_set_spk), SOC_ENUM_EXT("Jack Function", n810_enum[1], n810_get_jack, n810_set_jack), - SOC_ENUM_EXT("Input Select", n810_enum[2], - n810_get_input, n810_set_input), }; static int n810_aic33_init(struct snd_soc_codec *codec) @@ -247,9 +204,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec) int i, err; /* Not connected */ - snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); - snd_soc_dapm_disable_pin(codec, "HPLCOM"); - snd_soc_dapm_disable_pin(codec, "HPRCOM"); + snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0); + snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0); + snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0); /* Add N810 specific controls */ for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { @@ -260,13 +217,15 @@ static int n810_aic33_init(struct snd_soc_codec *codec) } /* Add N810 specific widgets */ - snd_soc_dapm_new_controls(codec, aic33_dapm_widgets, - ARRAY_SIZE(aic33_dapm_widgets)); + for (i = 0; i < ARRAY_SIZE(aic33_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &aic33_dapm_widgets[i]); /* Set up N810 specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + for (i = 0; i < ARRAY_SIZE(audio_map); i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } @@ -291,8 +250,6 @@ static struct snd_soc_machine snd_soc_machine_n810 = { /* Audio private data */ static struct aic3x_setup_data n810_aic33_setup = { .i2c_address = 0x18, - .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, - .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, }; /* Audio subsystem */ @@ -310,7 +267,7 @@ static int __init n810_soc_init(void) int err; struct device *dev; - if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) + if (!machine_is_nokia_n810()) return -ENODEV; n810_snd_device = platform_device_alloc("soc-audio", -1); @@ -348,12 +305,12 @@ static int __init n810_soc_init(void) clk_set_parent(sys_clkout2_src, func96m_clk); clk_set_rate(sys_clkout2, 12000000); - if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) + if (omap_request_gpio(RX44_HEADSET_AMP_GPIO) < 0) BUG(); - if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0) + if (omap_request_gpio(RX44_SPEAKER_AMP_GPIO) < 0) BUG(); - gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); - gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); + omap_set_gpio_direction(RX44_HEADSET_AMP_GPIO, 0); + omap_set_gpio_direction(RX44_SPEAKER_AMP_GPIO, 0); return 0; err2: @@ -368,9 +325,6 @@ static int __init n810_soc_init(void) static void __exit n810_soc_exit(void) { - gpio_free(N810_SPEAKER_AMP_GPIO); - gpio_free(N810_HEADSET_AMP_GPIO); - platform_device_unregister(n810_snd_device); } diff --git a/trunk/sound/soc/omap/omap-mcbsp.c b/trunk/sound/soc/omap/omap-mcbsp.c index 00b0c9d73cd4..40d87e6d0de8 100644 --- a/trunk/sound/soc/omap/omap-mcbsp.c +++ b/trunk/sound/soc/omap/omap-mcbsp.c @@ -103,7 +103,7 @@ static const unsigned long omap2420_mcbsp_port[][2] = {}; static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); int err = 0; @@ -116,7 +116,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); if (!cpu_dai->active) { @@ -128,7 +128,7 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); int err = 0; @@ -157,7 +157,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; @@ -223,7 +223,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, * This must be called before _set_clkdiv and _set_sysclk since McBSP register * cache is initialized here */ -static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, +static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int fmt) { struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); @@ -292,7 +292,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, +static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, int div_id, int div) { struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); @@ -347,7 +347,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, return 0; } -static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, +static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { @@ -376,7 +376,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, return err; } -struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = { +struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS] = { { .name = "omap-mcbsp-dai", .id = 0, diff --git a/trunk/sound/soc/omap/omap-mcbsp.h b/trunk/sound/soc/omap/omap-mcbsp.h index ed8afb550671..9965fd4b0427 100644 --- a/trunk/sound/soc/omap/omap-mcbsp.h +++ b/trunk/sound/soc/omap/omap-mcbsp.h @@ -44,6 +44,6 @@ enum omap_mcbsp_div { */ #define NUM_LINKS 1 -extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; +extern struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS]; #endif diff --git a/trunk/sound/soc/omap/omap-pcm.c b/trunk/sound/soc/omap/omap-pcm.c index e092f3d836d0..62370202c649 100644 --- a/trunk/sound/soc/omap/omap-pcm.c +++ b/trunk/sound/soc/omap/omap-pcm.c @@ -316,7 +316,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, +int omap_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) { int ret = 0; diff --git a/trunk/sound/soc/pxa/Kconfig b/trunk/sound/soc/pxa/Kconfig index 12f6ac99b04c..484f883459e0 100644 --- a/trunk/sound/soc/pxa/Kconfig +++ b/trunk/sound/soc/pxa/Kconfig @@ -1,6 +1,6 @@ config SND_PXA2XX_SOC tristate "SoC Audio for the Intel PXA2xx chip" - depends on ARCH_PXA + depends on ARCH_PXA && SND_SOC help Say Y or M if you want to add support for codecs attached to the PXA2xx AC97, I2S or SSP interface. You will also need @@ -62,12 +62,3 @@ config SND_PXA2XX_SOC_E800 help Say Y if you want to add support for SoC audio on the Toshiba e800 PDA - -config SND_PXA2XX_SOC_EM_X270 - tristate "SoC Audio support for CompuLab EM-x270" - depends on SND_PXA2XX_SOC && MACH_EM_X270 - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for SoC audio on - CompuLab EM-x270. diff --git a/trunk/sound/soc/pxa/Makefile b/trunk/sound/soc/pxa/Makefile index 5bc8edf9dca9..04e5646f75ba 100644 --- a/trunk/sound/soc/pxa/Makefile +++ b/trunk/sound/soc/pxa/Makefile @@ -13,11 +13,10 @@ snd-soc-poodle-objs := poodle.o snd-soc-tosa-objs := tosa.o snd-soc-e800-objs := e800_wm9712.o snd-soc-spitz-objs := spitz.o -snd-soc-em-x270-objs := em-x270.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o -obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o + diff --git a/trunk/sound/soc/pxa/corgi.c b/trunk/sound/soc/pxa/corgi.c index c0294464a23a..7f32a1167572 100644 --- a/trunk/sound/soc/pxa/corgi.c +++ b/trunk/sound/soc/pxa/corgi.c @@ -11,6 +11,10 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * Revision history + * 30th Nov 2005 Initial version. + * */ #include @@ -50,51 +54,47 @@ static int corgi_spk_func; static void corgi_ext_control(struct snd_soc_codec *codec) { + int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; + /* set up jack connection */ switch (corgi_jack_func) { case CORGI_HP: + hp = 1; /* set = unmute headphone */ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); - snd_soc_dapm_disable_pin(codec, "Mic Jack"); - snd_soc_dapm_disable_pin(codec, "Line Jack"); - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); break; case CORGI_MIC: + mic = 1; /* reset = mute headphone */ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); - snd_soc_dapm_enable_pin(codec, "Mic Jack"); - snd_soc_dapm_disable_pin(codec, "Line Jack"); - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); break; case CORGI_LINE: + line = 1; reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); - snd_soc_dapm_disable_pin(codec, "Mic Jack"); - snd_soc_dapm_enable_pin(codec, "Line Jack"); - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); break; case CORGI_HEADSET: + hs = 1; + mic = 1; reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); - snd_soc_dapm_enable_pin(codec, "Mic Jack"); - snd_soc_dapm_disable_pin(codec, "Line Jack"); - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_enable_pin(codec, "Headset Jack"); break; } if (corgi_spk_func == CORGI_SPK_ON) - snd_soc_dapm_enable_pin(codec, "Ext Spk"); - else - snd_soc_dapm_disable_pin(codec, "Ext Spk"); + spk = 1; + + /* set the enpoints to their new connetion states */ + snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic); + snd_soc_dapm_set_endpoint(codec, "Line Jack", line); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); /* signal a DAPM event */ - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); } static int corgi_startup(struct snd_pcm_substream *substream) @@ -123,8 +123,8 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int clk = 0; int ret = 0; @@ -143,25 +143,25 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, } /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* set the I2S system clock as input (unused) */ - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, SND_SOC_CLOCK_IN); if (ret < 0) return ret; @@ -247,7 +247,7 @@ SND_SOC_DAPM_HP("Headset Jack", NULL), }; /* Corgi machine audio map (connections to the codec pins) */ -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* headset Jack - in = micin, out = LHPOUT*/ {"Headset Jack", NULL, "LHPOUT"}, @@ -265,6 +265,8 @@ static const struct snd_soc_dapm_route audio_map[] = { /* Same as the above but no mic bias for line signals */ {"MICIN", NULL, "Line Jack"}, + + {NULL, NULL, NULL}, }; static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", @@ -289,8 +291,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) { int i, err; - snd_soc_dapm_disable_pin(codec, "LLINEIN"); - snd_soc_dapm_disable_pin(codec, "RLINEIN"); + snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); /* Add corgi specific controls */ for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { @@ -301,13 +303,15 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) } /* Add corgi specific widgets */ - snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, - ARRAY_SIZE(wm8731_dapm_widgets)); + for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); /* Set up corgi specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + for (i = 0; audio_map[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } diff --git a/trunk/sound/soc/pxa/em-x270.c b/trunk/sound/soc/pxa/em-x270.c deleted file mode 100644 index 02dcac39cdf6..000000000000 --- a/trunk/sound/soc/pxa/em-x270.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * em-x270.c -- SoC audio for EM-X270 - * - * Copyright 2007 CompuLab, Ltd. - * - * Author: Mike Rapoport - * - * Copied from tosa.c: - * Copyright 2005 Wolfson Microelectronics PLC. - * Copyright 2005 Openedhand Ltd. - * - * Authors: Liam Girdwood - * Richard Purdie - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../codecs/wm9712.h" -#include "pxa2xx-pcm.h" -#include "pxa2xx-ac97.h" - -static struct snd_soc_dai_link em_x270_dai[] = { - { - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], - }, - { - .name = "AC97 Aux", - .stream_name = "AC97 Aux", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], - }, -}; - -static struct snd_soc_machine em_x270 = { - .name = "EM-X270", - .dai_link = em_x270_dai, - .num_links = ARRAY_SIZE(em_x270_dai), -}; - -static struct snd_soc_device em_x270_snd_devdata = { - .machine = &em_x270, - .platform = &pxa2xx_soc_platform, - .codec_dev = &soc_codec_dev_wm9712, -}; - -static struct platform_device *em_x270_snd_device; - -static int __init em_x270_init(void) -{ - int ret; - - if (!machine_is_em_x270()) - return -ENODEV; - - em_x270_snd_device = platform_device_alloc("soc-audio", -1); - if (!em_x270_snd_device) - return -ENOMEM; - - platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata); - em_x270_snd_devdata.dev = &em_x270_snd_device->dev; - ret = platform_device_add(em_x270_snd_device); - - if (ret) - platform_device_put(em_x270_snd_device); - - return ret; -} - -static void __exit em_x270_exit(void) -{ - platform_device_unregister(em_x270_snd_device); -} - -module_init(em_x270_init); -module_exit(em_x270_exit); - -/* Module information */ -MODULE_AUTHOR("Mike Rapoport"); -MODULE_DESCRIPTION("ALSA SoC EM-X270"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/pxa/poodle.c b/trunk/sound/soc/pxa/poodle.c index 65a4e9a8c39e..7e830b218943 100644 --- a/trunk/sound/soc/pxa/poodle.c +++ b/trunk/sound/soc/pxa/poodle.c @@ -48,6 +48,8 @@ static int poodle_spk_func; static void poodle_ext_control(struct snd_soc_codec *codec) { + int spk = 0; + /* set up jack connection */ if (poodle_jack_func == POODLE_HP) { /* set = unmute headphone */ @@ -55,23 +57,23 @@ static void poodle_ext_control(struct snd_soc_codec *codec) POODLE_LOCOMO_GPIO_MUTE_L, 1); locomo_gpio_write(&poodle_locomo_device.dev, POODLE_LOCOMO_GPIO_MUTE_R, 1); - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); } else { locomo_gpio_write(&poodle_locomo_device.dev, POODLE_LOCOMO_GPIO_MUTE_L, 0); locomo_gpio_write(&poodle_locomo_device.dev, POODLE_LOCOMO_GPIO_MUTE_R, 0); - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); } - /* set the enpoints to their new connetion states */ if (poodle_spk_func == POODLE_SPK_ON) - snd_soc_dapm_enable_pin(codec, "Ext Spk"); - else - snd_soc_dapm_disable_pin(codec, "Ext Spk"); + spk = 1; + + /* set the enpoints to their new connetion states */ + snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); /* signal a DAPM event */ - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); } static int poodle_startup(struct snd_pcm_substream *substream) @@ -102,8 +104,8 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int clk = 0; int ret = 0; @@ -122,25 +124,25 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, } /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* set the I2S system clock as input (unused) */ - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, SND_SOC_CLOCK_IN); if (ret < 0) return ret; @@ -213,8 +215,8 @@ SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), }; -/* Corgi machine connections to the codec pins */ -static const struct snd_soc_dapm_route audio_map[] = { +/* Corgi machine audio_mapnections to the codec pins */ +static const char *audio_map[][3] = { /* headphone connected to LHPOUT1, RHPOUT1 */ {"Headphone Jack", NULL, "LHPOUT"}, @@ -223,6 +225,8 @@ static const struct snd_soc_dapm_route audio_map[] = { /* speaker connected to LOUT, ROUT */ {"Ext Spk", NULL, "ROUT"}, {"Ext Spk", NULL, "LOUT"}, + + {NULL, NULL, NULL}, }; static const char *jack_function[] = {"Off", "Headphone"}; @@ -246,9 +250,9 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) { int i, err; - snd_soc_dapm_disable_pin(codec, "LLINEIN"); - snd_soc_dapm_disable_pin(codec, "RLINEIN"); - snd_soc_dapm_enable_pin(codec, "MICIN"); + snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "MICIN", 1); /* Add poodle specific controls */ for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { @@ -259,13 +263,15 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) } /* Add poodle specific widgets */ - snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, - ARRAY_SIZE(wm8731_dapm_widgets)); + for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); /* Set up poodle specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + for (i = 0; audio_map[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } diff --git a/trunk/sound/soc/pxa/pxa2xx-ac97.c b/trunk/sound/soc/pxa/pxa2xx-ac97.c index 059af815ea0c..97ec2d90547c 100644 --- a/trunk/sound/soc/pxa/pxa2xx-ac97.c +++ b/trunk/sound/soc/pxa/pxa2xx-ac97.c @@ -283,7 +283,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { #ifdef CONFIG_PM static int pxa2xx_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { GCR |= GCR_ACLINK_OFF; clk_disable(ac97_clk); @@ -291,7 +291,7 @@ static int pxa2xx_ac97_suspend(struct platform_device *pdev, } static int pxa2xx_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { pxa_gpio_mode(GPIO31_SYNC_AC97_MD); pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); @@ -310,8 +310,7 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev, #define pxa2xx_ac97_resume NULL #endif -static int pxa2xx_ac97_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int pxa2xx_ac97_probe(struct platform_device *pdev) { int ret; @@ -356,8 +355,7 @@ static int pxa2xx_ac97_probe(struct platform_device *pdev, return ret; } -static void pxa2xx_ac97_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static void pxa2xx_ac97_remove(struct platform_device *pdev) { GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); @@ -374,7 +372,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; @@ -388,7 +386,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; @@ -402,7 +400,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; @@ -420,7 +418,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, * There is only 1 physical AC97 interface for pxa2xx, but it * has extra fifo's that can be used for aux DACs and ADCs. */ -struct snd_soc_dai pxa_ac97_dai[] = { +struct snd_soc_cpu_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97", .id = 0, diff --git a/trunk/sound/soc/pxa/pxa2xx-ac97.h b/trunk/sound/soc/pxa/pxa2xx-ac97.h index e390de8edcd4..b8ccfee095c4 100644 --- a/trunk/sound/soc/pxa/pxa2xx-ac97.h +++ b/trunk/sound/soc/pxa/pxa2xx-ac97.h @@ -14,7 +14,7 @@ #define PXA2XX_DAI_AC97_AUX 1 #define PXA2XX_DAI_AC97_MIC 2 -extern struct snd_soc_dai pxa_ac97_dai[3]; +extern struct snd_soc_cpu_dai pxa_ac97_dai[3]; /* platform data */ extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; diff --git a/trunk/sound/soc/pxa/pxa2xx-i2s.c b/trunk/sound/soc/pxa/pxa2xx-i2s.c index 9c06553b9267..425071030970 100644 --- a/trunk/sound/soc/pxa/pxa2xx-i2s.c +++ b/trunk/sound/soc/pxa/pxa2xx-i2s.c @@ -9,6 +9,9 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * Revision history + * 12th Aug 2005 Initial version. */ #include @@ -77,7 +80,7 @@ static struct pxa2xx_gpio gpio_bus[] = { static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (!cpu_dai->active) { SACR0 |= SACR0_RST; @@ -98,7 +101,7 @@ static int pxa_i2s_wait(void) return 0; } -static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, +static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int fmt) { /* interface format */ @@ -124,7 +127,7 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, +static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { if (clk_id != PXA2XX_I2S_SYSCLK) @@ -140,7 +143,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); @@ -237,7 +240,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) #ifdef CONFIG_PM static int pxa2xx_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { if (!dai->active) return 0; @@ -255,7 +258,7 @@ static int pxa2xx_i2s_suspend(struct platform_device *dev, } static int pxa2xx_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { if (!dai->active) return 0; @@ -280,7 +283,7 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev, SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) -struct snd_soc_dai pxa_i2s_dai = { +struct snd_soc_cpu_dai pxa_i2s_dai = { .name = "pxa2xx-i2s", .id = 0, .type = SND_SOC_DAI_I2S, diff --git a/trunk/sound/soc/pxa/pxa2xx-i2s.h b/trunk/sound/soc/pxa/pxa2xx-i2s.h index e2def441153e..4435bd9f884f 100644 --- a/trunk/sound/soc/pxa/pxa2xx-i2s.h +++ b/trunk/sound/soc/pxa/pxa2xx-i2s.h @@ -15,6 +15,6 @@ /* I2S clock */ #define PXA2XX_I2S_SYSCLK 0 -extern struct snd_soc_dai pxa_i2s_dai; +extern struct snd_soc_cpu_dai pxa_i2s_dai; #endif diff --git a/trunk/sound/soc/pxa/pxa2xx-pcm.c b/trunk/sound/soc/pxa/pxa2xx-pcm.c index 2df03ee5819e..01ad7bf716b7 100644 --- a/trunk/sound/soc/pxa/pxa2xx-pcm.c +++ b/trunk/sound/soc/pxa/pxa2xx-pcm.c @@ -330,7 +330,7 @@ static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; -int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, +int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) { int ret = 0; diff --git a/trunk/sound/soc/pxa/spitz.c b/trunk/sound/soc/pxa/spitz.c index 64385797da5d..d8b8372db00e 100644 --- a/trunk/sound/soc/pxa/spitz.c +++ b/trunk/sound/soc/pxa/spitz.c @@ -12,6 +12,9 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 30th Nov 2005 Initial version. + * */ #include @@ -51,60 +54,60 @@ static int spitz_spk_func; static void spitz_ext_control(struct snd_soc_codec *codec) { if (spitz_spk_func == SPITZ_SPK_ON) - snd_soc_dapm_enable_pin(codec, "Ext Spk"); + snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); else - snd_soc_dapm_disable_pin(codec, "Ext Spk"); + snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0); /* set up jack connection */ switch (spitz_jack_func) { case SPITZ_HP: /* enable and unmute hp jack, disable mic bias */ - snd_soc_dapm_disable_pin(codec, "Headset Jack"); - snd_soc_dapm_disable_pin(codec, "Mic Jack"); - snd_soc_dapm_disable_pin(codec, "Line Jack"); - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); break; case SPITZ_MIC: /* enable mic jack and bias, mute hp */ - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); - snd_soc_dapm_disable_pin(codec, "Line Jack"); - snd_soc_dapm_enable_pin(codec, "Mic Jack"); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); break; case SPITZ_LINE: /* enable line jack, disable mic bias and mute hp */ - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); - snd_soc_dapm_disable_pin(codec, "Mic Jack"); - snd_soc_dapm_enable_pin(codec, "Line Jack"); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 1); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); break; case SPITZ_HEADSET: /* enable and unmute headset jack enable mic bias, mute L hp */ - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_enable_pin(codec, "Mic Jack"); - snd_soc_dapm_disable_pin(codec, "Line Jack"); - snd_soc_dapm_enable_pin(codec, "Headset Jack"); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); break; case SPITZ_HP_OFF: /* jack removed, everything off */ - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); - snd_soc_dapm_disable_pin(codec, "Mic Jack"); - snd_soc_dapm_disable_pin(codec, "Line Jack"); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); + snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); break; } - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); } static int spitz_startup(struct snd_pcm_substream *substream) @@ -121,8 +124,8 @@ static int spitz_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int clk = 0; int ret = 0; @@ -141,25 +144,25 @@ static int spitz_hw_params(struct snd_pcm_substream *substream, } /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* set the I2S system clock as input (unused) */ - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, SND_SOC_CLOCK_IN); if (ret < 0) return ret; @@ -247,7 +250,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { }; /* Spitz machine audio_map */ -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* headphone connected to LOUT1, ROUT1 */ {"Headphone Jack", NULL, "LOUT1"}, @@ -266,6 +269,8 @@ static const struct snd_soc_dapm_route audio_map[] = { /* line is connected to input 1 - no bias */ {"LINPUT1", NULL, "Line Jack"}, + + {NULL, NULL, NULL}, }; static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", @@ -291,13 +296,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) int i, err; /* NC codec pins */ - snd_soc_dapm_disable_pin(codec, "RINPUT1"); - snd_soc_dapm_disable_pin(codec, "LINPUT2"); - snd_soc_dapm_disable_pin(codec, "RINPUT2"); - snd_soc_dapm_disable_pin(codec, "LINPUT3"); - snd_soc_dapm_disable_pin(codec, "RINPUT3"); - snd_soc_dapm_disable_pin(codec, "OUT3"); - snd_soc_dapm_disable_pin(codec, "MONO"); + snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0); + snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0); + snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0); + snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0); + snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0); + snd_soc_dapm_set_endpoint(codec, "OUT3", 0); + snd_soc_dapm_set_endpoint(codec, "MONO", 0); /* Add spitz specific controls */ for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { @@ -308,13 +313,15 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) } /* Add spitz specific widgets */ - snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, - ARRAY_SIZE(wm8750_dapm_widgets)); + for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); - /* Set up spitz specific audio paths */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + /* Set up spitz specific audio path audio_map */ + for (i = 0; audio_map[i][0] != NULL; i++) + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } diff --git a/trunk/sound/soc/pxa/tosa.c b/trunk/sound/soc/pxa/tosa.c index b6edb61a3a30..7346d7e5d066 100644 --- a/trunk/sound/soc/pxa/tosa.c +++ b/trunk/sound/soc/pxa/tosa.c @@ -12,6 +12,9 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 30th Nov 2005 Initial version. + * * GPIO's * 1 - Jack Insertion * 5 - Hookswitch (headset answer/hang up switch) @@ -52,31 +55,29 @@ static int tosa_spk_func; static void tosa_ext_control(struct snd_soc_codec *codec) { + int spk = 0, mic_int = 0, hp = 0, hs = 0; + /* set up jack connection */ switch (tosa_jack_func) { case TOSA_HP: - snd_soc_dapm_disable_pin(codec, "Mic (Internal)"); - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); + hp = 1; break; case TOSA_MIC_INT: - snd_soc_dapm_enable_pin(codec, "Mic (Internal)"); - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_disable_pin(codec, "Headset Jack"); + mic_int = 1; break; case TOSA_HEADSET: - snd_soc_dapm_disable_pin(codec, "Mic (Internal)"); - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - snd_soc_dapm_enable_pin(codec, "Headset Jack"); + hs = 1; break; } if (tosa_spk_func == TOSA_SPK_ON) - snd_soc_dapm_enable_pin(codec, "Speaker"); - else - snd_soc_dapm_disable_pin(codec, "Speaker"); + spk = 1; - snd_soc_dapm_sync(codec); + snd_soc_dapm_set_endpoint(codec, "Speaker", spk); + snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); + snd_soc_dapm_sync_endpoints(codec); } static int tosa_startup(struct snd_pcm_substream *substream) @@ -153,7 +154,7 @@ SND_SOC_DAPM_SPK("Speaker", NULL), }; /* tosa audio map */ -static const struct snd_soc_dapm_route audio_map[] = { +static const char *audio_map[][3] = { /* headphone connected to HPOUTL, HPOUTR */ {"Headphone Jack", NULL, "HPOUTL"}, @@ -172,6 +173,8 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Headset Jack", NULL, "HPOUTR"}, {"LINEINR", NULL, "Mic Bias"}, {"Mic Bias", NULL, "Headset Jack"}, + + {NULL, NULL, NULL}, }; static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", @@ -193,8 +196,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec) { int i, err; - snd_soc_dapm_disable_pin(codec, "OUT3"); - snd_soc_dapm_disable_pin(codec, "MONOOUT"); + snd_soc_dapm_set_endpoint(codec, "OUT3", 0); + snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0); /* add tosa specific controls */ for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { @@ -205,13 +208,17 @@ static int tosa_ac97_init(struct snd_soc_codec *codec) } /* add tosa specific widgets */ - snd_soc_dapm_new_controls(codec, tosa_dapm_widgets, - ARRAY_SIZE(tosa_dapm_widgets)); + for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]); + } /* set up tosa specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + for (i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } diff --git a/trunk/sound/soc/s3c24xx/Kconfig b/trunk/sound/soc/s3c24xx/Kconfig index b9f2353effeb..1f6dbfc4caa8 100644 --- a/trunk/sound/soc/s3c24xx/Kconfig +++ b/trunk/sound/soc/s3c24xx/Kconfig @@ -1,6 +1,7 @@ config SND_S3C24XX_SOC tristate "SoC Audio for the Samsung S3C24XX chips" - depends on ARCH_S3C2410 + depends on ARCH_S3C2410 && SND_SOC + select SND_PCM help Say Y or M if you want to add support for codecs attached to the S3C24XX AC97, I2S or SSP interface. You will also need @@ -15,6 +16,7 @@ config SND_S3C2412_SOC_I2S config SND_S3C2443_SOC_AC97 tristate select AC97_BUS + select SND_AC97_CODEC select SND_SOC_AC97_BUS config SND_S3C24XX_SOC_NEO1973_WM8753 diff --git a/trunk/sound/soc/s3c24xx/neo1973_wm8753.c b/trunk/sound/soc/s3c24xx/neo1973_wm8753.c index 4d7a9aa15f1a..0e9d1c5f2484 100644 --- a/trunk/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/trunk/sound/soc/s3c24xx/neo1973_wm8753.c @@ -10,6 +10,10 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 20th Jan 2007 Initial version. + * 05th Feb 2007 Rename all to Neo1973 + * */ #include @@ -22,7 +26,6 @@ #include #include #include -#include #include #include @@ -40,14 +43,6 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-i2s.h" -/* Debugging stuff */ -#define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0 -#if S3C24XX_SOC_NEO1973_WM8753_DEBUG -#define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x) -#else -#define DBG(x...) -#endif - /* define the scenarios */ #define NEO_AUDIO_OFF 0 #define NEO_GSM_CALL_AUDIO_HANDSET 1 @@ -66,14 +61,12 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int pll_out = 0, bclk = 0; int ret = 0; unsigned long iis_clkrate; - DBG("Entered %s\n", __func__); - iis_clkrate = s3c24xx_i2s_get_clockrate(); switch (params_rate(params)) { @@ -108,44 +101,44 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, } /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* set MCLK division for sample rate */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, S3C2410_IISMOD_32FS); if (ret < 0) return ret; /* set codec BCLK division for sample rate */ - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); + ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); if (ret < 0) return ret; /* set prescaler division for sample rate */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, S3C24XX_PRESCALE(4, 4)); if (ret < 0) return ret; /* codec PLL input is PCLK/4 */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, + ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, iis_clkrate / 4, pll_out); if (ret < 0) return ret; @@ -156,12 +149,10 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - - DBG("Entered %s\n", __func__); + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); + return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0); } /* @@ -176,13 +167,11 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; unsigned int pcmdiv = 0; int ret = 0; unsigned long iis_clkrate; - DBG("Entered %s\n", __func__); - iis_clkrate = s3c24xx_i2s_get_clockrate(); if (params_rate(params) != 8000) @@ -194,24 +183,24 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, /* todo: gg check mode (DSP_B) against CSR datasheet */ /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, SND_SOC_CLOCK_IN); if (ret < 0) return ret; /* set codec PCM division for sample rate */ - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); + ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); if (ret < 0) return ret; /* configue and enable PLL for 12.288MHz output */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, + ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, iis_clkrate / 4, 12288000); if (ret < 0) return ret; @@ -222,12 +211,10 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - - DBG("Entered %s\n", __func__); + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); + return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0); } static struct snd_soc_ops neo1973_voice_ops = { @@ -246,81 +233,79 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) { - DBG("Entered %s\n", __func__); - switch (neo1973_scenario) { case NEO_AUDIO_OFF: - snd_soc_dapm_disable_pin(codec, "Audio Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_GSM_CALL_AUDIO_HANDSET: - snd_soc_dapm_enable_pin(codec, "Audio Out"); - snd_soc_dapm_enable_pin(codec, "GSM Line Out"); - snd_soc_dapm_enable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_enable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); break; case NEO_GSM_CALL_AUDIO_HEADSET: - snd_soc_dapm_enable_pin(codec, "Audio Out"); - snd_soc_dapm_enable_pin(codec, "GSM Line Out"); - snd_soc_dapm_enable_pin(codec, "GSM Line In"); - snd_soc_dapm_enable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_GSM_CALL_AUDIO_BLUETOOTH: - snd_soc_dapm_disable_pin(codec, "Audio Out"); - snd_soc_dapm_enable_pin(codec, "GSM Line Out"); - snd_soc_dapm_enable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_STEREO_TO_SPEAKERS: - snd_soc_dapm_enable_pin(codec, "Audio Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_STEREO_TO_HEADPHONES: - snd_soc_dapm_enable_pin(codec, "Audio Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_CAPTURE_HANDSET: - snd_soc_dapm_disable_pin(codec, "Audio Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_enable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); break; case NEO_CAPTURE_HEADSET: - snd_soc_dapm_disable_pin(codec, "Audio Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line In"); - snd_soc_dapm_enable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; case NEO_CAPTURE_BLUETOOTH: - snd_soc_dapm_disable_pin(codec, "Audio Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); break; default: - snd_soc_dapm_disable_pin(codec, "Audio Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line Out"); - snd_soc_dapm_disable_pin(codec, "GSM Line In"); - snd_soc_dapm_disable_pin(codec, "Headset Mic"); - snd_soc_dapm_disable_pin(codec, "Call Mic"); + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); } - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } @@ -330,8 +315,6 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - DBG("Entered %s\n", __func__); - if (neo1973_scenario == ucontrol->value.integer.value[0]) return 0; @@ -344,8 +327,6 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; static void lm4857_write_regs(void) { - DBG("Entered %s\n", __func__); - if (i2c_master_send(i2c, lm4857_regs, 4) != 4) printk(KERN_ERR "lm4857: i2c write failed\n"); } @@ -357,8 +338,6 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol, int shift = (kcontrol->private_value >> 8) & 0x0F; int mask = (kcontrol->private_value >> 16) & 0xFF; - DBG("Entered %s\n", __func__); - ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; return 0; } @@ -385,8 +364,6 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol, { u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; - DBG("Entered %s\n", __func__); - if (value) value -= 5; @@ -399,8 +376,6 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol, { u8 value = ucontrol->value.integer.value[0]; - DBG("Entered %s\n", __func__); - if (value) value += 5; @@ -422,7 +397,8 @@ static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { }; -static const struct snd_soc_dapm_route dapm_routes[] = { +/* example machine audio_mapnections */ +static const char *audio_map[][3] = { /* Connections to the lm4857 amp */ {"Audio Out", NULL, "LOUT1"}, @@ -445,6 +421,8 @@ static const struct snd_soc_dapm_route dapm_routes[] = { /* Connect the ALC pins */ {"ACIN", NULL, "ACOP"}, + + {NULL, NULL, NULL}, }; static const char *lm4857_mode[] = { @@ -475,16 +453,13 @@ static const struct soc_enum neo_scenario_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios), }; -static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); -static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); - static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { - SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, - lm4857_get_reg, lm4857_set_reg, stereo_tlv), - SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, - lm4857_get_reg, lm4857_set_reg, stereo_tlv), - SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, - lm4857_get_reg, lm4857_set_reg, mono_tlv), + SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, + lm4857_get_reg, lm4857_set_reg), + SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, + lm4857_get_reg, lm4857_set_reg), + SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, + lm4857_get_reg, lm4857_set_reg), SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], lm4857_get_mode, lm4857_set_mode), SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0], @@ -508,23 +483,21 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) { int i, err; - DBG("Entered %s\n", __func__); - /* set up NC codec pins */ - snd_soc_dapm_disable_pin(codec, "LOUT2"); - snd_soc_dapm_disable_pin(codec, "ROUT2"); - snd_soc_dapm_disable_pin(codec, "OUT3"); - snd_soc_dapm_disable_pin(codec, "OUT4"); - snd_soc_dapm_disable_pin(codec, "LINE1"); - snd_soc_dapm_disable_pin(codec, "LINE2"); + snd_soc_dapm_set_endpoint(codec, "LOUT2", 0); + snd_soc_dapm_set_endpoint(codec, "ROUT2", 0); + snd_soc_dapm_set_endpoint(codec, "OUT3", 0); + snd_soc_dapm_set_endpoint(codec, "OUT4", 0); + snd_soc_dapm_set_endpoint(codec, "LINE1", 0); + snd_soc_dapm_set_endpoint(codec, "LINE2", 0); /* set endpoints to default mode */ set_scenario_endpoints(codec, NEO_AUDIO_OFF); /* Add neo1973 specific widgets */ - snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, - ARRAY_SIZE(wm8753_dapm_widgets)); + for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]); /* add neo1973 specific controls */ for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { @@ -535,18 +508,20 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) return err; } - /* set up neo1973 specific audio routes */ - err = snd_soc_dapm_add_routes(codec, dapm_routes, - ARRAY_SIZE(dapm_routes)); + /* set up neo1973 specific audio path audio_mapnects */ + for (i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } /* * BT Codec DAI */ -static struct snd_soc_dai bt_dai = { +static struct snd_soc_cpu_dai bt_dai = { .name = "Bluetooth", .id = 0, .type = SND_SOC_DAI_PCM, @@ -608,8 +583,6 @@ static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind) { int ret; - DBG("Entered %s\n", __func__); - client_template.adapter = adap; client_template.addr = addr; @@ -633,8 +606,6 @@ static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind) static int lm4857_i2c_detach(struct i2c_client *client) { - DBG("Entered %s\n", __func__); - i2c_detach_client(client); kfree(client); return 0; @@ -642,8 +613,6 @@ static int lm4857_i2c_detach(struct i2c_client *client) static int lm4857_i2c_attach(struct i2c_adapter *adap) { - DBG("Entered %s\n", __func__); - return i2c_probe(adap, &addr_data, lm4857_amp_probe); } @@ -651,8 +620,6 @@ static u8 lm4857_state; static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) { - DBG("Entered %s\n", __func__); - dev_dbg(&dev->dev, "lm4857_suspend\n"); lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; if (lm4857_state) { @@ -664,8 +631,6 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) static int lm4857_resume(struct i2c_client *dev) { - DBG("Entered %s\n", __func__); - if (lm4857_state) { lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); lm4857_write_regs(); @@ -675,8 +640,6 @@ static int lm4857_resume(struct i2c_client *dev) static void lm4857_shutdown(struct i2c_client *dev) { - DBG("Entered %s\n", __func__); - dev_dbg(&dev->dev, "lm4857_shutdown\n"); lm4857_regs[LM4857_CTRL] &= 0xf0; lm4857_write_regs(); @@ -708,8 +671,6 @@ static int __init neo1973_init(void) { int ret; - DBG("Entered %s\n", __func__); - neo1973_snd_device = platform_device_alloc("soc-audio", -1); if (!neo1973_snd_device) return -ENOMEM; @@ -730,8 +691,6 @@ static int __init neo1973_init(void) static void __exit neo1973_exit(void) { - DBG("Entered %s\n", __func__); - i2c_del_driver(&lm4857_i2c_driver); platform_device_unregister(neo1973_snd_device); } diff --git a/trunk/sound/soc/s3c24xx/s3c2412-i2s.c b/trunk/sound/soc/s3c24xx/s3c2412-i2s.c index ee4676ed1283..c4a46dd589b3 100644 --- a/trunk/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/trunk/sound/soc/s3c24xx/s3c2412-i2s.c @@ -295,7 +295,7 @@ static inline int s3c2412_snd_is_clkmaster(void) /* * Set S3C2412 I2S DAI format */ -static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, +static int s3c2412_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int fmt) { u32 iismod; @@ -500,7 +500,7 @@ EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); /* * Set S3C2412 Clock source */ -static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, +static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); @@ -528,7 +528,7 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, /* * Set S3C2412 Clock dividers */ -static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, +static int s3c2412_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, int div_id, int div) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; @@ -601,8 +601,7 @@ struct clk *s3c2412_get_iisclk(void) EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); -static int s3c2412_i2s_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int s3c2412_i2s_probe(struct platform_device *pdev) { DBG("Entered %s\n", __func__); @@ -648,7 +647,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, #ifdef CONFIG_PM static int s3c2412_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; u32 iismod; @@ -676,7 +675,7 @@ static int s3c2412_i2s_suspend(struct platform_device *dev, } static int s3c2412_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) + struct snd_soc_cpu_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; @@ -708,7 +707,7 @@ static int s3c2412_i2s_resume(struct platform_device *pdev, SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) -struct snd_soc_dai s3c2412_i2s_dai = { +struct snd_soc_cpu_dai s3c2412_i2s_dai = { .name = "s3c2412-i2s", .id = 0, .type = SND_SOC_DAI_I2S, diff --git a/trunk/sound/soc/s3c24xx/s3c2412-i2s.h b/trunk/sound/soc/s3c24xx/s3c2412-i2s.h index aac08a25e541..27f48e1ffa86 100644 --- a/trunk/sound/soc/s3c24xx/s3c2412-i2s.h +++ b/trunk/sound/soc/s3c24xx/s3c2412-i2s.h @@ -24,7 +24,7 @@ extern struct clk *s3c2412_get_iisclk(void); -extern struct snd_soc_dai s3c2412_i2s_dai; +extern struct snd_soc_cpu_dai s3c2412_i2s_dai; struct s3c2412_rate_calc { unsigned int clk_div; /* for prescaler */ diff --git a/trunk/sound/soc/s3c24xx/s3c2443-ac97.c b/trunk/sound/soc/s3c24xx/s3c2443-ac97.c index 783349b7fede..e81d9a6c83da 100644 --- a/trunk/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/trunk/sound/soc/s3c24xx/s3c2443-ac97.c @@ -10,6 +10,9 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * Revision history + * 21st Mar 2007 Initial Version */ #include @@ -209,8 +212,7 @@ static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = { .dma_size = 4, }; -static int s3c2443_ac97_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int s3c2443_ac97_probe(struct platform_device *pdev) { int ret; u32 ac_glbctrl; @@ -261,8 +263,7 @@ static int s3c2443_ac97_probe(struct platform_device *pdev, return ret; } -static void s3c2443_ac97_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static void s3c2443_ac97_remove(struct platform_device *pdev) { free_irq(IRQ_S3C244x_AC97, NULL); clk_disable(s3c24xx_ac97.ac97_clk); @@ -274,7 +275,7 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out; @@ -316,7 +317,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; @@ -352,7 +353,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) -struct snd_soc_dai s3c2443_ac97_dai[] = { +struct snd_soc_cpu_dai s3c2443_ac97_dai[] = { { .name = "s3c2443-ac97", .id = 0, diff --git a/trunk/sound/soc/s3c24xx/s3c24xx-ac97.h b/trunk/sound/soc/s3c24xx/s3c24xx-ac97.h index a96dcadf28b4..bf03e8ed16c3 100644 --- a/trunk/sound/soc/s3c24xx/s3c24xx-ac97.h +++ b/trunk/sound/soc/s3c24xx/s3c24xx-ac97.h @@ -26,6 +26,6 @@ #define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97 #endif -extern struct snd_soc_dai s3c2443_ac97_dai[]; +extern struct snd_soc_cpu_dai s3c2443_ac97_dai[]; #endif /*S3C24XXAC97_H_*/ diff --git a/trunk/sound/soc/s3c24xx/s3c24xx-i2s.c b/trunk/sound/soc/s3c24xx/s3c24xx-i2s.c index 397524282b57..1ed6afd45459 100644 --- a/trunk/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/trunk/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -12,6 +12,11 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * + * Revision history + * 11th Dec 2006 Merged with Simtec driver + * 10th Nov 2006 Initial version. */ #include @@ -175,7 +180,7 @@ static void s3c24xx_snd_rxctrl(int on) static int s3c24xx_snd_lrsync(void) { u32 iiscon; - int timeout = 50; /* 5ms */ + unsigned long timeout = jiffies + msecs_to_jiffies(5); DBG("Entered %s\n", __func__); @@ -184,9 +189,8 @@ static int s3c24xx_snd_lrsync(void) if (iiscon & S3C2410_IISCON_LRINDEX) break; - if (!timeout--) + if (time_after(jiffies, timeout)) return -ETIMEDOUT; - udelay(100); } return 0; @@ -205,7 +209,7 @@ static inline int s3c24xx_snd_is_clkmaster(void) /* * Set S3C24xx I2S DAI format */ -static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, +static int s3c24xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int fmt) { u32 iismod; @@ -313,7 +317,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) /* * Set S3C24xx Clock source */ -static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, +static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -339,7 +343,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, /* * Set S3C24xx Clock dividers */ -static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, +static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, int div_id, int div) { u32 reg; @@ -377,8 +381,7 @@ u32 s3c24xx_i2s_get_clockrate(void) } EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); -static int s3c24xx_i2s_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int s3c24xx_i2s_probe(struct platform_device *pdev) { DBG("Entered %s\n", __func__); @@ -411,7 +414,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, #ifdef CONFIG_PM static int s3c24xx_i2s_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) + struct snd_soc_cpu_dai *cpu_dai) { DBG("Entered %s\n", __func__); @@ -426,7 +429,7 @@ static int s3c24xx_i2s_suspend(struct platform_device *pdev, } static int s3c24xx_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) + struct snd_soc_cpu_dai *cpu_dai) { DBG("Entered %s\n", __func__); clk_enable(s3c24xx_i2s.iis_clk); @@ -449,7 +452,7 @@ static int s3c24xx_i2s_resume(struct platform_device *pdev, SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) -struct snd_soc_dai s3c24xx_i2s_dai = { +struct snd_soc_cpu_dai s3c24xx_i2s_dai = { .name = "s3c24xx-i2s", .id = 0, .type = SND_SOC_DAI_I2S, diff --git a/trunk/sound/soc/s3c24xx/s3c24xx-i2s.h b/trunk/sound/soc/s3c24xx/s3c24xx-i2s.h index 726d91cf4e1c..537b4ecce8a3 100644 --- a/trunk/sound/soc/s3c24xx/s3c24xx-i2s.h +++ b/trunk/sound/soc/s3c24xx/s3c24xx-i2s.h @@ -32,6 +32,6 @@ u32 s3c24xx_i2s_get_clockrate(void); -extern struct snd_soc_dai s3c24xx_i2s_dai; +extern struct snd_soc_cpu_dai s3c24xx_i2s_dai; #endif /*S3C24XXI2S_H_*/ diff --git a/trunk/sound/soc/s3c24xx/s3c24xx-pcm.c b/trunk/sound/soc/s3c24xx/s3c24xx-pcm.c index cef79b34dc6f..7806ae614617 100644 --- a/trunk/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/trunk/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -12,6 +12,10 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * Revision history + * 11th Dec 2006 Merged with Simtec driver + * 10th Nov 2006 Initial version. */ #include @@ -429,7 +433,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 s3c24xx_pcm_dmamask = DMA_32BIT_MASK; static int s3c24xx_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) + struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) { int ret = 0; diff --git a/trunk/sound/soc/s3c24xx/smdk2443_wm9710.c b/trunk/sound/soc/s3c24xx/smdk2443_wm9710.c index 8515d6ff03f2..b4a56302b9ab 100644 --- a/trunk/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/trunk/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -10,6 +10,9 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 8th Mar 2007 Initial version. + * */ #include diff --git a/trunk/sound/soc/sh/Kconfig b/trunk/sound/soc/sh/Kconfig index 54bd604012af..4c1e013381c9 100644 --- a/trunk/sound/soc/sh/Kconfig +++ b/trunk/sound/soc/sh/Kconfig @@ -3,7 +3,7 @@ menu "SoC Audio support for SuperH" config SND_SOC_PCM_SH7760 tristate "SoC Audio support for Renesas SH7760" - depends on CPU_SUBTYPE_SH7760 && SH_DMABRG + depends on CPU_SUBTYPE_SH7760 && SND_SOC && SH_DMABRG help Enable this option for SH7760 AC97/I2S audio support. @@ -13,9 +13,10 @@ config SND_SOC_PCM_SH7760 ## config SND_SOC_SH4_HAC - tristate select AC97_BUS select SND_SOC_AC97_BUS + select SND_AC97_CODEC + tristate config SND_SOC_SH4_SSI tristate diff --git a/trunk/sound/soc/sh/dma-sh7760.c b/trunk/sound/soc/sh/dma-sh7760.c index 9faa12622d09..7a3ce80d6727 100644 --- a/trunk/sound/soc/sh/dma-sh7760.c +++ b/trunk/sound/soc/sh/dma-sh7760.c @@ -326,7 +326,7 @@ static void camelot_pcm_free(struct snd_pcm *pcm) } static int camelot_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, + struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) { /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel diff --git a/trunk/sound/soc/sh/hac.c b/trunk/sound/soc/sh/hac.c index df7bc345c320..b7b676b3d671 100644 --- a/trunk/sound/soc/sh/hac.c +++ b/trunk/sound/soc/sh/hac.c @@ -266,7 +266,7 @@ static int hac_hw_params(struct snd_pcm_substream *substream, #define AC97_FMTS \ SNDRV_PCM_FMTBIT_S16_LE -struct snd_soc_dai sh4_hac_dai[] = { +struct snd_soc_cpu_dai sh4_hac_dai[] = { { .name = "HAC0", .id = 0, diff --git a/trunk/sound/soc/sh/sh7760-ac97.c b/trunk/sound/soc/sh/sh7760-ac97.c index 92bfaf4774a7..2f91de84c5c7 100644 --- a/trunk/sound/soc/sh/sh7760-ac97.c +++ b/trunk/sound/soc/sh/sh7760-ac97.c @@ -20,12 +20,12 @@ #define IPSEL 0xFE400034 /* platform specific structs can be declared here */ -extern struct snd_soc_dai sh4_hac_dai[2]; +extern struct snd_soc_cpu_dai sh4_hac_dai[2]; extern struct snd_soc_platform sh7760_soc_platform; static int machine_init(struct snd_soc_codec *codec) { - snd_soc_dapm_sync(codec); + snd_soc_dapm_sync_endpoints(codec); return 0; } diff --git a/trunk/sound/soc/sh/ssi.c b/trunk/sound/soc/sh/ssi.c index 55c3464163ab..3388bc3d62d1 100644 --- a/trunk/sound/soc/sh/ssi.c +++ b/trunk/sound/soc/sh/ssi.c @@ -208,7 +208,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream, return 0; } -static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, +static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; @@ -222,7 +222,7 @@ static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, * This divider is used to generate the SSI_SCK (I2S bitclock) from the * clock at the HAC_BIT_CLK ("oversampling clock") pin. */ -static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div) +static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div) { struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; unsigned long ssicr; @@ -245,7 +245,7 @@ static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div) return 0; } -static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt) { struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; unsigned long ssicr = SSIREG(SSICR); @@ -332,7 +332,7 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) -struct snd_soc_dai sh4_ssi_dai[] = { +struct snd_soc_cpu_dai sh4_ssi_dai[] = { { .name = "SSI0", .id = 0, diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index 83f1190293a8..e148db940cfc 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -14,6 +14,10 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 12th Aug 2005 Initial version. + * 25th Oct 2005 Working Codec, Interface and Platform registration. + * * TODO: * o Add hw rules to enforce rates, etc. * o More testing with other codecs/machines. @@ -108,9 +112,9 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) } #endif -static inline const char *get_dai_name(int type) +static inline const char* get_dai_name(int type) { - switch (type) { + switch(type) { case SND_SOC_DAI_AC97_BUS: case SND_SOC_DAI_AC97: return "AC97"; @@ -134,8 +138,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_dai *cpu_dai = machine->cpu_dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; int ret = 0; mutex_lock(&pcm_mutex); @@ -178,11 +182,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* Check that the codec and cpu DAI's are compatible */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { runtime->hw.rate_min = - max(codec_dai->playback.rate_min, - cpu_dai->playback.rate_min); + max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min); runtime->hw.rate_max = - min(codec_dai->playback.rate_max, - cpu_dai->playback.rate_max); + min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max); runtime->hw.channels_min = max(codec_dai->playback.channels_min, cpu_dai->playback.channels_min); @@ -195,11 +197,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) codec_dai->playback.rates & cpu_dai->playback.rates; } else { runtime->hw.rate_min = - max(codec_dai->capture.rate_min, - cpu_dai->capture.rate_min); + max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min); runtime->hw.rate_max = - min(codec_dai->capture.rate_max, - cpu_dai->capture.rate_max); + min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max); runtime->hw.channels_min = max(codec_dai->capture.channels_min, cpu_dai->capture.channels_min); @@ -229,7 +229,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto machine_err; } - dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); + dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name); dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, runtime->hw.channels_max); @@ -272,11 +272,11 @@ static void close_delayed_work(struct work_struct *work) struct snd_soc_device *socdev = container_of(work, struct snd_soc_device, delayed_work.work); struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_dai *codec_dai; + struct snd_soc_codec_dai *codec_dai; int i; mutex_lock(&pcm_mutex); - for (i = 0; i < codec->num_dai; i++) { + for(i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; dbg("pop wq checking: %s status: %s waiting: %s\n", @@ -287,12 +287,12 @@ static void close_delayed_work(struct work_struct *work) /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { - /* Reduce power if no longer active */ + /* power down the codec to D1 if no longer active */ if (codec->active == 0) { dbg("pop wq D1 %s %s\n", codec->name, codec_dai->playback.stream_name); - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); + snd_soc_dapm_device_event(socdev, + SNDRV_CTL_POWER_D1); } codec_dai->pop_wait = 0; @@ -300,12 +300,12 @@ static void close_delayed_work(struct work_struct *work) codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_STOP); - /* Fall into standby if no longer active */ + /* power down the codec power domain if no longer active */ if (codec->active == 0) { dbg("pop wq D3 %s %s\n", codec->name, codec_dai->playback.stream_name); - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_STANDBY); + snd_soc_dapm_device_event(socdev, + SNDRV_CTL_POWER_D3hot); } } } @@ -323,8 +323,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_dai *cpu_dai = machine->cpu_dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; mutex_lock(&pcm_mutex); @@ -365,8 +365,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) SND_SOC_DAPM_STREAM_STOP); if (codec->active == 0 && codec_dai->pop_wait == 0) - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_STANDBY); + snd_soc_dapm_device_event(socdev, + SNDRV_CTL_POWER_D3hot); } mutex_unlock(&pcm_mutex); @@ -384,8 +384,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_dai *cpu_dai = machine->cpu_dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; int ret = 0; @@ -434,14 +434,14 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) else { codec_dai->pop_wait = 0; cancel_delayed_work(&socdev->delayed_work); - snd_soc_dai_digital_mute(codec_dai, 0); + if (codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 0); } } else { /* no delayed work - do we need to power up codec */ - if (codec->bias_level != SND_SOC_BIAS_ON) { + if (codec->dapm_state != SNDRV_CTL_POWER_D0) { - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); + snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D1); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dapm_stream_event(codec, @@ -452,8 +452,9 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); - snd_soc_dai_digital_mute(codec_dai, 0); + snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D0); + if (codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 0); } else { /* codec already powered - power on widgets */ @@ -465,8 +466,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - - snd_soc_dai_digital_mute(codec_dai, 0); + if (codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 0); } } @@ -487,8 +488,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_dai *cpu_dai = machine->cpu_dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; int ret = 0; mutex_lock(&pcm_mutex); @@ -513,7 +514,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (cpu_dai->ops.hw_params) { ret = cpu_dai->ops.hw_params(substream, params); if (ret < 0) { - printk(KERN_ERR "asoc: interface %s hw params failed\n", + printk(KERN_ERR "asoc: can't set interface %s hw params\n", cpu_dai->name); goto interface_err; } @@ -522,7 +523,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (platform->pcm_ops->hw_params) { ret = platform->pcm_ops->hw_params(substream, params); if (ret < 0) { - printk(KERN_ERR "asoc: platform %s hw params failed\n", + printk(KERN_ERR "asoc: can't set platform %s hw params\n", platform->name); goto platform_err; } @@ -541,7 +542,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_dai->ops.hw_free(substream); codec_err: - if (machine->ops && machine->ops->hw_free) + if(machine->ops && machine->ops->hw_free) machine->ops->hw_free(substream); mutex_unlock(&pcm_mutex); @@ -557,15 +558,15 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_dai *cpu_dai = machine->cpu_dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; mutex_lock(&pcm_mutex); /* apply codec digital mute */ - if (!codec->active) - snd_soc_dai_digital_mute(codec_dai, 1); + if (!codec->active && codec_dai->dai_ops.digital_mute) + codec_dai->dai_ops.digital_mute(codec_dai, 1); /* free any machine hw params */ if (machine->ops && machine->ops->hw_free) @@ -592,8 +593,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_dai *cpu_dai = machine->cpu_dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_codec_dai *codec_dai = machine->codec_dai; int ret; if (codec_dai->ops.trigger) { @@ -630,26 +631,16 @@ static struct snd_pcm_ops soc_pcm_ops = { /* powers down audio subsystem for suspend */ static int soc_suspend(struct platform_device *pdev, pm_message_t state) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; int i; - /* Due to the resume being scheduled into a workqueue we could - * suspend before that's finished - wait for it to complete. - */ - snd_power_lock(codec->card); - snd_power_wait(codec->card, SNDRV_CTL_POWER_D0); - snd_power_unlock(codec->card); - - /* we're going to block userspace touching us until resume completes */ - snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot); - /* mute any active DAC's */ - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; if (dai->dai_ops.digital_mute && dai->playback.active) dai->dai_ops.digital_mute(dai, 1); } @@ -661,8 +652,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (machine->suspend_pre) machine->suspend_pre(pdev, state); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) @@ -671,9 +662,9 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) /* close any waiting streams and save state */ run_delayed_work(&socdev->delayed_work); - codec->suspend_bias_level = codec->bias_level; + codec->suspend_dapm_state = codec->dapm_state; - for (i = 0; i < codec->num_dai; i++) { + for(i = 0; i < codec->num_dai; i++) { char *stream = codec->dai[i].playback.stream_name; if (stream != NULL) snd_soc_dapm_stream_event(codec, stream, @@ -687,8 +678,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (codec_dev->suspend) codec_dev->suspend(pdev, state); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) cpu_dai->suspend(pdev, cpu_dai); } @@ -699,32 +690,21 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -/* deferred resume work, so resume can complete before we finished - * setting our codec back up, which can be very slow on I2C - */ -static void soc_resume_deferred(struct work_struct *work) +/* powers up audio subsystem after a suspend */ +static int soc_resume(struct platform_device *pdev) { - struct snd_soc_device *socdev = container_of(work, - struct snd_soc_device, - deferred_resume_work); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_platform *platform = socdev->platform; - struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; - struct platform_device *pdev = to_platform_device(socdev->dev); int i; - /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, - * so userspace apps are blocked from touching us - */ - - dev_info(socdev->dev, "starting resume work\n"); - if (machine->resume_pre) machine->resume_pre(pdev); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) cpu_dai->resume(pdev, cpu_dai); } @@ -732,8 +712,8 @@ static void soc_resume_deferred(struct work_struct *work) if (codec_dev->resume) codec_dev->resume(pdev); - for (i = 0; i < codec->num_dai; i++) { - char *stream = codec->dai[i].playback.stream_name; + for(i = 0; i < codec->num_dai; i++) { + char* stream = codec->dai[i].playback.stream_name; if (stream != NULL) snd_soc_dapm_stream_event(codec, stream, SND_SOC_DAPM_STREAM_RESUME); @@ -743,15 +723,15 @@ static void soc_resume_deferred(struct work_struct *work) SND_SOC_DAPM_STREAM_RESUME); } - /* unmute any active DACs */ - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; + /* unmute any active DAC's */ + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; if (dai->dai_ops.digital_mute && dai->playback.active) dai->dai_ops.digital_mute(dai, 0); } - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for(i = 0; i < machine->num_links; i++) { + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) cpu_dai->resume(pdev, cpu_dai); if (platform->resume) @@ -761,22 +741,6 @@ static void soc_resume_deferred(struct work_struct *work) if (machine->resume_post) machine->resume_post(pdev); - dev_info(socdev->dev, "resume work completed\n"); - - /* userspace can access us now we are back as we were before */ - snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0); -} - -/* powers up audio subsystem after a suspend */ -static int soc_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - dev_info(socdev->dev, "scheduling resume work\n"); - - if (!schedule_work(&socdev->deferred_resume_work)) - dev_err(socdev->dev, "work item may be lost\n"); - return 0; } @@ -796,38 +760,33 @@ static int soc_probe(struct platform_device *pdev) if (machine->probe) { ret = machine->probe(pdev); - if (ret < 0) + if(ret < 0) return ret; } for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->probe) { - ret = cpu_dai->probe(pdev, cpu_dai); - if (ret < 0) + ret = cpu_dai->probe(pdev); + if(ret < 0) goto cpu_dai_err; } } if (codec_dev->probe) { ret = codec_dev->probe(pdev); - if (ret < 0) + if(ret < 0) goto cpu_dai_err; } if (platform->probe) { ret = platform->probe(pdev); - if (ret < 0) + if(ret < 0) goto platform_err; } /* DAPM stream work */ INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); -#ifdef CONFIG_PM - /* deferred resume work */ - INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred); -#endif - return 0; platform_err: @@ -836,9 +795,9 @@ static int soc_probe(struct platform_device *pdev) cpu_dai_err: for (i--; i >= 0; i--) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->remove) - cpu_dai->remove(pdev, cpu_dai); + cpu_dai->remove(pdev); } if (machine->remove) @@ -865,9 +824,9 @@ static int soc_remove(struct platform_device *pdev) codec_dev->remove(pdev); for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->remove) - cpu_dai->remove(pdev, cpu_dai); + cpu_dai->remove(pdev); } if (machine->remove) @@ -893,8 +852,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, struct snd_soc_dai_link *dai_link, int num) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_dai *codec_dai = dai_link->codec_dai; - struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; + struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai; struct snd_soc_pcm_runtime *rtd; struct snd_pcm *pcm; char new_name[64]; @@ -909,7 +868,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev, codec_dai->codec = socdev->codec; /* check client and interface hw capabilities */ - sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name, + sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, get_dai_name(cpu_dai->type), num); if (codec_dai->playback.channels_min) @@ -920,8 +879,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev, ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, capture, &pcm); if (ret < 0) { - printk(KERN_ERR "asoc: can't create pcm for codec %s\n", - codec->name); + printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); kfree(rtd); return ret; } @@ -970,9 +928,8 @@ static ssize_t codec_reg_show(struct device *dev, step = codec->reg_cache_step; count += sprintf(buf, "%s registers\n", codec->name); - for (i = 0; i < codec->reg_cache_size; i += step) - count += sprintf(buf + count, "%2x: %4x\n", i, - codec->read(codec, i)); + for(i = 0; i < codec->reg_cache_size; i += step) + count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i)); return count; } @@ -1115,7 +1072,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); /* create the pcms */ - for (i = 0; i < machine->num_links; i++) { + for(i = 0; i < machine->num_links; i++) { ret = soc_new_pcm(socdev, &machine->dai_link[i], i); if (ret < 0) { printk(KERN_ERR "asoc: can't create pcm %s\n", @@ -1145,7 +1102,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) struct snd_soc_machine *machine = socdev->machine; int ret = 0, i, ac97 = 0, err = 0; - for (i = 0; i < machine->num_links; i++) { + for(i = 0; i < machine->num_links; i++) { if (socdev->machine->dai_link[i].init) { err = socdev->machine->dai_link[i].init(codec); if (err < 0) { @@ -1154,7 +1111,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) continue; } } - if (socdev->machine->dai_link[i].codec_dai->type == + if (socdev->machine->dai_link[i].codec_dai->type == SND_SOC_DAI_AC97_BUS) ac97 = 1; } @@ -1165,7 +1122,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) ret = snd_card_register(codec->card); if (ret < 0) { - printk(KERN_ERR "asoc: failed to register soundcard for %s\n", + printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", codec->name); goto out; } @@ -1189,7 +1146,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) err = device_create_file(socdev->dev, &dev_attr_codec_reg); if (err < 0) - printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); + printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); mutex_unlock(&codec->mutex); @@ -1209,13 +1166,13 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; #ifdef CONFIG_SND_SOC_AC97_BUS - struct snd_soc_dai *codec_dai; + struct snd_soc_codec_dai *codec_dai; int i; #endif mutex_lock(&codec->mutex); #ifdef CONFIG_SND_SOC_AC97_BUS - for (i = 0; i < codec->num_dai; i++) { + for(i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { soc_ac97_dev_unregister(codec); @@ -1325,8 +1282,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] - = (val >> e->shift_l) & (bitmask - 1); + ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); if (e->shift_l != e->shift_r) ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1); @@ -1620,8 +1576,7 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, val = val << shift; val2 = val2 << shift; - err = snd_soc_update_bits(codec, reg, val_mask, val); - if (err < 0) + if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) return err; err = snd_soc_update_bits(codec, reg2, val_mask, val2); @@ -1629,204 +1584,6 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); -/** - * snd_soc_info_volsw_s8 - signed mixer info callback - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to provide information about a signed mixer control. - * - * Returns 0 for success. - */ -int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int max = (signed char)((kcontrol->private_value >> 16) & 0xff); - int min = (signed char)((kcontrol->private_value >> 24) & 0xff); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = max-min; - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); - -/** - * snd_soc_get_volsw_s8 - signed mixer get callback - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to get the value of a signed mixer control. - * - * Returns 0 for success. - */ -int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value & 0xff; - int min = (signed char)((kcontrol->private_value >> 24) & 0xff); - int val = snd_soc_read(codec, reg); - - ucontrol->value.integer.value[0] = - ((signed char)(val & 0xff))-min; - ucontrol->value.integer.value[1] = - ((signed char)((val >> 8) & 0xff))-min; - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); - -/** - * snd_soc_put_volsw_sgn - signed mixer put callback - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to set the value of a signed mixer control. - * - * Returns 0 for success. - */ -int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value & 0xff; - int min = (signed char)((kcontrol->private_value >> 24) & 0xff); - unsigned short val; - - val = (ucontrol->value.integer.value[0]+min) & 0xff; - val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; - - return snd_soc_update_bits(codec, reg, 0xffff, val); -} -EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); - -/** - * snd_soc_dai_set_sysclk - configure DAI system or master clock. - * @dai: DAI - * @clk_id: DAI specific clock ID - * @freq: new clock frequency in Hz - * @dir: new clock direction - input/output. - * - * Configures the DAI master (MCLK) or system (SYSCLK) clocking. - */ -int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); - -/** - * snd_soc_dai_set_clkdiv - configure DAI clock dividers. - * @dai: DAI - * @clk_id: DAI specific clock divider ID - * @div: new clock divisor. - * - * Configures the clock dividers. This is used to derive the best DAI bit and - * frame clocks from the system or master clock. It's best to set the DAI bit - * and frame clocks as low as possible to save system power. - */ -int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div) -{ - if (dai->dai_ops.set_clkdiv) - return dai->dai_ops.set_clkdiv(dai, div_id, div); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); - -/** - * snd_soc_dai_set_pll - configure DAI PLL. - * @dai: DAI - * @pll_id: DAI specific PLL ID - * @freq_in: PLL input clock frequency in Hz - * @freq_out: requested PLL output clock frequency in Hz - * - * Configures and enables PLL to generate output clock based on input clock. - */ -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) -{ - if (dai->dai_ops.set_pll) - return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); - -/** - * snd_soc_dai_set_fmt - configure DAI hardware audio format. - * @dai: DAI - * @clk_id: DAI specific clock ID - * @fmt: SND_SOC_DAIFMT_ format value. - * - * Configures the DAI hardware format and clocking. - */ -int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - if (dai->dai_ops.set_fmt) - return dai->dai_ops.set_fmt(dai, fmt); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); - -/** - * snd_soc_dai_set_tdm_slot - configure DAI TDM. - * @dai: DAI - * @mask: DAI specific mask representing used slots. - * @slots: Number of slots in use. - * - * Configures a DAI for TDM operation. Both mask and slots are codec and DAI - * specific. - */ -int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots) -{ - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_tdm_slot(dai, mask, slots); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); - -/** - * snd_soc_dai_set_tristate - configure DAI system or master clock. - * @dai: DAI - * @tristate: tristate enable - * - * Tristates the DAI so that others can use it. - */ -int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) -{ - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_tristate(dai, tristate); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); - -/** - * snd_soc_dai_digital_mute - configure DAI system or master clock. - * @dai: DAI - * @mute: mute enable - * - * Mutes the DAI DAC. - */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) -{ - if (dai->dai_ops.digital_mute) - return dai->dai_ops.digital_mute(dai, mute); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); - static int __devinit snd_soc_init(void) { printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); @@ -1835,7 +1592,7 @@ static int __devinit snd_soc_init(void) static void snd_soc_exit(void) { - platform_driver_unregister(&soc_driver); + platform_driver_unregister(&soc_driver); } module_init(snd_soc_init); diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index 2c87061c2a6b..af3326c63504 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -10,6 +10,11 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * + * Revision history + * 12th Aug 2005 Initial version. + * 25th Oct 2005 Implemented path power domain. + * 18th Dec 2005 Implemented machine and stream level power domain. + * * Features: * o Changes power status of internal codec blocks depending on the * dynamic configuration of codec internal audio paths and active @@ -45,10 +50,23 @@ #include /* debug */ -#ifdef DEBUG +#define DAPM_DEBUG 0 +#if DAPM_DEBUG #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) +#define dbg(format, arg...) printk(format, ## arg) #else #define dump_dapm(codec, action) +#define dbg(format, arg...) +#endif + +#define POP_DEBUG 0 +#if POP_DEBUG +#define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */ +#define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time)) +#define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME) +#else +#define pop_dbg(format, arg...) +#define pop_wait(time) #endif /* dapm power sequences - make this per codec in the future */ @@ -67,28 +85,6 @@ static int dapm_status = 1; module_param(dapm_status, int, 0); MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); -static unsigned int pop_time; - -static void pop_wait(void) -{ - if (pop_time) - schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); -} - -static void pop_dbg(const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - - if (pop_time) { - vprintk(fmt, args); - pop_wait(); - } - - va_end(args); -} - /* create a new dapm widget */ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) @@ -226,12 +222,11 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget) change = old != new; if (change) { pop_dbg("pop test %s : %s in %d ms\n", widget->name, - widget->power ? "on" : "off", pop_time); + widget->power ? "on" : "off", POP_TIME); snd_soc_write(codec, widget->reg, new); - pop_wait(); + pop_wait(POP_TIME); } - pr_debug("reg %x old %x new %x change %d\n", widget->reg, - old, new, change); + dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change); return change; } @@ -452,25 +447,6 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) return con; } -/* - * Handler for generic register modifier widget. - */ -int dapm_reg_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - unsigned int val; - - if (SND_SOC_DAPM_EVENT_ON(event)) - val = w->on_val; - else - val = w->off_val; - - snd_soc_update_bits(w->codec, -(w->reg + 1), - w->mask << w->shift, val << w->shift); - - return 0; -} - /* * Scan each dapm widget for complete audio path. * A complete path is a route that has valid endpoints i.e.:- @@ -589,8 +565,8 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) /* call any power change event handlers */ if (power_change) { if (w->event) { - pr_debug("power %s event for %s flags %x\n", - w->power ? "on" : "off", w->name, w->event_flags); + dbg("power %s event for %s flags %x\n", + w->power ? "on" : "off", w->name, w->event_flags); if (power) { /* power up event */ if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { @@ -632,7 +608,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) return ret; } -#ifdef DEBUG +#if DAPM_DEBUG static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) { struct snd_soc_dapm_widget *w; @@ -717,10 +693,8 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, path->connect = 0; /* old connection must be powered down */ } - if (found) { + if (found) dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(widget->codec, "mux power update"); - } return 0; } @@ -756,10 +730,8 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, break; } - if (found) { + if (found) dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(widget->codec, "mixer power update"); - } return 0; } @@ -796,18 +768,21 @@ static ssize_t dapm_widget_show(struct device *dev, } } - switch (codec->bias_level) { - case SND_SOC_BIAS_ON: - state = "On"; + switch(codec->dapm_state){ + case SNDRV_CTL_POWER_D0: + state = "D0"; break; - case SND_SOC_BIAS_PREPARE: - state = "Prepare"; + case SNDRV_CTL_POWER_D1: + state = "D1"; break; - case SND_SOC_BIAS_STANDBY: - state = "Standby"; + case SNDRV_CTL_POWER_D2: + state = "D2"; break; - case SND_SOC_BIAS_OFF: - state = "Off"; + case SNDRV_CTL_POWER_D3hot: + state = "D3hot"; + break; + case SNDRV_CTL_POWER_D3cold: + state = "D3cold"; break; } count += sprintf(buf + count, "PM State: %s\n", state); @@ -817,51 +792,20 @@ static ssize_t dapm_widget_show(struct device *dev, static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); -/* pop/click delay times */ -static ssize_t dapm_pop_time_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", pop_time); -} - -static ssize_t dapm_pop_time_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) - -{ - unsigned long val; - - if (strict_strtoul(buf, 10, &val) >= 0) - pop_time = val; - else - printk(KERN_ERR "Unable to parse pop_time setting\n"); - - return count; -} - -static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show, - dapm_pop_time_store); - int snd_soc_dapm_sys_add(struct device *dev) { int ret = 0; - if (dapm_status) { + if (dapm_status) ret = device_create_file(dev, &dev_attr_dapm_widget); - if (ret == 0) - ret = device_create_file(dev, &dev_attr_dapm_pop_time); - } - return ret; } static void snd_soc_dapm_sys_remove(struct device *dev) { - if (dapm_status) { - device_remove_file(dev, &dev_attr_dapm_pop_time); + if (dapm_status) device_remove_file(dev, &dev_attr_dapm_widget); - } } /* free all dapm widgets and resources */ @@ -882,25 +826,8 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) } } -static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, - char *pin, int status) -{ - struct snd_soc_dapm_widget *w; - - list_for_each_entry(w, &codec->dapm_widgets, list) { - if (!strcmp(w->name, pin)) { - pr_debug("dapm: %s: pin %s\n", codec->name, pin); - w->connected = status; - return 0; - } - } - - pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin); - return -EINVAL; -} - /** - * snd_soc_dapm_sync - scan and power dapm paths + * snd_soc_dapm_sync_endpoints - scan and power dapm paths * @codec: audio codec * * Walks all dapm audio paths and powers widgets according to their @@ -908,16 +835,27 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, * * Returns 0 for success. */ -int snd_soc_dapm_sync(struct snd_soc_codec *codec) +int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec) { - int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(codec, "sync"); - return ret; + return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); } -EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); +EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints); -static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, - const char *sink, const char *control, const char *source) +/** + * snd_soc_dapm_connect_input - connect dapm widgets + * @codec: audio codec + * @sink: name of target widget + * @control: mixer control name + * @source: name of source name + * + * Connects 2 dapm widgets together via a named audio path. The sink is + * the widget receiving the audio signal, whilst the source is the sender + * of the audio signal. + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, + const char * control, const char *source) { struct snd_soc_dapm_path *path; struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; @@ -1019,63 +957,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, kfree(path); return ret; } - -/** - * snd_soc_dapm_connect_input - connect dapm widgets - * @codec: audio codec - * @sink: name of target widget - * @control: mixer control name - * @source: name of source name - * - * Connects 2 dapm widgets together via a named audio path. The sink is - * the widget receiving the audio signal, whilst the source is the sender - * of the audio signal. - * - * This function has been deprecated in favour of snd_soc_dapm_add_routes(). - * - * Returns 0 for success else error. - */ -int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, - const char *control, const char *source) -{ - return snd_soc_dapm_add_route(codec, sink, control, source); -} EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); -/** - * snd_soc_dapm_add_routes - Add routes between DAPM widgets - * @codec: codec - * @route: audio routes - * @num: number of routes - * - * Connects 2 dapm widgets together via a named audio path. The sink is - * the widget receiving the audio signal, whilst the source is the sender - * of the audio signal. - * - * Returns 0 for success else error. On error all resources can be freed - * with a call to snd_soc_card_free(). - */ -int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, - const struct snd_soc_dapm_route *route, int num) -{ - int i, ret; - - for (i = 0; i < num; i++) { - ret = snd_soc_dapm_add_route(codec, route->sink, - route->control, route->source); - if (ret < 0) { - printk(KERN_ERR "Failed to add route %s->%s\n", - route->source, - route->sink); - return ret; - } - route++; - } - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); - /** * snd_soc_dapm_new_widgets - add new dapm widgets * @codec: audio codec @@ -1350,33 +1233,6 @@ int snd_soc_dapm_new_control(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); -/** - * snd_soc_dapm_new_controls - create new dapm controls - * @codec: audio codec - * @widget: widget array - * @num: number of widgets - * - * Creates new DAPM controls based upon the templates. - * - * Returns 0 for success else error. - */ -int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, - const struct snd_soc_dapm_widget *widget, - int num) -{ - int i, ret; - - for (i = 0; i < num; i++) { - ret = snd_soc_dapm_new_control(codec, widget); - if (ret < 0) - return ret; - widget++; - } - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); - - /** * snd_soc_dapm_stream_event - send a stream event to the dapm core * @codec: audio codec @@ -1401,8 +1257,8 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, { if (!w->sname) continue; - pr_debug("widget %s\n %s stream %s event %d\n", - w->name, w->sname, stream, event); + dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname, + stream, event); if (strstr(w->sname, stream)) { switch(event) { case SND_SOC_DAPM_STREAM_START: @@ -1438,81 +1294,53 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); /** - * snd_soc_dapm_set_bias_level - set the bias level for the system + * snd_soc_dapm_device_event - send a device event to the dapm core * @socdev: audio device - * @level: level to configure + * @event: device event * - * Configure the bias (power) levels for the SoC audio device. + * Sends a device event to the dapm core. The core then makes any + * necessary machine or codec power changes.. * * Returns 0 for success else error. */ -int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, - enum snd_soc_bias_level level) +int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event) { struct snd_soc_codec *codec = socdev->codec; struct snd_soc_machine *machine = socdev->machine; - int ret = 0; - - if (machine->set_bias_level) - ret = machine->set_bias_level(machine, level); - if (ret == 0 && codec->set_bias_level) - ret = codec->set_bias_level(codec, level); - return ret; -} - -/** - * snd_soc_dapm_enable_pin - enable pin. - * @snd_soc_codec: SoC codec - * @pin: pin name - * - * Enables input/output pin and it's parents or children widgets iff there is - * a valid audio route and active audio stream. - * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to - * do any widget power switching. - */ -int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin) -{ - return snd_soc_dapm_set_pin(codec, pin, 1); -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); - -/** - * snd_soc_dapm_disable_pin - disable pin. - * @codec: SoC codec - * @pin: pin name - * - * Disables input/output pin and it's parents or children widgets. - * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to - * do any widget power switching. - */ -int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin) -{ - return snd_soc_dapm_set_pin(codec, pin, 0); + if (machine->dapm_event) + machine->dapm_event(machine, event); + if (codec->dapm_event) + codec->dapm_event(codec, event); + return 0; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); +EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event); /** - * snd_soc_dapm_get_pin_status - get audio pin status + * snd_soc_dapm_set_endpoint - set audio endpoint status * @codec: audio codec - * @pin: audio signal pin endpoint (or start point) + * @endpoint: audio signal endpoint (or start point) + * @status: point status * - * Get audio pin status - connected or disconnected. + * Set audio endpoint status - connected or disconnected. * - * Returns 1 for connected otherwise 0. + * Returns 0 for success else error. */ -int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin) +int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, + char *endpoint, int status) { struct snd_soc_dapm_widget *w; list_for_each_entry(w, &codec->dapm_widgets, list) { - if (!strcmp(w->name, pin)) - return w->connected; + if (!strcmp(w->name, endpoint)) { + w->connected = status; + return 0; + } } - return 0; + return -ENODEV; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); +EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint); /** * snd_soc_dapm_free - free dapm resources diff --git a/trunk/sound/sparc/Kconfig b/trunk/sound/sparc/Kconfig index d75deba5617d..079e22af074c 100644 --- a/trunk/sound/sparc/Kconfig +++ b/trunk/sound/sparc/Kconfig @@ -1,17 +1,11 @@ # ALSA Sparc drivers -menuconfig SND_SPARC - bool "Sparc sound devices" - depends on SPARC - default y - help - Support for sound devices specific to Sun SPARC architectures. - -if SND_SPARC +menu "ALSA Sparc devices" + depends on SND!=n && SPARC config SND_SUN_AMD7930 tristate "Sun AMD7930" - depends on SBUS + depends on SBUS && SND select SND_PCM help Say Y here to include support for AMD7930 sound device on Sun. @@ -21,6 +15,7 @@ config SND_SUN_AMD7930 config SND_SUN_CS4231 tristate "Sun CS4231" + depends on SND select SND_PCM help Say Y here to include support for CS4231 sound device on Sun. @@ -30,7 +25,7 @@ config SND_SUN_CS4231 config SND_SUN_DBRI tristate "Sun DBRI" - depends on SBUS + depends on SND && SBUS select SND_PCM help Say Y here to include support for DBRI sound device on Sun. @@ -38,4 +33,4 @@ config SND_SUN_DBRI To compile this driver as a module, choose M here: the module will be called snd-sun-dbri. -endif # SND_SPARC +endmenu diff --git a/trunk/sound/sparc/dbri.c b/trunk/sound/sparc/dbri.c index ee2e1b4f3551..3d00e0797b11 100644 --- a/trunk/sound/sparc/dbri.c +++ b/trunk/sound/sparc/dbri.c @@ -2490,7 +2490,7 @@ static void dbri_debug_read(struct snd_info_entry *entry, } #endif -static void __devinit snd_dbri_proc(struct snd_card *card) +void __devinit snd_dbri_proc(struct snd_card *card) { struct snd_dbri *dbri = card->private_data; struct snd_info_entry *entry; diff --git a/trunk/sound/spi/Kconfig b/trunk/sound/spi/Kconfig index e6485be2e6f7..0d08c29213c8 100644 --- a/trunk/sound/spi/Kconfig +++ b/trunk/sound/spi/Kconfig @@ -1,13 +1,7 @@ #SPI drivers -menuconfig SND_SPI - bool "SPI sound devices" - depends on SPI - default y - help - Support for sound devices connected via the SPI bus. - -if SND_SPI +menu "SPI devices" + depends on SND != n config SND_AT73C213 tristate "Atmel AT73C213 DAC driver" @@ -34,5 +28,4 @@ config SND_AT73C213_TARGET_BITRATE Set to 48000 Hz by default. -endif # SND_SPI - +endmenu diff --git a/trunk/sound/usb/Kconfig b/trunk/sound/usb/Kconfig index ffcdc8f4ef66..9351b8a765b9 100644 --- a/trunk/sound/usb/Kconfig +++ b/trunk/sound/usb/Kconfig @@ -1,16 +1,11 @@ # ALSA USB drivers -menuconfig SND_USB - bool "USB sound devices" - depends on USB - default y - help - Support for sound devices connected via the USB bus. - -if SND_USB && USB +menu "USB devices" + depends on SND!=n && USB!=n config SND_USB_AUDIO tristate "USB Audio/MIDI driver" + depends on SND && USB select SND_HWDEP select SND_RAWMIDI select SND_PCM @@ -23,7 +18,7 @@ config SND_USB_AUDIO config SND_USB_USX2Y tristate "Tascam US-122, US-224 and US-428 USB driver" - depends on X86 || PPC || ALPHA + depends on SND && USB && (X86 || PPC || ALPHA) select SND_HWDEP select SND_RAWMIDI select SND_PCM @@ -36,6 +31,7 @@ config SND_USB_USX2Y config SND_USB_CAIAQ tristate "Native Instruments USB audio devices" + depends on SND && USB select SND_HWDEP select SND_RAWMIDI select SND_PCM @@ -67,5 +63,5 @@ config SND_USB_CAIAQ_INPUT * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 -endif # SND_USB +endmenu diff --git a/trunk/sound/usb/caiaq/caiaq-audio.c b/trunk/sound/usb/caiaq/caiaq-audio.c index b3a603325835..24970a5c888f 100644 --- a/trunk/sound/usb/caiaq/caiaq-audio.c +++ b/trunk/sound/usb/caiaq/caiaq-audio.c @@ -637,7 +637,6 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO): dev->samplerates |= SNDRV_PCM_RATE_88200; dev->samplerates |= SNDRV_PCM_RATE_192000; break; diff --git a/trunk/sound/usb/caiaq/caiaq-device.c b/trunk/sound/usb/caiaq/caiaq-device.c index 83175083e50f..a972f77bd785 100644 --- a/trunk/sound/usb/caiaq/caiaq-device.c +++ b/trunk/sound/usb/caiaq/caiaq-device.c @@ -42,15 +42,14 @@ #endif MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.6"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," "{Native Instruments, Kore Controller}," "{Native Instruments, Kore Controller 2}," - "{Native Instruments, Audio Kontrol 1}," - "{Native Instruments, Audio 8 DJ}," - "{Native Instruments, Session I/O}}"); + "{Native Instruments, Audio Kontrol 1}" + "{Native Instruments, Audio 8 DJ}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -111,11 +110,6 @@ static struct usb_device_id snd_usb_id_table[] = { .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_AUDIO8DJ }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = USB_VID_NATIVEINSTRUMENTS, - .idProduct = USB_PID_SESSIONIO - }, { /* terminator */ } }; diff --git a/trunk/sound/usb/caiaq/caiaq-device.h b/trunk/sound/usb/caiaq/caiaq-device.h index f9fbdbae269d..96a491379c60 100644 --- a/trunk/sound/usb/caiaq/caiaq-device.h +++ b/trunk/sound/usb/caiaq/caiaq-device.h @@ -11,7 +11,6 @@ #define USB_PID_KORECONTROLLER2 0x4712 #define USB_PID_AK1 0x0815 #define USB_PID_AUDIO8DJ 0x1978 -#define USB_PID_SESSIONIO 0x1915 #define EP1_BUFSIZE 64 #define CAIAQ_USB_STR_LEN 0xff diff --git a/trunk/sound/usb/usbaudio.c b/trunk/sound/usb/usbaudio.c index b8cfb7c22768..410be4aff1ba 100644 --- a/trunk/sound/usb/usbaudio.c +++ b/trunk/sound/usb/usbaudio.c @@ -819,6 +819,10 @@ static const char *usb_error_string(int err) return "device disabled"; case -EHOSTUNREACH: return "device suspended"; +#ifndef CONFIG_USB_EHCI_SPLIT_ISO + case -ENOSYS: + return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub"; +#endif case -EINVAL: case -EAGAIN: case -EFBIG: diff --git a/trunk/sound/usb/usbquirks.h b/trunk/sound/usb/usbquirks.h index 9ea726c049c6..82a8d14c26af 100644 --- a/trunk/sound/usb/usbquirks.h +++ b/trunk/sound/usb/usbquirks.h @@ -210,11 +210,6 @@ YAMAHA_DEVICE(0x1042, NULL), YAMAHA_DEVICE(0x1043, NULL), YAMAHA_DEVICE(0x1044, NULL), YAMAHA_DEVICE(0x1045, NULL), -YAMAHA_INTERFACE(0x104e, 0, NULL), -YAMAHA_DEVICE(0x104f, NULL), -YAMAHA_DEVICE(0x1050, NULL), -YAMAHA_DEVICE(0x1051, NULL), -YAMAHA_DEVICE(0x1052, NULL), YAMAHA_DEVICE(0x2000, "DGP-7"), YAMAHA_DEVICE(0x2001, "DGP-5"), YAMAHA_DEVICE(0x2002, NULL), @@ -1384,39 +1379,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, -{ - /* Roland SonicCell */ - USB_DEVICE(0x0582, 0x00c2), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Roland", - .product_name = "SonicCell", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 0, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0001 - } - }, - { - .ifnum = -1 - } - } - } -}, - - /* Guillemot devices */ { /*