diff options
Diffstat (limited to 'drivers')
437 files changed, 36335 insertions, 11089 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 23a0579cd..874799bbe 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -7,12 +7,12 @@ # # Note 2! The CFLAGS definitions are now in the main makefile. -SUB_DIRS := block char net parport sound misc +SUB_DIRS := block char net parport sound misc media MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci sgi ide scsi sbus cdrom isdn pnp i2o \ ieee1394 macintosh video dio zorro fc4 \ usb nubus tc atm pcmcia i2c telephony \ - acpi mtd + acpi mtd input ifdef CONFIG_DIO SUB_DIRS += dio @@ -77,6 +77,15 @@ else endif endif +ifeq ($(CONFIG_INPUT),y) +SUB_DIRS += input +MOD_SUB_DIRS += input +else + ifeq ($(CONFIG_INPUT),m) + MOD_SUB_DIRS += input + endif +endif + ifeq ($(CONFIG_PHONE),y) SUB_DIRS += telephony MOD_SUB_DIRS += telephony diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile index 50171ce47..7ee1e3c99 100644 --- a/drivers/acorn/block/Makefile +++ b/drivers/acorn/block/Makefile @@ -9,6 +9,8 @@ # parent makefile. # +USE_STANDARD_AS_RULE := true + L_TARGET := acorn-block.a obj-y := diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index 5e90e6ba4..c1e7dc469 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -142,6 +142,7 @@ #include <asm/io.h> #include <asm/ioc.h> #include <asm/irq.h> +#include <asm/mach-types.h> #include <asm/pgtable.h> #include <asm/segment.h> #include <asm/uaccess.h> diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile index d102cc876..649804348 100644 --- a/drivers/acorn/char/Makefile +++ b/drivers/acorn/char/Makefile @@ -35,7 +35,12 @@ obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o # Do the i2c and rtc last -obj-y += $(obj-$(MACHINE)) i2c.o pcf8583.o +obj-y += $(obj-$(MACHINE)) + +# CL-PS7500 does not have these devices. +ifneq ($(CONFIG_ARCH_CLPS7500),y) +obj-y += i2c.o pcf8583.o +endif O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) diff --git a/drivers/acorn/scsi/Makefile b/drivers/acorn/scsi/Makefile index bde60136f..1d9bc6dd4 100644 --- a/drivers/acorn/scsi/Makefile +++ b/drivers/acorn/scsi/Makefile @@ -2,6 +2,8 @@ # Makefile for drivers/acorn/scsi # +USE_STANDARD_AS_RULE := true + L_TARGET := acorn-scsi.a obj-y := diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 749b0d3da..318e14f86 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -19,8 +19,8 @@ */ -#define DAC960_DriverVersion "2.4.7" -#define DAC960_DriverDate "1 August 2000" +#define DAC960_DriverVersion "2.4.8" +#define DAC960_DriverDate "19 August 2000" #include <linux/version.h> @@ -2206,7 +2206,6 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType) Controller->Bus = Bus; Controller->Device = Device; Controller->Function = Function; - sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); /* Map the Controller Register Window. */ @@ -3756,15 +3755,15 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller, { 0x008D, "M Rebuild Failed for Unknown Reasons" }, { 0x008E, "M Rebuild Failed due to New Physical Device" }, { 0x008F, "M Rebuild Failed due to Logical Drive Failure" }, - { 0x0090, "L Initialization Started" }, - { 0x0091, "L Initialization Completed" }, - { 0x0092, "L Initialization Cancelled" }, - { 0x0093, "L Initialization Failed" }, + { 0x0090, "M Initialization Started" }, + { 0x0091, "M Initialization Completed" }, + { 0x0092, "M Initialization Cancelled" }, + { 0x0093, "M Initialization Failed" }, { 0x0094, "L Found" }, { 0x0095, "L Gone" }, - { 0x0096, "L Expand Capacity Started" }, - { 0x0097, "L Expand Capacity Completed" }, - { 0x0098, "L Expand Capacity Failed" }, + { 0x0096, "M Expand Capacity Started" }, + { 0x0097, "M Expand Capacity Completed" }, + { 0x0098, "M Expand Capacity Failed" }, { 0x0099, "L Bad Block Found" }, { 0x009A, "L Size Changed" }, { 0x009B, "L Type Changed" }, @@ -3799,6 +3798,12 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller, { 0, "" } }; int EventListIndex = 0, EventCode; unsigned char EventType, *EventMessage; + if (Event->EventCode == 0x1C && + RequestSense->SenseKey == DAC960_SenseKey_VendorSpecific && + (RequestSense->AdditionalSenseCode == 0x80 || + RequestSense->AdditionalSenseCode == 0x81)) + Event->EventCode = ((RequestSense->AdditionalSenseCode - 0x80) << 8) | + RequestSense->AdditionalSenseCodeQualifier; while (true) { EventCode = EventList[EventListIndex].EventCode; @@ -3862,6 +3867,7 @@ static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller, RequestSense->CommandSpecificInformation[3]); break; case 'E': + if (Controller->SuppressEnclosureMessages) break; sprintf(MessageBuffer, EventMessage, Event->LogicalUnit); DAC960_Critical("Enclosure %d %s\n", Controller, Event->TargetID, MessageBuffer); @@ -4274,7 +4280,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) LogicalDeviceSize); else if (NewLogicalDeviceInfo->BackgroundInitializationInProgress) DAC960_V2_ReportProgress(Controller, - "BackgroundInitialization", + "Background Initialization", LogicalDeviceNumber, NewLogicalDeviceInfo ->BackgroundInitializationBlockNumber, @@ -4900,6 +4906,7 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File, DiskGeometry_T Geometry, *UserGeometry; DAC960_Controller_T *Controller; int PartitionNumber; + if (File == NULL) return -EINVAL; if (File->f_flags & O_NONBLOCK) return DAC960_UserIOCTL(Inode, File, Request, Argument); if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) @@ -5106,6 +5113,7 @@ static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File, ErrorCode = copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T)); if (ErrorCode != 0) goto Failure1; + if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && DCDB.Direction == DAC960_V1_DCDB_NoDataTransfer) || @@ -5434,6 +5442,7 @@ int DAC960_KernelIOCTL(unsigned int Request, void *Argument) if (CommandOpcode == DAC960_V1_DCDB) { DCDB = KernelCommand->DCDB; + if (DCDB->Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && DCDB->Direction == DAC960_V1_DCDB_NoDataTransfer) || (DataTransferLength > 0 && @@ -6246,6 +6255,8 @@ static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller, == DAC960_V2_NormalCompletion ? "Cancelled" : "Not Cancelled")); } + else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0) + Controller->SuppressEnclosureMessages = true; else DAC960_UserCritical("Illegal User Command: '%s'\n", Controller, UserCommand); DAC960_AcquireControllerLock(Controller, &ProcessorFlags); @@ -6425,6 +6436,7 @@ static void DAC960_CreateProcEntries(void) PROC_DirectoryEntry_T *ControllerProcEntry; PROC_DirectoryEntry_T *UserCommandProcEntry; if (Controller == NULL) continue; + sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); ControllerProcEntry = proc_mkdir(Controller->ControllerName, DAC960_ProcDirectoryEntry); create_proc_read_entry("initial_status", 0, ControllerProcEntry, diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index a7062899e..aa25a10ed 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -1911,26 +1911,6 @@ extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument); /* - Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. -*/ - -static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress) -{ - return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress); -} - - -/* - Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. -*/ - -static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress) -{ - return (void *) bus_to_virt(BusAddress); -} - - -/* DAC960_DriverVersion protects the private portion of this file. */ @@ -2317,6 +2297,7 @@ typedef struct DAC960_Controller boolean EphemeralProgressMessage; boolean DriveSpinUpMessageDisplayed; boolean MonitoringAlertMode; + boolean SuppressEnclosureMessages; Timer_T MonitoringTimer; GenericDiskInfo_T GenericDiskInfo; DAC960_Command_T *FreeCommands; @@ -2522,6 +2503,26 @@ void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller, /* + Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. +*/ + +static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress) +{ + return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress); +} + + +/* + Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. +*/ + +static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress) +{ + return (void *) bus_to_virt(BusAddress); +} + + +/* Define the DAC960 BA Series Controller Interface Register Offsets. */ diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 200fb446a..1200773c2 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -14,6 +14,10 @@ * an existing request * - elevator_dequeue_fn, called when a request is taken off the active list * + * 20082000 Dave Jones <davej@suse.de> : + * Removed tests for max-bomb-segments, which was breaking elvtune + * when run without -bN + * */ #include <linux/fs.h> @@ -147,7 +151,7 @@ int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg) output.queue_ID = elevator->queue_ID; output.read_latency = elevator->read_latency; output.write_latency = elevator->write_latency; - output.max_bomb_segments = elevator->max_bomb_segments; + output.max_bomb_segments = 0; if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t))) return -EFAULT; @@ -166,13 +170,9 @@ int blkelvset_ioctl(elevator_t * elevator, const blkelv_ioctl_arg_t * arg) return -EINVAL; if (input.write_latency < 0) return -EINVAL; - if (input.max_bomb_segments <= 0) - return -EINVAL; elevator->read_latency = input.read_latency; elevator->write_latency = input.write_latency; - elevator->max_bomb_segments = input.max_bomb_segments; - return 0; } diff --git a/drivers/block/linear.c b/drivers/block/linear.c index fcd5b8b06..855bc44dd 100644 --- a/drivers/block/linear.c +++ b/drivers/block/linear.c @@ -144,7 +144,7 @@ static int linear_make_request (mddev_t *mddev, if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset) { - printk ("linear_make_request: Block %ld out of bounds on dev %s size %d offset %d\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); + printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); return -1; } bh->b_rdev = tmp_dev->dev; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 5c1fda2c3..8a61d1e84 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -182,8 +182,8 @@ static int __blk_cleanup_queue(struct list_head *head) * Currently, its primary task it to free all the &struct request structures * that were allocated to the queue. * Caveat: - * Hopefully the low level driver will have finished any outstanding requests - * first... + * Hopefully the low level driver will have finished any outstanding + * requests first... **/ void blk_cleanup_queue(request_queue_t * q) { @@ -204,21 +204,23 @@ void blk_cleanup_queue(request_queue_t * q) * @active: A flag indication where the head of the queue is active. * * Description: - * The driver for a block device may choose to leave the currently active request - * on the request queue, removing it only when it has completed. The queue - * handling routines assume this by default and will not involved the head of the - * request queue in any merging or reordering of requests. + * The driver for a block device may choose to leave the currently active + * request on the request queue, removing it only when it has completed. + * The queue handling routines assume this by default for safety reasons + * and will not involve the head of the request queue in any merging or + * reordering of requests when the queue is unplugged (and thus may be + * working on this particular request). * - * If a driver removes requests from the queue before processing them, then it may - * indicate that it does so, there by allowing the head of the queue to be involved - * in merging and reordering. This is done be calling blk_queue_headactive() with an - * @active flag of %1. + * If a driver removes requests from the queue before processing them, then + * it may indicate that it does so, there by allowing the head of the queue + * to be involved in merging and reordering. This is done be calling + * blk_queue_headactive() with an @active flag of %0. * - * If a driver processes several requests at once, it must remove them (or at least all - * but one of them) from the request queue. + * If a driver processes several requests at once, it must remove them (or + * at least all but one of them) from the request queue. * - * When a queue is plugged (see blk_queue_pluggable()) the head will be assumed to - * be inactive. + * When a queue is plugged (see blk_queue_pluggable()) the head will be + * assumed to be inactive. **/ void blk_queue_headactive(request_queue_t * q, int active) @@ -236,9 +238,9 @@ void blk_queue_headactive(request_queue_t * q, int active) * is empty. This allows a number of requests to be added before any are * processed, thus providing an opportunity for these requests to be merged * or re-ordered. - * The default plugging function (generic_plug_device()) sets the "plugged" flag - * for the queue and adds a task the the $tq_disk task queue to unplug the - * queue and call the request function at a later time. + * The default plugging function (generic_plug_device()) sets the "plugged" + * flag for the queue and adds a task to the $tq_disk task queue to unplug + * the queue and call the request function at a later time. * * A device driver may provide an alternate plugging function by passing it to * blk_queue_pluggable(). This function should set the "plugged" flag if it @@ -259,15 +261,14 @@ void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug) * @mfn: the alternate make_request function * * Description: - * The normal way for &struct buffer_heads to be passes to a device driver it to - * collect into requests on a request queue, and allow the device driver to select - * requests off that queue when it is ready. This works well for many block devices. - * However some block devices (typically virtual devices such as md or lvm) do not benefit - * from the processes on the request queue, and are served best by having the requests passed - * directly to them. This can be achived by providing a function to blk_queue_make_request(). - * If this is done, then the rest of the &request_queue_t structure is unused (unless the alternate - * make_request function explicitly uses it). In particular, there is no need to call - * blk_init_queue() if blk_queue_make_request() has been called. + * The normal way for &struct buffer_heads to be passed to a device driver + * it to collect into requests on a request queue, and allow the device + * driver to select requests off that queue when it is ready. This works + * well for many block devices. However some block devices (typically + * virtual devices such as md or lvm) do not benefit from the processes on + * the request queue, and are served best by having the requests passed + * directly to them. This can be achieved by providing a function to + * blk_queue_make_request(). **/ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) @@ -390,32 +391,30 @@ static void blk_init_free_list(request_queue_t *q) * placed on the queue. * * Description: - * If a block device wishes to use the stand request handling procedures, - * which sorts requests and coalesces adjactent requests, then it must + * If a block device wishes to use the standard request handling procedures, + * which sorts requests and coalesces adjacent requests, then it must * call blk_init_queue(). The function @rfn will be called when there * are requests on the queue that need to be processed. If the device - * supports plugging, then @rfn may not be called immediately that requests + * supports plugging, then @rfn may not be called immediately when requests * are available on the queue, but may be called at some time later instead. + * Plugged queues are generally unplugged when a buffer belonging to one + * of the requests on the queue is needed, or due to memory pressure. * - * @rfn is not required, or even expected, to remove all requests off the queue, but - * only as many as it can handle at a time. If it does leave requests on the queue, - * it is responsible for arranging that the requests get dealt with eventually. + * @rfn is not required, or even expected, to remove all requests off the + * queue, but only as many as it can handle at a time. If it does leave + * requests on the queue, it is responsible for arranging that the requests + * get dealt with eventually. * - * A global spin lock $io_spin_lock must held while manipulating the requests - * on the request queue. + * A global spin lock $io_request_lock must be held while manipulating the + * requests on the request queue. * - * The request on the head of the queue is by default assumed to be potentially active, - * and it is not considered for re-ordering or merging. This behaviour can - * be changed with blk_queue_headactive(). + * The request on the head of the queue is by default assumed to be + * potentially active, and it is not considered for re-ordering or merging + * whenever the given queue is unplugged. This behaviour can be changed with + * blk_queue_headactive(). * * Note: - * blk_init_queue() does not need to be called if - * blk_queue_make_request() has been called to register an alternate - * request handler. Ofcourse, it may be called if the handler wants - * to still use the fields on &request_queue_t, but in a non-standard - * way. - * - * blk_init_queue() should be paired with a blk_cleanup-queue() call + * blk_init_queue() must be paired with a blk_cleanup-queue() call * when the block device is deactivated (such as at module unload). **/ static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); @@ -697,19 +696,7 @@ static int __make_request(request_queue_t * q, int rw, rw_ahead = 1; rw = READ; /* drop into READ */ case READ: - if (buffer_uptodate(bh)) /* Hmmph! Already have it */ - goto end_io; - kstat.pgpgin++; - break; - case WRITERAW: - rw = WRITE; - goto do_write; /* Skip the buffer refile */ case WRITE: - if (!test_and_clear_bit(BH_Dirty, &bh->b_state)) - goto end_io; /* Hmmph! Nothing to write */ - refile_buffer(bh); - do_write: - kstat.pgpgout++; break; default: BUG(); @@ -942,6 +929,30 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) set_bit(BH_Req, &bh->b_state); + switch(rw) { + case WRITE: + if (!atomic_set_buffer_clean(bh)) + /* Hmmph! Nothing to write */ + goto end_io; + __mark_buffer_clean(bh); + kstat.pgpgout++; + break; + + case READA: + case READ: + if (buffer_uptodate(bh)) + /* Hmmph! Already have it */ + goto end_io; + kstat.pgpgin++; + break; + default: + BUG(); + end_io: + bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); + continue; + + } + /* * First step, 'identity mapping' - RAID or LVM might * further remap this. @@ -1023,6 +1034,9 @@ int __init blk_dev_init(void) sizeof(struct request), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!request_cachep) + panic("Can't create request pool slab cache\n"); + for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) dev->queue = NULL; diff --git a/drivers/block/md.c b/drivers/block/md.c index d54669fc8..19b97d161 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -1520,22 +1520,22 @@ static int device_size_calculation (mddev_t * mddev) md_size[mdidx(mddev)] = sb->size * data_disks; readahead = MD_READAHEAD; - if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) - readahead = mddev->sb->chunk_size * 4 * data_disks; - if (readahead < data_disks * MAX_SECTORS*512*2) - readahead = data_disks * MAX_SECTORS*512*2; - else { + if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) { + readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; + if (readahead < data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2) + readahead = data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2; + } else { if (sb->level == -3) readahead = 0; } md_maxreadahead[mdidx(mddev)] = readahead; - printk(KERN_INFO "md%d: max total readahead window set to %dk\n", - mdidx(mddev), readahead/1024); + printk(KERN_INFO "md%d: max total readahead window set to %ldk\n", + mdidx(mddev), readahead*(PAGE_SIZE/1024)); printk(KERN_INFO - "md%d: %d data-disks, max readahead per data-disk: %dk\n", - mdidx(mddev), data_disks, readahead/data_disks/1024); + "md%d: %d data-disks, max readahead per data-disk: %ldk\n", + mdidx(mddev), data_disks, readahead/data_disks*(PAGE_SIZE/1024)); return 0; abort: return 1; @@ -3318,7 +3318,7 @@ recheck: /* * Tune reconstruction: */ - window = md_maxreadahead[mdidx(mddev)]/1024; + window = MAX_READAHEAD*(PAGE_SIZE/1024); printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window,max_blocks); atomic_set(&mddev->recovery_active, 0); diff --git a/drivers/block/raid0.c b/drivers/block/raid0.c index acbf07be4..09f3f8547 100644 --- a/drivers/block/raid0.c +++ b/drivers/block/raid0.c @@ -103,7 +103,7 @@ static int create_strip_zones (mddev_t *mddev) zone->nb_dev = c; zone->size = (smallest->size - current_offset) * c; - printk(" zone->nb_dev: %d, size: %d\n",zone->nb_dev,zone->size); + printk(" zone->nb_dev: %d, size: %ld\n",zone->nb_dev,zone->size); if (!conf->smallest || (zone->size < conf->smallest->size)) conf->smallest = zone; @@ -112,7 +112,7 @@ static int create_strip_zones (mddev_t *mddev) curr_zone_offset += zone->size; current_offset = smallest->size; - printk("current zone offset: %d\n", current_offset); + printk("current zone offset: %ld\n", current_offset); } printk("done.\n"); return 0; @@ -139,7 +139,7 @@ static int raid0_run (mddev_t *mddev) goto out_free_conf; printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]); - printk("raid0 : conf->smallest->size is %d blocks.\n", conf->smallest->size); + printk("raid0 : conf->smallest->size is %ld blocks.\n", conf->smallest->size); nb_zone = md_size[mdidx(mddev)]/conf->smallest->size + (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0); printk("raid0 : nb_zone is %ld.\n", nb_zone); diff --git a/drivers/block/raid1.c b/drivers/block/raid1.c index 4c364712a..b39c87e0e 100644 --- a/drivers/block/raid1.c +++ b/drivers/block/raid1.c @@ -564,28 +564,6 @@ static int raid1_make_request (mddev_t *mddev, int rw, if (rw == READA) rw = READ; - if (rw == WRITE) { - rw = WRITERAW; - /* - * we first clean the bh, then we start the IO, then - * when the IO has finished, we end_io the bh and - * mark it uptodate. This way we do not miss the - * case when the bh got dirty again during the IO. - * - * We do an important optimization here - if the - * buffer was not dirty and we are during resync or - * reconstruction, then we can skip writing it back - * to the master disk! (we still have to write it - * back to the other disks, because we are not sync - * yet.) - */ - if (atomic_set_buffer_clean(bh)) - __mark_buffer_clean(bh); - else { - bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); - return 0; - } - } r1_bh = raid1_alloc_r1bh (conf); spin_lock_irq(&conf->segment_lock); diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c index 5d575a7f5..cff836dc4 100644 --- a/drivers/block/raid5.c +++ b/drivers/block/raid5.c @@ -863,8 +863,7 @@ static void compute_parity(struct stripe_head *sh, int method) if (!sh->bh_copy[i]) sh->bh_copy[i] = raid5_alloc_buffer(sh, sh->size); raid5_build_block(sh, sh->bh_copy[i], i); - if (atomic_set_buffer_clean(sh->bh_new[i])) - atomic_set_buffer_dirty(sh->bh_copy[i]); + atomic_set_buffer_dirty(sh->bh_copy[i]); memcpy(sh->bh_copy[i]->b_data, sh->bh_new[i]->b_data, sh->size); } if (sh->bh_copy[pd_idx] == NULL) { @@ -995,28 +994,12 @@ static void complete_stripe(struct stripe_head *sh) } -static int is_stripe_allclean(struct stripe_head *sh, int disks) -{ - int i; - - return 0; - for (i = 0; i < disks; i++) { - if (sh->bh_new[i]) - if (test_bit(BH_Dirty, &sh->bh_new[i])) - return 0; - if (sh->bh_old[i]) - if (test_bit(BH_Dirty, &sh->bh_old[i])) - return 0; - } - return 1; -} - static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, struct stripe_head *sh, int nr_write, int * operational, int disks, int parity, int parity_failed, int nr_cache, int nr_cache_other, int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) { - int i, allclean; + int i; unsigned int block; struct buffer_head *bh; int method1 = INT_MAX, method2 = INT_MAX; @@ -1068,7 +1051,6 @@ static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, PRINTK("handle_stripe(), sector %lu, nr_write %d, method1 %d, method2 %d\n", sh->sector, nr_write, method1, method2); if (!method1 || !method2) { - allclean = is_stripe_allclean(sh, disks); sh->phase = PHASE_WRITE; compute_parity(sh, method1 <= method2 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); @@ -1087,24 +1069,11 @@ static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, PRINTK("writing spare %d\n", i); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->spare->dev; - generic_make_request(WRITERAW, bh); + generic_make_request(WRITE, bh); } else { -#if 0 atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[i].dev; - generic_make_request(WRITERAW, bh); -#else - if (!allclean || (i==sh->pd_idx)) { - PRINTK("writing dirty %d\n", i); - atomic_inc(&sh->nr_pending); - bh->b_dev = bh->b_rdev = conf->disks[i].dev; - generic_make_request(WRITERAW, bh); - } else { - PRINTK("not writing clean %d\n", i); - raid5_end_request(bh, 1); - sh->new[i] = 0; - } -#endif + generic_make_request(WRITE, bh); } atomic_dec(&bh->b_count); } @@ -1282,7 +1251,7 @@ static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, atomic_inc(&sh->nr_pending); lock_get_bh(bh); bh->b_dev = bh->b_rdev = conf->spare->dev; - generic_make_request(WRITERAW, bh); + generic_make_request(WRITE, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); atomic_dec(&bh->b_count); PRINTK("handle_stripe_sync() %lu, phase WRITE, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); @@ -1308,7 +1277,7 @@ static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, lock_get_bh(bh); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[pd_idx].dev; - generic_make_request(WRITERAW, bh); + generic_make_request(WRITE, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); atomic_dec(&bh->b_count); PRINTK("handle_stripe_sync() %lu phase WRITE, pending %d buffers\n", diff --git a/drivers/block/xor.c b/drivers/block/xor.c index 362ec6f8f..eb99582de 100644 --- a/drivers/block/xor.c +++ b/drivers/block/xor.c @@ -1175,7 +1175,7 @@ xor_block_VIS: wr %%g0, 0, %%fprs " : : "i" (&((struct buffer_head *)0)->b_data), - "i" (&((struct buffer_head *)0)->b_data), + "i" (&((struct buffer_head *)0)->b_size), "i" (FPRS_FEF|FPRS_DU), "i" (ASI_BLK_P), "i" (FPRS_FEF), "i" (VISenter)); } diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 08b50aaa1..7872a6f00 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -8,7 +8,7 @@ bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE fi -tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL +tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE if [ "$CONFIG_ARCH_ACORN" = "y" ]; then @@ -60,6 +60,15 @@ if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi fi +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'DC21285 serial port support' CONFIG_SERIAL_21285 + if [ "$CONFIG_SERIAL_21285" = "y" ]; then + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD + fi + bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE + fi +fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 @@ -124,8 +133,9 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT - tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD + tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then @@ -154,98 +164,7 @@ if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi -mainmenu_option next_comment -comment 'Video For Linux' - -tristate 'Video For Linux' CONFIG_VIDEO_DEV -if [ "$CONFIG_VIDEO_DEV" != "n" ]; then - bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS Y - dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C - comment 'Radio Adapters' - dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV - dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then - hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f - fi - dep_tristate ' AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then - hex ' RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c - fi - dep_tristate ' Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then - hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 - fi - dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then - hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c - fi - dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV - dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then - hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 - fi - dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then - hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590 - fi - dep_tristate ' Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_TRUST" = "y" ]; then - hex ' Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350 - fi - dep_tristate ' Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV - if [ "$CONFIG_PROC_FS" = "y" ]; then - if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then - bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS - fi - fi - if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then - hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316 - int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500 - fi - dep_tristate ' Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then - hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c - fi - comment 'Video Adapters' - if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT - fi - dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV - if [ "$CONFIG_ALL_PPC" = "y" ]; then - dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV - fi - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - fi - fi - dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV - if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then - if [ "CONFIG_PARPORT_1284" != "n" ]; then - dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT - fi - if [ "$CONFIG_USB" != "n" ]; then - dep_tristate ' CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB - fi - fi - dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C - dep_tristate ' SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_SGI" = "y" ]; then - dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI - fi - dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI - fi - dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI - dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN - dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C -fi - -endmenu - tristate 'Double Talk PC internal speech card support' CONFIG_DTLK - tristate 'Siemens R3964 line discipline' CONFIG_R3964 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM diff --git a/drivers/char/Makefile b/drivers/char/Makefile index a83719fb7..b7a71c0f5 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -36,12 +36,11 @@ obj-y += tty_io.o n_tty.o tty_ioctl.o mem.o raw.o pty.o misc.o random.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \ - misc.o pty.o random.o selection.o serial.o videodev.o \ - tty_io.o bttv-if.o cpia.o +export-objs := busmouse.o console.o keyboard.o sysrq.o \ + misc.o pty.o random.o selection.o serial.o \ + tty_io.o -list-multi := bttv.o -bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o +list-multi := KEYMAP =defkeymap.o KEYBD =pc_keyb.o @@ -65,11 +64,12 @@ ifeq ($(ARCH),m68k) endif ifeq ($(ARCH),arm) -# we actually need to be able to select various different keymaps -# and keyboards dependent on which actual machine we're going to -# run on. - KEYMAP = - KEYBD = + ifneq ($(CONFIG_PC_KEYMAP),y) + KEYMAP = + endif + ifneq ($(CONFIG_PC_KEYB),y) + KEYBD = + endif endif ifeq ($(ARCH),sh) @@ -142,12 +142,12 @@ obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o -ifeq ($(CONFIG_JOYSTICK),y) +ifeq ($(CONFIG_INPUT),y) obj-y += joystick/js.o SUB_DIRS += joystick MOD_SUB_DIRS += joystick else - ifeq ($(CONFIG_JOYSTICK),m) + ifeq ($(CONFIG_INPUT),m) MOD_SUB_DIRS += joystick endif endif @@ -175,44 +175,12 @@ ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif -obj-$(CONFIG_VIDEO_DEV) += videodev.o - obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_I810_TCO) += i810-tco.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o -obj-$(CONFIG_BUS_I2C) += i2c-old.o -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \ - tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o tuner.o -obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o - -obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o -obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o -obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o -obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o -obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o -obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o -obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o -obj-$(CONFIG_VIDEO_PMS) += pms.o -obj-$(CONFIG_VIDEO_PLANB) += planb.o -obj-$(CONFIG_VIDEO_VINO) += vino.o -obj-$(CONFIG_VIDEO_STRADIS) += stradis.o -obj-$(CONFIG_VIDEO_CPIA) += cpia.o -obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o -obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o -obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o -obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o -obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o -obj-$(CONFIG_RADIO_CADET) += radio-cadet.o -obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o -obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o -obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o -obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o -obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o -obj-$(CONFIG_RADIO_TRUST) += radio-trust.o -obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_QIC02_TAPE) += tpqic02.o ifeq ($(CONFIG_FTAPE),y) @@ -300,10 +268,3 @@ consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h defkeymap.c: defkeymap.map loadkeys --mktable defkeymap.map > defkeymap.c - -zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o - $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o - -bttv.o: $(bttv-objs) - $(LD) $(LD_RFLAG) -r -o $@ $(bttv-objs) - diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index af32ba284..acad5947a 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -154,8 +154,11 @@ struct agp_bridge_data { #ifndef PCI_DEVICE_ID_VIA_82C691_0 #define PCI_DEVICE_ID_VIA_82C691_0 0x0691 #endif -#ifndef PCI_DEVICE_ID_VIA_82C691_1 -#define PCI_DEVICE_ID_VIA_82C691_1 0x8691 +#ifndef PCI_DEVICE_ID_VIA_8371_0 +#define PCI_DEVICE_ID_VIA_8371_0 0x0391 +#endif +#ifndef PCI_DEVICE_ID_VIA_8363_0 +#define PCI_DEVICE_ID_VIA_8363_0 0x0305 #endif #ifndef PCI_DEVICE_ID_INTEL_810_0 #define PCI_DEVICE_ID_INTEL_810_0 0x7120 diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index e5fbba8b5..44bd3bfb4 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -67,14 +67,16 @@ static inline void flush_cache(void) { #if defined(__i386__) asm volatile ("wbinvd":::"memory"); -#elif defined(__alpha__) +#elif defined(__alpha__) || defined(__ia64__) /* ??? I wonder if we'll really need to flush caches, or if the core logic can manage to keep the system coherent. The ARM speaks only of using `cflush' to get things in memory in preparation for power failure. If we do need to call `cflush', we'll need a target page, - as we can only flush one page at a time. */ + as we can only flush one page at a time. + + Ditto for IA-64. --davidm 00/08/07 */ mb(); #else #error "Please define flush_cache." @@ -412,10 +414,9 @@ int agp_unbind_memory(agp_memory * curr) /* * Driver routines - start - * Currently this module supports the - * i810, 440lx, 440bx, 440gx, via vp3, via mvp3, - * amd irongate, ALi M1541 and generic support for the - * SiS chipsets. + * Currently this module supports the following chipsets: + * i810, 440lx, 440bx, 440gx, via vp3, via mvp3, via kx133, via kt133, + * amd irongate, ALi M1541, and generic support for the SiS chipsets. */ /* Generic Agp routines - Start */ @@ -637,7 +638,7 @@ static int agp_generic_create_gatt_table(void) } table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); - for (page = virt_to_page(table); page < virt_to_page(table_end); page++) + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) set_bit(PG_reserved, &page->flags); agp_bridge.gatt_table_real = (unsigned long *) table; @@ -647,7 +648,7 @@ static int agp_generic_create_gatt_table(void) CACHE_FLUSH(); if (agp_bridge.gatt_table == NULL) { - for (page = virt_to_page(table); page < virt_to_page(table_end); page++) + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) clear_bit(PG_reserved, &page->flags); free_pages((unsigned long) table, page_order); @@ -704,7 +705,7 @@ static int agp_generic_free_gatt_table(void) table = (char *) agp_bridge.gatt_table_real; table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); - for (page = virt_to_page(table); page < virt_to_page(table_end); page++) + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) clear_bit(PG_reserved, &page->flags); free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); @@ -976,6 +977,7 @@ static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start, agp_bridge.scratch_page); } + CACHE_FLUSH(); agp_bridge.tlb_flush(mem); return 0; } @@ -2127,12 +2129,6 @@ static struct { #endif /* CONFIG_AGP_SIS */ #ifdef CONFIG_AGP_VIA - { PCI_DEVICE_ID_VIA_8371_0, - PCI_VENDOR_ID_VIA, - VIA_APOLLO_SUPER, - "Via", - "Apollo Super", - via_generic_setup }, { PCI_DEVICE_ID_VIA_8501_0, PCI_VENDOR_ID_VIA, VIA_MVP4, @@ -2157,6 +2153,18 @@ static struct { "Via", "Apollo Pro", via_generic_setup }, + { PCI_DEVICE_ID_VIA_8371_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_KX133, + "Via", + "Apollo Pro KX133", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_8363_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_KT133, + "Via", + "Apollo Pro KT133", + via_generic_setup }, { 0, PCI_VENDOR_ID_VIA, VIA_GENERIC, diff --git a/drivers/char/drm/agpsupport.c b/drivers/char/drm/agpsupport.c index 7ed234e15..42a1bc2f6 100644 --- a/drivers/char/drm/agpsupport.c +++ b/drivers/char/drm/agpsupport.c @@ -309,7 +309,9 @@ drm_agp_head_t *drm_agp_init(void) #if LINUX_VERSION_CODE >= 0x020400 case VIA_MVP4: head->chipset = "VIA MVP4"; break; - case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super"; + case VIA_APOLLO_KX133: head->chipset = "VIA Apollo KX133"; + break; + case VIA_APOLLO_KT133: head->chipset = "VIA Apollo KT133"; break; #endif @@ -322,7 +324,7 @@ drm_agp_head_t *drm_agp_init(void) case ALI_M1541: head->chipset = "ALi M1541"; break; default: head->chipset = "Unknown"; break; } - DRM_INFO("AGP %d.%d on %s @ 0x%08lx %dMB\n", + DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n", head->agp_info.version.major, head->agp_info.version.minor, head->chipset, diff --git a/drivers/char/drm/auth.c b/drivers/char/drm/auth.c index 9f81c5391..4556bd966 100644 --- a/drivers/char/drm/auth.c +++ b/drivers/char/drm/auth.c @@ -126,12 +126,12 @@ int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd, if (priv->magic) { auth.magic = priv->magic; } else { - spin_lock(&lock); do { + spin_lock(&lock); if (!sequence) ++sequence; /* reserve 0 */ auth.magic = sequence++; + spin_unlock(&lock); } while (drm_find_file(dev, auth.magic)); - spin_unlock(&lock); priv->magic = auth.magic; drm_add_magic(dev, priv, auth.magic); } diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 0fa205717..e8ec9bdbc 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -328,6 +328,7 @@ typedef struct drm_freelist { int low_mark; /* Low water mark */ int high_mark; /* High water mark */ atomic_t wfh; /* If waiting for high mark */ + spinlock_t lock; } drm_freelist_t; typedef struct drm_buf_entry { @@ -450,6 +451,11 @@ typedef struct { extern drm_agp_func_t drm_agp; #endif +typedef struct drm_sigdata { + int context; + drm_hw_lock_t *lock; +} drm_sigdata_t; + typedef struct drm_device { const char *name; /* Simple driver name */ char *unique; /* Unique identifier: e.g., busid */ @@ -534,6 +540,8 @@ typedef struct drm_device { #endif unsigned long *ctx_bitmap; void *dev_private; + drm_sigdata_t sigdata; /* For block_all_signals */ + sigset_t sigmask; } drm_device_t; @@ -728,6 +736,7 @@ extern int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags); extern int drm_flush_block_and_flush(drm_device_t *dev, int context, drm_lock_flags_t flags); +extern int drm_notifier(void *priv); /* Context Bitmap support (ctxbitmap.c) */ extern int drm_ctxbitmap_init(drm_device_t *dev); diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c index d81685230..84c7f0644 100644 --- a/drivers/char/drm/ffb_drv.c +++ b/drivers/char/drm/ffb_drv.c @@ -1,4 +1,4 @@ -/* $Id: ffb_drv.c,v 1.5 2000/07/26 01:03:57 davem Exp $ +/* $Id: ffb_drv.c,v 1.6 2000/08/10 05:26:23 davem Exp $ * ffb_drv.c: Creator/Creator3D direct rendering driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -754,6 +754,7 @@ static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt) extern struct vm_operations_struct drm_vm_ops; extern struct vm_operations_struct drm_vm_shm_ops; +extern struct vm_operations_struct drm_vm_shm_lock_ops; static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) { @@ -766,7 +767,6 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", vma->vm_start, vma->vm_end, VM_OFFSET(vma)); - lock_kernel(); minor = MINOR(filp->f_dentry->d_inode->i_rdev); ffb_priv = NULL; for (i = 0; i < ffb_dev_table_size; i++) { @@ -774,15 +774,13 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) if (ffb_priv->miscdev.minor == minor) break; } - if (i >= ffb_dev_table_size) { - unlock_kernel(); + if (i >= ffb_dev_table_size) return -EINVAL; - } + /* We don't support/need dma mappings, so... */ - if (!VM_OFFSET(vma)) { - unlock_kernel(); + if (!VM_OFFSET(vma)) return -EINVAL; - } + for (i = 0; i < dev->map_count; i++) { unsigned long off; @@ -794,19 +792,16 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) break; } - if (i >= dev->map_count) { - unlock_kernel(); + if (i >= dev->map_count) return -EINVAL; - } + if (!map || - ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) { - unlock_kernel(); + ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) return -EPERM; - } - if (map->size != (vma->vm_end - vma->vm_start)) { - unlock_kernel(); + + if (map->size != (vma->vm_end - vma->vm_start)) return -EINVAL; - } + /* Set read-only attribute before mappings are created * so it works for fb/reg maps too. */ @@ -829,15 +824,19 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) if (io_remap_page_range(vma->vm_start, ffb_priv->card_phys_base + VM_OFFSET(vma), vma->vm_end - vma->vm_start, - vma->vm_page_prot, 0)) { - unlock_kernel(); + vma->vm_page_prot, 0)) return -EAGAIN; - } + vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock); - vma->vm_ops = &drm_vm_shm_ops; + if (map->flags & _DRM_CONTAINS_LOCK) + vma->vm_ops = &drm_vm_shm_lock_ops; + else { + vma->vm_ops = &drm_vm_shm_ops; + vma->vm_private_data = (void *) map; + } /* Don't let this area swap. Change when * DRM_KERNEL advisory is supported. @@ -845,10 +844,8 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_LOCKED; break; default: - unlock_kernel(); return -EINVAL; /* This should never happen. */ }; - unlock_kernel(); vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ diff --git a/drivers/char/drm/lists.c b/drivers/char/drm/lists.c index f62495aa2..5da7cc6c5 100644 --- a/drivers/char/drm/lists.c +++ b/drivers/char/drm/lists.c @@ -116,6 +116,7 @@ int drm_freelist_create(drm_freelist_t *bl, int count) bl->low_mark = 0; bl->high_mark = 0; atomic_set(&bl->wfh, 0); + bl->lock = SPIN_LOCK_UNLOCKED; ++bl->initialized; return 0; } @@ -130,8 +131,6 @@ int drm_freelist_destroy(drm_freelist_t *bl) int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) { - drm_buf_t *old, *prev; - int count = 0; drm_device_dma_t *dma = dev->dma; if (!dma) { @@ -152,15 +151,12 @@ int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) drm_histogram_compute(dev, buf); #endif buf->list = DRM_LIST_FREE; - do { - old = bl->next; - buf->next = old; - prev = cmpxchg(&bl->next, old, buf); - if (++count > DRM_LOOPING_LIMIT) { - DRM_ERROR("Looping\n"); - return 1; - } - } while (prev != old); + + spin_lock(&bl->lock); + buf->next = bl->next; + bl->next = buf; + spin_unlock(&bl->lock); + atomic_inc(&bl->count); if (atomic_read(&bl->count) > dma->buf_count) { DRM_ERROR("%d of %d buffers free after addition of %d\n", @@ -177,26 +173,21 @@ int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) static drm_buf_t *drm_freelist_try(drm_freelist_t *bl) { - drm_buf_t *old, *new, *prev; drm_buf_t *buf; - int count = 0; if (!bl) return NULL; /* Get buffer */ - do { - old = bl->next; - if (!old) return NULL; - new = bl->next->next; - prev = cmpxchg(&bl->next, old, new); - if (++count > DRM_LOOPING_LIMIT) { - DRM_ERROR("Looping\n"); - return NULL; - } - } while (prev != old); - atomic_dec(&bl->count); + spin_lock(&bl->lock); + if (!bl->next) { + spin_unlock(&bl->lock); + return NULL; + } + buf = bl->next; + bl->next = bl->next->next; + spin_unlock(&bl->lock); - buf = old; + atomic_dec(&bl->count); buf->next = NULL; buf->list = DRM_LIST_NONE; DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", diff --git a/drivers/char/drm/lock.c b/drivers/char/drm/lock.c index 550827278..33b2cc03f 100644 --- a/drivers/char/drm/lock.c +++ b/drivers/char/drm/lock.c @@ -223,3 +223,35 @@ int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd, drm_flush_unblock(dev, lock.context, lock.flags); return ret; } + +/* If we get here, it means that the process has called DRM_IOCTL_LOCK + without calling DRM_IOCTL_UNLOCK. + + If the lock is not held, then let the signal proceed as usual. + + If the lock is held, then set the contended flag and keep the signal + blocked. + + + Return 1 if the signal should be delivered normally. + Return 0 if the signal should be blocked. */ + +int drm_notifier(void *priv) +{ + drm_sigdata_t *s = (drm_sigdata_t *)priv; + unsigned int old, new, prev; + + + /* Allow signal delivery if lock isn't held */ + if (!_DRM_LOCK_IS_HELD(s->lock->lock) + || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1; + + /* Otherwise, set flag to force call to + drmUnlock */ + do { + old = s->lock->lock; + new = old | _DRM_LOCK_CONT; + prev = cmpxchg(&s->lock->lock, old, new); + } while (prev != old); + return 0; +} diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index d02c3b581..0df0906e5 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c @@ -765,7 +765,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->mAccess = init->mAccess; init_waitqueue_head(&dev_priv->flush_queue); init_waitqueue_head(&dev_priv->buf_queue); - dev_priv->WarpPipe = -1; + dev_priv->WarpPipe = 0xff000000; DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", dev_priv->chipset, dev_priv->warp_ucode_size, diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index fac882471..e0080e595 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c @@ -656,6 +656,14 @@ int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd, #endif if (!ret) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); if (lock.flags & _DRM_LOCK_READY) { /* Wait for space in DMA/FIFO */ } @@ -719,6 +727,6 @@ int r128_unlock(struct inode *inode, struct file *filp, unsigned int cmd, current->priority = DEF_PRIORITY; } #endif - + unblock_all_signals(); return 0; } diff --git a/drivers/char/drm/vm.c b/drivers/char/drm/vm.c index d295529ba..7c5a24bc9 100644 --- a/drivers/char/drm/vm.c +++ b/drivers/char/drm/vm.c @@ -250,7 +250,7 @@ int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) vma->vm_start, vma->vm_end, VM_OFFSET(vma)); /* Length must match exact page count */ - if ((length >> PAGE_SHIFT) != dma->page_count) { + if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { unlock_kernel(); return -EINVAL; } @@ -323,6 +323,9 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; } +#elif defined(__ia64__) + if (map->type != _DRM_AGP) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #endif vma->vm_flags |= VM_IO; /* not in core dump */ } diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index f0c76181b..8b8d0f123 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/uaccess.h> #include <asm/therm.h> diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 9bb1748ae..4639f34eb 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -395,11 +395,10 @@ efi_rtc_init(void) return 0; } -static int __exit +static void __exit efi_rtc_exit(void) { /* not yet used */ - return 0; } module_init(efi_rtc_init); diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 01eb20e92..6ceb5a152 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -12,7 +12,12 @@ * Version 0.1 -- December, 1998. Initial version. * Version 0.2 -- March, 1999. Some more routines. Bugfixes. Etc. * Version 0.5 -- August, 1999. Some more fixes. Reformat for Linus. - */ + * + * BitWizard is actively maintaining this file. We sometimes find + * that someone submitted changes to this file. We really appreciate + * your help, but please submit changes through us. We're doing our + * best to be responsive. -- REW + * */ #include <linux/tty.h> #include <linux/serial.h> @@ -80,10 +85,18 @@ static void my_hd (unsigned char *addr, int len) void gs_put_char(struct tty_struct * tty, unsigned char ch) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; DECL - /* func_enter (); */ + func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + + if (! (port->flags & ASYNC_INITIALIZED)) return; /* Take a lock on the serial tranmit buffer! */ LOCKIT; @@ -99,7 +112,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch) port->xmit_cnt++; /* Characters in buffer */ RELEASEIT; - /* func_exit ();*/ + func_exit (); } @@ -115,11 +128,17 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch) int gs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; int c, total = 0; int t; - /* func_enter (); */ + func_enter (); + + if (!tty) return 0; + + port = tty->driver; + + if (!port) return 0; if (! (port->flags & ASYNC_INITIALIZED)) return 0; @@ -170,7 +189,7 @@ int gs_write(struct tty_struct * tty, int from_user, port->flags |= GS_TX_INTEN; port->rd->enable_tx_interrupts (port); } - /* func_exit (); */ + func_exit (); return total; } #else @@ -309,11 +328,11 @@ int gs_write_room(struct tty_struct * tty) struct gs_port *port = tty->driver_data; int ret; - /* func_enter (); */ + func_enter (); ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; if (ret < 0) ret = 0; - /* func_exit (); */ + func_exit (); return ret; } @@ -361,7 +380,7 @@ static int gs_wait_tx_flushed (void * ptr, int timeout) if (!port || port->xmit_cnt < 0 || !port->xmit_buf) { gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n"); - func_exit(); + func_exit(); return -EINVAL; /* This is an error which we don't know how to handle. */ } @@ -399,7 +418,7 @@ static int gs_wait_tx_flushed (void * ptr, int timeout) gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies " "(%d chars).\n", jiffies_to_transmit, charsleft); - current->state = TASK_INTERRUPTIBLE; + set_current_state (TASK_INTERRUPTIBLE); schedule_timeout(jiffies_to_transmit); if (signal_pending (current)) { gs_dprintk (GS_DEBUG_FLUSH, "Signal pending. Bombing out: "); @@ -409,7 +428,7 @@ static int gs_wait_tx_flushed (void * ptr, int timeout) } gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); - current->state = TASK_RUNNING; + set_current_state (TASK_RUNNING); func_exit(); return rv; @@ -419,10 +438,17 @@ static int gs_wait_tx_flushed (void * ptr, int timeout) void gs_flush_buffer(struct tty_struct *tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; unsigned long flags; func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + /* XXX Would the write semaphore do? */ save_flags(flags); cli(); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; @@ -438,9 +464,16 @@ void gs_flush_buffer(struct tty_struct *tty) void gs_flush_chars(struct tty_struct * tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf) { func_exit (); @@ -456,9 +489,16 @@ void gs_flush_chars(struct tty_struct * tty) void gs_stop(struct tty_struct * tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + if (port->xmit_cnt && port->xmit_buf && (port->flags & GS_TX_INTEN) ) { @@ -471,7 +511,13 @@ void gs_stop(struct tty_struct * tty) void gs_start(struct tty_struct * tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; if (port->xmit_cnt && port->xmit_buf && @@ -486,7 +532,11 @@ void gs_start(struct tty_struct * tty) void gs_shutdown_port (struct gs_port *port) { long flags; + func_enter(); + + if (!port) return; + if (!(port->flags & ASYNC_INITIALIZED)) return; @@ -505,16 +555,20 @@ void gs_shutdown_port (struct gs_port *port) port->flags &= ~ASYNC_INITIALIZED; restore_flags (flags); + func_exit(); } void gs_hangup(struct tty_struct *tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); + if (!tty) return; + + port = tty->driver_data; tty = port->tty; if (!tty) return; @@ -534,8 +588,13 @@ void gs_do_softint(void *private_) struct gs_port *port = private_; struct tty_struct *tty; + func_enter (); + + if (!port) return; + tty = port->tty; - if(!tty) return; + + if (!tty) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && @@ -557,8 +616,13 @@ int block_til_ready(void *port_, struct file * filp) struct tty_struct *tty; func_enter (); + + if (!port) return 0; + tty = port->tty; + if (!tty) return 0; + gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n"); /* * If the device is in the middle of being closed, then block @@ -571,6 +635,7 @@ int block_til_ready(void *port_, struct file * filp) else return -ERESTARTSYS; } + gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); /* @@ -593,6 +658,7 @@ int block_til_ready(void *port_, struct file * filp) } gs_dprintk (GS_DEBUG_BTR, "after subtype\n"); + /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -606,6 +672,7 @@ int block_til_ready(void *port_, struct file * filp) } gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); + if (port->flags & ASYNC_CALLOUT_ACTIVE) { if (port->normal_termios.c_cflag & CLOCAL) do_clocal = 1; @@ -614,7 +681,6 @@ int block_til_ready(void *port_, struct file * filp) do_clocal = 1; } - gs_dprintk (GS_DEBUG_BTR, "after clocal check.\n"); /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -623,9 +689,9 @@ int block_til_ready(void *port_, struct file * filp) * exit, either normal or abnormal. */ retval = 0; - + add_wait_queue(&port->open_wait, &wait); - + gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); cli(); if (!tty_hung_up_p(filp)) @@ -635,7 +701,7 @@ int block_til_ready(void *port_, struct file * filp) while (1) { CD = port->rd->get_CD (port); gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state (TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) @@ -679,12 +745,11 @@ void gs_close(struct tty_struct * tty, struct file * filp) func_enter (); + if (!tty) return; + port = (struct gs_port *) tty->driver_data; - if(! port) { - func_exit(); - return; - } + if (!port) return; if (!port->tty) { /* This seems to happen when this is called from vhangup. */ @@ -693,6 +758,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) } save_flags(flags); cli(); + if (tty_hung_up_p(filp)) { restore_flags(flags); port->rd->hungup (port); @@ -761,7 +827,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) if (port->blocked_open) { if (port->close_delay) { - current->state = TASK_INTERRUPTIBLE; + set_current_state (TASK_INTERRUPTIBLE); schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); @@ -784,14 +850,19 @@ static unsigned int gs_baudrates[] = { void gs_set_termios (struct tty_struct * tty, struct termios * old_termios) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; int baudrate, tmp, rv; struct termios *tiosp; func_enter(); - tiosp = tty->termios; + if (!tty) return; + + port = tty->driver_data; + if (!port) return; + + tiosp = tty->termios; if (gs_debug & GS_DEBUG_TERMIOS) { gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); diff --git a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c new file mode 100644 index 000000000..fcd105d35 --- /dev/null +++ b/drivers/char/i810-tco.c @@ -0,0 +1,326 @@ +/* + * i810-tco 0.02: TCO timer driver for i810 chipsets + * + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. + * http://www.kernelconcepts.de + * + * 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. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de> + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i810/i815 chipsets + * based on softdog.c by Alan Cox <alan@redhat.com> + * + * The TCO timer is implemented in the 82801AA (82801AB) chip, + * see intel documentation from http://developer.intel.com, + * order number 290655-003 + * + * 20000710 Nils Faerber + * Initial Version 0.01 + * 20000728 Nils Faerber + * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include "i810-tco.h" + + +/* Just in case that the PCI vendor and device IDs are not yet defined */ +#ifndef PCI_DEVICE_ID_INTEL_82801AA_0 +#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 +#endif + +/* Default expire timeout */ +#define TIMER_MARGIN 50 /* steps of 0.6sec, 2<n<64. Default is 30 seconds */ + +static unsigned int ACPIBASE; + +static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */ + +MODULE_PARM (i810_margin, "i"); + +/* + * Timer active flag + */ + +static int timer_alive; +static int boot_status; + +/* + * Some i810 specific functions + */ + + +/* + * Start the timer countdown + */ +static int tco_timer_start (void) +{ + unsigned char val; + + val = inb (TCO1_CNT + 1); + val &= 0xf7; + outb (val, TCO1_CNT + 1); + val = inb (TCO1_CNT + 1); + if (val & 0x08) + return -1; + return 0; +} + +/* + * Stop the timer countdown + */ +static int tco_timer_stop (void) +{ + unsigned char val; + + val = inb (TCO1_CNT + 1); + val |= 0x08; + outb (val, TCO1_CNT + 1); + val = inb (TCO1_CNT + 1); + if ((val & 0x08) == 0) + return -1; + return 0; +} + +/* + * Set the timer reload value + */ +static int tco_timer_settimer (unsigned char tmrval) +{ + unsigned char val; + + /* from the specs: */ + /* "Values of 0h-3h are ignored and should not be attempted" */ + if (tmrval > 0x3f || tmrval < 0x03) + return -1; + + val = inb (TCO1_TMR); + val &= 0xc0; + val |= tmrval; + outb (val, TCO1_TMR); + val = inb (TCO1_TMR); + if ((val & 0x3f) != tmrval) + return -1; + + return 0; +} + +/* + * Reload (trigger) the timer + */ +static void tco_timer_reload (void) +{ + outb (0x01, TCO1_RLD); +} + +/* + * Read the current timer value + */ +static unsigned char tco_timer_read (void) +{ + return (inb (TCO1_RLD)); +} + + +/* + * Allow only one person to hold it open + */ + +static int i810tco_open (struct inode *inode, struct file *file) +{ + if (timer_alive) + return -EBUSY; + + /* + * Reload and activate timer + */ + tco_timer_reload (); + tco_timer_start (); + timer_alive = 1; + return 0; +} + +static int i810tco_release (struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + */ + tco_timer_stop (); + timer_alive = 0; + return 0; +} + +static ssize_t i810tco_write (struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if (len) { + tco_timer_reload (); + return 1; + } + return 0; +} + +static int i810tco_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + 0, + 0, + "i810 TCO timer" + }; + switch (cmd) { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + return put_user (tco_timer_read (), + (unsigned int *) (int) arg); + case WDIOC_GETBOOTSTATUS: + return put_user (boot_status, (int *) arg); + case WDIOC_KEEPALIVE: + tco_timer_reload (); + return 0; + } +} + +static struct pci_dev *i810tco_pci; + +static unsigned char i810tco_getdevice (void) +{ + u8 val1, val2; + u16 badr; + /* + * Find the PCI device which has vendor id 0x8086 + * and device ID 0x2410 + */ + i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801AA_0, NULL); + if (i810tco_pci) { + /* + * Find the ACPI base I/O address which is the base + * for the TCO registers (TCOBASE=ACPIBASE + 0x60) + * ACPIBASE is bits [15:7] from 0x40-0x43 + */ + pci_read_config_byte (i810tco_pci, 0x40, &val1); + pci_read_config_byte (i810tco_pci, 0x41, &val2); + badr = ((val2 << 1) | (val1 >> 7)) << 7; + ACPIBASE = badr; + /* Something's wrong here, ACPIBASE has to be set */ + if (badr == 0x0001 || badr == 0x0000) { + printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n"); + return 0; + } + /* + * Check chipset's NO_REBOOT bit + */ + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + val1 &= 0xfd; + pci_write_config_byte (i810tco_pci, 0xd4, val1); + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag\n"); + return 0; /* Cannot reset NO_REBOOT bit */ + } + } + /* Set the TCO_EN bit in SMI_EN register */ + val1 = inb (SMI_EN + 1); + val1 &= 0xdf; + outb (val1, SMI_EN + 1); + /* Clear out the (probably old) status */ + outb (0, TCO1_STS); + boot_status = (int) inb (TCO2_STS); + outb (3, TCO2_STS); + return 1; + } + return 0; +} + +static struct file_operations i810tco_fops = { + owner: THIS_MODULE, + write: i810tco_write, + ioctl: i810tco_ioctl, + open: i810tco_open, + release: i810tco_release, +}; + +static struct miscdevice i810tco_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &i810tco_fops +}; + +static int __init watchdog_init (void) +{ + if (!i810tco_getdevice () || i810tco_pci == NULL) + return -ENODEV; + if (!request_region (TCOBASE, 0x10, "i810 TCO")) { + printk (KERN_ERR + "i810 TCO timer: I/O address 0x%04x already in use\n", + TCOBASE); + return -EIO; + } + if (misc_register (&i810tco_miscdev) != 0) { + release_region (TCOBASE, 0x10); + printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n"); + return -EIO; + } + tco_timer_settimer ((unsigned char) i810_margin); + tco_timer_reload (); + + /* FIXME: no floating point math */ + printk (KERN_INFO + "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n", + (int) (i810_margin * 0.6), TCOBASE); + return 0; +} + +static void __exit watchdog_cleanup (void) +{ + u8 val; + + /* Reset the timer before we leave */ + tco_timer_reload (); + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_byte (i810tco_pci, 0xd4, &val); + val |= 0x02; + pci_write_config_byte (i810tco_pci, 0xd4, val); + release_region (TCOBASE, 0x10); + misc_deregister (&i810tco_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_cleanup); diff --git a/drivers/char/i810-tco.h b/drivers/char/i810-tco.h new file mode 100644 index 000000000..a078ae8f6 --- /dev/null +++ b/drivers/char/i810-tco.h @@ -0,0 +1,45 @@ +/* + * i810-tco 0.02: TCO timer driver for i810 chipsets + * + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. + * http://www.kernelconcepts.de + * + * 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. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de> + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i810 chipsets + * based on softdog.c by Alan Cox <alan@redhat.com> + * + * The TCO timer is implemented in the 82801AA (82801AB) chip, + * see intel documentation from http://developer.intel.com, + * order number 290655-003 + * + * For history see i810-tco.c + */ + + +/* + * Some address definitions for the i810 TCO + */ + +#define TCOBASE ACPIBASE + 0x60 /* TCO base address */ +#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ +#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */ +#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ +#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ +#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ +#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ +#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ +#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ + +#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */ diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in index b020f1728..e99afa949 100644 --- a/drivers/char/joystick/Config.in +++ b/drivers/char/joystick/Config.in @@ -5,50 +5,50 @@ mainmenu_option next_comment comment 'Joysticks' -tristate 'Joystick support' CONFIG_JOYSTICK +dep_mbool 'Joystick support' CONFIG_JOYSTICK $CONFIG_INPUT if [ "$CONFIG_JOYSTICK" != "n" ]; then - define_tristate CONFIG_INPUT_JOYDEV $CONFIG_JOYSTICK - comment 'Game port support' - dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_JOYSTICK - dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_JOYSTICK - dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_JOYSTICK + dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT + dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT + dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT comment 'Gameport joysticks' - dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_JOYSTICK - dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_JOYSTICK - dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_JOYSTICK - dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_JOYSTICK - dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_JOYSTICK - dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_JOYSTICK - dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_JOYSTICK - dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_JOYSTICK - dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_JOYSTICK + dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT + dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_INPUT + dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_INPUT + dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_INPUT + dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_INPUT + dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_INPUT + dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_INPUT + dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_INPUT + dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_INPUT comment 'Serial port support' - dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_JOYSTICK + dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_INPUT comment 'Serial port joysticks' - dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_JOYSTICK - dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_JOYSTICK - dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_JOYSTICK - dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_JOYSTICK - dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_JOYSTICK - if [ "$CONFIG_INPUT_IFORCE_232" != "n" ]; then - define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_232 - fi + dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_INPUT + dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT + dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT + dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT + dep_tristate ' I-Force/Serial controllers' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT + dep_tristate ' I-Force/USB controllers' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB - if [ "$CONFIG_PARPORT" != "n" ]; then comment 'Parallel port joysticks' - dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_JOYSTICK - dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_JOYSTICK - dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_JOYSTICK + if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_INPUT $CONFIG_PARPORT + dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_INPUT $CONFIG_PARPORT + dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_INPUT $CONFIG_PARPORT + else + comment ' Parport support is needed for parallel port joysticks' fi if [ "$CONFIG_AMIGA" = "y" ]; then comment 'System joysticks' - dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_JOYSTICK + dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_INPUT fi +else + comment 'Input core support is needed for joysticks' fi - + endmenu diff --git a/drivers/char/joystick/Makefile b/drivers/char/joystick/Makefile index ae6a42cb8..e8eadc870 100644 --- a/drivers/char/joystick/Makefile +++ b/drivers/char/joystick/Makefile @@ -19,6 +19,19 @@ O_OBJS := export-objs := serio.o gameport.o +# I-Force may need both USB and RS-232 + +ifeq ($(CONFIG_INPUT_IFORCE_232),m) + ifeq ($(CONFIG_INPUT_IFORCE_USB),y) + CONFIG_INPUT_IFORCE_USB := m + endif +endif +ifeq ($(CONFIG_INPUT_IFORCE_USB),m) + ifeq ($(CONFIG_INPUT_IFORCE_232),y) + CONFIG_INPUT_IFORCE_232 := m + endif +endif + # Object file lists. obj-y := @@ -38,7 +51,8 @@ obj-$(CONFIG_INPUT_WARRIOR) += warrior.o serio.o obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o serio.o obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o serio.o obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o serio.o -obj-$(CONFIG_INPUT_IFORCE_232) += serio.o +obj-$(CONFIG_INPUT_IFORCE_232) += iforce.o serio.o +obj-$(CONFIG_INPUT_IFORCE_USB) += iforce.o obj-$(CONFIG_INPUT_ANALOG) += analog.o gameport.o obj-$(CONFIG_INPUT_A3D) += a3d.o gameport.o diff --git a/drivers/char/joystick/amijoy.c b/drivers/char/joystick/amijoy.c index f17aeda24..452d173d7 100644 --- a/drivers/char/joystick/amijoy.c +++ b/drivers/char/joystick/amijoy.c @@ -1,5 +1,5 @@ /* - * $Id: amijoy.c,v 1.4 2000/05/29 10:39:54 vojtech Exp $ + * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -77,7 +77,7 @@ static int amijoy_open(struct input_dev *dev) return 0; if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) { - amijoy_used--; + (*used)--; printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq); return -EBUSY; } @@ -89,7 +89,7 @@ static void amijoy_close(struct input_dev *dev) { int *used = dev->private; - if (!--(*port->used)) + if (!--(*used)) free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); } @@ -112,13 +112,21 @@ static int __init amijoy_init(void) for (i = 0; i < 2; i++) if (amijoy[i]) { + if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2, + amijoy [Denise]")) { + if (i == 1 && amijoy[0]) { + input_unregister_device(amijoy_dev); + release_mem_region(CUSTOM_PHYSADDR+10, 2); + } + return -EBUSY; + } amijoy_dev[i].open = amijoy_open; amijoy_dev[i].close = amijoy_close; amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - for (j = 0; j < 2; j++) + for (j = 0; j < 2; j++) { amijoy_dev[i].absmin[ABS_X + j] = -1; amijoy_dev[i].absmax[ABS_X + j] = 1; } @@ -134,6 +142,7 @@ static int __init amijoy_init(void) input_register_device(amijoy_dev + i); printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i); } + return 0; } static void _exit amijoy_exit(void) @@ -141,8 +150,10 @@ static void _exit amijoy_exit(void) int i; for (i = 0; i < 2; i++) - if (amijoy[i]) + if (amijoy[i]) { input_unregister_device(amijoy_dev + i); + release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2); + } } module_init(amijoy_init); diff --git a/drivers/char/joystick/db9.c b/drivers/char/joystick/db9.c index f9edd0755..4277e7f3d 100644 --- a/drivers/char/joystick/db9.c +++ b/drivers/char/joystick/db9.c @@ -1,5 +1,5 @@ /* - * $Id: db9.c,v 1.5 2000/05/29 20:39:38 vojtech Exp $ + * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $ * * Copyright (c) 1999 Vojtech Pavlik * @@ -95,7 +95,7 @@ static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 }; -static short *db9_btn[DB9_MAX_PAD] = { db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, +static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn }; static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", @@ -113,36 +113,36 @@ static void db9_timer(unsigned long private) data = parport_read_data(port) >> 3; - input_report_abs(dev + 1, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev + 1, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev + 1, BTN_TRIGGER, ~data&DB9_FIRE1); + input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1); case DB9_MULTI_0802: data = parport_read_status(port) >> 3; - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_TRIGGER, data&DB9_FIRE1); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1); break; case DB9_MULTI_STICK: data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1); break; case DB9_MULTI2_STICK: data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1); - input_report_key(dev, BTN_THUMB, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1); + input_report_key(dev, BTN_THUMB, ~data & DB9_FIRE2); break; case DB9_GENESIS_PAD: @@ -150,16 +150,16 @@ static void db9_timer(unsigned long private) parport_write_control(port, DB9_NOSELECT); data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_B, ~data&DB9_FIRE1); - input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_B, ~data & DB9_FIRE1); + input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); data=parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_FIRE1); - input_report_key(dev, BTN_START, ~data&DB9_FIRE2); + input_report_key(dev, BTN_A, ~data & DB9_FIRE1); + input_report_key(dev, BTN_START, ~data & DB9_FIRE2); break; case DB9_GENESIS5_PAD: @@ -167,18 +167,18 @@ static void db9_timer(unsigned long private) parport_write_control(port, DB9_NOSELECT); data=parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_B, ~data&DB9_FIRE1); - input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_B, ~data & DB9_FIRE1); + input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); data=parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_FIRE1); - input_report_key(dev, BTN_X, ~data&DB9_FIRE2); - input_report_key(dev, BTN_Y, ~data&DB9_LEFT); - input_report_key(dev, BTN_START, ~data&DB9_RIGHT); + input_report_key(dev, BTN_A, ~data & DB9_FIRE1); + input_report_key(dev, BTN_X, ~data & DB9_FIRE2); + input_report_key(dev, BTN_Y, ~data & DB9_LEFT); + input_report_key(dev, BTN_START, ~data & DB9_RIGHT); break; case DB9_GENESIS6_PAD: @@ -187,17 +187,17 @@ static void db9_timer(unsigned long private) udelay(DB9_GENESIS6_DELAY); data=parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_B, ~data&DB9_FIRE1); - input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_B, ~data & DB9_FIRE1); + input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); udelay(DB9_GENESIS6_DELAY); data=parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_FIRE1); - input_report_key(dev, BTN_X, ~data&DB9_FIRE2); + input_report_key(dev, BTN_A, ~data & DB9_FIRE1); + input_report_key(dev, BTN_X, ~data & DB9_FIRE2); parport_write_control(port, DB9_NOSELECT); /* 2 */ udelay(DB9_GENESIS6_DELAY); @@ -207,10 +207,10 @@ static void db9_timer(unsigned long private) udelay(DB9_GENESIS6_DELAY); data=parport_read_data(port); - input_report_key(dev, BTN_Y, ~data&DB9_LEFT); - input_report_key(dev, BTN_Z, ~data&DB9_DOWN); - input_report_key(dev, BTN_MODE, ~data&DB9_UP); - input_report_key(dev, BTN_START, ~data&DB9_RIGHT); + input_report_key(dev, BTN_Y, ~data & DB9_LEFT); + input_report_key(dev, BTN_Z, ~data & DB9_DOWN); + input_report_key(dev, BTN_MODE, ~data & DB9_UP); + input_report_key(dev, BTN_START, ~data & DB9_RIGHT); parport_write_control(port, DB9_NORMAL); udelay(DB9_GENESIS6_DELAY); @@ -224,32 +224,32 @@ static void db9_timer(unsigned long private) parport_write_control(port, DB9_SATURN0); data = parport_read_data(port); - input_report_key(dev, BTN_Y, ~data&DB9_LEFT); - input_report_key(dev, BTN_Z, ~data&DB9_DOWN); - input_report_key(dev, BTN_TL,~data&DB9_UP); - input_report_key(dev, BTN_TR,~data&DB9_RIGHT); + input_report_key(dev, BTN_Y, ~data & DB9_LEFT); + input_report_key(dev, BTN_Z, ~data & DB9_DOWN); + input_report_key(dev, BTN_TL, ~data & DB9_UP); + input_report_key(dev, BTN_TR, ~data & DB9_RIGHT); parport_write_control(port, DB9_SATURN2); data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); parport_write_control(port, DB9_NORMAL); data = parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_LEFT); - input_report_key(dev, BTN_B, ~data&DB9_UP); - input_report_key(dev, BTN_C, ~data&DB9_DOWN); - input_report_key(dev, BTN_X, ~data&DB9_RIGHT); + input_report_key(dev, BTN_A, ~data & DB9_LEFT); + input_report_key(dev, BTN_B, ~data & DB9_UP); + input_report_key(dev, BTN_C, ~data & DB9_DOWN); + input_report_key(dev, BTN_X, ~data & DB9_RIGHT); break; case DB9_CD32_PAD: data=parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); parport_write_control(port, 0x0a); @@ -257,7 +257,7 @@ static void db9_timer(unsigned long private) data = parport_read_data(port); parport_write_control(port, 0x02); parport_write_control(port, 0x0a); - input_report_key(dev, db9_cd32_btn[i], ~data&DB9_FIRE2); + input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2); } parport_write_control(port, 0x00); diff --git a/drivers/char/joystick/gamecon.c b/drivers/char/joystick/gamecon.c index a92ef58a9..c1d37248f 100644 --- a/drivers/char/joystick/gamecon.c +++ b/drivers/char/joystick/gamecon.c @@ -1,5 +1,5 @@ /* - * $Id: gamecon.c,v 1.4 2000/05/29 21:08:45 vojtech Exp $ + * $Id: gamecon.c,v 1.5 2000/06/25 09:56:58 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -157,7 +157,7 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data) static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 }; static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 }; -static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_START, BTN_SELECT, BTN_X, BTN_Y, BTN_TL, BTN_TR }; +static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR }; /* * gc_nes_read_packet() reads a NES/SNES packet. @@ -515,7 +515,7 @@ static struct gc __init *gc_probe(int *config) case GC_N64: for (j = 0; j < 10; j++) - set_bit(gc_n64_btn[j], gc->dev[j].keybit); + set_bit(gc_n64_btn[j], gc->dev[i].keybit); for (j = 0; j < 2; j++) { set_bit(ABS_X + j, gc->dev[i].absbit); @@ -530,18 +530,15 @@ static struct gc __init *gc_probe(int *config) break; case GC_SNES: - for (j = 0; j < 8; j++) - set_bit(gc_snes_btn[j], gc->dev[j].keybit); - break; - + for (j = 4; j < 8; j++) + set_bit(gc_snes_btn[j], gc->dev[i].keybit); case GC_NES: for (j = 0; j < 4; j++) - set_bit(gc_snes_btn[j], gc->dev[j].keybit); + set_bit(gc_snes_btn[j], gc->dev[i].keybit); break; case GC_MULTI2: set_bit(BTN_THUMB, gc->dev[i].keybit); - case GC_MULTI: set_bit(BTN_TRIGGER, gc->dev[i].keybit); break; @@ -656,12 +653,13 @@ void __exit gc_exit(void) { int i, j; - for (i = 0; i < 3; i++) { - for (j = 0; j < 5; j++) - if (gc_base[i]->pads[0] & gc_status_bit[j]) - input_unregister_device(gc_base[i]->dev + j); - parport_unregister_device(gc_base[i]->pd); - } + for (i = 0; i < 3; i++) + if (gc_base[i]) { + for (j = 0; j < 5; j++) + if (gc_base[i]->pads[0] & gc_status_bit[j]) + input_unregister_device(gc_base[i]->dev + j); + parport_unregister_device(gc_base[i]->pd); + } } module_init(gc_init); diff --git a/drivers/usb/iforce.c b/drivers/char/joystick/iforce.c index d70bfd90e..acb0bfe5b 100644 --- a/drivers/usb/iforce.c +++ b/drivers/char/joystick/iforce.c @@ -107,6 +107,7 @@ static void iforce_process_packet(struct input_dev *dev, unsigned char id, int i } } +#ifdef IFORCE_USB static int iforce_open(struct input_dev *dev) { @@ -127,6 +128,8 @@ static void iforce_close(struct input_dev *dev) usb_unlink_urb(&iforce->irq); } +#endif + static void iforce_input_setup(struct iforce *iforce) { int i; @@ -156,8 +159,11 @@ static void iforce_input_setup(struct iforce *iforce) } iforce->dev.private = iforce; + +#ifdef IFORCE_USB iforce->dev.open = iforce_open; iforce->dev.close = iforce_close; +#endif input_register_device(&iforce->dev); } diff --git a/drivers/char/joystick/ns558.c b/drivers/char/joystick/ns558.c index f34a18640..9ea833113 100644 --- a/drivers/char/joystick/ns558.c +++ b/drivers/char/joystick/ns558.c @@ -1,5 +1,5 @@ /* - * $Id: ns558.c,v 1.11 2000/06/20 23:35:03 vojtech Exp $ + * $Id: ns558.c,v 1.16 2000/08/17 20:03:56 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Brian Gerst @@ -138,7 +138,7 @@ static struct ns558* ns558_isa_probe(int io, struct ns558 *next) port->next = next; port->type = NS558_ISA; - port->gameport.io = io; + port->gameport.io = io & (-1 << i); port->gameport.size = (1 << i); request_region(port->gameport.io, port->gameport.size, "ns558-isa"); @@ -182,6 +182,7 @@ static int __devinit ns558_pci_probe(struct pci_dev *pdev, const struct pci_devi if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) { printk(KERN_ERR "Memory allocation failed.\n"); + release_region(ioport, iolen); return -ENOMEM; } memset(port, 0, sizeof(struct ns558)); @@ -208,6 +209,7 @@ static void __devexit ns558_pci_remove(struct pci_dev *pdev) { struct ns558 *port = (struct ns558 *)pdev->driver_data; release_region(port->gameport.io, port->gameport.size); + kfree(port); } static struct pci_driver ns558_pci_driver = { @@ -216,10 +218,16 @@ static struct pci_driver ns558_pci_driver = { probe: ns558_pci_probe, remove: ns558_pci_remove, }; +#else +static struct pci_driver ns558_pci_driver; #endif /* CONFIG_PCI */ -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) +#define NSS558_ISAPNP +#endif + +#ifdef NSS558_ISAPNP /* * PnP IDs: * @@ -297,7 +305,7 @@ deactivate: int __init ns558_init(void) { int i = 0; -#ifdef CONFIG_ISAPNP +#ifdef NSS558_ISAPNP struct pci_dev *dev = NULL; struct pnp_devid *devid; #endif @@ -310,17 +318,10 @@ int __init ns558_init(void) ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558); /* - * Probe for PCI ports. - */ -#ifdef CONFIG_PCI - pci_register_driver(&ns558_pci_driver); -#endif - -/* * Probe for PnP ports. */ -#ifdef CONFIG_ISAPNP +#ifdef NSS558_ISAPNP for (devid = pnp_devids; devid->vendor; devid++) { while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) { ns558 = ns558_pnp_probe(dev, ns558); @@ -328,7 +329,14 @@ int __init ns558_init(void) } #endif - return -!ns558; +/* + * Probe for PCI ports. + */ + + if (!ns558 && pci_module_init(&ns558_pci_driver)) + return -ENODEV; + + return 0; } void __exit ns558_exit(void) @@ -339,7 +347,7 @@ void __exit ns558_exit(void) gameport_unregister_port(&port->gameport); switch (port->type) { -#ifdef CONFIG_ISAPNP +#ifdef NSS558_ISAPNP case NS558_PNP: if (port->dev->deactivate) port->dev->deactivate(port->dev); @@ -357,9 +365,7 @@ void __exit ns558_exit(void) port = port->next; } -#ifdef CONFIG_PCI pci_unregister_driver(&ns558_pci_driver); -#endif } module_init(ns558_init); diff --git a/drivers/char/joystick/sidewinder.c b/drivers/char/joystick/sidewinder.c index 861966b4e..85be9f8b1 100644 --- a/drivers/char/joystick/sidewinder.c +++ b/drivers/char/joystick/sidewinder.c @@ -1,5 +1,5 @@ /* - * $Id: sidewinder.c,v 1.14 2000/05/29 11:27:55 vojtech Exp $ + * $Id: sidewinder.c,v 1.16 2000/07/14 09:02:41 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -330,8 +330,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (sw_parity(GB(i*15,15))) return -1; - input_report_key(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); - input_report_key(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); + input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); + input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); for (j = 0; j < 10; j++) input_report_key(dev, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); diff --git a/drivers/char/joystick/spaceball.c b/drivers/char/joystick/spaceball.c index 4f5059330..8e2936f73 100644 --- a/drivers/char/joystick/spaceball.c +++ b/drivers/char/joystick/spaceball.c @@ -1,5 +1,5 @@ /* - * $Id: spaceball.c,v 1.6 2000/05/29 11:19:51 vojtech Exp $ + * $Id: spaceball.c,v 1.7 2000/06/24 11:55:40 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -46,7 +46,7 @@ */ #define JS_SBALL_MAX_LENGTH 128 -static int spaceball_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; +static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; /* @@ -70,10 +70,12 @@ static void spaceball_process_packet(struct spaceball* spaceball) { struct input_dev *dev = &spaceball->dev; unsigned char *data = spaceball->data; - int i, d; + int i; if (spaceball->idx < 2) return; + printk("%c %d\n", spaceball->data[0], spaceball->idx); + switch (spaceball->data[0]) { case '@': /* Reset packet */ @@ -84,17 +86,17 @@ static void spaceball_process_packet(struct spaceball* spaceball) break; case 'D': /* Ball data */ - if (spaceball->idx != 16) return; + if (spaceball->idx != 15) return; for (i = 0; i < 6; i++) { - d = ((data[2 * i + 3] << 8) | data[2 * i + 2]); - input_report_abs(dev, spaceball_axes[i], d - ((d & 0x8000) ? 0x10000 : 0)); + input_report_abs(dev, spaceball_axes[i], + (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2])); } break; case '.': /* Button data, part2 */ - if (spaceball->idx != 4) return; - input_report_key(dev, BTN_LEFT, data[2] & 1); - input_report_key(dev, BTN_RIGHT, data[2] & 2); + if (spaceball->idx != 3) return; + input_report_key(dev, BTN_0, data[2] & 1); + input_report_key(dev, BTN_1, data[2] & 2); break; case '?': /* Error packet */ @@ -118,22 +120,27 @@ static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigne switch (data) { case 0xd: - if (spaceball->idx) - spaceball_process_packet(spaceball); + spaceball_process_packet(spaceball); spaceball->idx = 0; spaceball->escape = 0; return; + case '^': + if (!spaceball->escape) { + spaceball->escape ^= 1; + return; + } + spaceball->escape = 0; case 'M': case 'Q': case 'S': - if (spaceball->escape) + if (spaceball->escape) { + spaceball->escape = 0; data = 0xd; - case '^': - spaceball->escape ^= 1; + } default: if (spaceball->escape) { - printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x\n", data); spaceball->escape = 0; + printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data); } if (spaceball->idx < JS_SBALL_MAX_LENGTH) spaceball->data[spaceball->idx++] = data; @@ -172,15 +179,15 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) memset(spaceball, 0, sizeof(struct spaceball)); spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - spaceball->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); + spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1); for (i = 0; i < 6; i++) { t = spaceball_axes[i]; set_bit(t, spaceball->dev.absbit); - spaceball->dev.absmin[t] = i < 3 ? -10000 : -2000; - spaceball->dev.absmax[t] = i < 3 ? 10000 : 2000; - spaceball->dev.absflat[t] = i < 3 ? 50 : 10; - spaceball->dev.absfuzz[t] = i < 3 ? 12 : 2; + spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600; + spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600; + spaceball->dev.absflat[t] = i < 3 ? 40 : 8; + spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2; } spaceball->serio = serio; diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 8cf8a15a7..e99d92856 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -19,6 +19,8 @@ #include <asm/uaccess.h> #include <asm/irq.h> +#include <asm/mach-types.h> + #define __NWBUTTON_C /* Tell the header file who we are */ #include "nwbutton.h" diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index 5be07b769..8b5c266a6 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -18,6 +18,7 @@ #include <asm/dec21285.h> #include <asm/io.h> #include <asm/leds.h> +#include <asm/mach-types.h> #include <asm/system.h> #include <asm/uaccess.h> diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c index 757af9c14..7629e24ad 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -1,5 +1,5 @@ /* - * linux/drivers/char/pcxe.c + * linux/drivers/char/pcxx.c * * Written by Troy De Jongh, November, 1994 * @@ -12,13 +12,11 @@ * This driver does NOT support DigiBoard's fastcook FEP option and * does not support the transparent print (i.e. digiprint) option. * - * This Driver is currently maintained by Christoph Lameter (clameter@fuller.edu) - * Please contact the mailing list for problems first. + * This Driver is currently maintained by Christoph Lameter (christoph@lameter.com) * - * Sources of Information: - * 1. The Linux Digiboard Page at http://private.fuller.edu/clameter/digi.html - * 2. The Linux Digiboard Mailing list at digiboard@list.fuller.edu - * (Simply write a message to introduce yourself to subscribe) + * Please contact digi for support issues at digilnux@dgii.com. Some + * information (mostly of historical interest) can be found at + * http://lameter.com/digi. * * 1.5.2 Fall 1995 Bug fixes by David Nugent * 1.5.3 March 9, 1996 Christoph Lameter: Fixed 115.2K Support. Memory @@ -39,6 +37,8 @@ * verbose messages to assist user during card configuration. * Currently only tested on a PC/Xi card, but should work on Xe * and Xeve also. + * 1.6.2 August, 7, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * get rid of panics, release previously allocated resources * */ @@ -81,7 +81,7 @@ #include <asm/bitops.h> #include <asm/semaphore.h> -#define VERSION "1.6.1" +#define VERSION "1.6.2" #include "digi.h" #include "fep.h" @@ -193,6 +193,30 @@ static inline void assertmemoff(struct channel *ch); #define TZ_BUFSZ 4096 /* function definitions */ + +/*****************************************************************************/ + +static void cleanup_board_resources(void) +{ + int crd, i; + struct board_info *bd; + struct channel *ch; + + for(crd = 0; crd < numcards; crd++) { + bd = &boards[crd]; + ch = digi_channels + bd->first_minor; + + if (bd->region) + release_region(bd->port, 4); + + for(i = 0; i < bd->numports; i++, ch++) + if (ch->tmp_buf) + kfree(ch->tmp_buf); + } +} + +/*****************************************************************************/ + #ifdef MODULE /* @@ -209,10 +233,7 @@ void cleanup_module() { unsigned long flags; - int crd, i; int e1, e2; - struct board_info *bd; - struct channel *ch; printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION); @@ -226,14 +247,7 @@ void cleanup_module() if ((e2 = tty_unregister_driver(&pcxe_callout))) printk("SERIAL: failed to unregister callout driver (%d)\n",e2); - for(crd=0; crd < numcards; crd++) { - bd = &boards[crd]; - ch = digi_channels+bd->first_minor; - for(i=0; i < bd->numports; i++, ch++) { - kfree(ch->tmp_buf); - } - release_region(bd->port, 4); - } + cleanup_board_resources(); kfree(digi_channels); kfree(pcxe_termios_locked); kfree(pcxe_termios); @@ -620,7 +634,7 @@ static void pcxe_close(struct tty_struct * tty, struct file * filp) ** worth noting that while I'm not sure what this hunk of code is supposed ** to do, it is not present in the serial.c driver. Hmmm. If you know, ** please send me a note. brian@ilinx.com -** Don't know either what this is supposed to do clameter@waterf.org. +** Don't know either what this is supposed to do christoph@lameter.com. */ if(tty->ldisc.num != ldiscs[N_TTY].num) { if(tty->ldisc.close) @@ -1090,6 +1104,7 @@ int __init pcxe_init(void) { ulong memory_seg=0, memory_size=0; int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L; + int ret = -ENOMEM; unchar *fepos, *memaddr, *bios, v; volatile struct global_data *gd; volatile struct board_chan *bc; @@ -1099,7 +1114,7 @@ int __init pcxe_init(void) printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION); #ifdef MODULE - for (i = 0; i < 4; i++) { + for (i = 0; i < MAX_DIGI_BOARDS; i++) { if (io[i]) { numcards = 0; break; @@ -1108,7 +1123,7 @@ int __init pcxe_init(void) if (numcards == 0) { int first_minor = 0; - for (i = 0; i < 4; i++) { + for (i = 0; i < MAX_DIGI_BOARDS; i++) { if (io[i] == 0) { boards[i].port = 0; boards[i].status = DISABLED; @@ -1139,6 +1154,7 @@ int __init pcxe_init(void) else boards[i].numports = 16; + boards[i].region = NULL; first_minor += boards[i].numports; } } @@ -1178,23 +1194,31 @@ int __init pcxe_init(void) * unused spaces. */ digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL); - if (!digi_channels) - panic("Unable to allocate digi_channel struct"); + if (!digi_channels) { + printk(KERN_ERR "Unable to allocate digi_channel struct\n"); + return -ENOMEM; + } memset(digi_channels, 0, sizeof(struct channel) * nbdevs); pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL); - if (!pcxe_table) - panic("Unable to allocate pcxe_table struct"); + if (!pcxe_table) { + printk(KERN_ERR "Unable to allocate pcxe_table struct\n"); + goto cleanup_digi_channels; + } memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs); pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); - if (!pcxe_termios) - panic("Unable to allocate pcxe_termios struct"); + if (!pcxe_termios) { + printk(KERN_ERR "Unable to allocate pcxe_termios struct\n"); + goto cleanup_pcxe_table; + } memset(pcxe_termios,0,sizeof(struct termios *)*nbdevs); pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); - if (!pcxe_termios_locked) - panic("Unable to allocate pcxe_termios_locked struct"); + if (!pcxe_termios_locked) { + printk(KERN_ERR "Unable to allocate pcxe_termios_locked struct\n"); + goto cleanup_pcxe_termios; + } memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs); init_bh(DIGI_BH,do_pcxe_bh); @@ -1512,7 +1536,13 @@ load_fep: if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3)) shrinkmem = 1; - request_region(bd->port, 4, "PC/Xx"); + bd->region = request_region(bd->port, 4, "PC/Xx"); + + if (!bd->region) { + printk(KERN_ERR "I/O port 0x%x is already used\n", bd->port); + ret = -EBUSY; + goto cleanup_boards; + } for(i=0; i < bd->numports; i++, ch++, bc++) { if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) { @@ -1562,6 +1592,12 @@ load_fep: ch->txbufsize = bc->tmax + 1; ch->rxbufsize = bc->rmax + 1; ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); + + if (!ch->tmp_buf) { + printk(KERN_ERR "Unable to allocate memory for temp buffers\n"); + goto cleanup_boards; + } + lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2; fepcmd(ch, STXLWATER, lowwater, 0, 10, 0); fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0); @@ -1608,14 +1644,21 @@ load_fep: if (enabled_cards <= 0) { printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n"); - return -EIO; + ret = -EIO; + goto cleanup_boards; } - if(tty_register_driver(&pcxe_driver)) - panic("Couldn't register PC/Xe driver"); + ret = tty_register_driver(&pcxe_driver); + if(ret) { + printk(KERN_ERR "Couldn't register PC/Xe driver\n"); + goto cleanup_boards; + } - if(tty_register_driver(&pcxe_callout)) - panic("Couldn't register PC/Xe callout"); + ret = tty_register_driver(&pcxe_callout); + if(ret) { + printk(KERN_ERR "Couldn't register PC/Xe callout\n"); + goto cleanup_pcxe_driver; + } /* * Start up the poller to check for events on all enabled boards @@ -1626,6 +1669,13 @@ load_fep: printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards); return 0; +cleanup_pcxe_driver: tty_unregister_driver(&pcxe_driver); +cleanup_boards: cleanup_board_resources(); + kfree(pcxe_termios_locked); +cleanup_pcxe_termios: kfree(pcxe_termios); +cleanup_pcxe_table: kfree(pcxe_table); +cleanup_digi_channels: kfree(digi_channels); + return ret; } diff --git a/drivers/char/pcxx.h b/drivers/char/pcxx.h index 6d7a08b85..464fbe061 100644 --- a/drivers/char/pcxx.h +++ b/drivers/char/pcxx.h @@ -51,6 +51,7 @@ struct board_info { ulong membase; ulong memsize; ushort first_minor; + void *region; }; diff --git a/drivers/char/rio/linux_compat.h b/drivers/char/rio/linux_compat.h index 3b6d2f3b1..ca1649f1e 100644 --- a/drivers/char/rio/linux_compat.h +++ b/drivers/char/rio/linux_compat.h @@ -72,8 +72,6 @@ struct ttystatics { extern int rio_debug; -#define rio_dprint(f, p) do {if (rio_debug & f) printk p;} while (0) - #define RIO_DEBUG_INIT 0x000001 #define RIO_DEBUG_BOOT 0x000002 #define RIO_DEBUG_CMD 0x000004 @@ -92,7 +90,7 @@ extern int rio_debug; #define RIO_DEBUG_REC 0x008000 #define RIO_DEBUG_SPINLOCK 0x010000 #define RIO_DEBUG_DELAY 0x020000 - +#define RIO_DEBUG_MOD_COUNT 0x040000 /* Copied over from riowinif.h . This is ugly. The winif file declares also much other stuff which is incompatible with the headers from diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 01865a09d..93d1e1c46 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -249,6 +249,8 @@ long rio_irqmask = -1; #ifndef TWO_ZERO #ifdef MODULE +MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>"); +MODULE_DESCRIPTION("RIO driver"); MODULE_PARM(rio_poll, "i"); MODULE_PARM(rio_debug, "i"); MODULE_PARM(rio_irqmask, "i"); @@ -394,26 +396,37 @@ void rio_udelay (int usecs) void rio_inc_mod_count (void) { +#ifdef MODULE func_enter (); + rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_inc_mod_count\n"); MOD_INC_USE_COUNT; func_exit (); +#endif } void rio_dec_mod_count (void) { +#ifdef MODULE func_enter (); + rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_dec_mod_count\n"); MOD_DEC_USE_COUNT; func_exit (); +#endif } static int rio_set_real_termios (void *ptr) { - int rv; + int rv, modem; + struct tty_struct *tty; func_enter(); - rv = RIOParam( (struct Port *) ptr, CONFIG, 0, 1); + tty = ((struct Port *)ptr)->gs.tty; + + modem = (MAJOR(tty->device) == RIO_NORMAL_MAJOR0) || (MAJOR(tty->device) == RIO_NORMAL_MAJOR1); + + rv = RIOParam( (struct Port *) ptr, CONFIG, modem, 1); func_exit (); @@ -631,6 +644,7 @@ static void rio_shutdown_port (void * ptr) func_exit(); } + /* I haven't the foggiest why the decrement use count has to happen here. The whole linux serial drivers stuff needs to be redesigned. My guess is that this is a hack to minimize the impact of a bug @@ -641,7 +655,7 @@ static void rio_shutdown_port (void * ptr) static void rio_hungup (void *ptr) { func_enter (); - /* rio_dec_mod_count (); */ + rio_dec_mod_count (); func_exit (); } @@ -652,9 +666,22 @@ static void rio_hungup (void *ptr) */ static void rio_close (void *ptr) { + struct Port *PortP; + func_enter (); + + PortP = (struct Port *)ptr; + riotclose (ptr); + + if(PortP->gs.count) { + printk (KERN_ERR "WARNING port count:%d\n", PortP->gs.count); + PortP->gs.count = 0; + } + + rio_dec_mod_count (); + func_exit (); } @@ -974,13 +1001,12 @@ static int rio_init_datastructures (void) port->gs.close_delay = HZ/2; port->gs.closing_wait = 30 * HZ; port->gs.rd = &rio_real_driver; - + port->portSem = SPIN_LOCK_UNLOCKED; /* * Initializing wait queue */ init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); - + init_waitqueue_head(&port->gs.close_wait); } #else /* We could postpone initializing them to when they are configured. */ @@ -1010,7 +1036,7 @@ static int rio_init_datastructures (void) return -ENOMEM; } - +#ifdef MODULE static void rio_release_drivers(void) { func_enter(); @@ -1020,6 +1046,7 @@ static void rio_release_drivers(void) tty_unregister_driver (&rio_driver); func_exit(); } +#endif #ifdef TWO_ZERO #define PDEV unsigned char pci_bus, unsigned pci_fun @@ -1120,7 +1147,7 @@ int rio_init(void) while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) { - if (pci_enable_device(pdev)) continue; + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, @@ -1157,6 +1184,7 @@ int rio_init(void) hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; + hp->HostLock = SPIN_LOCK_UNLOCKED; rio_reset_interrupt (hp); rio_start_card_running (hp); @@ -1206,7 +1234,7 @@ int rio_init(void) while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) { - if (pci_enable_device(pdev)) continue; + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h index c8b72bdce..4242197e5 100644 --- a/drivers/char/rio/rio_linux.h +++ b/drivers/char/rio/rio_linux.h @@ -29,6 +29,8 @@ #define RIO_PORTSPERBOARD 128 #define RIO_NPORTS (RIO_NBOARDS * RIO_PORTSPERBOARD) +#define MODEM_SUPPORT + #ifdef __KERNEL__ #define RIO_MAGIC 0x12345678 @@ -85,31 +87,34 @@ struct vpd_prom { #endif +void rio_dec_mod_count (void); +void rio_inc_mod_count (void); + /* Allow us to debug "in the field" without requiring clients to recompile.... */ #if 1 #define rio_spin_lock_irqsave(sem, flags) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlockirqsave: %p %s:%d\n", \ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlockirqsave: %p %s:%d\n", \ + sem, __FILE__, __LINE__);\ spin_lock_irqsave(sem, flags);\ } while (0) #define rio_spin_unlock_irqrestore(sem, flags) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlockirqrestore: %p %s:%d\n",\ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlockirqrestore: %p %s:%d\n",\ + sem, __FILE__, __LINE__);\ spin_unlock_irqrestore(sem, flags);\ } while (0) #define rio_spin_lock(sem) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlock: %p %s:%d\n",\ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlock: %p %s:%d\n",\ + sem, __FILE__, __LINE__);\ spin_lock(sem);\ } while (0) #define rio_spin_unlock(sem) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlock: %p %s:%d\n",\ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlock: %p %s:%d\n",\ + sem, __FILE__, __LINE__);\ spin_unlock(sem);\ } while (0) #else @@ -173,7 +178,7 @@ static inline void *rio_memcpy_fromio (void *dest, void *source, int n) */ #ifdef DEBUG -#define rio_dprintk(f, str...) if (rio_debug & f) printk (str) +#define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0) #define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ "\n") #define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit " __FUNCTION__ "\n") #define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ \ diff --git a/drivers/char/rio/rioboot.c b/drivers/char/rio/rioboot.c index 8168f2133..d5ab5ba02 100644 --- a/drivers/char/rio/rioboot.c +++ b/drivers/char/rio/rioboot.c @@ -118,13 +118,13 @@ struct DownLoad * rbp; "copyin". (Crash when a pagefault occurs). */ /* disable(oldspl); */ - rio_dprint(RIO_DEBUG_BOOT, ("Data at user address 0x%x\n",(int)rbp->DataP)); + rio_dprintk (RIO_DEBUG_BOOT, "Data at user address 0x%x\n",(int)rbp->DataP); /* ** Check that we have set asside enough memory for this */ if ( rbp->Count > SIXTY_FOUR_K ) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code Too Large!\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n"); p->RIOError.Error = HOST_FILE_TOO_LARGE; /* restore(oldspl); */ func_exit (); @@ -132,7 +132,7 @@ struct DownLoad * rbp; } if ( p->RIOBooting ) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code : BUSY BUSY BUSY!\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n"); p->RIOError.Error = BOOT_IN_PROGRESS; /* restore(oldspl); */ func_exit (); @@ -160,7 +160,7 @@ struct DownLoad * rbp; if ( copyin((int)rbp->DataP,((caddr_t)(p->RIOBootPackets))+offset, rbp->Count) ==COPYFAIL ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bad data copy from user space\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bad data copy from user space\n"); p->RIOError.Error = COPYIN_FAILED; /* restore(oldspl); */ func_exit (); @@ -185,7 +185,7 @@ void rio_start_card_running (struct Host * HostP) switch ( HostP->Type ) { case RIO_AT: - rio_dprint(RIO_DEBUG_BOOT, ("Start ISA card running\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Start ISA card running\n"); WBYTE(HostP->Control, BOOT_FROM_RAM | EXTERNAL_BUS_ON | HostP->Mode @@ -198,7 +198,7 @@ void rio_start_card_running (struct Host * HostP) ** MCA handles IRQ vectors differently, so we don't write ** them to this register. */ - rio_dprint(RIO_DEBUG_BOOT, ("Start MCA card running\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Start MCA card running\n"); WBYTE(HostP->Control, McaTpBootFromRam | McaTpBusEnable | HostP->Mode); break; @@ -206,7 +206,7 @@ void rio_start_card_running (struct Host * HostP) /* ** EISA is totally different and expects OUTBZs to turn it on. */ - rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_DAEMON,"Start EISA card running\n"); + rio_dprintk (RIO_DEBUG_BOOT, "Start EISA card running\n"); OUTBZ( HostP->Slot, EISA_CONTROL_PORT, HostP->Mode | RIOEisaVec2Ctrl[HostP->Ivec] | EISA_TP_RUN | EISA_TP_BUS_ENABLE | EISA_TP_BOOT_FROM_RAM ); break; #endif @@ -217,11 +217,11 @@ void rio_start_card_running (struct Host * HostP) ** mapped, so we are writing to memory registers instead of io ** ports. */ - rio_dprint(RIO_DEBUG_BOOT, ("Start PCI card running\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Start PCI card running\n"); WBYTE(HostP->Control, PCITpBootFromRam | PCITpBusEnable | HostP->Mode); break; default: - rio_dprint(RIO_DEBUG_BOOT, ("Unknown host type %d\n",HostP->Type)); + rio_dprintk (RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type); break; } /* @@ -260,15 +260,15 @@ register struct DownLoad *rbp; HostP = NULL; /* Assure the compiler we've initialized it */ for ( host=0; host<p->RIONumHosts; host++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Attempt to boot host %d\n",host)); + rio_dprintk (RIO_DEBUG_BOOT, "Attempt to boot host %d\n",host); HostP = &p->RIOHosts[host]; - rio_dprint(RIO_DEBUG_BOOT, ("Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", - HostP->Type, HostP->Mode, HostP->Ivec ) ); + rio_dprintk (RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", + HostP->Type, HostP->Mode, HostP->Ivec); if ( (HostP->Flags & RUN_STATE) != RC_WAITING ) { - rio_dprint(RIO_DEBUG_BOOT, ("%s %d already running\n","Host",host)); + rio_dprintk (RIO_DEBUG_BOOT, "%s %d already running\n","Host",host); continue; } @@ -285,13 +285,13 @@ register struct DownLoad *rbp; */ StartP = (caddr_t)&Cad[p->RIOConf.HostLoadBase-rbp->Count]; - rio_dprint(RIO_DEBUG_BOOT, ("kernel virtual address for host is 0x%x\n", (int)Cad ) ); - rio_dprint(RIO_DEBUG_BOOT, ("kernel virtual address for download is 0x%x\n", (int)StartP ) ); - rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase)); - rio_dprint(RIO_DEBUG_BOOT, ("size of download is 0x%x\n", rbp->Count ) ); + rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for host is 0x%x\n", (int)Cad ); + rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for download is 0x%x\n", (int)StartP); + rio_dprintk (RIO_DEBUG_BOOT, "host loadbase is 0x%x\n",p->RIOConf.HostLoadBase); + rio_dprintk (RIO_DEBUG_BOOT, "size of download is 0x%x\n", rbp->Count); if ( p->RIOConf.HostLoadBase < rbp->Count ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bin too large\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bin too large\n"); p->RIOError.Error = HOST_FILE_TOO_LARGE; func_exit (); return EFBIG; @@ -307,7 +307,7 @@ register struct DownLoad *rbp; ** This ain't going to be none too clever if the download ** code is bigger than this segment. */ - rio_dprint(RIO_DEBUG_BOOT, ("Copy in code\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Copy in code\n"); /* ** PCI hostcard can't cope with 32 bit accesses and so need to copy @@ -318,7 +318,7 @@ register struct DownLoad *rbp; DownCode = sysbrk(rbp->Count); if ( !DownCode ) { - rio_dprint(RIO_DEBUG_BOOT, ("No system memory available\n")); + rio_dprintk (RIO_DEBUG_BOOT, "No system memory available\n"); p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY; func_exit (); return ENOMEM; @@ -326,7 +326,7 @@ register struct DownLoad *rbp; bzero(DownCode, rbp->Count); if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); p->RIOError.Error = COPYIN_FAILED; func_exit (); return EFAULT; @@ -337,13 +337,13 @@ register struct DownLoad *rbp; sysfree( DownCode, rbp->Count ); } else if ( copyin((int)rbp->DataP,StartP,rbp->Count)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); p->RIOError.Error = COPYIN_FAILED; func_exit (); return EFAULT; } - rio_dprint(RIO_DEBUG_BOOT, ("Copy completed\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Copy completed\n"); /* ** S T O P ! @@ -444,8 +444,8 @@ register struct DownLoad *rbp; WBYTE( DestP[6] , NFIX(0) ); WBYTE( DestP[7] , JUMP(8) ); - rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase)); - rio_dprint(RIO_DEBUG_BOOT, ("startup offset is 0x%x\n",offset)); + rio_dprintk (RIO_DEBUG_BOOT, "host loadbase is 0x%x\n",p->RIOConf.HostLoadBase); + rio_dprintk (RIO_DEBUG_BOOT, "startup offset is 0x%x\n",offset); /* ** Flag what is going on @@ -459,19 +459,19 @@ register struct DownLoad *rbp; */ OldParmMap = RWORD(HostP->__ParmMapR); - rio_dprint(RIO_DEBUG_BOOT, ("Original parmmap is 0x%x\n",OldParmMap)); + rio_dprintk (RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n",OldParmMap); /* ** And start it running (I hope). ** As there is nothing dodgy or obscure about the ** above code, this is guaranteed to work every time. */ - rio_dprint(RIO_DEBUG_BOOT, ("Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", - HostP->Type, HostP->Mode, HostP->Ivec ) ); + rio_dprintk (RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", + HostP->Type, HostP->Mode, HostP->Ivec); rio_start_card_running(HostP); - rio_dprint(RIO_DEBUG_BOOT, ("Set control port\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Set control port\n"); /* ** Now, wait for upto five seconds for the Tp to setup the parmmap @@ -479,7 +479,7 @@ register struct DownLoad *rbp; */ for ( wait_count=0; (wait_count<p->RIOConf.StartupTime)&& (RWORD(HostP->__ParmMapR)==OldParmMap); wait_count++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR))); + rio_dprintk (RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR)); delay(HostP, HUNDRED_MS); } @@ -489,8 +489,8 @@ register struct DownLoad *rbp; ** has crashed & burned in a really spectacular way */ if ( RWORD(HostP->__ParmMapR) == OldParmMap ) { - rio_dprint(RIO_DEBUG_BOOT, ("parmmap 0x%x\n", RWORD(HostP->__ParmMapR))); - rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail\n")); + rio_dprintk (RIO_DEBUG_BOOT, "parmmap 0x%x\n", RWORD(HostP->__ParmMapR)); + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n"); #define HOST_DISABLE \ HostP->Flags &= ~RUN_STATE; \ @@ -501,7 +501,7 @@ register struct DownLoad *rbp; HOST_DISABLE; } - rio_dprint(RIO_DEBUG_BOOT, ("Running 0x%x\n",RWORD(HostP->__ParmMapR))); + rio_dprintk (RIO_DEBUG_BOOT, "Running 0x%x\n", RWORD(HostP->__ParmMapR)); /* ** Well, the board thought it was OK, and setup its parmmap @@ -513,10 +513,10 @@ register struct DownLoad *rbp; ** Grab a 32 bit pointer to the parmmap structure */ ParmMapP = (PARM_MAP *)RIO_PTR(Cad,RWORD(HostP->__ParmMapR)); - rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP)); + rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)ParmMapP); ParmMapP = (PARM_MAP *)((unsigned long)Cad + (unsigned long)((RWORD((HostP->__ParmMapR))) & 0xFFFF)); - rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP)); + rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)ParmMapP); /* ** The links entry should be 0xFFFF; we set it up @@ -524,8 +524,8 @@ register struct DownLoad *rbp; ** which links to use. */ if ( (RWORD(ParmMapP->links) & 0xFFFF) != 0xFFFF ) { - rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name)); - rio_dprint(RIO_DEBUG_BOOT, ("Links = 0x%x\n",RWORD(ParmMapP->links))); + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); + rio_dprintk (RIO_DEBUG_BOOT, "Links = 0x%x\n",RWORD(ParmMapP->links)); HOST_DISABLE; } @@ -535,28 +535,28 @@ register struct DownLoad *rbp; ** now wait for the card to set all the parmmap->XXX stuff ** this is a wait of upto two seconds.... */ - rio_dprint(RIO_DEBUG_BOOT, ("Looking for init_done - %d ticks\n",p->RIOConf.StartupTime)); + rio_dprintk (RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n",p->RIOConf.StartupTime); HostP->timeout_id = 0; for ( wait_count=0; (wait_count<p->RIOConf.StartupTime) && !RWORD(ParmMapP->init_done); wait_count++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Waiting for init_done\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Waiting for init_done\n"); delay(HostP, HUNDRED_MS); } - rio_dprint(RIO_DEBUG_BOOT, ("OK! init_done!\n")); + rio_dprintk (RIO_DEBUG_BOOT, "OK! init_done!\n"); if (RWORD(ParmMapP->error) != E_NO_ERROR || !RWORD(ParmMapP->init_done) ) { - rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name)); - rio_dprint(RIO_DEBUG_BOOT, ("Timedout waiting for init_done\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); + rio_dprintk (RIO_DEBUG_BOOT, "Timedout waiting for init_done\n"); HOST_DISABLE; } - rio_dprint(RIO_DEBUG_BOOT, ("Got init_done\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Got init_done\n"); /* ** It runs! It runs! */ - rio_dprint(RIO_DEBUG_BOOT, ("Host ID %x Running\n",HostP->UniqueNum)); + rio_dprintk (RIO_DEBUG_BOOT, "Host ID %x Running\n",HostP->UniqueNum); /* ** set the time period between interrupts. @@ -580,12 +580,14 @@ register struct DownLoad *rbp; HostP->UnixRups[RupN].RupP = &HostP->RupP[RupN]; HostP->UnixRups[RupN].Id = RupN+1; HostP->UnixRups[RupN].BaseSysPort = NO_PORT; + HostP->UnixRups[RupN].RupLock = SPIN_LOCK_UNLOCKED; } for ( RupN = 0; RupN<LINKS_PER_UNIT; RupN++ ) { HostP->UnixRups[RupN+MAX_RUP].RupP = &HostP->LinkStrP[RupN].rup; HostP->UnixRups[RupN+MAX_RUP].Id = 0; HostP->UnixRups[RupN+MAX_RUP].BaseSysPort = NO_PORT; + HostP->UnixRups[RupN+MAX_RUP].RupLock = SPIN_LOCK_UNLOCKED; } /* @@ -622,7 +624,7 @@ register struct DownLoad *rbp; } } - rio_dprint(RIO_DEBUG_BOOT, ("Set the card running... \n")); + rio_dprintk (RIO_DEBUG_BOOT, "Set the card running... \n"); /* ** last thing - show the world that everything is in place */ @@ -638,7 +640,7 @@ register struct DownLoad *rbp; p->RIOSystemUp++; - rio_dprint(RIO_DEBUG_BOOT, ("Done everything %x\n", HostP->Ivec)); + rio_dprintk (RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec); func_exit (); return 0; } @@ -672,7 +674,7 @@ struct PKT *PacketP; ** If we haven't been told what to boot, we can't boot it. */ if ( p->RIONumBootPkts == 0 ) { - rio_dprint(RIO_DEBUG_BOOT, ("No RTA code to download yet\n")); + rio_dprintk (RIO_DEBUG_BOOT, "No RTA code to download yet\n"); return 0; } @@ -693,7 +695,7 @@ struct PKT *PacketP; ** try to unhook a command block from the command free list. */ if ( !(CmdBlkP = RIOGetCmdBlk()) ) { - rio_dprint(RIO_DEBUG_BOOT, ("No command blocks to boot RTA! come back later.\n")); + rio_dprintk (RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n"); return 0; } @@ -716,8 +718,8 @@ struct PKT *PacketP; ** We only expect one type of command - a BOOT_REQUEST! */ if ( RBYTE(PktCmdP->Command) != BOOT_REQUEST ) { - rio_dprint(RIO_DEBUG_BOOT, ("Unexpected command %d on BOOT RUP %d of host %d\n", - PktCmdP->Command,Rup,HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %d\n", + PktCmdP->Command,Rup,HostP-p->RIOHosts); ShowPacket( DBG_BOOT, PacketP ); RIOFreeCmdBlk( CmdBlkP ); return 1; @@ -754,9 +756,9 @@ struct PKT *PacketP; bcopy("BOOT",(void *)&CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN],4); - rio_dprint(RIO_DEBUG_BOOT, ("Boot RTA on Host %d Rup %d - %d (0x%x) packets to 0x%x\n", + rio_dprintk (RIO_DEBUG_BOOT, "Boot RTA on Host %d Rup %d - %d (0x%x) packets to 0x%x\n", HostP-p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, - p->RIOConf.RtaLoadBase)); + p->RIOConf.RtaLoadBase); /* ** If this host is in slave mode, send the RTA an invalid boot @@ -775,11 +777,11 @@ struct PKT *PacketP; */ sequence = RWORD(PktCmdP->Sequence); - rio_dprint(RIO_DEBUG_BOOT, ("Boot block %d on Host %d Rup%d\n",sequence,HostP-p->RIOHosts,Rup)); + rio_dprintk (RIO_DEBUG_BOOT, "Boot block %d on Host %d Rup%d\n",sequence,HostP-p->RIOHosts,Rup); if ( sequence >= p->RIONumBootPkts ) { - rio_dprint(RIO_DEBUG_BOOT, ("Got a request for packet %d, max is %d\n", sequence, - p->RIONumBootPkts)); + rio_dprintk (RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, + p->RIONumBootPkts); ShowPacket( DBG_BOOT, PacketP ); } @@ -821,26 +823,26 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk driver will never think that the RTA has booted... -- REW */ p->RIOBooting = 0; - rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot completed - BootInProgress now %d\n", p->RIOBooting)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting); /* ** Determine type of unit (16/8 port RTA). */ RtaType = GetUnitType(RtaUniq); if ( Rup >= (ushort)MAX_RUP ) { - rio_dprint(RIO_DEBUG_BOOT, ("RIO: Host %s has booted an RTA(%d) on link %c\n", - HostP->Name, 8 * RtaType, RBYTE(PktCmdP->LinkNum)+'A' )); + rio_dprintk (RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", + HostP->Name, 8 * RtaType, RBYTE(PktCmdP->LinkNum)+'A'); } else { - rio_dprint(RIO_DEBUG_BOOT, ("RIO: RTA %s has booted an RTA(%d) on link %c\n", + rio_dprintk (RIO_DEBUG_BOOT, "RIO: RTA %s has booted an RTA(%d) on link %c\n", HostP->Mapping[Rup].Name, 8 * RtaType, - RBYTE(PktCmdP->LinkNum)+'A')); + RBYTE(PktCmdP->LinkNum)+'A'); } - rio_dprint(RIO_DEBUG_BOOT, ("UniqNum is 0x%x\n",RtaUniq)); + rio_dprintk (RIO_DEBUG_BOOT, "UniqNum is 0x%x\n",RtaUniq); if ( ( RtaUniq == 0x00000000 ) || ( RtaUniq == 0xffffffff ) ) { - rio_dprint(RIO_DEBUG_BOOT, ( "Illegal RTA Uniq Number\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Illegal RTA Uniq Number\n"); return TRUE; } @@ -861,8 +863,8 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk */ if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink)) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA failed to suspend booting on link %c\n", - 'A' + MyLink)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA failed to suspend booting on link %c\n", + 'A' + MyLink); } } else @@ -874,8 +876,8 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk */ WWORD(HostP->LinkStrP[MyLink].WaitNoBoot, 30); } - rio_dprint(RIO_DEBUG_BOOT, ("RTA %x not owned - suspend booting down link %c on unit %x\n", - RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA %x not owned - suspend booting down link %c on unit %x\n", + RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum); return TRUE; } @@ -925,16 +927,16 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk } } if (RtaType == TYPE_RTA16) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given IDs %d+%d\n", - entry+1, entry2+1)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA will be given IDs %d+%d\n", + entry+1, entry2+1); } else { - rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given ID %d\n",entry+1)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA will be given ID %d\n",entry+1); } return TRUE; } } - rio_dprint(RIO_DEBUG_BOOT, ("RTA not configured for this host\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RTA not configured for this host\n"); if ( Rup >= (ushort)MAX_RUP ) { @@ -978,13 +980,13 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk entry2 = HostP->Mapping[entry].ID2 - 1; if ( (HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq) ) - rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slots (%d+%d)\n", - entry, entry2)); + rio_dprintk (RIO_DEBUG_BOOT, "Found previous tentative slots (%d+%d)\n", + entry, entry2); else continue; } else - rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slot (%d)\n",entry)); + rio_dprintk (RIO_DEBUG_BOOT, "Found previous tentative slot (%d)\n",entry); if (! p->RIONoMessage) cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A'); return TRUE; @@ -1013,7 +1015,7 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk ** + Configure RTA on host A. We now have the same RTA configured ** with different ports on two different hosts. */ - rio_dprint(RIO_DEBUG_BOOT, ("Have we seen RTA %x before?\n", RtaUniq )); + rio_dprintk (RIO_DEBUG_BOOT, "Have we seen RTA %x before?\n", RtaUniq ); found = 0; Flag = 0; /* Convince the compiler this variable is initialized */ for ( host = 0; !found && (host < p->RIONumHosts); host++ ) @@ -1029,12 +1031,12 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk if (RtaType == TYPE_RTA16) { MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1]; - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is units %d+%d from host %s\n", - rta+1, MapP->ID2, p->RIOHosts[host].Name )); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is units %d+%d from host %s\n", + rta+1, MapP->ID2, p->RIOHosts[host].Name); } else - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is unit %d from host %s\n", - rta+1, p->RIOHosts[host].Name )); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is unit %d from host %s\n", + rta+1, p->RIOHosts[host].Name); found = 1; break; } @@ -1052,12 +1054,12 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk */ if ( !MapP ) { - rio_dprint(RIO_DEBUG_BOOT, ("Look for RTA %x in RIOSavedTable\n",RtaUniq)); + rio_dprintk (RIO_DEBUG_BOOT, "Look for RTA %x in RIOSavedTable\n",RtaUniq); for ( rta=0; rta < TOTAL_MAP_ENTRIES; rta++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Check table entry %d (%x)", + rio_dprintk (RIO_DEBUG_BOOT, "Check table entry %d (%x)", rta, - p->RIOSavedTable[rta].RtaUniqueNum )); + p->RIOSavedTable[rta].RtaUniqueNum); if ( (p->RIOSavedTable[rta].Flags & SLOT_IN_USE) && (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq) ) @@ -1073,11 +1075,11 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk break; } MapP2 = &p->RIOSavedTable[entry2]; - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entries %d+%d\n", - rta, entry2)); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is from table entries %d+%d\n", + rta, entry2); } else - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entry %d\n", rta)); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is from table entry %d\n", rta); break; } } @@ -1133,8 +1135,8 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk { if (Flag & SLOT_IN_USE) { - rio_dprint(RIO_DEBUG_BOOT, ( - "This RTA configured on another host - move entry to current host (1)\n")); + rio_dprintk (RIO_DEBUG_BOOT, + "This RTA configured on another host - move entry to current host (1)\n"); HostP->Mapping[entry].SysPort = MapP->SysPort; CCOPY( MapP->Name, HostP->Mapping[entry].Name, MAX_NAME_LEN ); HostP->Mapping[entry].Flags = @@ -1147,12 +1149,12 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort; if ( HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted ) p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort; - rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n",(int)MapP->SysPort,MapP->Name)); + rio_dprintk (RIO_DEBUG_BOOT, "SysPort %d, Name %s\n",(int)MapP->SysPort,MapP->Name); } else { - rio_dprint(RIO_DEBUG_BOOT, ( - "This RTA has a tentative entry on another host - delete that entry (1)\n")); + rio_dprintk (RIO_DEBUG_BOOT, + "This RTA has a tentative entry on another host - delete that entry (1)\n"); HostP->Mapping[entry].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT; #if NEED_TO_FIX @@ -1177,9 +1179,9 @@ int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct Pk p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort; if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted) p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort; - rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n", + rio_dprintk (RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int)HostP->Mapping[entry2].SysPort, - HostP->Mapping[entry].Name)); + HostP->Mapping[entry].Name); } else HostP->Mapping[entry2].Flags = SLOT_TENTATIVE | @@ -1272,7 +1274,7 @@ struct Host *HostP; { int link; - rio_dprint(RIO_DEBUG_BOOT, ("FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq)); + rio_dprintk (RIO_DEBUG_BOOT, "FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq); HostP->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE); HostP->Mapping[entry].SysPort = NO_PORT; diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 835d815d3..3a330a07c 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -91,12 +91,12 @@ struct Map * MapP; { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA\n")); + rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -111,7 +111,7 @@ struct Map * MapP; CmdBlkP->Packet.data[3] = (IFOAD_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: Failed to queue foad command\n")); + rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA: Failed to queue foad command\n"); return EIO; } return 0; @@ -124,12 +124,12 @@ struct Map * MapP; { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA\n")); + rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -144,7 +144,7 @@ struct Map * MapP; CmdBlkP->Packet.data[3] = (ZOMBIE_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: Failed to queue zombie command\n")); + rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA: Failed to queue zombie command\n"); return EIO; } return 0; @@ -158,7 +158,7 @@ int (* func)( struct Host *HostP, struct Map *MapP ); { uint Host; - rio_dprint(RIO_DEBUG_CMD, ("Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func )); + rio_dprintk (RIO_DEBUG_CMD, "Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func); if ( !RtaUnique ) return(0); @@ -203,7 +203,7 @@ caddr_t arg; uint Host; if ( copyin( (int)arg, (caddr_t)&IdRta, sizeof(IdRta) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("RIO_IDENTIFY_RTA copy failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "RIO_IDENTIFY_RTA copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -231,12 +231,12 @@ caddr_t arg; */ struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA\n")); + rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -249,9 +249,8 @@ caddr_t arg; CmdBlkP->Packet.data[1] = 0; CmdBlkP->Packet.data[2] = IdRta.ID; - if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) - == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: Failed to queue command\n")); + if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { + rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA: Failed to queue command\n"); return EIO; } return 0; @@ -274,11 +273,10 @@ caddr_t arg; struct Host *HostP; struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("KILL HOST NEIGHBOUR\n")); + rio_dprintk (RIO_DEBUG_CMD, "KILL HOST NEIGHBOUR\n"); - if ( copyin( (int)arg, (caddr_t)&KillUnit, - sizeof(KillUnit) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("RIO_KILL_NEIGHBOUR copy failed\n")); + if ( copyin( (int)arg, (caddr_t)&KillUnit, sizeof(KillUnit) ) == COPYFAIL ) { + rio_dprintk (RIO_DEBUG_CMD, "RIO_KILL_NEIGHBOUR copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -289,7 +287,7 @@ caddr_t arg; CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("UFOAD: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "UFOAD: GetCmdBlk failed\n"); return ENXIO; } @@ -310,7 +308,7 @@ caddr_t arg; if ( HostP->UniqueNum == KillUnit.UniqueNum ) { if ( RIOQueueCmdBlk( HostP, RTAS_PER_HOST+KillUnit.Link, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n")); + rio_dprintk (RIO_DEBUG_CMD, "UFOAD: Failed queue command\n"); return EIO; } return 0; @@ -320,7 +318,7 @@ caddr_t arg; if ( HostP->Mapping[ID].RtaUniqueNum == KillUnit.UniqueNum ) { CmdBlkP->Packet.dest_unit = ID+1; if ( RIOQueueCmdBlk( HostP, ID, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n")); + rio_dprintk (RIO_DEBUG_CMD, "UFOAD: Failed queue command\n"); return EIO; } return 0; @@ -339,12 +337,12 @@ int Link; { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link)); + rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -359,7 +357,7 @@ int Link; CmdBlkP->Packet.data[3] = (IWAIT_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, ID - 1, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: Failed to queue iwait command\n")); + rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: Failed to queue iwait command\n"); return EIO; } return 0; @@ -416,6 +414,7 @@ PKT *PacketP; ushort subCommand; unsigned long flags; + func_enter (); #ifdef CHECK CheckHost( Host ); @@ -435,34 +434,35 @@ PKT *PacketP; UnixRupP = &HostP->UnixRups[rup]; SysPort = UnixRupP->BaseSysPort + (RBYTE(PktCmdP->PhbNum) % (ushort)PORTS_PER_RTA); - rio_dprint(RIO_DEBUG_CMD, ("Command on rup %d, port %d\n", rup, SysPort)); + rio_dprintk (RIO_DEBUG_CMD, "Command on rup %d, port %d\n", rup, SysPort); #ifdef CHECK CheckRup( rup ); CheckUnixRupP( UnixRupP ); #endif if ( UnixRupP->BaseSysPort == NO_PORT ) { - rio_dprint(RIO_DEBUG_CMD, ("OBSCURE ERROR!\n")); - rio_dprint(RIO_DEBUG_CMD, ("Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n")); - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Host number %d, name ``%s''\n", - HostP-p->RIOHosts, HostP->Name )); - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Rup number 0x%x\n", rup)); - - if ( Rup >= (ushort)MAX_RUP ) - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for RTA ``%s''\n", - HostP->Mapping[Rup].Name )); - else - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", 'A' + Rup - MAX_RUP, HostP->Name )); - - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Destination 0x%x:0x%x\n", - PacketP->dest_unit, PacketP->dest_port )); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Source 0x%x:0x%x\n", - PacketP->src_unit, PacketP->src_port )); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Length 0x%x (%d)\n", PacketP->len,PacketP->len )); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Control 0x%x (%d)\n", PacketP->control, PacketP->control)); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Check 0x%x (%d)\n", PacketP->csum, PacketP->csum )); - rio_dprint(RIO_DEBUG_CMD, ("COMMAND information: Host Port Number 0x%x, - Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command )); + rio_dprintk (RIO_DEBUG_CMD, "OBSCURE ERROR!\n"); + rio_dprintk (RIO_DEBUG_CMD, "Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n"); + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: Host number %d, name ``%s''\n", + HostP-p->RIOHosts, HostP->Name ); + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); + + if ( Rup >= (ushort)MAX_RUP ) { + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", + HostP->Mapping[Rup].Name); + } else + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", + ('A' + Rup - MAX_RUP), HostP->Name); + + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Destination 0x%x:0x%x\n", + PacketP->dest_unit, PacketP->dest_port ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Source 0x%x:0x%x\n", + PacketP->src_unit, PacketP->src_port ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Length 0x%x (%d)\n", PacketP->len,PacketP->len ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Control 0x%x (%d)\n", PacketP->control, PacketP->control); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Check 0x%x (%d)\n", PacketP->csum, PacketP->csum ); + rio_dprintk (RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, + Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command ); return TRUE; } @@ -470,13 +470,10 @@ PKT *PacketP; CheckSysPort( SysPort ); #endif PortP = p->RIOPortp[ SysPort ]; -#if 0 - ttyP = PortP->TtyP; -#endif rio_spin_lock_irqsave(&PortP->portSem, flags); switch( RBYTE(PktCmdP->Command) ) { case BREAK_RECEIVED: - rio_dprint(RIO_DEBUG_CMD, ("Received a break!\n")); + rio_dprintk (RIO_DEBUG_CMD, "Received a break!\n"); /* If the current line disc. is not multi-threading and the current processor is not the default, reset rup_intr and return FALSE to ensure that the command packet is @@ -486,16 +483,16 @@ PKT *PacketP; break; case COMPLETE: - rio_dprint(RIO_DEBUG_CMD, ("Command complete on phb %d host %d\n", - RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n", + RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts); subCommand = 1; switch (RBYTE(PktCmdP->SubCommand)) { case MEMDUMP : - rio_dprint(RIO_DEBUG_CMD, ("Memory dump cmd (0x%x) from addr 0x%x\n", - RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr))); + rio_dprintk (RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", + RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr)); break; case READ_REGISTER : - rio_dprint(RIO_DEBUG_CMD, ("Read register (0x%x)\n", RWORD(PktCmdP->SubAddr))); + rio_dprintk (RIO_DEBUG_CMD, "Read register (0x%x)\n", RWORD(PktCmdP->SubAddr)); p->CdRegister = (RBYTE(PktCmdP->ModemStatus) & MSVR1_HOST); break; default : @@ -504,18 +501,16 @@ PKT *PacketP; } if (subCommand) break; - rio_dprint(RIO_DEBUG_CMD, ("New status is 0x%x was 0x%x\n", - RBYTE(PktCmdP->PortStatus),PortP->PortState)); + rio_dprintk (RIO_DEBUG_CMD, "New status is 0x%x was 0x%x\n", + RBYTE(PktCmdP->PortStatus),PortP->PortState); if (PortP->PortState != RBYTE(PktCmdP->PortStatus)) { - rio_dprint(RIO_DEBUG_CMD, ("Mark status & wakeup\n")); + rio_dprintk (RIO_DEBUG_CMD, "Mark status & wakeup\n"); PortP->PortState = RBYTE(PktCmdP->PortStatus); /* What should we do here ... wakeup( &PortP->PortState ); */ - } - else { - rio_dprint(RIO_DEBUG_CMD, ("No change\n")); - } + } else + rio_dprintk (RIO_DEBUG_CMD, "No change\n"); /* FALLTHROUGH */ case MODEM_STATUS: @@ -527,7 +522,7 @@ PKT *PacketP; ReportedModemStatus = RBYTE(PktCmdP->ModemStatus); if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) { - rio_dprint(RIO_DEBUG_CMD, ("Modem status unchanged 0x%x\n", PortP->ModemState)); + rio_dprintk (RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState); /* ** Update ModemState just in case tbusy or tstop states have ** changed. @@ -535,8 +530,8 @@ PKT *PacketP; PortP->ModemState = ReportedModemStatus; } else { - rio_dprint(RIO_DEBUG_CMD, ("Modem status change from 0x%x to 0x%x\n", - PortP->ModemState, ReportedModemStatus)); + rio_dprintk (RIO_DEBUG_CMD, "Modem status change from 0x%x to 0x%x\n", + PortP->ModemState, ReportedModemStatus); PortP->ModemState = ReportedModemStatus; #ifdef MODEM_SUPPORT if ( PortP->Mapped ) { @@ -551,50 +546,41 @@ PKT *PacketP; ** If the device is a modem, then check the modem ** carrier. */ - if(!(ttyP->t_cflag & CLOCAL) && - ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) - { + if (PortP->gs.tty == NULL) + break; + + if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && + ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) { + + rio_dprintk (RIO_DEBUG_CMD, "Is there a Carrier?\n"); /* ** Is there a carrier? */ - if ( PortP->ModemState & MSVR1_CD ) - { + if ( PortP->ModemState & MSVR1_CD ) { /* ** Has carrier just appeared? */ - if (!(ttyP->t_state & CARR_ON)) - { - rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just came up.\n"); - ttyP->t_state |=CARR_ON; + if (!(PortP->State & RIO_CARR_ON)) { + rio_dprintk (RIO_DEBUG_CMD, "Carrier just came up.\n"); + PortP->State |= RIO_CARR_ON; /* ** wakeup anyone in WOPEN */ - if ( ttyP->t_state & (ISOPEN|WOPEN) ) - wakeup((caddr_t)&ttyP->t_canq); + if (PortP->State & (PORT_ISOPEN | RIO_WOPEN) ) + wake_up_interruptible (&PortP->gs.open_wait); #ifdef STATS PortP->Stat.ModemOnCnt++; #endif } - } - else - { + } else { /* ** Has carrier just dropped? */ - if (ttyP->t_state & CARR_ON) - { - /* - ** send SIGHUP to the process group - */ - if ( ttyP->t_state & (ISOPEN|WOPEN) ) - { - signal(ttyP->t_pgrp,SIGHUP); - ttyflush(ttyP,(FREAD|FWRITE)); - } - ttyP->t_state &= ~CARR_ON; - wakeup( (caddr_t)&PortP->TxBufferOut ); - wakeup( (caddr_t)&PortP->TxBufferIn ); - rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just went down.\n"); + if (PortP->State & RIO_CARR_ON) { + if (PortP->State & (PORT_ISOPEN|RIO_WOPEN|RIO_MOPEN)) + tty_hangup (PortP->gs.tty); + PortP->State &= ~RIO_CARR_ON; + rio_dprintk (RIO_DEBUG_CMD, "Carrirer just went down\n"); #ifdef STATS PortP->Stat.ModemOffCnt++; #endif @@ -607,11 +593,14 @@ PKT *PacketP; break; default: - rio_dprint(RIO_DEBUG_CMD, ("Unknown command %d on CMD_RUP of host %d\n", - RBYTE(PktCmdP->Command),HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %d\n", + RBYTE(PktCmdP->Command),HostP-p->RIOHosts); break; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); + + func_exit (); + return TRUE; } /* @@ -667,11 +656,8 @@ struct CmdBlk *CmdBlkP; CheckRup( Rup ); CheckCmdBlkP( CmdBlkP ); #endif - - rio_dprint(RIO_DEBUG_CMD, ("RIOQueueCmdBlk(Host, Rup %d, 0x%x)\n", Rup, (int)CmdBlkP )); - if ( Rup >= (ushort)(MAX_RUP+LINKS_PER_UNIT) ) { - rio_dprint(RIO_DEBUG_CMD, ("Illegal rup number %d in RIOQueueCmdBlk\n",Rup)); + rio_dprintk (RIO_DEBUG_CMD, "Illegal rup number %d in RIOQueueCmdBlk\n",Rup); RIOFreeCmdBlk( CmdBlkP ); return RIO_FAIL; } @@ -685,11 +671,12 @@ struct CmdBlk *CmdBlkP; ** straight on the RUP.... */ if ( (UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && - (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) && + (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE ) && (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg,CmdBlkP) :TRUE)) { - rio_dprint(RIO_DEBUG_CMD, ("RUP inactive-placing command straight on. Cmd byte is 0x%x\n", - CmdBlkP->Packet.data[0])); + rio_dprintk (RIO_DEBUG_CMD, "RUP inactive-placing command straight on. Cmd byte is 0x%x\n", + CmdBlkP->Packet.data[0]); + /* ** Whammy! blat that pack! @@ -711,28 +698,27 @@ struct CmdBlk *CmdBlkP; return RIO_SUCCESS; } - - rio_dprint(RIO_DEBUG_CMD, ("RUP active - en-queing\n")); + rio_dprintk (RIO_DEBUG_CMD, "RUP active - en-queing\n"); if ( UnixRupP->CmdsWaitingP != NULL) - rio_dprint(RIO_DEBUG_CMD, ("Rup active - command waiting\n")); + rio_dprintk (RIO_DEBUG_CMD, "Rup active - command waiting\n"); if ( UnixRupP->CmdPendingP != NULL ) - rio_dprint(RIO_DEBUG_CMD, ("Rup active - command pending\n")); + rio_dprintk (RIO_DEBUG_CMD, "Rup active - command pending\n"); if ( RWORD(UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE ) - rio_dprint(RIO_DEBUG_CMD, ("Rup active - command rup not ready\n")); + rio_dprintk (RIO_DEBUG_CMD, "Rup active - command rup not ready\n"); Base = &UnixRupP->CmdsWaitingP; - rio_dprint(RIO_DEBUG_CMD, ("First try to queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base)); + rio_dprintk (RIO_DEBUG_CMD, "First try to queue cmdblk 0x%x at 0x%x\n", (int)CmdBlkP,(int)Base); while ( *Base ) { - rio_dprint(RIO_DEBUG_CMD, ("Command cmdblk 0x%x here\n",(int)(*Base))); + rio_dprintk (RIO_DEBUG_CMD, "Command cmdblk 0x%x here\n", (int)(*Base)); Base = &((*Base)->NextP); - rio_dprint(RIO_DEBUG_CMD, ("Now try to queue cmd cmdblk 0x%x at 0x%x\n", - (int)CmdBlkP,(int)Base)); + rio_dprintk (RIO_DEBUG_CMD, "Now try to queue cmd cmdblk 0x%x at 0x%x\n", + (int)CmdBlkP,(int)Base); } - rio_dprint(RIO_DEBUG_CMD, ("Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base)); + rio_dprintk (RIO_DEBUG_CMD, "Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base); *Base = CmdBlkP; @@ -775,17 +761,15 @@ struct Host * HostP; if ( RWORD(UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE ) { int FreeMe; - /* rio_dprint(RIO_DEBUG_CMD, ("RIORupCmd( %d, %d )\n", HostP-p->RIOHosts, Rup )); */ - PacketP =(PKT *)RIO_PTR(HostP->Caddr,RWORD(UnixRupP->RupP->rxpkt)); ShowPacket( DBG_CMD, PacketP ); switch ( RBYTE(PacketP->dest_port) ) { case BOOT_RUP: - rio_dprint(RIO_DEBUG_CMD, ("Incoming Boot %s packet '%x'\n", + rio_dprintk (RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", RBYTE(PacketP->len) & 0x80 ? "Command":"Data", - RBYTE(PacketP->data[0]) )); + RBYTE(PacketP->data[0])); rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOBootRup(p, Rup,HostP,PacketP); rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); @@ -800,8 +784,8 @@ struct Host * HostP; rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOCommandRup(p, Rup,HostP,PacketP); if (PacketP->data[5] == MEMDUMP) { - rio_dprint(RIO_DEBUG_CMD, ("Memdump from 0x%x complete\n", - *(ushort *) &(PacketP->data[6]))); + rio_dprintk (RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", + *(ushort *) &(PacketP->data[6])); HostP->Copy( (caddr_t)&(PacketP->data[8]), (caddr_t)p->RIOMemDump, 32 ); } @@ -815,19 +799,19 @@ struct Host * HostP; break; default: - rio_dprint(RIO_DEBUG_CMD, ("Unknown RUP %d\n", RBYTE(PacketP->dest_port))); + rio_dprintk (RIO_DEBUG_CMD, "Unknown RUP %d\n", RBYTE(PacketP->dest_port)); FreeMe = 1; break; } if ( FreeMe ) { - rio_dprint(RIO_DEBUG_CMD, ("Free processed incoming command packet\n")); + rio_dprintk (RIO_DEBUG_CMD, "Free processed incoming command packet\n"); put_free_end(HostP,PacketP); WWORD(UnixRupP->RupP->rxcontrol , RX_RUP_INACTIVE); if ( RWORD(UnixRupP->RupP->handshake)==PHB_HANDSHAKE_SET ) { - rio_dprint(RIO_DEBUG_CMD, ("Handshake rup %d\n",Rup)); + rio_dprintk (RIO_DEBUG_CMD, "Handshake rup %d\n",Rup); WWORD(UnixRupP->RupP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } @@ -839,7 +823,7 @@ struct Host * HostP; ** and it has completed, then tidy it up. */ if ( (CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */ - (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) { + (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** we are idle. ** there is a command in pending. @@ -848,11 +832,11 @@ struct Host * HostP; ** what happened). */ if ( CmdBlkP->Packet.dest_port == BOOT_RUP ) - rio_dprint(RIO_DEBUG_CMD, ("Free Boot %s Command Block '%x'\n", + rio_dprintk (RIO_DEBUG_CMD, "Free Boot %s Command Block '%x'\n", CmdBlkP->Packet.len & 0x80 ? "Command":"Data", - CmdBlkP->Packet.data[0] )); + CmdBlkP->Packet.data[0]); - rio_dprint(RIO_DEBUG_CMD, ("Command 0x%x completed\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CMD, "Command 0x%x completed\n",(int)CmdBlkP); /* ** Clear the Rup lock to prevent mutual exclusion. @@ -880,27 +864,27 @@ struct Host * HostP; */ if ( (CmdBlkP = UnixRupP->CmdsWaitingP) && /* ASSIGN! */ (UnixRupP->CmdPendingP == NULL) && - (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) { + (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** if the pre-function is non-zero, call it. ** If it returns RIO_FAIL then don't ** send this command yet! */ #ifdef CHECK -CheckCmdBlkP( CmdBlkP ); + CheckCmdBlkP (CmdBlkP); #endif if ( !(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg, CmdBlkP) : TRUE)) { - rio_dprint(RIO_DEBUG_CMD, ("Not ready to start command 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CMD, "Not ready to start command 0x%x\n",(int)CmdBlkP); } else { - rio_dprint(RIO_DEBUG_CMD, ("Start new command 0x%x Cmd byte is 0x%x\n", - (int)CmdBlkP, CmdBlkP->Packet.data[0])); + rio_dprintk (RIO_DEBUG_CMD, "Start new command 0x%x Cmd byte is 0x%x\n", + (int)CmdBlkP, CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */ #ifdef CHECK -CheckPacketP( (PKT *)RIO_PTR(HostP->Caddr,UnixRupP->RupP->txpkt) ); + CheckPacketP ((PKT *)RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt)); #endif HostP->Copy( (caddr_t)&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(PKT)); @@ -1026,7 +1010,7 @@ struct CmdBlk *CmdBlkP; ** MAGIC! (Basically, handshake the RX buffer, so that ** the RTAs upstream can be re-enabled.) */ - rio_dprint(RIO_DEBUG_CMD, ("Util: Set RX handshake bit\n")); + rio_dprintk (RIO_DEBUG_CMD, "Util: Set RX handshake bit\n"); WWORD(PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -1046,7 +1030,7 @@ struct CmdBlk *CmdBlkP; #ifdef CHECK CheckPortP( PortP ); #endif - rio_dprint(RIO_DEBUG_CMD, ("Decrement in use count for port\n")); + rio_dprintk (RIO_DEBUG_CMD, "Decrement in use count for port\n"); if (PortP->InUse) { if ( --PortP->InUse != NOT_INUSE ) { diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index fa68646d5..af61dc997 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -137,7 +137,7 @@ int copyin (int arg, caddr_t dp, int siz) { int rv; - rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes from user %p to %p.\n", siz, (void *) arg, dp)); + rio_dprintk (RIO_DEBUG_CTRL, "Copying %d bytes from user %p to %p.\n", siz, (void *)arg, dp); rv = copy_from_user (dp, (void *)arg, siz); if (rv < 0) return COPYFAIL; else return rv; @@ -148,7 +148,7 @@ int copyout (caddr_t dp, int arg, int siz) { int rv; - rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes to user %p from %p.\n", siz, (void *) arg, dp)); + rio_dprintk (RIO_DEBUG_CTRL, "Copying %d bytes to user %p from %p.\n", siz, (void *)arg, dp); rv = copy_to_user ((void *)arg, dp, siz); if (rv < 0) return COPYFAIL; else return rv; @@ -207,7 +207,7 @@ int su; Host=0; PortP = NULL; - rio_dprint(RIO_DEBUG_CTRL, ("control ioctl cmd: 0x%x arg: 0x%x\n", cmd, (int)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "control ioctl cmd: 0x%x arg: 0x%x\n", cmd, (int)arg); switch (cmd) { /* @@ -218,7 +218,7 @@ int su; ** otherwise just the specified host card will be changed. */ case RIO_SET_TIMER: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_TIMER to %dms\n", (uint)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_TIMER to %dms\n", (uint)arg); { int host, value; host = (uint)arg >> 16; @@ -296,42 +296,42 @@ int su; */ case RIO_FOAD_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_FOAD_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_FOAD_RTA\n"); return RIOCommandRta(p, (uint)arg, RIOFoadRta); case RIO_ZOMBIE_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ZOMBIE_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ZOMBIE_RTA\n"); return RIOCommandRta(p, (uint)arg, RIOZombieRta); case RIO_IDENTIFY_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_IDENTIFY_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_IDENTIFY_RTA\n"); return RIOIdentifyRta(p, arg); case RIO_KILL_NEIGHBOUR: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_KILL_NEIGHBOUR\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_KILL_NEIGHBOUR\n"); return RIOKillNeighbour(p, arg); case SPECIAL_RUP_CMD: { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD\n")); + rio_dprintk (RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD\n"); if (copyin((int)arg, (caddr_t)&SpecialRupCmd, sizeof(SpecialRupCmd)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD GetCmdBlk failed\n"); return ENXIO; } CmdBlkP->Packet = SpecialRupCmd.Packet; if ( SpecialRupCmd.Host >= p->RIONumHosts ) SpecialRupCmd.Host = 0; - rio_dprint(RIO_DEBUG_CTRL, ("Queue special rup command for host %d rup %d\n", - SpecialRupCmd.Host, SpecialRupCmd.RupNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue special rup command for host %d rup %d\n", + SpecialRupCmd.Host, SpecialRupCmd.RupNum); if (RIOQueueCmdBlk(&p->RIOHosts[SpecialRupCmd.Host], SpecialRupCmd.RupNum, CmdBlkP) == RIO_FAIL) { cprintf("FAILED TO QUEUE SPECIAL RUP COMMAND\n"); @@ -348,7 +348,7 @@ RIO_DEBUG_CTRL, if (su) return EPERM; case RIO_ALL_MODEM: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ALL_MODEM\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ALL_MODEM\n"); p->RIOError.Error = IOCTL_COMMAND_UNKNOWN; return EINVAL; @@ -356,44 +356,44 @@ RIO_DEBUG_CTRL, if (su) /* ** Read the routing table from the device driver to user space */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_TABLE\n"); if ((retval = RIOApel(p)) != 0) return retval; if (copyout((caddr_t)p->RIOConnectTable, (int)arg, TOTAL_MAP_ENTRIES*sizeof(struct Map)) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_TABLE copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } { int entry; - rio_dprint(RIO_DEBUG_CTRL, ("*****\nMAP ENTRIES\n") ); + rio_dprintk (RIO_DEBUG_CTRL, "*****\nMAP ENTRIES\n"); for ( entry=0; entry<TOTAL_MAP_ENTRIES; entry++ ) { if ((p->RIOConnectTable[entry].ID == 0) && (p->RIOConnectTable[entry].HostUniqueNum == 0) && (p->RIOConnectTable[entry].RtaUniqueNum == 0)) continue; - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Flags = 0x%x\n", entry, (int)p->RIOConnectTable[entry].Flags ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.SysPort = 0x%x\n", entry, (int)p->RIOConnectTable[entry].SysPort ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Flags = 0x%x\n", entry, (int)p->RIOConnectTable[entry].Flags ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.SysPort = 0x%x\n", entry, (int)p->RIOConnectTable[entry].SysPort ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ); } - rio_dprint(RIO_DEBUG_CTRL, ("*****\nEND MAP ENTRIES\n") ); + rio_dprintk (RIO_DEBUG_CTRL, "*****\nEND MAP ENTRIES\n"); } p->RIOQuickCheck = NOT_CHANGED; /* a table has been gotten */ return 0; @@ -402,16 +402,16 @@ RIO_DEBUG_CTRL, if (su) /* ** Write the routing table to the device driver from user space */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_TABLE\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_TABLE !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if ( copyin((int)arg, (caddr_t)&p->RIOConnectTable[0], TOTAL_MAP_ENTRIES*sizeof(struct Map) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_TABLE copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -449,17 +449,17 @@ RIO_DEBUG_CTRL, if (su) ** Send bindings table, containing unique numbers of RTAs owned ** by this system to user space */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_BINDINGS\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_BINDINGS !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyout((caddr_t) p->RIOBindTab, (int)arg, (sizeof(ulong) * MAX_RTA_BINDINGS)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_BINDINGS copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -470,17 +470,17 @@ RIO_DEBUG_CTRL, if (su) ** Receive a bindings table, containing unique numbers of RTAs owned ** by this system */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&p->RIOBindTab[0], (sizeof(ulong) * MAX_RTA_BINDINGS))==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -493,10 +493,10 @@ RIO_DEBUG_CTRL, if (su) ** Bind this RTA to host, so that it will be booted by ** host in 'boot owned RTAs' mode. */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_BIND_RTA\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_BIND_RTA !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } @@ -508,8 +508,8 @@ RIO_DEBUG_CTRL, if (su) ** Already exists - delete */ p->RIOBindTab[Entry] = 0L; - rio_dprint(RIO_DEBUG_CTRL, ("Removing Rta %x from p->RIOBindTab\n", - (int) arg)); + rio_dprintk (RIO_DEBUG_CTRL, "Removing Rta %x from p->RIOBindTab\n", + (int) arg); return 0; } } @@ -518,90 +518,90 @@ RIO_DEBUG_CTRL, if (su) */ if (EmptySlot != -1) { p->RIOBindTab[EmptySlot] = (int) arg; - rio_dprint(RIO_DEBUG_CTRL, ("Adding Rta %x to p->RIOBindTab\n", - (int) arg)); + rio_dprintk (RIO_DEBUG_CTRL, "Adding Rta %x to p->RIOBindTab\n", + (int) arg); } else { - rio_dprint(RIO_DEBUG_CTRL, ("p->RIOBindTab full! - Rta %x not added\n", - (int) arg)); + rio_dprintk (RIO_DEBUG_CTRL, "p->RIOBindTab full! - Rta %x not added\n", + (int) arg); return 1; } return 0; } case RIO_RESUME : - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME\n"); port = (uint) arg; if ((port < 0) || (port > 511)) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Bad port number %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Bad port number %d\n", port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } PortP = p->RIOPortp[port]; if (!PortP->Mapped) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not mapped\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not mapped\n", port); p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM; return EINVAL; } if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not open\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not open\n", port); return EINVAL; } rio_spin_lock_irqsave(&PortP->portSem, flags); if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME failed\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return EBUSY; } else { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d resumed\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Port %d resumed\n", port); PortP->State |= RIO_BUSY; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); return retval; case RIO_ASSIGN_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Copy from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } return RIOAssignRta(p, &MapEnt); case RIO_CHANGE_NAME: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_CHANGE_NAME\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_CHANGE_NAME !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Copy from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } return RIOChangeName(p, &MapEnt); case RIO_DELETE_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DELETE_RTA\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DELETE_RTA !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("Copy from data space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Copy from data space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -638,7 +638,7 @@ RIO_DEBUG_CTRL, if (su) return 0; case RIO_GET_LOG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_LOG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_LOG\n"); #ifdef LOGGING RIOGetLog(arg); return 0; @@ -653,17 +653,17 @@ RIO_DEBUG_CTRL, if (su) p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("Get module type for port %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "Get module type for port %d\n", port); if ( port < 0 || port > 511 ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Bad port number %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Bad port number %d\n", port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } PortP = (p->RIOPortp[port]); if (!PortP->Mapped) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Port %d not mapped\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Port %d not mapped\n", port); p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM; return EINVAL; } @@ -703,7 +703,7 @@ RIO_DEBUG_CTRL, if (su) */ case RIO_BLOCK_OPENS: - rio_dprint(RIO_DEBUG_CTRL, ("Opens block until booted\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Opens block until booted\n"); for ( Entry=0; Entry < RIO_PORTS; Entry++ ) { rio_spin_lock_irqsave(&PortP->portSem, flags); p->RIOPortp[Entry]->WaitUntilBooted = 1; @@ -712,33 +712,33 @@ RIO_DEBUG_CTRL, if (su) return 0; case RIO_SETUP_PORTS: - rio_dprint(RIO_DEBUG_CTRL, ("Setup ports\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Setup ports\n"); if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("EFAULT")); + rio_dprintk (RIO_DEBUG_CTRL, "EFAULT"); return EFAULT; } if ( PortSetup.From > PortSetup.To || PortSetup.To >= RIO_PORTS ) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("ENXIO")); + rio_dprintk (RIO_DEBUG_CTRL, "ENXIO"); return ENXIO; } if ( PortSetup.XpCps > p->RIOConf.MaxXpCps || PortSetup.XpCps < p->RIOConf.MinXpCps ) { p->RIOError.Error = XPRINT_CPS_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("EINVAL")); + rio_dprintk (RIO_DEBUG_CTRL, "EINVAL"); return EINVAL; } if ( !p->RIOPortp ) { cprintf("No p->RIOPortp array!\n"); - rio_dprint(RIO_DEBUG_CTRL, ("No p->RIOPortp array!\n")); + rio_dprintk (RIO_DEBUG_CTRL, "No p->RIOPortp array!\n"); return EIO; } - rio_dprint(RIO_DEBUG_CTRL, ("entering loop (%d %d)!\n", PortSetup.From, PortSetup.To)); + rio_dprintk (RIO_DEBUG_CTRL, "entering loop (%d %d)!\n", PortSetup.From, PortSetup.To); for (loop=PortSetup.From; loop<=PortSetup.To; loop++) { - rio_dprint(RIO_DEBUG_CTRL, ("in loop (%d)!\n", loop)); + rio_dprintk (RIO_DEBUG_CTRL, "in loop (%d)!\n", loop); #if 0 PortP = p->RIOPortp[loop]; if ( !PortP->TtyP ) @@ -791,12 +791,12 @@ RIO_DEBUG_CTRL, if (su) rio_spin_unlock_irqrestore( &PortP->portSem , flags); #endif } - rio_dprint(RIO_DEBUG_CTRL, ("after loop (%d)!\n", loop)); - rio_dprint(RIO_DEBUG_CTRL, ("Retval:%x\n", retval ) ); + rio_dprintk (RIO_DEBUG_CTRL, "after loop (%d)!\n", loop); + rio_dprintk (RIO_DEBUG_CTRL, "Retval:%x\n", retval); return retval; case RIO_GET_PORT_SETUP : - rio_dprint(RIO_DEBUG_CTRL, ("Get port setup\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Get port setup\n"); if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -832,7 +832,7 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_GET_PORT_PARAMS : - rio_dprint(RIO_DEBUG_CTRL, ("Get port params\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Get port params\n"); if (copyin( (int)arg, (caddr_t)&PortParams, sizeof(struct PortParams)) == COPYFAIL) { p->RIOError.Error = COPYIN_FAILED; @@ -845,7 +845,7 @@ RIO_DEBUG_CTRL, if (su) PortP = (p->RIOPortp[PortParams.Port]); PortParams.Config = PortP->Config; PortParams.State = PortP->State; - rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortParams.Port)); + rio_dprintk (RIO_DEBUG_CTRL, "Port %d\n", PortParams.Port); if (copyout((caddr_t)&PortParams, (int)arg, sizeof(struct PortParams)) == COPYFAIL ) { @@ -855,7 +855,7 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_GET_PORT_TTY : - rio_dprint(RIO_DEBUG_CTRL, ("Get port tty\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Get port tty\n"); if (copyin((int)arg, (caddr_t)&PortTty, sizeof(struct PortTty)) == COPYFAIL) { p->RIOError.Error = COPYIN_FAILED; @@ -866,7 +866,7 @@ RIO_DEBUG_CTRL, if (su) return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortTty.port)); + rio_dprintk (RIO_DEBUG_CTRL, "Port %d\n", PortTty.port); PortP = (p->RIOPortp[PortTty.port]); #if 0 PortTty.Tty.tm.c_iflag = PortP->TtyP->tm.c_iflag; @@ -887,7 +887,7 @@ RIO_DEBUG_CTRL, if (su) p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("Set port %d tty\n", PortTty.port)); + rio_dprintk (RIO_DEBUG_CTRL, "Set port %d tty\n", PortTty.port); if (PortTty.port >= (ushort) RIO_PORTS) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; @@ -906,7 +906,7 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_SET_PORT_PARAMS : - rio_dprint(RIO_DEBUG_CTRL, ("Set port params\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Set port params\n"); if ( copyin((int)arg, (caddr_t)&PortParams, sizeof(PortParams)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -923,7 +923,7 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_GET_PORT_STATS : - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_PORT_STATS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_PORT_STATS\n"); if ( copyin((int)arg, (caddr_t)&portStats, sizeof(struct portStats)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -949,7 +949,7 @@ RIO_DEBUG_CTRL, if (su) case RIO_RESET_PORT_STATS : port = (uint) arg; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESET_PORT_STATS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESET_PORT_STATS\n"); if ( port >= RIO_PORTS ) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; @@ -965,7 +965,7 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_GATHER_PORT_STATS : - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GATHER_PORT_STATS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GATHER_PORT_STATS\n"); if ( copyin( (int)arg, (caddr_t)&portStats, sizeof(struct portStats)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -985,22 +985,22 @@ RIO_DEBUG_CTRL, if (su) case RIO_READ_LEVELS: { int num; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_LEVELS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_LEVELS\n"); for ( num=0; RIODbInf[num].Flag; num++ ) ; - rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copy\n",num)); + rio_dprintk (RIO_DEBUG_CTRL, "%d levels to copy\n",num); if (copyout((caddr_t)RIODbInf,(int)arg, sizeof(struct DbInf)*(num+1))==COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("ReadLevels Copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "ReadLevels Copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copied\n",num)); + rio_dprintk (RIO_DEBUG_CTRL, "%d levels to copied\n",num); return retval; } #endif case RIO_READ_CONFIG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_CONFIG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_CONFIG\n"); if (copyout((caddr_t)&p->RIOConf, (int)arg, sizeof(struct Conf)) ==COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; @@ -1009,7 +1009,7 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_SET_CONFIG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_CONFIG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_CONFIG\n"); if ( !su ) { p->RIOError.Error = NOT_SUPER_USER; return EPERM; @@ -1029,11 +1029,11 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_START_POLLER: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_START_POLLER\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_START_POLLER\n"); return EINVAL; case RIO_STOP_POLLER: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_STOP_POLLER\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_STOP_POLLER\n"); if ( !su ) { p->RIOError.Error = NOT_SUPER_USER; return EPERM; @@ -1043,7 +1043,7 @@ RIO_DEBUG_CTRL, if (su) case RIO_SETDEBUG: case RIO_GETDEBUG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG/RIO_GETDEBUG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SETDEBUG/RIO_GETDEBUG\n"); if ( copyin( (int)arg, (caddr_t)&DebugCtrl, sizeof(DebugCtrl) ) ==COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -1057,18 +1057,18 @@ RIO_DEBUG_CTRL, if (su) } p->rio_debug = DebugCtrl.Debug; p->RIODebugWait = DebugCtrl.Wait; - rio_dprint(RIO_DEBUG_CTRL, ("Set global debug to 0x%x set wait to 0x%x\n", - p->rio_debug,p->RIODebugWait)); + rio_dprintk (RIO_DEBUG_CTRL, "Set global debug to 0x%x set wait to 0x%x\n", + p->rio_debug,p->RIODebugWait); } else { - rio_dprint(RIO_DEBUG_CTRL, ("Get global debug 0x%x wait 0x%x\n", - p->rio_debug,p->RIODebugWait)); + rio_dprintk (RIO_DEBUG_CTRL, "Get global debug 0x%x wait 0x%x\n", + p->rio_debug,p->RIODebugWait); DebugCtrl.Debug = p->rio_debug; DebugCtrl.Wait = p->RIODebugWait; if ( copyout((caddr_t)&DebugCtrl,(int)arg, sizeof(DebugCtrl)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n", - DebugCtrl.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", + DebugCtrl.SysPort); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1076,8 +1076,8 @@ RIO_DEBUG_CTRL, if (su) } else if ( DebugCtrl.SysPort >= RIO_PORTS && DebugCtrl.SysPort != NO_PORT ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n", - DebugCtrl.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", + DebugCtrl.SysPort); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; } @@ -1089,16 +1089,16 @@ RIO_DEBUG_CTRL, if (su) rio_spin_lock_irqsave(&PortP->portSem, flags); p->RIOPortp[DebugCtrl.SysPort]->Debug = DebugCtrl.Debug; rio_spin_unlock_irqrestore( &PortP->portSem , flags); - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG 0x%x\n", - p->RIOPortp[DebugCtrl.SysPort]->Debug)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SETDEBUG 0x%x\n", + p->RIOPortp[DebugCtrl.SysPort]->Debug); } else { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG 0x%x\n", - p->RIOPortp[DebugCtrl.SysPort]->Debug)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GETDEBUG 0x%x\n", + p->RIOPortp[DebugCtrl.SysPort]->Debug); DebugCtrl.Debug = p->RIOPortp[DebugCtrl.SysPort]->Debug; if ( copyout((caddr_t)&DebugCtrl,(int)arg, sizeof(DebugCtrl))==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GETDEBUG: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1111,12 +1111,12 @@ RIO_DEBUG_CTRL, if (su) ** We return MAX_VERSION_LEN bytes, being a ** textual null terminated string. */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID\n") ); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_VERSID\n"); if ( copyout( (caddr_t)RIOVersid(), (int)arg, sizeof(struct rioVersion) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID: Bad copy to user space (host=%d)\n",Host) ); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_VERSID: Bad copy to user space (host=%d)\n", Host); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1150,10 +1150,10 @@ RIO_DEBUG_CTRL, if (su) ** Enquire as to the number of hosts located ** at init time. */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_NUM_HOSTS\n"); if (copyout((caddr_t)&p->RIONumHosts, (int)arg, sizeof(p->RIONumHosts) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_NUM_HOSTS: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1163,9 +1163,9 @@ RIO_DEBUG_CTRL, if (su) /* ** Kill host. This may not be in the final version... */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD %d\n", (int)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_FOAD %d\n", (int)arg); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD: Not super user\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_FOAD: Not super user\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } @@ -1213,27 +1213,27 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_DOWNLOAD: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Not super user\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Not super user\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if ( copyin((int)arg, (caddr_t)&DownLoad, sizeof(DownLoad) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("Copied in download code for product code 0x%x\n", - DownLoad.ProductCode ) ); + rio_dprintk (RIO_DEBUG_CTRL, "Copied in download code for product code 0x%x\n", + DownLoad.ProductCode); /* ** It is important that the product code is an unsigned object! */ if ( DownLoad.ProductCode > MAX_PRODUCT ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Bad product code %d passed\n", - DownLoad.ProductCode)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Bad product code %d passed\n", + DownLoad.ProductCode); p->RIOError.Error = NO_SUCH_PRODUCT; return ENXIO; } @@ -1254,63 +1254,63 @@ RIO_DEBUG_CTRL, if (su) if (copyin((int)arg, (caddr_t)&host, sizeof(host) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ( - "RIO_HOST_REQ: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, + "RIO_HOST_REQ: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } /* ** Fetch the parmmap */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PARMS\n"); if ( copyout( (caddr_t)p->RIOHosts[host].ParmMapP, (int)arg, sizeof(PARM_MAP) )==COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS: Copy out to user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PARMS: Copy out to user space failed\n"); return EFAULT; } } return retval; case RIO_HOST_REQ: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ\n"); if (copyin((int)arg, (caddr_t)&HostReq, sizeof(HostReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if ( HostReq.HostNum >= p->RIONumHosts ) { p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Illegal host number %d\n", - HostReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ: Illegal host number %d\n", + HostReq.HostNum); return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for host %d\n", HostReq.HostNum); if (copyout((caddr_t)&p->RIOHosts[HostReq.HostNum], (int)HostReq.HostP,sizeof(struct Host) ) == COPYFAIL) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ: Bad copy to user space\n"); return EFAULT; } return retval; case RIO_HOST_DPRAM: - rio_dprint(RIO_DEBUG_CTRL, ("Request for DPRAM\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Request for DPRAM\n"); if ( copyin( (int)arg, (caddr_t)&HostDpRam, sizeof(HostDpRam) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if ( HostDpRam.HostNum >= p->RIONumHosts ) { p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Illegal host number %d\n", - HostDpRam.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Illegal host number %d\n", + HostDpRam.HostNum); return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostDpRam.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for host %d\n", HostDpRam.HostNum); if (p->RIOHosts[HostDpRam.HostNum].Type == RIO_PCI) { int off; @@ -1321,7 +1321,7 @@ RIO_DEBUG_CTRL, if (su) if ( copyout( (caddr_t)copy, (int)HostDpRam.DpRamP, sizeof(struct DpRam) ) == COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n"); return EFAULT; } } @@ -1329,15 +1329,15 @@ RIO_DEBUG_CTRL, if (su) (int)HostDpRam.DpRamP, sizeof(struct DpRam) ) == COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n"); return EFAULT; } return retval; case RIO_SET_BUSY: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_BUSY\n"); if ( (int)arg < 0 || (int)arg > 511 ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY: Bad port number %d\n",(int)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_BUSY: Bad port number %d\n",(int)arg); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1351,26 +1351,26 @@ RIO_DEBUG_CTRL, if (su) ** The daemon want port information ** (probably for debug reasons) */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT\n"); if ( copyin((int)arg, (caddr_t)&PortReq, sizeof(PortReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if (PortReq.SysPort >= RIO_PORTS) { /* SysPort is unsigned */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Illegal port number %d\n", - PortReq.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT: Illegal port number %d\n", + PortReq.SysPort); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for port %d\n", PortReq.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for port %d\n", PortReq.SysPort); if (copyout((caddr_t)p->RIOPortp[PortReq.SysPort], (int)PortReq.PortP, sizeof(struct Port) ) == COPYFAIL) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT: Bad copy to user space\n"); return EFAULT; } return retval; @@ -1380,40 +1380,40 @@ RIO_DEBUG_CTRL, if (su) ** The daemon want rup information ** (probably for debug reasons) */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP\n"); if (copyin((int)arg, (caddr_t)&RupReq, sizeof(RupReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if (RupReq.HostNum >= p->RIONumHosts) { /* host is unsigned */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal host number %d\n", - RupReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal host number %d\n", + RupReq.HostNum); p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; return ENXIO; } if ( RupReq.RupNum >= MAX_RUP+LINKS_PER_UNIT ) { /* eek! */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal rup number %d\n", - RupReq.RupNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal rup number %d\n", + RupReq.RupNum); p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE; return EINVAL; } HostP = &p->RIOHosts[RupReq.HostNum]; if ((HostP->Flags & RUN_STATE) != RC_RUNNING) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Host %d not running\n", - RupReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Host %d not running\n", + RupReq.HostNum); p->RIOError.Error = HOST_NOT_RUNNING; return EIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for rup %d from host %d\n", - RupReq.RupNum,RupReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for rup %d from host %d\n", + RupReq.RupNum,RupReq.HostNum); if (copyout((caddr_t)HostP->UnixRups[RupReq.RupNum].RupP, (int)RupReq.RupP,sizeof(struct RUP) ) == COPYFAIL) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Bad copy to user space\n"); return EFAULT; } return retval; @@ -1423,39 +1423,39 @@ RIO_DEBUG_CTRL, if (su) ** The daemon want lpb information ** (probably for debug reasons) */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB\n"); if (copyin((int)arg, (caddr_t)&LpbReq, sizeof(LpbReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy from user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy from user space\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if (LpbReq.Host >= p->RIONumHosts) { /* host is unsigned */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal host number %d\n", - LpbReq.Host)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal host number %d\n", + LpbReq.Host); p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; return ENXIO; } if ( LpbReq.Link >= LINKS_PER_UNIT ) { /* eek! */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal link number %d\n", - LpbReq.Link)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal link number %d\n", + LpbReq.Link); p->RIOError.Error = LINK_NUMBER_OUT_OF_RANGE; return EINVAL; } HostP = &p->RIOHosts[LpbReq.Host]; if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Host %d not running\n", - LpbReq.Host)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Host %d not running\n", + LpbReq.Host ); p->RIOError.Error = HOST_NOT_RUNNING; return EIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for lpb %d from host %d\n", - LpbReq.Link, LpbReq.Host)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for lpb %d from host %d\n", + LpbReq.Link, LpbReq.Host); if (copyout((caddr_t)&HostP->LinkStrP[LpbReq.Link], (int)LpbReq.LpbP,sizeof(struct LPB) ) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1494,7 +1494,7 @@ RIO_DEBUG_CTRL, if (su) p->RIOError.Error = NOT_RECEIVING_PROCESS; return EPERM; } - rio_dprint(RIO_DEBUG_CTRL, ("Clear signal process to zero\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Clear signal process to zero\n"); p->RIOSignalProcess = 0; return retval; @@ -1526,10 +1526,10 @@ RIO_DEBUG_CTRL, if (su) case RIO_MAP_B50_TO_57600: case RIO_MAP_B110_TO_110: case RIO_MAP_B110_TO_115200: - rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Baud rate mapping\n"); port = (uint) arg; if ( port < 0 || port > 511 ) { - rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1553,14 +1553,14 @@ RIO_DEBUG_CTRL, if (su) return retval; case RIO_STREAM_INFO: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_STREAM_INFO\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_STREAM_INFO\n"); return EINVAL; case RIO_SEND_PACKET: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SEND_PACKET\n"); if ( copyin( (int)arg, (caddr_t)&SendPack, sizeof(SendPack) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET: Bad copy from user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SEND_PACKET: Bad copy from user space\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -1605,7 +1605,7 @@ RIO_DEBUG_CTRL, if (su) case RIO_WHAT_MESG: if ( copyout( (caddr_t)&p->RIONoMessage, (int)arg, sizeof(p->RIONoMessage) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_WHAT_MESG: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_WHAT_MESG: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1617,8 +1617,8 @@ RIO_DEBUG_CTRL, if (su) p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP host %d rup %d addr %x\n", - SubCmd.Host, SubCmd.Rup, SubCmd.Addr)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_MEM_DUMP host %d rup %d addr %x\n", + SubCmd.Host, SubCmd.Rup, SubCmd.Addr); if (SubCmd.Rup >= MAX_RUP+LINKS_PER_UNIT ) { p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE; @@ -1638,7 +1638,7 @@ RIO_DEBUG_CTRL, if (su) rio_spin_lock_irqsave(&PortP->portSem, flags); if ( RIOPreemptiveCmd(p, PortP, MEMDUMP ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n"); rio_spin_unlock_irqrestore( &PortP->portSem , flags); return EBUSY; } @@ -1648,7 +1648,7 @@ RIO_DEBUG_CTRL, if (su) rio_spin_unlock_irqrestore( &PortP->portSem , flags); if ( copyout( (caddr_t)p->RIOMemDump, (int)arg, MEMDUMP_SIZE) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_MEM_DUMP copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1657,14 +1657,14 @@ RIO_DEBUG_CTRL, if (su) case RIO_TICK: if ((int)arg < 0 || (int)arg >= p->RIONumHosts) return EINVAL; - rio_dprint(RIO_DEBUG_CTRL, ("Set interrupt for host %d\n", (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Set interrupt for host %d\n", (int)arg); WBYTE(p->RIOHosts[(int)arg].SetInt , 0xff); return 0; case RIO_TOCK: if ((int)arg < 0 || (int)arg >= p->RIONumHosts) return EINVAL; - rio_dprint(RIO_DEBUG_CTRL, ("Clear interrupt for host %d\n", (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Clear interrupt for host %d\n", (int)arg); WBYTE((p->RIOHosts[(int)arg].ResetInt) , 0xff); return 0; @@ -1684,12 +1684,12 @@ RIO_DEBUG_CTRL, if (su) p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER host %d rup %d port %d reg %x\n", - SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_REGISTER host %d rup %d port %d reg %x\n", + SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr); if (SubCmd.Port > 511) { - rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", - SubCmd.Port)); + rio_dprintk (RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", + SubCmd.Port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1711,7 +1711,7 @@ RIO_DEBUG_CTRL, if (su) rio_spin_lock_irqsave(&PortP->portSem, flags); if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n"); rio_spin_unlock_irqrestore( &PortP->portSem , flags); return EBUSY; } @@ -1721,7 +1721,7 @@ RIO_DEBUG_CTRL, if (su) rio_spin_unlock_irqrestore( &PortP->portSem , flags); if (copyout((caddr_t)&p->CdRegister, (int)arg, sizeof(uint)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_REGISTER copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1738,18 +1738,18 @@ RIO_DEBUG_CTRL, if (su) switch ( (uint)arg & RIO_DEV_MASK ) { case RIO_DEV_DIRECT: arg = (caddr_t)drv_makedev(major(dev), port); - rio_dprint(RIO_DEBUG_CTRL, ("Makedev direct 0x%x is 0x%x\n",port, (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev direct 0x%x is 0x%x\n",port, (int)arg); return (int)arg; case RIO_DEV_MODEM: arg = (caddr_t)drv_makedev(major(dev), (port|RIO_MODEM_BIT) ); - rio_dprint(RIO_DEBUG_CTRL, ("Makedev modem 0x%x is 0x%x\n",port, (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev modem 0x%x is 0x%x\n",port, (int)arg); return (int)arg; case RIO_DEV_XPRINT: arg = (caddr_t)drv_makedev(major(dev), port); - rio_dprint(RIO_DEBUG_CTRL, ("Makedev printer 0x%x is 0x%x\n",port, (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev printer 0x%x is 0x%x\n",port, (int)arg); return (int)arg; } - rio_dprint(RIO_DEBUG_CTRL, ("MAKE Device is called\n")); + rio_dprintk (RIO_DEBUG_CTRL, "MAKE Device is called\n"); return EINVAL; } /* @@ -1766,17 +1766,17 @@ RIO_DEBUG_CTRL, if (su) mino = RIO_UNMODEM(dv); if ( RIO_ISMODEM(dv) ) { - rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: modem %d\n", dv, mino)); + rio_dprintk (RIO_DEBUG_CTRL, "Minor for device 0x%x: modem %d\n", dv, mino); arg = (caddr_t)(mino | RIO_DEV_MODEM); } else { - rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: direct %d\n", dv, mino)); + rio_dprintk (RIO_DEBUG_CTRL, "Minor for device 0x%x: direct %d\n", dv, mino); arg = (caddr_t)(mino | RIO_DEV_DIRECT); } return (int)arg; } } - rio_dprint(RIO_DEBUG_CTRL, ("INVALID DAEMON IOCTL 0x%x\n",cmd)); + rio_dprintk (RIO_DEBUG_CTRL, "INVALID DAEMON IOCTL 0x%x\n",cmd); p->RIOError.Error = IOCTL_COMMAND_UNKNOWN; func_exit (); @@ -1803,18 +1803,18 @@ uchar Cmd; #endif if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_CTRL, ("Preemptive command to deleted RTA ignored\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Preemptive command to deleted RTA ignored\n"); return RIO_FAIL; } if (((int)((char)PortP->InUse) == -1) || ! (CmdBlkP = RIOGetCmdBlk()) ) { - rio_dprint(RIO_DEBUG_CTRL, ("Cannot allocate command block for command %d on port %d\n", - Cmd, PortP->PortNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Cannot allocate command block for command %d on port %d\n", + Cmd, PortP->PortNum); return RIO_FAIL; } - rio_dprint(RIO_DEBUG_CTRL, ("Command blk 0x%x - InUse now %d\n", - (int)CmdBlkP,PortP->InUse)); + rio_dprintk (RIO_DEBUG_CTRL, "Command blk 0x%x - InUse now %d\n", + (int)CmdBlkP,PortP->InUse); PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0]; @@ -1840,40 +1840,40 @@ uchar Cmd; switch ( Cmd ) { case MEMDUMP: - rio_dprint(RIO_DEBUG_CTRL, ("Queue MEMDUMP command blk 0x%x (addr 0x%x)\n", - (int)CmdBlkP, (int)SubCmd.Addr)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue MEMDUMP command blk 0x%x (addr 0x%x)\n", + (int)CmdBlkP, (int)SubCmd.Addr); PktCmdP->SubCommand = MEMDUMP; PktCmdP->SubAddr = SubCmd.Addr; break; case FCLOSE: - rio_dprint(RIO_DEBUG_CTRL, ("Queue FCLOSE command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue FCLOSE command blk 0x%x\n",(int)CmdBlkP); break; case READ_REGISTER: - rio_dprint(RIO_DEBUG_CTRL, ("Queue READ_REGISTER (0x%x) command blk 0x%x\n", - (int)SubCmd.Addr, (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) command blk 0x%x\n", + (int)SubCmd.Addr, (int)CmdBlkP); PktCmdP->SubCommand = READ_REGISTER; PktCmdP->SubAddr = SubCmd.Addr; break; case RESUME: - rio_dprint(RIO_DEBUG_CTRL, ("Queue RESUME command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue RESUME command blk 0x%x\n",(int)CmdBlkP); break; case RFLUSH: - rio_dprint(RIO_DEBUG_CTRL, ("Queue RFLUSH command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue RFLUSH command blk 0x%x\n",(int)CmdBlkP); CmdBlkP->PostFuncP = RIORFlushEnable; break; case SUSPEND: - rio_dprint(RIO_DEBUG_CTRL, ("Queue SUSPEND command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue SUSPEND command blk 0x%x\n",(int)CmdBlkP); break; case MGET : - rio_dprint(RIO_DEBUG_CTRL, ("Queue MGET command blk 0x%x\n", (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue MGET command blk 0x%x\n", (int)CmdBlkP); break; case MSET : case MBIC : case MBIS : CmdBlkP->Packet.data[4] = (char) PortP->ModemLines; - rio_dprint(RIO_DEBUG_CTRL, ("Queue MSET/MBIC/MBIS command blk 0x%x\n", (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command blk 0x%x\n", (int)CmdBlkP); break; case WFLUSH: @@ -1883,12 +1883,12 @@ uchar Cmd; ** RTA. */ if ((int)((char)PortP->WflushFlag) == (int)-1) { - rio_dprint(RIO_DEBUG_CTRL, ("Trashed WFLUSH, WflushFlag about to wrap!")); + rio_dprintk (RIO_DEBUG_CTRL, "Trashed WFLUSH, WflushFlag about to wrap!"); RIOFreeCmdBlk(CmdBlkP); return(RIO_FAIL); } else { - rio_dprint(RIO_DEBUG_CTRL, ("Queue WFLUSH command blk 0x%x\n", - (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue WFLUSH command blk 0x%x\n", + (int)CmdBlkP); CmdBlkP->PostFuncP = RIOWFlushMark; } break; diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index 59cfdedd5..cbefdac2d 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c @@ -81,7 +81,7 @@ static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3"; #include "control.h" #include "cirrus.h" #include "rioioctl.h" - +#include "rio_linux.h" #undef bcopy #define bcopy rio_pcicopy @@ -109,7 +109,7 @@ struct RioHostInfo * info; */ if ( !p->RIOPortp ) { - rio_dprint(RIO_DEBUG_INIT, ("Allocating and setting up driver data structures\n") ); + rio_dprintk (RIO_DEBUG_INIT, "Allocating and setting up driver data structures\n"); RIOAllocDataStructs(p); /* allocate host/port structs */ RIOSetupDataStructs(p); /* setup topology structs */ @@ -155,16 +155,16 @@ struct RioHostInfo * info; if ( info->bus & ISA_BUS ) { - rio_dprint(RIO_DEBUG_INIT, ("initialising card %d (ISA)\n", p->RIONumHosts) ); + rio_dprintk (RIO_DEBUG_INIT, "initialising card %d (ISA)\n", p->RIONumHosts); RIOISAinit(p, p->mode); } else { - rio_dprint(RIO_DEBUG_INIT, ("initialising card %d (PCI)\n", p->RIONumHosts) ); + rio_dprintk (RIO_DEBUG_INIT, "initialising card %d (PCI)\n", p->RIONumHosts); RIOPCIinit(p, RIO_PCI_DEFAULT_MODE); } - rio_dprint(RIO_DEBUG_INIT, ("Total hosts initialised so far : %d\n", p->RIONumHosts) ); + rio_dprintk (RIO_DEBUG_INIT, "Total hosts initialised so far : %d\n", p->RIONumHosts); #ifdef FUTURE_RELEASE @@ -193,13 +193,13 @@ int mode; p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec, (int (*)())rio_intr, (char*)p->RIONumHosts); - rio_dprint(RIO_DEBUG_INIT, ("Set interrupt handler, intr_tid = 0x%x\n", p->intr_tid ) ); + rio_dprintk (RIO_DEBUG_INIT, "Set interrupt handler, intr_tid = 0x%x\n", p->intr_tid ); if (RIODoAT(p, p->RIOHosts[p->RIONumHosts].PaddrP, mode)) { return; } else { - rio_dprint(RIO_DEBUG_INIT, ("RIODoAT failed\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIODoAT failed\n"); p->RIOFailed++; } #endif @@ -268,7 +268,7 @@ int Base; ** map it in in one 64K block. */ if (RIOMapin(Base, RIO_AT_MEM_SIZE, &virtAddr) == -1) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't map the board in!\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Couldn't map the board in!\n"); return((caddr_t)0); } @@ -285,8 +285,8 @@ int Base; ** Signature mismatch - card not at this address */ RIOMapout(Base, RIO_AT_MEM_SIZE, virtAddr); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't match the signature 0x%x 0x%x!\n", - (int)cardp, off)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Couldn't match the signature 0x%x 0x%x!\n", + (int)cardp, off); return((caddr_t)0); } } @@ -356,10 +356,10 @@ int mode; ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)| ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)| ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum); p->RIONumHosts++; - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Tests Passed at 0x%x\n", Base)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Tests Passed at 0x%x\n", Base); return(1); } #if 0 @@ -378,7 +378,7 @@ int RIOMCAinit(int Mode) ** is only FAST LINKS */ Mode = (Mode & FAST_LINKS) ? McaTpFastLinks : McaTpSlowLinks; - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOMCAinit(%d)\n",Mode); + rio_dprintk (RIO_DEBUG_INIT, "RIOMCAinit(%d)\n",Mode); /* @@ -395,7 +395,7 @@ int RIOMCAinit(int Mode) */ if (((inb(McaIdHigh)<< 8)|inb(McaIdLow)) == McaRIOId) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Potential MCA card in slot %d\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Potential MCA card in slot %d\n", SlotNumber); /* ** Card appears to be a RIO MCA card! @@ -417,48 +417,44 @@ int RIOMCAinit(int Mode) */ Ivec = inb(McaIrqEnable); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Ivec is %x\n",Ivec); + rio_dprintk (RIO_DEBUG_INIT, "Ivec is %x\n", Ivec); switch ( Ivec & McaIrqMask ) { case McaIrq9: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ9\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ9\n"); break; case McaIrq3: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ3\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ3\n"); break; case McaIrq4: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ4\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ4\n"); break; case McaIrq7: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ7\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ7\n"); break; case McaIrq10: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ10\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ10\n"); break; case McaIrq11: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ11\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ11\n"); break; case McaIrq12: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ12\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ12\n"); break; case McaIrq15: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ15\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ15\n"); break; } /* ** If the card enable bit isn't set, then set it! */ - if ((Ivec & McaCardEnable) != McaCardEnable ) - { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable not set - setting!\n"); - outb(McaIrqEnable,Ivec|McaCardEnable); - } - else - { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable already set\n"); - } + if ((Ivec & McaCardEnable) != McaCardEnable) { + rio_dprintk (RIO_DEBUG_INIT, "McaCardEnable not set - setting!\n"); + outb(McaIrqEnable,Ivec|McaCardEnable); + } else + rio_dprintk (RIO_DEBUG_INIT, "McaCardEnable already set\n"); /* ** Convert the IRQ enable mask into something useful @@ -468,10 +464,10 @@ int RIOMCAinit(int Mode) /* ** Find the physical address */ - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"inb(McaMemory) is %x\n",inb(McaMemory)); + rio_dprintk (RIO_DEBUG_INIT, "inb(McaMemory) is %x\n", inb(McaMemory)); Paddr = McaAddress(inb(McaMemory)); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"MCA card has Ivec %d Addr %x\n",Ivec,Paddr); + rio_dprintk (RIO_DEBUG_INIT, "MCA card has Ivec %d Addr %x\n", Ivec, Paddr); if ( Paddr != 0 ) { @@ -482,21 +478,20 @@ int RIOMCAinit(int Mode) Handle = RIOMapin( Paddr, RIO_MCA_MEM_SIZE, &Caddr ); if ( Handle == -1 ) { - rio_dprint(RIO_DEBUG_INIT, ("Couldn't map %d bytes at %x\n", RIO_MCA_MEM_SIZE,Paddr); + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at %x\n", RIO_MCA_MEM_SIZE, Paddr; continue; } - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board mapped to vaddr 0x%x\n",Caddr); + rio_dprintk (RIO_DEBUG_INIT, "Board mapped to vaddr 0x%x\n", Caddr); /* ** And check that it is actually there! */ if ( RIOBoardTest( Paddr,Caddr,RIO_MCA,SlotNumber ) == RIO_SUCCESS ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board has passed test\n"); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT, - "Slot %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", - SlotNumber,RIO_MCA,Paddr,Caddr,Mode); + rio_dprintk (RIO_DEBUG_INIT, "Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", + SlotNumber, RIO_MCA, Paddr, Caddr, Mode); /* ** Board has passed its scrub test. Fill in all the @@ -524,25 +519,25 @@ int RIOMCAinit(int Mode) /* ** It failed the test, so ignore it. */ - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"TEST FAILED\n"); + rio_dprintk (RIO_DEBUG_INIT, "TEST FAILED\n"); RIOMapout(Paddr, RIO_MCA_MEM_SIZE, Caddr ); } } else { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d - Paddr zero!\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d - Paddr zero!\n", SlotNumber); } } else { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d NOT RIO\n", SlotNumber); } } /* ** Now we have checked all the slots, turn off the MCA slot selector */ outb(McaSlotSelect,0); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d NOT RIO\n", SlotNumber); return ret; } @@ -565,13 +560,13 @@ int RIOEISAinit( int Mode ) if ( EISADone ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit() - already done, return.\n"); + rio_dprintk (RIO_DEBUG_INIT, "RIOEISAinit() - already done, return.\n"); return(0); } EISADone++; - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit()\n"); + rio_dprintk (RIO_DEBUG_INIT, "RIOEISAinit()\n"); /* @@ -584,23 +579,21 @@ int RIOEISAinit( int Mode ) Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) | INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO); - /* rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT, "Check EISA slot %d, ID=%x\n",EisaSlot,Ident); */ - if ( Ident == RIO_EISA_IDENT ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Found Specialix product\n"); + rio_dprintk (RIO_DEBUG_INIT, "Found Specialix product\n"); if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Not Specialix RIO - Product number %x\n", - INBZ(EisaSlot,EISA_PRODUCT_NUMBER)); + rio_dprintk (RIO_DEBUG_INIT, "Not Specialix RIO - Product number %x\n", + INBZ(EisaSlot, EISA_PRODUCT_NUMBER)); continue; /* next slot */ } /* ** Its a Specialix RIO! */ - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIO Revision %d\n", - INBZ(EisaSlot,EISA_REVISION_NUMBER)); + rio_dprintk (RIO_DEBUG_INIT, "RIO Revision %d\n", + INBZ(EisaSlot, EISA_REVISION_NUMBER)); RIOMachineType |= (1<<RIO_EISA); @@ -627,43 +620,43 @@ int RIOEISAinit( int Mode ) switch ( Ivec & EISA_INTERRUPT_MASK ) { case EISA_IRQ_3: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 3\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 3\n"); break; case EISA_IRQ_4: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 4\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 4\n"); break; case EISA_IRQ_5: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 5\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 5\n"); break; case EISA_IRQ_6: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 6\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 6\n"); break; case EISA_IRQ_7: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 7\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 7\n"); break; case EISA_IRQ_9: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 9\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 9\n"); break; case EISA_IRQ_10: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 10\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 10\n"); break; case EISA_IRQ_11: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 11\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 11\n"); break; case EISA_IRQ_12: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 12\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 12\n"); break; case EISA_IRQ_14: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 14\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 14\n"); break; case EISA_IRQ_15: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA IRQ 15\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 15\n"); break; case EISA_POLLED: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"EISA POLLED\n"); + rio_dprintk (RIO_DEBUG_INIT, "EISA POLLED\n"); break; default: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT|DBG_FAIL,"Shagged interrupt number!\n"); + rio_dprintk (RIO_DEBUG_INIT, NULL,DBG_INIT|DBG_FAIL,"Shagged interrupt number!\n"); Ivec &= EISA_CONTROL_MASK; } #endif @@ -741,7 +734,7 @@ int RIOEISAinit( int Mode ) */ Ivec = RIOEisaToIvec(Ivec); - rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT, "EISA host in slot %d has Ivec 0x%x\n", + rio_dprintk (RIO_DEBUG_INIT, "EISA host in slot %d has Ivec 0x%x\n", EisaSlot, Ivec); /* @@ -750,11 +743,11 @@ int RIOEISAinit( int Mode ) Paddr = (INBZ(EisaSlot,EISA_MEMORY_BASE_HI)<<24) | (INBZ(EisaSlot,EISA_MEMORY_BASE_LO)<<16); - rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"EISA card has Ivec %d Addr %x\n",Ivec,Paddr); + rio_dprintk (RIO_DEBUG_INIT, "EISA card has Ivec %d Addr %x\n", Ivec, Paddr); if ( Paddr == 0 ) { - rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT | DBG_FAIL, + rio_dprintk (RIO_DEBUG_INIT, "Board in slot %d configured for address zero!\n", EisaSlot); continue; } @@ -762,23 +755,23 @@ int RIOEISAinit( int Mode ) /* ** Tell the memory mapper that we want to talk to it */ - rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"About to map EISA card \n"); + rio_dprintk (RIO_DEBUG_INIT, "About to map EISA card \n"); if (RIOMapin( Paddr, RIO_EISA_MEM_SIZE, &Caddr) == -1) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"Couldn't map %d bytes at %x\n", + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at %x\n", RIO_EISA_MEM_SIZE,Paddr); continue; } - rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"Board mapped to vaddr 0x%x\n",Caddr); + rio_dprintk (RIO_DEBUG_INIT, "Board mapped to vaddr 0x%x\n", Caddr); /* ** And check that it is actually there! */ if ( RIOBoardTest( Paddr,Caddr,RIO_EISA,EisaSlot) == RIO_SUCCESS ) { - rio_dprint(RIO_DEBUG_INIT, NULL, DBG_INIT,"Board has passed test\n"); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT, + rio_dprintk (RIO_DEBUG_INIT, "Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d. Ivec %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", EisaSlot,Ivec,RIO_EISA,Paddr,Caddr,Mode); @@ -818,7 +811,7 @@ int RIOEISAinit( int Mode ) /* ** It failed the test, so ignore it. */ - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"TEST FAILED\n"); + rio_dprintk (RIO_DEBUG_INIT, "TEST FAILED\n"); RIOMapout(Paddr, RIO_EISA_MEM_SIZE, Caddr ); } @@ -917,7 +910,7 @@ int Mode; int Handle; /* Handle to Virtual memory allocated for current PCI host */ - rio_dprint(RIO_DEBUG_INIT, ("Search for a RIO PCI card - start at slot %d\n", slot ) ); + rio_dprintk (RIO_DEBUG_INIT, "Search for a RIO PCI card - start at slot %d\n", slot); /* ** Initialise the search status @@ -926,7 +919,7 @@ int Mode; while ( (slot < MAX_PCI_SLOT) & (p->RIOLastPCISearch != RIO_SUCCESS) ) { - rio_dprint(RIO_DEBUG_INIT, ("Currently testing slot %d\n", slot ) ); + rio_dprintk (RIO_DEBUG_INIT, "Currently testing slot %d\n", slot); if (read_config(0,slot,0) == RIO_PCI_JET_CARD) { p->RIOHosts[p->RIONumHosts].Ivec = 0; @@ -934,7 +927,7 @@ int Mode; Paddr = Paddr - (Paddr & 0x1); /* Mask off the io bit */ if ( (Paddr == 0) || ((Paddr & 0xffff0000) == 0xffff0000) ) { - rio_dprint(RIO_DEBUG_INIT, ("Goofed up slot\n") ); /* what! */ + rio_dprintk (RIO_DEBUG_INIT, "Goofed up slot\n"); /* what! */ slot++; continue; } @@ -942,11 +935,11 @@ int Mode; p->RIOHosts[p->RIONumHosts].PaddrP = Paddr; Ivec = (read_config(0,slot,0x3c) & 0xff); - rio_dprint(RIO_DEBUG_INIT, ("PCI Host at 0x%x, Intr %d\n", (int)Paddr, Ivec ) ); + rio_dprintk (RIO_DEBUG_INIT, "PCI Host at 0x%x, Intr %d\n", (int)Paddr, Ivec); Handle = RIOMapin( Paddr, RIO_PCI_MEM_SIZE, &Caddr ); if (Handle == -1) { - rio_dprint(RIO_DEBUG_INIT, ("Couldn't map %d bytes at 0x%x\n", RIO_PCI_MEM_SIZE, (int)Paddr ) ); + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at 0x%x\n", RIO_PCI_MEM_SIZE, (int)Paddr); slot++; continue; } @@ -954,9 +947,8 @@ int Mode; p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec, (int (*)())rio_intr, (char *)p->RIONumHosts); if (RIOBoardTest( Paddr, Caddr, RIO_PCI, 0 ) == RIO_SUCCESS) { - rio_dprint(RIO_DEBUG_INIT, ("Board has passed test\n")); - rio_dprint(RIO_DEBUG_INIT, ("Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", Paddr, Caddr, - Mode)); + rio_dprintk (RIO_DEBUG_INIT, ("Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, ("Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", Paddr, Caddr, Mode); /* ** Board has passed its scrub test. Fill in all the @@ -991,8 +983,8 @@ int Mode; ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)| ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24); - rio_dprint(RIO_DEBUG_INIT, ("Unique no 0x%x.\n", - p->RIOHosts[p->RIONumHosts].UniqueNum ) ); + rio_dprintk (RIO_DEBUG_INIT, "Unique no 0x%x.\n", + p->RIOHosts[p->RIONumHosts].UniqueNum); p->RIOLastPCISearch = RIO_SUCCESS; p->RIONumHosts++; @@ -1002,8 +994,8 @@ int Mode; } if ( slot >= MAX_PCI_SLOT ) { - rio_dprint(RIO_DEBUG_INIT, ("All %d PCI slots have tested for RIO cards !!!\n", - MAX_PCI_SLOT ) ); + rio_dprintk (RIO_DEBUG_INIT, "All %d PCI slots have tested for RIO cards !!!\n", + MAX_PCI_SLOT); } @@ -1025,7 +1017,7 @@ void riohalt( void ) int host; for ( host=0; host<p->RIONumHosts; host++ ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Stop host %d\n",host); + rio_dprintk (RIO_DEBUG_INIT, "Stop host %d\n", host); (void)RIOBoardTest( p->RIOHosts[host].PaddrP, p->RIOHosts[host].Caddr, p->RIOHosts[host].Type,p->RIOHosts[host].Slot ); } } @@ -1058,8 +1050,8 @@ int slot; int op, bank; int nbanks; - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Reset host type=%d, DpRam=0x%x, slot=%d\n", - type,(int)DpRam,slot)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Reset host type=%d, DpRam=0x%x, slot=%d\n", + type,(int)DpRam, slot); RIOHostReset(type, DpRam, slot); @@ -1071,7 +1063,7 @@ int slot; ** scratch - 1000h bytes */ - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Setup ram/size arrays\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Setup ram/size arrays\n"); size[0] = DP_SRAM1_SIZE; size[1] = DP_SRAM2_SIZE; @@ -1087,12 +1079,12 @@ int slot; if (nbanks == 3) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Memory: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", - (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2])); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Memory: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", + (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2]); } else { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2], (int)ram[3], - size[3])); + size[3]); } /* @@ -1103,14 +1095,14 @@ int slot; for (op=0; op<TEST_END; op++) { for (bank=0; bank<nbanks; bank++) { if (RIOScrub(op, (BYTE *)ram[bank], size[bank]) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: RIOScrub band %d, op %d failed\n", - bank, op)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: RIOScrub band %d, op %d failed\n", + bank, op); return RIO_FAIL; } } } - rio_dprint(RIO_DEBUG_INIT, ("Test completed\n")); + rio_dprintk (RIO_DEBUG_INIT, "Test completed\n"); return RIO_SUCCESS; } @@ -1158,14 +1150,14 @@ int size; if (op) { for (off=0; off<size; off++) { if (RBYTE(ram[off]) != oldbyte) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Pre Check 1: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, RBYTE(ram[off]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Pre Check 1: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, RBYTE(ram[off])); return RIO_FAIL; } } for (off=0; off<size; off+=2) { if (*(ushort *)&ram[off] != oldword) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Pre Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,oldword,*(ushort *)&ram[off])); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Pre Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Pre Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,oldword,*(ushort *)&ram[off]); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Pre Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); return RIO_FAIL; } } @@ -1180,12 +1172,12 @@ int size; */ for (off=0; off<size; off++) { if (op && (RBYTE(ram[off]) != oldbyte)) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Pre Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off,oldbyte,RBYTE(ram[off]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Pre Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, RBYTE(ram[off])); return RIO_FAIL; } WBYTE(ram[off],invbyte); if (RBYTE(ram[off]) != invbyte) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Byte Inv Check: BYTE at offset 0x%x should have been=%x, was=%x\n",off,invbyte,RBYTE(ram[off]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Inv Check: BYTE at offset 0x%x should have been=%x, was=%x\n", off, invbyte, RBYTE(ram[off])); return RIO_FAIL; } } @@ -1199,15 +1191,15 @@ int size; */ for (off=0; off<size; off+=2) { if (*(ushort *)&ram[off] != invword) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Inv Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,invword,*(ushort *)&ram[off])); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Word Inv Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Inv Check: WORD at offset 0x%x should have been=%x, was=%x\n", off, invword, *(ushort *)&ram[off]); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Inv Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); return RIO_FAIL; } *(ushort *)&ram[off] = newword; if ( *(ushort *)&ram[off] != newword ) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 1: WORD at offset 0x%x should have been=%x, was=%x\n",off,newword,*(ushort *)&ram[off])); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 1: WORD at offset 0x%x should have been=%x, was=%x\n", off, newword, *(ushort *)&ram[off]); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); return RIO_FAIL; } } @@ -1219,15 +1211,15 @@ int size; */ for (off=0; off<size; off++) { if (RBYTE(ram[off]) != newbyte) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Byte Check: BYTE at offset 0x%x should have been=%x, was=%x\n",off,newbyte,RBYTE(ram[off]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Byte Check: BYTE at offset 0x%x should have been=%x, was=%x\n", off, newbyte, RBYTE(ram[off])); return RIO_FAIL; } } for (off=0; off<size; off+=2) { if ( *(ushort *)&ram[off] != newword ) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 2: WORD at offset 0x%x should have been=%x, was=%x\n",off,newword,*(ushort *)&ram[off])); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Post Word Check 2: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 2: WORD at offset 0x%x should have been=%x, was=%x\n", off, newword, *(ushort *)&ram[off]); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 2: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); return RIO_FAIL; } } @@ -1244,8 +1236,8 @@ int size; for ( off=0; off<size; off+=2 ) { if (*(ushort *)&ram[off] != swapword) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 1: WORD at offset 0x%x should have been=%x, was=%x\n",off,swapword,*((ushort *)&ram[off]))); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n",off,RBYTE(ram[off]),off+1,RBYTE(ram[off+1]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 1: WORD at offset 0x%x should have been=%x, was=%x\n", off, swapword, *((ushort *)&ram[off])); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); return RIO_FAIL; } *((ushort *)&ram[off]) = ~swapword; @@ -1253,11 +1245,11 @@ int size; for (off=0; off<size; off+=2) { if (RBYTE(ram[off]) != newbyte) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off,newbyte,RBYTE(ram[off]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off, newbyte, RBYTE(ram[off])); return RIO_FAIL; } if (RBYTE(ram[off+1]) != invbyte) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n",off+1,invbyte,RBYTE(ram[off+1]))); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off+1, invbyte, RBYTE(ram[off+1])); return RIO_FAIL; } *((ushort *)&ram[off]) = newword; @@ -1384,14 +1376,14 @@ struct rio_info * p; p->RIOPortp = (struct Port *)sysbrk(RIO_PORTS * sizeof(struct Port)); if (!p->RIOPortp) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for port structures\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: No memory for port structures\n"); p->RIOFailed++; return; } bzero( p->RIOPortp, sizeof(struct Port) * RIO_PORTS ); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: allocated and cleared memory for port structs\n") ); - rio_dprint(RIO_DEBUG_INIT, ("First RIO port struct @0x%x, size=0x%x bytes\n", - (int)p->RIOPortp, sizeof(struct Port) ) ); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: allocated and cleared memory for port structs\n"); + rio_dprintk (RIO_DEBUG_INIT, "First RIO port struct @0x%x, size=0x%x bytes\n", + (int)p->RIOPortp, sizeof(struct Port)); for( port=0; port<RIO_PORTS; port++ ) { p->RIOPortp[port].PortNum = port; @@ -1404,14 +1396,14 @@ struct rio_info * p; p->RIOHosts = (struct Host *)sysbrk(RIO_HOSTS * sizeof(struct Host)); if (!p->RIOHosts) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for host structures\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: No memory for host structures\n"); p->RIOFailed++; return; } bzero(p->RIOHosts, sizeof(struct Host)*RIO_HOSTS); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: allocated and cleared memory for host structs\n")); - rio_dprint(RIO_DEBUG_INIT, ("First RIO host struct @0x%x, size=0x%x bytes\n", - (int)p->RIOHosts, sizeof(struct Host) ) ); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: allocated and cleared memory for host structs\n"); + rio_dprintk (RIO_DEBUG_INIT, "First RIO host struct @0x%x, size=0x%x bytes\n", + (int)p->RIOHosts, sizeof(struct Host)); for( host=0; host<RIO_HOSTS; host++ ) { spin_lock_init (&p->RIOHosts[host].HostLock); @@ -1494,10 +1486,10 @@ struct rio_info * p; char * RIORelID = RELEASE_ID; int host; - rio_dprint(RIO_DEBUG_INIT, ("RIO : Release: %s ID: %s\n", RIORelease, RIORelID)); + rio_dprintk (RIO_DEBUG_INIT, "RIO : Release: %s ID: %s\n", RIORelease, RIORelID); if ( p->RIONumHosts==0 ) { - rio_dprint(RIO_DEBUG_INIT, ("\nNo Hosts configured\n")); + rio_dprintk (RIO_DEBUG_INIT, "\nNo Hosts configured\n"); return(0); } @@ -1505,7 +1497,7 @@ struct rio_info * p; struct Host *HostP = &p->RIOHosts[host]; switch ( HostP->Type ) { case RIO_AT: - rio_dprint(RIO_DEBUG_INIT, ("AT BUS : found the card at 0x%x\n", HostP->PaddrP)); + rio_dprintk (RIO_DEBUG_INIT, "AT BUS : found the card at 0x%x\n", HostP->PaddrP); } } return 0; @@ -1587,17 +1579,17 @@ uint Slot; /* ** Reset the Tpu */ - rio_dprint(RIO_DEBUG_INIT, ("RIOHostReset: type 0x%x", Type ) ); + rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: type 0x%x", Type); switch ( Type ) { case RIO_AT: - rio_dprint(RIO_DEBUG_INIT, (" (RIO_AT)\n")); + rio_dprintk (RIO_DEBUG_INIT, " (RIO_AT)\n"); WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); WBYTE(DpRamP->DpResetTpu, 0xFF); rio_udelay (3); - rio_dprint(RIO_DEBUG_INIT, ("RIOHostReset: Don't know if it worked. Try reset again\n") ); + rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n"); WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); @@ -1630,7 +1622,7 @@ uint Slot; break; #endif case RIO_PCI: - rio_dprint(RIO_DEBUG_INIT, (" (RIO_PCI)\n") ); + rio_dprintk (RIO_DEBUG_INIT, " (RIO_PCI)\n"); DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM; DpRamP->DpResetInt = 0xFF; DpRamP->DpResetTpu = 0xFF; @@ -1645,7 +1637,7 @@ uint Slot; #endif default: - rio_dprint(RIO_DEBUG_INIT, (" (UNKNOWN)\n") ); + rio_dprintk (RIO_DEBUG_INIT, " (UNKNOWN)\n"); break; } return; diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index e92609839..f52124b78 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c @@ -190,8 +190,8 @@ char * en; tty = PortP->gs.tty; - rio_dprint (RIO_DEBUG_INTR, ("tx port %d: %d chars queued.\n", - PortP->PortNum, PortP->gs.xmit_cnt)); + rio_dprintk (RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", + PortP->PortNum, PortP->gs.xmit_cnt); if (!PortP->gs.xmit_cnt) return; @@ -215,10 +215,10 @@ char * en; { int t; t = (c > 10)?10:c; - rio_dprint (RIO_DEBUG_INTR, ("tx port %d: copying %d chars: %s - %s\n", - PortP->PortNum, c, - firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail , t), - firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail + c-t, t))); + rio_dprintk (RIO_DEBUG_INTR, "rio: tx port %d: copying %d chars: %s - %s\n", + PortP->PortNum, c, + firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail , t), + firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail + c-t, t)); } /* If for one reason or another, we can't copy more data, we're done! */ @@ -244,14 +244,14 @@ char * en; rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2*PKT_MAX_DATA_LEN)) { - rio_dprint (RIO_DEBUG_INTR, ("Waking up.... ldisc:%d (%d/%d)....", + rio_dprintk (RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....", (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)), - PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); + PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty); - rio_dprint (RIO_DEBUG_INTR, ("(%d/%d)\n", - PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); + rio_dprintk (RIO_DEBUG_INTR, "(%d/%d)\n", + PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); wake_up_interruptible(&PortP->gs.tty->write_wait); } @@ -273,7 +273,7 @@ struct rio_info * p; for ( host=0; host<p->RIONumHosts; host++ ) { struct Host *HostP = &p->RIOHosts[host]; - rio_dprint(RIO_DEBUG_INTR, ("riointr() doing host %d type %d\n", host, HostP->Type ) ); + rio_dprintk (RIO_DEBUG_INTR, "riointr() doing host %d type %d\n", host, HostP->Type); switch( HostP->Type ) { case RIO_AT: @@ -363,7 +363,7 @@ int From; static int t =0; rio_spin_unlock (&HostP->HostLock); if ((t++ % 200) == 0) - rio_dprint(RIO_DEBUG_INTR, ("Interrupt but host not running. flags=%x.\n", (int)HostP->Flags)); + rio_dprintk (RIO_DEBUG_INTR, "Interrupt but host not running. flags=%x.\n", (int)HostP->Flags); return; } rio_spin_unlock (&HostP->HostLock); @@ -372,7 +372,7 @@ int From; WWORD( HostP->ParmMapP->rup_intr , 0 ); p->RIORupCount++; RupIntr++; - rio_dprint(RIO_DEBUG_INTR, ("RUP interrupt on host %d\n", HostP-p->RIOHosts )); + rio_dprintk (RIO_DEBUG_INTR, "rio: RUP interrupt on host %d\n", HostP-p->RIOHosts); RIOPollHostCommands(p, HostP ); } @@ -383,7 +383,7 @@ int From; p->RIORxCount++; RxIntr++; - rio_dprint(RIO_DEBUG_INTR, ("RX interrupt on host %d\n", HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_INTR, "rio: RX interrupt on host %d\n", HostP-p->RIOHosts); /* ** Loop through every port. If the port is mapped into ** the system ( i.e. has /dev/ttyXXXX associated ) then it is @@ -451,7 +451,7 @@ int From; ** MAGIC! ( Basically, handshake the RX buffer, so that ** the RTAs upstream can be re-enabled. ) */ - rio_dprint(RIO_DEBUG_INTR, ("Set RX handshake bit\n" )); + rio_dprintk (RIO_DEBUG_INTR, "Set RX handshake bit\n"); WWORD( PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET ); } @@ -466,7 +466,7 @@ int From; p->RIOTxCount++; TxIntr++; - rio_dprint(RIO_DEBUG_INTR, ("TX interrupt on host %d\n", HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_INTR, "rio: TX interrupt on host %d\n", HostP-p->RIOHosts); /* ** Loop through every port. @@ -504,7 +504,7 @@ int From; continue; } - rio_dprint (RIO_DEBUG_INTR, ("Looking into port %d.\n", port)); + rio_dprintk (RIO_DEBUG_INTR, "rio: Looking into port %d.\n", port); /* ** Lock the port before we begin working on it. */ @@ -515,7 +515,7 @@ int From; ** we need do none of this processing. */ if ( !can_add_transmit( &PacketP, PortP ) ) { - rio_dprint (RIO_DEBUG_INTR, ("Can't add to port, so skipping.\n")); + rio_dprintk (RIO_DEBUG_INTR, "Can't add to port, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } @@ -527,7 +527,7 @@ int From; ttyP = PortP->gs.tty; /* If ttyP is NULL, the port is getting closed. Forget about it. */ if (!ttyP) { - rio_dprint (RIO_DEBUG_INTR, ("no tty, so skipping.\n")); + rio_dprintk (RIO_DEBUG_INTR, "no tty, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } @@ -603,10 +603,10 @@ int From; ** with WFLUSH */ if ( PortP->WflushFlag ) { - rio_dprint(RIO_DEBUG_INTR, ("Want to WFLUSH mark this port\n")); + rio_dprintk (RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n"); if ( PortP->InUse ) - rio_dprint(RIO_DEBUG_INTR, ("FAILS - PORT IS IN USE\n")); + rio_dprintk (RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n"); } while ( PortP->WflushFlag && @@ -615,7 +615,7 @@ int From; int p; struct PktCmd *PktCmdP; - rio_dprint(RIO_DEBUG_INTR, ("Add WFLUSH marker to data queue\n")); + rio_dprintk (RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n"); /* ** make it look just like a WFLUSH command */ @@ -670,8 +670,8 @@ int From; PortP->MagicFlags &= ~MAGIC_FLUSH; } - rio_dprint(RIO_DEBUG_INTR, ("Wflush count now stands at %d\n", - PortP->WflushFlag)); + rio_dprintk (RIO_DEBUG_INTR, "Wflush count now stands at %d\n", + PortP->WflushFlag); } if ( PortP->MagicFlags & MORE_OUTPUT_EYGOR ) { if ( PortP->MagicFlags & MAGIC_FLUSH ) { @@ -747,12 +747,12 @@ struct Port * PortP; TtyP = PortP->gs.tty; if (!TtyP) { - rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: tty is null. \n")); + rio_dprintk (RIO_DEBUG_INTR, "RIOReceive: tty is null. \n"); return; } if (PortP->State & RIO_THROTTLE_RX) { - rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: Throttled. Can't handle more input.\n")); + rio_dprintk (RIO_DEBUG_INTR, "RIOReceive: Throttled. Can't handle more input.\n"); return; } @@ -786,18 +786,18 @@ struct Port * PortP; ** check that it is not a command! */ if ( PacketP->len & PKT_CMD_BIT ) { - rio_dprint(RIO_DEBUG_INTR, ("RIO: unexpected command packet received on PHB\n")); + rio_dprintk (RIO_DEBUG_INTR, "RIO: unexpected command packet received on PHB\n"); /* rio_dprint(RIO_DEBUG_INTR, (" sysport = %d\n", p->RIOPortp->PortNum)); */ - rio_dprint(RIO_DEBUG_INTR, (" dest_unit = %d\n", PacketP->dest_unit)); - rio_dprint(RIO_DEBUG_INTR, (" dest_port = %d\n", PacketP->dest_port)); - rio_dprint(RIO_DEBUG_INTR, (" src_unit = %d\n", PacketP->src_unit)); - rio_dprint(RIO_DEBUG_INTR, (" src_port = %d\n", PacketP->src_port)); - rio_dprint(RIO_DEBUG_INTR, (" len = %d\n", PacketP->len)); - rio_dprint(RIO_DEBUG_INTR, (" control = %d\n", PacketP->control)); - rio_dprint(RIO_DEBUG_INTR, (" csum = %d\n", PacketP->csum)); - rio_dprint(RIO_DEBUG_INTR, (" data bytes: ")); + rio_dprintk (RIO_DEBUG_INTR, " dest_unit = %d\n", PacketP->dest_unit); + rio_dprintk (RIO_DEBUG_INTR, " dest_port = %d\n", PacketP->dest_port); + rio_dprintk (RIO_DEBUG_INTR, " src_unit = %d\n", PacketP->src_unit); + rio_dprintk (RIO_DEBUG_INTR, " src_port = %d\n", PacketP->src_port); + rio_dprintk (RIO_DEBUG_INTR, " len = %d\n", PacketP->len); + rio_dprintk (RIO_DEBUG_INTR, " control = %d\n", PacketP->control); + rio_dprintk (RIO_DEBUG_INTR, " csum = %d\n", PacketP->csum); + rio_dprintk (RIO_DEBUG_INTR, " data bytes: "); for ( DataCnt=0; DataCnt<PKT_MAX_DATA_LEN; DataCnt++ ) - rio_dprint(RIO_DEBUG_INTR, ("%d\n", PacketP->data[DataCnt])); + rio_dprintk (RIO_DEBUG_INTR, "%d\n", PacketP->data[DataCnt]); remove_receive( PortP ); put_free_end( PortP->HostP, PacketP ); continue; /* with next packet */ @@ -820,8 +820,8 @@ struct Port * PortP; transCount = min(PacketP->len & PKT_LEN_MASK, TTY_FLIPBUF_SIZE - TtyP->flip.count); - rio_dprint(RIO_DEBUG_REC, ("port %d: Copy %d bytes\n", - PortP->PortNum, transCount ) ); + rio_dprintk (RIO_DEBUG_REC, "port %d: Copy %d bytes\n", + PortP->PortNum, transCount); /* ** To use the following 'kkprintfs' for debugging - change the '#undef' ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the @@ -880,7 +880,7 @@ struct Port * PortP; } } if (copied) { - rio_dprint ( RIO_DEBUG_REC, ("port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied)); + rio_dprintk (RIO_DEBUG_REC, "port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied); tty_flip_buffer_push (TtyP); } @@ -906,25 +906,25 @@ int port; SysPort = port; /* Believe me, it works. */ if ( SysPort < 0 || SysPort >= RIO_PORTS ) { - rio_dprint(RIO_DEBUG_INTR, ("Illegal port %d derived from TTY in riotproc()\n",SysPort)); + rio_dprintk (RIO_DEBUG_INTR, "Illegal port %d derived from TTY in riotproc()\n",SysPort); return 0; } PortP = p->RIOPortp[SysPort]; if ((uint)PortP->PhbP < (uint)PortP->Caddr || (uint)PortP->PhbP >= (uint)PortP->Caddr+SIXTY_FOUR_K ) { - rio_dprint(RIO_DEBUG_INTR, ("RIO: NULL or BAD PhbP on sys port %d in proc routine\n", - SysPort)); - rio_dprint(RIO_DEBUG_INTR, (" PortP = 0x%x\n",PortP)); - rio_dprint(RIO_DEBUG_INTR, (" PortP->PhbP = 0x%x\n",PortP->PhbP)); - rio_dprint(RIO_DEBUG_INTR, (" PortP->Caddr = 0x%x\n",PortP->PhbP)); - rio_dprint(RIO_DEBUG_INTR, (" PortP->HostPort = 0x%x\n",PortP->HostPort)); + rio_dprintk (RIO_DEBUG_INTR, "RIO: NULL or BAD PhbP on sys port %d in proc routine\n", + SysPort); + rio_dprintk (RIO_DEBUG_INTR, " PortP = 0x%x\n",PortP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->PhbP = 0x%x\n",PortP->PhbP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->Caddr = 0x%x\n",PortP->PhbP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->HostPort = 0x%x\n",PortP->HostPort); return 0; } switch(cmd) { case T_WFLUSH: - rio_dprint(RIO_DEBUG_INTR, "T_WFLUSH\n"); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH\n"); /* ** Because of the spooky way the RIO works, we don't need ** to issue a flush command on any of the SET*F commands, @@ -941,14 +941,14 @@ int port; ** form a wflush packet - 1 byte long, no data */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("WFLUSH on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "WFLUSH on deleted RTA\n"); } else { if ( RIOPreemptiveCmd(p, PortP, WFLUSH ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command failed\n"); } else - rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command\n"); } /* ** WFLUSH operation - flush the data! @@ -956,7 +956,7 @@ int port; PortP->TxBufferIn = PortP->TxBufferOut = 0; } else { - rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command ignored\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command ignored\n"); } /* ** sort out the line discipline @@ -966,16 +966,16 @@ int port; break; case T_RESUME: - rio_dprint(RIO_DEBUG_INTR, ("T_RESUME\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RESUME\n"); /* ** send pre-emptive resume packet */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("RESUME on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "RESUME on deleted RTA\n"); } else { if ( RIOPreemptiveCmd(p, PortP, RESUME ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_RESUME Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RESUME Command failed\n"); } } /* @@ -986,7 +986,7 @@ int port; break; case T_TIME: - rio_dprint(RIO_DEBUG_INTR, ("T_TIME\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_TIME\n"); /* ** T_TIME is called when xDLY is set in oflags and ** the line discipline timeout has expired. It's @@ -1008,16 +1008,16 @@ start: break; case T_SUSPEND: - rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_SUSPEND\n"); /* ** send a suspend pre-emptive packet. */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("SUSPEND deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "SUSPEND deleted RTA\n"); } else { if ( RIOPreemptiveCmd(p, PortP, SUSPEND ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_SUSPEND Command failed\n"); } } /* @@ -1026,18 +1026,18 @@ start: break; case T_BLOCK: - rio_dprint(RIO_DEBUG_INTR, ("T_BLOCK\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_BLOCK\n"); break; case T_RFLUSH: - rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RFLUSH\n"); if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("RFLUSH on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "RFLUSH on deleted RTA\n"); PortP->RxDataStart = 0; } else { if ( RIOPreemptiveCmd( p, PortP, RFLUSH ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RFLUSH Command failed\n"); return 0; } PortP->RxDataStart = 0; @@ -1050,14 +1050,14 @@ start: /* ** MAGIC! */ - rio_dprint(RIO_DEBUG_INTR, ("Set receive handshake bit\n")); + rio_dprintk (RIO_DEBUG_INTR, "Set receive handshake bit\n"); PortP->PhbP->handshake |= PHB_HANDSHAKE_RESET; } } break; /* FALLTHROUGH */ case T_UNBLOCK: - rio_dprint(RIO_DEBUG_INTR, ("T_UNBLOCK\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_UNBLOCK\n"); /* ** If there is any data to receive set a timeout to service it. */ @@ -1065,7 +1065,7 @@ start: break; case T_BREAK: - rio_dprint(RIO_DEBUG_INTR, ("T_BREAK\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_BREAK\n"); /* ** Send a break command. For Sys V ** this is a timed break, so we @@ -1075,12 +1075,12 @@ start: ** Build a BREAK command */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("BREAK on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "BREAK on deleted RTA\n"); } else { if (RIOShortCommand(PortP,SBREAK,2, p->RIOConf.BreakInterval)==RIO_FAIL) { - rio_dprint(RIO_DEBUG_INTR, ("SBREAK RIOShortCommand failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); } } @@ -1090,18 +1090,18 @@ start: break; case T_INPUT: - rio_dprint(RIO_DEBUG_INTR, ("Proc T_INPUT called - I don't know what to do!\n")); + rio_dprintk (RIO_DEBUG_INTR, "Proc T_INPUT called - I don't know what to do!\n"); break; case T_PARM: - rio_dprint(RIO_DEBUG_INTR, ("Proc T_PARM called - I don't know what to do!\n")); + rio_dprintk (RIO_DEBUG_INTR, "Proc T_PARM called - I don't know what to do!\n"); break; case T_SWTCH: - rio_dprint(RIO_DEBUG_INTR, ("Proc T_SWTCH called - I don't know what to do!\n")); + rio_dprintk (RIO_DEBUG_INTR, "Proc T_SWTCH called - I don't know what to do!\n"); break; default: - rio_dprint(RIO_DEBUG_INTR, ("Proc UNKNOWN command %d\n",cmd)); + rio_dprintk (RIO_DEBUG_INTR, "Proc UNKNOWN command %d\n",cmd); } /* ** T_OUTPUT returns without passing through this point! diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c index 550e2c17d..4ce8443c3 100644 --- a/drivers/char/rio/rioparam.c +++ b/drivers/char/rio/rioparam.c @@ -176,13 +176,18 @@ int SleepFlag; int retries = 0xff; unsigned long flags; + func_enter (); + TtyP = PortP->gs.tty; - rio_dprint(RIO_DEBUG_PARAM, ("RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", - PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP) ); + rio_dprintk (RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", + PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP); if (!TtyP) { - rio_dprint (RIO_DEBUG_PARAM, ("Can't call rioparam with null tty.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Can't call rioparam with null tty.\n"); + + func_exit (); + return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags ); @@ -205,7 +210,7 @@ int SleepFlag; PortP->FirstOpen = 0; } else if (PortP->Store || PortP->Lock) { - rio_dprint(RIO_DEBUG_PARAM, ("OPEN: Restoring stored/locked params\n")); + rio_dprintk (RIO_DEBUG_PARAM, "OPEN: Restoring stored/locked params\n"); TtyP->tm.c_iflag = PortP->StoredTty.iflag; TtyP->tm.c_oflag = PortP->StoredTty.oflag; TtyP->tm.c_cflag = PortP->StoredTty.cflag; @@ -226,41 +231,49 @@ int SleepFlag; break; } if ( PortP->InUse != NOT_INUSE ) { - rio_dprint(RIO_DEBUG_PARAM, ("Port IN_USE for pre-emptive command\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Port IN_USE for pre-emptive command\n"); } if ( !res ) { - rio_dprint(RIO_DEBUG_PARAM, ("Port has no space on transmit queue\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Port has no space on transmit queue\n"); } if ( SleepFlag != OK_TO_SLEEP ) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit(); + return RIO_FAIL; } - rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit\n")); + rio_dprintk (RIO_DEBUG_PARAM, "wait for can_add_transmit\n"); rio_spin_unlock_irqrestore( &PortP->portSem, flags); retval = RIODelay(PortP, HUNDRED_MS); rio_spin_lock_irqsave( &PortP->portSem, flags); if (retval == RIO_FAIL) { - rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit broken by signal\n")); + rio_dprintk (RIO_DEBUG_PARAM, "wait for can_add_transmit broken by signal\n"); rio_spin_unlock_irqrestore( &PortP->portSem, flags); pseterr(EINTR); + func_exit(); + return RIO_FAIL; } if ( PortP->State & RIO_DELETED ) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit (); + return RIO_SUCCESS; } } if (!res) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit (); + return RIO_FAIL; } - rio_dprint(RIO_DEBUG_PARAM, ("can_add_transmit() returns %x\n",res)); - rio_dprint(RIO_DEBUG_PARAM, ("Packet is 0x%x\n",(int) PacketP)); + rio_dprintk (RIO_DEBUG_PARAM, "can_add_transmit() returns %x\n",res); + rio_dprintk (RIO_DEBUG_PARAM, "Packet is 0x%x\n",(int) PacketP); phb_param_ptr = (struct phb_param *)PacketP->data; @@ -270,7 +283,7 @@ int SleepFlag; ** COR 1 */ if ( TtyP->tm.c_iflag & INPCK ) { - rio_dprint(RIO_DEBUG_PARAM, ("Parity checking on input enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Parity checking on input enabled\n"); Cor1 |= COR1_INPCK; } #endif @@ -278,53 +291,53 @@ int SleepFlag; switch ( TtyP->termios->c_cflag & CSIZE ) { case CS5: { - rio_dprint(RIO_DEBUG_PARAM, ("5 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "5 bit data\n"); Cor1 |= COR1_5BITS; break; } case CS6: { - rio_dprint(RIO_DEBUG_PARAM, ("6 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "6 bit data\n"); Cor1 |= COR1_6BITS; break; } case CS7: { - rio_dprint(RIO_DEBUG_PARAM, ("7 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "7 bit data\n"); Cor1 |= COR1_7BITS; break; } case CS8: { - rio_dprint(RIO_DEBUG_PARAM, ("8 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "8 bit data\n"); Cor1 |= COR1_8BITS; break; } } if ( TtyP->termios->c_cflag & CSTOPB ) { - rio_dprint(RIO_DEBUG_PARAM, ("2 stop bits\n")); + rio_dprintk (RIO_DEBUG_PARAM, "2 stop bits\n"); Cor1 |= COR1_2STOP; } else { - rio_dprint(RIO_DEBUG_PARAM, ("1 stop bit\n")); + rio_dprintk (RIO_DEBUG_PARAM, "1 stop bit\n"); Cor1 |= COR1_1STOP; } if ( TtyP->termios->c_cflag & PARENB ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable parity\n"); Cor1 |= COR1_NORMAL; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Disable parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Disable parity\n"); Cor1 |= COR1_NOP; } if ( TtyP->termios->c_cflag & PARODD ) { - rio_dprint(RIO_DEBUG_PARAM, ("Odd parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Odd parity\n"); Cor1 |= COR1_ODD; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Even parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Even parity\n"); Cor1 |= COR1_EVEN; } @@ -332,89 +345,89 @@ int SleepFlag; ** COR 2 */ if ( TtyP->termios->c_iflag & IXON ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop output control\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable start/stop output control\n"); Cor2 |= COR2_IXON; } else { if ( PortP->Config & RIO_IXON ) { - rio_dprint(RIO_DEBUG_PARAM, ("Force enable start/stop output control\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Force enable start/stop output control\n"); Cor2 |= COR2_IXON; } else - rio_dprint(RIO_DEBUG_PARAM, ("IXON has been disabled.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "IXON has been disabled.\n"); } if (TtyP->termios->c_iflag & IXANY) { if ( PortP->Config & RIO_IXANY ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable any key to restart output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable any key to restart output\n"); Cor2 |= COR2_IXANY; } else - rio_dprint(RIO_DEBUG_PARAM, ("IXANY has been disabled due to sanity reasons.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n"); } if ( TtyP->termios->c_iflag & IXOFF ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop input control 2\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable start/stop input control 2\n"); Cor2 |= COR2_IXOFF; } if ( TtyP->termios->c_cflag & HUPCL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Hangup on last close\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Hangup on last close\n"); Cor2 |= COR2_HUPCL; } if ( C_CRTSCTS (TtyP)) { - rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n"); Cor2 |= COR2_CTSFLOW; Cor2 |= COR2_RTSFLOW; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control disabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n"); Cor2 &= ~COR2_CTSFLOW; Cor2 &= ~COR2_RTSFLOW; } if ( TtyP->termios->c_cflag & CLOCAL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Local line\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Local line\n"); } else { - rio_dprint(RIO_DEBUG_PARAM, ("Possible Modem line\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Possible Modem line\n"); } /* ** COR 4 (there is no COR 3) */ if ( TtyP->termios->c_iflag & IGNBRK ) { - rio_dprint(RIO_DEBUG_PARAM, ("Ignore break condition\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Ignore break condition\n"); Cor4 |= COR4_IGNBRK; } if ( !(TtyP->termios->c_iflag & BRKINT) ) { - rio_dprint(RIO_DEBUG_PARAM, ("Break generates NULL condition\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Break generates NULL condition\n"); Cor4 |= COR4_NBRKINT; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Interrupt on break condition\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Interrupt on break condition\n"); } if ( TtyP->termios->c_iflag & INLCR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage return on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map newline to carriage return on input\n"); Cor4 |= COR4_INLCR; } if ( TtyP->termios->c_iflag & IGNCR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Ignore carriage return on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Ignore carriage return on input\n"); Cor4 |= COR4_IGNCR; } if ( TtyP->termios->c_iflag & ICRNL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map carriage return to newline on input\n"); Cor4 |= COR4_ICRNL; } if ( TtyP->termios->c_iflag & IGNPAR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Ignore characters with parity errors\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Ignore characters with parity errors\n"); Cor4 |= COR4_IGNPAR; } if ( TtyP->termios->c_iflag & PARMRK ) { - rio_dprint(RIO_DEBUG_PARAM, ("Mark parity errors\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Mark parity errors\n"); Cor4 |= COR4_PARMRK; } @@ -444,24 +457,24 @@ int SleepFlag; ** Could set LNE here if you wanted LNext processing. SVR4 will use it. */ if ( TtyP->termios->c_iflag & ISTRIP ) { - rio_dprint(RIO_DEBUG_PARAM, ("Strip input characters\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Strip input characters\n"); if (! (PortP->State & RIO_TRIAD_MODE)) { Cor5 |= COR5_ISTRIP; } } if ( TtyP->termios->c_oflag & ONLCR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage-return, newline on output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n"); if ( PortP->CookMode == COOK_MEDIUM ) Cor5 |= COR5_ONLCR; } if ( TtyP->termios->c_oflag & OCRNL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map carriage return to newline on output\n"); if ( PortP->CookMode == COOK_MEDIUM ) Cor5 |= COR5_OCRNL; } if ( ( TtyP->termios->c_oflag & TABDLY) == TAB3 ) { - rio_dprint(RIO_DEBUG_PARAM, ("Tab delay 3 set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Tab delay 3 set\n"); if ( PortP->CookMode == COOK_MEDIUM ) Cor5 |= COR5_TAB3; } @@ -481,8 +494,8 @@ int SleepFlag; /* ** Baud rate bytes */ - rio_dprint(RIO_DEBUG_PARAM, ("Mapping of rx/tx baud %x (%x)\n", - TtyP->termios->c_cflag, CBAUD)); + rio_dprintk (RIO_DEBUG_PARAM, "Mapping of rx/tx baud %x (%x)\n", + TtyP->termios->c_cflag, CBAUD); switch (TtyP->termios->c_cflag & CBAUD) { #define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break @@ -494,77 +507,77 @@ int SleepFlag; /* XXX MIssing conversion table. XXX */ /* (TtyP->termios->c_cflag & V_CBAUD); */ - rio_dprint(RIO_DEBUG_PARAM, ("tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud)); + rio_dprintk (RIO_DEBUG_PARAM, "tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud); /* ** Leftovers */ if ( TtyP->termios->c_cflag & CREAD ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable receiver\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable receiver\n"); #ifdef RCV1EN if ( TtyP->termios->c_cflag & RCV1EN ) - rio_dprint(RIO_DEBUG_PARAM, ("RCV1EN (?)\n")); + rio_dprintk (RIO_DEBUG_PARAM, "RCV1EN (?)\n"); #endif #ifdef XMT1EN if ( TtyP->termios->c_cflag & XMT1EN ) - rio_dprint(RIO_DEBUG_PARAM, ("XMT1EN (?)\n")); + rio_dprintk (RIO_DEBUG_PARAM, "XMT1EN (?)\n"); #endif #if 0 if ( TtyP->termios->c_cflag & LOBLK ) - rio_dprint(RIO_DEBUG_PARAM, ("LOBLK - JCL output blocks when not current\n")); + rio_dprintk (RIO_DEBUG_PARAM, "LOBLK - JCL output blocks when not current\n"); #endif if ( TtyP->termios->c_lflag & ISIG ) - rio_dprint(RIO_DEBUG_PARAM, ("Input character signal generating enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Input character signal generating enabled\n"); if ( TtyP->termios->c_lflag & ICANON ) - rio_dprint(RIO_DEBUG_PARAM, ("Canonical input: erase and kill enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Canonical input: erase and kill enabled\n"); if ( TtyP->termios->c_lflag & XCASE ) - rio_dprint(RIO_DEBUG_PARAM, ("Canonical upper/lower presentation\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Canonical upper/lower presentation\n"); if ( TtyP->termios->c_lflag & ECHO ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable input echo\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable input echo\n"); if ( TtyP->termios->c_lflag & ECHOE ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable echo erase\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable echo erase\n"); if ( TtyP->termios->c_lflag & ECHOK ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable echo kill\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable echo kill\n"); if ( TtyP->termios->c_lflag & ECHONL ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable echo newline\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable echo newline\n"); if ( TtyP->termios->c_lflag & NOFLSH ) - rio_dprint(RIO_DEBUG_PARAM, ("Disable flush after interrupt or quit\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Disable flush after interrupt or quit\n"); #ifdef TOSTOP if ( TtyP->termios->c_lflag & TOSTOP ) - rio_dprint(RIO_DEBUG_PARAM, ("Send SIGTTOU for background output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Send SIGTTOU for background output\n"); #endif #ifdef XCLUDE if ( TtyP->termios->c_lflag & XCLUDE ) - rio_dprint(RIO_DEBUG_PARAM, ("Exclusive use of this line\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Exclusive use of this line\n"); #endif if ( TtyP->termios->c_iflag & IUCLC ) - rio_dprint(RIO_DEBUG_PARAM, ("Map uppercase to lowercase on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map uppercase to lowercase on input\n"); if ( TtyP->termios->c_oflag & OPOST ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable output post-processing\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable output post-processing\n"); if ( TtyP->termios->c_oflag & OLCUC ) - rio_dprint(RIO_DEBUG_PARAM, ("Map lowercase to uppercase on output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map lowercase to uppercase on output\n"); if ( TtyP->termios->c_oflag & ONOCR ) - rio_dprint(RIO_DEBUG_PARAM, ("No carriage return output at column 0\n")); + rio_dprintk (RIO_DEBUG_PARAM, "No carriage return output at column 0\n"); if ( TtyP->termios->c_oflag & ONLRET ) - rio_dprint(RIO_DEBUG_PARAM, ("Newline performs carriage return function\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Newline performs carriage return function\n"); if ( TtyP->termios->c_oflag & OFILL ) - rio_dprint(RIO_DEBUG_PARAM, ("Use fill characters for delay\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Use fill characters for delay\n"); if ( TtyP->termios->c_oflag & OFDEL ) - rio_dprint(RIO_DEBUG_PARAM, ("Fill character is DEL\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Fill character is DEL\n"); if ( TtyP->termios->c_oflag & NLDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Newline delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Newline delay set\n"); if ( TtyP->termios->c_oflag & CRDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Carriage return delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Carriage return delay set\n"); if ( TtyP->termios->c_oflag & TABDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Tab delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Tab delay set\n"); #if 0 if ( TtyP->termios->c_oflag & BSDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Back-space delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Back-space delay set\n"); if ( TtyP->termios->c_oflag & VTDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Vertical tab delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Vertical tab delay set\n"); if ( TtyP->termios->c_oflag & FFDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Form-feed delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Form-feed delay set\n"); #endif /* ** These things are kind of useful in a later life! @@ -573,6 +586,8 @@ int SleepFlag; if ( PortP->State & RIO_DELETED ) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit (); + return RIO_FAIL; } @@ -610,10 +625,12 @@ int SleepFlag; rio_spin_unlock_irqrestore( &PortP->portSem, flags); - rio_dprint(RIO_DEBUG_PARAM, ("add_transmit returned.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "add_transmit returned.\n"); /* ** job done. */ + func_exit (); + return RIO_SUCCESS; } @@ -644,7 +661,7 @@ add_transmit(PortP) struct Port *PortP; { if (RWORD(*PortP->TxAdd) & PKT_IN_USE) { - rio_dprint (RIO_DEBUG_PARAM, ("add_transmit: Packet has been stolen!")); + rio_dprintk (RIO_DEBUG_PARAM, "add_transmit: Packet has been stolen!"); } WWORD( *(ushort *)PortP->TxAdd, RWORD(*PortP->TxAdd) | PKT_IN_USE); PortP->TxAdd = (PortP->TxAdd == PortP->TxEnd) ? PortP->TxStart : @@ -672,7 +689,7 @@ PKT *PktP; * ************************************************/ - rio_dprint(RIO_DEBUG_PFE, ("put_free_end(PktP=%x)\n",(int)PktP)); + rio_dprintk (RIO_DEBUG_PFE, "put_free_end(PktP=%x)\n",(int)PktP); if ((old_end=RWORD(HostP->ParmMapP->free_list_end)) != TPNULL) { new_end = RIO_OFF(HostP->Caddr,PktP); @@ -683,12 +700,13 @@ PKT *PktP; WWORD(HostP->ParmMapP->free_list_end, new_end); } else { /* First packet on the free list this should never happen! */ - rio_dprint(RIO_DEBUG_PFE, ("put_free_end(): This should never happen\n")); + rio_dprintk (RIO_DEBUG_PFE, "put_free_end(): This should never happen\n"); WWORD(HostP->ParmMapP->free_list_end , RIO_OFF(HostP->Caddr,PktP)); tmp_pointer = (FREE_LIST *)PktP; WWORD(tmp_pointer->prev , TPNULL); WWORD(tmp_pointer->next , TPNULL); } + rio_dprintk (RIO_DEBUG_CMD, "Before unlock: %p\n", &HostP->HostLock); rio_spin_unlock_irqrestore(&HostP->HostLock, flags); } diff --git a/drivers/char/rio/rioroute.c b/drivers/char/rio/rioroute.c index 2f13eb273..ab78ddf5d 100644 --- a/drivers/char/rio/rioroute.c +++ b/drivers/char/rio/rioroute.c @@ -178,8 +178,8 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP if ( Lies ) { - rio_dprint(RIO_DEBUG_ROUTE, ("LIES! DAMN LIES! %d LIES!\n",Lies)); - rio_dprint(RIO_DEBUG_ROUTE, ("%d:%c %d:%c %d:%c %d:%c\n", + rio_dprintk (RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n",Lies); + rio_dprintk (RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n", RBYTE(PktCmdP->RouteTopology[0].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[0].Link), RBYTE(PktCmdP->RouteTopology[1].Unit), @@ -187,7 +187,7 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP RBYTE(PktCmdP->RouteTopology[2].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[2].Link), RBYTE(PktCmdP->RouteTopology[3].Unit), - 'A'+RBYTE(PktCmdP->RouteTopology[3].Link))); + 'A'+RBYTE(PktCmdP->RouteTopology[3].Link)); return TRUE; } @@ -219,11 +219,11 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT ) { - rio_dprint(RIO_DEBUG_ROUTE, ("I have a link from %s %s to unit %d:%d - I don't like it.\n", + rio_dprintk (RIO_DEBUG_ROUTE, "I have a link from %s %s to unit %d:%d - I don't like it.\n", MyType, MyName, NewUnit, - NewLink)); + NewLink); } else { @@ -248,8 +248,8 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP RIOConCon(p,HostP,ThisUnit,ThisLink,NewUnit,NewLink,CONNECT); if ( NewUnit == ROUTE_NO_ID ) - rio_dprint(RIO_DEBUG_ROUTE, ("%s %s (%c) is connected to an unconfigured unit.\n", - MyType,MyName,'A'+ThisLink)); + rio_dprintk (RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", + MyType,MyName,'A'+ThisLink); if ( NewUnit == ROUTE_INTERCONNECT ) { @@ -267,14 +267,14 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP if ( HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink ) { - rio_dprint(RIO_DEBUG_ROUTE, ("SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A'); HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT; HostP->Topology[OldLink].Link = NO_LINK; } else { - rio_dprint(RIO_DEBUG_ROUTE, ("HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", - OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", + OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } else if ( OldUnit <= MAX_RUP ) @@ -282,29 +282,29 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP if ( HostP->Mapping[OldUnit-1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit-1].Topology[OldLink].Link == ThisLink ) { - rio_dprint(RIO_DEBUG_ROUTE, ("SETTING RTA %s (%c) TO DISCONNECTED!\n", - HostP->Mapping[OldUnit-1].Name,OldLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", + HostP->Mapping[OldUnit-1].Name,OldLink+'A'); HostP->Mapping[OldUnit-1].Topology[OldLink].Unit=ROUTE_DISCONNECT; HostP->Mapping[OldUnit-1].Topology[OldLink].Link=NO_LINK; } else { - rio_dprint(RIO_DEBUG_ROUTE, ("RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", + rio_dprintk (RIO_DEBUG_ROUTE, "RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", HostP->Mapping[OldUnit-1].Name,OldLink+'A', - HostP->Mapping[ThisUnit-1].Name,ThisLink+'A')); + HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } if ( NewUnit == HOST_ID ) { - rio_dprint(RIO_DEBUG_ROUTE, ("MARKING HOST (%c) CONNECTED TO %s (%c)\n", - NewLink+'A',MyName,ThisLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", + NewLink+'A',MyName,ThisLink+'A'); HostP->Topology[NewLink].Unit = ThisUnit; HostP->Topology[NewLink].Link = ThisLink; } else if ( NewUnit <= MAX_RUP ) { - rio_dprint(RIO_DEBUG_ROUTE, ("MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", - HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", + HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A'); HostP->Mapping[NewUnit-1].Topology[NewLink].Unit=ThisUnit; HostP->Mapping[NewUnit-1].Topology[NewLink].Link=ThisLink; } @@ -321,8 +321,8 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP */ if ( RBYTE(PktCmdP->Command) != ROUTE_REQUEST ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Unknown command %d received on rup %d host %d ROUTE_RUP\n", - RBYTE(PktCmdP->Command),Rup,(int)HostP)); + rio_dprintk (RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %d ROUTE_RUP\n", + RBYTE(PktCmdP->Command),Rup,(int)HostP); return TRUE; } @@ -336,7 +336,7 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP */ RtaType = GetUnitType(RtaUniq); - rio_dprint(RIO_DEBUG_ROUTE, ("Received a request for an ID for serial number %x\n", RtaUniq)); + rio_dprintk (RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq); Mod = RBYTE(PktCmdP->ModuleTypes); Mod1 = LONYBLE(Mod); @@ -347,14 +347,14 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP ** with 8 port, set 2nd ident in Mod2 to the same as Mod1. */ Mod2 = Mod1; - rio_dprint(RIO_DEBUG_ROUTE, ("Backplane type is %s (all ports)\n", - p->RIOModuleTypes[Mod1].Name )); + rio_dprintk (RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", + p->RIOModuleTypes[Mod1].Name); } else { Mod2 = HINYBLE(Mod); - rio_dprint(RIO_DEBUG_ROUTE, ("Module types are %s (ports 0-3) and %s (ports 4-7)\n", - p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name )); + rio_dprintk (RIO_DEBUG_ROUTE, "Module types are %s (ports 0-3) and %s (ports 4-7)\n", + p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name); } if ( RtaUniq == 0xffffffff ) @@ -367,7 +367,7 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP */ if ( !(CmdBlkP = RIOGetCmdBlk()) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("No command blocks to route RTA! come back later.\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n"); return 0; } @@ -384,8 +384,8 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP if (! RIOBootOk(p, HostP, RtaUniq)) { - rio_dprint(RIO_DEBUG_ROUTE, ("RTA %x tried to get an ID, but does not belong - FOAD it!\n", - RtaUniq)); + rio_dprintk (RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", + RtaUniq); PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); @@ -397,13 +397,13 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP */ for ( ThisUnit=0; ThisUnit<MAX_RUP; ThisUnit++ ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Entry %d Flags=%s %s UniqueNum=0x%x\n", + rio_dprintk (RIO_DEBUG_ROUTE, "Entry %d Flags=%s %s UniqueNum=0x%x\n", ThisUnit, HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ? "Slot-In-Use":"Not In Use", HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? "Slot-Tentative":"Not Tentative", - HostP->Mapping[ThisUnit].RtaUniqueNum )); + HostP->Mapping[ThisUnit].RtaUniqueNum); /* ** We have an entry for it. @@ -414,12 +414,12 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP if (RtaType == TYPE_RTA16) { ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1; - rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slots %d+%d\n", - RtaUniq,ThisUnit,ThisUnit2)); + rio_dprintk (RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", + RtaUniq,ThisUnit,ThisUnit2); } else - rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slot %d\n", - RtaUniq,ThisUnit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", + RtaUniq,ThisUnit); /* ** If we have no knowledge of booting it, then the host has ** been re-booted, and so we must kill the RTA, so that it @@ -458,14 +458,14 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP */ RIOFixPhbs(p, HostP, ThisUnit2); PktReplyP->IDNum2 = ThisUnit2+1; - rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated IDs %d+%d\n", - HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2)); + rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", + HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2); } else { PktReplyP->IDNum2 = ROUTE_NO_ID; - rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated ID %d\n", - HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum)); + rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", + HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum); } HostP->Copy("RT_ALLOCAT",PktReplyP->CommandText,10); @@ -489,7 +489,7 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -502,7 +502,7 @@ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -628,7 +628,7 @@ uint unit; unsigned long flags; int PortN = HostP->Mapping[unit].SysPort; - rio_dprint(RIO_DEBUG_ROUTE, ("RIOFixPhbs unit %d sysport %d\n", unit, PortN)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN); if (PortN != -1) { ushort dest_unit = HostP->Mapping[unit].ID2; @@ -656,7 +656,7 @@ uint unit; ** unset, so go no further. */ if (PortP->TxStart == 0) { - rio_dprint(RIO_DEBUG_ROUTE, ("Tx pkts not set up yet\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n"); break; } @@ -691,10 +691,10 @@ uint unit; WBYTE(Pkt->dest_unit, dest_unit); WBYTE(Pkt->dest_port, dest_port); } - rio_dprint(RIO_DEBUG_ROUTE, ("phb dest: Old %x:%x New %x:%x\n", + rio_dprintk (RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", RWORD(PortP->PhbP->destination) & 0xff, (RWORD(PortP->PhbP->destination) >> 8) & 0xff, - dest_unit, dest_port)); + dest_unit, dest_port); WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8)); WWORD(PortP->PhbP->link, link); @@ -706,7 +706,7 @@ uint unit; */ if (link > 3) return; if (((unit * 8) + 7) > RWORD(HostP->LinkStrP[link].last_port)) { - rio_dprint(RIO_DEBUG_ROUTE, ("last port on host link %d: %d\n", link, (unit * 8) + 7)); + rio_dprintk (RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7); WWORD(HostP->LinkStrP[link].last_port, (unit * 8) + 7); } } @@ -732,7 +732,7 @@ uint UnitId; CheckUnitId( UnitId ); #endif if ( RIOCheck( HostP, UnitId ) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated\n",UnitId)); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit %d is NOT isolated\n", UnitId); rio_spin_unlock_irqrestore(&HostP->HostLock, flags); return(0); } @@ -771,7 +771,7 @@ uint UnitId; HostP->Mapping[UnitId].Flags |= BEEN_HERE; if ( p->RIOPrintDisabled == DO_PRINT ) - rio_dprint(RIO_DEBUG_ROUTE, ("RIOMesgIsolated %s",HostP->Mapping[UnitId].Name)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOMesgIsolated %s", HostP->Mapping[UnitId].Name); for ( link=0; link<LINKS_PER_UNIT; link++) { unit = HostP->Mapping[UnitId].Topology[link].Unit; @@ -795,7 +795,7 @@ uint UnitId; CheckUnitId( UnitId ); #endif /* rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */ - rio_dprint(RIO_DEBUG_ROUTE, ("RIOCheck : UnitID = %d\n",UnitId)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOCheck : UnitID = %d\n", UnitId); if ( UnitId == HOST_ID ) { /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */ @@ -854,16 +854,16 @@ uint Uniq; case RIO_MCA: case RIO_EISA: case RIO_PCI: - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Host\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: Host\n"); return(TYPE_HOST); case RIO_RTA_16: - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 16 port RTA\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: 16 port RTA\n"); return(TYPE_RTA16); case RIO_RTA: - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 8 port RTA\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: 8 port RTA\n"); return(TYPE_RTA8); default : - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Unrecognised\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: Unrecognised\n"); return(99); } } @@ -876,7 +876,7 @@ struct rio_info * p; return(0); p->RIOQuickCheck = CHANGED; if ( p->RIOSignalProcess ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Send SIG-HUP")); + rio_dprintk (RIO_DEBUG_ROUTE, "Send SIG-HUP"); /* psignal( RIOSignalProcess, SIGHUP ); */ @@ -951,10 +951,10 @@ int Change; ToName = ToId ? HostP->Mapping[ToId-1].Name : HostP->Name; ToType = ToId ? "RTA" : "HOST"; - rio_dprint(RIO_DEBUG_ROUTE, ("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", + rio_dprintk (RIO_DEBUG_ROUTE, "Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A'+FromLink, ToType, ToName, 'A'+ToLink, - (Change==CONNECT) ? "established" : "disconnected")); + (Change==CONNECT) ? "established" : "disconnected"); cprintf("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A'+FromLink, ToType, ToName, 'A'+ToLink, @@ -1000,7 +1000,7 @@ RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit) int link; - rio_dprint(RIO_DEBUG_ROUTE, ("RIOFreeDisconnect unit %d\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOFreeDisconnect unit %d\n", unit); /* ** If the slot is tentative and does not belong to the ** second half of a 16 port RTA then scan to see if @@ -1023,17 +1023,17 @@ RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit) ** made this slot tentative and not yet received a topology update. ** Lets check how long ago we made it tentative. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Just about to check LBOLT on entry %d\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Just about to check LBOLT on entry %d\n", unit); if (drv_getparm(LBOLT, (ulong_t *) ¤t_time)) - rio_dprint(RIO_DEBUG_ROUTE, ("drv_getparm(LBOLT,....) Failed.\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "drv_getparm(LBOLT,....) Failed.\n"); elapse_time = current_time - TentTime[unit]; - rio_dprint(RIO_DEBUG_ROUTE, ("elapse %d = current %d - tent %d (%d usec)\n", - elapse_time, current_time, TentTime[unit],drv_hztousec(elapse_time))); + rio_dprintk (RIO_DEBUG_ROUTE, "elapse %d = current %d - tent %d (%d usec)\n", + elapse_time, current_time, TentTime[unit], drv_hztousec(elapse_time)); if (drv_hztousec(elapse_time) < WAIT_TO_FINISH) { - rio_dprint(RIO_DEBUG_ROUTE, ("Skipping slot %d, not timed out yet %d\n" - ,unit,drv_hztousec(elapse_time))); + rio_dprintk (RIO_DEBUG_ROUTE, "Skipping slot %d, not timed out yet %d\n", + unit, drv_hztousec(elapse_time)); return 1; } #endif @@ -1046,7 +1046,7 @@ RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit) { int nOther = (HostP->Mapping[unit].ID2) -1; - rio_dprint(RIO_DEBUG_ROUTE, ("RioFreedis second slot %d.\n",nOther)); + rio_dprintk (RIO_DEBUG_ROUTE, "RioFreedis second slot %d.\n", nOther); bzero((caddr_t)&HostP->Mapping[nOther], sizeof(struct Map)); } RIORemoveFromSavedTable(p, &HostP->Mapping[unit]); @@ -1082,19 +1082,19 @@ RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2) */ for (unit = 0; unit < MAX_RUP; unit++) { - rio_dprint(RIO_DEBUG_ROUTE, ("Scanning unit %d\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Scanning unit %d\n",unit); /* ** If the flags are zero then the slot is empty. */ if (HostP->Mapping[unit].Flags == 0) { - rio_dprint(RIO_DEBUG_ROUTE, (" This slot is empty.\n")); + rio_dprintk (RIO_DEBUG_ROUTE, " This slot is empty.\n"); /* ** If we haven't allocated the first ID then do it now. */ if (*pID1 == MAX_RUP) { - rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for first unit %d\n", unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Make tentative entry for first unit %d\n", unit); *pID1 = unit; /* @@ -1109,7 +1109,7 @@ RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2) /* ** Allocate the second slot and return. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for second unit %d\n", unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Make tentative entry for second unit %d\n", unit); *pID2 = unit; return 0; } @@ -1121,18 +1121,18 @@ RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2) ** need to start all over again looking for tentative slots ** that we can re-use. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Starting to scan for tentative slots\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Starting to scan for tentative slots\n"); for (unit = 0; unit < MAX_RUP; unit++) { if (((HostP->Mapping[unit].Flags & SLOT_TENTATIVE) || (HostP->Mapping[unit].Flags == 0)) && ! (HostP->Mapping[unit].Flags & RTA16_SECOND_SLOT )) { - rio_dprint(RIO_DEBUG_ROUTE, (" Slot %d looks promising.\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, " Slot %d looks promising.\n",unit); if(unit == *pID1) { - rio_dprint(RIO_DEBUG_ROUTE, (" No it isn't, its the 1st half\n")); + rio_dprintk (RIO_DEBUG_ROUTE, " No it isn't, its the 1st half\n"); continue; } @@ -1152,7 +1152,7 @@ RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2) */ if (*pID1 == MAX_RUP) { - rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative entry for first unit %d\n", unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Grab tentative entry for first unit %d\n", unit); *pID1 = unit; /* @@ -1172,8 +1172,8 @@ RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2) /* ** Allocate the second slot and return. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative/empty entry for second unit %d\n", - unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Grab tentative/empty entry for second unit %d\n", + unit); *pID2 = unit; /* @@ -1190,7 +1190,7 @@ RIOFindFreeID(struct rio_info *p, struct Host *HostP, uint *pID1, uint *pID2) if (*pID1 > *pID2) { - rio_dprint(RIO_DEBUG_ROUTE, ("Swapping IDS %d %d\n",*pID1,*pID2)); + rio_dprintk (RIO_DEBUG_ROUTE, "Swapping IDS %d %d\n", *pID1, *pID2); tempID = *pID1; *pID1 = *pID2; *pID2 = tempID; diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c index 6329a6e18..2b82c25ad 100644 --- a/drivers/char/rio/riotable.c +++ b/drivers/char/rio/riotable.c @@ -120,7 +120,7 @@ struct rio_info * p; ** (9) That names aren't duplicated ** xx (10) That hosts that actually exist are mentioned in the table. xx */ - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(1)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(1)\n"); if ( p->RIOSystemUp ) { /* (1) */ p->RIOError.Error = HOST_HAS_ALREADY_BEEN_BOOTED; return EBUSY; @@ -133,7 +133,7 @@ struct rio_info * p; for ( Entry=0; Entry<TOTAL_MAP_ENTRIES; Entry++ ) { MapP = &p->RIOConnectTable[Entry]; if ((MapP->Flags & RTA16_SECOND_SLOT) == 0) { - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(2)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(2)\n"); cptr = MapP->Name; /* (2) */ cptr[MAX_NAME_LEN-1]='\0'; if ( cptr[0]=='\0' ) { @@ -161,19 +161,19 @@ struct rio_info * p; continue; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(3)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(3)\n"); if ( !MapP->RtaUniqueNum && !MapP->HostUniqueNum ) { /* (3) */ if ( MapP->ID || MapP->SysPort || MapP->Flags ) { - rio_dprint(RIO_DEBUG_TABLE, ("%s pretending to be empty but isn't\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "%s pretending to be empty but isn't\n",MapP->Name); p->RIOError.Error = TABLE_ENTRY_ISNT_PROPERLY_NULL; p->RIOError.Entry = Entry; return ENXIO; } - rio_dprint(RIO_DEBUG_TABLE, ("!RIO: Daemon: test (3) passes\n")); + rio_dprintk (RIO_DEBUG_TABLE, "!RIO: Daemon: test (3) passes\n"); continue; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(4)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(4)\n"); for ( Host=0; Host<p->RIONumHosts; Host++ ) { /* (4) */ if ( p->RIOHosts[Host].UniqueNum==MapP->HostUniqueNum ) { HostP = &p->RIOHosts[Host]; @@ -187,8 +187,8 @@ struct rio_info * p; } if ( Host >= p->RIONumHosts ) { - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has unknown host unique number 0x%x\n", - MapP->Name,MapP->HostUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s has unknown host unique number 0x%x\n", + MapP->Name, MapP->HostUniqueNum); MapP->HostUniqueNum = 0; /* MapP->RtaUniqueNum = 0; */ /* MapP->ID = 0; */ @@ -198,18 +198,18 @@ struct rio_info * p; continue; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(5)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(5)\n"); if ( MapP->RtaUniqueNum ) { /* (5) */ if ( !MapP->ID ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an ID of zero!\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an ID of zero!\n", + MapP->Name); p->RIOError.Error = ZERO_RTA_ID; p->RIOError.Entry = Entry; return ENXIO; } if ( MapP->ID > MAX_RUP ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an illegal ID %d\n", - MapP->Name, MapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an illegal ID %d\n", + MapP->Name, MapP->ID); p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE; p->RIOError.Entry = Entry; return ENXIO; @@ -218,8 +218,8 @@ struct rio_info * p; if ( MapP->HostUniqueNum == p->RIOConnectTable[SubEnt].HostUniqueNum && MapP->ID == p->RIOConnectTable[SubEnt].ID ) { - rio_dprint(RIO_DEBUG_TABLE, ("Dupl. ID number allocated to RTA %s and RTA %s\n", - MapP->Name,p->RIOConnectTable[SubEnt].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Dupl. ID number allocated to RTA %s and RTA %s\n", + MapP->Name, p->RIOConnectTable[SubEnt].Name); p->RIOError.Error = DUPLICATED_RTA_ID; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; @@ -232,29 +232,29 @@ struct rio_info * p; if ((MapP->RtaUniqueNum == p->RIOConnectTable[SubEnt].RtaUniqueNum) && (MapP->ID2 != p->RIOConnectTable[SubEnt].ID)) { - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",MapP->Name)); - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n", - p->RIOConnectTable[SubEnt].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n",MapP->Name); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n", + p->RIOConnectTable[SubEnt].Name); p->RIOError.Error = DUPLICATE_UNIQUE_NUMBER; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; return ENXIO; } } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7a)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(7a)\n"); /* (7a) */ if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort % PORTS_PER_RTA)) { - rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d-RTA %s is not a multiple of %d!\n", - (int)MapP->SysPort,MapP->Name,PORTS_PER_RTA)); + rio_dprintk (RIO_DEBUG_TABLE, "TTY Port number %d-RTA %s is not a multiple of %d!\n", + (int)MapP->SysPort,MapP->Name, PORTS_PER_RTA); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; p->RIOError.Entry = Entry; return ENXIO; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7b)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(7b)\n"); /* (7b) */ if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort >= RIO_PORTS)) { - rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d for RTA %s is too big\n", - (int)MapP->SysPort,MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "TTY Port number %d for RTA %s is too big\n", + (int)MapP->SysPort, MapP->Name); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; p->RIOError.Entry = Entry; return ENXIO; @@ -263,22 +263,22 @@ struct rio_info * p; if ( p->RIOConnectTable[SubEnt].Flags & RTA16_SECOND_SLOT ) continue; if ( p->RIOConnectTable[SubEnt].RtaUniqueNum ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(8)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(8)\n"); /* (8) */ if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort == p->RIOConnectTable[SubEnt].SysPort) ) { - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s:same TTY port # as RTA %s (%d)\n", + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s:same TTY port # as RTA %s (%d)\n", MapP->Name, p->RIOConnectTable[SubEnt].Name, - (int)MapP->SysPort)); + (int)MapP->SysPort); p->RIOError.Error = TTY_NUMBER_IN_USE; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; return ENXIO; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(9)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(9)\n"); if (RIOStrCmp(MapP->Name, p->RIOConnectTable[SubEnt].Name)==0 && !(MapP->Flags & RTA16_SECOND_SLOT)) { /* (9) */ - rio_dprint(RIO_DEBUG_TABLE, ("RTA name %s used twice\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA name %s used twice\n", MapP->Name); p->RIOError.Error = NAME_USED_TWICE; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; @@ -288,17 +288,17 @@ struct rio_info * p; } } else { /* (6) */ - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(6)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(6)\n"); if ( MapP->ID ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO:HOST %s has been allocated ID that isn't zero!\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO:HOST %s has been allocated ID that isn't zero!\n", + MapP->Name); p->RIOError.Error = HOST_ID_NOT_ZERO; p->RIOError.Entry = Entry; return ENXIO; } if ( MapP->SysPort != NO_PORT ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO: HOST %s has been allocated port numbers!\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO: HOST %s has been allocated port numbers!\n", + MapP->Name); p->RIOError.Error = HOST_SYSPORT_BAD; p->RIOError.Entry = Entry; return ENXIO; @@ -326,7 +326,7 @@ struct rio_info * p; ** Copy in the new table entries */ for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: Copy table for Host entry %d\n", Entry)); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: Copy table for Host entry %d\n", Entry); MapP = &p->RIOConnectTable[Entry]; /* @@ -344,7 +344,7 @@ struct rio_info * p; ** If it is a host, then we only need to fill in the name field. */ if ( MapP->ID==0 ) { - rio_dprint(RIO_DEBUG_TABLE, ("Host entry found. Name %s\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Host entry found. Name %s\n", MapP->Name); bcopy(MapP->Name,HostP->Name,MAX_NAME_LEN); continue; } @@ -357,7 +357,7 @@ struct rio_info * p; HostMapP = &HostP->Mapping[MapP->ID-1]; if (MapP->Flags & SLOT_IN_USE) { - rio_dprint(RIO_DEBUG_TABLE, ("Rta entry found. Name %s\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Rta entry found. Name %s\n", MapP->Name); /* ** structure assign, then sort out the bits we shouldn't have done */ @@ -370,7 +370,7 @@ struct rio_info * p; RIOReMapPorts(p, HostP, HostMapP ); } else { - rio_dprint(RIO_DEBUG_TABLE, ("TENTATIVE Rta entry found. Name %s\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "TENTATIVE Rta entry found. Name %s\n", MapP->Name); } } @@ -420,11 +420,11 @@ struct rio_info * p; */ if (Host1 != Host) { - rio_dprint(RIO_DEBUG_TABLE, ("Default name %s already used\n", p->RIOHosts[Host].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Default name %s already used\n", p->RIOHosts[Host].Name); bcopy("HOST 1",p->RIOHosts[Host].Name,7); p->RIOHosts[Host].Name[5] += Host1; } - rio_dprint(RIO_DEBUG_TABLE, ("Assigning default name %s\n", p->RIOHosts[Host].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Assigning default name %s\n", p->RIOHosts[Host].Name); } return 0; } @@ -447,13 +447,13 @@ struct rio_info * p; disable(oldspl); /* strange but true! */ - rio_dprint(RIO_DEBUG_TABLE, ("Generating a table to return to config.rio\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Generating a table to return to config.rio\n"); bzero((caddr_t)&p->RIOConnectTable[0], sizeof(struct Map) * TOTAL_MAP_ENTRIES ); for ( Host=0; Host<RIO_HOSTS; Host++ ) { - rio_dprint(RIO_DEBUG_TABLE, ("Processing host %d\n", Host)); + rio_dprintk (RIO_DEBUG_TABLE, "Processing host %d\n", Host); HostP = &p->RIOHosts[Host]; MapP = &p->RIOConnectTable[Next++]; MapP->HostUniqueNum = HostP->UniqueNum; @@ -501,8 +501,8 @@ struct Map *MapP; int work_done = 0; unsigned long flags; - rio_dprint(RIO_DEBUG_TABLE, ("Delete entry on host %x, rta %x\n", - MapP->HostUniqueNum,MapP->RtaUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "Delete entry on host %x, rta %x\n", + MapP->HostUniqueNum, MapP->RtaUniqueNum); for ( host=0; host < p->RIONumHosts; host++ ) { HostP = &p->RIOHosts[host]; @@ -517,15 +517,15 @@ struct Map *MapP; for ( entry=0; entry<MAX_RUP; entry++ ) { if ( MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum ) { HostMapP = &HostP->Mapping[entry]; - rio_dprint(RIO_DEBUG_TABLE, ("Found entry offset %d on host %s\n", - entry,HostP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Found entry offset %d on host %s\n", + entry, HostP->Name); /* ** Check all four links of the unit are disconnected */ for ( link=0; link< LINKS_PER_UNIT; link++ ) { if ( HostMapP->Topology[link].Unit != ROUTE_DISCONNECT ) { - rio_dprint(RIO_DEBUG_TABLE, ("Entry is in use and cannot be deleted!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Entry is in use and cannot be deleted!\n"); p->RIOError.Error = UNIT_IS_IN_USE; rio_spin_unlock_irqrestore( &HostP->HostLock, flags); return EBUSY; @@ -540,7 +540,7 @@ struct Map *MapP; if ( SysPort != NO_PORT ) { for (port=SysPort; port < SysPort+PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port]; - rio_dprint(RIO_DEBUG_TABLE, ("Unmap port\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Unmap port\n"); rio_spin_lock_irqsave( &PortP->portSem, flags ); @@ -548,7 +548,7 @@ struct Map *MapP; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { - rio_dprint(RIO_DEBUG_TABLE, ("Gob on port\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Gob on port\n"); PortP->TxBufferIn = PortP->TxBufferOut = 0; /* What should I do wakeup( &PortP->TxBufferIn ); @@ -585,25 +585,25 @@ struct Map *MapP; */ Pkt = (PKT *) RIO_PTR(HostP->Caddr, RWORD(*TxPktP)); - rio_dprint(RIO_DEBUG_TABLE, ( + rio_dprintk (RIO_DEBUG_TABLE, "Tx packet (%x) destination: Old %x:%x New %x:%x\n", *TxPktP, Pkt->dest_unit, - Pkt->dest_port, dest_unit, dest_port)); + Pkt->dest_port, dest_unit, dest_port); WWORD(Pkt->dest_unit, dest_unit); WWORD(Pkt->dest_port, dest_port); } - rio_dprint(RIO_DEBUG_TABLE, ( + rio_dprintk (RIO_DEBUG_TABLE, "Port %d phb destination: Old %x:%x New %x:%x\n", port, PortP->PhbP->destination & 0xff, (PortP->PhbP->destination >> 8) & 0xff, - dest_unit, dest_port)); + dest_unit, dest_port); WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8)); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } - rio_dprint(RIO_DEBUG_TABLE, ("Entry nulled.\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Entry nulled.\n"); bzero((char *)HostMapP,sizeof(struct Map)); work_done++; } @@ -625,7 +625,7 @@ struct Map *MapP; if ( work_done ) return 0; - rio_dprint(RIO_DEBUG_TABLE, ("Couldn't find entry to be deleted\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Couldn't find entry to be deleted\n"); p->RIOError.Error = COULDNT_FIND_ENTRY; return ENXIO; } @@ -638,32 +638,32 @@ int RIOAssignRta( struct rio_info *p, struct Map *MapP ) int link; - rio_dprint(RIO_DEBUG_TABLE, ("Assign entry on host %x, rta %x, ID %d, Sysport %d\n", + rio_dprintk (RIO_DEBUG_TABLE, "Assign entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum,MapP->RtaUniqueNum, - MapP->ID, (int)MapP->SysPort )); + MapP->ID, (int)MapP->SysPort); if ((MapP->ID != (ushort)-1) && ((int)MapP->ID < (int)1 || (int)MapP->ID > MAX_RUP )) { - rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Bad ID in map entry!\n"); p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE; return EINVAL; } if (MapP->RtaUniqueNum == 0) { - rio_dprint(RIO_DEBUG_TABLE, ("Rta Unique number zero!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Rta Unique number zero!\n"); p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO; return EINVAL; } if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA) ) { - rio_dprint(RIO_DEBUG_TABLE, ("Port %d not multiple of %d!\n",(int)MapP->SysPort,PORTS_PER_RTA)); + rio_dprintk (RIO_DEBUG_TABLE, "Port %d not multiple of %d!\n",(int)MapP->SysPort,PORTS_PER_RTA); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; return EINVAL; } if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS) ) { - rio_dprint(RIO_DEBUG_TABLE, ("Port %d not valid!\n",(int)MapP->SysPort)); + rio_dprintk (RIO_DEBUG_TABLE, "Port %d not valid!\n",(int)MapP->SysPort); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -677,7 +677,7 @@ int RIOAssignRta( struct rio_info *p, struct Map *MapP ) { if ( *sptr<' ' || *sptr>'~' ) { - rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n"); p->RIOError.Error = BAD_CHARACTER_IN_NAME; return EINVAL; } @@ -702,8 +702,8 @@ int RIOAssignRta( struct rio_info *p, struct Map *MapP ) { int nNewID; - rio_dprint(RIO_DEBUG_TABLE, ("Attempting to get a new ID for rta \"%s\"\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Attempting to get a new ID for rta \"%s\"\n", + MapP->Name); /* ** The idea here is to allow RTA's to be assigned ** before they actually appear on the network. @@ -721,7 +721,7 @@ int RIOAssignRta( struct rio_info *p, struct Map *MapP ) return EBUSY; } MapP->ID = (ushort)nNewID + 1; - rio_dprint(RIO_DEBUG_TABLE, ("Allocated ID %d for this new RTA.\n",MapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "Allocated ID %d for this new RTA.\n", MapP->ID); HostMapP = &p->RIOHosts[host].Mapping[nNewID]; HostMapP->RtaUniqueNum = MapP->RtaUniqueNum; HostMapP->HostUniqueNum = MapP->HostUniqueNum; @@ -747,9 +747,9 @@ int RIOAssignRta( struct rio_info *p, struct Map *MapP ) HostMapP->Flags |= RTA16_SECOND_SLOT; HostMapP->ID2 = MapP->ID2 = p->RIOHosts[host].Mapping[unit].ID; p->RIOHosts[host].Mapping[unit].ID2 = MapP->ID; - rio_dprint(RIO_DEBUG_TABLE, ("Cross referenced id %d to ID %d.\n", + rio_dprintk (RIO_DEBUG_TABLE, "Cross referenced id %d to ID %d.\n", MapP->ID, - p->RIOHosts[host].Mapping[unit].ID)); + p->RIOHosts[host].Mapping[unit].ID); } } @@ -757,7 +757,7 @@ int RIOAssignRta( struct rio_info *p, struct Map *MapP ) if ( HostMapP->Flags & SLOT_IN_USE ) { - rio_dprint(RIO_DEBUG_TABLE, ("Map table slot for ID %d is already in use.\n",MapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "Map table slot for ID %d is already in use.\n", MapP->ID); p->RIOError.Error = ID_ALREADY_IN_USE; return EBUSY; } @@ -791,15 +791,15 @@ int RIOAssignRta( struct rio_info *p, struct Map *MapP ) p->RIOLastPortsBooted = HostMapP->SysPort; } if (MapP->Flags & RTA16_SECOND_SLOT) - rio_dprint(RIO_DEBUG_TABLE, ("Second map of RTA %s added to configuration\n", - p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Second map of RTA %s added to configuration\n", + p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name); else - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s added to configuration\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s added to configuration\n", MapP->Name); return 0; } } p->RIOError.Error = UNKNOWN_HOST_NUMBER; - rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum); return ENXIO; } @@ -822,7 +822,7 @@ struct Map *HostMapP; CheckHostMapP( HostMapP ); #endif - rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d to id %d\n",(int)HostMapP->SysPort, HostMapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "Mapping sysport %d to id %d\n", (int)HostMapP->SysPort, HostMapP->ID); /* ** We need to tell the UnixRups which sysport the rup corresponds to @@ -833,26 +833,26 @@ struct Map *HostMapP; return(0); RtaType = GetUnitType(HostMapP->RtaUniqueNum); - rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d-%d\n", - (int)HostMapP->SysPort,(int)HostMapP->SysPort+PORTS_PER_RTA-1)); + rio_dprintk (RIO_DEBUG_TABLE, "Mapping sysport %d-%d\n", + (int)HostMapP->SysPort, (int)HostMapP->SysPort+PORTS_PER_RTA-1); /* ** now map each of its eight ports */ for ( SubEnt=0; SubEnt<PORTS_PER_RTA; SubEnt++) { - rio_dprint (RIO_DEBUG_TABLE, ("subent = %d, HostMapP->SysPort = %d\n", - SubEnt, (int) HostMapP->SysPort)); + rio_dprintk (RIO_DEBUG_TABLE, "subent = %d, HostMapP->SysPort = %d\n", + SubEnt, (int)HostMapP->SysPort); SysPort = HostMapP->SysPort+SubEnt; /* portnumber within system */ /* portnumber on host */ HostPort = (HostMapP->ID-1)*PORTS_PER_RTA+SubEnt; - rio_dprint (RIO_DEBUG_TABLE, ("c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp)); + rio_dprintk (RIO_DEBUG_TABLE, "c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp); PortP = p->RIOPortp[SysPort]; #if 0 PortP->TtyP = &p->channel[SysPort]; #endif - rio_dprint(RIO_DEBUG_TABLE, ("Map port\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Map port\n"); /* ** Point at all the real neat data structures @@ -1008,12 +1008,12 @@ struct Map* MapP; struct Map *HostMapP; char *sptr; - rio_dprint(RIO_DEBUG_TABLE, ("Change name entry on host %x, rta %x, ID %d, Sysport %d\n", + rio_dprintk (RIO_DEBUG_TABLE, "Change name entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum,MapP->RtaUniqueNum, - MapP->ID, (int)MapP->SysPort )); + MapP->ID, (int)MapP->SysPort); if ( MapP->ID > MAX_RUP ) { - rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Bad ID in map entry!\n"); p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1023,7 +1023,7 @@ struct Map* MapP; while ( *sptr ) { if ( *sptr<' ' || *sptr>'~' ) { - rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n"); p->RIOError.Error = BAD_CHARACTER_IN_NAME; return EINVAL; } @@ -1052,6 +1052,6 @@ struct Map* MapP; } } p->RIOError.Error = UNKNOWN_HOST_NUMBER; - rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum); return ENXIO; } diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c index cda417f3f..c9134e3fc 100644 --- a/drivers/char/rio/riotty.c +++ b/drivers/char/rio/riotty.c @@ -164,15 +164,15 @@ riotopen(struct tty_struct * tty, struct file * filp) Modem = rio_ismodem (tty->device); if ( p->RIOFailed ) { - rio_dprint(RIO_DEBUG_TTY, ("System initialisation failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "System initialisation failed\n"); pseterr(ENXIO); func_exit (); return -ENXIO; } - rio_dprint(RIO_DEBUG_TTY, ("port open SysPort %d (%s) (mapped:%d)\n", + rio_dprintk (RIO_DEBUG_TTY, "port open SysPort %d (%s) (mapped:%d)\n", SysPort, Modem ? "Modem" : "tty", - p->RIOPortp[SysPort]->Mapped ) ); + p->RIOPortp[SysPort]->Mapped); /* ** Validate that we have received a legitimate request. @@ -181,7 +181,7 @@ riotopen(struct tty_struct * tty, struct file * filp) ** has been mapped onto a host. */ if (SysPort >= RIO_PORTS) { /* out of range ? */ - rio_dprint(RIO_DEBUG_TTY, ("Illegal port number %d\n",SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "Illegal port number %d\n",SysPort); pseterr(ENXIO); func_exit(); return -ENXIO; @@ -197,7 +197,7 @@ riotopen(struct tty_struct * tty, struct file * filp) ** The system doesn't know which RTA this port ** corresponds to. */ - rio_dprint(RIO_DEBUG_TTY, ("port not mapped into system\n")); + rio_dprintk (RIO_DEBUG_TTY, "port not mapped into system\n"); func_exit (); pseterr(ENXIO); return -ENXIO; @@ -206,17 +206,26 @@ riotopen(struct tty_struct * tty, struct file * filp) tty->driver_data = PortP; PortP->gs.tty = tty; + if (!PortP->gs.count) + rio_inc_mod_count (); PortP->gs.count++; - rio_dprint(RIO_DEBUG_TTY, ("%d bytes in tx buffer\n", - PortP->gs.xmit_cnt)); - gs_init_port (&PortP->gs); + rio_dprintk (RIO_DEBUG_TTY, "%d bytes in tx buffer\n", + PortP->gs.xmit_cnt); + + retval = gs_init_port (&PortP->gs); + if (retval) { + PortP->gs.count--; + if (PortP->gs.count) + rio_dec_mod_count (); + return -ENXIO; + } /* ** If the host hasn't been booted yet, then ** fail */ if ( (PortP->HostP->Flags & RUN_STATE) != RC_RUNNING ) { - rio_dprint(RIO_DEBUG_TTY, ("Host not running\n")); + rio_dprintk (RIO_DEBUG_TTY, "Host not running\n"); pseterr(ENXIO); func_exit (); return -ENXIO; @@ -230,24 +239,24 @@ riotopen(struct tty_struct * tty, struct file * filp) #if 0 if (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) { if (PortP->WaitUntilBooted) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot\n"); do { if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); func_exit (); return -EINTR; } if (repeat_this -- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); pseterr(EINTR); func_exit (); return -EIO; } } while(!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)); - rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA has been booted\n"); } else { - rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA never booted\n"); pseterr(ENXIO); func_exit (); return 0; @@ -258,10 +267,10 @@ riotopen(struct tty_struct * tty, struct file * filp) easier to read and shorter. Now, if it works too that would be great... -- REW */ - rio_dprint(RIO_DEBUG_TTY, ("Checking if RTA has booted... \n")); + rio_dprintk (RIO_DEBUG_TTY, "Checking if RTA has booted... \n"); while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) { if (!PortP->WaitUntilBooted) { - rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA never booted\n"); func_exit (); return -ENXIO; } @@ -271,17 +280,17 @@ riotopen(struct tty_struct * tty, struct file * filp) now. --REW */ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("RTA_wait_for_boot: EINTR in delay \n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA_wait_for_boot: EINTR in delay \n"); func_exit (); return -EINTR; } if (repeat_this -- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n"); func_exit (); return -EIO; } } - rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA has been booted\n"); #endif #if 0 tp = PortP->TtyP; /* get tty struct */ @@ -304,9 +313,9 @@ riotopen(struct tty_struct * tty, struct file * filp) ** for it to finish, so that it doesn't close us! */ while ( (PortP->State & RIO_CLOSING) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RIO_CLOSING to go away\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n"); if (repeat_this -- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); retval = -EINTR; goto bombout; @@ -321,7 +330,7 @@ riotopen(struct tty_struct * tty, struct file * filp) } if ( !PortP->Mapped ) { - rio_dprint(RIO_DEBUG_TTY, ("Port unmapped while closing!\n")); + rio_dprintk (RIO_DEBUG_TTY, "Port unmapped while closing!\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); retval = -ENXIO; func_exit (); @@ -344,8 +353,8 @@ riotopen(struct tty_struct * tty, struct file * filp) } if (!(PortP->firstOpen)) { /* First time ? */ - rio_dprint(RIO_DEBUG_TTY, ("First open for this port\n")); - rio_inc_mod_count (); + rio_dprintk (RIO_DEBUG_TTY, "First open for this port\n"); + PortP->firstOpen++; PortP->CookMode = 0; /* XXX RIOCookMode(tp); */ @@ -375,7 +384,7 @@ riotopen(struct tty_struct * tty, struct file * filp) ** wait for the port to be not closed. */ while ( !(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for PORT_ISOPEN-currently %x\n",PortP->PortState)); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for PORT_ISOPEN-currently %x\n",PortP->PortState); /* ** 15.10.1998 ARG - ESIL 0759 ** (Part) fix for port being trashed when opened whilst RTA "disconnected" @@ -392,7 +401,7 @@ riotopen(struct tty_struct * tty, struct file * filp) */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish broken by signal\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); func_exit (); return -EINTR; @@ -407,52 +416,67 @@ bombout: rio_spin_unlock_irqrestore(&PortP->portSem, flags); return retval; } - rio_dprint(RIO_DEBUG_TTY, ("PORT_ISOPEN found\n")); + rio_dprintk (RIO_DEBUG_TTY, "PORT_ISOPEN found\n"); } #ifdef MODEM_SUPPORT if (Modem) { - rio_dprint(RIO_DEBUG_TTY, ("Modem - test for carrier\n")); + rio_dprintk (RIO_DEBUG_TTY, "Modem - test for carrier\n"); /* ** ACTION ** insert test for carrier here. -- ??? ** I already see that test here. What's the deal? -- REW */ - if ((tp->tm.c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) + if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) { - rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) Modem carr on\n",SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort); + /* tp->tm.c_state |= CARR_ON; wakeup((caddr_t) &tp->tm.c_canq); + */ + PortP->State |= RIO_CARR_ON; + wake_up_interruptible (&PortP->gs.open_wait); } else /* no carrier - wait for DCD */ { - while (!(tp->tm.c_state&CARR_ON) && - !(filp->f_flags&O_NONBLOCK) && !p->RIOHalted ) - { - rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) sleeping for carr on\n",SysPort)); - tp->tm.c_state |= WOPEN; + /* + while (!(PortP->gs.tty->termios->c_state & CARR_ON) && + !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted ) + */ + while (!(PortP->State & RIO_CARR_ON) && + !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted ) { + + rio_dprintk (RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n",SysPort); + /* + PortP->gs.tty->termios->c_state |= WOPEN; + */ PortP->State |= RIO_WOPEN; - if ( sleep((caddr_t)&tp->tm.c_canq, TTIPRI|PCATCH)) +#if 0 + if ( sleep((caddr_t)&tp->tm.c_canqo, TTIPRI|PCATCH)) { /* ** ACTION: verify that this is a good thing ** to do here. -- ??? ** I think it's OK. -- REW */ - rio_dprint(RIO_DEBUG_TTY, ("open(%d) sleeping for carr broken by signal\n", - SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", + SysPort); RIOPreemptiveCmd( p, PortP, FCLOSE ); + /* tp->tm.c_state &= ~WOPEN; + */ PortP->State &= ~RIO_WOPEN; rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit (); return -EINTR; } +#endif } PortP->State &= ~RIO_WOPEN; } - if ( RIOHalted ) + if ( p->RIOHalted ) goto bombout; + rio_dprintk (RIO_DEBUG_TTY, "Setting RIO_MOPEN\n"); PortP->State |= RIO_MOPEN; } else @@ -470,7 +494,7 @@ bombout: goto bombout; } - rio_dprint(RIO_DEBUG_TTY, ("high level open done\n")); + rio_dprintk (RIO_DEBUG_TTY, "high level open done\n"); #ifdef STATS PortP->Stat.OpenCnt++; @@ -482,7 +506,7 @@ bombout: PortP->opens++; rio_spin_unlock_irqrestore(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Returning from open\n")); + rio_dprintk (RIO_DEBUG_TTY, "Returning from open\n"); func_exit (); return 0; } @@ -509,13 +533,13 @@ riotclose(void *ptr) int Modem; int rv =0; - rio_dprint(RIO_DEBUG_TTY, ("port close SysPort %d\n",PortP->PortNum)); + rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum); /* PortP = p->RIOPortp[SysPort]; */ - rio_dprint(RIO_DEBUG_TTY, ("Port is at address 0x%x\n",(int)PortP)); + rio_dprintk (RIO_DEBUG_TTY, "Port is at address 0x%x\n",(int)PortP); /* tp = PortP->TtyP;*/ /* Get tty */ tty = PortP->gs.tty; - rio_dprint(RIO_DEBUG_TTY, ("TTY is at address 0x%x\n",(int)tty)); + rio_dprintk (RIO_DEBUG_TTY, "TTY is at address 0x%x\n",(int)tty); Modem = rio_ismodem(tty->device); #if 0 /* What F.CKING cache? Even then, a higly idle multiprocessor, @@ -533,7 +557,7 @@ riotclose(void *ptr) PortP->State |= RIO_CLOSING; if ( (PortP->State & RIO_DELETED) ) { - rio_dprint(RIO_DEBUG_TTY, ("Close on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_TTY, "Close on deleted RTA\n"); deleted = 1; } @@ -543,7 +567,7 @@ riotclose(void *ptr) goto close_end; } - rio_dprint(RIO_DEBUG_TTY, ("Clear bits\n")); + rio_dprintk (RIO_DEBUG_TTY, "Clear bits\n"); /* ** clear the open bits for this device */ @@ -561,7 +585,7 @@ riotclose(void *ptr) ** The port is still open for the other task - ** return, pretending that we are still active. */ - rio_dprint(RIO_DEBUG_TTY, ("Channel %d still open !\n",PortP->PortNum)); + rio_dprintk (RIO_DEBUG_TTY, "Channel %d still open !\n",PortP->PortNum); PortP->State &= ~RIO_CLOSING; if (PortP->firstOpen) PortP->firstOpen--; @@ -569,7 +593,7 @@ riotclose(void *ptr) return -EIO; } - rio_dprint(RIO_DEBUG_TTY, ("Closing down - everything must go!\n")); + rio_dprintk (RIO_DEBUG_TTY, "Closing down - everything must go!\n"); PortP->State &= ~RIO_DYNOROD; @@ -578,7 +602,7 @@ riotclose(void *ptr) ** to drain down before closing. Bye-bye.... ** (We never meant to do this) */ - rio_dprint(RIO_DEBUG_TTY, ("Timeout 1 starts\n")); + rio_dprintk (RIO_DEBUG_TTY, "Timeout 1 starts\n"); #if 0 if (!deleted) @@ -587,14 +611,14 @@ riotclose(void *ptr) cprintf("Need to flush the ttyport\n"); if (repeat_this -- <= 0) { rv = -EINTR; - rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); goto close_end; } - rio_dprint(RIO_DEBUG_TTY, ("Calling timeout to flush in closing\n")); + rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay_ni(PortP, HUNDRED_MS*10) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); rv = -EINTR; rio_spin_lock_irqsave(&PortP->portSem, flags); goto close_end; @@ -611,7 +635,7 @@ riotclose(void *ptr) ** The port has been re-opened for the other task - ** return, pretending that we are still active. */ - rio_dprint(RIO_DEBUG_TTY, ("Channel %d re-open!\n", PortP->PortNum)); + rio_dprintk (RIO_DEBUG_TTY, "Channel %d re-open!\n", PortP->PortNum); PortP->State &= ~RIO_CLOSING; rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (PortP->firstOpen) @@ -638,12 +662,12 @@ riotclose(void *ptr) while (try && (PortP->PortState & PORT_ISOPEN)) { try--; if (try == 0) { - rio_dprint(RIO_DEBUG_TTY, ("Run out of tries - force the bugger shut!\n" )); + rio_dprintk (RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n" ); RIOPreemptiveCmd(p, PortP,FCLOSE); break; } - rio_dprint(RIO_DEBUG_TTY, ("Close: PortState:ISOPEN is %d\n", - PortP->PortState & PORT_ISOPEN)); + rio_dprintk (RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", + PortP->PortState & PORT_ISOPEN); if ( p->RIOHalted ) { RIOClearUp( PortP ); @@ -652,7 +676,7 @@ riotclose(void *ptr) RIODelay_ni(PortP, HUNDRED_MS); } rio_spin_lock_irqsave(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Close: try was %d on completion\n", try )); + rio_dprintk (RIO_DEBUG_TTY, "Close: try was %d on completion\n", try ); /* RIOPreemptiveCmd(p, PortP, FCLOSE); */ @@ -682,7 +706,7 @@ close_end: if (PortP->firstOpen) PortP->firstOpen--; rio_spin_unlock_irqrestore(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Return from close\n")); + rio_dprintk (RIO_DEBUG_TTY, "Return from close\n"); return rv; } @@ -731,7 +755,7 @@ static void RIOClearUp(PortP) struct Port *PortP; { - rio_dprint(RIO_DEBUG_TTY, ("RIOHalted set\n")); + rio_dprintk (RIO_DEBUG_TTY, "RIOHalted set\n"); PortP->Config = 0; /* Direct semaphore */ PortP->PortState = 0; PortP->firstOpen = 0; @@ -761,7 +785,7 @@ static int RIOShortCommand(struct rio_info *p, struct Port *PortP, int retries = 20; /* at 10 per second -> 2 seconds */ unsigned long flags; - rio_dprint(RIO_DEBUG_TTY, ("entering shortcommand.\n")); + rio_dprintk (RIO_DEBUG_TTY, "entering shortcommand.\n"); #ifdef CHECK CheckPortP( PortP ); if ( len < 1 || len > 2 ) @@ -769,7 +793,7 @@ static int RIOShortCommand(struct rio_info *p, struct Port *PortP, #endif if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n")); + rio_dprintk (RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n"); return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags); @@ -779,8 +803,8 @@ static int RIOShortCommand(struct rio_info *p, struct Port *PortP, ** be free again. */ while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for not in use (%d)\n", - retries)); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for not in use (%d)\n", + retries); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (retries-- <= 0) { return RIO_FAIL; @@ -791,16 +815,16 @@ static int RIOShortCommand(struct rio_info *p, struct Port *PortP, rio_spin_lock_irqsave(&PortP->portSem, flags); } if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n")); + rio_dprintk (RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIO_FAIL; } while ( !can_add_transmit(&PacketP,PortP) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting to add short command to queue (%d)\n", retries)); + rio_dprintk (RIO_DEBUG_TTY, "Waiting to add short command to queue (%d)\n", retries); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (retries-- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("out of tries. Failing\n")); + rio_dprintk (RIO_DEBUG_TTY, "out of tries. Failing\n"); return RIO_FAIL; } if ( RIODelay_ni(PortP, HUNDRED_MS)==RIO_FAIL ) { @@ -865,11 +889,11 @@ register caddr_t arg; int Modem = rio_ismodem(dev); int ioctl_processed; - rio_dprint(RIO_DEBUG_TTY, ("port ioctl SysPort %d command 0x%x argument 0x%x %s\n", - SysPort,cmd,arg,Modem?"Modem":"tty")); + rio_dprintk (RIO_DEBUG_TTY, "port ioctl SysPort %d command 0x%x argument 0x%x %s\n", + SysPort, cmd, arg, Modem?"Modem":"tty") ; if ( SysPort >= RIO_PORTS ) { - rio_dprint(RIO_DEBUG_TTY, ("Bad port number %d\n",SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "Bad port number %d\n", SysPort); return -ENXIO; } @@ -926,22 +950,22 @@ register caddr_t arg; return 0; case TCRIOTSTATE: - rio_dprint(RIO_DEBUG_TTY, ("tbusy/tstop monitoring %sabled\n", - arg ? "en" : "dis")); + rio_dprintk (RIO_DEBUG_TTY, "tbusy/tstop monitoring %sabled\n", + arg ? "en" : "dis"); /* MonitorTstate = 0 ;*/ rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP, CONFIG, Modem, OK_TO_SLEEP); return 0; case TCRIOSTATE: /* current state of Modem input pins */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOSTATE\n"); if (RIOPreemptiveCmd(p, PortP, MGET) == RIO_FAIL) - rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE command failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOSTATE command failed\n"); PortP->State |= RIO_BUSY; current = PortP->ModemState; if ( copyout((caddr_t)¤t, (int)arg, sizeof(current))==COPYFAIL ) { - rio_dprint(RIO_DEBUG_TTY, ("Copyout failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "Copyout failed\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EFAULT); } @@ -950,15 +974,15 @@ register caddr_t arg; case TCRIOMBIS: /* Set modem lines */ case TCRIOMBIC: /* Clear modem lines */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIS/TCRIOMBIC\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOMBIS/TCRIOMBIC\n"); if (cmd == TCRIOMBIS) { uint state; state = (uint)arg; PortP->ModemState |= (ushort)state; PortP->ModemLines = (ulong) arg; if (RIOPreemptiveCmd(p, PortP, MBIS) == RIO_FAIL) - rio_dprint(RIO_DEBUG_TTY, ( - "TCRIOMBIS command failed\n")); + rio_dprintk (RIO_DEBUG_TTY, + "TCRIOMBIS command failed\n"); } else { uint state; @@ -967,17 +991,17 @@ register caddr_t arg; PortP->ModemState &= ~(ushort)state; PortP->ModemLines = (ulong) arg; if (RIOPreemptiveCmd(p, PortP, MBIC) == RIO_FAIL) - rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIC command failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOMBIC command failed\n"); } PortP->State |= RIO_BUSY; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOXPON: /* set Xprint ON string */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPON\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPON\n"); if ( copyin((int)arg, (caddr_t)PortP->Xprint.XpOn, MAX_XP_CTRL_LEN)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "Copyin failed\n"); PortP->Xprint.XpOn[0] = '\0'; rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EFAULT); @@ -989,10 +1013,10 @@ register caddr_t arg; return 0; case TCRIOXPOFF: /* set Xprint OFF string */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPOFF\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPOFF\n"); if ( copyin( (int)arg, (caddr_t)PortP->Xprint.XpOff, MAX_XP_CTRL_LEN)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "Copyin failed\n"); PortP->Xprint.XpOff[0] = '\0'; rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EFAULT); @@ -1004,10 +1028,10 @@ register caddr_t arg; return 0; case TCRIOXPCPS: /* set Xprint CPS string */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPCPS\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPCPS\n"); if ( (uint)arg > p->RIOConf.MaxXpCps || (uint)arg < p->RIOConf.MinXpCps ) { - rio_dprint(RIO_DEBUG_TTY, ("%d CPS out of range\n",arg)); + rio_dprintk (RIO_DEBUG_TTY, "%d CPS out of range\n",arg); rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EINVAL); return 0; @@ -1017,7 +1041,7 @@ register caddr_t arg; return 0; case TCRIOXPRINT: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPRINT\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPRINT\n"); if ( copyout((caddr_t)&PortP->Xprint, (int)arg, sizeof(struct Xprint))==COPYFAIL ) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -1027,25 +1051,25 @@ register caddr_t arg; return 0; case TCRIOIXANYON: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYON\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXANYON\n"); PortP->Config |= RIO_IXANY; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOIXANYOFF: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYOFF\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXANYOFF\n"); PortP->Config &= ~RIO_IXANY; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOIXONON: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONON\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXONON\n"); PortP->Config |= RIO_IXON; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOIXONOFF: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONOFF\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXONOFF\n"); PortP->Config &= ~RIO_IXON; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; @@ -1055,28 +1079,28 @@ register caddr_t arg; ** Added support for CTS and RTS flow control ioctls : */ case TCRIOCTSFLOWEN: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWEN\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOCTSFLOWEN\n"); PortP->Config |= RIO_CTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); return 0; case TCRIOCTSFLOWDIS: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWDIS\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOCTSFLOWDIS\n"); PortP->Config &= ~RIO_CTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); return 0; case TCRIORTSFLOWEN: - rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWEN\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIORTSFLOWEN\n"); PortP->Config |= RIO_RTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); return 0; case TCRIORTSFLOWDIS: - rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWDIS\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIORTSFLOWDIS\n"); PortP->Config &= ~RIO_RTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); @@ -1100,13 +1124,13 @@ register caddr_t arg; case TCSETAW: case TCSETAF: ioctl_processed++; - rio_dprint(RIO_DEBUG_TTY, ("NON POSIX ioctl\n")); + rio_dprintk (RIO_DEBUG_TTY, "NON POSIX ioctl\n"); ttyseth_pv(PortP, tp, (struct termios *)arg, 0); break; case TCSETAP: /* posix tcsetattr() */ case TCSETAWP: /* posix tcsetattr() */ case TCSETAFP: /* posix tcsetattr() */ - rio_dprint(RIO_DEBUG_TTY, ("NON POSIX SYSV ioctl\n")); + rio_dprintk (RIO_DEBUG_TTY, "NON POSIX SYSV ioctl\n"); ttyseth_pv(PortP, tp, (struct termios *)arg, 1); ioctl_processed++; break; @@ -1141,7 +1165,7 @@ register caddr_t arg; #endif case TIOCSETD: case TIOCSETN: - rio_dprint(RIO_DEBUG_TTY, ("wait for non-BUSY, semaphore set\n")); + rio_dprintk (RIO_DEBUG_TTY, "wait for non-BUSY, semaphore set\n"); /* ** Wait for drain here, at least as far as the double buffer ** being empty. @@ -1208,8 +1232,8 @@ register caddr_t arg; PortP->CookMode = RIOCookMode(tp); /* Set new cooking mode */ - rio_dprint(RIO_DEBUG_TTY, ("RIOIoctl changed %d newcook %d oldcook %d\n", - changed,PortP->CookMode,oldcook)); + rio_dprintk (RIO_DEBUG_TTY, "RIOIoctl changed %d newcook %d oldcook %d\n", + changed,PortP->CookMode,oldcook); #ifdef MODEM_SUPPORT /* @@ -1232,7 +1256,7 @@ register caddr_t arg; */ if (changed || oldcook != PortP->CookMode || (ioctl_processed)) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Ioctl changing the PORT settings\n")); + rio_dprintk (RIO_DEBUG_TTY, "Ioctl changing the PORT settings\n"); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); rio_spin_lock_irqsave(&PortP->portSem, flags); } diff --git a/drivers/char/scan_keyb.c b/drivers/char/scan_keyb.c index 1936e0b6e..f2435e9ec 100644 --- a/drivers/char/scan_keyb.c +++ b/drivers/char/scan_keyb.c @@ -82,18 +82,21 @@ int register_scan_keyboard(void (*scan)(unsigned char *buffer), { struct scan_keyboard *kbd; - if((kbd=kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL))==NULL) + kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL); + if (kbd == NULL) goto error_out; kbd->scan=scan; kbd->table=table; kbd->length=length; - kbd->s0=kbd->s1=NULL; - if((kbd->s0=kmalloc(length, GFP_KERNEL))==NULL) - goto error_mem_free; - if((kbd->s1=kmalloc(length, GFP_KERNEL))==NULL) - goto error_mem_free; + kbd->s0 = kmalloc(length, GFP_KERNEL); + if (kbd->s0 == NULL) + goto error_free_kbd; + + kbd->s1 = kmalloc(length, GFP_KERNEL); + if (kbd->s1 == NULL) + goto error_free_s0; kbd->scan(kbd->s0); kbd->scan(kbd->s1); @@ -103,11 +106,10 @@ int register_scan_keyboard(void (*scan)(unsigned char *buffer), return 0; - error_mem_free: - if(kbd->s0) - kfree(kbd->s0); - if(kbd->s1) - kfree(kbd->s1); + error_free_s0: + kfree(kbd->s0); + + error_free_kbd: kfree(kbd); error_out: diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 8ec857e06..f23f911ad 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -51,13 +51,16 @@ * * 7/00: Support Timedia/Sunix/Exsys PCI cards * + * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT. + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * * This module exports the following rs232 io functions: * * int rs_init(void); */ -static char *serial_version = "5.01"; -static char *serial_revdate = "2000-05-29"; +static char *serial_version = "5.02"; +static char *serial_revdate = "2000-08-09"; /* * Serial driver configuration section. Here are the various options: @@ -142,6 +145,10 @@ static char *serial_revdate = "2000-05-29"; #endif #endif +#ifdef MODULE +#undef CONFIG_SERIAL_CONSOLE +#endif + #define CONFIG_SERIAL_RSA #define RS_STROBE_TIME (10*HZ) @@ -260,8 +267,9 @@ static struct rs_multiport_struct rs_multiport[NR_IRQS]; static int IRQ_timeout[NR_IRQS]; #ifdef CONFIG_SERIAL_CONSOLE static struct console sercons; +static int lsr_break_flag = 0; #endif -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) static unsigned long break_pressed; /* break, really ... */ #endif @@ -281,7 +289,7 @@ static struct serial_uart_config uart_config[] = { { "16550", 1, 0 }, { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, { "cirrus", 1, 0 }, /* usurped by cyclades.c */ - { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, + { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, @@ -302,7 +310,9 @@ static int probe_rsa[PORT_RSA_MAX]; static int force_rsa[PORT_RSA_MAX]; MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); #endif /* CONFIG_SERIAL_RSA */ static struct serial_state rs_table[RS_TABLE_SIZE] = { @@ -313,7 +323,7 @@ static struct serial_state rs_table[RS_TABLE_SIZE] = { #if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)) #define NR_PCI_BOARDS 8 -/* We don't unregister PCI boards right now */ + static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; static int serial_pci_board_idx = 0; @@ -573,6 +583,23 @@ static _INLINE_ void receive_chars(struct async_struct *info, if (*status & UART_LSR_BI) { *status &= ~(UART_LSR_FE | UART_LSR_PE); icount->brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (info->line == sercons.index) { + if (!break_pressed) { + break_pressed = jiffies; + goto ignore_char; + } + break_pressed = 0; + } +#endif + if (info->flags & ASYNC_SAK) + do_SAK(tty); } else if (*status & UART_LSR_PE) icount->parity++; else if (*status & UART_LSR_FE) @@ -591,23 +618,19 @@ static _INLINE_ void receive_chars(struct async_struct *info, goto ignore_char; } *status &= info->read_status_mask; - + +#ifdef CONFIG_SERIAL_CONSOLE + if (info->line == sercons.index) { + /* Recover the break flag from console xmit */ + *status |= lsr_break_flag; + lsr_break_flag = 0; + } +#endif if (*status & (UART_LSR_BI)) { #ifdef SERIAL_DEBUG_INTR printk("handling break...."); #endif -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) - if (info->line == sercons.index) { - if (!break_pressed) { - break_pressed = jiffies; - goto ignore_char; - } - break_pressed = 0; - } -#endif *tty->flip.flag_buf_ptr = TTY_BREAK; - if (info->flags & ASYNC_SAK) - do_SAK(tty); } else if (*status & UART_LSR_PE) *tty->flip.flag_buf_ptr = TTY_PARITY; else if (*status & UART_LSR_FE) @@ -626,7 +649,7 @@ static _INLINE_ void receive_chars(struct async_struct *info, goto ignore_char; } } -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { @@ -1068,19 +1091,15 @@ static void rs_timer(unsigned long dummy) mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); if (IRQ_ports[0]) { - unsigned long next; save_flags(flags); cli(); #ifdef CONFIG_SERIAL_SHARE_IRQ rs_interrupt(0, NULL, NULL); #else rs_interrupt_single(0, NULL, NULL); #endif - - next = jiffies + IRQ_timeout[0] - 2; - if (next < jiffies + 1) - next = jiffies + 1; - mod_timer(&serial_timer, next); restore_flags(flags); + + mod_timer(&serial_timer, jiffies + IRQ_timeout[0]); } } @@ -1115,7 +1134,7 @@ static void figure_IRQ_timeout(int irq) } if (!irq) timeout = timeout / 2; - IRQ_timeout[irq] = timeout ? timeout : 1; + IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1; } #ifdef CONFIG_SERIAL_RSA @@ -2081,7 +2100,7 @@ static int set_serial_info(struct async_struct * info, new_serial.irq = irq_cannonicalize(new_serial.irq); - if ((new_serial.irq >= NR_IRQS) || + if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || (new_serial.type == PORT_STARTECH)) { @@ -2314,7 +2333,7 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd, static int do_autoconfig(struct async_struct * info) { - int retval; + int irq, retval; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -2327,8 +2346,11 @@ static int do_autoconfig(struct async_struct * info) autoconfig(info->state); if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0) && - (info->state->type != PORT_UNKNOWN)) - info->state->irq = detect_uart_irq(info->state); + (info->state->type != PORT_UNKNOWN)) { + irq = detect_uart_irq(info->state); + if (irq > 0) + info->state->irq = irq; + } retval = startup(info); if (retval) @@ -3115,8 +3137,10 @@ static int rs_open(struct tty_struct *tty, struct file * filp) } tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) + if (serial_paranoia_check(info, tty->device, "rs_open")) { + MOD_DEC_USE_COUNT; return -ENODEV; + } #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, @@ -3129,6 +3153,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); if (!page) { + MOD_DEC_USE_COUNT; return -ENOMEM; } if (tmp_buf) @@ -3144,6 +3169,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); + MOD_DEC_USE_COUNT; #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -3157,6 +3183,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) */ retval = startup(info); if (retval) { + MOD_DEC_USE_COUNT; return retval; } @@ -3166,6 +3193,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) printk("rs_open returning after block_til_ready with %d\n", retval); #endif + MOD_DEC_USE_COUNT; return retval; } @@ -3490,6 +3518,7 @@ static void autoconfig_startech_uarts(struct async_struct *info, * (Exoray@isys.ca) claims that it's needed for 952 * dual UART's (which are not recommended for new designs). */ + info->ACR = 0; serial_out(info, UART_LCR, 0xBF); serial_out(info, UART_EFR, 0x10); serial_out(info, UART_LCR, 0x00); @@ -3808,10 +3837,11 @@ static _INLINE_ int get_pci_port(struct pci_dev *dev, if (idx >= max_port) return 1; } - + offset = board->first_uart_offset; /* Timedia/SUNIX uses a mixture of BARs and offsets */ + /* Ugh, this is ugly as all hell --- TYT */ if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ switch(idx) { case 0: base_idx=0; @@ -4094,6 +4124,62 @@ pci_inteli960ni_fn(struct pci_dev *dev, return(0); } +/* + * Timedia has an explosion of boards, and to avoid the PCI table from + * growing *huge*, we use this function to collapse some 70 entries + * in the PCI table into one, for sanity's and compactness's sake. + */ +static unsigned short timedia_single_port[] = { + 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 }; +static unsigned short timedia_dual_port[] = { + 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, + 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, + 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, + 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, + 0xD079, 0 }; +static unsigned short timedia_quad_port[] = { + 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, + 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, + 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, + 0xB157, 0 }; +static unsigned short timedia_eight_port[] = { + 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, + 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; +static struct timedia_struct { + int num; + unsigned short *ids; +} timedia_data[] = { + { 1, timedia_single_port }, + { 2, timedia_dual_port }, + { 4, timedia_quad_port }, + { 8, timedia_eight_port }, + { 0, 0 } +}; + +static int +#ifndef MODULE +__init +#endif +pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + int i, j; + unsigned short *ids; + + if (!enable) + return 0; + + for (i=0; timedia_data[i].num; i++) { + ids = timedia_data[i].ids; + for (j=0; ids[j]; j++) { + if (pci_get_subvendor(dev) == ids[j]) { + board->num_ports = timedia_data[i].num; + return 0; + } + } + } + return 0; +} + /* * This is the configuration table for all of the PCI serial boards @@ -4120,58 +4206,50 @@ static struct pci_board pci_boards[] __initdata = { PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, SPCI_FL_BASE1, 2, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, SPCI_FL_BASE1, 8, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, SPCI_FL_BASE1, 4, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, SPCI_FL_BASE1, 2, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, SPCI_FL_BASE1, 2, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, - SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, - SPCI_FL_BASE1, 2, 921600 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, @@ -4200,6 +4278,9 @@ static struct pci_board pci_boards[] __initdata = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE2, 8, 921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 4, 921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, PCI_SUBDEVICE_ID_KEYSPAN_SX2, @@ -4269,75 +4350,10 @@ static struct pci_board pci_boards[] __initdata = { { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, - /* PCI_VENDOR_ID_TIMEDIA/Sunix, PCI_DEVICE_ID_TIMEDIA_1889, */ - { 0x1409, 0x7168, 0x1409, 0x0002, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4036A*/ - { 0x1409, 0x7168, 0x1409, 0x4025, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4025A*/ - { 0x1409, 0x7168, 0x1409, 0x4027, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4027A*/ - { 0x1409, 0x7168, 0x1409, 0x4028, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4028D*/ - { 0x1409, 0x7168, 0x1409, 0x4036, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4036D*/ - { 0x1409, 0x7168, 0x1409, 0x4037, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4037A*/ - { 0x1409, 0x7168, 0x1409, 0x4038, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4038D*/ - { 0x1409, 0x7168, 0x1409, 0x4055, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4055A*/ - { 0x1409, 0x7168, 0x1409, 0x4056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4056A*/ - { 0x1409, 0x7168, 0x1409, 0x4065, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4065A*/ - { 0x1409, 0x7168, 0x1409, 0x4066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4066A*/ - { 0x1409, 0x7168, 0x1409, 0x4078, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4078A*/ - { 0x1409, 0x7168, 0x1409, 0x4079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079H*/ - { 0x1409, 0x7168, 0x1409, 0x4085, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4085H*/ - { 0x1409, 0x7168, 0x1409, 0x4088, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4088A*/ - { 0x1409, 0x7168, 0x1409, 0x4089, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4089A*/ - { 0x1409, 0x7168, 0x1409, 0x4095, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4095A*/ - { 0x1409, 0x7168, 0x1409, 0x4096, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4096A*/ - { 0x1409, 0x7168, 0x1409, 0x5025, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4025D*/ - { 0x1409, 0x7168, 0x1409, 0x5027, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4027D*/ - { 0x1409, 0x7168, 0x1409, 0x5037, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4037D*/ - { 0x1409, 0x7168, 0x1409, 0x5056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4056R*/ - { 0x1409, 0x7168, 0x1409, 0x5065, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4065R*/ - { 0x1409, 0x7168, 0x1409, 0x5066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4066R*/ - { 0x1409, 0x7168, 0x1409, 0x5078, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4078U*/ - { 0x1409, 0x7168, 0x1409, 0x5079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079A*/ - { 0x1409, 0x7168, 0x1409, 0x5085, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4085U*/ - { 0x1409, 0x7168, 0x1409, 0x6079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079R*/ - { 0x1409, 0x7168, 0x1409, 0x7079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079S*/ - { 0x1409, 0x7168, 0x1409, 0x8079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079D*/ - { 0x1409, 0x7168, 0x1409, 0x8137, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8137*/ - { 0x1409, 0x7168, 0x1409, 0x8138, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8138*/ - { 0x1409, 0x7168, 0x1409, 0x8156, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8156*/ - { 0x1409, 0x7168, 0x1409, 0x8157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8157*/ - { 0x1409, 0x7168, 0x1409, 0x8166, SPCI_FL_BASE_TABLE, 8, 921600 }, /*8166*/ - { 0x1409, 0x7168, 0x1409, 0x8237, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8237*/ - { 0x1409, 0x7168, 0x1409, 0x8238, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8238*/ - { 0x1409, 0x7168, 0x1409, 0x8256, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8256*/ - { 0x1409, 0x7168, 0x1409, 0x8257, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8257*/ - { 0x1409, 0x7168, 0x1409, 0x9056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9056A*/ - { 0x1409, 0x7168, 0x1409, 0x9066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9066A*/ - { 0x1409, 0x7168, 0x1409, 0x9079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079E*/ - { 0x1409, 0x7168, 0x1409, 0x9137, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8137S*/ - { 0x1409, 0x7168, 0x1409, 0x9138, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8138S*/ - { 0x1409, 0x7168, 0x1409, 0x9156, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8156S*/ - { 0x1409, 0x7168, 0x1409, 0x9157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8157S*/ - { 0x1409, 0x7168, 0x1409, 0x9158, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9158*/ - { 0x1409, 0x7168, 0x1409, 0x9159, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9159*/ - { 0x1409, 0x7168, 0x1409, 0x9166, SPCI_FL_BASE_TABLE, 8, 921600 }, /*8166S*/ - { 0x1409, 0x7168, 0x1409, 0x9167, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9167*/ - { 0x1409, 0x7168, 0x1409, 0x9168, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9168*/ - { 0x1409, 0x7168, 0x1409, 0x9237, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8237S*/ - { 0x1409, 0x7168, 0x1409, 0x9238, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8238S*/ - { 0x1409, 0x7168, 0x1409, 0x9256, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8256S*/ - { 0x1409, 0x7168, 0x1409, 0x9257, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8257S*/ - { 0x1409, 0x7168, 0x1409, 0xA056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9056B*/ - { 0x1409, 0x7168, 0x1409, 0xA066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9066B*/ - { 0x1409, 0x7168, 0x1409, 0xA079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079F*/ - { 0x1409, 0x7168, 0x1409, 0xA157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9157*/ - { 0x1409, 0x7168, 0x1409, 0xA158, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9158S*/ - { 0x1409, 0x7168, 0x1409, 0xA159, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9159S*/ - { 0x1409, 0x7168, 0x1409, 0xA167, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9167S*/ - { 0x1409, 0x7168, 0x1409, 0xA168, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9168S*/ - { 0x1409, 0x7168, 0x1409, 0xB056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9056C*/ - { 0x1409, 0x7168, 0x1409, 0xB079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*9079A*/ - { 0x1409, 0x7168, 0x1409, 0xB157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9157S*/ - { 0x1409, 0x7168, 0x1409, 0xC079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*9079B*/ - { 0x1409, 0x7168, 0x1409, 0xD079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*9079C*/ + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, + SPCI_FL_BASE_TABLE, 1, 921600, + 0, 0, pci_timedia_fn }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, @@ -4544,7 +4560,7 @@ static struct pci_board pci_boards[] __initdata = { { PCI_VENDOR_ID_ROCKWELL, 0x1004, 0x1048, 0x1500, SPCI_FL_BASE1, 1, 115200 }, -#ifdef CONFIG_DDB5074 +#if CONFIG_DDB5074 /* * NEC Vrc-5074 (Nile 4) builtin UART. * Conditionally compiled in since this is a motherboard device. @@ -4584,7 +4600,7 @@ static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev, for (i=0; i < 6; i++) { if (IS_PCI_REGION_IOPORT(dev, i)) { - num_port = 0; + num_port++; if (first_port == -1) first_port = i; } else { @@ -5081,16 +5097,6 @@ static int __init rs_init(void) int i; struct serial_state * state; - if (serial_timer.function) { - printk("RS_TIMER already set, another serial driver " - "already loaded?\n"); -#ifdef MODULE - printk("Can't load serial driver module over built-in " - "serial driver\n"); -#endif - return -EBUSY; - } - init_bh(SERIAL_BH, do_serial_bh); init_timer(&serial_timer); serial_timer.function = rs_timer; @@ -5423,6 +5429,8 @@ static void __exit rs_fini(void) module_init(rs_init); module_exit(rs_fini); +MODULE_DESCRIPTION("Standard/generic (dumb) serial driver"); +MODULE_AUTHOR("Theodore Ts'o <tytso@mit.edu>"); /* @@ -5441,10 +5449,17 @@ static struct async_struct async_sercons; */ static inline void wait_for_xmitr(struct async_struct *info) { - unsigned int tmout = 1000000; + unsigned int status, tmout = 1000000; + + do { + status = serial_in(info, UART_LSR); - while (--tmout && - ((serial_in(info, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)); + if (status & UART_LSR_BI) + lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + } while((status & BOTH_EMPTY) != BOTH_EMPTY); } diff --git a/drivers/char/serial_21285.c b/drivers/char/serial_21285.c new file mode 100644 index 000000000..575cf0bc0 --- /dev/null +++ b/drivers/char/serial_21285.c @@ -0,0 +1,511 @@ +/* + * linux/drivers/char/serial_21285.c + * + * Driver for the serial port on the 21285 StrongArm-110 core logic chip. + * + * Based on drivers/char/serial.c + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/major.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <linux/init.h> +#include <linux/console.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/dec21285.h> +#include <asm/hardware.h> + +#define BAUD_BASE (mem_fclk_21285/64) + +#define SERIAL_21285_NAME "ttyFB" +#define SERIAL_21285_MAJOR 204 +#define SERIAL_21285_MINOR 4 + +#define SERIAL_21285_AUXNAME "cuafb" +#define SERIAL_21285_AUXMAJOR 205 +#define SERIAL_21285_AUXMINOR 4 + +static struct tty_driver rs285_driver, callout_driver; +static int rs285_refcount; +static struct tty_struct *rs285_table[1]; + +static struct termios *rs285_termios[1]; +static struct termios *rs285_termios_locked[1]; + +static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; +static struct tty_struct *rs285_tty; +static int rs285_use_count; + +static int rs285_write_room(struct tty_struct *tty) +{ + return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1); +} + +static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + if (!rs285_tty) { + disable_irq(IRQ_CONRX); + return; + } + while (!(*CSR_UARTFLG & 0x10)) { + int ch, flag; + ch = *CSR_UARTDR; + flag = *CSR_RXSTAT; + if (flag & 4) + tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN); + if (flag & 2) + flag = TTY_PARITY; + else if (flag & 1) + flag = TTY_FRAME; + tty_insert_flip_char(rs285_tty, ch, flag); + } + tty_flip_buffer_push(rs285_tty); +} + +static void rs285_send_xchar(struct tty_struct *tty, char ch) +{ + x_char = ch; + enable_irq(IRQ_CONTX); +} + +static void rs285_throttle(struct tty_struct *tty) +{ + if (I_IXOFF(tty)) + rs285_send_xchar(tty, STOP_CHAR(tty)); +} + +static void rs285_unthrottle(struct tty_struct *tty) +{ + if (I_IXOFF(tty)) { + if (x_char) + x_char = 0; + else + rs285_send_xchar(tty, START_CHAR(tty)); + } +} + +static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + while (!(*CSR_UARTFLG & 0x20)) { + if (x_char) { + *CSR_UARTDR = x_char; + x_char = 0; + continue; + } + if (putp == getp) { + disable_irq(IRQ_CONTX); + break; + } + *CSR_UARTDR = *getp; + if (++getp >= wbuf + sizeof(wbuf)) + getp = wbuf; + } + if (rs285_tty) + wake_up_interruptible(&rs285_tty->write_wait); +} + +static inline int rs285_xmit(int ch) +{ + if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf)) + return 0; + *putp = ch; + if (++putp >= wbuf + sizeof(wbuf)) + putp = wbuf; + enable_irq(IRQ_CONTX); + return 1; +} + +static int rs285_write(struct tty_struct *tty, int from_user, + const u_char * buf, int count) +{ + int i; + + if (from_user && verify_area(VERIFY_READ, buf, count)) + return -EINVAL; + + for (i = 0; i < count; i++) { + char ch; + if (from_user) + __get_user(ch, buf + i); + else + ch = buf[i]; + if (!rs285_xmit(ch)) + break; + } + return i; +} + +static void rs285_put_char(struct tty_struct *tty, u_char ch) +{ + rs285_xmit(ch); +} + +static int rs285_chars_in_buffer(struct tty_struct *tty) +{ + return sizeof(wbuf) - rs285_write_room(tty); +} + +static void rs285_flush_buffer(struct tty_struct *tty) +{ + disable_irq(IRQ_CONTX); + putp = getp = wbuf; + if (x_char) + enable_irq(IRQ_CONTX); +} + +static inline void rs285_set_cflag(int cflag) +{ + int h_lcr, baud, quot; + + switch (cflag & CSIZE) { + case CS5: + h_lcr = 0x10; + break; + case CS6: + h_lcr = 0x30; + break; + case CS7: + h_lcr = 0x50; + break; + default: /* CS8 */ + h_lcr = 0x70; + break; + + } + if (cflag & CSTOPB) + h_lcr |= 0x08; + if (cflag & PARENB) + h_lcr |= 0x02; + if (!(cflag & PARODD)) + h_lcr |= 0x04; + + switch (cflag & CBAUD) { + case B200: baud = 200; break; + case B300: baud = 300; break; + case B1200: baud = 1200; break; + case B1800: baud = 1800; break; + case B2400: baud = 2400; break; + case B4800: baud = 4800; break; + default: + case B9600: baud = 9600; break; + case B19200: baud = 19200; break; + case B38400: baud = 38400; break; + case B57600: baud = 57600; break; + case B115200: baud = 115200; break; + } + + /* + * The documented expression for selecting the divisor is: + * BAUD_BASE / baud - 1 + * However, typically BAUD_BASE is not divisible by baud, so + * we want to select the divisor that gives us the minimum + * error. Therefore, we want: + * int(BAUD_BASE / baud - 0.5) -> + * int(BAUD_BASE / baud - (baud >> 1) / baud) -> + * int((BAUD_BASE - (baud >> 1)) / baud) + */ + quot = (BAUD_BASE - (baud >> 1)) / baud; + + *CSR_UARTCON = 0; + *CSR_L_UBRLCR = quot & 0xff; + *CSR_M_UBRLCR = (quot >> 8) & 0x0f; + *CSR_H_UBRLCR = h_lcr; + *CSR_UARTCON = 1; +} + +static void rs285_set_termios(struct tty_struct *tty, struct termios *old) +{ + if (old && tty->termios->c_cflag == old->c_cflag) + return; + rs285_set_cflag(tty->termios->c_cflag); +} + + +static void rs285_stop(struct tty_struct *tty) +{ + disable_irq(IRQ_CONTX); +} + +static void rs285_start(struct tty_struct *tty) +{ + enable_irq(IRQ_CONTX); +} + +static void rs285_wait_until_sent(struct tty_struct *tty, int timeout) +{ + int orig_jiffies = jiffies; + while (*CSR_UARTFLG & 8) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + current->state = TASK_RUNNING; +} + +static int rs285_open(struct tty_struct *tty, struct file *filp) +{ + int line; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if (line) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + tty->driver_data = NULL; + if (!rs285_tty) + rs285_tty = tty; + + enable_irq(IRQ_CONRX); + rs285_use_count++; + return 0; +} + +static void rs285_close(struct tty_struct *tty, struct file *filp) +{ + if (!--rs285_use_count) { + rs285_wait_until_sent(tty, 0); + disable_irq(IRQ_CONRX); + disable_irq(IRQ_CONTX); + rs285_tty = NULL; + } + MOD_DEC_USE_COUNT; +} + +static int __init rs285_init(void) +{ + int baud = B9600; + + if (machine_is_personal_server()) + baud = B57600; + + rs285_driver.magic = TTY_DRIVER_MAGIC; + rs285_driver.driver_name = "serial_21285"; + rs285_driver.name = SERIAL_21285_NAME; + rs285_driver.major = SERIAL_21285_MAJOR; + rs285_driver.minor_start = SERIAL_21285_MINOR; + rs285_driver.num = 1; + rs285_driver.type = TTY_DRIVER_TYPE_SERIAL; + rs285_driver.subtype = SERIAL_TYPE_NORMAL; + rs285_driver.init_termios = tty_std_termios; + rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL; + rs285_driver.flags = TTY_DRIVER_REAL_RAW; + rs285_driver.refcount = &rs285_refcount; + rs285_driver.table = rs285_table; + rs285_driver.termios = rs285_termios; + rs285_driver.termios_locked = rs285_termios_locked; + + rs285_driver.open = rs285_open; + rs285_driver.close = rs285_close; + rs285_driver.write = rs285_write; + rs285_driver.put_char = rs285_put_char; + rs285_driver.write_room = rs285_write_room; + rs285_driver.chars_in_buffer = rs285_chars_in_buffer; + rs285_driver.flush_buffer = rs285_flush_buffer; + rs285_driver.throttle = rs285_throttle; + rs285_driver.unthrottle = rs285_unthrottle; + rs285_driver.send_xchar = rs285_send_xchar; + rs285_driver.set_termios = rs285_set_termios; + rs285_driver.stop = rs285_stop; + rs285_driver.start = rs285_start; + rs285_driver.wait_until_sent = rs285_wait_until_sent; + + callout_driver = rs285_driver; + callout_driver.name = SERIAL_21285_AUXNAME; + callout_driver.major = SERIAL_21285_AUXMAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL)) + panic("Couldn't get rx irq for rs285"); + + if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL)) + panic("Couldn't get tx irq for rs285"); + + if (tty_register_driver(&rs285_driver)) + printk(KERN_ERR "Couldn't register 21285 serial driver\n"); + if (tty_register_driver(&callout_driver)) + printk(KERN_ERR "Couldn't register 21285 callout driver\n"); + + return 0; +} + +static void __exit rs285_fini(void) +{ + unsigned long flags; + int ret; + + save_flags(flags); + cli(); + ret = tty_unregister_driver(&callout_driver); + if (ret) + printk(KERN_ERR "Unable to unregister 21285 callout driver " + "(%d)\n", ret); + ret = tty_unregister_driver(&rs285_driver); + if (ret) + printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n", + ret); + free_irq(IRQ_CONTX, NULL); + free_irq(IRQ_CONRX, NULL); + restore_flags(flags); +} + +module_init(rs285_init); +module_exit(rs285_fini); + +#ifdef CONFIG_SERIAL_21285_CONSOLE +/************** console driver *****************/ + +static void rs285_console_write(struct console *co, const char *s, u_int count) +{ + int i; + + disable_irq(IRQ_CONTX); + for (i = 0; i < count; i++) { + while (*CSR_UARTFLG & 0x20); + *CSR_UARTDR = s[i]; + if (s[i] == '\n') { + while (*CSR_UARTFLG & 0x20); + *CSR_UARTDR = '\r'; + } + } + enable_irq(IRQ_CONTX); +} + +static int rs285_console_wait_key(struct console *co) +{ + int c; + + disable_irq(IRQ_CONRX); + while (*CSR_UARTFLG & 0x10); + c = *CSR_UARTDR; + enable_irq(IRQ_CONRX); + return c; +} + +static kdev_t rs285_console_device(struct console *c) +{ + return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); +} + +static int __init rs285_console_setup(struct console *co, char *options) +{ + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + + if (machine_is_personal_server()) + baud = 57600; + + if (options) { + char *s = options; + baud = simple_strtoul(options, NULL, 10); + while (*s >= '0' && *s <= '9') + s++; + if (*s) + parity = *s++; + if (*s) + bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch (baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 9600: + cflag |= B9600; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + default: + cflag |= B9600; + break; + } + switch (bits) { + case 7: + cflag |= CS7; + break; + default: + cflag |= CS8; + break; + } + switch (parity) { + case 'o': + case 'O': + cflag |= PARODD; + break; + case 'e': + case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + rs285_set_cflag(cflag); + rs285_console_write(NULL, "\e[2J\e[Hboot ", 12); + if (options) + rs285_console_write(NULL, options, strlen(options)); + else + rs285_console_write(NULL, "no options", 10); + rs285_console_write(NULL, "\n", 1); + + return 0; +} + +static struct console rs285_cons = +{ + SERIAL_21285_NAME, + rs285_console_write, + NULL, + rs285_console_device, + rs285_console_wait_key, + NULL, + rs285_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +void __init rs285_console_init(void) +{ + register_console(&rs285_cons); +} + +#endif /* CONFIG_SERIAL_21285_CONSOLE */ diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 82e3cae1e..e6336fc03 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -1518,9 +1518,14 @@ static int sx_open (struct tty_struct * tty, struct file * filp) exit minicom. I expect an "oops". -- REW */ static void sx_hungup (void *ptr) { + /* struct sx_port *port = ptr; + */ func_enter (); + /* Don't force the SX card to close. mgetty doesn't like it !!!!!! -- pvdl */ + /* For some reson we added this code. Don't know why anymore ;-( -- pvdl */ + /* sx_setsignals (port, 0, 0); sx_reconfigure_port(port); sx_send_command (port, HS_CLOSE, 0, 0); @@ -1532,7 +1537,7 @@ static void sx_hungup (void *ptr) } else sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); } - + */ MOD_DEC_USE_COUNT; func_exit (); } @@ -2368,7 +2373,7 @@ static int sx_init_portstructs (int nboards, int nports) return 0; } - +#ifdef MODULE static void sx_release_drivers(void) { func_enter(); @@ -2376,6 +2381,7 @@ static void sx_release_drivers(void) tty_unregister_driver(&sx_callout_driver); func_exit(); } +#endif #ifdef TWO_ZERO #define PDEV unsigned char pci_bus, unsigned pci_fun diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0d6e6f3fa..17fce4ddf 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1839,9 +1839,12 @@ void do_SAK( struct tty_struct *tty) read_lock(&tasklist_lock); for_each_task(p) { if ((p->tty == tty) || - ((session > 0) && (p->session == session))) + ((session > 0) && (p->session == session))) { send_sig(SIGKILL, p, 1); - else if (p->files) { + continue; + } + task_lock(p); + if (p->files) { read_lock(&p->files->file_lock); /* FIXME: p->files could change */ for (i=0; i < p->files->max_fds; i++) { @@ -1854,6 +1857,7 @@ void do_SAK( struct tty_struct *tty) } read_unlock(&p->files->file_lock); } + task_unlock(p); } read_unlock(&tasklist_lock); #endif diff --git a/drivers/char/wdt285.c b/drivers/char/wdt285.c index 66633fd20..6745493de 100644 --- a/drivers/char/wdt285.c +++ b/drivers/char/wdt285.c @@ -31,7 +31,7 @@ #include <asm/irq.h> #include <asm/uaccess.h> #include <asm/hardware.h> -#include <asm/system.h> +#include <asm/mach-types.h> #include <asm/dec21285.h> /* diff --git a/drivers/input/Config.in b/drivers/input/Config.in new file mode 100644 index 000000000..966ae308a --- /dev/null +++ b/drivers/input/Config.in @@ -0,0 +1,20 @@ +# +# Input core configuration +# + +mainmenu_option next_comment +comment 'Input core support' + +tristate 'Input core support' CONFIG_INPUT +if [ "$CONFIG_INPUT" != "n" ]; then + dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT + dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT + if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then + int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 + int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 + fi + dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT + dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT +fi + +endmenu diff --git a/drivers/input/Makefile b/drivers/input/Makefile new file mode 100644 index 000000000..af6305cec --- /dev/null +++ b/drivers/input/Makefile @@ -0,0 +1,51 @@ +# +# Makefile for the input core drivers. +# + +# Subdirs. + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +# The target object and module list name. + +O_TARGET := inputdrv.o +M_OBJS := +O_OBJS := + +# Objects that export symbols. + +export-objs := input.o + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +# Each configuration option enables a list of files. + +obj-$(CONFIG_INPUT) += input.o +obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o +obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o +obj-$(CONFIG_INPUT_JOYDEV) += joydev.o +obj-$(CONFIG_INPUT_EVDEV) += evdev.o + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Translate to Rules.make lists. + +O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +# The global Rules.make. + +include $(TOPDIR)/Rules.make diff --git a/drivers/usb/evdev.c b/drivers/input/evdev.c index 65109e9ca..65109e9ca 100644 --- a/drivers/usb/evdev.c +++ b/drivers/input/evdev.c diff --git a/drivers/usb/input.c b/drivers/input/input.c index f3701965e..f3701965e 100644 --- a/drivers/usb/input.c +++ b/drivers/input/input.c diff --git a/drivers/usb/joydev.c b/drivers/input/joydev.c index 99b17a3cd..90c4dbcef 100644 --- a/drivers/usb/joydev.c +++ b/drivers/input/joydev.c @@ -1,5 +1,5 @@ /* - * $Id: joydev.c,v 1.11 2000/06/23 09:23:00 vojtech Exp $ + * $Id: joydev.c,v 1.13 2000/08/14 21:05:26 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Colin Van Dyke @@ -390,7 +390,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct int i, j, minor; if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && - test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) && + (test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) && (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) || test_bit(BTN_1, dev->keybit)))) return NULL; diff --git a/drivers/usb/keybdev.c b/drivers/input/keybdev.c index 95fce5e80..95fce5e80 100644 --- a/drivers/usb/keybdev.c +++ b/drivers/input/keybdev.c diff --git a/drivers/usb/mousedev.c b/drivers/input/mousedev.c index ccb118520..1aa85e227 100644 --- a/drivers/usb/mousedev.c +++ b/drivers/input/mousedev.c @@ -1,5 +1,5 @@ /* - * $Id: mousedev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $ + * $Id: mousedev.c,v 1.15 2000/08/14 21:05:26 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -62,7 +62,7 @@ struct mousedev_list { struct mousedev *mousedev; struct mousedev_list *next; int dx, dy, dz, oldx, oldy; - char ps2[6]; + signed char ps2[6]; unsigned long buttons; unsigned char ready, buffer, bufsiz; unsigned char mode, genseq, impseq; @@ -91,6 +91,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig while (list) { switch (type) { case EV_ABS: + if (test_bit(BTN_TRIGGER, handle->dev->keybit)) + break; switch (code) { case ABS_X: size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; @@ -104,6 +106,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig break; } break; + case EV_REL: switch (code) { case REL_X: list->dx += value; break; @@ -252,7 +255,7 @@ static void mousedev_packet(struct mousedev_list *list, unsigned char off) list->bufsiz = off + 3; if (list->mode > 1) - list->ps2[off] |= ((list->buttons & 0x30) << 2); + list->ps2[off] |= ((list->buttons & 0x18) << 3); if (list->mode) { list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index e4ba2cf1f..2062f753c 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -37,6 +37,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD fi bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 + bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1 comment ' HiSax supported cards' bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0 bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 @@ -55,6 +56,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER bool ' MIC card' CONFIG_HISAX_MIC bool ' NETjet card' CONFIG_HISAX_NETJET + bool ' NETspider U card' CONFIG_HISAX_NETJET_U bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR @@ -83,7 +85,15 @@ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then fi dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then - bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + if [ "$CONFIG_ISDN_DRV_EICON_STANDALONE" != "y" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI + fi + bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + fi + if [ "$CONFIG_PCI" = "y" ]; then + bool ' build eicon driver type standalone' CONFIG_ISDN_DRV_EICON_STANDALONE + fi fi dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then @@ -109,8 +119,13 @@ if [ "$CONFIG_ISDN_CAPI" != "n" ]; then bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON fi if [ "$CONFIG_PROC_FS" != "n" ]; then -if [ "$CONFIG_MODULES" != "n" ]; then - bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN + if [ "$CONFIG_MODULES" != "n" ]; then + bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN + fi fi +if [ "$CONFIG_HYSDN" != "n" ]; then + if [ "$CONFIG_ISDN_CAPI" != "n" ]; then + bool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI + fi fi endmenu diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c index ff13e1636..747b5ea7f 100644 --- a/drivers/isdn/avmb1/b1.c +++ b/drivers/isdn/avmb1/b1.c @@ -1,11 +1,17 @@ /* - * $Id: b1.c,v 1.14 2000/06/19 16:51:53 keil Exp $ + * $Id: b1.c,v 1.16 2000/08/04 15:36:31 calle Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.16 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.15 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.14 2000/06/19 16:51:53 keil * don't free skb in irq context * @@ -95,7 +101,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.14 $"; +static char *revision = "$Revision: 1.16 $"; /* ------------------------------------------------------------- */ @@ -597,25 +603,29 @@ void b1_handle_interrupt(avmcard * card) ctrl->ready(ctrl); break; - case RECEIVE_TASK_READY: + case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; - case RECEIVE_DEBUGMSG: + case RECEIVE_DEBUGMSG: MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c index 42a77acf5..3bd6a01c0 100644 --- a/drivers/isdn/avmb1/b1dma.c +++ b/drivers/isdn/avmb1/b1dma.c @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.6 2000/06/29 13:59:06 calle Exp $ + * $Id: b1dma.c,v 1.7 2000/08/04 12:20:08 calle Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.7 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.6 2000/06/29 13:59:06 calle * Bugfix: reinit txdma without interrupt will confuse some AMCC chips. * @@ -44,7 +47,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.6 $"; +static char *revision = "$Revision: 1.7 $"; /* ------------------------------------------------------------- */ @@ -561,22 +564,26 @@ static void b1dma_handle_rx(avmcard *card) case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c index fb7b5f755..69bab9557 100644 --- a/drivers/isdn/avmb1/b1pci.c +++ b/drivers/isdn/avmb1/b1pci.c @@ -1,11 +1,14 @@ /* - * $Id: b1pci.c,v 1.26 2000/07/20 10:21:21 calle Exp $ + * $Id: b1pci.c,v 1.27 2000/08/08 09:24:19 calle Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.27 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * * Revision 1.26 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -91,13 +94,12 @@ #include <linux/pci.h> #include <linux/capi.h> #include <asm/io.h> -#include <linux/isdn.h> #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.26 $"; +static char *revision = "$Revision: 1.27 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c index 64de830c2..d814eec1a 100644 --- a/drivers/isdn/avmb1/c4.c +++ b/drivers/isdn/avmb1/c4.c @@ -1,11 +1,20 @@ /* - * $Id: c4.c,v 1.13 2000/07/20 10:21:21 calle Exp $ + * $Id: c4.c,v 1.16 2000/08/20 07:30:13 keil Exp $ * * Module for AVM C4 card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: c4.c,v $ + * Revision 1.16 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.15 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * + * Revision 1.14 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.13 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -63,15 +72,15 @@ #include <linux/ioport.h> #include <linux/pci.h> #include <linux/capi.h> -#include <linux/isdn.h> #include <asm/io.h> #include <asm/uaccess.h> +#include <linux/netdevice.h> #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.13 $"; +static char *revision = "$Revision: 1.16 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -682,22 +691,26 @@ static void c4_handle_rx(avmcard *card) case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index a4223e878..0b7cc80d2 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.38 2000/07/24 08:49:09 calle Exp $ + * $Id: capi.c,v 1.39 2000/07/24 13:42:50 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.39 2000/07/24 13:42:50 calle + * - lock_kernel/unlock_kernel for _release functions. (from 2.4) + * * Revision 1.38 2000/07/24 08:49:09 calle * - Bugfix: capiminor_del_all_ack completely wrong :-( * @@ -216,7 +219,7 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include <linux/slab.h> -static char *revision = "$Revision: 1.38 $"; +static char *revision = "$Revision: 1.39 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); @@ -325,11 +328,11 @@ static struct capidev *capidev_openlist = 0; static struct capiminor *minors = 0; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -static kmem_cache_t *capidev_cachep = 0; -static kmem_cache_t *capincci_cachep = 0; +static kmem_cache_t *capidev_cachep = 0; +static kmem_cache_t *capincci_cachep = 0; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -static kmem_cache_t *capiminor_cachep = 0; -static kmem_cache_t *capidh_cachep = 0; +static kmem_cache_t *capiminor_cachep = 0; +static kmem_cache_t *capidh_cachep = 0; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1239,7 +1242,7 @@ capi_release(struct inode *inode, struct file *file) capincci_free(cdev, 0xffffffff); capidev_free(cdev); file->private_data = NULL; - + MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); @@ -1251,13 +1254,13 @@ capi_release(struct inode *inode, struct file *file) static struct file_operations capi_fops = { owner: THIS_MODULE, - llseek: capi_llseek, - read: capi_read, - write: capi_write, - poll: capi_poll, - ioctl: capi_ioctl, - open: capi_open, - release: capi_release, + llseek: capi_llseek, + read: capi_read, + write: capi_write, + poll: capi_poll, + ioctl: capi_ioctl, + open: capi_open, + release: capi_release, }; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1980,9 +1983,9 @@ static void alloc_exit(void) static int alloc_init(void) { - capidev_cachep = kmem_cache_create("capi20_dev", + capidev_cachep = kmem_cache_create("capi20_dev", sizeof(struct capidev), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidev_cachep) { @@ -1990,9 +1993,9 @@ static int alloc_init(void) return -ENOMEM; } - capincci_cachep = kmem_cache_create("capi20_ncci", + capincci_cachep = kmem_cache_create("capi20_ncci", sizeof(struct capincci), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capincci_cachep) { @@ -2000,18 +2003,18 @@ static int alloc_init(void) return -ENOMEM; } #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - capidh_cachep = kmem_cache_create("capi20_dh", + capidh_cachep = kmem_cache_create("capi20_dh", sizeof(struct datahandle_queue), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidh_cachep) { alloc_exit(); return -ENOMEM; } - capiminor_cachep = kmem_cache_create("capi20_minor", + capiminor_cachep = kmem_cache_create("capi20_minor", sizeof(struct capiminor), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capiminor_cachep) { diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c index 0b04920f8..58b2eb9c6 100644 --- a/drivers/isdn/avmb1/capidrv.c +++ b/drivers/isdn/avmb1/capidrv.c @@ -2183,50 +2183,6 @@ static void enable_dchannel_trace(capidrv_contr *card) send_message(card, &cmdcmsg); } -static void disable_dchannel_trace(capidrv_contr *card) -{ - __u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - __u16 contr = card->contrnr; - __u16 errcode; - __u16 avmversion[3]; - - errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", - card->name, errcode); - return; - } - if (strstr(manufacturer, "AVM") == 0) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", - card->name, manufacturer); - return; - } - errcode = (*capifuncs->capi_get_version)(contr, &version); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get version (0x%x)\n", - card->name, errcode); - return; - } - avmversion[0] = (version.majormanuversion >> 4) & 0x0f; - avmversion[1] = (version.majormanuversion << 4) & 0xf0; - avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; - avmversion[2] |= version.minormanuversion & 0x0f; - - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { - printk(KERN_INFO "%s: D2 trace disabled\n", card->name); - } else { - printk(KERN_INFO "%s: D3 trace disabled\n", card->name); - } - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\000\000\000\000"); - send_message(card, &cmdcmsg); -} static void send_listen(capidrv_contr *card) { @@ -2288,15 +2244,15 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) card->interface.writecmd = 0; card->interface.readstat = if_readstat; card->interface.features = ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_X75UI | ISDN_FEATURE_L2_X75BUI; if (profp->support1 & (1<<2)) card->interface.features |= ISDN_FEATURE_L2_V11096 | - ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038; if (profp->support1 & (1<<8)) card->interface.features |= ISDN_FEATURE_L2_MODEM; diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c index ec4f9c559..64ef8436c 100644 --- a/drivers/isdn/avmb1/capifs.c +++ b/drivers/isdn/avmb1/capifs.c @@ -1,11 +1,20 @@ /* - * $Id: capifs.c,v 1.6 2000/04/03 13:29:25 calle Exp $ + * $Id: capifs.c,v 1.9 2000/08/20 07:30:13 keil Exp $ * * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) * * Heavily based on devpts filesystem from H. Peter Anvin * * $Log: capifs.c,v $ + * Revision 1.9 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.8 2000/07/20 10:23:13 calle + * Include isdn_compat.h for people that don't use -p option of std2kern. + * + * Revision 1.7 2000/06/18 16:09:54 keil + * more changes for 2.4 + * * Revision 1.6 2000/04/03 13:29:25 calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... @@ -60,7 +69,7 @@ MODULE_AUTHOR("Carsten Paeth <calle@calle.de>"); -static char *revision = "$Revision: 1.6 $"; +static char *revision = "$Revision: 1.9 $"; struct capifs_ncci { struct inode *inode; @@ -130,12 +139,12 @@ static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldi switch(nr) { case 0: - if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ case 1: - if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ @@ -147,7 +156,7 @@ static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldi char *p = numbuf; if (np->type) *p++ = np->type; sprintf(p, "%u", np->num); - if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 ) + if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_UNKNOWN) < 0 ) return 0; } filp->f_pos = ++nr; @@ -228,9 +237,9 @@ static void capifs_put_super(struct super_block *sb) for ( i = 0 ; i < sbi->max_ncci ; i++ ) { if ( (inode = sbi->nccis[i].inode) ) { - if ( atomic_read(&inode->i_count) != 1 ) + if (atomic_read(&inode->i_count) != 1 ) printk("capifs_put_super: badness: entry %d count %d\n", - i, atomic_read(&inode->i_count)); + i, (unsigned)atomic_read(&inode->i_count)); inode->i_nlink--; iput(inode); } diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c index b87f7293e..b6ec1aa52 100644 --- a/drivers/isdn/avmb1/t1isa.c +++ b/drivers/isdn/avmb1/t1isa.c @@ -1,11 +1,17 @@ /* - * $Id: t1isa.c,v 1.11 2000/04/03 13:29:25 calle Exp $ + * $Id: t1isa.c,v 1.13 2000/08/04 15:36:31 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.13 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.12 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.11 2000/04/03 13:29:25 calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... @@ -85,7 +91,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.11 $"; +static char *revision = "$Revision: 1.13 $"; /* ------------------------------------------------------------- */ @@ -282,25 +288,30 @@ static void t1_handle_interrupt(avmcard * card) case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; + case 0xff: printk(KERN_ERR "%s: card reseted ?\n", card->name); return; diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c index 6248419be..d2303feab 100644 --- a/drivers/isdn/avmb1/t1pci.c +++ b/drivers/isdn/avmb1/t1pci.c @@ -1,11 +1,14 @@ /* - * $Id: t1pci.c,v 1.10 2000/07/20 10:21:21 calle Exp $ + * $Id: t1pci.c,v 1.11 2000/08/08 09:24:19 calle Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.11 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * * Revision 1.10 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -60,13 +63,12 @@ #include <linux/pci.h> #include <linux/capi.h> #include <asm/io.h> -#include <linux/isdn.h> #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.11 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index bd065a48d..5b08e8025 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -1,5 +1,5 @@ /* - * $Id: divert_procfs.c,v 1.8 2000/03/03 16:37:11 kai Exp $ + * $Id: divert_procfs.c,v 1.9 2000/08/20 07:40:14 keil Exp $ * * Filesystem handling for the diversion supplementary services. * @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divert_procfs.c,v $ + * Revision 1.9 2000/08/20 07:40:14 keil + * changes from 2.4 + * * Revision 1.8 2000/03/03 16:37:11 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS diff --git a/drivers/isdn/eicon/Divas_mod.c b/drivers/isdn/eicon/Divas_mod.c new file mode 100644 index 000000000..8cb2a0409 --- /dev/null +++ b/drivers/isdn/eicon/Divas_mod.c @@ -0,0 +1,172 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.15 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 <linux/config.h> +#include <linux/fs.h> +#undef N_DATA + +#include <linux/kernel.h> + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <errno.h> + +#include "adapter.h" +#include "uxio.h" + +#ifdef MODULE +#include "idi.h" +void EtdM_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#define Divas_init init_module +#endif + +extern char *file_check(void); + +int DivasCardsDiscover(void); + +int +Divas_init(void) +{ + printk(KERN_DEBUG "DIVA Server Driver - initialising\n"); + + printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.12 (%s)\n",file_check()); + + +#if !defined(CONFIG_PCI) + printk(KERN_WARNING "CONFIG_PCI is not defined!\n"); + return -ENODEV; +#endif + + if (pci_present()) + { + if (DivasCardsDiscover() < 0) + { + printk(KERN_WARNING "Divas: Not loaded\n"); + return -ENODEV; + } + } + else + { + printk(KERN_WARNING "Divas: No PCI bus present\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void +cleanup_module(void) +{ + card_t *pCard; + word wCardIndex; + extern int Divas_major; + + printk(KERN_DEBUG "DIVA Server Driver - unloading\n"); + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + pCard++; + } + + unregister_chrdev(Divas_major, "Divas"); +} + +void mod_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void mod_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +#else +Divas_setup(char *str, int *ints) +{ +} +#endif + diff --git a/drivers/isdn/eicon/Makefile b/drivers/isdn/eicon/Makefile index 306aac0e8..63c557492 100644 --- a/drivers/isdn/eicon/Makefile +++ b/drivers/isdn/eicon/Makefile @@ -1,8 +1,37 @@ L_OBJS := M_OBJS := -O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o +LX_OBJS := +MX_OBJS := +O_OBJS := +OX_OBJS := +L_TARGET := +O_TARGET := + +ifeq ($(CONFIG_ISDN_DRV_EICON_STANDALONE),y) + + ifeq ($(CONFIG_PCI),y) + O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o + O_OBJS += lincfg.o linchr.o linsys.o linio.o + O_OBJS += fcheck.o + OX_OBJS += Divas_mod.o + endif + +else + + OX_OBJS += eicon_mod.o + O_OBJS := eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o + O_OBJS += fcheck.o + ifeq ($(CONFIG_PCI),y) + ifeq ($(CONFIG_ISDN_DRV_EICON_PCI),y) + O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o + O_OBJS += lincfg.o linchr.o linsys.o linio.o + endif + endif + +endif O_TARGET := + ifeq ($(CONFIG_ISDN_DRV_EICON),y) O_TARGET += eicon.o else @@ -10,4 +39,14 @@ else M_OBJS = eicon.o endif + include $(TOPDIR)/Rules.make + +MD5FILES += common.c idi.c bri.c pri.c log.c xlog.c kprintf.c fpga.c \ + fourbri.c fcheck.c + +FCHECK = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) + +fcheck.o: $(MD5FILES) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D FILECHECK=$(FCHECK) -c -o fcheck.o fcheck.c + diff --git a/drivers/isdn/eicon/adapter.h b/drivers/isdn/eicon/adapter.h new file mode 100644 index 000000000..cabba68be --- /dev/null +++ b/drivers/isdn/eicon/adapter.h @@ -0,0 +1,265 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.7 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Main internal include file for Diva Server driver */ + +#if !defined(ADAPTER_H) +#define ADAPTER_H + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" + +#define XMOREC 0x1f +#define XMOREF 0x20 +#define XBUSY 0x40 +#define RMORE 0x80 + + /* structure for all information we have to keep on a per */ + /* adapater basis */ + +typedef struct adapter_s ADAPTER; + +struct adapter_s { + void * io; + + byte IdTable[256]; + byte ReadyInt; + + byte (* ram_in)(ADAPTER * a, void * adr); + word (* ram_inw)(ADAPTER * a, void * adr); + void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length); + void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e); + + void (* ram_out)(ADAPTER * a, void * adr, byte data); + void (* ram_outw)(ADAPTER * a, void * adr, word data); + void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length); + + void (* ram_inc)(ADAPTER * a, void * adr); +}; + +typedef struct card card_t; + +typedef int card_load_fn_t(card_t *card, dia_load_t *load); +typedef int card_config_fn_t(card_t *card, dia_config_t *config); +typedef int card_start_fn_t(card_t *card, byte *channels); +typedef int card_reset_fn_t(card_t *card); +typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block); + +#define MAX_PENTITIES 256 /* Number of entities primary adapter */ +#define MAX_ENTITIES 16 /* Number of entities standard adapter */ + +typedef struct e_info_s E_INFO; + +struct e_info_s +{ + ENTITY *e; /* entity pointer */ + byte next; /* chaining index */ + word assign_ref; /* assign reference */ +}; + +/* DIVA card info (details hidden from user) */ + +typedef struct ux_diva_card_s ux_diva_card_t; + +/* card info */ + +struct card +{ + ADAPTER a; /* per-adapter information */ + dia_card_t cfg; /* card configuration */ + int state; /* State of the adapter */ + dword serial_no; /* serial number */ + int test_int_pend; /* set for interrupt testing */ + ux_diva_card_t *hw; /* O/S-specific handle */ + card_reset_fn_t *card_reset; /* call this to reset card */ + card_load_fn_t *card_load; /* call this to load card */ + card_config_fn_t *card_config; /* call this to config card */ + card_start_fn_t *card_start; /* call this to start card */ + card_mem_get_fn_t *card_mem_get; /* call this to get card memory */ + E_INFO *e_tbl; /* table of ENTITY pointers */ + byte e_head; /* list of active ENTITIES */ + byte e_tail; /* list of active ENTITIES */ + int e_count; /* # of active ENTITIES */ + int e_max; /* total # of ENTITIES */ + byte assign; /* assign queue entry */ + PBUFFER RBuffer; /* Copy of receive lookahead buffer */ + int log_types; /* bit-mask of active logs */ + word xlog_offset; /* offset to XLOG buffer on card */ + void (*out)(ADAPTER *a); + byte (*dpc)(ADAPTER * a); + byte (*test_int)(ADAPTER * a); + void (*clear_int)(ADAPTER * a); + void (*reset_int)(card_t *c); + int is_live; + + int (*card_isr)(card_t *card); + + int int_pend; /* interrupt pending */ + long interrupt_reentered; + long dpc_reentered; + int set_xlog_request; + +} ; + +/* card information */ + +#define MAX_CARDS 20 /* max number of cards on a system */ + +extern +card_t DivasCards[]; + +extern +int DivasCardNext; + +extern +dia_config_t DivasCardConfigs[]; + +extern +byte DivasFlavourConfig[]; + +/*------------------------------------------------------------------*/ +/* public functions of IDI common code */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a); +byte DivasDpc(ADAPTER * a); +byte DivasTestInt(ADAPTER * a); +void DivasClearInt(ADAPTER * a); + +/*------------------------------------------------------------------*/ +/* public functions of configuration platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasConfigGet(dia_card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of LOG related code */ +/*------------------------------------------------------------------*/ + +void DivasXlogReq(int card_num); +int DivasXlogRetrieve(card_t *card); +void DivasLog(dia_log_t *log); +void DivasLogIdi(card_t *card, ENTITY *e, int request); + +/*------------------------------------------------------------------*/ +/* public functions to initialise cards for each type supported */ +/*------------------------------------------------------------------*/ + +int DivasPriInit(card_t *card, dia_card_t *cfg); + +int DivasBriInit(card_t *card, dia_card_t *cfg); +int Divas4BriInit(card_t *card, dia_card_t *cfg); +void DivasBriPatch(card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of log common code */ +/*------------------------------------------------------------------*/ + +extern char *DivasLogFifoRead(void); +extern void DivasLogFifoWrite(char *entry, int length); +extern int DivasLogFifoEmpty(void); +extern int DivasLogFifoFull(void); +extern void DivasLogAdd(void *buffer, int length); + +/*------------------------------------------------------------------*/ +/* public functions of misc. platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasDpcSchedule(void); +void DivasDoDpc(void *); +void DivasDoRequestDpc(void *pData); +int DivasScheduleRequestDpc(void); + +/* table of IDI request functions */ + +extern +IDI_CALL DivasIdiRequest[]; + +/* + * intialisation entry point + */ + +int DivasInit(void); + +/* + * Get information on the number and type of cards present + */ + +extern +int DivasCardsDiscover(void); + +/* + * initialise a new card + */ + +int DivasCardNew(dia_card_t *card); + +/* + * configure specified card + */ + +int DivasCardConfig(dia_config_t *config); + +/* + * load specified binary code onto card + */ + +int DivasCardLoad(dia_load_t *load); + +/* + * start specified card running + */ + +int DivasCardStart(int card_id); + +/* + * ISR for card + * Returns 0 if specified card was interrupting + */ + +int DivasIsr(void *arg); + +/* + * Get number of active cards + */ + +int DivasGetNum(void); + +/* + * Get list of active cards + */ + +int DivasGetList(dia_card_list_t *card_list); + +/* definitions common to several card types */ + +#define DIVAS_SHARED_OFFSET (0x1000) + +#endif /* ADAPTER_H */ diff --git a/drivers/isdn/eicon/bri.c b/drivers/isdn/eicon/bri.c new file mode 100644 index 000000000..5a8afc11d --- /dev/null +++ b/drivers/isdn/eicon/bri.c @@ -0,0 +1,717 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.8 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 <sys/types.h> + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_BADDR0 0x10 +#define PCI_BADDR1 0x14 +#define PCI_BADDR2 0x18 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for BRI card */ + +#define PROTCAP_TELINDUS 0x1 +#define PROTCAP_V90D 0x8 + +word GetProtFeatureValue(char *sw_id); +byte io_in(ADAPTER *a, void *adr); +word io_inw(ADAPTER *a, void *adr); +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void io_out(ADAPTER *a, void *adr, byte data); +void io_outw(ADAPTER *a, void *adr, word data); +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_inc(ADAPTER *a, void *adr); + +static int diva_server_bri_test_int(card_t *card); + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +#define REG_DATA 0x00 +#define REG_ADDRLO 0x04 +#define REG_ADDRHI 0x0C +#define REG_IOCTRL 0x10 + +#define M_PCI_RESET 0x10 + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg); +int bri_ISR (card_t* card); + +static +int diva_server_bri_reset(card_t *card) +{ + byte *DivasIOBase; + word i; + dword dwWait; + + UxCardLog(0); + + DPRINTF(("divas: resetting BRI adapter")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0); + + for (i=0; i < 50000; i++) + ; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000); + + for (i=0; i<0x8000; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + } + + for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++) + ; + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +void diva_server_bri_reset_int(card_t *card) +{ + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +int diva_server_bri_start(card_t *card, byte *channels) +{ + byte *DivasIOBase, *PLXIOBase; + word wSig = 0; + word i; + dword dwSerialNum; + byte bPLX9060 = FALSE; + + DPRINTF(("divas: starting Diva Server BRI card")); + + card->is_live = FALSE; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + /* wait for signature to indicate card has started */ + for (i = 0; i < 300; i++) + { + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + if (wSig == DIVAS_SIGNATURE) + { + DPRINTF(("divas: card started after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if (wSig != DIVAS_SIGNATURE) + { + DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig)); + UxCardMemDetach(card->hw, DivasIOBase); + return -1; + } + + card->is_live = TRUE; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6); + *channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + UxCardMemDetach(card->hw, DivasIOBase); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x22)); + DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum)); + } + else + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x26)); + DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum)); + } + + UxCardMemDetach(card->hw, PLXIOBase); + + card->serial_no = dwSerialNum; + + diva_server_bri_test_int(card); + + return 0; +} + +static +int diva_server_bri_load(card_t *card, dia_load_t *load) +{ + byte *DivasIOBase; + dword r3000_base; + dword dwAddr, dwLength, i; + word wTest, aWord; + + DPRINTF(("divas: loading Diva Server BRI card")); + + switch (load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: loading RISC %s", &load->code[0x80])); + + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + DPRINTF(("divas: features 0x%x", card->hw->features)); + if (card->hw->features == 0xFFFF) + { + DPRINTF(("divas: invalid feature string failed load\n")); + return -1; + } + + r3000_base = 0; + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code \"%s\"", load->code)); + + if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS))) + { + DPRINTF(("divas: only Telindus style binaries supported")); + return -1; + } + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: V.90 DSP binary")); + r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + else + { + DPRINTF(("divas: non-V.90 DSP binary")); + r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + DPRINTF(("divas: loading at 0x%x", r3000_base)); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000 + sizeof(dword); + } + else + { + r3000_base = 0xBF7A0000 + sizeof(dword); + } + + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000; + } + else + { + r3000_base = 0xBF7A0000; + } + break; + + default: + DPRINTF(("divas: unknown code type %d", load->code_type)); + return -1; + break; + } + + DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + DPRINTF(("divas: Attached to 0x%04X", DivasIOBase)); + + dwLength = load->length; + + for (i=0; i < dwLength; i++) + { + dwAddr = r3000_base + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]); + } + + DPRINTF(("divas: Verifying")); + + for (i=0; i<dwLength; i++) + { + dwAddr = r3000_base + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + + aWord = load->code[i]; + + if (wTest != aWord) + { + DPRINTF(("divas: load verify failed on byte %d", i)); + DPRINTF(("divas: RAM 0x%x File 0x%x",wTest,aWord)); + + UxCardMemDetach(card->hw, DivasIOBase); + + return -1; + } + } + + DPRINTF(("divas: Loaded and verified. Detaching from adapter")); + + UxCardMemDetach(card->hw, DivasIOBase); + + UxCardLog(0); + + return 0; +} + +static +int diva_server_bri_config(card_t *card, dia_config_t *config) +{ + byte *DivasIOBase, i; + + DPRINTF(("divas: configuring Diva Server BRI card")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4); + } + else + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + } + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21); + + for (i=0; i<32; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]); + + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +void DivasBriPatch(card_t *card) +{ + dword PLXIOBase = 0; + dword DivasIOBase = 0; + + PLXIOBase = card->cfg.reset_base; + DivasIOBase = card->cfg.io_base; + + if(card->hw == NULL) + { + DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null")); + return; + } + + if (PLXIOBase == 0) + { + DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may")); + DPRINTF(("Divas: not function properly. If you do encounter problems,")); + DPRINTF(("Divas: ensure that your machine is using the latest BIOS.")); + return; + } + + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + + if (PLXIOBase & 0x80) + { + dword dwSize, dwSerialNum, dwCmd; + boolean_t bPLX9060; + word wSerHi, wSerLo; + + DPRINTF(("Divas: Patch required")); + dwCmd = 0; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + PLXIOBase &= ~0x80; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase); + + dwSize = 0xFFFFFFFF; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize); + UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize); + + dwSize = (~ (dwSize & ~7)) + 1; + + DivasIOBase = PLXIOBase + dwSize; + + card->cfg.reset_base = PLXIOBase; + card->cfg.io_base = DivasIOBase; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base); + UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base); + + dwCmd = 5; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + } + else + { + word wSerHi, wSerLo; + boolean_t bPLX9060; + dword dwSerialNum; + + DPRINTF(("divas: No patch required")); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + } + DPRINTF(("Divas: After patching:")); + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + +} + +#define TEST_INT_DIVAS_BRI 0x12 +static +int diva_server_bri_test_int(card_t *card) +{ + boolean_t bPLX9060 = FALSE; + byte *PLXIOBase = NULL, *DivasIOBase = NULL; + + DPRINTF(("divas: test interrupt for Diva Server BRI card")); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { /* PLX9060 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09); + } + else + { /* PLX9050 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41); + } + + card->test_int_pend = TEST_INT_DIVAS_BRI; + + UxCardMemDetach(card->hw, PLXIOBase); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89); + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block) +{ + dword user_addr = mem_block->addr; + word length = 0; + dword addr; + word i; + byte *DivasIOBase; + + DPRINTF(("divas: Retrieving memory from 0x%x", user_addr)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + addr = user_addr; + + for (i=0; i < (16 * 8); i++) + { + addr = user_addr + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr); + + mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + length++; + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return length; +} + +int DivasBriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server BRI card")); + + if (DivasBRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_bri_reset; + card->card_start = diva_server_bri_start; + card->card_load = diva_server_bri_load; + card->card_config = diva_server_bri_config; + card->reset_int = diva_server_bri_reset_int; + card->card_mem_get = diva_server_bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = bri_ISR; + + card->a.ram_out = io_out; + card->a.ram_outw = io_outw; + card->a.ram_out_buffer = io_out_buffer; + card->a.ram_inc = io_inc; + + card->a.ram_in = io_in; + card->a.ram_inw = io_inw; + card->a.ram_in_buffer = io_in_buffer; + card->a.ram_look_ahead = io_look_ahead; + + return 0; +} + +word GetProtFeatureValue(char *sw_id) +{ + word features = 0; + + while ((*sw_id) && (sw_id[0] != '[')) + sw_id++; + + if (sw_id == NULL) + { + DPRINTF(("divas: no feature string present")); + features = -1; + } + else + { + byte i, shifter; + + sw_id += 3; + + for (i=0, shifter=12; i<4; i++, shifter-=4) + { + if ((sw_id[i] >= '0') && (sw_id[i] <= '9')) + { + features |= (sw_id[i] - '0') << shifter; + } + else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f')) + { + features |= (sw_id[i] - 'a' + 10) << shifter; + } + else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F')) + { + features |= (sw_id[i] - 'A' + 10) << shifter; + } + else + { + DPRINTF(("divas: invalid feature string")); + return -1; + } + } + } + + return features; +} + + +int bri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +} + + diff --git a/drivers/isdn/eicon/common.c b/drivers/isdn/eicon/common.c new file mode 100644 index 000000000..4a4f77d9f --- /dev/null +++ b/drivers/isdn/eicon/common.c @@ -0,0 +1,896 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.15 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" + +#include "uxio.h" +#include <sys/types.h> + +#define MAX_ADDR_LEN + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_INTERRUPT 0x3C + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_SIGNATURE 0x4447 + +#define MP_PROTOCOL_ADDR 0xA0011000 + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +int DivasCardNext; +card_t DivasCards[MAX_CARDS]; + +dia_config_t *DivasConfig(card_t *, dia_config_t *); + +static +DESCRIPTOR DIDD_Table[16]; +static +int DIDD_Length = 0; + +void EtdM_DIDD_Read( DESCRIPTOR *table, int *tablelength ) +{ + int table_size = sizeof(DIDD_Table); + + bcopy((caddr_t)DIDD_Table, (caddr_t)table, table_size); + + *tablelength = DIDD_Length; + + return; +} + +static +void EtdM_DIDD_Write(DESCRIPTOR *table, int tablelength) +{ + int table_size = sizeof(DIDD_Table); + + bcopy((caddr_t)table, (caddr_t)DIDD_Table, table_size); + + DIDD_Length = tablelength; + + return; +} + +static +void init_idi_tab(void) +{ + int length = 0; + + DESCRIPTOR d[16]; + + EtdM_DIDD_Read(d, &length); + + d[length].type = IDI_DIMAINT; /* identify the DIMAINT entry */ + d[length].channels = 0; /* zero channels associated with dimaint*/ + d[length].features = 0; /* no features associated with dimaint */ + d[length].request = (IDI_CALL) DivasPrintf; + length++; + + EtdM_DIDD_Write(d, length); + + return; +} + +/* + * I/O routines for memory mapped cards + */ + +byte mem_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + byte value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemIn(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +word mem_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + word value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemInBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (dword) &RBuffer->length; + card->RBuffer.length = UxCardMemInW(card->hw, m); + + m = b; + m += (dword) &RBuffer->P; + UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOut(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutW(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + value++; + UxCardMemOutW(card->hw, m, value); + + UxCardMemDetach(card->hw, b); + + return; +} + +/* + * I/O routines for I/O mapped cards + */ + +byte io_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + byte value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoIn(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +word io_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + word value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer); + + UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length); + + UxCardMemDetach(card->hw, DivasIOBase); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + return; +} + +void io_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOut(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutW(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + byte *DivasIOBase; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + value++; + + UxCardIoOutW(card->hw, DivasIOBase, adr, value); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +void test_int(card_t *card) + +{ + byte *shared, *DivasIOBase; + + switch (card->test_int_pend) + { + case TEST_INT_DIVAS: + DPRINTF(("divas: test interrupt pending")); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + if (UxCardMemIn(card->hw, &shared[0x3FE])) + { + UxCardMemOut(card->hw, + &(((struct pr_ram *)shared)->RcOutput), 0); + UxCardMemDetach(card->hw, shared); + (*card->reset_int)(card); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + DPRINTF(("divas: test interrupt cleared")); + } + + UxCardMemDetach(card->hw, shared); + + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_BRI: + DPRINTF(("divas: BRI test interrupt pending")); + (*card->reset_int)(card); + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0); + UxCardMemDetach(card->hw, DivasIOBase); + DPRINTF(("divas: test interrupt cleared")); + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_Q: + DPRINTF(("divas: 4BRI test interrupt pending")); + (*card->reset_int)(card); + card->test_int_pend = 0; + break; + + default: + DPRINTF(("divas: unknown test interrupt pending")); + return; + } + return; +} + +void card_isr (void *dev_id) +{ + card_t *card = (card_t *) dev_id; + ADAPTER *a = &card->a; + int ipl; + + if (card->test_int_pend) + { + ipl = UxCardLock(card->hw); + card->int_pend=0; + test_int(card); + UxCardUnlock(card->hw,ipl); + return; + } + + if(card->card_isr) + { + (*(card->card_isr))(card); + } + else + { + ipl = UxCardLock(card->hw); + + if ((card->test_int)(a)) + { + (card->reset_int)(card); + } + + UxCardUnlock(card->hw,ipl); + + } + +} + +int DivasCardNew(dia_card_t *card_info) +{ + card_t *card; + byte b; + static boolean_t first_call = TRUE; + boolean_t NeedISRandReset = FALSE; + + DPRINTF(("divas: new card ")); + + if (first_call) + { + first_call = FALSE; + init_idi_tab(); + } + + DivasConfigGet(card_info); + + if (DivasCardNext == DIM(DivasCards)) + { + KDPRINTF((KERN_WARNING "Divas: no space available for new card")); + return -1; + } + + card = &DivasCards[DivasCardNext]; + + card->state = DIA_UNKNOWN; + + card->cfg = *card_info; + + card->a.io = card; + + if (UxCardHandleGet(&card->hw, card_info)) + { + KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card")); + return -1; + } + + if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + DivasBriPatch(card); + card_info->io_base = card->cfg.io_base; + } + + switch (card_info->card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + if (DivasPriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + if (DivasBriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_Q: + if (Divas4BriInit(card, card_info)) + { + return -1; + } + + if (card_info->name[6] == '0') + { + NeedISRandReset = TRUE; + } + else // Need to set paramater for ISR anyway + { + card->hw->user_isr_arg = card; + card->hw->user_isr = card_isr; + } + break; + + default: + KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type)); + return -1; + } + + if (NeedISRandReset) + { + if (UxIsrInstall(card->hw, card_isr, card)) + { + KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq)); + UxCardHandleFree(card->hw); + return -1; + } + + b = card->cfg.irq; + + UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b); + + if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q) + { + if ((*card->card_reset)(card)) + { + KDPRINTF((KERN_WARNING "Divas: Adapter reset failed")); + return -1; + } + card->state = DIA_RESET; + } + + NeedISRandReset = FALSE; + } + + DivasCardNext++; + + return 0; +} + +void *get_card(int card_id) +{ + int i; + + for (i=0; i < DivasCardNext; i++) + { + if (DivasCards[i].cfg.card_id == card_id) + { + return(&DivasCards[i]); + } + } + + DPRINTF(("divas: get_card() : no such card id (%d)", card_id)); + + return NULL; +} + +int DivasCardConfig(dia_config_t *config) +{ + card_t *card; + int status; + + DPRINTF(("divas: configuring card")); + + card = get_card(config->card_id); + if (!card) + { + return -1; + } + + config = DivasConfig(card, config); + + status = (*card->card_config)(card, config); + + if (!status) + { + card->state = DIA_CONFIGURED; + } + return status; +} + +int DivasCardLoad(dia_load_t *load) +{ + card_t *card; + int status; + + card = get_card(load->card_id); + if (!card) + { + return -1; + } + + if (card->state == DIA_RUNNING) + { + (*card->card_reset)(card); + } + + status = (*card->card_load)(card, load); + if (!status) + { + card->state = DIA_LOADED; + } + return status; +} + +static int idi_register(card_t *card, byte channels) +{ + DESCRIPTOR d[16]; + int length, num_entities; + + DPRINTF(("divas: registering card with IDI")); + + num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES; + card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities); + + if (!card->e_tbl) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available")); + return -1; + } + + bzero(card->e_tbl, sizeof(E_INFO) * num_entities); + card->e_max = num_entities; + + EtdM_DIDD_Read(d, &length); + + if (length == DIM(d)) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full")); + return -1; + } + + switch (card->cfg.card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + d[length].type = IDI_ADAPTER_PR; + d[length].serial = card->serial_no; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + d[length].type = IDI_ADAPTER_MAESTRA; + d[length].serial = card->serial_no; + break; + + // 4BRI is treated as 4 BRI adapters + case DIA_CARD_TYPE_DIVA_SERVER_Q: + d[length].type = IDI_ADAPTER_MAESTRA; + d[length].serial = card->cfg.serial; + } + + d[length].features = 0; + d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120; + + if ( card->hw->features & PROTCAP_MANIF ) + { + d[length].features |= DI_MANAGE ; + } + if ( card->hw->features & PROTCAP_V_42 ) + { + d[length].features |= DI_V_42 ; + } + if ( card->hw->features & PROTCAP_EXTD_FAX ) + { + d[length].features |= DI_EXTD_FAX ; + } + + d[length].channels = channels; + d[length].request = DivasIdiRequest[card - DivasCards]; + + length++; + + EtdM_DIDD_Write(d, length); + + return 0; +} + +int DivasCardStart(int card_id) +{ + card_t *card; + byte channels; + int status; + + DPRINTF(("divas: starting card")); + + card = get_card(card_id); + if (!card) + { + return -1; + } + + status = (*card->card_start)(card, &channels); + if (status) + { + return status; + } + + /* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */ + if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + int i; + card_t *FourBRISlave; + + for (i=3; i >= 0; i--) + { + FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */ + if (FourBRISlave) + { + idi_register(FourBRISlave, 2); + FourBRISlave->state = DIA_RUNNING; + } + } + card->serial_no = card->cfg.serial; + + DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", + card_id - 3, card->serial_no, (int) channels)); + } + else + { + status = idi_register(card, channels); + if (!status) + { + card->state = DIA_RUNNING; + DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", + card_id, card->serial_no, (int) channels)); + } + } + + return status; +} + +int DivasGetMem(mem_block_t *mem_block) +{ + card_t *card; + word card_id = mem_block->card_id; + + card = get_card(card_id); + if (!card) + { + return 0; + } + + return (*card->card_mem_get)(card, mem_block); +} + + +/* + * Deleyed Procedure Call for handling interrupts from card + */ + +void DivaDoCardDpc(card_t *card) +{ + ADAPTER *a; + + a = &card->a; + + if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1) + { + return; + } + + do{ + if((*(card->test_int))(a)) + { + (*(card->dpc))(a); + (*(card->clear_int))(a); + } + (*(card->out))(a); + }while(UxInterlockedDecrement(card->hw, &card->dpc_reentered)); + +} + +void DivasDoDpc(void *pData) +{ + card_t *card = DivasCards; + int i = DivasCardNext; + + while(i--) + { + DivaDoCardDpc(card++); + } +} + +void DivasDoRequestDpc(void *pData) +{ + DivasDoDpc(pData); +} + +/* + * DivasGetNum + * Returns the number of active adapters + */ + +int DivasGetNum(void) +{ + return(DivasCardNext); +} + +/* + * DivasGetList + * Returns a list of active adapters + */ +int DivasGetList(dia_card_list_t *card_list) +{ + int i; + + bzero(card_list, sizeof(dia_card_list_t)); + + for(i = 0; i < DivasCardNext; i++) + { + card_list->card_type = DivasCards[i].cfg.card_type; + card_list->card_slot = DivasCards[i].cfg.slot; + card_list->state = DivasCards[i].state; + card_list++; + } + + return 0; + +} + +/* + * control logging for specified card + */ + +void DivasLog(dia_log_t *log) +{ + card_t *card; + + card = get_card(log->card_id); + if (!card) + { + return; + } + + card->log_types = log->log_types; + + return; +} + diff --git a/drivers/isdn/eicon/constant.h b/drivers/isdn/eicon/constant.h new file mode 100644 index 000000000..ea92f05ad --- /dev/null +++ b/drivers/isdn/eicon/constant.h @@ -0,0 +1,179 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + + +/*------------------------------------------------------------------*/ +/* Q.931 information elements maximum length */ +/* excluding the identifier, including the length field */ +/*------------------------------------------------------------------*/ + +#define MAX_LEN_BC 13 +#define MAX_LEN_LLC 19 /* ctr3 */ +#define MAX_LEN_HLC 6 /* ctr3 */ +#define MAX_LEN_UUI 200 /* Hicom USBS req */ +#define MAX_LEN_NUM 24 +#define MAX_LEN_DSP 83 /* ctr3 */ +#define MAX_LEN_NI 4 +#define MAX_LEN_PI 5 +#define MAX_LEN_SIN 3 +#define MAX_LEN_CST 4 +#define MAX_LEN_SIG 2 +#define MAX_LEN_SPID 32 +#define MAX_LEN_EID 3 +#define MAX_LEN_CHI 35 /* ctr3 */ +#define MAX_LEN_CAU 33 +#define MAX_LEN_FTY 130 +#define MAX_LEN_KEY 83 /* ctr3 */ +#define MAX_LEN_RSI 4 +#define MAX_LEN_CAI 11 +#define MAX_NUM_SPID 4 +#define MAX_LEN_USERID 9 +#define MAX_LEN_APPLID 5 +#define MAX_LEN_NTTCIF 15 + +/*------------------------------------------------------------------*/ +/* decision return values */ +/*------------------------------------------------------------------*/ + +#define YES 1 +#define NO 0 + + +/*-------------------------------------------------------------------*/ +/* w element coding */ +/*-------------------------------------------------------------------*/ + +#define NTTCIF 0x01 +#define BC 0x04 +#define CAU 0x08 +#define CAD 0x0c +#define CAI 0x10 +#define CST 0x14 +#define CHI 0x18 +#define LLI 0x19 +#define CHA 0x1a +#define FTY 0x1c +#define PI 0x1e +#define NFAC 0x20 +#define TC 0x24 +#define ATT_EID 0x26 +#define NI 0x27 +#define DSP 0x28 +#define DT 0x29 +#define KEY 0x2c +#define KP 0x2c +#define UID 0x2d +#define SIG 0x34 +#define FI 0x39 +#define SPID 0x3a +#define EID 0x3b +#define DSPF 0x3c +#define ECAD 0x4c +#define OAD 0x6c +#define OSA 0x6d +#define DAD 0x70 +#define CPN 0x70 +#define DSA 0x71 +#define RDX 0x73 +#define RAD 0x74 +#define RDN 0x74 +#define RSI 0x79 +#define SCR 0x7A /* internal unscreened CPN */ +#define MIE 0x7a /* internal management info element */ +#define LLC 0x7c +#define HLC 0x7d +#define UUI 0x7e +#define ESC 0x7f + +#define SHIFT 0x90 +#define MORE 0xa0 +#define CL 0xb0 + +/* information elements used on the spid interface */ +#define SPID_CMD 0xc0 +#define SPID_LINK 0x10 +#define SPID_DN 0x70 +#define SPID_BC 0x04 +#define SPID_SWITCH 0x11 + +/*------------------------------------------------------------------*/ +/* global configuration parameters, defined in exec.c */ +/* these parameters are configured with program loading */ +/*------------------------------------------------------------------*/ + +#define PROT_1TR6 0 +#define PROT_ETSI 1 +#define PROT_FRANC 2 +#define PROT_BELG 3 +#define PROT_SWED 4 +#define PROT_NI 5 +#define PROT_5ESS 6 +#define PROT_JAPAN 7 +#define PROT_ATEL 8 +#define PROT_US 9 +#define PROT_ITALY 10 +#define PROT_TWAN 11 +#define PROT_AUSTRAL 12 + +#define INIT_PROT_1TR6 0x80|PROT_1TR6 +#define INIT_PROT_ETSI 0x80|PROT_ETSI +#define INIT_PROT_FRANC 0x80|PROT_FRANC +#define INIT_PROT_BELG 0x80|PROT_BELG +#define INIT_PROT_SWED 0x80|PROT_SWED +#define INIT_PROT_NI 0x80|PROT_NI +#define INIT_PROT_5ESS 0x80|PROT_5ESS +#define INIT_PROT_JAPAN 0x80|PROT_JAPAN +#define INIT_PROT_ATEL 0x80|PROT_ATEL +#define INIT_PROT_ITALY 0x80|PROT_ITALY +#define INIT_PROT_TWAN 0x80|PROT_TWAN +#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL + + +/* -----------------------------------------------------------** +** The PROTOCOL_FEATURE_STRING in feature.h (included ** +** in prstart.sx and astart.sx) defines capabilities and ** +** features of the actual protocol code. It's used as a bit ** +** mask. ** +** The following Bits are defined: ** +** -----------------------------------------------------------*/ + +#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ +#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ +#define PROTCAP_V_42 0x0004 /* V42 implemented */ +#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ +#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ +#define PROTCAP_FREE4 0x0020 /* not used */ +#define PROTCAP_FREE5 0x0040 /* not used */ +#define PROTCAP_FREE6 0x0080 /* not used */ +#define PROTCAP_FREE7 0x0100 /* not used */ +#define PROTCAP_FREE8 0x0200 /* not used */ +#define PROTCAP_FREE9 0x0400 /* not used */ +#define PROTCAP_FREE10 0x0800 /* not used */ +#define PROTCAP_FREE11 0x1000 /* not used */ +#define PROTCAP_FREE12 0x2000 /* not used */ +#define PROTCAP_FREE13 0x4000 /* not used */ +#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ diff --git a/drivers/isdn/eicon/divalog.h b/drivers/isdn/eicon/divalog.h new file mode 100644 index 000000000..93bd56ae9 --- /dev/null +++ b/drivers/isdn/eicon/divalog.h @@ -0,0 +1,57 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 file for defining the kernel loggger messages + * These definitions are shared between the klog driver and the + * klogd daemon process + */ + +#if !defined(_KLOGMSG_H) +#define _KLOGMSG_H + +/* define a type for a log entry */ + +#define KLOG_TEXT_MSG (0) +#define KLOG_XLOG_MSG (1) +#define KLOG_XTXT_MSG (2) +#define KLOG_IDI_REQ (4) +#define KLOG_IDI_CALLBACK (5) +#define KLOG_CAPI_MSG (6) + +typedef struct +{ + unsigned long time_stamp; /* in ms since last system boot */ + int card; /* card number (-1 for all) */ + unsigned int type; /* type of log message (0 is text) */ + unsigned int length; /* message length (non-text messages only) */ + unsigned short code; /* message code (non-text messages only) */ + char buffer[110];/* text/data to log */ +} klog_t; + +void DivasLogAdd(void *buffer, int length); +#endif /* of _KLOGMSG_H */ diff --git a/drivers/isdn/eicon/divas.h b/drivers/isdn/eicon/divas.h new file mode 100644 index 000000000..2fcd8349b --- /dev/null +++ b/drivers/isdn/eicon/divas.h @@ -0,0 +1,232 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* External Diva Server driver include file */ + +#if !defined(DIVAS_H) +#define DIVAS_H + +#include "sys.h" + + +/* IOCTL commands */ + +#define DIA_IOCTL_INIT (0) +#define DIA_IOCTL_LOAD (1) +#define DIA_IOCTL_CONFIG (2) +#define DIA_IOCTL_START (3) +#define DIA_IOCTL_GET_NUM (4) +#define DIA_IOCTL_GET_LIST (5) +#define DIA_IOCTL_LOG (6) +#define DIA_IOCTL_DETECT (7) +#define DIA_IOCTL_SPACE (8) +#define DIA_IOCTL_GET_MEM (9) +#define DIA_IOCTL_FLAVOUR (10) +#define DIA_IOCTL_XLOG_REQ (11) + +/* Error codes */ + +#define XLOG_ERR_CARD_NUM (13) +#define XLOG_ERR_DONE (14) +#define XLOG_ERR_CMD (15) +#define XLOG_ERR_TIMEOUT (16) +#define XLOG_ERR_CARD_STATE (17) +#define XLOG_ERR_UNKNOWN (18) +#define XLOG_OK (0) + +/* Adapter states */ + +#define DIA_UNKNOWN (0) +#define DIA_RESET (1) +#define DIA_LOADED (2) +#define DIA_CONFIGURED (3) +#define DIA_RUNNING (4) + +/* Stucture for getting card specific information from active cad driver */ + +typedef struct +{ + int card_type; + int card_slot; + int state; +} dia_card_list_t; + +/* use following to select which logging to have active */ + +#define DIVAS_LOG_DEBUG (1 << 0) +#define DIVAS_LOG_XLOG (1 << 1) +#define DIVAS_LOG_IDI (1 << 2) +#define DIVAS_LOG_CAPI (1 << 3) + +/* stucture for DIA_IOCTL_LOG to get information from adapter */ + +typedef struct +{ + int card_id; + int log_types; /* bit mask of log types: use DIVAS_LOG_XXX */ +} dia_log_t; + +/* list of cards supported by this driver */ + +#define DIA_CARD_TYPE_DIVA_SERVER (0) /* Diva Server PRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_B (1) /* Diva Server BRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_Q (2) /* Diva Server 4-BRI */ + +/* bus types */ + +#define DIA_BUS_TYPE_ISA (0) +#define DIA_BUS_TYPE_ISA_PNP (1) +#define DIA_BUS_TYPE_PCI (2) +#define DIA_BUS_TYPE_MCA (3) + +/* types of memory used (index for memory array below) */ + +#define DIVAS_RAM_MEMORY 0 +#define DIVAS_REG_MEMORY 1 +#define DIVAS_CFG_MEMORY 2 +#define DIVAS_SHARED_MEMORY 3 +#define DIVAS_CTL_MEMORY 4 +/* + * card config information + * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card + */ + +typedef struct +{ + int card_id; /* unique id assigned to this card */ + int card_type; /* use DIA_CARD_TYPE_xxx above */ + int bus_type; /* use DIA_BUS_TYPE_xxx above */ + int bus_num; /* bus number (instance number of bus type) */ + int func_num; /* adapter function number (PCI register) */ + int slot; /* slot number in bus */ + unsigned char irq; /* IRQ number */ + int reset_base; /* Reset register for I/O mapped cards */ + int io_base; /* I/O base for I/O mapped cards */ + void *memory[5]; /* memory base addresses for memory mapped cards */ + char name[9]; /* name of adapter */ + int serial; /* serial number */ + unsigned char int_priority; /* Interrupt priority */ +} dia_card_t; + +/* + * protocol configuration information + * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card + */ + +typedef struct +{ + int card_id; /* to identify particular card */ + unsigned char tei; + unsigned char nt2; + unsigned char watchdog; + unsigned char permanent; + unsigned char x_interface; + unsigned char stable_l2; + unsigned char no_order_check; + unsigned char handset_type; + unsigned char sig_flags; + unsigned char low_channel; + unsigned char prot_version; + unsigned char crc4; + struct + { + unsigned char oad[32]; + unsigned char osa[32]; + unsigned char spid[32]; + }terminal[2]; +} dia_config_t; + +/* + * code configuration + * passed as parameter to DIA_IOCTL_LOAD ioctl + * one of these ioctl per code file to load + */ + +typedef struct +{ + int card_id; /* card to load */ + enum + { + DIA_CPU_CODE, /* CPU code */ + DIA_DSP_CODE, /* DSP code */ + DIA_CONT_CODE, /* continuation of code */ + DIA_TABLE_CODE, /* code table */ + DIA_DLOAD_CNT, /* number of downloads*/ + DIA_FPGA_CODE + } code_type; /* code for CPU or DSP ? */ + int length; /* length of code */ + unsigned char *code; /* pointer (in user-space) to code */ +} dia_load_t; + +/* + * start configuration + * passed as parameter to DIA_IOCTL_START ioctl + */ + +typedef struct +{ + int card_id; /* card to start */ +} dia_start_t; + +/* used for retrieving memory from the card */ + +typedef struct { + word card_id; + dword addr; + byte data[16 * 8]; +} mem_block_t; + +/* DIVA Server specific addresses */ + +#define DIVAS_CPU_START_ADDR (0x0) +#define ORG_MAX_PROTOCOL_CODE_SIZE 0x000A0000 +#define ORG_MAX_DSP_CODE_SIZE (0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE) +#define ORG_DSP_CODE_BASE (0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE) +#define DIVAS_DSP_START_ADDR (0xBF7A0000) +#define DIVAS_SHARED_OFFSET (0x1000) +#define MP_DSP_CODE_BASE 0xa03a0000 +#define MQ_PROTCODE_OFFSET 0x100000 +#define MQ_SM_OFFSET 0X0f0000 + +#define V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 +#define V90D_MAX_DSP_CODE_SIZE (0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE) +#define V90D_DSP_CODE_BASE (0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE) + +#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ +#define MQ_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code */ +#define MQ_ORG_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_ORG_MAX_DSP_CODE_SIZE) +#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 /* max 576K Protocol-Code */ +#define MQ_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code if V.90D included */ +#define MQ_MAX_DSP_DOWNLOAD_ADDR 0xa03f0000 +#define MQ_V90D_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_V90D_MAX_DSP_CODE_SIZE) + + +#define ALIGNMENT_MASK_MAESTRA 0xfffffffc + +#endif /* DIVAS_H */ diff --git a/drivers/isdn/eicon/dsp_defs.h b/drivers/isdn/eicon/dsp_defs.h new file mode 100644 index 000000000..ee7c1429e --- /dev/null +++ b/drivers/isdn/eicon/dsp_defs.h @@ -0,0 +1,303 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#ifndef DSP_DEFS_H_ +#define DSP_DEFS_H_ + +#ifndef DSPDIDS_H_ +#include "dspdids.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif +#ifndef TRUE +#define TRUE (0 == 0) +#endif +#ifndef FALSE +#define FALSE (0 != 0) +#endif + + +/*---------------------------------------------------------------------------*/ + +#define DSP_MEMORY_TYPE_EXTERNAL_DM 0 +#define DSP_MEMORY_TYPE_EXTERNAL_PM 1 +#define DSP_MEMORY_TYPE_INTERNAL_DM 2 +#define DSP_MEMORY_TYPE_INTERNAL_PM 3 + +#define DSP_DOWNLOAD_FLAG_BOOTABLE 0x0001 +#define DSP_DOWNLOAD_FLAG_2181 0x0002 +#define DSP_DOWNLOAD_FLAG_TIMECRITICAL 0x0004 +#define DSP_DOWNLOAD_FLAG_COMPAND 0x0008 + +#define DSP_MEMORY_BLOCK_COUNT 16 + +#define DSP_SEGMENT_PM_FLAG 0x0001 +#define DSP_SEGMENT_SHARED_FLAG 0x0002 + +#define DSP_SEGMENT_EXTERNAL_DM DSP_MEMORY_TYPE_EXTERNAL_DM +#define DSP_SEGMENT_EXTERNAL_PM DSP_MEMORY_TYPE_EXTERNAL_PM +#define DSP_SEGMENT_INTERNAL_DM DSP_MEMORY_TYPE_INTERNAL_DM +#define DSP_SEGMENT_INTERNAL_PM DSP_MEMORY_TYPE_INTERNAL_PM +#define DSP_SEGMENT_FIRST_RELOCATABLE 4 + +#define DSP_DATA_BLOCK_PM_FLAG 0x0001 +#define DSP_DATA_BLOCK_DWORD_FLAG 0x0002 +#define DSP_DATA_BLOCK_RESOLVE_FLAG 0x0004 + +#define DSP_RELOC_NONE 0x00 +#define DSP_RELOC_SEGMENT_MASK 0x3f +#define DSP_RELOC_TYPE_MASK 0xc0 +#define DSP_RELOC_TYPE_0 0x00 /* relocation of address in DM word / high part of PM word */ +#define DSP_RELOC_TYPE_1 0x40 /* relocation of address in low part of PM data word */ +#define DSP_RELOC_TYPE_2 0x80 /* relocation of address in standard command */ +#define DSP_RELOC_TYPE_3 0xc0 /* relocation of address in call/jump on flag in */ + +#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 + +#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 + + +typedef struct tag_dsp_combifile_header +{ + char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word header_size; + word combifile_description_size; + word directory_entries; + word directory_size; + word download_count; + word usage_mask_size; +} t_dsp_combifile_header; + +typedef struct tag_dsp_combifile_directory_entry +{ + word card_type_number; + word file_set_number; +} t_dsp_combifile_directory_entry; + +typedef struct tag_dsp_file_header +{ + char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word header_size; + word download_description_size; + word memory_block_table_size; + word memory_block_count; + word segment_table_size; + word segment_count; + word symbol_table_size; + word symbol_count; + word total_data_size_dm; + word data_block_count_dm; + word total_data_size_pm; + word data_block_count_pm; +} t_dsp_file_header; + +typedef struct tag_dsp_memory_block_desc +{ + word alias_memory_block; + word memory_type; + word address; + word size; /* DSP words */ +} t_dsp_memory_block_desc; + +typedef struct tag_dsp_segment_desc +{ + word memory_block; + word attributes; + word base; + word size; + word alignment; /* ==0 -> no other legal start address than base */ +} t_dsp_segment_desc; + +typedef struct tag_dsp_symbol_desc +{ + word symbol_id; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_symbol_desc; + +typedef struct tag_dsp_data_block_header +{ + word attributes; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_data_block_header; + +typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ +{ + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word excess_header_size; + word memory_block_count; + word segment_count; + word symbol_count; + word data_block_count_dm; + word data_block_count_pm; + byte *p_excess_header_data; + char *p_download_description; + t_dsp_memory_block_desc *p_memory_block_table; + t_dsp_segment_desc *p_segment_table; + t_dsp_symbol_desc *p_symbol_table; + word *p_data_blocks_dm; + word *p_data_blocks_pm; +} t_dsp_download_desc; + +#define DSP_DOWNLOAD_INDEX_KERNEL 0 +#define DSP30TX_DOWNLOAD_INDEX_KERNEL 1 +#define DSP30RX_DOWNLOAD_INDEX_KERNEL 2 +#define DSP_MAX_DOWNLOAD_COUNT 35 + + +#define DSP_DOWNLOAD_MAX_SEGMENTS 16 + +#define DSP_UDATA_REQUEST_RECONFIGURE 0 +/* +parameters: + <word> reconfigure delay (in 8kHz samples) + <word> reconfigure code + <byte> reconfigure hdlc preamble flags +*/ + +#define DSP_RECONFIGURE_TX_FLAG 0x8000 +#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 +#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 +#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 +#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 +#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff +#define DSP_RECONFIGURE_IDLE 0 +#define DSP_RECONFIGURE_V25 1 +#define DSP_RECONFIGURE_V21_CH2 2 +#define DSP_RECONFIGURE_V27_2400 3 +#define DSP_RECONFIGURE_V27_4800 4 +#define DSP_RECONFIGURE_V29_7200 5 +#define DSP_RECONFIGURE_V29_9600 6 +#define DSP_RECONFIGURE_V33_12000 7 +#define DSP_RECONFIGURE_V33_14400 8 +#define DSP_RECONFIGURE_V17_7200 9 +#define DSP_RECONFIGURE_V17_9600 10 +#define DSP_RECONFIGURE_V17_12000 11 +#define DSP_RECONFIGURE_V17_14400 12 + +/* +data indications if transparent framer + <byte> data 0 + <byte> data 1 + ... + +data indications if HDLC framer + <byte> data 0 + <byte> data 1 + ... + <byte> CRC 0 + <byte> CRC 1 + <byte> preamble flags +*/ + +#define DSP_UDATA_INDICATION_SYNC 0 +/* +returns: + <word> time of sync (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_OFF 1 +/* +returns: + <word> time of DCD off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_ON 2 +/* +returns: + <word> time of DCD on (sampled from counter at 8kHz) + <byte> connected norm + <word> connected options + <dword> connected speed (bit/s) +*/ + +#define DSP_UDATA_INDICATION_CTS_OFF 3 +/* +returns: + <word> time of CTS off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_CTS_ON 4 +/* +returns: + <word> time of CTS on (sampled from counter at 8kHz) + <byte> connected norm + <word> connected options + <dword> connected speed (bit/s) +*/ + +#define DSP_CONNECTED_NORM_UNSPECIFIED 0 +#define DSP_CONNECTED_NORM_V21 1 +#define DSP_CONNECTED_NORM_V23 2 +#define DSP_CONNECTED_NORM_V22 3 +#define DSP_CONNECTED_NORM_V22_BIS 4 +#define DSP_CONNECTED_NORM_V32_BIS 5 +#define DSP_CONNECTED_NORM_V34 6 +#define DSP_CONNECTED_NORM_V8 7 +#define DSP_CONNECTED_NORM_BELL_212A 8 +#define DSP_CONNECTED_NORM_BELL_103 9 +#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 +#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 +#define DSP_CONNECTED_NORM_TFAST 12 +#define DSP_CONNECTED_NORM_V21_CH2 13 +#define DSP_CONNECTED_NORM_V27_TER 14 +#define DSP_CONNECTED_NORM_V29 15 +#define DSP_CONNECTED_NORM_V33 16 +#define DSP_CONNECTED_NORM_V17 17 + +#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 + + +/*---------------------------------------------------------------------------*/ +#ifdef __cplusplus +} +#endif + +#endif + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/isdn/eicon/dspdids.h b/drivers/isdn/eicon/dspdids.h new file mode 100644 index 000000000..1ac6a9bc6 --- /dev/null +++ b/drivers/isdn/eicon/dspdids.h @@ -0,0 +1,84 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#ifndef DSPDIDS_H_ +#define DSPDIDS_H_ + + +/*---------------------------------------------------------------------------*/ + +#define DSP_DID_INVALID 0 +#define DSP_DID_DIVA 1 +#define DSP_DID_DIVA_PRO 2 +#define DSP_DID_DIVA_PRO_20 3 +#define DSP_DID_DIVA_PRO_PCCARD 4 +#define DSP_DID_DIVA_SERVER_BRI_1M 5 +#define DSP_DID_DIVA_SERVER_BRI_2M 6 +#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7 +#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8 +#define DSP_DID_DIVA_SERVER_PRI_30M 9 +#define DSP_DID_TASK_HSCX 100 +#define DSP_DID_TASK_HSCX_PRI_2M_TX 101 +#define DSP_DID_TASK_HSCX_PRI_2M_RX 102 +#define DSP_DID_TASK_V110KRNL 200 +#define DSP_DID_OVERLAY_V1100 201 +#define DSP_DID_OVERLAY_V1101 202 +#define DSP_DID_OVERLAY_V1102 203 +#define DSP_DID_OVERLAY_V1103 204 +#define DSP_DID_OVERLAY_V1104 205 +#define DSP_DID_OVERLAY_V1105 206 +#define DSP_DID_OVERLAY_V1106 207 +#define DSP_DID_OVERLAY_V1107 208 +#define DSP_DID_OVERLAY_V1108 209 +#define DSP_DID_OVERLAY_V1109 210 +#define DSP_DID_TASK_V110_PRI_2M_TX 220 +#define DSP_DID_TASK_V110_PRI_2M_RX 221 +#define DSP_DID_TASK_MODEM 300 +#define DSP_DID_TASK_FAX05 400 +#define DSP_DID_TASK_VOICE 500 +#define DSP_DID_TASK_TIKRNL81 600 +#define DSP_DID_OVERLAY_DIAL 601 +#define DSP_DID_OVERLAY_V22 602 +#define DSP_DID_OVERLAY_V32 603 +#define DSP_DID_OVERLAY_FSK 604 +#define DSP_DID_OVERLAY_FAX 605 +#define DSP_DID_OVERLAY_VXX 606 +#define DSP_DID_OVERLAY_V8 607 +#define DSP_DID_OVERLAY_INFO 608 +#define DSP_DID_OVERLAY_V34 609 +#define DSP_DID_OVERLAY_DFX 610 +#define DSP_DID_PARTIAL_OVERLAY_DIAL 611 +#define DSP_DID_PARTIAL_OVERLAY_FSK 612 +#define DSP_DID_PARTIAL_OVERLAY_FAX 613 +#define DSP_DID_TASK_TIKRNL05 700 + + +/*---------------------------------------------------------------------------*/ + +#endif + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h index 5ad164518..42e9b3b95 100644 --- a/drivers/isdn/eicon/eicon.h +++ b/drivers/isdn/eicon/eicon.h @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon.h,v 1.23 2000/06/21 11:28:42 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,86 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon.h,v $ - * Revision 1.19 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.18 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.17 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.16 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.15 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.14 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.13 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.12 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.11 1999/08/29 17:23:44 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/22 20:26:41 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/18 20:16:57 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:01 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:23 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:24 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/03/29 11:19:41 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:42 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:07 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:04 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ @@ -124,6 +44,8 @@ #define EICON_IOCTL_TEST 98 #define EICON_IOCTL_DEBUGVAR 99 +#define EICON_IOCTL_DIA_OFFSET 100 + /* Bus types */ #define EICON_BUS_ISA 1 #define EICON_BUS_MCA 2 @@ -185,39 +107,10 @@ typedef struct { unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */ } eicon_isa_codebuf; -/* Struct for downloading protocol via ioctl for PCI cards */ -typedef struct { - /* start-up parameters */ - unsigned char tei; - unsigned char nt2; - unsigned char WatchDog; - unsigned char Permanent; - unsigned char XInterface; - unsigned char StableL2; - unsigned char NoOrderCheck; - unsigned char HandsetType; - unsigned char LowChannel; - unsigned char ProtVersion; - unsigned char Crc4; - unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */ - unsigned char Loopback; /* switch card into Loopback mode */ - struct q931_link_s - { - unsigned char oad[32]; - unsigned char osa[32]; - unsigned char spid[32]; - } l[2]; - unsigned long protocol_len; - unsigned int dsp_code_num; - unsigned long dsp_code_len[9]; - unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */ -} eicon_pci_codebuf; - /* Data for downloading protocol via ioctl */ typedef union { eicon_isa_codebuf isa; eicon_isa_codebuf mca; - eicon_pci_codebuf pci; } eicon_codebuf; /* Data for Management interface */ @@ -228,6 +121,7 @@ typedef struct { unsigned char data[700]; } eicon_manifbuf; +#define TRACE_OK (1) #ifdef __KERNEL__ @@ -265,206 +159,34 @@ typedef struct { #include "eicon_isa.h" +#include "idi.h" + +typedef struct { + __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ + __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ + __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ + __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ + __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ + __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ + __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ + __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ + __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ + __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ + __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ + __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ + __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ + __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ + __u8 B[1]; /* buffer space for Req,Ind and Rc */ +} eicon_pr_ram; + /* Macro for delay via schedule() */ #define SLEEP(j) { \ set_current_state(TASK_UNINTERRUPTIBLE); \ schedule_timeout(j); \ } -#endif /* KERNEL */ - -#define DIVAS_SHARED_OFFSET (0x1000) - -#define MIPS_BUFFER_SZ 128 -#define MIPS_MAINT_OFFS 0xff00 - -#define XLOG_ERR_CARD_NUM (13) -#define XLOG_ERR_DONE (14) -#define XLOG_ERR_CMD (15) -#define XLOG_ERR_TIMEOUT (16) -#define XLOG_ERR_CARD_STATE (17) -#define XLOG_ERR_UNKNOWN (18) -#define XLOG_OK (0) - -#define TRACE_OK (1) - -typedef struct { - __u8 Id __attribute__ ((packed)); - __u8 uX __attribute__ ((packed)); - __u8 listen __attribute__ ((packed)); - __u8 active __attribute__ ((packed)); - __u8 sin[3] __attribute__ ((packed)); - __u8 bc[6] __attribute__ ((packed)); - __u8 llc[6] __attribute__ ((packed)); - __u8 hlc[6] __attribute__ ((packed)); - __u8 oad[20] __attribute__ ((packed)); -}DSigStruc; - -typedef struct { - __u32 cx_b1 __attribute__ ((packed)); - __u32 cx_b2 __attribute__ ((packed)); - __u32 cr_b1 __attribute__ ((packed)); - __u32 cr_b2 __attribute__ ((packed)); - __u32 px_b1 __attribute__ ((packed)); - __u32 px_b2 __attribute__ ((packed)); - __u32 pr_b1 __attribute__ ((packed)); - __u32 pr_b2 __attribute__ ((packed)); - __u16 er_b1 __attribute__ ((packed)); - __u16 er_b2 __attribute__ ((packed)); -}BL1Struc; - -typedef struct { - __u32 XTotal __attribute__ ((packed)); - __u32 RTotal __attribute__ ((packed)); - __u16 XError __attribute__ ((packed)); - __u16 RError __attribute__ ((packed)); -}L2Struc; - -typedef struct { - __u16 free_n; -}OSStruc; - -typedef union -{ - DSigStruc DSigStats; - BL1Struc BL1Stats; - L2Struc L2Stats; - OSStruc OSStats; - __u8 b[MIPS_BUFFER_SZ]; - __u16 w[MIPS_BUFFER_SZ>>1]; - __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ - __u32 d[MIPS_BUFFER_SZ>>2]; -} MIPS_BUFFER; - -typedef struct -{ - __u8 req __attribute__ ((packed)); - __u8 rc __attribute__ ((packed)); - __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */ - __u8 *mem __attribute__ ((packed)); - __u16 length __attribute__ ((packed)); /* used to be short */ - __u16 port __attribute__ ((packed)); - __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */ - MIPS_BUFFER data __attribute__ ((packed)); -} mi_pc_maint_t; - -typedef struct -{ - __u16 command; - mi_pc_maint_t pcm; -}xlogreq_t; - -typedef struct{ - __u16 code __attribute__ ((packed)); /* used to be short */ - __u16 timeh __attribute__ ((packed)); - __u16 timel __attribute__ ((packed)); - char buffer[MIPS_BUFFER_SZ - 6]; -}xlog_entry_t; - - -#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 - -#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 - -typedef struct tag_dsp_combifile_header -{ - char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 combifile_description_size __attribute__ ((packed)); - __u16 directory_entries __attribute__ ((packed)); - __u16 directory_size __attribute__ ((packed)); - __u16 download_count __attribute__ ((packed)); - __u16 usage_mask_size __attribute__ ((packed)); -} t_dsp_combifile_header; - -typedef struct tag_dsp_combifile_directory_entry -{ - __u16 card_type_number __attribute__ ((packed)); - __u16 file_set_number __attribute__ ((packed)); -} t_dsp_combifile_directory_entry; - -typedef struct tag_dsp_file_header -{ - char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 download_id __attribute__ ((packed)); - __u16 download_flags __attribute__ ((packed)); - __u16 required_processing_power __attribute__ ((packed)); - __u16 interface_channel_count __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 download_description_size __attribute__ ((packed)); - __u16 memory_block_table_size __attribute__ ((packed)); - __u16 memory_block_count __attribute__ ((packed)); - __u16 segment_table_size __attribute__ ((packed)); - __u16 segment_count __attribute__ ((packed)); - __u16 symbol_table_size __attribute__ ((packed)); - __u16 symbol_count __attribute__ ((packed)); - __u16 total_data_size_dm __attribute__ ((packed)); - __u16 data_block_count_dm __attribute__ ((packed)); - __u16 total_data_size_pm __attribute__ ((packed)); - __u16 data_block_count_pm __attribute__ ((packed)); -} t_dsp_file_header; - -typedef struct tag_dsp_memory_block_desc -{ - __u16 alias_memory_block; - __u16 memory_type; - __u16 address; - __u16 size; /* DSP words */ -} t_dsp_memory_block_desc; - -typedef struct tag_dsp_segment_desc -{ - __u16 memory_block; - __u16 attributes; - __u16 base; - __u16 size; - __u16 alignment; /* ==0 -> no other legal start address than base */ -} t_dsp_segment_desc; - -typedef struct tag_dsp_symbol_desc -{ - __u16 symbol_id; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_symbol_desc; - -typedef struct tag_dsp_data_block_header -{ - __u16 attributes; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_data_block_header; - -typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ -{ - __u16 download_id; - __u16 download_flags; - __u16 required_processing_power; - __u16 interface_channel_count; - __u16 excess_header_size; - __u16 memory_block_count; - __u16 segment_count; - __u16 symbol_count; - __u16 data_block_count_dm; - __u16 data_block_count_pm; - __u8 * p_excess_header_data __attribute__ ((packed)); - char * p_download_description __attribute__ ((packed)); - t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed)); - t_dsp_segment_desc *p_segment_table __attribute__ ((packed)); - t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed)); - __u16 * p_data_blocks_dm __attribute__ ((packed)); - __u16 * p_data_blocks_pm __attribute__ ((packed)); -} t_dsp_download_desc; - - -#ifdef __KERNEL__ - typedef struct { __u8 Req; /* pending request */ __u8 Rc; /* return code received */ @@ -508,6 +230,7 @@ typedef struct { unsigned short statectrl; /* State controling bits */ unsigned short eazmask; /* EAZ-Mask for this Channel */ int queued; /* User-Data Bytes in TX queue */ + int pqueued; /* User-Data Packets in TX queue */ int waitq; /* User-Data Bytes in wait queue */ int waitpq; /* User-Data Bytes in packet queue */ struct sk_buff *tskb1; /* temp skb 1 */ @@ -518,7 +241,9 @@ typedef struct { T30_s *fax; /* pointer to fax data in LL */ eicon_ch_fax_buf fax2; /* fax related struct */ #endif - entity e; /* Entity */ + entity e; /* Native Entity */ + ENTITY de; /* Divas D Entity */ + ENTITY be; /* Divas B Entity */ char cpn[32]; /* remember cpn */ char oad[32]; /* remember oad */ char dsa[32]; /* remember dsa */ @@ -542,8 +267,6 @@ typedef struct { #define EICON_FLAGS_MVALID 8 /* Cards membase is valid */ #define EICON_FLAGS_LOADED 8 /* Firmware loaded */ -#define EICON_BCH 2 /* # of channels per card */ - /* D-Channel states */ #define EICON_STATE_NULL 0 #define EICON_STATE_ICALL 1 @@ -565,9 +288,6 @@ typedef struct { #define EICON_MAX_QUEUE 2138 -#define EICON_LOCK_TX 0 -#define EICON_LOCK_RX 1 - typedef union { eicon_isa_card isa; eicon_pci_card pci; @@ -593,17 +313,12 @@ typedef struct { __u8 more; } eicon_indhdr; -typedef struct msn_entry { - char eaz; - char msn[16]; - struct msn_entry * next; -} msn_entry; - /* * Per card driver data */ typedef struct eicon_card { eicon_hwif hwif; /* Hardware dependant interface */ + DESCRIPTOR *d; /* IDI Descriptor */ u_char ptype; /* Protocol type (1TR6 or Euro) */ u_char bus; /* Bustype (ISA, MCA, PCI) */ u_char type; /* Cardtype (EICON_CTYPE_...) */ @@ -621,49 +336,23 @@ typedef struct eicon_card { struct tq_struct snd_tq; /* Task struct for xmit bh */ struct tq_struct rcv_tq; /* Task struct for rcv bh */ struct tq_struct ack_tq; /* Task struct for ack bh */ - msn_entry *msn_list; eicon_chan* IdTable[256]; /* Table to find entity */ __u16 ref_in; __u16 ref_out; int nchannels; /* Number of B-Channels */ int ReadyInt; /* Ready Interrupt */ eicon_chan *bch; /* B-Channel status/control */ - char status_buf[256]; /* Buffer for status messages */ - char *status_buf_read; - char *status_buf_write; - char *status_buf_end; + DBUFFER *dbuf; /* Dbuffer for Diva Server */ + BUFFERS *sbuf; /* Buffer for Diva Server */ + char *sbufp; /* Data Buffer for Diva Server */ isdn_if interface; /* Interface to upper layer */ - char regname[35]; /* Name used for request_region */ + char regname[35]; /* Drivers card name */ #ifdef CONFIG_MCA int mca_slot; /* # of cards MCA slot */ int mca_io; /* MCA cards IO port */ #endif /* CONFIG_MCA */ } eicon_card; -/* -----------------------------------------------------------** -** The PROTOCOL_FEATURE_STRING ** -** defines capabilities and ** -** features of the actual protocol code. It's used as a bit ** -** mask. ** -** The following Bits are defined: ** -** -----------------------------------------------------------*/ -#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ -#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ -#define PROTCAP_V_42 0x0004 /* V42 implemented */ -#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ -#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ -#define PROTCAP_FREE4 0x0020 /* not used */ -#define PROTCAP_FREE5 0x0040 /* not used */ -#define PROTCAP_FREE6 0x0080 /* not used */ -#define PROTCAP_FREE7 0x0100 /* not used */ -#define PROTCAP_FREE8 0x0200 /* not used */ -#define PROTCAP_FREE9 0x0400 /* not used */ -#define PROTCAP_FREE10 0x0800 /* not used */ -#define PROTCAP_FREE11 0x1000 /* not used */ -#define PROTCAP_FREE12 0x2000 /* not used */ -#define PROTCAP_FREE13 0x4000 /* not used */ -#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ - #include "eicon_idi.h" extern eicon_card *cards; @@ -688,13 +377,11 @@ extern __inline__ void eicon_schedule_ack(eicon_card *card) mark_bh(IMMEDIATE_BH); } -extern char *eicon_find_eaz(eicon_card *, char); -extern int eicon_addcard(int, int, int, char *); +extern int eicon_addcard(int, int, int, char *, int); extern void eicon_io_transmit(eicon_card *card); extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs); extern void eicon_io_rcv_dispatch(eicon_card *ccard); extern void eicon_io_ack_dispatch(eicon_card *ccard); -extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq); #ifdef CONFIG_MCA extern int eicon_mca_find_card(int, int, int, char *); extern int eicon_mca_probe(int, int, int, int, char *); @@ -705,6 +392,8 @@ extern ulong DebugVar; extern void eicon_log(eicon_card * card, int level, const char *fmt, ...); extern void eicon_putstatus(eicon_card * card, char * buf); +extern spinlock_t eicon_lock; + #endif /* __KERNEL__ */ #endif /* eicon_h */ diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h index 420d73f6e..1470fa7e6 100644 --- a/drivers/isdn/eicon/eicon_dsp.h +++ b/drivers/isdn/eicon/eicon_dsp.h @@ -1,4 +1,4 @@ -/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * DSP definitions @@ -20,75 +20,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_dsp.h,v $ - * Revision 1.5 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.4 1999/07/25 15:12:02 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.3 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.2 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.1 1999/03/02 12:18:54 armin - * First checkin of DSP defines for audio features. - * * */ #ifndef DSP_H #define DSP_H -#define DSP_UDATA_REQUEST_RECONFIGURE 0 -/* -parameters: - <word> reconfigure delay (in 8kHz samples) - <word> reconfigure code - <byte> reconfigure hdlc preamble flags -*/ +#include "dsp_defs.h" -#define DSP_RECONFIGURE_TX_FLAG 0x8000 -#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 -#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 -#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 -#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 -#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff -#define DSP_RECONFIGURE_IDLE 0 -#define DSP_RECONFIGURE_V25 1 -#define DSP_RECONFIGURE_V21_CH2 2 -#define DSP_RECONFIGURE_V27_2400 3 -#define DSP_RECONFIGURE_V27_4800 4 -#define DSP_RECONFIGURE_V29_7200 5 -#define DSP_RECONFIGURE_V29_9600 6 -#define DSP_RECONFIGURE_V33_12000 7 -#define DSP_RECONFIGURE_V33_14400 8 -#define DSP_RECONFIGURE_V17_7200 9 -#define DSP_RECONFIGURE_V17_9600 10 -#define DSP_RECONFIGURE_V17_12000 11 -#define DSP_RECONFIGURE_V17_14400 12 - -/* -data indications if transparent framer - <byte> data 0 - <byte> data 1 - ... - -data indications if HDLC framer - <byte> data 0 - <byte> data 1 - ... - <byte> CRC 0 - <byte> CRC 1 - <byte> preamble flags -*/ #define DSP_UDATA_REQUEST_SWITCH_FRAMER 1 /* @@ -122,49 +61,6 @@ parameters: - none - */ - -#define DSP_UDATA_INDICATION_SYNC 0 -/* -returns: - <word> time of sync (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_OFF 1 -/* -returns: - <word> time of DCD off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_ON 2 -/* -returns: - <word> time of DCD on (sampled from counter at 8kHz) - <byte> connected norm - <word> connected options - <dword> connected speed (bit/s, max of tx and rx speed) - <word> roundtrip delay (ms) - <dword> connected speed tx (bit/s) - <dword> connected speed rx (bit/s) -*/ - -#define DSP_UDATA_INDICATION_CTS_OFF 3 -/* -returns: - <word> time of CTS off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_CTS_ON 4 -/* -returns: - <word> time of CTS on (sampled from counter at 8kHz) - <byte> connected norm - <word> connected options - <dword> connected speed (bit/s, max of tx and rx speed) - <word> roundtrip delay (ms) - <dword> connected speed tx (bit/s) - <dword> connected speed rx (bit/s) -*/ - typedef struct eicon_dsp_ind { __u16 time __attribute__ ((packed)); __u8 norm __attribute__ ((packed)); @@ -175,32 +71,11 @@ typedef struct eicon_dsp_ind { __u32 rxspeed __attribute__ ((packed)); } eicon_dsp_ind; -#define DSP_CONNECTED_NORM_UNSPECIFIED 0 -#define DSP_CONNECTED_NORM_V21 1 -#define DSP_CONNECTED_NORM_V23 2 -#define DSP_CONNECTED_NORM_V22 3 -#define DSP_CONNECTED_NORM_V22_BIS 4 -#define DSP_CONNECTED_NORM_V32_BIS 5 -#define DSP_CONNECTED_NORM_V34 6 -#define DSP_CONNECTED_NORM_V8 7 -#define DSP_CONNECTED_NORM_BELL_212A 8 -#define DSP_CONNECTED_NORM_BELL_103 9 -#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 -#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 -#define DSP_CONNECTED_NORM_V90 12 -#define DSP_CONNECTED_NORM_V21_CH2 13 -#define DSP_CONNECTED_NORM_V27_TER 14 -#define DSP_CONNECTED_NORM_V29 15 -#define DSP_CONNECTED_NORM_V33 16 -#define DSP_CONNECTED_NORM_V17 17 - -#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 #define DSP_CONNECTED_OPTION_V42_TRANS 0x0002 #define DSP_CONNECTED_OPTION_V42_LAPM 0x0004 #define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008 #define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010 - #define DSP_UDATA_INDICATION_DISCONNECT 5 /* returns: @@ -214,7 +89,6 @@ returns: #define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04 #define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05 - #define DSP_UDATA_INDICATION_TX_CONFIRMATION 6 /* returns: diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index 9cef520bc..5b63311da 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $ +/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,135 +25,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.c,v $ - * Revision 1.33 2000/03/06 15:45:17 armin - * Fixed incomplete number handling with BRI PtP connection. - * - * Revision 1.32 2000/03/04 17:04:21 armin - * Fix of statemachine, B-connect before D-connect, - * thanks to Helmut Adams <adams@ipcon.de> - * Minor change in send-data packet handling. - * - * Revision 1.31 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.30 2000/02/16 16:08:46 armin - * Fixed virtual channel handling of IDI. - * - * Revision 1.29 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.28 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.27 1999/11/29 13:12:03 armin - * Autoconnect on L2_TRANS doesn't work with link_level correctly, - * changed back to former mode. - * - * Revision 1.26 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.25 1999/11/18 20:30:55 armin - * removed old workaround for ISA cards. - * - * Revision 1.24 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.23 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.22 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.21 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.20 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.19 1999/09/21 20:06:40 armin - * Added pointer checks. - * - * Revision 1.18 1999/09/07 12:48:05 armin - * Prepared for sub-address usage. - * - * Revision 1.17 1999/09/07 12:35:39 armin - * Better checking and channel Id handling. - * - * Revision 1.16 1999/09/04 13:44:19 armin - * Fix of V.42 analog Modem negotiation handling. - * - * Revision 1.15 1999/08/28 21:32:50 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.14 1999/08/28 20:24:40 armin - * Corrected octet 3/3a in CPN/OAD information element. - * Thanks to John Simpson <xfl23@dial.pipex.com> - * - * Revision 1.13 1999/08/22 20:26:44 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.12 1999/08/18 20:16:59 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.11 1999/07/25 15:12:03 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.10 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.9 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.8 1999/03/02 12:37:43 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.7 1999/02/03 18:34:35 armin - * Channel selection for outgoing calls w/o CHI. - * Added channel # in debug messages. - * L2 Transparent should work with 800 byte/packet now. - * - * Revision 1.6 1999/01/26 07:18:59 armin - * Bug with wrong added CPN fixed. - * - * Revision 1.5 1999/01/24 20:14:11 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.4 1999/01/10 18:46:05 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.3 1999/01/05 14:49:34 armin - * Added experimental usage of full BC and HLC for - * speech, 3.1kHz audio, fax gr.2/3 - * - * Revision 1.2 1999/01/04 13:19:29 armin - * Channel status with listen-request wrong - fixed. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include <linux/config.h> @@ -161,25 +32,14 @@ #include "eicon.h" #include "eicon_idi.h" #include "eicon_dsp.h" +#include "uxio.h" #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.33 $"; +char *eicon_idi_revision = "$Revision: 1.41 $"; eicon_manifbuf *manbuf; -static char BC_Speech[3] = { 0x80, 0x90, 0xa3 }; -static char BC_31khz[3] = { 0x90, 0x90, 0xa3 }; -static char BC_64k[2] = { 0x88, 0x90 }; -static char BC_video[3] = { 0x91, 0x90, 0xa5 }; - -#ifdef EICON_FULL_SERVICE_OKTETT -/* -static char HLC_telephony[2] = { 0x91, 0x81 }; -*/ -static char HLC_faxg3[2] = { 0x91, 0x84 }; -#endif - int eicon_idi_manage_assign(eicon_card *card); int eicon_idi_manage_remove(eicon_card *card); int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer); @@ -209,7 +69,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0; + reqbuf->ReqId = DSIG_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ } @@ -221,6 +81,9 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = LLC; reqbuf->XBuffer.P[l++] = 2; switch(chan->l2prot) { + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; @@ -262,7 +125,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0x20; + reqbuf->ReqId = NL_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 1; /* Net Entity */ } @@ -282,6 +145,21 @@ idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch) } int +idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan) +{ + reqbuf->Req = SUSPEND; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.P[0] = CAI; + reqbuf->XBuffer.P[1] = 1; + reqbuf->XBuffer.P[2] = chan->No; + reqbuf->XBuffer.P[3] = 0; + reqbuf->XBuffer.length = 4; + reqbuf->Reference = 0; /* Sig Entity */ + return(0); +} + +int idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) { int l = 9; @@ -295,7 +173,7 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 3; + reqbuf->XBuffer.P[7] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -391,6 +269,12 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) case HANGUP: idi_put_req(reqbuf, HANGUP, 0, 0); break; + case SUSPEND: + idi_put_suspend_req(reqbuf, chan); + break; + case RESUME: + idi_put_req(reqbuf, RESUME, 0 ,0); + break; case REJECT: idi_put_req(reqbuf, REJECT, 0 ,0); break; @@ -400,17 +284,20 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) case CALL_RES: idi_call_res_req(reqbuf, chan); break; - case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); + case CALL_HOLD: + idi_put_req(reqbuf, CALL_HOLD, 0, 0); + break; + case N_CONNECT|0x700: + idi_put_req(reqbuf, N_CONNECT, 1, 0); break; - case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); + case N_CONNECT_ACK|0x700: + idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0); break; - case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); + case N_DISC|0x700: + idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh); break; - case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); + case N_DISC_ACK|0x700: + idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -492,7 +379,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan) if ((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) { - if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1); + if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1); } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { @@ -508,6 +395,32 @@ idi_hangup(eicon_card *card, eicon_chan *chan) } int +capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm) +{ + if ((cm->para[0] != 3) || (cm->para[1] != 0)) + return -1; + if (cm->para[2] < 3) + return -1; + if (cm->para[4] != 0) + return -1; + switch(cm->para[3]) { + case 4: /* Suspend */ + eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No); + if (cm->para[5]) { + idi_do_req(card, chan, SUSPEND, 0); + } else { + idi_do_req(card, chan, CALL_HOLD, 0); + } + break; + case 5: /* Resume */ + eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No); + idi_do_req(card, chan, RESUME, 0); + break; + } + return 0; +} + +int idi_connect_res(eicon_card *card, eicon_chan *chan) { if ((!card) || (!chan)) @@ -612,7 +525,14 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, reqbuf->XBuffer.P[l++] = *sub++ & 0x7f; } - if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { + if (si2 > 2) { + reqbuf->XBuffer.P[l++] = SHIFT|6; + reqbuf->XBuffer.P[l++] = SIN; + reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = si1; + reqbuf->XBuffer.P[l++] = si2; + } + else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { reqbuf->XBuffer.P[l++] = BC; reqbuf->XBuffer.P[l++] = tmp; for(i=0; i<tmp;i++) @@ -632,7 +552,7 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 32; - reqbuf->XBuffer.P[l++] = 3; + reqbuf->XBuffer.P[l++] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -859,7 +779,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } for(i=0; i < wlen; i++) message->llc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0], + eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0], message->llc[1],message->llc[2],message->llc[3]); break; case HLC: @@ -869,7 +789,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } for(i=0; i < wlen; i++) message->hlc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No, + eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No, message->hlc[0], message->hlc[1], message->hlc[2], message->hlc[3], message->hlc[4]); break; @@ -1061,31 +981,55 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } void -idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2) +idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2) { - si1[0] = 0; - si2[0] = 0; - if (memcmp(bc, BC_Speech, 3) == 0) { /* Speech */ - si1[0] = 1; + si1[0] = 0; + si2[0] = 0; + + switch (bc[0] & 0x7f) { + case 0x00: /* Speech */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 1; + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_31khz, 3) == 0) { /* 3.1kHz audio */ - si1[0] = 1; + break; + case 0x10: /* 3.1 Khz audio */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 2; - if (memcmp(hlc, HLC_faxg3, 2) == 0) { /* Fax Gr.2/3 */ - si1[0] = 2; - } + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_64k, 2) == 0) { /* unrestricted 64 kbits */ - si1[0] = 7; - } - if (memcmp(bc, BC_video, 3) == 0) { /* video */ - si1[0] = 4; - } + break; + case 0x08: /* Unrestricted digital information */ + si1[0] = 7; + si2[0] = sin[1]; + break; + case 0x09: /* Restricted digital information */ + si1[0] = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + si1[0] = 3; + break; + case 0x18: /* Video */ + si1[0] = 4; + break; + } + switch (bc[1] & 0x7f) { + case 0x40: /* packed mode */ + si1[0] = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + /* moderate = bc[1] & 0x7f; */ + break; + } } /********************* FAX stuff ***************************/ @@ -1225,7 +1169,7 @@ idi_send_edata(eicon_card *card, eicon_chan *chan) reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_EDATA; + reqbuf->Req = N_EDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -1359,7 +1303,7 @@ idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header) eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength); break; } - idi_send_data(card, chan, 0, skb, 0); + idi_send_data(card, chan, 0, skb, 0, 0); } void @@ -1913,7 +1857,7 @@ idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf OutBuf->Len = 0; OutBuf->Next = OutBuf->Data; - return(idi_send_data(ccard, chan, 0, skb, 1)); + return(idi_send_data(ccard, chan, 0, skb, 1, 0)); } int @@ -1958,6 +1902,8 @@ idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb) if (chan->queued + skb->len > 1200) return 0; + if (chan->pqueued > 1) + return 0; InBuf.Data = skb->data; InBuf.Size = skb->len; @@ -2183,6 +2129,7 @@ idi_fax_hangup(eicon_card *ccard, eicon_chan *chan) } if ((chan->fax->code > 1) && (chan->fax->code < 120)) chan->fax->code += 120; + eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code); chan->fax->r_code = ISDN_TTY_FAX_HNG; cmd.driver = ccard->myid; cmd.command = ISDN_STAT_FAXIND; @@ -2224,7 +2171,7 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_UDATA; + reqbuf->Req = N_UDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -2418,12 +2365,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (message.e_cau[0] & 0x7f) { cmd.driver = ccard->myid; cmd.arg = chan->No; @@ -2433,10 +2380,6 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) ccard->interface.statcallb(&cmd); } chan->cause[0] = 0; -#ifdef CONFIG_ISDN_TTY_FAX - if (!chan->e.B2Id) - chan->fax = 0; -#endif if (((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) || ((chan->l2prot == ISDN_PROTO_L2_FAX) && @@ -2446,6 +2389,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) if (chan->e.B2Id) idi_do_req(ccard, chan, REMOVE, 1); chan->statectrl &= ~WAITING_FOR_HANGUP; + chan->statectrl &= ~IN_HOLD; if (chan->statectrl & HAVE_CONN_REQ) { eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No); chan->statectrl &= ~HAVE_CONN_REQ; @@ -2463,6 +2407,9 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.command = ISDN_STAT_DHUP; ccard->interface.statcallb(&cmd); eicon_idi_listen_req(ccard, chan); +#ifdef CONFIG_ISDN_TTY_FAX + chan->fax = 0; +#endif } } break; @@ -2475,7 +2422,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) break; } chan->fsm_state = EICON_STATE_ICALL; - idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2); + idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2); strcpy(chan->cpn, message.cpn + 1); strcpy(chan->oad, message.oad); strcpy(chan->dsa, message.dsa); @@ -2553,12 +2500,15 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case ISDN_PROTO_L2_MODEM: /* do nothing, wait for connect */ break; + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); break; default: /* On most incoming calls we use automatic connect */ - /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ + /* idi_do_req(ccard, chan, N_CONNECT, 1); */ } } else { if (chan->fsm_state != EICON_STATE_ACTIVE) @@ -2568,33 +2518,50 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case CALL_CON: eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No); if (chan->fsm_state == EICON_STATE_OCALL) { - chan->fsm_state = EICON_STATE_OBWAIT; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DCONN; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - /* check if old NetID has been removed */ if (chan->e.B2Id) { eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n", chan->No, chan->e.B2Id); idi_do_req(ccard, chan, REMOVE, 1); } - - idi_do_req(ccard, chan, ASSIGN, 1); - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { - if (chan->fax) + if (chan->fax) { chan->fax->phase = ISDN_FAX_PHASE_A; + } else { + eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n"); + idi_hangup(ccard, chan); + break; + } } #endif + chan->fsm_state = EICON_STATE_OBWAIT; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + + idi_do_req(ccard, chan, ASSIGN, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); } else - idi_hangup(ccard, chan); + idi_hangup(ccard, chan); break; case AOC_IND: eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No); break; + case CALL_HOLD_ACK: + chan->statectrl |= IN_HOLD; + eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No); + break; + case SUSPEND_REJ: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No); + break; + case SUSPEND: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No); + break; + case RESUME: + eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No); + break; default: eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind); } @@ -2613,7 +2580,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } else switch(ind->Ind) { - case IDI_N_CONNECT_ACK: + case N_CONNECT_ACK: eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No); if (chan->l2prot == ISDN_PROTO_L2_MODEM) { chan->fsm_state = EICON_STATE_WMCONN; @@ -2634,7 +2601,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } } else { - eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n"); + eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n"); } #endif break; @@ -2646,10 +2613,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_CONNECT: + case N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); chan->e.IndCh = ind->IndCh; - if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); + if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; } @@ -2664,43 +2631,47 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_DISC: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No); + case N_DISC: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No); if (chan->e.B2Id) { while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1); + idi_do_req(ccard, chan, N_DISC_ACK, 1); idi_do_req(ccard, chan, REMOVE, 1); } #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { + if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); idi_fax_hangup(ccard, chan); } #endif chan->e.IndCh = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); - idi_do_req(ccard, chan, HANGUP, 0); + spin_unlock_irqrestore(&eicon_lock, flags); + if (!(chan->statectrl & IN_HOLD)) { + idi_do_req(ccard, chan, HANGUP, 0); + } if (chan->fsm_state == EICON_STATE_ACTIVE) { cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BHUP; cmd.arg = chan->No; ccard->interface.statcallb(&cmd); chan->fsm_state = EICON_STATE_NULL; - chan->statectrl |= WAITING_FOR_HANGUP; + if (!(chan->statectrl & IN_HOLD)) { + chan->statectrl |= WAITING_FOR_HANGUP; + } } #ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0; #endif break; - case IDI_N_DISC_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No); + case N_DISC_ACK: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); @@ -2708,10 +2679,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } #endif break; - case IDI_N_DATA_ACK: - eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + case N_DATA_ACK: + eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No); break; - case IDI_N_DATA: + case N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len); if (chan->l2prot == ISDN_PROTO_L2_FAX) { @@ -2723,11 +2694,11 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) free_buff = 0; } break; - case IDI_N_UDATA: + case N_UDATA: idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #ifdef CONFIG_ISDN_TTY_FAX - case IDI_N_EDATA: + case N_EDATA: idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #endif @@ -2747,6 +2718,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) { ulong flags; isdn_ctrl cmd; + int tqueued = 0; + int twaitpq = 0; if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { /* I dont know why this happens, should not ! */ @@ -2770,16 +2743,15 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); ccard->IdTable[ack->RcId] = NULL; - eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, - ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); if (!chan->e.ReqCh) chan->e.D3Id = 0; else chan->e.B2Id = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, + ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); return 1; } @@ -2790,25 +2762,21 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } else { /* Network layer */ switch(chan->e.Req & 0x0f) { - case IDI_N_CONNECT: + case N_CONNECT: chan->e.IndCh = ack->RcCh; eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); break; - case IDI_N_MDATA: - case IDI_N_DATA: - if ((chan->e.Req & 0x0f) == IDI_N_DATA) { - if (chan->queued) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BSENT; - cmd.arg = chan->No; - cmd.parm.length = chan->waitpq; - ccard->interface.statcallb(&cmd); - } - save_flags(flags); - cli(); + case N_MDATA: + case N_DATA: + tqueued = chan->queued; + twaitpq = chan->waitpq; + if ((chan->e.Req & 0x0f) == N_DATA) { + spin_lock_irqsave(&eicon_lock, flags); chan->waitpq = 0; - restore_flags(flags); + if(chan->pqueued) + chan->pqueued--; + spin_unlock_irqrestore(&eicon_lock, flags); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { if (((chan->queued - chan->waitq) < 1) && @@ -2828,11 +2796,17 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } #endif } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued -= chan->waitq; if (chan->queued < 0) chan->queued = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) { + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BSENT; + cmd.arg = chan->No; + cmd.parm.length = twaitpq; + ccard->interface.statcallb(&cmd); + } break; default: eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, @@ -2858,11 +2832,10 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ack->RcId]) != NULL) dCh = chan->No; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); switch (ack->Rc) { case OK_FC: @@ -2890,8 +2863,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n", chan->No, chan->e.D3Id, chan->e.B2Id); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); for(j = 0; j < ccard->nchannels + 1; j++) { if ((ccard->bch[j].e.ref == ack->Reference) && (ccard->bch[j].e.Req == ASSIGN)) { @@ -2901,12 +2873,12 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) ccard->bch[j].e.B2Id = ack->RcId; ccard->IdTable[ack->RcId] = &ccard->bch[j]; chan = &ccard->bch[j]; - eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, - ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); break; } - } - restore_flags(flags); + } + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, + ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); if (j > ccard->nchannels) { eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", ack->Reference, ack->RcId); @@ -2917,6 +2889,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) case UNKNOWN_COMMAND: case WRONG_COMMAND: case WRONG_ID: + case ADAPTER_DEAD: case WRONG_CH: case UNKNOWN_IE: case WRONG_IE: @@ -2949,19 +2922,18 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) ccard->interface.statcallb(&cmd); } } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if (chan) { chan->e.ref = 0; chan->e.busy = 0; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); dev_kfree_skb(skb); eicon_schedule_tx(ccard); } int -idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que) +idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk) { struct sk_buff *xmit_skb; struct sk_buff *skb2; @@ -2985,13 +2957,14 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, return -1; if (!len) return 0; - if (chan->queued + len > EICON_MAX_QUEUE) + + if ((chk) && (chan->pqueued > 1)) return 0; - eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len); + eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n", + chan->No, len, chan->pqueued); - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while(offset < len) { plen = ((len - offset) > 270) ? 270 : len - offset; @@ -3000,7 +2973,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); if ((!xmit_skb) || (!skb2)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No); if (xmit_skb) dev_kfree_skb(skb); @@ -3013,13 +2986,10 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, chan2->ptr = chan; reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); - if (((len - offset) > 270) && - (chan->l2prot != ISDN_PROTO_L2_MODEM) && - (chan->l2prot != ISDN_PROTO_L2_FAX) && - (chan->l2prot != ISDN_PROTO_L2_TRANS)) { - reqbuf->Req = IDI_N_MDATA; + if ((len - offset) > 270) { + reqbuf->Req = N_MDATA; } else { - reqbuf->Req = IDI_N_DATA; + reqbuf->Req = N_DATA; /* if (ack) reqbuf->Req |= N_D_BIT; */ } reqbuf->ReqCh = chan->e.IndCh; @@ -3033,9 +3003,11 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, offset += plen; } - if (que) + if (que) { chan->queued += len; - restore_flags(flags); + chan->pqueued++; + } + spin_unlock_irqrestore(&eicon_lock, flags); eicon_schedule_tx(card); dev_kfree_skb(skb); return len; @@ -3073,7 +3045,7 @@ eicon_idi_manage_assign(eicon_card *card) reqbuf->XBuffer.P[0] = 0; reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0xe0; + reqbuf->ReqId = MAN_ID; reqbuf->XBuffer.length = 1; reqbuf->Reference = 2; /* Man Entity */ @@ -3199,7 +3171,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) reqbuf->XBuffer.P[1] = manbuf->length[0] + 1; reqbuf->XBuffer.P[l++] = 0; - reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */ + reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; reqbuf->XBuffer.length = l; diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h index 2fe6167a4..a11039219 100644 --- a/drivers/isdn/eicon/eicon_idi.h +++ b/drivers/isdn/eicon/eicon_idi.h @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for the Eicon active cards. * IDI-Interface @@ -20,168 +20,30 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.h,v $ - * Revision 1.9 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.8 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.7 1999/08/22 20:26:46 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:04 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/07/11 17:16:26 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.4 1999/03/29 11:19:44 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:18 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:42 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * * */ -#ifndef IDI_H -#define IDI_H +#ifndef E_IDI_H +#define E_IDI_H #include <linux/config.h> -#define ASSIGN 0x01 -#define REMOVE 0xff - -#define CALL_REQ 1 /* call request */ -#define CALL_CON 1 /* call confirmation */ -#define CALL_IND 2 /* incoming call connected */ -#define LISTEN_REQ 2 /* listen request */ -#define HANGUP 3 /* hangup request/indication */ -#define SUSPEND 4 /* call suspend request/confirm */ -#define RESUME 5 /* call resume request/confirm */ -#define SUSPEND_REJ 6 /* suspend rejected indication */ -#define USER_DATA 8 /* user data for user to user signaling */ -#define CONGESTION 9 /* network congestion indication */ -#define INDICATE_REQ 10 /* request to indicate an incoming call */ -#define INDICATE_IND 10 /* indicates that there is an incoming call */ -#define CALL_RES 11 /* accept an incoming call */ -#define CALL_ALERT 12 /* send ALERT for incoming call */ -#define INFO_REQ 13 /* INFO request */ -#define INFO_IND 13 /* INFO indication */ -#define REJECT 14 /* reject an incoming call */ -#define RESOURCES 15 /* reserve B-Channel hardware resources */ -#define TEL_CTRL 16 /* Telephone control request/indication */ -#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ -#define FAC_REG_REQ 18 /* connection idependent fac registration */ -#define FAC_REG_ACK 19 /* fac registration acknowledge */ -#define FAC_REG_REJ 20 /* fac registration reject */ -#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ -#define AOC_IND 26/* Advice of Charge */ - -#define IDI_N_MDATA (0x01) -#define IDI_N_CONNECT (0x02) -#define IDI_N_CONNECT_ACK (0x03) -#define IDI_N_DISC (0x04) -#define IDI_N_DISC_ACK (0x05) -#define IDI_N_RESET (0x06) -#define IDI_N_RESET_ACK (0x07) -#define IDI_N_DATA (0x08) -#define IDI_N_EDATA (0x09) -#define IDI_N_UDATA (0x0a) -#define IDI_N_BDATA (0x0b) -#define IDI_N_DATA_ACK (0x0c) -#define IDI_N_EDATA_ACK (0x0d) +#undef N_DATA +#undef ID_MASK -#define N_Q_BIT 0x10 /* Q-bit for req/ind */ -#define N_M_BIT 0x20 /* M-bit for req/ind */ -#define N_D_BIT 0x40 /* D-bit for req/ind */ +#include "pc.h" +#define AOC_IND 26 /* Advice of Charge */ +#define PI 0x1e /* Progress Indicator */ +#define NI 0x27 /* Notification Indicator */ -#define SHIFT 0x90 /* codeset shift */ -#define MORE 0xa0 /* more data */ -#define CL 0xb0 /* congestion level */ - - /* codeset 0 */ - -#define BC 0x04 /* Bearer Capability */ -#define CAU 0x08 /* cause */ -#define CAD 0x0c /* Connected address */ -#define CAI 0x10 /* call identity */ -#define CHI 0x18 /* channel identification */ -#define LLI 0x19 /* logical link id */ -#define CHA 0x1a /* charge advice */ -#define FTY 0x1c -#define PI 0x1e /* Progress Indicator */ -#define NI 0x27 /* Notification Indicator */ -#define DT 0x29 /* ETSI date/time */ -#define KEY 0x2c /* keypad information element */ -#define DSP 0x28 /* display */ -#define OAD 0x6c /* origination address */ -#define OSA 0x6d /* origination sub-address */ -#define CPN 0x70 /* called party number */ -#define DSA 0x71 /* destination sub-address */ -#define RDN 0x74 /* redirecting number */ -#define LLC 0x7c /* low layer compatibility */ -#define HLC 0x7d /* high layer compatibility */ -#define UUI 0x7e /* user user information */ -#define ESC 0x7f /* escape extension */ - -#define DLC 0x20 /* data link layer configuration */ -#define NLC 0x21 /* network layer configuration */ - - /* codeset 6 */ - -#define SIN 0x01 /* service indicator */ -#define CIF 0x02 /* charging information */ -#define DATE 0x03 /* date */ -#define CPS 0x07 /* called party status */ - -/*------------------------------------------------------------------*/ -/* return code coding */ -/*------------------------------------------------------------------*/ - -#define UNKNOWN_COMMAND 0x01 /* unknown command */ -#define WRONG_COMMAND 0x02 /* wrong command */ -#define WRONG_ID 0x03 /* unknown task/entity id */ -#define WRONG_CH 0x04 /* wrong task/entity id */ -#define UNKNOWN_IE 0x05 /* unknown information el. */ -#define WRONG_IE 0x06 /* wrong information el. */ -#define OUT_OF_RESOURCES 0x07 /* card out of res. */ -#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ -#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ -#define ASSIGN_OK 0xef /* ASSIGN OK */ -#define OK_FC 0xfc /* Flow-Control RC */ -#define READY_INT 0xfd /* Ready interrupt */ -#define TIMER_INT 0xfe /* timer interrupt */ -#define OK 0xff /* command accepted */ - -/*------------------------------------------------------------------*/ +#define CALL_HOLD 0x22 +#define CALL_HOLD_ACK 0x24 /* defines for statectrl */ #define WAITING_FOR_HANGUP 0x01 #define HAVE_CONN_REQ 0x02 +#define IN_HOLD 0x04 typedef struct { char cpn[32]; @@ -242,26 +104,6 @@ typedef struct { } eicon_IND; typedef struct { - __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ - __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ - __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ - __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ - __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ - __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ - __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ - __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ - __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ - __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ - __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ - __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ - __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ - __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ - __u8 B[1]; /* buffer space for Req,Ind and Rc */ -} eicon_pr_ram; - -typedef struct { __u8 *Data; unsigned int Size; unsigned int Len; @@ -278,8 +120,9 @@ extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb); extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb); extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb); -extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que); +extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk); extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value); +extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm); #ifdef CONFIG_ISDN_TTY_FAX extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan); extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb); diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c index 4f4180ed6..6f294e8b7 100644 --- a/drivers/isdn/eicon/eicon_io.c +++ b/drivers/isdn/eicon/eicon_io.c @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. @@ -23,52 +23,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_io.c,v $ - * Revision 1.10 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.9 1999/11/18 20:55:25 armin - * Ready_Int fix of ISA cards. - * - * Revision 1.8 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.7 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.6 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.5 1999/08/31 11:20:11 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.4 1999/08/22 20:26:47 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.3 1999/08/18 20:17:01 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.2 1999/07/25 15:12:05 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.1 1999/03/29 11:19:45 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * */ #include <linux/config.h> #include "eicon.h" +#include "uxio.h" void eicon_io_rcv_dispatch(eicon_card *ccard) { @@ -85,12 +45,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { while((skb = skb_dequeue(&ccard->rcvq))) { ind = (eicon_IND *)skb->data; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + spin_unlock_irqrestore(&eicon_lock, flags); if (DebugVar & 1) { switch(ind->Ind) { - case IDI_N_DISC_ACK: + case N_DISC_ACK: /* doesn't matter if this happens */ break; default: @@ -99,11 +59,10 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } } - restore_flags(flags); dev_kfree_skb(skb); continue; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (chan->e.complete) { /* check for rec-buffer chaining */ if (ind->MLength == ind->RBuffer.length) { @@ -119,12 +78,9 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { } } else { - save_flags(flags); - cli(); if (!(skb2 = skb_dequeue(&chan->e.R))) { chan->e.complete = 1; eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n"); - restore_flags(flags); dev_kfree_skb(skb); continue; } @@ -133,7 +89,6 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { GFP_ATOMIC); if (!skb_new) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n"); - restore_flags(flags); dev_kfree_skb(skb); dev_kfree_skb(skb2); continue; @@ -152,14 +107,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { dev_kfree_skb(skb2); if (ind->MLength == ind->RBuffer.length) { chan->e.complete = 2; - restore_flags(flags); idi_handle_ind(ccard, skb_new); continue; } else { chan->e.complete = 0; skb_queue_tail(&chan->e.R, skb_new); - restore_flags(flags); continue; } } @@ -181,242 +134,120 @@ eicon_io_ack_dispatch(eicon_card *ccard) { /* - * IO-Functions for different card-types + * IO-Functions for ISA cards */ u8 ram_inb(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inb((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readb(addr)); - } - return(0); + return(readb(addr)); } u16 ram_inw(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inw((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readw(addr)); - } - return(0); + + return(readw(addr)); } void ram_outb(eicon_card *card, void *adr, u8 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outb((u8)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writeb(data, addr); - break; - } + writeb(data, addr); } void ram_outw(eicon_card *card, void *adr , u16 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outw((u16)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writew(data, addr); - break; - } + writew(data, addr); } void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - writeb(ram_inb(card, adr + i), adrto + i); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_fromio(adrto, adr, len); - break; - } + memcpy_fromio(adrto, adr, len); } void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - ram_outb(card, adrto + i, readb(adr + i)); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_toio(adrto, adr, len); - break; - } + memcpy_toio(adrto, adr, len); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * XLOG + * IDI-Callback function */ -int -eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq) +void +eicon_idi_callback(ENTITY *de) { - int timeout, i; - int divas_shared_offset = 0; + eicon_card *ccard = (eicon_card *)de->R; + struct sk_buff *skb; + eicon_RC *ack; + eicon_IND *ind; int len = 0; - int stype = 0; - __u32 time = 0; - mi_pc_maint_t *pcm = &xlogreq->pcm; - eicon_pci_card *pci_card = &card->hwif.pci; - eicon_isa_card *isa_card = &card->hwif.isa; - eicon_pr_ram *prram = 0; - char *ram; - switch(card->type) { - case EICON_CTYPE_MAESTRAP: - ram = (char *)pci_card->PCIram; - prram = (eicon_pr_ram *)ram; - divas_shared_offset = DIVAS_SHARED_OFFSET; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_MAESTRA: - prram = 0; - divas_shared_offset = 0; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - case EICON_CTYPE_S2M: - prram = (eicon_pr_ram *)isa_card->shmem; - divas_shared_offset = 0xfb80; - len = sizeof(mi_pc_maint_t) - 78; - stype = 1; - break; - default: - return -ENODEV; - } - - memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t)); - - xlogreq->pcm.rc = 0; - xlogreq->pcm.req = 1; /* DO_LOG */ - - ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset; - - ram_outb(card, ram+1, pcm->rc); - ram_outb(card, ram+0, pcm->req); - - timeout = jiffies + 50; - while (timeout > jiffies) { - pcm->rc = ram_inb(card, ram+1); - pcm->req = ram_inb(card, ram+0); - if (!pcm->req) break; - SLEEP(10); - } - - if (pcm->req) { - return XLOG_ERR_TIMEOUT; - } - - if (pcm->rc != OK) { - return XLOG_ERR_DONE; - } - - ram_copyfromcard(card, pcm, ram, len); - - if (stype) { - for (i=0; i<8; i++) - ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i]; - time = (__u32)pcm->data.w[2] * 3600 * 1000 + - (__u32)pcm->data.w[1] * 1000 + - (__u32)pcm->data.b[1] * 20 + - (__u32)pcm->data.b[0] ; - pcm->data.w[1] = (__u16) (time >> 16); - pcm->data.w[2] = (__u16) (time & 0x0000ffff); - pcm->data.w[0] = 2; + if (de->complete == 255) { + /* Return Code */ + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = de->Rc; + if (de->Rc == ASSIGN_OK) { + ack->RcId = de->Id; + de->user[1] = de->Id; + } else { + ack->RcId = de->user[1]; + } + ack->RcCh = de->RcCh; + ack->Reference = de->user[0]; + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Rc, ack->RcId, de->RLength, de->complete); + } + } else { + /* Indication */ + if (de->complete) { + len = de->RLength; + } else { + len = 270; + if (de->RLength <= 270) + eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n"); + } + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = de->Ind; + ind->IndId = de->user[1]; + ind->IndCh = de->IndCh; + ind->MInd = de->Ind; + ind->RBuffer.length = len; + ind->MLength = de->RLength; + memcpy(&ind->RBuffer.P, &de->RBuffer->P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Ind, ind->IndId, de->RLength, de->complete); + } } - return XLOG_OK; + de->RNum = 0; + de->RNR = 0; + de->Rc = 0; + de->Ind = 0; } +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ /* * Transmit-Function */ void eicon_io_transmit(eicon_card *ccard) { - eicon_pci_card *pci_card; eicon_isa_card *isa_card; struct sk_buff *skb; struct sk_buff *skb2; unsigned long flags; - char *ram, *reg, *cfg; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_REQ *ReqOut = 0; @@ -426,10 +257,11 @@ eicon_io_transmit(eicon_card *ccard) { int ReqCount; int scom = 0; int tmp = 0; + int tmpid = 0; int quloop = 1; int dlev = 0; + ENTITY *ep = 0; - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; if (!ccard) { @@ -451,20 +283,17 @@ eicon_io_transmit(eicon_card *ccard) { prram = (eicon_pr_ram *)isa_card->shmem; break; #endif +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = (eicon_pr_ram *)ram; + scom = 2; + break; + case EICON_CTYPE_MAESTRAQ: + scom = 2; break; case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = 0; + scom = 2; break; +#endif default: eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n"); return; @@ -474,69 +303,91 @@ eicon_io_transmit(eicon_card *ccard) { if (!(skb2 = skb_dequeue(&ccard->sndq))) quloop = 0; while(quloop) { - save_flags(flags); - cli(); - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + switch (scom) { + case 1: if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) { if (!ccard->ReadyInt) { tmp = ram_inb(ccard, &com->ReadyInt) + 1; ram_outb(ccard, &com->ReadyInt, tmp); ccard->ReadyInt++; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } - } else { + break; + case 0: if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } + break; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + chan2 = (eicon_chan_ptr *)skb2->data; chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { - save_flags(flags); - cli(); + reqbuf = (eicon_REQ *)skb->data; if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); } else { - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + + switch (scom) { + case 1: ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh); - - } else { + break; + case 0: /* get address of next available request buffer */ ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)]; ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh); ram_outb(ccard, &ReqOut->Req, reqbuf->Req); + break; } + dlev = 160; + if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ - if (scom) + switch (scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.D3Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); - + break; + case 2: + ep = &chan->de; + break; + } + tmpid = chan->e.D3Id; chan->e.ReqCh = 0; } else { /* Net Layer */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.B2Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); - + break; + case 2: + ep = &chan->be; + break; + } + tmpid = chan->e.B2Id; chan->e.ReqCh = 1; if (((reqbuf->Req & 0x0f) == 0x08) || ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ @@ -548,51 +399,106 @@ eicon_io_transmit(eicon_card *ccard) { } else { /* It is an ASSIGN */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, reqbuf->ReqId); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); + break; + case 2: + if (!reqbuf->Reference) + ep = &chan->de; + else + ep = &chan->be; + ep->Id = reqbuf->ReqId; + break; + } + tmpid = reqbuf->ReqId; if (!reqbuf->Reference) chan->e.ReqCh = 0; else chan->e.ReqCh = 1; } - if (scom) + + switch(scom) { + case 1: chan->e.ref = ccard->ref_out++; - else + break; + case 0: chan->e.ref = ram_inw(ccard, &ReqOut->Reference); + break; + case 2: + chan->e.ref = chan->No; + break; + } chan->e.Req = reqbuf->Req; ReqCount++; - if (scom) + + switch (scom) { + case 1: ram_outb(ccard, &com->Req, reqbuf->Req); - else + break; + case 0: ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); + break; + case 2: +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (!ep) break; + ep->callback = eicon_idi_callback; + ep->R = (BUFFERS *)ccard; + ep->user[0] = (word)chan->No; + ep->user[1] = (word)tmpid; + ep->XNum = 1; + ep->RNum = 0; + ep->RNR = 0; + ep->Rc = 0; + ep->Ind = 0; + ep->X->PLength = reqbuf->XBuffer.length; + memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); + ep->ReqCh = reqbuf->ReqCh; + ep->Req = reqbuf->Req; +#endif + break; + } chan->e.busy = 1; + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", - reqbuf->Req, - (scom) ? ram_inb(ccard, &com->ReqId) : - ram_inb(ccard, &ReqOut->ReqId), + reqbuf->Req, tmpid, reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (scom == 2) { + if (ep) { + ccard->d->request(ep); + if (ep->Rc) + eicon_idi_callback(ep); + } + } +#endif } - restore_flags(flags); dev_kfree_skb(skb); } dev_kfree_skb(skb2); } else { - skb_queue_tail(&ccard->sackq, skb2); - eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); + skb_queue_tail(&ccard->sackq, skb2); + eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); } - if (scom) - quloop = 0; - else - if (!(skb2 = skb_dequeue(&ccard->sndq))) + switch(scom) { + case 1: quloop = 0; + break; + case 0: + case 2: + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + break; + } } if (!scom) @@ -603,18 +509,14 @@ eicon_io_transmit(eicon_card *ccard) { } } - +#ifdef CONFIG_ISDN_DRV_EICON_ISA /* * IRQ handler */ void eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { eicon_card *ccard = (eicon_card *)dev_id; - eicon_pci_card *pci_card; eicon_isa_card *isa_card; - char *ram = 0; - char *reg = 0; - char *cfg = 0; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_RC *RcIn; @@ -646,11 +548,9 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { } } - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -664,23 +564,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { prram = (eicon_pr_ram *)isa_card->shmem; irqprobe = &isa_card->irqprobe; break; -#endif - case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = (eicon_pr_ram *)ram; - break; - case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = 0; - break; default: eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n"); return; @@ -688,7 +571,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { if (*irqprobe) { switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -706,26 +588,11 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { } (*irqprobe)++; break; -#endif - case EICON_CTYPE_MAESTRAP: - if (readb(&ram[0x3fe])) { - writeb(0, &prram->RcOutput); - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - } - *irqprobe = 0; - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - *irqprobe = 0; - break; } return; } switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -736,20 +603,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { return; } break; -#endif - case EICON_CTYPE_MAESTRAP: - if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; - case EICON_CTYPE_MAESTRA: - outw(0x3fe, pci_card->PCIreg + M_ADDR); - if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; } if (scom) { @@ -891,7 +744,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { /* clear interrupt */ switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_QUADRO: writeb(0, isa_card->intack); writeb(0, &com[0x401]); @@ -902,19 +754,8 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { case EICON_CTYPE_S2M: writeb(0, isa_card->intack); break; -#endif - case EICON_CTYPE_MAESTRAP: - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - outw(0x3fe, pci_card->PCIreg + M_ADDR); - outb(0, pci_card->PCIreg + M_DATA); - break; } return; } - +#endif diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index 265e07e08..1d2ece7cd 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -21,62 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.c,v $ - * Revision 1.14 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.13 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.12 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.11 1999/11/25 11:33:09 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * - * Revision 1.10 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.9 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.8 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.7 1999/08/22 20:26:48 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:06 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/04/01 12:48:33 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:46 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:19 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:43 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include <linux/config.h> @@ -87,7 +31,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.14 $"; +char *eicon_isa_revision = "$Revision: 1.16 $"; #undef EICON_MCA_DEBUG @@ -357,7 +301,7 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) { tmp = eicon_addcard(card->type, card->physmem, card->irq, - ((eicon_card *)card->card)->regname); + ((eicon_card *)card->card)->regname, 0); printk(KERN_INFO "Eicon: %d adapters added\n", tmp); } return 0; diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h index b53adfcbf..1c8034f77 100644 --- a/drivers/isdn/eicon/eicon_isa.h +++ b/drivers/isdn/eicon/eicon_isa.h @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,38 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.h,v $ - * Revision 1.8 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.7 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.6 1999/11/15 19:37:04 keil - * need config.h - * - * Revision 1.5 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.4 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.3 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:46 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_isa_h @@ -138,7 +106,6 @@ typedef struct { unsigned char mvalid; /* Flag: Memory is valid */ unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card ist Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_isa_card; /* Offsets for special locations on standard cards */ diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index 9bc91d6f4..f3af22b27 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_mod.c,v 1.35 2000/08/12 18:00:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -9,8 +9,6 @@ * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax * capabilities with Diva Server cards. @@ -30,105 +28,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_mod.c,v $ - * Revision 1.25 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.24 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.23 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.22 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.21 1999/11/25 11:35:10 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * Minor cleanup. - * - * Revision 1.20 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.19 1999/11/12 13:21:44 armin - * Bugfix of undefined reference with CONFIG_MCA - * - * Revision 1.18 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.17 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.16 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.15 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.14 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.13 1999/09/04 17:37:59 armin - * Removed not used define, did not work and caused error - * in 2.3.16 - * - * Revision 1.12 1999/08/31 11:20:14 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.11 1999/08/29 17:23:45 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/28 21:32:53 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.9 1999/08/18 20:17:02 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:08 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:27 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:26 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/04/01 12:48:35 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:47 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:21 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ -#define DRIVERPATCH "" +#define DRIVERNAME "Eicon active ISDN driver" +#define DRIVERRELEASE "2.0" +#define DRIVERPATCH ".14" + #include <linux/config.h> #include <linux/module.h> @@ -139,17 +44,30 @@ #include "eicon.h" +#include "../avmb1/capicmd.h" /* this should be moved in a common place */ + +#undef N_DATA +#include "adapter.h" +#include "uxio.h" + #define INCLUDE_INLINE_FUNCS static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.25 $"; +static char *eicon_revision = "$Revision: 1.35 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; extern char *eicon_idi_revision; +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern void eicon_pci_init_conf(eicon_card *card); +void mod_inc_use_count(void); +void mod_dec_use_count(void); +extern char *file_check(void); + #ifdef MODULE #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) #endif @@ -158,6 +76,11 @@ extern char *eicon_idi_revision; ulong DebugVar; +spinlock_t eicon_lock; + +DESCRIPTOR idi_d[16]; +int idi_dlength; + /* Parameters to be set by insmod */ #ifdef CONFIG_ISDN_DRV_EICON_ISA static int membase = -1; @@ -189,23 +112,6 @@ char *eicon_ctype_name[] = { "DIVA Server PRI/PCI" }; -static int -getrel(char *p) -{ - int v = 0; - char *tmp = 0; - - if ((tmp = strchr(p, '.'))) - p = tmp + 1; - while (p[0] >= '0' && p[0] <= '9') { - v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0'); - p++; - } - return v; - - -} - static char * eicon_getrev(const char *revision) { @@ -229,68 +135,26 @@ find_channel(eicon_card *card, int channel) return NULL; } +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * Free MSN list + * Find pcicard with given card number */ -static void -eicon_clear_msn(eicon_card *card) +static inline eicon_card * +eicon_findnpcicard(int driverid) { - struct msn_entry *p = card->msn_list; - struct msn_entry *q; - unsigned long flags; + eicon_card *p = cards; - save_flags(flags); - cli(); - card->msn_list = NULL; - restore_flags(flags); while (p) { - q = p->next; - kfree(p); - p = q; + if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) && + (p->bus == EICON_BUS_PCI)) + return p; + p = p->next; } + return (eicon_card *) 0; } - -/* - * Find an MSN entry in the list. - * If ia5 != 0, return IA5-encoded EAZ, else - * return a bitmask with corresponding bit set. - */ -static __u16 -eicon_find_msn(eicon_card *card, char *msn, int ia5) -{ - struct msn_entry *p = card->msn_list; - __u8 eaz = '0'; - - while (p) { - if (!strcmp(p->msn, msn)) { - eaz = p->eaz; - break; - } - p = p->next; - } - if (!ia5) - return (1 << (eaz - '0')); - else - return eaz; -} - -/* - * Find an EAZ entry in the list. - * return a string with corresponding msn. - */ -char * -eicon_find_eaz(eicon_card *card, char eaz) -{ - struct msn_entry *p = card->msn_list; - - while (p) { - if (p->eaz == eaz) - return(p->msn); - p = p->next; - } - return("\0"); -} - +#endif +#endif /* CONFIG_PCI */ static void eicon_rcv_dispatch(struct eicon_card *card) @@ -337,39 +201,18 @@ eicon_transmit(struct eicon_card *card) } } -static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq) -{ - xlogreq_t *xlr; - int ret_val; - - if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) { - eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n"); - return -ENOMEM; - } - if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - - ret_val = eicon_get_xlog(card, xlr); - - if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - kfree(xlr); - - return ret_val; -} - static int eicon_command(eicon_card * card, isdn_ctrl * c) { ulong a; eicon_chan *chan; eicon_cdef cdef; +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + dia_start_t dstart; +#endif +#endif isdn_ctrl cmd; - char tmp[17]; int ret = 0; unsigned long flags; @@ -383,16 +226,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_IOCTL_GETVER: return(EICON_CTRL_VERSION); case EICON_IOCTL_GETTYPE: + if (card->bus == EICON_BUS_PCI) { + copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int)); + } return(card->type); case EICON_IOCTL_GETMMIO: switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: return (int)card->hwif.isa.shmem; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.PCIram; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -433,10 +275,6 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_BUS_ISA: case EICON_BUS_MCA: return card->hwif.isa.irq; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.irq; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -514,7 +352,9 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_IOCTL_MANIF: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - if (!card->Feature & PROTCAP_MANIF) + if (!card->d) + return -ENODEV; + if (!card->d->features & DI_MANAGE) return -ENODEV; ret = eicon_idi_manage( card, @@ -522,49 +362,12 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return ret; case EICON_IOCTL_GETXLOG: - if (!card->flags & EICON_FLAGS_RUNNING) - return XLOG_ERR_CARD_STATE; - ret = eicon_xlog(card, (xlogreq_t *)a); - return ret; -#if CONFIG_PCI - case EICON_IOCTL_LOADPCI: - if (card->flags & EICON_FLAGS_RUNNING) - return -EBUSY; - if (card->bus == EICON_BUS_PCI) { - switch(card->type) { - case EICON_CTYPE_MAESTRA: - ret = eicon_pci_load_bri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - - case EICON_CTYPE_MAESTRAP: - ret = eicon_pci_load_pri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - } - if (!ret) { - card->flags |= EICON_FLAGS_LOADED; - card->flags |= EICON_FLAGS_RUNNING; - if (card->hwif.pci.channels > 1) { - cmd.command = ISDN_STAT_ADDCH; - cmd.driver = card->myid; - cmd.arg = card->hwif.pci.channels - 1; - card->interface.statcallb(&cmd); - } - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - return ret; - } else return -ENODEV; -#endif + return -ENODEV; + case EICON_IOCTL_ADDCARD: if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef)))) return -EFAULT; - if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id))) + if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0))) return -EIO; return 0; case EICON_IOCTL_DEBUGVAR: @@ -574,11 +377,77 @@ eicon_command(eicon_card * card, isdn_ctrl * c) #ifdef MODULE case EICON_IOCTL_FREEIT: while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT; - MOD_INC_USE_COUNT; + mod_inc_use_count(); return 0; #endif - default: + case EICON_IOCTL_LOADPCI: + eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n"); + eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n"); + eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n"); return -EINVAL; + default: +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (c->arg < EICON_IOCTL_DIA_OFFSET) + return -EINVAL; + if (copy_from_user(&dstart, (char *)a, sizeof(dstart))) + return -1; + if (!(card = eicon_findnpcicard(dstart.card_id))) + return -EINVAL; + ret = do_ioctl(NULL, NULL, + c->arg - EICON_IOCTL_DIA_OFFSET, + (unsigned long) a); + if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) { + if (card->type != EICON_CTYPE_MAESTRAQ) { + EtdM_DIDD_Read(idi_d, &idi_dlength); + card->d = &idi_d[idi_dlength - 1]; + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x, SerNo. %d)\n", + (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI", + card->d->channels, card->d->features, card->d->serial); + } else { + int i; + EtdM_DIDD_Read(idi_d, &idi_dlength); + for(i = 3; i >= 0; i--) { + if (!(card = eicon_findnpcicard(dstart.card_id - i))) + return -EINVAL; + + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + card->d = &idi_d[idi_dlength - (i+1)]; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x, SerNo. %d)\n", + 4-i, card->d->channels, card->d->features, card->d->serial); + } + } + } + return ret; +#else + return -EINVAL; +#endif +#endif /* CONFIG_PCI */ } break; case ISDN_CMD_DIAL: @@ -586,20 +455,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "Dial on channel %d with state %d\n", chan->No, chan->fsm_state); return -EBUSY; } - if (card->ptype == ISDN_PTYPE_EURO) - tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1); - else - tmp[0] = c->parm.setup.eazmsn[0]; chan->fsm_state = EICON_STATE_OCALL; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); ret = idi_connect_req(card, chan, c->parm.setup.phone, c->parm.setup.eazmsn, @@ -637,19 +501,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - if (strlen(c->parm.num)) { - if (card->ptype == ISDN_PTYPE_EURO) { - chan->eazmask = eicon_find_msn(card, c->parm.num, 0); - } - if (card->ptype == ISDN_PTYPE_1TR6) { - int i; - chan->eazmask = 0; - for (i = 0; i < strlen(c->parm.num); i++) - if (isdigit(c->parm.num[i])) - chan->eazmask |= (1 << (c->parm.num[i] - '0')); - } - } else - chan->eazmask = 0x3ff; + chan->eazmask = 0x3ff; eicon_idi_listen_req(card, chan); return 0; case ISDN_CMD_CLREAZ: @@ -680,8 +532,10 @@ eicon_command(eicon_card * card, isdn_ctrl * c) break; chan->l3prot = (c->arg >> 8); #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) + if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) { chan->fax = c->parm.fax; + eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax); + } #endif return 0; case ISDN_CMD_GETL3: @@ -706,10 +560,14 @@ eicon_command(eicon_card * card, isdn_ctrl * c) eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n"); return 0; case ISDN_CMD_LOCK: - MOD_INC_USE_COUNT; +#ifdef MODULE + mod_inc_use_count(); +#endif return 0; case ISDN_CMD_UNLOCK: - MOD_DEC_USE_COUNT; +#ifdef MODULE + mod_dec_use_count(); +#endif return 0; #ifdef CONFIG_ISDN_TTY_FAX case ISDN_CMD_FAXCMD: @@ -729,6 +587,23 @@ eicon_command(eicon_card * card, isdn_ctrl * c) break; idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); return 0; + case CAPI_PUT_MESSAGE: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (c->parm.cmsg.Length < 8) + break; + switch(c->parm.cmsg.Command) { + case CAPI_FACILITY: + if (c->parm.cmsg.Subcommand == CAPI_REQ) + return(capipmsg(card, chan, &c->parm.cmsg)); + break; + case CAPI_MANUFACTURER: + default: + break; + } + return 0; } return -EINVAL; @@ -787,8 +662,7 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel) if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while((skb = skb_dequeue(&card->statq))) { if ((skb->len + count) > len) @@ -811,12 +685,12 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel) } else { skb_pull(skb, cnt); skb_queue_head(&card->statq, skb); - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } } card->statq_entries = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } printk(KERN_ERR @@ -848,7 +722,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) } else #endif - ret = idi_send_data(card, chan, ack, skb, 1); + ret = idi_send_data(card, chan, ack, skb, 1, 1); return (ret); } else { return -ENODEV; @@ -895,12 +769,11 @@ eicon_putstatus(eicon_card * card, char * buf) return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); count = strlen(buf); skb = alloc_skb(count, GFP_ATOMIC); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); printk(KERN_ERR "eicon: could not alloc skb in putstatus\n"); return; } @@ -918,7 +791,7 @@ eicon_putstatus(eicon_card * card, char * buf) } else card->statq_entries++; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (count) { cmd.command = ISDN_STAT_STAVAIL; cmd.driver = card->myid; @@ -967,7 +840,7 @@ eicon_log(eicon_card * card, int level, const char *fmt, ...) * link it into cards-list. */ static void -eicon_alloccard(int Type, int membase, int irq, char *id) +eicon_alloccard(int Type, int membase, int irq, char *id, int card_id) { int i; int j; @@ -976,9 +849,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id) char qid[5]; #endif eicon_card *card; -#if CONFIG_PCI - eicon_pci_card *pcic; -#endif qloop = (Type == EICON_CTYPE_QUADRO)?2:0; for (i = 0; i <= qloop; i++) { @@ -1088,9 +958,9 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->interface.channels = 1; break; #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRA: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1101,11 +971,26 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; + card->hwif.pci.irq = irq; + card->hwif.pci.type = Type; + card->flags = 0; + card->nchannels = 2; + card->interface.channels = 1; + break; + + case EICON_CTYPE_MAESTRAQ: + card->bus = EICON_BUS_PCI; + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_TRANSDSP | + ISDN_FEATURE_L3_FCLASS2; + card->hwif.pci.card = (void *)card; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1114,7 +999,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id) break; case EICON_CTYPE_MAESTRAP: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1125,13 +1009,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIram = pcic->PCIram; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1139,6 +1017,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->interface.channels = 1; break; #endif +#endif #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_ISABRI: if (membase == -1) @@ -1197,6 +1076,53 @@ eicon_alloccard(int Type, int membase, int irq, char *id) skb_queue_head_init(&card->bch[j].e.X); skb_queue_head_init(&card->bch[j].e.R); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI + /* *** Diva Server *** */ + if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2 + , GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate DBUFFER-struct.\n", id); + kfree(card); + kfree(card->bch); + return; + } + if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERS-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + return; + } + if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + kfree(card->sbuf); + return; + } + for (j=0; j< (card->nchannels + 1); j++) { + memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER)); + card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j]; + memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS)); + card->bch[j].de.X = (BUFFERS *)&card->sbuf[j]; + memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbufp[j], 0, 270); + card->bch[j].de.X->P = (char *)&card->sbufp[j * 270]; + memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270); + card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270]; + } + /* *** */ +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ + card->next = cards; cards = card; } @@ -1220,10 +1146,7 @@ eicon_registercard(eicon_card * card) #endif /* CONFIG_MCA */ #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_printpar(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon_registercard: Illegal BUS type %d\n", @@ -1260,10 +1183,7 @@ unregister_card(eicon_card * card) break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_release(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon: Invalid BUS type %d\n", @@ -1295,13 +1215,17 @@ eicon_freecard(eicon_card *card) { while((skb = skb_dequeue(&card->statq))) dev_kfree_skb(skb); - eicon_clear_msn(card); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + kfree(card->sbufp); + kfree(card->sbuf); + kfree(card->dbuf); +#endif kfree(card->bch); kfree(card); } int -eicon_addcard(int Type, int membase, int irq, char *id) +eicon_addcard(int Type, int membase, int irq, char *id, int card_id) { eicon_card *p; eicon_card *q = NULL; @@ -1314,7 +1238,7 @@ eicon_addcard(int Type, int membase, int irq, char *id) if ((Type = eicon_isa_find_card(membase, irq, id)) < 0) return 0; #endif - eicon_alloccard(Type, membase, irq, id); + eicon_alloccard(Type, membase, irq, id, card_id); p = cards; while (p) { registered = 0; @@ -1333,12 +1257,14 @@ eicon_addcard(int Type, int membase, int irq, char *id) break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI if (eicon_registercard(p)) break; registered = 1; break; #endif +#endif default: printk(KERN_ERR "eicon: addcard: Invalid BUS type %d\n", @@ -1371,8 +1297,6 @@ eicon_addcard(int Type, int membase, int irq, char *id) return (added - failed); } -#define DRIVERNAME "Eicon active ISDN driver" -#define DRIVERRELEASE "1" #ifdef MODULE #define eicon_init init_module @@ -1382,35 +1306,30 @@ int eicon_init(void) { int card_count = 0; - int release = 0; char tmprev[50]; DebugVar = 1; + eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; printk(KERN_INFO "%s Rev: ", DRIVERNAME); strcpy(tmprev, eicon_revision); printk("%s/", eicon_getrev(tmprev)); - release += getrel(tmprev); strcpy(tmprev, eicon_pci_revision); -#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_isa_revision); #ifdef CONFIG_ISDN_DRV_EICON_ISA printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_idi_revision); printk("%s\n", eicon_getrev(tmprev)); - release += getrel(tmprev); - sprintf(tmprev,"%d", release); - printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME, - DRIVERRELEASE, tmprev, DRIVERPATCH); + printk(KERN_INFO "%s Release: %s%s (%s)\n", DRIVERNAME, + DRIVERRELEASE, DRIVERPATCH, file_check()); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1427,18 +1346,23 @@ eicon_init(void) card_count++; }; #else - card_count = eicon_addcard(0, membase, irq, id); + card_count = eicon_addcard(0, membase, irq, id, 0); #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + DivasCardsDiscover(); card_count += eicon_pci_find_card(id); #endif +#endif + if (!cards) { #ifdef MODULE -#ifndef CONFIG_PCI +#ifndef CONFIG_ISDN_DRV_EICON_PCI #ifndef CONFIG_ISDN_DRV_EICON_ISA printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n"); + printk(KERN_INFO "Eicon: Driver not loaded !\n"); #else printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n"); #endif @@ -1451,17 +1375,47 @@ eicon_init(void) } else printk(KERN_INFO "Eicon: %d card%s added\n", card_count, (card_count>1)?"s":""); - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; return 0; } + #ifdef MODULE + +void mod_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void mod_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +#ifdef CONFIG_ISDN_DRV_EICON_PCI +void EtdM_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#else +int DivasCardNext; +card_t DivasCards[1]; +#endif + void cleanup_module(void) { +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + card_t *pCard; + word wCardIndex; + extern int Divas_major; + int iTmp = 0; +#endif +#endif + eicon_card *card = cards; eicon_card *last; + while (card) { #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1481,6 +1435,54 @@ cleanup_module(void) card = card->next; eicon_freecard(last); } + +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + for (iTmp = 0; iTmp < 3; iTmp++) + { + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + } + pCard++; + } + unregister_chrdev(Divas_major, "Divas"); +#endif +#endif /* CONFIG_PCI */ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } @@ -1675,7 +1677,7 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ return ENODEV; }; /* matching membase & irq */ - if ( 1 == eicon_addcard(type, membase, irq, id)) { + if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name); mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards); diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c index e696b5584..6cb3bca6d 100644 --- a/drivers/isdn/eicon/eicon_pci.c +++ b/drivers/isdn/eicon/eicon_pci.c @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.c,v 1.15 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -9,8 +9,6 @@ * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * 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) @@ -25,53 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.c,v $ - * Revision 1.11 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.10 1999/08/22 20:26:49 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/11 21:01:11 keil - * new PCI codefix - * - * Revision 1.8 1999/08/10 16:02:20 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.7 1999/06/09 19:31:29 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.6 1999/04/01 12:48:37 armin - * Changed some log outputs. - * - * Revision 1.5 1999/03/29 11:19:49 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:48 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:24 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:06 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:45 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include <linux/config.h> @@ -80,896 +31,90 @@ #include "eicon.h" #include "eicon_pci.h" +#undef N_DATA +#include "adapter.h" +#include "uxio.h" -char *eicon_pci_revision = "$Revision: 1.11 $"; +char *eicon_pci_revision = "$Revision: 1.15 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ - -#undef EICON_PCI_DEBUG +#ifdef CONFIG_ISDN_DRV_EICON_PCI int eicon_pci_find_card(char *ID) { - if (pci_present()) { - struct pci_dev *pdev = NULL; - int pci_nextindex=0, pci_cards=0, pci_akt=0; - int pci_type = PCI_MAESTRA; - int NoMorePCICards = FALSE; - char *ram, *reg, *cfg; - unsigned int pram=0, preg=0, pcfg=0; - char did[12]; - eicon_pci_card *aparms; - - if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) { - printk(KERN_WARNING - "eicon_pci: Could not allocate card-struct.\n"); - return 0; - } - - for (pci_cards = 0; pci_cards < 0x0f; pci_cards++) - { - do { - if ((pdev = pci_find_device(PCI_VENDOR_EICON, - pci_type, - pdev))) + int pci_cards = 0; + int card_id = 0; + int had_q = 0; + int ctype = 0; + char did[20]; + card_t *pCard; + word wCardIndex; + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) { - pci_nextindex++; - break; - } - else { - pci_nextindex = 0; - switch (pci_type) /* switch to next card type */ - { - case PCI_MAESTRA: - pci_type = PCI_MAESTRAQ; break; - case PCI_MAESTRAQ: - pci_type = PCI_MAESTRAQ_U; break; - case PCI_MAESTRAQ_U: - pci_type = PCI_MAESTRAP; break; - default: - case PCI_MAESTRAP: - NoMorePCICards = TRUE; - } - } - } - while (!NoMorePCICards); - if (NoMorePCICards) - { - if (pci_cards < 1) { - printk(KERN_INFO "Eicon: No supported PCI cards found.\n"); - kfree(aparms); - return 0; - } - else - { - printk(KERN_INFO "Eicon: %d PCI card%s registered.\n", - pci_cards, (pci_cards > 1) ? "s":""); - kfree(aparms); - return (pci_cards); - } - } - - pci_enable_device(pdev); /* XXX handle error return */ - - pci_akt = 0; - switch(pci_type) - { - case PCI_MAESTRA: - printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRA; - - aparms->irq = pdev->irq; - preg = pci_resource_start(pdev, 2); - pcfg = pci_resource_start(pdev, 1); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg); -#endif - pci_akt = 1; - break; - - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n"); - pci_cards--; - pci_akt = 0; - break; - - case PCI_MAESTRAP: - printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/ - aparms->irq = pdev->irq; - pram = pci_resource_start(pdev, 0); - preg = pci_resource_start(pdev, 2); - pcfg = pci_resource_start(pdev, 4); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: ram=0x%x\n", - (pram)); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", - (preg)); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", - (pcfg)); -#endif - pci_akt = 1; - break; - default: - printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n"); - pci_cards--; - pci_akt = 0; - break; - } - - if (pci_akt) { - /* remapping memory */ - switch(pci_type) + if ((pCard->hw) && (pCard->hw->in_use)) { - case PCI_MAESTRA: - aparms->PCIreg = (unsigned int) preg; - aparms->PCIcfg = (unsigned int) pcfg; - if (check_region((aparms->PCIreg), 0x20)) { - printk(KERN_WARNING "eicon_pci: reg port already in use !\n"); - aparms->PCIreg = 0; - break; - } else { - request_region(aparms->PCIreg, 0x20, "eicon reg"); + switch(pCard->hw->card_type) { + case DIA_CARD_TYPE_DIVA_SERVER: + ctype = EICON_CTYPE_MAESTRAP; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_B: + ctype = EICON_CTYPE_MAESTRA; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_Q: + ctype = EICON_CTYPE_MAESTRAQ; + if (!had_q) + card_id++; + if (++had_q >=4) + had_q = 0; + break; + default: + printk(KERN_ERR "eicon_pci: unknown card type %d !\n", + pCard->hw->card_type); + goto err; } - if (check_region((aparms->PCIcfg), 0x80)) { - printk(KERN_WARNING "eicon_pci: cfg port already in use !\n"); - aparms->PCIcfg = 0; - release_region(aparms->PCIreg, 0x20); - break; - } else { - request_region(aparms->PCIcfg, 0x80, "eicon cfg"); - } - break; - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - case PCI_MAESTRAP: - aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000); - ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET); - reg = ioremap(preg, 0x4000); - cfg = ioremap(pcfg, 0x1000); - aparms->PCIram = (unsigned int) ram; - aparms->PCIreg = (unsigned int) reg; - aparms->PCIcfg = (unsigned int) cfg; - break; - } - if ((!aparms->PCIreg) || (!aparms->PCIcfg)) { - printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; - } else { - aparms->mvalid = 1; - sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards); - - printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did); - - if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) { + if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) { printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; + } else { + pci_cards++; + printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n", + eicon_ctype_name[ctype], did, card_id); } +err: } + pCard++; } - - } - } else - printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n"); - return 0; -} - -/* - * Checks protocol file id for "F#xxxx" string fragment to - * extract the features, supported by this protocol version. - * binary representation of the feature string value is returned - * in *value. The function returns 0 if feature string was not - * found or has a wrong format, else 1. - */ -static int GetProtFeatureValue(char *sw_id, int *value) -{ - __u8 i, offset; - - while (*sw_id) - { - if ((sw_id[0] == 'F') && (sw_id[1] == '#')) - { - sw_id = &sw_id[2]; - for (i=0, *value=0; i<4; i++, sw_id++) - { - if ((*sw_id >= '0') && (*sw_id <= '9')) - { - offset = '0'; - } - else if ((*sw_id >= 'A') && (*sw_id <= 'F')) - { - offset = 'A' + 10; - } - else if ((*sw_id >= 'a') && (*sw_id <= 'f')) - { - offset = 'a' + 10; - } - else - { - return 0; - } - *value |= (*sw_id - offset) << (4*(3-i)); - } - return 1; - } - else - { - sw_id++; - } - } - return 0; + return pci_cards; } - void -eicon_pci_printpar(eicon_pci_card *card) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->PCIreg, - (unsigned int)card->PCIcfg, - card->irq); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - printk(KERN_INFO "%s at 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->shmem, - card->irq); -#ifdef EICON_PCI_DEBUG - printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram); - printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg); - printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); -#endif - break; - } -} - - -static void -eicon_pci_release_shmem(eicon_pci_card *card) { - if (!card->master) - return; - if (card->mvalid) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - /* reset board */ - outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */ - outb(0, card->PCIreg + M_RESET); - SLEEP(20); - outb(0, card->PCIreg + M_ADDRH); - outw(0, card->PCIreg + M_ADDR); - outw(0, card->PCIreg + M_DATA); - - release_region(card->PCIreg, 0x20); - release_region(card->PCIcfg, 0x80); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - iounmap((void *)card->shmem); - iounmap((void *)card->PCIreg); - iounmap((void *)card->PCIcfg); - break; - } - } - card->mvalid = 0; -} - -static void -eicon_pci_release_irq(eicon_pci_card *card) { - if (!card->master) - return; - if (card->ivalid) - free_irq(card->irq, card); - card->ivalid = 0; -} - -void -eicon_pci_release(eicon_pci_card *card) { - eicon_pci_release_irq(card); - eicon_pci_release_shmem(card); -} - -/* - * Upload buffer content to adapters shared memory - * on verify error, 1 is returned and a message is printed on screen - * else 0 is returned - * Can serve IO-Type and Memory type adapters - */ -int eicon_upload(t_dsp_download_space *p_para, - __u16 length, /* byte count */ - __u8 *buffer, - int verify) +eicon_pci_init_conf(eicon_card *card) { - __u32 i, dwdata = 0, val = 0, timeout; - __u16 data; - eicon_pci_boot *boot = 0; - - switch (p_para->type) /* actions depend on type of union */ - { - case DL_PARA_IO_TYPE: - for (i=0; i<length; i+=2) - { - outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */ - outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); - } - if (verify) /* check written block */ - { - for (i=0; i<length; i+=2) - { - outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - data = inw(p_para->dat.io.ioDATA); - if (data != *(u16 *)&buffer[i]) - { - p_para->dat.io.r3addr += i; - p_para->dat.io.BadData = data; - p_para->dat.io.GoodData = *(u16 *)&buffer[i]; - return 1; - } - } - } - break; - - case DL_PARA_MEM_TYPE: - boot = p_para->dat.mem.boot; - writel(p_para->dat.mem.r3addr, &boot->addr); - for (i=0; i<length; i+=4) - { - writel(((u32 *)buffer)[i >> 2], &boot->data[i]); - } - if (verify) /* check written block */ - { - for (i=0; i<length; i+=4) - { - dwdata = readl(&boot->data[i]); - if (((u32 *)buffer)[i >> 2] != dwdata) - { - p_para->dat.mem.r3addr += i; - p_para->dat.mem.BadData = dwdata; - p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2]; - return 1; - } - } - } - writel(((length + 3) / 4), &boot->len); /* len in dwords */ - writel(2, &boot->cmd); - - timeout = jiffies + 20; - while (timeout > jiffies) { - val = readl(&boot->cmd); - if (!val) break; - SLEEP(2); - } - if (val) - { - p_para->dat.mem.timeout = 1; - return 1; - } - break; - } - return 0; -} - - -/* show header information of code file */ -static -int eicon_pci_print_hdr(unsigned char *code, int offset) -{ - unsigned char hdr[80]; - int i, fvalue = 0; - - i = 0; - while ((i < (sizeof(hdr) -1)) - && (code[offset + i] != '\0') - && (code[offset + i] != '\r') - && (code[offset + i] != '\n')) - { - hdr[i] = code[offset + i]; - i++; - } - hdr[i] = '\0'; - printk(KERN_DEBUG "Eicon: loading %s\n", hdr); - if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue); - else return(0); -} - - -/* - * Configure a card, download code into BRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - int i,j; - int timeout; - unsigned int offset, offp=0, size, length; - int signature = 0; - int FeatureValue = 0; - eicon_pci_codebuf cbuf; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - unsigned char *code; - unsigned int reg; - unsigned int cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - reg = card->PCIreg; - cfg = card->PCIcfg; - - /* reset board */ - outb(0, reg + M_RESET); - SLEEP(10); - outb(0, reg + M_ADDRH); - outw(0, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card\n"); -#endif - - /* clear shared memory */ - outb(0xff, reg + M_ADDRH); - outw(0, reg + M_ADDR); - for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA); - SLEEP(10); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: clear shared memory\n"); -#endif - - /* download protocol and dsp file */ - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_IO_TYPE; - dl_para.dat.io.ioADDR = reg + M_ADDR; - dl_para.dat.io.ioADDRH = reg + M_ADDRH; - dl_para.dat.io.ioDATA = reg + M_DATA; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j == 0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - offset = 0; - - if (j == 0) dl_para.dat.io.r3addr = 0; - if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32); - - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - kfree(code); - return -EIO; - } - /* move onto next block */ - offset += length; - dl_para.dat.io.r3addr += length; - } while (offset < size); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* clear signature */ - outb(0xff, reg + M_ADDRH); - outw(0x1e, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* copy configuration data into shared memory */ - outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA); - outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA); - outw(10,reg + M_ADDR); outb(0, reg + M_DATA); - outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA); - outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA); - outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */ - outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA); - outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA); - outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */ - outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */ - outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA); - outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA); - outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA); - outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA); - - for (i=0;i<32;i++) - { - outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA); - outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA); - outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA); - outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA); - outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA); - outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA); + int j; + + /* initializing some variables */ + card->ReadyInt = 0; + + for(j = 0; j < 256; j++) + card->IdTable[j] = NULL; + + for(j = 0; j < (card->d->channels + 1); j++) { + card->bch[j].e.busy = 0; + card->bch[j].e.D3Id = 0; + card->bch[j].e.B2Id = 0; + card->bch[j].e.ref = 0; + card->bch[j].e.Req = 0; + card->bch[j].e.complete = 1; + card->bch[j].fsm_state = EICON_STATE_NULL; } - -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: starting CPU...\n"); -#endif - /* let the CPU run */ - outw(0x08, reg + M_RESET); - - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - outw(0x1e, reg + M_ADDR); - signature = inw(reg + M_DATA); - if (signature == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if (signature != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - outb(0xff, reg + M_ADDRH); - outw(0x3f6, reg + M_ADDR); - card->channels = inw(reg + M_DATA); - card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - /* Trigger an interrupt and check if it is delivered */ - outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */ - outb(0x89, reg + M_RESET); /* place int request */ - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(5); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; } - -/* - * Configure a card, download code into PRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - eicon_pci_boot *boot; - eicon_pr_ram *prram; - int i,j; - int timeout; - int FeatureValue = 0; - unsigned int offset, offp=0, size, length; - unsigned long int signature = 0; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - eicon_pci_codebuf cbuf; - unsigned char *code; - unsigned char req_int; - char *ram, *reg, *cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - boot = &card->shmem->boot; - ram = (char *)card->PCIram; - reg = (char *)card->PCIreg; - cfg = (char *)card->PCIcfg; - prram = (eicon_pr_ram *)ram; - - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - /* set command count to 0 */ - writel(0, &boot->reserved); - - /* check if CPU increments the life word */ - i = readw(&boot->live); - SLEEP(20); - if (i == readw(&boot->live)) { - printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n"); #endif - - /* download firmware : DSP and Protocol */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_MEM_TYPE; - dl_para.dat.mem.boot = boot; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j==0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */ - - if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR; - if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32); - - offset = 0; - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - if (dl_para.dat.mem.timeout == 0) - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - else - printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n"); - kfree(code); - return -EIO; - } - - /* move onto next block */ - offset += length; - dl_para.dat.mem.r3addr += length; - } while (offset < size); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* initialize the adapter data structure */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* clear out config space */ - for (i = 0; i < 256; i++) writeb(0, &ram[i]); - - /* copy configuration down to the card */ - writeb(cbuf.tei, &ram[8]); - writeb(cbuf.nt2, &ram[9]); - writeb(0, &ram[10]); - writeb(cbuf.WatchDog, &ram[11]); - writeb(cbuf.Permanent, &ram[12]); - writeb(cbuf.XInterface, &ram[13]); - writeb(cbuf.StableL2, &ram[14]); - writeb(cbuf.NoOrderCheck, &ram[15]); - writeb(cbuf.HandsetType, &ram[16]); - writeb(0, &ram[17]); - writeb(cbuf.LowChannel, &ram[18]); - writeb(cbuf.ProtVersion, &ram[19]); - writeb(cbuf.Crc4, &ram[20]); - for (i = 0; i < 32; i++) - { - writeb(cbuf.l[0].oad[i], &ram[32 + i]); - writeb(cbuf.l[0].osa[i], &ram[64 + i]); - writeb(cbuf.l[0].spid[i], &ram[96 + i]); - writeb(cbuf.l[1].oad[i], &ram[128 + i]); - writeb(cbuf.l[1].osa[i], &ram[160 + i]); - writeb(cbuf.l[1].spid[i], &ram[192 + i]); - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: configured card OK\n"); -#endif - - /* start adapter */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: tell card to start...\n"); -#endif - writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */ - writel(3, &boot->cmd); /* DIVAS_START_CMD */ - - /* wait till card ACKs */ - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - signature = readl(&boot->signature); - if ((signature >> 16) == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if ((signature >> 16) != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - card->channels = readb(&ram[0x3f6]); - card->serial = readl(&ram[0x3f0]); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - readb(&ram[0x3fe]); - writeb(0, &ram[0x3fe]); /* reset any pending interrupt */ - readb(&ram[0x3fe]); - - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - - req_int = readb(&prram->ReadyInt); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - req_int++; - /* Trigger an interrupt and check if it is delivered */ - writeb(req_int, &prram->ReadyInt); - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(2); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; -} - #endif /* CONFIG_PCI */ diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h index 384cc422c..17fd4183a 100644 --- a/drivers/isdn/eicon/eicon_pci.h +++ b/drivers/isdn/eicon/eicon_pci.h @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards (PCI part). * @@ -19,26 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.h,v $ - * Revision 1.4 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.3 1999/03/29 11:19:51 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:50 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:46 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_pci_h @@ -46,147 +26,20 @@ #ifdef __KERNEL__ - -#define PCI_VENDOR_EICON 0x1133 -#define PCI_DIVA_PRO20 0xe001 /* Not supported */ -#define PCI_DIVA20 0xe002 /* Not supported */ -#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */ -#define PCI_DIVA20_U 0xe004 /* Not supported */ -#define PCI_MAESTRA 0xe010 -#define PCI_MAESTRAQ 0xe012 -#define PCI_MAESTRAQ_U 0xe013 -#define PCI_MAESTRAP 0xe014 - -#define DIVA_PRO20 1 -#define DIVA20 2 -#define DIVA_PRO20_U 3 -#define DIVA20_U 4 -#define MAESTRA 5 -#define MAESTRAQ 6 -#define MAESTRAQ_U 7 -#define MAESTRAP 8 - -#define TRUE 1 -#define FALSE 0 - -#define DIVAS_SIGNATURE 0x4447 - - -/* MAESTRA BRI PCI */ - -#define M_RESET 0x10 /* offset of reset register */ -#define M_DATA 0x00 /* offset of data register */ -#define M_ADDR 0x04 /* offset of address register */ -#define M_ADDRH 0x0c /* offset of high address register */ - -#define M_DSP_CODE_LEN 0xbf7d0000 -#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */ -#define M_DSP_CODE_BASE 0xbf7a0000 -#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */ - - - -/* MAESTRA PRI PCI */ - -#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */ - -#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */ -#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */ - -#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */ -#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */ -#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ -#define MP_DSP_CODE_BASE 0xa03a0000 -#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */ - -#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */ - -/* RESET register bits */ -#define _MP_S2M_RESET 0x10 /* active lo */ -#define _MP_LED2 0x08 /* 1 = on */ -#define _MP_LED1 0x04 /* 1 = on */ -#define _MP_DSP_RESET 0x02 /* active lo */ -#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */ - -/* boot interface structure */ -typedef struct { - __u32 cmd __attribute__ ((packed)); - __u32 addr __attribute__ ((packed)); - __u32 len __attribute__ ((packed)); - __u32 err __attribute__ ((packed)); - __u32 live __attribute__ ((packed)); - __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed)); - __u32 signature __attribute__ ((packed)); - __u8 data[1]; /* real interface description */ -} eicon_pci_boot; - - -#define DL_PARA_IO_TYPE 0 -#define DL_PARA_MEM_TYPE 1 - -typedef struct tag_dsp_download_space -{ - __u16 type; /* see definitions above to differ union elements */ - union - { - struct - { - __u32 r3addr; - __u16 ioADDR; - __u16 ioADDRH; - __u16 ioDATA; - __u16 BadData; /* in case of verify error */ - __u16 GoodData; - } io; /* for io based adapters */ - struct - { - __u32 r3addr; - eicon_pci_boot *boot; - __u32 BadData; /* in case of verify error */ - __u32 GoodData; - __u16 timeout; - } mem; /* for memory based adapters */ - } dat; -} t_dsp_download_space; - - -/* Shared memory */ -typedef union { - eicon_pci_boot boot; -} eicon_pci_shmem; - /* * card's description */ typedef struct { - int ramsize; int irq; /* IRQ */ - unsigned int PCIram; - unsigned int PCIreg; - unsigned int PCIcfg; - long int serial; /* Serial No. */ int channels; /* No. of supported channels */ void* card; - eicon_pci_shmem* shmem; /* Shared-memory area */ - unsigned char* intack; /* Int-Acknowledge */ - unsigned char* stopcpu; /* Writing here stops CPU */ - unsigned char* startcpu; /* Writing here starts CPU */ unsigned char type; /* card type */ - unsigned char irqprobe; /* Flag: IRQ-probing */ - unsigned char mvalid; /* Flag: Memory is valid */ - unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card is Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_pci_card; - - -extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern void eicon_pci_release(eicon_pci_card *card); -extern void eicon_pci_printpar(eicon_pci_card *card); extern int eicon_pci_find_card(char *ID); #endif /* __KERNEL__ */ #endif /* eicon_pci_h */ + diff --git a/drivers/isdn/eicon/fcheck.c b/drivers/isdn/eicon/fcheck.c new file mode 100644 index 000000000..c86f7d3df --- /dev/null +++ b/drivers/isdn/eicon/fcheck.c @@ -0,0 +1,31 @@ +/* $Id: fcheck.c,v 1.3 2000/06/12 12:44:02 armin Exp $ + * + * (c) 2000 Cytronics & Melware + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/README.eicon + * + * + */ + +#include <linux/kernel.h> + +char * +file_check(void) { + +#ifdef FILECHECK +#if FILECHECK == 0 + return("verified"); +#endif +#if FILECHECK == 1 + return("modified"); +#endif +#if FILECHECK == 127 + return("verification failed"); +#endif +#else + return("not verified"); +#endif +} + diff --git a/drivers/isdn/eicon/fourbri.c b/drivers/isdn/eicon/fourbri.c new file mode 100644 index 000000000..5fe9817e0 --- /dev/null +++ b/drivers/isdn/eicon/fourbri.c @@ -0,0 +1,583 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.7 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Diva Server 4BRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" +#include "constant.h" +#include "adapter.h" +#include "uxio.h" + +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for 4BRI card */ +#define MQ_BOARD_DSP_OFFSET 0x00a00000 +#define MQ_DSP1_ADDR_OFFSET 0x00000008 +#define MQ_DSP_JUNK_OFFSET 0x00000400 +#define MQ_DSP1_DATA_OFFSET 0x00000000 +#define MQ_BOARD_ISAC_DSP_RESET 0x00800028 +#define MQ_BREG_RISC 0x1200 /* RISC Reset */ +#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */ +#define MQ_RISC_COLD_RESET_MASK 0x0001 /* RISC Cold reset */ +#define MQ_RISC_WARM_RESET_MASK 0x0002 /* RISC Warm reset */ +#define MQ_IRQ_REQ_ON 0x1 +#define MQ_IRQ_REQ_OFF 0x0 +#define MQ_BREG_IRQ_TEST 0x0608 +#define PLX9054_INTCSR 0x69 +#define PLX9054_INT_ENA 0x09 + +#define DIVAS_IOBASE 0x01 +#define M_PCI_RESET 0x10 + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg); +int fourbri_ISR (card_t* card); + +int FPGA_Download(word, dword, byte *, byte *, int); +extern byte FPGA_Bytes[]; +extern void *get_card(int); + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +word GetProtFeatureValue(char *sw_id); + +void memcp(byte *dst, byte *src, dword dwLen); +int memcm(byte *dst, byte *src, dword dwLen); + +static int diva_server_4bri_reset(card_t *card) +{ + byte *ctl; + + DPRINTF(("divas: reset Diva Server 4BRI")); + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + /* stop RISC, DSP's and ISAC */ + UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0); + UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0); + + UxCardMemDetach(card->hw, ctl); + + return 0; +} + +static int diva_server_4bri_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server 4BRI")); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardMemOut(card->hw, &shared[22], 4); + } + else + { + UxCardMemOut(card->hw, &shared[22], 0); + } + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_4bri_reset_int(card_t *card) +{ + byte *ctl; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + + UxCardMemDetach(card->hw, ctl); + + return; +} + + +static int diva_server_4bri_test_int(card_t *card) +{ + byte *ctl, i; + byte *reg; + + DPRINTF(("divas: test interrupt for Diva Server 4BRI")); + + /* We get the last (dummy) adapter in so we need to go back to the first */ + + card = get_card(card->cfg.card_id - 3); + + /* Enable interrupts on PLX chip */ + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA); + + UxCardMemDetach(card->hw, reg); + + /* Set the test interrupt flag */ + card->test_int_pend = TEST_INT_DIVAS_Q; + + /* Now to trigger the interrupt */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON); + + UxCardMemDetach(card->hw, ctl); + + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + if (card->test_int_pend) + { + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_4bri_load(card_t *card, dia_load_t *load) +{ + byte *pRAM=NULL; + int download_offset=0; + card_t *FirstCard; + byte sw_id[80]; + + DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id)); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + download_offset = 0; // Protocol code written to offset 0 + pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC); + + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword); + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword); + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_FPGA_CODE: + DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length)); + if (FPGA_Download(IDI_ADAPTER_MAESTRAQ, + card->hw->io_base, + sw_id, + load->code, + load->length + ) == -1) + { + DPRINTF(("divas: FPGA download failed")); + return -1; + } + + /* NOW reset the 4BRI */ + diva_server_4bri_reset(card); + return 0; // No need for anything further loading + + default: + DPRINTF(("divas: unknown code type")); + return -1; + } + + memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length); + + { + int mism_off; + if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length))) + { + DPRINTF(("divas: memory mismatch at offset %d", mism_off)); + UxCardMemDetach(card->hw, pRAM); + return -1; + } + } + + UxCardMemDetach(card->hw, pRAM); + + return 0; +} + +static int diva_server_4bri_start(card_t *card, byte *channels) +{ + byte *ctl; + byte *shared, i; + int adapter_num; + + DPRINTF(("divas: start Diva Server 4BRI")); + *channels = 0; + card->is_live = FALSE; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK); + + UxPause(2); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK); + + UxPause(10); + + UxCardMemDetach(card->hw, ctl); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for ( i = 0 ; i < 300 ; ++i ) + { + UxPause (10) ; + + if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 ) + { + DPRINTF(("divas: Protocol startup time %d.%02d seconds", + (i / 100), (i % 100) )); + + break; + } + } + + if (i==300) + { + DPRINTF(("divas: Timeout starting card")); + DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E]))); + + UxCardMemDetach(card->hw, shared); + return -1; + } + + UxCardMemDetach(card->hw, shared); + + for (adapter_num=3; adapter_num >= 0; adapter_num--) + { + card_t *qbri_card; + + qbri_card = get_card(card->cfg.card_id - adapter_num); + + if (qbri_card) + { + qbri_card->is_live = TRUE; + shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY); + *channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]); + UxCardMemDetach(qbri_card->hw, shared); + } + else + { + DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id)); + } + } + + diva_server_4bri_test_int(card); + + return 0; +} + +static +int diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise 4BRI specific entry points + */ + +int Divas4BriInit(card_t *card, dia_card_t *cfg) +{ +// byte sw_id[80]; +// extern int FPGA_Done; + + DPRINTF(("divas: initialise Diva Server 4BRI")); + + if (Divas4BRIInitPCI(card, cfg) == -1) + { + return -1; + } + + /* Need to download the FPGA */ +/* if (!FPGA_Done) + { + int retVal; + + retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ, + cfg->io_base, + sw_id, + FPGA_Bytes + ); + if(retVal==-1) + { + + DPRINTF(("divas: FPGA Download Failed")); + return -1; + + } + FPGA_Done = 1; + } */ + + card->card_reset = diva_server_4bri_reset; + card->card_load = diva_server_4bri_load; + card->card_config = diva_server_4bri_config; + card->card_start = diva_server_4bri_start; + card->reset_int = diva_server_4bri_reset_int; + card->card_mem_get = diva_server_4bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = fourbri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + +void memcp(byte *dst, byte *src, dword dwLen) +{ + while (dwLen) + { + *dst = *src; + dst++; src++; + dwLen--; + } +} + +int memcm(byte *dst, byte *src, dword dwLen) +{ + int offset = 0; + + while (offset < dwLen) + { + if(*dst != *src) + return (offset+1); + + offset++; + src++; + dst++; + } + + return 0; +} + + + +/*int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +}*/ + + +int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *ctl; + byte *reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + if (UxCardPortIoIn(card->hw, reg, PLX9054_INTCSR) & 0x80) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + UxCardMemDetach(card->hw, ctl); + } + + UxCardMemDetach(card->hw, reg); + return (served != 0); +} diff --git a/drivers/isdn/eicon/fpga.c b/drivers/isdn/eicon/fpga.c new file mode 100644 index 000000000..b5f21678e --- /dev/null +++ b/drivers/isdn/eicon/fpga.c @@ -0,0 +1,158 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 "sys.h" +#include "idi.h" +#include "uxio.h" + +#define FPGA_PORT 0x6E +#define FPGA_DLOAD_BUFLEN 256 +#define NAME_OFFSET 0x10 +#define NAME_MAXLEN 12 +#define DATE_OFFSET 0x2c +#define DATE_MAXLEN 10 + +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); +void UxPause(long int); + +/*-------------------------------------------------------------------------*/ +/* Loads the FPGA configuration file onto the hardware. */ +/* Function returns 0 on success, else an error number. */ +/* On success, an identifier string is returned in the buffer */ +/* */ +/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream */ +/* file and a file read function has to be provided by the operating */ +/* system part. */ +/* ----------------------------------------------------------------------- */ +int FPGA_Download( word cardtype, + dword RegBase, + byte *strbuf, + byte FPGA_SRC[], + int FPGA_LEN + ) +{ + word i, j, k; + word baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN; + dword addr; + byte *pFPGA; + + //--- check for legal cardtype + switch (cardtype) + { + case IDI_ADAPTER_MAESTRAQ: + addr = RegBase ; // address where to access FPGA + Mask_PROGRAM = 0x0001; // FPGA pins at address + Mask_DONE = 0x0002; + Mask_CCLK = 0x0100; + Mask_DIN = 0x0400; + baseval = 0x000d; // PROGRAM hi, CCLK lo, DIN lo by default + break; + + default: + + DPRINTF(("divas: FPGA Download ,Illegal Card")); + return -1; // illegal card + } + + //--- generate id string from file content + for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k++] = ' '; + for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k] = 0; + + DPRINTF(("divas: FPGA Download - %s", strbuf)); + + //--- prepare download, Pulse PROGRAM pin down. + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM); // PROGRAM low pulse + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // release + UxPause(50); // wait until FPGA finised internal memory clear + + //--- check done pin, must be low + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL")); + return -1; + } + + pFPGA = FPGA_SRC; + + i = 0; + /* Move past the header */ + while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN)) + { + i++; + } + + // We've hit the 0xFF so move on to the next byte + // i++; + DPRINTF(("divas: FPGA Code starts at offset %d", i)); + + //--- put data onto the FPGA + for (;i<FPGA_LEN; i++) + { + //--- put byte onto FPGA + for (j=0; j<8; j++) + { + if (FPGA_SRC[i] &(0x80>>j)) baseval |= Mask_DIN; // write a hi + else baseval &=~Mask_DIN; // write a lo + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + } + + //--- add some additional startup clock cycles and check done pin + for (i=0; i<5; i++) + { + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + + UxPause(100); + + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA download successful")); + } + else + { + DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT))); + return -1; + } + +return 0; +} + diff --git a/drivers/isdn/eicon/idi.c b/drivers/isdn/eicon/idi.c new file mode 100644 index 000000000..f9b8a0ee3 --- /dev/null +++ b/drivers/isdn/eicon/idi.c @@ -0,0 +1,870 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.8 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Core driver for Diva Server cards + * Implements the IDI interface + */ + +#include "idi.h" +#include "adapter.h" +#include "pc.h" +#include "pr_pc.h" +#include "sys.h" +#include "uxio.h" + +/* IDI request functions */ + +static void request(card_t *card, ENTITY *e); + +static void req_0(ENTITY *e) { request(&DivasCards[ 0], e); } +static void req_1(ENTITY *e) { request(&DivasCards[ 1], e); } +static void req_2(ENTITY *e) { request(&DivasCards[ 2], e); } +static void req_3(ENTITY *e) { request(&DivasCards[ 3], e); } +static void req_4(ENTITY *e) { request(&DivasCards[ 4], e); } +static void req_5(ENTITY *e) { request(&DivasCards[ 5], e); } +static void req_6(ENTITY *e) { request(&DivasCards[ 6], e); } +static void req_7(ENTITY *e) { request(&DivasCards[ 7], e); } +static void req_8(ENTITY *e) { request(&DivasCards[ 8], e); } +static void req_9(ENTITY *e) { request(&DivasCards[ 9], e); } +static void req_10(ENTITY *e) { request(&DivasCards[10], e); } +static void req_11(ENTITY *e) { request(&DivasCards[11], e); } +static void req_12(ENTITY *e) { request(&DivasCards[12], e); } +static void req_13(ENTITY *e) { request(&DivasCards[13], e); } +static void req_14(ENTITY *e) { request(&DivasCards[14], e); } +static void req_15(ENTITY *e) { request(&DivasCards[15], e); } + +IDI_CALL DivasIdiRequest[16] = +{ + &req_0, &req_1, &req_2, &req_3, + &req_4, &req_5, &req_6, &req_7, + &req_8, &req_9, &req_10, &req_11, + &req_12, &req_13, &req_14, &req_15 +}; + +#define PR_RAM ((struct pr_ram *)0) +#define RAM ((struct dual *)0) + +/*------------------------------------------------------------------*/ +/* local function prototypes */ +/*------------------------------------------------------------------*/ + +static byte isdn_rc(ADAPTER *, byte, byte, byte, word); +static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word); + +/* + * IDI related functions + */ + +static +ENTITY *entity_ptr(ADAPTER *a, byte e_no) +{ + card_t *card; + + card = a->io; + + return card->e_tbl[e_no].e; +} + +static +void CALLBACK(ADAPTER *a, ENTITY *e) +{ + card_t *card = a->io; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, FALSE); + } + + (*e->callback)(e); +} + +static +void *PTR_P(ADAPTER *a, ENTITY *e, void *P) +{ + return(P); +} + +static +void *PTR_R(ADAPTER *a, ENTITY *e) +{ + return((void*)e->R); +} + +static +void *PTR_X(ADAPTER *a, ENTITY *e) +{ + return((void*)e->X); +} + +static +void free_entity(ADAPTER *a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].e = NULL; + card->e_count--; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +void assign_queue(ADAPTER * a, byte e_no, word ref) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].assign_ref = ref; + card->e_tbl[e_no].next = card->assign; + card->assign = e_no; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte get_assign(ADAPTER *a, word ref) +{ + card_t *card; + byte e_no; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + e_no = (byte)card->assign; + while (e_no) + { + if (card->e_tbl[e_no].assign_ref == ref) + { + break; + } + e_no = card->e_tbl[e_no].next; + } + + UxCardUnlock(card->hw, ipl); + + return e_no; +} + +static +void req_queue(ADAPTER * a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].next = 0; + + if (card->e_head) + { + card->e_tbl[card->e_tail].next = e_no; + card->e_tail = e_no; + } + else + { + card->e_head = e_no; + card->e_tail = e_no; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte look_req(ADAPTER * a) +{ + card_t *card; + + card = a->io; + + return(card->e_head); +} + +static +void next_req(ADAPTER * a) +{ + card_t *card; + int ipl; + + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_head = card->e_tbl[card->e_head].next; + if (!card->e_head) + { + card->e_tail = 0; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + + +/* + * IDI request function for active cards + */ + +static +void request(card_t *card, ENTITY *e) +{ + word *special_req; + int i; + int ipl; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, TRUE); + } + + if (!e->Req) + { + special_req = (word *) e; + + switch (*special_req) + { + case REQ_REMOVE: + return; + + case REQ_NAME: + for (i=0; i < DIM(card->cfg.name); i++) + { + ((struct get_name_s *) e)->name[i] = card->cfg.name[i]; + } + return; + + case REQ_SERIAL: + case REQ_XLOG: + DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG")); + return; + + default: + return; + } + } + + ipl = UxCardLock(card->hw); + + if (!(e->Id & 0x1f)) + { + DPRINTF(("IDI: ASSIGN req")); + + for (i = 1; i < card->e_max; i++) + { + if (!card->e_tbl[i].e) + { + break; + } + } + + if (i == card->e_max) + { + DPRINTF(("IDI: request all ids in use (IDI req ignored)")); + UxCardUnlock(card->hw, ipl); + e->Rc = OUT_OF_RESOURCES; + return; + } + + card->e_tbl[i].e = e; + card->e_count++; + + e->No = (byte) i; + e->More = 0; + e->RCurrent = 0xff; + } + else + { + i = e->No; + } + + if (e->More & XBUSY) + { + DPRINTF(("IDI: request - entity is busy")); + UxCardUnlock(card->hw, ipl); + return; + } + + e->More |= XBUSY; + e->More &= ~ XMOREF; + e->XCurrent = 0; + e->XOffset = 0; + + card->e_tbl[i].next = 0; + + if(card->e_head) + { + card->e_tbl[card->e_tail].next = i; + card->e_tail = i; + } + else + { + card->e_head = i; + card->e_tail = i; + } + + UxCardUnlock(card->hw, ipl); + + DivasScheduleRequestDpc(); + + return; +} + +static byte pr_ready(ADAPTER * a) +{ + byte ReadyCount; + + ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) - + a->ram_in(a, &PR_RAM->ReqInput)); + + if(!ReadyCount) { + if(!a->ReadyInt) { + a->ram_inc(a, &PR_RAM->ReadyInt); + a->ReadyInt++; + } + } + return ReadyCount; +} + +/*------------------------------------------------------------------*/ +/* output function */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a) +{ + byte e_no; + ENTITY * this = NULL; + BUFFERS *X; + word length; + word i; + word clength; + REQ * ReqOut; + byte more; + byte ReadyCount; + byte ReqCount; + byte Id; + + /* while a request is pending ... */ + e_no = look_req(a); + if(!e_no) + { + return; + } + + ReadyCount = pr_ready(a); + if(!ReadyCount) + { + DPRINTF(("IDI: card not ready for next request")); + return; + } + + ReqCount = 0; + while(e_no && ReadyCount) { + + next_req(a); + + this = entity_ptr(a, e_no); + +#ifdef USE_EXTENDED_DEBUGS + if ( !this ) + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum)) + e_no = look_req(a) ; + ReadyCount-- ; + continue ; + } + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req)) + } +#else + DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh)); +#endif + + /* get address of next available request buffer */ + ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)]; + + /* now copy the data from the current data buffer into the */ + /* adapters request buffer */ + length = 0; + i = this->XCurrent; + X = PTR_X(a,this); + while(i<this->XNum && length<270) { + clength = MIN((word)(270-length),X[i].PLength-this->XOffset); + a->ram_out_buffer(a, + &ReqOut->XBuffer.P[length], + PTR_P(a,this,&X[i].P[this->XOffset]), + clength); + + length +=clength; + this->XOffset +=clength; + if(this->XOffset==X[i].PLength) { + this->XCurrent = (byte)++i; + this->XOffset = 0; + } + } + + a->ram_outw(a, &ReqOut->XBuffer.length, length); + a->ram_out(a, &ReqOut->ReqId, this->Id); + a->ram_out(a, &ReqOut->ReqCh, this->ReqCh); + + /* if its a specific request (no ASSIGN) ... */ + + if(this->Id &0x1f) { + + /* if buffers are left in the list of data buffers do */ + /* do chaining (LL_MDATA, N_MDATA) */ + + this->More++; + if(i<this->XNum && this->MInd) { + a->ram_out(a, &ReqOut->Req, this->MInd); + more = TRUE; + } + else { + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + more = FALSE; + } + + /* if we did chaining, this entity is put back into the */ + /* request queue */ + + if(more) { + req_queue(a,this->No); + } + } + + /* else it's a ASSIGN */ + + else { + + /* save the request code used for buffer chaining */ + + this->MInd = 0; + if (this->Id==BLLC_ID) this->MInd = LL_MDATA; + if (this->Id==NL_ID || + this->Id==TASK_ID || + this->Id==MAN_ID + ) this->MInd = N_MDATA; + + /* send the ASSIGN */ + + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + + /* save the reference of the ASSIGN */ + + assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference)); + } + a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next)); + ReadyCount--; + ReqCount++; + + e_no = look_req(a); + } + + /* send the filled request buffers to the ISDN adapter */ + + a->ram_out(a, &PR_RAM->ReqInput, + (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount)); + + /* if it is a 'unreturncoded' UREMOVE request, remove the */ + /* Id from our table after sending the request */ + if(this->Req==UREMOVE && this->Id) { + Id = this->Id; + e_no = a->IdTable[Id]; + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + +} + +/*------------------------------------------------------------------*/ +/* isdn interrupt handler */ +/*------------------------------------------------------------------*/ + +byte DivasDpc(ADAPTER * a) +{ + byte Count; + RC * RcIn; + IND * IndIn; + byte c; + byte RNRId; + byte Rc; + byte Ind; + + /* if return codes are available ... */ + if((Count = a->ram_in(a, &PR_RAM->RcOutput))) { + + DPRINTF(("IDI: #Rc=%x",Count)); + + /* get the buffer address of the first return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)]; + + /* for all return codes do ... */ + while(Count--) { + + if((Rc=a->ram_in(a, &RcIn->Rc))) { + + /* call return code handler, if it is not our return code */ + /* the handler returns 2 */ + /* for all return codes we process, we clear the Rc field */ + isdn_rc(a, + Rc, + a->ram_in(a, &RcIn->RcId), + a->ram_in(a, &RcIn->RcCh), + a->ram_inw(a, &RcIn->Reference)); + + a->ram_out(a, &RcIn->Rc, 0); + } + + /* get buffer address of next return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)]; + } + + /* clear all return codes (no chaining!) */ + a->ram_out(a, &PR_RAM->RcOutput ,0); + + /* call output function */ + DivasOut(a); + } + + /* clear RNR flag */ + RNRId = 0; + + /* if indications are available ... */ + if((Count = a->ram_in(a, &PR_RAM->IndOutput))) { + + DPRINTF(("IDI: #Ind=%x",Count)); + + /* get the buffer address of the first indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)]; + + /* for all indications do ... */ + while(Count--) { + + /* if the application marks an indication as RNR, all */ + /* indications from the same Id delivered in this interrupt */ + /* are marked RNR */ + if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) { + a->ram_out(a, &IndIn->Ind, 0); + a->ram_out(a, &IndIn->RNR, TRUE); + } + else { + Ind = a->ram_in(a, &IndIn->Ind); + if(Ind) { + RNRId = 0; + + /* call indication handler, a return value of 2 means chain */ + /* a return value of 1 means RNR */ + /* for all indications we process, we clear the Ind field */ + c = isdn_ind(a, + Ind, + a->ram_in(a, &IndIn->IndId), + a->ram_in(a, &IndIn->IndCh), + &IndIn->RBuffer, + a->ram_in(a, &IndIn->MInd), + a->ram_inw(a, &IndIn->MLength)); + + if(c==1) { + DPRINTF(("IDI: RNR")); + a->ram_out(a, &IndIn->Ind, 0); + RNRId = a->ram_in(a, &IndIn->IndId); + a->ram_out(a, &IndIn->RNR, TRUE); + } + } + } + + /* get buffer address of next indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)]; + } + + a->ram_out(a, &PR_RAM->IndOutput, 0); + } + return FALSE; +} + +byte DivasTestInt(ADAPTER * a) +{ + return a->ram_in(a,(void *)0x3fe); +} + +void DivasClearInt(ADAPTER * a) +{ + a->ram_out(a,(void *)0x3fe,0); +} + +/*------------------------------------------------------------------*/ +/* return code handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_rc(ADAPTER * a, + byte Rc, + byte Id, + byte Ch, + word Ref) +{ + ENTITY * this; + byte e_no; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc)) + } +#else + DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch)); +#endif + + /* check for ready interrupt */ + if(Rc==READY_INT) { + if(a->ReadyInt) { + a->ReadyInt--; + return 0; + } + return 2; + } + + /* if we know this Id ... */ + e_no = a->IdTable[Id]; + if(e_no) { + + this = entity_ptr(a,e_no); + + this->RcCh = Ch; + + /* if it is a return code to a REMOVE request, remove the */ + /* Id from our table */ + if(this->Req==REMOVE && Rc==OK) { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; +/**************************************************************/ + if ((this->More & XMOREC) > 1) { + this->More &= ~XMOREC; + this->More |= 1; + DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id)); + } + } + + if (Rc==OK_FC) { + this->Rc = Rc; + this->More = (this->More & (~XBUSY | XMOREC)) | 1; + this->complete = 0xFF; + CALLBACK(a, this); + return 0; + } + if(this->More &XMOREC) + this->More--; + + /* call the application callback function */ + if(this->More &XMOREF && !(this->More &XMOREC)) { + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + } + return 0; + } + + /* if it's an ASSIGN return code check if it's a return */ + /* code to an ASSIGN request from us */ + if((Rc &0xf0)==ASSIGN_RC) { + + e_no = get_assign(a, Ref); + + if(e_no) { + + this = entity_ptr(a,e_no); + + this->Id = Id; + + /* call the application callback function */ + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + + if(Rc==ASSIGN_OK) { + a->IdTable[Id] = e_no; + } + else + { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + return 1; + } + } + return 2; +} + +/*------------------------------------------------------------------*/ +/* indication handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_ind(ADAPTER * a, + byte Ind, + byte Id, + byte Ch, + PBUFFER * RBuffer, + byte MInd, + word MLength) +{ + ENTITY * this; + word clength; + word offset; + BUFFERS *R; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind)) + } +#else + DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch)); +#endif + + if(a->IdTable[Id]) { + + this = entity_ptr(a,a->IdTable[Id]); + + this->IndCh = Ch; + + /* if the Receive More flag is not yet set, this is the */ + /* first buffer of the packet */ + if(this->RCurrent==0xff) { + + /* check for receive buffer chaining */ + if(Ind==this->MInd) { + this->complete = 0; + this->Ind = MInd; + } + else { + this->complete = 1; + this->Ind = Ind; + } + + /* call the application callback function for the receive */ + /* look ahead */ + this->RLength = MLength; + + a->ram_look_ahead(a, RBuffer, this); + + this->RNum = 0; + CALLBACK(a, this); + + /* map entity ptr, selector could be re-mapped by call to */ + /* IDI from within callback */ + this = entity_ptr(a,a->IdTable[Id]); + + /* check for RNR */ + if(this->RNR==1) { + this->RNR = 0; + return 1; + } + + /* if no buffers are provided by the application, the */ + /* application want to copy the data itself including */ + /* N_MDATA/LL_MDATA chaining */ + if(!this->RNR && !this->RNum) { + return 0; + } + + /* if there is no RNR, set the More flag */ + this->RCurrent = 0; + this->ROffset = 0; + } + + if(this->RNR==2) { + if(Ind!=this->MInd) { + this->RCurrent = 0xff; + this->RNR = 0; + } + return 0; + } + /* if we have received buffers from the application, copy */ + /* the data into these buffers */ + offset = 0; + R = PTR_R(a,this); + do { + if(this->ROffset==R[this->RCurrent].PLength) { + this->ROffset = 0; + this->RCurrent++; + } + clength = MIN(a->ram_inw(a, &RBuffer->length)-offset, + R[this->RCurrent].PLength-this->ROffset); + if(R[this->RCurrent].P) { + a->ram_in_buffer(a, + &RBuffer->P[offset], + PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]), + clength); + } + offset +=clength; + this->ROffset +=clength; + } while(offset<(a->ram_inw(a, &RBuffer->length))); + + /* if it's the last buffer of the packet, call the */ + /* application callback function for the receive complete */ + /* call */ + if(Ind!=this->MInd) { + R[this->RCurrent].PLength = this->ROffset; + if(this->ROffset) this->RCurrent++; + this->RNum = this->RCurrent; + this->RCurrent = 0xff; + this->Ind = Ind; + this->complete = 2; + CALLBACK(a, this); + } + return 0; + } + return 2; +} diff --git a/drivers/isdn/eicon/idi.h b/drivers/isdn/eicon/idi.h new file mode 100644 index 000000000..0819665fe --- /dev/null +++ b/drivers/isdn/eicon/idi.h @@ -0,0 +1,146 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* External IDI interface */ + +#if !defined(IDI_H) +#define IDI_H + +#include "sys.h" + +/* typedefs for our data structures */ + +typedef struct get_name_s GET_NAME; +typedef struct entity_s ENTITY; +typedef struct buffers_s BUFFERS; + +/* IDI request/callback function pointer */ + +typedef void (* IDI_CALL)(ENTITY *); + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} DBUFFER; + +#define REQ_NAME 0x0100 +#define BOARD_NAME_LENGTH 9 +struct get_name_s { + word command; /* command = 0x0100 */ + byte name[BOARD_NAME_LENGTH]; +}; + +#define REQ_REMOVE 0x0000 /* pointer to word which is 0 */ +#define REQ_SERIAL 0x0200 +struct get_serial_s { + word command; /* command = 0x0200 */ + dword serial; /* serial number */ +}; + +#define REQ_POSTCALL 0x0300 +struct postcall_s { + word command; /* command = 0x0300 */ + word dummy; /* not used */ + IDI_CALL callback; /* routine adress to call back */ + ENTITY *contxt; /* ptr to entity to use */ +}; + +#define REQ_XLOG 0x0400 /* structure is card dependent/defined locally */ + +struct buffers_s { + word PLength; + byte *P; +}; + +struct entity_s { + byte Req; /* pending request */ + byte Rc; /* return code received */ + byte Ind; /* indication received */ + byte ReqCh; /* channel of current Req */ + byte RcCh; /* channel of current Rc */ + byte IndCh; /* channel of current Ind */ + byte Id; /* ID used by this entity */ + byte GlobalId; /* reserved field */ + byte XNum; /* number of X-buffers */ + byte RNum; /* number of R-buffers */ + BUFFERS *X; /* pointer to X-buffer list */ + BUFFERS *R; /* pointer to R-buffer list */ + word RLength; /* length of current R-data */ + DBUFFER *RBuffer; /* buffer of current R-data */ + byte RNR; /* receive not ready flag */ + byte complete; /* receive complete status */ + IDI_CALL callback; + + word user[2]; + + /* fields used by the driver internally */ + byte No; /* entity number */ + byte reserved2; /* reserved field */ + byte More; /* R/X More flags */ + byte MInd; /* MDATA coding for this ID */ + byte XCurrent; /* current transmit buffer */ + byte RCurrent; /* current receive buffer */ + word XOffset; /* offset in x-buffer */ + word ROffset; /* offset in r-buffer */ +}; + +typedef struct { + byte type; + byte channels; + word features; + dword serial; + IDI_CALL request; +} DESCRIPTOR; + +extern void EtdM_DIDD_Read(DESCRIPTOR *, int *); + + /* descriptor type field coding */ +#define IDI_ADAPTER_S 1 +#define IDI_ADAPTER_PR 2 +#define IDI_ADAPTER_DIVA 3 +#define IDI_ADAPTER_MAESTRA 4 +#define IDI_ADAPTER_MAESTRAQ 5 +#define IDI_ADAPTER_MAESTRAP 6 +#define IDI_VADAPTER 0x40 +#define IDI_DRIVER 0x80 +#define IDI_DIMAINT 0xff + +/* feature bit mask values */ + +#define DI_VOICE 0x0 /* obsolete define */ +#define DI_FAX3 0x1 +#define DI_MODEM 0x2 +#define DI_POST 0x4 +#define DI_V110 0x8 +#define DI_V120 0x10 +#define DI_POTS 0x20 +#define DI_CODEC 0x40 +#define DI_MANAGE 0x80 +#define DI_V_42 0x0100 +#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */ + +#endif /* IDI_H */ diff --git a/drivers/isdn/eicon/kprintf.c b/drivers/isdn/eicon/kprintf.c new file mode 100644 index 000000000..3282b7fc5 --- /dev/null +++ b/drivers/isdn/eicon/kprintf.c @@ -0,0 +1,538 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.3 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Source file for kernel interface to kernel log facility + */ + + +#include "sys.h" +#include <stdarg.h> +#undef MAX +#undef MIN + +#include <sys/types.h> +#include <sys/param.h> + +#include "divas.h" +#include "divalog.h" +#include "uxio.h" + +/* + * Implementation of printf and sprintf for kernel + */ + +#define MAX_BUFF (80) /* limit size of temporary buffers */ + +#define WRITE_CHAR(BUFFER, SIZE, C) \ + if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C) + + +/* + * convert a number to decimal ASCII + */ + +static +void do_decimal( char *temp, + int temp_len, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i < temp_len; i++) + { + temp[i] = (char) ((value % 10) + (int) '0'); + value /= 10; + } + + for (i = (temp_len - 1); temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to octal ASCII + */ + +static +void do_octal( char *temp, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i <= 11; i++) + { + temp[i] = (char) ((value & 07) + (int) '0'); + value >>= 3; + } + temp[11] &= '3'; + + for (i = 11; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to hex ASCII + */ + +static +void do_hex( char *temp, + unsigned int value, + char *s) + +{ + int i; + static + char *dec_to_hex = "0123456789abcdef"; + + temp[0] = '\0'; + + for (i = 1; i <= 8; i++) + { + temp[i] = dec_to_hex[value & 0x0f]; + value >>= 4; + } + + for (i = 8; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a buffer to ASCII HEX + */ + +static +void do_buffer( char *buffer, + int length, + char *s) + +{ + static + char hex_char [] = "0123456789abcdef"; + char *b = buffer; + int hex_byte; + int nybble; + + length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length; + + while (length) + { + hex_byte = (int) *b++; + nybble = (hex_byte >> 4) & 0xf; + *s++ = hex_char[nybble]; + nybble = hex_byte & 0xf; + *s++ = hex_char[nybble]; + *s++ = ' '; + length--; + } + *s = '\0'; + + return; +} + +/* + * Body of sprintf function: behaves just like standard sprintf, except we + * have an extra argument (buffer size) which we use to ensure we don't + * overflow + */ + +void Divas_vsprintf( char *buffer, + int size, + char *fmt, + va_list argptr) + +{ + char c; /* single character buffer */ + int i; /* handy scratch counter */ + int f; /* format character (after %) */ + char *str; /* pointer into string */ + char temp[20]; /* temp buffer used in printing numbers */ + char string[MAX_BUFF]; /* output from number conversion */ + int length; /* length of string "str" */ + char fill; /* fill character ' ' or '0' */ + boolean_t leftjust; /* TRUE if left justified, else right justified */ + int fmax, fmin; /* field specifiers % MIN . MAX s */ + int leading; /* number of leading/trailing fill characters */ + char sign; /* set to '-' for negative decimals */ + int number; /* numeric argument */ + + char *buff_ptr; /* pointer to user's buffer of hex data */ + int buff_len; /* length of hex data */ + + /* make sure we have somthing to write into */ + + if ((!buffer) || (size <= 0)) + { + return; + } + + while (TRUE) + { + /* echo characters until end or '%' encountered */ + + while ((c = *fmt++) != '%') + { + if (!c) + { + *buffer = '\0'; + return; + } + WRITE_CHAR(buffer, size, c); + } + + /* echo %% as % */ + + if (*fmt == '%') + { + WRITE_CHAR(buffer, size, *fmt); + continue; + } + + /* %- turns on left-justify */ + + if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE))) + { + fmt++; + } + + /* %0 turns on zero filling */ + + if (*fmt == '0') + { + fill = '0'; + } + else + { + fill = ' '; + } + + /* minium field width specifier for %d, u, x, c, s */ + + fmin = 0; + + if (*fmt == '*') + { + fmin = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmin = (fmin * 10) + (*fmt++ - '0'); + } + } + + /* maximum string width specifier for %s */ + + fmax = 0; + + if (*fmt == '.') + { + if (*(++fmt) == '*') + { + fmax = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmax = (fmax * 10) + (*fmt++ - '0'); + } + } + } + + /* skip over 'l' option (ints are assumed same size as longs) */ + + if (*fmt == 'l') + { + fmt++; + } + + /* get the format chacater */ + + if (!(f = *fmt++)) + { + WRITE_CHAR(buffer, size, '%'); + *buffer = '\0'; + return; + } + + sign = '\0'; /* sign == '-' for negative decimal */ + + str = string; + + switch (f) + { + case 'c' : + string[0] = (char) va_arg(argptr, int); + string[1] = '\0'; + fmax = 0; + fill = ' '; + break; + + case 's' : + str = va_arg(argptr, char *); + fill = ' '; + break; + + case 'D' : + case 'd' : + number = va_arg(argptr, int); + if (number < 0) + { + sign = '-'; + number = -number; + } + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'U' : + case 'u' : + number = va_arg(argptr, int); + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'O' : + case 'o' : + number = va_arg(argptr, int); + do_octal(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'X' : + case 'x' : + number = va_arg(argptr, int); + do_hex(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'H' : + case 'h' : + buff_ptr = va_arg(argptr, char *); + buff_len = va_arg(argptr, int); + do_buffer(buff_ptr, buff_len, str); + fmax = 0; + break; + + default : + WRITE_CHAR(buffer, size, ((char) f)); + break; + } + + /* get the length of the string */ + + length = 0; + while (str[length]) + { + length++; + } + + /* make sure we have fmax and fmin values that are O.K. */ + + if (fmin > DIM(string) || fmin < 0) + { + fmin = 0; + } + + if (fmax > DIM(string) || fmax < 0) + { + fmax = 0; + } + + /* figure out how many leading characters thare are */ + + leading = 0; + + if (fmax || fmin) + { + if (fmax) + { + if (length > fmax) + { + length = fmax; + } + } + + if (fmin) + { + leading = fmin - length; + } + + if (sign == '-') + { + leading--; + } + } + + /* output sign now, if fill is numeric */ + + if (sign == '-' && fill == '0') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* if right justified, output fill characters */ + + if (!leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + + /* output sign now, if fill is spaces */ + + if (sign == '-' && fill == ' ') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* now the actual value */ + + for (i = 0; i < length; i++) + { + WRITE_CHAR(buffer, size, str[i]); + } + + /* if left justified, fill out with the fill character */ + + if (leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + } +} + +/* + * sprintf for kernel + * + * call our vsprintf assuming user has a big buffer.... + */ + +void DivasSprintf(char *buffer, char *fmt, ...) + +{ + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + Divas_vsprintf(buffer, 1024, fmt, argptr); + + va_end(argptr); + + return; +} + +void DivasPrintf(char *fmt, ...) + +{ + klog_t log; /* log entry buffer */ + + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + /* clear log entry */ + + bzero((caddr_t) &log, sizeof(klog_t)); + + log.card = -1; + log.type = KLOG_TEXT_MSG; + + /* time stamp the entry */ + + log.time_stamp = UxTimeGet(); + + /* call vsprintf to format the user's information */ + + Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr); + + va_end(argptr); + + /* send to the log streams driver and return */ + + DivasLogAdd(&log, sizeof(klog_t)); + + return; +} diff --git a/drivers/isdn/eicon/lincfg.c b/drivers/isdn/eicon/lincfg.c new file mode 100644 index 000000000..3d2a8bfb1 --- /dev/null +++ b/drivers/isdn/eicon/lincfg.c @@ -0,0 +1,410 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.9 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 <linux/fs.h> +#undef N_DATA /* Because we have our own definition */ + +#include <asm/segment.h> +#include <asm/io.h> + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" +#include "pr_pc.h" + +#include "adapter.h" +#include "uxio.h" + +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/ioport.h> + +#define HW_ID_EICON_PCI 0x1133 +#define HW_ID_DIVA_SERVER_P 0xE014 +#define HW_ID_DIVA_SERVER_B_ST 0xE010 +#define HW_ID_DIVA_SERVER_B_U 0xE013 +#define HW_ID_DIVA_SERVER_Q 0xE012 + +struct file_operations Divas_fops; +int Divas_major; + +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable); +extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset); +extern int do_open(struct inode *, struct file *); +extern int do_release(struct inode *, struct file *); + +int FPGA_Done=0; + +int DivasCardsDiscover(void) +{ + word wNumCards = 0, wDeviceIndex = 0; + byte byBus, byFunc; + word wPCIConsultation, PCItmp; + dword j, i; + unsigned int PCIserial; + dia_card_t Card; + byte *b; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_Q, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + + dword dwRAM, dwDivasIOBase, dwCFG, dwCTL; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM); + dwRAM &= 0xFFC00000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG); + dwCFG &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL); + dwCTL &= 0xFFFFE000; + + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + /* Retrieve the serial number */ + + pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC); + + for (j=0, PCItmp=0; j<10000 && !PCItmp; j++) + { + pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp); + PCItmp &= 0x8000; // extract done flag + } + + pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial); + + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000); + Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100); + Card.io_base=dwDivasIOBase; + + Card.irq = byIRQ; + + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q; + Card.bus_type = DIA_BUS_TYPE_PCI; + + FPGA_Done = 0; + + /* Create four virtual card structures as we want to treat + the 4Bri card as 4 Bri cards*/ + for(i=0;i<4;i++) + { + + b=Card.memory[DIVAS_RAM_MEMORY]; + b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1); + DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET)); + Card.memory[DIVAS_RAM_MEMORY]=b; + + b = Card.memory[DIVAS_RAM_MEMORY]; + b += MQ_SM_OFFSET; + Card.memory[DIVAS_SHARED_MEMORY] = b; + + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + + + /* Fill in Name */ + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'Q'; + Card.name[6] = '0' + i; + Card.name[7] = '\0'; + + Card.serial = PCIserial; + + Card.card_id = wNumCards; + + if (DivasCardNew(&Card) != 0) + { + // Force for loop to terminate + i = 4; + continue; + } + wNumCards++; + + }//for + } + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_ST, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_U, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_P, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwRAM, dwREG, dwCFG; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM); + dwRAM &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG); + dwREG &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG); + dwCFG &= 0xFFFFF000; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000); + Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000); + Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET; + +/* pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFFFc; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF80; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); +*/ + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; +/* Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase;*/ + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'P'; + Card.name[6] = '\0'; + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + + printk(KERN_INFO "Divas: %d cards detected\n", wNumCards); + + if(wNumCards == 0) + { + return -1; + } + + Divas_fops.ioctl = do_ioctl; + Divas_fops.poll = do_poll; + Divas_fops.read = do_read; + Divas_fops.open = do_open; + Divas_fops.release = do_release; + + Divas_major = register_chrdev(0, "Divas", &Divas_fops); + + if (Divas_major < 0) + { + printk(KERN_WARNING "Divas: Unable to register character driver\n"); + return -1; + } + + return 0; +} + +/* Error return -1 */ +int DivasConfigGet(dia_card_t *card) +{ + /* Retrieve Config from O/S? Not in Linux */ + return 0; +} + +dia_config_t *DivasConfig(card_t *card, dia_config_t *config) +{ + /* If config retrieved from OS then copy the data into a dia_config_t structure here + and return the pointer here. If the config 'came from above' then just + + return config; + */ + + return config; +} + diff --git a/drivers/isdn/eicon/linchr.c b/drivers/isdn/eicon/linchr.c new file mode 100644 index 000000000..782429523 --- /dev/null +++ b/drivers/isdn/eicon/linchr.c @@ -0,0 +1,274 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.12 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 <linux/kernel.h> +#include <linux/poll.h> +#include <linux/fs.h> +#include <linux/malloc.h> + +#undef N_DATA + +#include "adapter.h" +#include "divas.h" +#include "divalog.h" + +extern int DivasCardNext; +void UxPause(long ms); +void bcopy(void *pSource, void *pDest, dword dwLength); +int DivasGetMem(mem_block_t *); + +#define DIA_IOCTL_UNLOCK 12 +void UnlockDivas(void); + +int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg) +{ + dia_load_t *pDivaLoad; + dia_start_t *pDivaStart; + dia_config_t *pDivaConfig; + dia_log_t *pDivaLog; + byte *pUserCards, card_i; + word wCardNum; + mem_block_t *mem_block; + + switch (command) + { + case DIA_IOCTL_CONFIG: + pDivaConfig = (dia_config_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t))) + { + DivasCardConfig(pDivaConfig); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_DETECT: + pUserCards = (byte *) arg; + + if (!verify_area(VERIFY_WRITE, pUserCards, 20)) + { + put_user(DivasCardNext, pUserCards++); + + for (card_i=1; card_i < 20; card_i++) + { + put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++); + } + } + else + { + printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_START: + pDivaStart = (dia_start_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t))) + { + return DivasCardStart(pDivaStart->card_id); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n"); + return -1; + } + + + case DIA_IOCTL_FLAVOUR: + return 0; + + case DIA_IOCTL_LOAD: + pDivaLoad = (dia_load_t *) arg; + if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length)) + { + if (DivasCardLoad(pDivaLoad)) + { + printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n"); + return -EINVAL; + } + } + else + { + printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n"); + return -EINVAL; + } + return 0; + + case DIA_IOCTL_LOG: + pDivaLog = (dia_log_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t))) + { + DivasLog(pDivaLog); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_XLOG_REQ: + + if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word))) + { + wCardNum = * (word *) arg; + DivasXlogReq(wCardNum); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_NUM: + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) + { + * (int *) arg = DivasCardNext; + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_LIST: + DPRINTF(("divas: DIA_IOCTL_GET_LIST")); + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t))) + { + DivasGetList((dia_card_list_t *)arg); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_MEM: + mem_block = (mem_block_t *) arg; + + if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t))) + { + DivasGetMem(mem_block); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_UNLOCK: + UnlockDivas(); + return 0; + + default: + printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command); + return -EINVAL; + } + + return -EINVAL; +} + +unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable) +{ + word wMask = 0; + + if (!DivasLogFifoEmpty()) + { + wMask |= POLLIN | POLLRDNORM; + } + + return wMask; +} + +ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset) +{ + klog_t *pClientLogBuffer = (klog_t *) pUserBuffer; + klog_t *pHeadItem; + + if (BufferSize < sizeof(klog_t)) + { + printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n", + BufferSize, sizeof(klog_t)); + return 0; + } + + pHeadItem = (klog_t *) DivasLogFifoRead(); + + if (pHeadItem) + { + bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t)); + kfree(pHeadItem); + return sizeof(klog_t); + } + + return 0; +} +int private_usage_count; +extern void mod_inc_use_count(void); +extern void mod_dec_use_count(void); + +int do_open(struct inode *pInode, struct file *pFile) +{ +#if defined(MODULE) + mod_inc_use_count(); + private_usage_count++; +#endif + return 0; +} + +int do_release(struct inode *pInode, struct file *pFile) +{ +#if defined(MODULE) + mod_dec_use_count(); + private_usage_count--; +#endif + return 0; +} + +void UnlockDivas(void) +{ + while (private_usage_count > 0) + { + private_usage_count--; +#if defined(MODULE) + mod_dec_use_count(); +#endif + } +} diff --git a/drivers/isdn/eicon/linio.c b/drivers/isdn/eicon/linio.c new file mode 100644 index 000000000..74c599069 --- /dev/null +++ b/drivers/isdn/eicon/linio.c @@ -0,0 +1,750 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.16 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#define N_DATA + +#include <asm/io.h> +#include <asm/system.h> +#include <linux/malloc.h> +#include <linux/pci.h> +#include <linux/delay.h> +#undef N_DATA + +#include "uxio.h" + +static +int log_on=0; + +int Divasdevflag = 0; + +//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED; + +static +ux_diva_card_t card_pool[MAX_CARDS]; + +void UxPause(long int ms) +{ + int timeout = jiffies + ((ms * HZ) / 1000); + + while (time_before(jiffies, timeout)); +} + +int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg) +{ + int i; + ux_diva_card_t *c; + + if (cfg->bus_type != DIA_BUS_TYPE_PCI) + { + DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type)); + return -1; + } + + for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++) + { + ; + } + + if (i == DIM(card_pool)) + { + DPRINTF(("divas hw: card_pool exhausted")); + return -1; + } + + c = *card = &card_pool[i]; + + switch (cfg->bus_type) + { + case DIA_BUS_TYPE_PCI: + c->bus_num = cfg->bus_num; + c->func_num = cfg->func_num; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->card_type = cfg->card_type; + c->mapped = NULL; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + c->pCONTROL = cfg->memory[DIVAS_CTL_MEMORY]; + + /* c->bus_type = DIA_BUS_TYPE_PCI; + c->bus_num = cfg->bus_num & 0x3f; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->int_priority = (int) cfg->int_priority; + c->card_type = cfg->card_type; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM)); + DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED)); + DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG)); + c->cm_key = cm_getbrdkey("Divas", cfg->card_id);*/ + break; + default: + break; + } + + c->in_use = TRUE; + + return 0; +} + +void UxCardHandleFree(ux_diva_card_t *card) +{ + card->in_use = FALSE; +} + + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 +void *UxCardMemAttach(ux_diva_card_t *card, int id) +{ + if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = card->pDEVICES; + return card->pDEVICES; + break; + case DIVAS_CFG_MEMORY: + card->mapped = card->pCONFIG; + return card->pCONFIG; + break; + default: + ASSERT(FALSE); + card->mapped = NULL; + return (void *) 0; + } + } + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + switch (id) + { + case PLX_IOBASE: + return (void *) card->reset_base; + break; + case DIVAS_IOBASE: + return (void *) card->io_base; + break; + default: + ASSERT(FALSE); + return 0; + } + } + + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = (void *) card->io_base; + return (void *) card->io_base; + break; + case DIVAS_CTL_MEMORY: + card->mapped = card->pCONTROL; + return card->pCONTROL; + break; + default: + // ASSERT(FALSE); + DPRINTF(("divas: Trying to attach to mem %d", id)); + card->mapped = NULL; + return (void *) 0; + } + } else + DPRINTF(("divas: Tried to attach to unknown card")); + + /* Unknown card type */ + return NULL; +} + +void UxCardMemDetach(ux_diva_card_t *card, void *address) +{ + return; // Just a place holder. No un-mapping done. +} + +void UxCardLog(int turn_on) +{ + log_on = turn_on; +} + +/* + * Control Register I/O Routines to be performed on Attached I/O ports + */ + +void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outb(the_byte, base); +} + +void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outw(the_word, base); +} + +void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outl(the_dword, base); +} + +byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inb(base); +} + +word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inw(base); +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address) +{ + byte b; + volatile byte* t = (byte*)address; + + b = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a)); + } + + return(b); +} + +word UxCardMemInW(ux_diva_card_t *card, void *address) +{ + word w; + volatile word* t = (word*)address; + + w = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a)); + } + + return (w); +} + +dword UxCardMemInD(ux_diva_card_t *card, void *address) +{ + dword dw; + volatile dword* t = (dword*)address; + + dw = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a)); + } + + return (dw); +} + +void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + volatile byte *pSource = address; + byte *pDest = buffer; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data) +{ + volatile byte* t = (byte*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a)); + } + + *t = data; + + return; +} + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data) +{ + volatile word* t = (word*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a)); + } + + *t = data; + return; +} + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data) +{ + volatile dword* t = (dword*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a)); + } + + *t = data; + return; +} + +void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + byte *pSource = buffer; + byte *pDest = address; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + byte the_byte; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + + the_byte = inb(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)", + the_byte & 0xff, address)); + } + + return the_byte; +} + +word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + word the_word; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_word = inw(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)", + the_word & 0xffff, address)); + } + + return the_word; +} + +dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + dword the_dword; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_dword = inl(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)", + the_dword, address)); + } + + return the_dword; +} + +void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = address; + byte *pDest = buffer; + + if ((word) (dword) address & 0x1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + *pDest = (byte) inb(card->io_base); + pDest++; + pSource++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +/* Output */ + +void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)", + data & 0xff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outb((byte) data & 0xFF, card->io_base); + + return; +} + +void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)", + data & 0xffff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outw((word) data & 0xFFFF, card->io_base); + + return; +} + +void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outl((dword) data & 0xFFFFFFFF, card->io_base); + + return; +} + +void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = buffer; + byte *pDest = address; + + if ((word) (dword) address & 1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outb(*pSource, card->io_base); + pSource++; + pDest++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +void Divasintr(int arg, void *unused, struct pt_regs *unused_regs) +{ + int i; + card_t *card = NULL; + ux_diva_card_t *ux_ref = NULL; + + for (i = 0; i < DivasCardNext; i++) + { + + if (arg == DivasCards[i].cfg.irq) + { + card = &DivasCards[i]; + ux_ref = card->hw; + + if ((ux_ref) && (card->is_live)) + { + (*ux_ref->user_isr)(ux_ref->user_isr_arg); + } + else + { + DPRINTF(("divas: ISR couldn't locate card")); + } + } + } + + return; +} + + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg) +{ + int result; + + card->user_isr = isr_fn; + card->user_isr_arg = isr_arg; + + result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg); + + return result; +} + +void UxIsrRemove(ux_diva_card_t *card, void *dev_id) +{ + free_irq(card->irq, card->user_isr_arg); +} + +void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value); + break; + case sizeof(word): + pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value); + break; + case sizeof(dword): + pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n"); + } +} + +void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value); + break; + case sizeof(word): + pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value); + break; + case sizeof(dword): + pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n"); + } +} + +void *UxAlloc(unsigned int size) +{ + void *m; + + m = kmalloc(size, GFP_ATOMIC); + + return m; +} + +void UxFree(void *ptr) +{ + kfree(ptr); +} + +int UxCardLock(ux_diva_card_t *card) +{ + unsigned long flags; + + //spin_lock_irqsave(&diva_lock, flags); + + save_flags(flags); + cli(); + return flags; + +} + +void UxCardUnlock(ux_diva_card_t *card, int ipl) +{ + //spin_unlock_irqrestore(&diva_lock, ipl); + + restore_flags(ipl); + +} + +dword UxTimeGet(void) +{ + return jiffies; +} + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p += 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} + +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p -= 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} diff --git a/drivers/isdn/eicon/linsys.c b/drivers/isdn/eicon/linsys.c new file mode 100644 index 000000000..3f167ed7b --- /dev/null +++ b/drivers/isdn/eicon/linsys.c @@ -0,0 +1,170 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.10 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 <linux/sched.h> +#undef N_DATA +#include <linux/tqueue.h> + +#include <linux/smp.h> +struct pt_regs; +#include <linux/interrupt.h> +#include <linux/ioport.h> + +#include "sys.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +#ifdef MODULE +void bcopy(void *pSource, void *pDest, dword dwLength) +{ + memcpy(pDest, pSource, dwLength); +} +#endif + +void bzero(void *pDataArea, dword dwLength) +{ + memset(pDataArea, 0, dwLength); +} + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); +*/ + return 0; +} + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/ + + return 0; +} + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Need to set these platform dependent values after patching */ + + card->hw->reset_base = card->cfg.reset_base; + card->hw->io_base = card->cfg.io_base; + + request_region(card->hw->reset_base,0x80,"Divas"); + request_region(card->hw->io_base,0x20,"Divas"); + + + /* Same as for PRI */ + return DivasPRIInitPCI(card, cfg); +} + +/* ######################### Stubs of routines that are not done yet ################## */ +/*void DivasLogIdi(card_t *card, ENTITY *e, int request) +{ +} +*/ + +int DivasDpcSchedule(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +int DivasScheduleRequestDpc(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoRequestDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +void DivasLogAdd(void *buffer, int length) +{ + static + boolean_t overflow = FALSE; + static + boolean_t busy = FALSE; + + /* make sure we're not interrupting ourselves */ + + if (busy) + { + printk(KERN_DEBUG "Divas: Logging interrupting self !\n"); + return; + } + busy = TRUE; + + /* ignore call if daemon isn't running and we've reached limit */ + + if (DivasLogFifoFull()) + { + if (!overflow) + { + printk(KERN_DEBUG "Divas: Trace buffer full\n"); + overflow = TRUE; + } + busy = FALSE; + return; + } + + DivasLogFifoWrite(buffer, length); + + busy = FALSE; + return; +} + +/* #################################################################################### */ diff --git a/drivers/isdn/eicon/log.c b/drivers/isdn/eicon/log.c new file mode 100644 index 000000000..1d847f0a8 --- /dev/null +++ b/drivers/isdn/eicon/log.c @@ -0,0 +1,179 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Source file for diva log facility + */ + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +/*Counter to monitor number of messages */ +static int m_count; + +#define MAX_BUFFERED_MSGS (1000) + +/* Our Linked List Structure to hold message */ +typedef struct klog_link{ + klog_t klog; + struct klog_link *next; +}KNODE; + +/* First & Last structures in list*/ +KNODE *head; +KNODE *tail; + +/* + * retrieve message from FIFO buffer + * returns NULL if buffer empty + * otherwise returns pointer to entry + */ + +char *DivasLogFifoRead(void) + +{ + KNODE *old_head; + + if(head==NULL) + { + /* Buffer Empty - No Messages */ + return NULL; + } + + m_count--; + /* Keep track of message to be read & increment to next message*/ + old_head = head; + head = head->next; + /*Return ptr to Msg */ + return((char *)old_head); +} + +/* + * write message into FIFO buffer + */ + +void DivasLogFifoWrite(char *entry, int length) + +{ + KNODE *new_klog; + + if(head == NULL) + { + /* No Entries in Log */ + tail=NULL; + m_count=0; + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Set head & tail to point to the new Msg Struct */ + head=tail=new_klog; + tail->next=NULL; + } + else + { + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Let last Msg Struct point to new Msg Struct & inc tail */ + tail->next=new_klog; + tail=new_klog; + tail->next=NULL; + } + + if (length > sizeof(klog_t)) + { + length = sizeof(klog_t); + } + + bcopy(entry,&tail->klog,length); + + return; +} + +/* + * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE + */ +int DivasLogFifoEmpty(void) +{ + return (m_count == 0); +} + +/* + *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE + */ +int DivasLogFifoFull(void) +{ + return (m_count == MAX_BUFFERED_MSGS); +} + +/* + * generate an IDI log entry + */ + +void DivasLogIdi(card_t *card, ENTITY *e, int request) + +{ + klog_t klog; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = UxTimeGet(); + + klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ? + sizeof(klog.buffer) : sizeof(ENTITY); + + klog.card = (int) (card - DivasCards); + + klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK; + klog.code = 0; + bcopy(e, klog.buffer, klog.length); + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} diff --git a/drivers/isdn/eicon/md5sums.asc b/drivers/isdn/eicon/md5sums.asc new file mode 100644 index 000000000..aa1cd9065 --- /dev/null +++ b/drivers/isdn/eicon/md5sums.asc @@ -0,0 +1,16 @@ +# These are valid md5sums to detect modifications +# in eicon driver files provided by Eicon Technology. +# For changes and modifications in these files please +# read ../../../Documentation/isdn/README.eicon +# +9b0e381d4558af3a6eba66843e1ee5d9 common.c +dbb92cba52db31ff8325a252b3f595c3 idi.c +15687687ef82f099966ed42772001cd3 bri.c +c3e3b720c3351b66635bd548195e29e8 pri.c +b0a6d2ab49bcfcfd1825860f178a84b4 log.c +673746176316b72271a09c0a27287a01 xlog.c +07e1bbabdb4d69880db196ef31bfb241 kprintf.c +b60b40ad630f26b7923369df95b4d1b9 fpga.c +5013ecca0a38a8fcc4a61642754f2076 fourbri.c +1501ae468a0c5eaab1e60720fa723a67 fcheck.c +# end of md5sums diff --git a/drivers/isdn/eicon/pc.h b/drivers/isdn/eicon/pc.h new file mode 100644 index 000000000..412a61faa --- /dev/null +++ b/drivers/isdn/eicon/pc.h @@ -0,0 +1,320 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#ifndef PC_H_INCLUDED +#define PC_H_INCLUDED + + +#define byte unsigned char +#define word unsigned short +#define dword unsigned long +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/*------------------------------------------------------------------*/ +/* buffer definition */ +/*------------------------------------------------------------------*/ + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} PBUFFER; + +/*------------------------------------------------------------------*/ +/* dual port ram structure */ +/*------------------------------------------------------------------*/ + +struct dual +{ + byte Req; /* request register */ + byte ReqId; /* request task/entity identification */ + byte Rc; /* return code register */ + byte RcId; /* return code task/entity identification */ + byte Ind; /* Indication register */ + byte IndId; /* Indication task/entity identification */ + byte IMask; /* Interrupt Mask Flag */ + byte RNR; /* Receiver Not Ready (set by PC) */ + byte XLock; /* XBuffer locked Flag */ + byte Int; /* ISDN-S interrupt */ + byte ReqCh; /* Channel field for layer-3 Requests */ + byte RcCh; /* Channel field for layer-3 Returncodes */ + byte IndCh; /* Channel field for layer-3 Indications */ + byte MInd; /* more data indication field */ + word MLength; /* more data total packet length */ + byte ReadyInt; /* request field for ready interrupt */ + byte SWReg; /* Software register for special purposes */ + byte Reserved[11]; /* reserved space */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-S adapter Signature (GD) */ + PBUFFER XBuffer; /* Transmit Buffer */ + PBUFFER RBuffer; /* Receive Buffer */ +}; + +/*------------------------------------------------------------------*/ +/* SWReg Values (0 means no command) */ +/*------------------------------------------------------------------*/ +#define SWREG_DIE_WITH_LEDON 0x01 +#define SWREG_HALT_CPU 0x02 /* Push CPU into a while(1) loop */ + +/*------------------------------------------------------------------*/ +/* Id Fields Coding */ +/*------------------------------------------------------------------*/ + +#define ID_MASK 0xe0 /* Mask for the ID field */ +#define GL_ERR_ID 0x1f /* ID for error reporting on global requests*/ + +#define DSIG_ID 0x00 /* ID for D-channel signaling */ +#define NL_ID 0x20 /* ID for network-layer access (B or D) */ +#define BLLC_ID 0x60 /* ID for B-channel link level access */ +#define TASK_ID 0x80 /* ID for dynamic user tasks */ +#define TIMER_ID 0xa0 /* ID for timer task */ +#define TEL_ID 0xc0 /* ID for telephone support */ +#define MAN_ID 0xe0 /* ID for management */ + +/*------------------------------------------------------------------*/ +/* ASSIGN and REMOVE requests are the same for all entities */ +/*------------------------------------------------------------------*/ + +#define ASSIGN 0x01 +#define UREMOVE 0xfe /* without returncode */ +#define REMOVE 0xff + +/*------------------------------------------------------------------*/ +/* Timer Interrupt Task Interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TIM 0x01 +#define REMOVE_TIM 0xff + +/*------------------------------------------------------------------*/ +/* dynamic user task interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TSK 0x01 +#define REMOVE_TSK 0xff + +#define LOAD 0xf0 +#define RELOCATE 0xf1 +#define START 0xf2 +#define LOAD2 0xf3 +#define RELOCATE2 0xf4 + +/*------------------------------------------------------------------*/ +/* dynamic user task messages */ +/*------------------------------------------------------------------*/ + +#define TSK_B2 0x0000 +#define TSK_WAKEUP 0x2000 +#define TSK_TIMER 0x4000 +#define TSK_TSK 0x6000 +#define TSK_PC 0xe000 + +/*------------------------------------------------------------------*/ +/* LL management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_LL 1 /* assign logical link */ +#define REMOVE_LL 0xff /* remove logical link */ + +/*------------------------------------------------------------------*/ +/* LL service primitives */ +/*------------------------------------------------------------------*/ + +#define LL_UDATA 1 /* link unit data request/indication */ +#define LL_ESTABLISH 2 /* link establish request/indication */ +#define LL_RELEASE 3 /* link release request/indication */ +#define LL_DATA 4 /* data request/indication */ +#define LL_LOCAL 5 /* switch to local operation (COM only) */ +#define LL_DATA_PEND 5 /* data pending indication (SDLC SHM only) */ +#define LL_REMOTE 6 /* switch to remote operation (COM only) */ +#define LL_TEST 8 /* link test request */ +#define LL_MDATA 9 /* more data request/indication */ +#define LL_BUDATA 10 /* broadcast unit data request/indication */ +#define LL_XID 12 /* XID command request/indication */ +#define LL_XID_R 13 /* XID response request/indication */ + +/*------------------------------------------------------------------*/ +/* NL service primitives */ +/*------------------------------------------------------------------*/ + +#define N_MDATA 1 /* more data to come REQ/IND */ +#define N_CONNECT 2 /* OSI N-CONNECT REQ/IND */ +#define N_CONNECT_ACK 3 /* OSI N-CONNECT CON/RES */ +#define N_DISC 4 /* OSI N-DISC REQ/IND */ +#define N_DISC_ACK 5 /* OSI N-DISC CON/RES */ +#define N_RESET 6 /* OSI N-RESET REQ/IND */ +#define N_RESET_ACK 7 /* OSI N-RESET CON/RES */ +#define N_DATA 8 /* OSI N-DATA REQ/IND */ +#define N_EDATA 9 /* OSI N-EXPEDITED DATA REQ/IND */ +#define N_UDATA 10 /* OSI D-UNIT-DATA REQ/IND */ +#define N_BDATA 11 /* BROADCAST-DATA REQ/IND */ +#define N_DATA_ACK 12 /* data ack ind for D-bit procedure */ +#define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */ + +#define N_Q_BIT 0x10 /* Q-bit for req/ind */ +#define N_M_BIT 0x20 /* M-bit for req/ind */ +#define N_D_BIT 0x40 /* D-bit for req/ind */ + +/*------------------------------------------------------------------*/ +/* Signaling management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_SIG 1 /* assign signaling task */ +#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */ +#define REMOVE_SIG 0xff /* remove signaling task */ + +/*------------------------------------------------------------------*/ +/* Signaling service primitives */ +/*------------------------------------------------------------------*/ + +#define CALL_REQ 1 /* call request */ +#define CALL_CON 1 /* call confirmation */ +#define CALL_IND 2 /* incoming call connected */ +#define LISTEN_REQ 2 /* listen request */ +#define HANGUP 3 /* hangup request/indication */ +#define SUSPEND 4 /* call suspend request/confirm */ +#define RESUME 5 /* call resume request/confirm */ +#define SUSPEND_REJ 6 /* suspend rejected indication */ +#define USER_DATA 8 /* user data for user to user signaling */ +#define CONGESTION 9 /* network congestion indication */ +#define INDICATE_REQ 10 /* request to indicate an incoming call */ +#define INDICATE_IND 10 /* indicates that there is an incoming call */ +#define CALL_RES 11 /* accept an incoming call */ +#define CALL_ALERT 12 /* send ALERT for incoming call */ +#define INFO_REQ 13 /* INFO request */ +#define INFO_IND 13 /* INFO indication */ +#define REJECT 14 /* reject an incoming call */ +#define RESOURCES 15 /* reserve B-Channel hardware resources */ +#define TEL_CTRL 16 /* Telephone control request/indication */ +#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ +#define FAC_REG_REQ 18 /* connection idependent fac registration */ +#define FAC_REG_ACK 19 /* fac registration acknowledge */ +#define FAC_REG_REJ 20 /* fac registration reject */ +#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ +#define FACILITY_REQ 22 /* send a Facility Message type */ +#define FACILITY_IND 22 /* Facility Message type indication */ +#define SIG_CTRL 29 /* Control for signalling hardware */ +#define DSP_CTRL 30 /* Control for DSPs */ +#define LAW_REQ 31 /* Law config request for (returns info_i) */ + + +/*------------------------------------------------------------------*/ +/* management service primitives */ +/*------------------------------------------------------------------*/ + +#define MAN_READ 2 +#define MAN_WRITE 3 +#define MAN_EXECUTE 4 +#define MAN_EVENT_ON 5 +#define MAN_EVENT_OFF 6 +#define MAN_LOCK 7 +#define MAN_UNLOCK 8 + +#define MAN_INFO_IND 2 +#define MAN_EVENT_IND 3 +#define MAN_TRACE_IND 4 + +#define MAN_ESC 0x80 + +/*------------------------------------------------------------------*/ +/* return code coding */ +/*------------------------------------------------------------------*/ + +#define UNKNOWN_COMMAND 0x01 /* unknown command */ +#define WRONG_COMMAND 0x02 /* wrong command */ +#define WRONG_ID 0x03 /* unknown task/entity id */ +#define WRONG_CH 0x04 /* wrong task/entity id */ +#define UNKNOWN_IE 0x05 /* unknown information el. */ +#define WRONG_IE 0x06 /* wrong information el. */ +#define OUT_OF_RESOURCES 0x07 /* ISDN-S card out of res. */ +#define ADAPTER_DEAD 0x08 /* ISDN card CPU halted */ +#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ +#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ +#define ASSIGN_OK 0xef /* ASSIGN OK */ +#define OK_FC 0xfc /* Flow-Control RC */ +#define READY_INT 0xfd /* Ready interrupt */ +#define TIMER_INT 0xfe /* timer interrupt */ +#define OK 0xff /* command accepted */ + +/*------------------------------------------------------------------*/ +/* information elements */ +/*------------------------------------------------------------------*/ + +#define SHIFT 0x90 /* codeset shift */ +#define MORE 0xa0 /* more data */ +#define CL 0xb0 /* congestion level */ + + /* codeset 0 */ + +#define BC 0x04 /* Bearer Capability */ +#define CAU 0x08 /* cause */ +#define CAD 0x0c /* Connected address */ +#define CAI 0x10 /* call identity */ +#define CHI 0x18 /* channel identification */ +#define LLI 0x19 /* logical link id */ +#define CHA 0x1a /* charge advice */ +#define DT 0x29 /* ETSI date/time */ +#define KEY 0x2c /* keypad information element */ +#define FTY 0x1c /* facility information element */ +#define DSP 0x28 /* display */ +#define OAD 0x6c /* origination address */ +#define OSA 0x6d /* origination sub-address */ +#define CPN 0x70 /* called party number */ +#define DSA 0x71 /* destination sub-address */ +#define RDX 0x73 /* redirected number extended */ +#define RDN 0x74 /* redirected number */ +#define LLC 0x7c /* low layer compatibility */ +#define HLC 0x7d /* high layer compatibility */ +#define UUI 0x7e /* user user information */ +#define ESC 0x7f /* escape extension */ + +#define DLC 0x20 /* data link layer configuration */ +#define NLC 0x21 /* network layer configuration */ + + /* codeset 6 */ + +#define SIN 0x01 /* service indicator */ +#define CIF 0x02 /* charging information */ +#define DATE 0x03 /* date */ +#define CPS 0x07 /* called party status */ + +/*------------------------------------------------------------------*/ +/* TEL_CTRL contents */ +/*------------------------------------------------------------------*/ + +#define RING_ON 0x01 +#define RING_OFF 0x02 +#define HANDS_FREE_ON 0x03 +#define HANDS_FREE_OFF 0x04 +#define ON_HOOK 0x80 +#define OFF_HOOK 0x90 + +#endif diff --git a/drivers/isdn/eicon/pc_maint.h b/drivers/isdn/eicon/pc_maint.h new file mode 100644 index 000000000..e6e902f00 --- /dev/null +++ b/drivers/isdn/eicon/pc_maint.h @@ -0,0 +1,165 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#ifndef PC_MAINT_H +#define PC_MAINT_H + +#if !defined(MIPS_SCOM) +#define BUFFER_SZ 48 +#define MAINT_OFFS 0x380 +#else +#define BUFFER_SZ 128 +#define MAINT_OFFS 0xff00 +#endif + +#define MIPS_BUFFER_SZ 128 +#define MIPS_MAINT_OFFS 0xff00 + +#define DO_LOG 1 +#define MEMR 2 +#define MEMW 3 +#define IOR 4 +#define IOW 5 +#define B1TEST 6 +#define B2TEST 7 +#define BTESTOFF 8 +#define DSIG_STATS 9 +#define B_CH_STATS 10 +#define D_CH_STATS 11 +#define BL1_STATS 12 +#define BL1_STATS_C 13 +#define GET_VERSION 14 +#define OS_STATS 15 +#define XLOG_SET_MASK 16 +#define XLOG_GET_MASK 17 +#define DSP_READ 20 +#define DSP_WRITE 21 + +#define OK 0xff +#define MORE_EVENTS 0xfe +#define NO_EVENT 1 + +struct DSigStruc +{ + byte Id; + byte uX; + byte listen; + byte active; + byte sin[3]; + byte bc[6]; + byte llc[6]; + byte hlc[6]; + byte oad[20]; +}; + +struct BL1Struc { + dword cx_b1; + dword cx_b2; + dword cr_b1; + dword cr_b2; + dword px_b1; + dword px_b2; + dword pr_b1; + dword pr_b2; + word er_b1; + word er_b2; +}; + +struct L2Struc { + dword XTotal; + dword RTotal; + word XError; + word RError; +}; + +struct OSStruc { + word free_n; +}; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[BUFFER_SZ]; + word w[BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[BUFFER_SZ>>2]; +} BUFFER; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[MIPS_BUFFER_SZ]; + word w[MIPS_BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[MIPS_BUFFER_SZ>>2]; +} MIPS_BUFFER; + + +#if !defined(MIPS_SCOM) +struct pc_maint +{ + byte req; + byte rc; + byte *mem; /*far*/ + short length; + word port; + byte fill[6]; + BUFFER data; +}; +#else +struct pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte far *mem; + short length; + word port; + byte fill[4]; /* data at offset 16 */ + BUFFER data; +}; +#endif + +struct mi_pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte *mem; /*far*/ + short length; + word port; + byte fill[4]; /* data at offset 16 */ + MIPS_BUFFER data; +}; + +#endif /* PC_MAINT_H */ diff --git a/drivers/isdn/eicon/pr_pc.h b/drivers/isdn/eicon/pr_pc.h new file mode 100644 index 000000000..f01ad4499 --- /dev/null +++ b/drivers/isdn/eicon/pr_pc.h @@ -0,0 +1,86 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#if !defined(PR_PC_H) +#define PR_PC_H + +struct pr_ram { + word NextReq; /* pointer to next Req Buffer */ + word NextRc; /* pointer to next Rc Buffer */ + word NextInd; /* pointer to next Ind Buffer */ + byte ReqInput; /* number of Req Buffers sent */ + byte ReqOutput; /* number of Req Buffers returned */ + byte ReqReserved; /* number of Req Buffers reserved */ + byte Int; /* ISDN-P interrupt */ + byte XLock; /* Lock field for arbitration */ + byte RcOutput; /* number of Rc buffers received */ + byte IndOutput; /* number of Ind buffers received */ + byte IMask; /* Interrupt Mask Flag */ + byte Reserved1[2]; /* reserved field, do not use */ + byte ReadyInt; /* request field for ready interrupt */ + byte Reserved2[12]; /* reserved field, do not use */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-P initialized indication */ + byte B[1]; /* buffer space for Req,Ind and Rc */ +}; + +typedef struct { + word next; + byte Req; + byte ReqId; + byte ReqCh; + byte Reserved1; + word Reference; + byte Reserved[8]; + PBUFFER XBuffer; +} REQ; + +typedef struct { + word next; + byte Rc; + byte RcId; + byte RcCh; + byte Reserved1; + word Reference; + byte Reserved2[8]; +} RC; + +typedef struct { + word next; + byte Ind; + byte IndId; + byte IndCh; + byte MInd; + word MLength; + word Reference; + byte RNR; + byte Reserved; + dword Ack; + PBUFFER RBuffer; +} IND; + +#endif diff --git a/drivers/isdn/eicon/pri.c b/drivers/isdn/eicon/pri.c new file mode 100644 index 000000000..a6a63945e --- /dev/null +++ b/drivers/isdn/eicon/pri.c @@ -0,0 +1,533 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Diva Server PRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_RESET_REG 0x20 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xef00 /* value for PRI card */ + +#define MP_PROTOCOL_ADDR 0xA0011000 +#define MP_DSP_CODE_BASE 0xa03a0000 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg); +int pri_ISR (card_t* card); + +static int diva_server_reset(card_t *card) +{ + byte *reg; + diva_server_boot_t *boot = NULL; + dword live = 0; + int i = 0; + dword dwWait; + + DPRINTF(("divas: reset Diva Server PRI")); + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], DIVAS_RESET | + DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], 0x00); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemDetach(card->hw, reg); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, boot->reserved, 0); + + live = UxCardMemInD(card->hw, &boot->live); + + for (i=0; i<5; i++) + { + if (live != UxCardMemInD(card->hw, &boot->live)) + { + break; + } + UxPause(10); + } + + if (i == 5) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card is reset but CPU not running")); + return -1; + } + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card reset after %d ms", i * 10)); + + return 0; +} + +static int diva_server_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardLog(0); + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_reset_int(card_t *card) +{ + byte *cfg; + + cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL); + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0); + UxCardMemDetach(card->hw, cfg); + + return; +} + + +static int diva_server_test_int(card_t *card) +{ + int i; + byte *shared; + byte req_int; + + DPRINTF(("divas: test interrupt for Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardMemIn(card->hw, &shared[0x3FE]); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + UxCardMemIn(card->hw, &shared[0x3FE]); + + UxCardMemDetach(card->hw, shared); + + diva_server_reset_int(card); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + card->test_int_pend = TEST_INT_DIVAS; + + req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt)); + + req_int++; + + UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int); + + UxCardMemDetach(card->hw, shared); + + UxCardLog(0); + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + + if (card->test_int_pend) + { + + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_load(card_t *card, dia_load_t *load) +{ + diva_server_boot_t *boot; + int i, offset, length; + dword cmd = 0; + + DPRINTF(("divas: loading Diva Server PRI")); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + (((sizeof(dword) + + (sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT)) + + ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA))); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + sizeof(dword))); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE); + break; + + default: + DPRINTF(("divas: unknown code type")); + UxCardMemDetach(card->hw, boot); + return -1; + } + + UxCardLog(0); + offset = 0; + + do + { + length = (load->length - offset >= 400) ? 400 : load->length - offset; + + for (i=0; i<length; i++) + { + UxCardMemOut(card->hw, &boot->data[i], load->code[offset+i]); + } + + for (i=0; i<length; i++) + { + if (load->code[offset + i] != UxCardMemIn(card->hw, &boot->data[i])) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card code block verify failed")); + return -1; + } + } + + UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD); + + for (i=0; i<50000; i++) + { + cmd = UxCardMemInD(card->hw, &boot->cmd); + if (!cmd) + { + break; + } + /*UxPause(1);*/ + } + + if (cmd) + { + DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset)); + UxCardMemDetach(card->hw, boot); + return -1; + } + + offset += length; + + } while (offset < load->length); + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: DIVA Server card loaded")); + + return 0; +} + +static int diva_server_start(card_t *card, byte *channels) +{ + diva_server_boot_t *boot; + byte *ram; + int i; + dword signature = 0; + + DPRINTF(("divas: start Diva Server PRI")); + + card->is_live = FALSE; + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD); + + UxCardLog(0); + + for (i = 0; i < 300; i++) + { + signature = UxCardMemInD(card->hw, &boot->signature); + if ((signature >> 16) == DIVAS_SIGNATURE) + { + DPRINTF(("divas: started card after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if ((signature >> 16) != DIVAS_SIGNATURE) + { + UxCardMemDetach(card->hw, boot); + DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature)); + return -1; + } + + card->is_live = TRUE; + + ram = (byte *) boot; + ram += DIVAS_SHARED_OFFSET; + + *channels = UxCardMemIn(card->hw, &ram[0x3F6]); + card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]); + + UxCardMemDetach(card->hw, boot); + + if (diva_server_test_int(card)) + { + DPRINTF(("divas: interrupt test failed")); + return -1; + } + + DPRINTF(("divas: DIVA Server card started")); + + return 0; +} + +static +int diva_server_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise PRI specific entry points + */ + +int DivasPriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server PRI")); + + if (DivasPRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_reset; + card->card_load = diva_server_load; + card->card_config = diva_server_config; + card->card_start = diva_server_start; + card->reset_int = diva_server_reset_int; + card->card_mem_get = diva_server_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = pri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + + +int pri_ISR (card_t* card) +{ + int served = 0; + byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET]; + register unsigned long val = *isr; + + if (val & 0x80000000) /* our card had caused interrupt ??? */ + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + *isr = (unsigned long)~0x03E00000; /* Clear interrupt line */ + } + + UxCardMemDetach(card->hw, cfg); + + return (served != 0); +} + + diff --git a/drivers/isdn/eicon/sys.h b/drivers/isdn/eicon/sys.h new file mode 100644 index 000000000..0e636c547 --- /dev/null +++ b/drivers/isdn/eicon/sys.h @@ -0,0 +1,119 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Environment provided by system and miscellaneous definitions */ + +#if !defined(SYS_H) +#define SYS_H + +/* abreviations for unsigned types */ +typedef int boolean_t; + +typedef unsigned char byte; + +typedef unsigned long dword; +typedef unsigned short word; + +/* abreviations for volatile types */ + +typedef volatile byte vbyte; +typedef volatile word vword; +typedef volatile dword vdword; + +/* Booleans */ + +#if !defined(TRUE) +#define TRUE (1) +#define FALSE (0) +#endif + +/* NULL pointer */ + +#if !defined(NULL) +#define NULL ((void *) 0) +#endif + +/* MIN and MAX */ + +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/* Return the dimension of an array */ + +#if !defined(DIM) +#define DIM(array) (sizeof (array)/sizeof ((array)[0])) +#endif + +/* + * Return the number of milliseconds since last boot + */ + +extern dword UxTimeGet(void); + +extern void DivasSprintf(char *buffer, char *format, ...); +extern void DivasPrintf(char *format, ...); + +/* fatal errors, asserts and tracing */ + +void HwFatalErrorFrom(char *file, int line); +void HwFatalError(void); +/* void HwAssert(char *file, int line, char *condition); */ + +#include <linux/kernel.h> +#define _PRINTK printk + +#define _PRINTF DivasPrintf +void _PRINTF(char *format, ...); +#define PRINTF(arg_list) _PRINTF arg_list +#if defined DTRACE +# define DPRINTF(arg_list) _PRINTF arg_list +# define KDPRINTF(arg_list) _PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n"); +#else +# define DPRINTF(arg_list) (void)0 +# define KDPRINTF(arg_list) _PRINTK arg_list ; _PRINTK("\n"); +#endif + +#if !defined(ASSERT) +#if defined DEBUG || defined DBG +# define HwFatalError() HwFatalErrorFrom(__FILE__, __LINE__) +# define ASSERT(cond) \ + if (!(cond)) \ + { \ +/* HwAssert(__FILE__, __LINE__, #cond);*/ \ + } +#else +# define ASSERT(cond) ((void)0) +#endif +#endif /* !defined(ASSERT) */ + +#define TRACE (_PRINTF(__FILE__"@%d\n", __LINE__)) + +#endif /* SYS_H */ diff --git a/drivers/isdn/eicon/uxio.h b/drivers/isdn/eicon/uxio.h new file mode 100644 index 000000000..c15d93f96 --- /dev/null +++ b/drivers/isdn/eicon/uxio.h @@ -0,0 +1,220 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.6 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Interface to Unix specific code for performing card I/O + */ + +#if !defined(UXIO_H) +#define UXIO_H + +#include "sys.h" +#include "adapter.h" + + +struct pt_regs; + +/* user callback, returns zero if interrupt was from this card */ +typedef void isr_fn_t(void *); +struct ux_diva_card_s +{ + word in_use; + int io_base; + int reset_base; + int card_type; + byte *mapped; + int bus_num; + int func_num; + int slot; + int irq; + byte *pDRAM; + byte *pDEVICES; + byte *pCONFIG; + byte *pSHARED; + byte *pCONTROL; + word features; + void *user_isr_arg; + isr_fn_t *user_isr; +}; + +void bcopy(void *pSource, void *pDest, dword dwLength); +void bzero(void *pDataArea, dword dwLength); + + +/* + * Get a card handle to enable card to be accessed + */ + +int UxCardHandleGet( ux_diva_card_t **card, + dia_card_t *cfg); + +/* + * Free a card handle as no longer needed + */ + +void UxCardHandleFree(ux_diva_card_t *card); + +/* + * Lock and unlock access to a card + */ + +int UxCardLock(ux_diva_card_t *card); +void UxCardUnlock(ux_diva_card_t *card, int ipl); + +/* + * Set the mapping address for PCI cards + */ + +int UxCardAddrMappingSet(ux_diva_card_t *card, + int id, + void *address, + int size); + +/* + * Attach card to memory to enable it to be accessed + * Returns the mapped address + */ + +void *UxCardMemAttach(ux_diva_card_t *card, int id); + +/* + * map card out of memory after completion of access + */ + +void UxCardMemDetach(ux_diva_card_t *card, void *address); + +/* + * input functions for memory-mapped cards + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address); + +word UxCardMemInW(ux_diva_card_t *card, void *address); + +dword UxCardMemInD(ux_diva_card_t *card, void *address); + +void UxCardMemInBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * output functions for memory-mapped cards + */ + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data); + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data); + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data); + +void UxCardMemOutBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * input functions for I/O-mapped cards + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *, void *address); + +word UxCardIoInW(ux_diva_card_t *card, void *, void *address); + +dword UxCardIoInD(ux_diva_card_t *card, void *, void *address); + +void UxCardIoInBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * output functions for I/O-mapped cards + */ + +void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data); + +void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data); + +void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data); + +void UxCardIoOutBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * Get specified PCI config + */ + +void UxPciConfigRead(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* + * Set specified PCI config + */ + +void UxPciConfigWrite(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* allocate memory, returning NULL if none available */ + +void *UxAlloc(unsigned int size); + +void UxFree(void *); + +/* + * Pause for specified number of milli-seconds + */ + +void UxPause(long ms); + +/* + * Install an ISR for the specified card + */ + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg); + +/* + * Remove an ISR for the specified card + */ +void UxIsrRemove(ux_diva_card_t *card, void *); + +/* + * DEBUG function to turn logging ON or OFF + */ + +void UxCardLog(int turn_on); + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst); +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst); + +#endif /* of UXIO_H */ diff --git a/drivers/isdn/eicon/xlog.c b/drivers/isdn/eicon/xlog.c new file mode 100644 index 000000000..282662cfc --- /dev/null +++ b/drivers/isdn/eicon/xlog.c @@ -0,0 +1,183 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Unix Eicon active card driver + * XLOG related functions + */ + +#include "sys.h" +#include "idi.h" +#include "pc.h" +#include "pc_maint.h" +#include "divalog.h" + +#include "adapter.h" +#include "uxio.h" + +/* + * convert/copy XLOG info into a KLOG entry + */ + +static +void xlog_to_klog(byte *b, int size, int card_num) + +{ + typedef struct + { + word code; + word time_hi; + word time_lo; + word xcode; + byte data[2]; + } card_xlog_t; + + card_xlog_t *x; + + klog_t klog; + + x = (card_xlog_t *) b; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = (dword) x->time_hi; + klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo; + + klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size; + + klog.card = card_num; + if (x->code == 1) + { + klog.type = KLOG_XTXT_MSG; + klog.code = 0; + bcopy(&x->xcode, klog.buffer, klog.length); + } + else if (x->code == 2) + { + klog.type = KLOG_XLOG_MSG; + klog.code = x->xcode; + bcopy(&x->data, klog.buffer, klog.length); + } + else + { + char *c; int i; + klog.type = KLOG_TEXT_MSG; + klog.code = 0; + c = "divas: invalid xlog message code from card"; + i = 0; + while (*c) + { + klog.buffer[i] = *c; + c++; + i++; + } + klog.buffer[i] = *c; + } + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} + +/* + * send an XLOG request down to specified card + * if response available from previous request then read it + * if not then just send down new request, ready for next time + */ + +void DivasXlogReq(int card_num) + +{ + card_t *card; + ADAPTER *a; + + if ((card_num < 0) || (card_num > DivasCardNext)) + { + DPRINTF(("xlog: invalid card number")); + return; + } + + card = &DivasCards[card_num]; + + if (DivasXlogRetrieve(card)) + { + return; + } + + /* send down request for next time */ + + a = &card->a; + + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return; +} + +/* + * retrieve XLOG request from specified card + * returns non-zero if new request sent to card + */ + +int DivasXlogRetrieve(card_t *card) + +{ + ADAPTER *a; + struct mi_pc_maint pcm; + + a = &card->a; + + /* get status of last request */ + + pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1)); + + /* if nothing there from previous request, send down a new one */ + + if (pcm.rc == OK) + { + /* read in response */ + + a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm)); + + xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data), + (int) (card - DivasCards)); + } + + /* if any response received from card, re-send request */ + + if (pcm.rc) + { + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return 1; + } + + return 0; +} diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index 7bc340de9..071e3b1ca 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -31,6 +31,8 @@ HFC_OBJ := HFC_2BDS0 := JADE_OBJ := W6692_OBJ := +NETJ_OBJ := +ICC_OBJ := ifeq ($(CONFIG_HISAX_16_0),y) O_OBJS += teles0.o @@ -124,10 +126,17 @@ ifeq ($(CONFIG_HISAX_MIC),y) endif ifeq ($(CONFIG_HISAX_NETJET),y) - O_OBJS += netjet.o + O_OBJS += nj_s.o + NETJ_OBJ := netjet.o ISAC_OBJ := isac.o endif +ifeq ($(CONFIG_HISAX_NETJET_U),y) + O_OBJS += nj_u.o + NETJ_OBJ := netjet.o + ICC_OBJ := icc.o +endif + ifeq ($(CONFIG_HISAX_HFCS),y) O_OBJS += hfcscard.o HFC_2BDS0 := hfc_2bds0.o @@ -189,7 +198,7 @@ ifeq ($(ISAC_OBJ), isac.o) endif O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ) -O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) +O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) $(NETJ_OBJ) $(ICC_OBJ) OX_OBJS += config.o O_TARGET := @@ -208,10 +217,9 @@ include $(TOPDIR)/Rules.make MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ - elsa.c diva.c + elsa.c diva.c sedlbauer.c CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) cert.o: $(MD5FILES) md5sums.asc $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c - diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index dabb179b5..4302585dc 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.17 2000/06/26 08:59:12 keil Exp $ +/* $Id: avm_pci.c,v 1.18 2000/08/20 07:34:04 keil Exp $ * * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -17,13 +17,17 @@ #include <linux/interrupt.h> extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.15 $"; +static const char *avm_pci_rev = "$Revision: 1.18 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 -#define PCI_VENDOR_AVM 0x1244 -#define PCI_FRITZPCI_ID 0xa00 +#ifndef PCI_VENDOR_ID_AVM +#define PCI_VENDOR_ID_AVM 0x1244 +#endif +#ifndef PCI_DEVICE_ID_AVM_FRITZ +#define PCI_DEVICE_ID_AVM_FRITZ 0xa00 +#endif #define HDLC_FIFO 0x0 #define HDLC_STATUS 0x4 @@ -293,7 +297,15 @@ hdlc_empty_fifo(struct BCState *bcs, int count) if (cs->subtyp == AVM_FRITZ_PCI) { outl(idx, cs->hw.avm.cfg_reg + 4); while (cnt < count) { +#ifdef __powerpc__ +#ifdef CONFIG_APUS + *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#else + *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#endif /* CONFIG_APUS */ +#else *ptr++ = inl(cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -349,7 +361,15 @@ hdlc_fill_fifo(struct BCState *bcs) write_ctrl(bcs, 3); /* sets the correct index too */ if (cs->subtyp == AVM_FRITZ_PCI) { while (cnt<count) { +#ifdef __powerpc__ +#ifdef CONFIG_APUS + out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); +#else + out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); +#endif /* CONFIG_APUS */ +#else outl(*ptr++, cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -767,8 +787,8 @@ setup_avm_pcipnp(struct IsdnCard *card)) printk(KERN_ERR "FritzPCI: no PCI bus present\n"); return(0); } - if ((dev_avm = pci_find_device(PCI_VENDOR_AVM, - PCI_FRITZPCI_ID, dev_avm))) { + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_FRITZ, dev_avm))) { cs->irq = dev_avm->irq; if (!cs->irq) { printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); @@ -776,9 +796,9 @@ setup_avm_pcipnp(struct IsdnCard *card)) } if (pci_enable_device(dev_avm)) return(0); - cs->hw.avm.cfg_reg = pci_resource_start (dev_avm, 1); + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); if (!cs->hw.avm.cfg_reg) { - printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n"); + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); return(0); } cs->subtyp = AVM_FRITZ_PCI; diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index 17e3a19a7..75729c282 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -18,12 +18,12 @@ #include "hscx.h" #include "jade.h" #include "isdnl1.h" -#include "bkm_ax.h" #include <linux/pci.h> +#include "bkm_ax.h" extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.9 $"; +const char *bkm_a4t_revision = "$Revision: 1.11 $"; static inline u_char @@ -287,17 +287,20 @@ __initfunc(int printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); return (0); } - if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) { - u_int sub_sys_id = 0; - - if (pci_enable_device(dev_a4t)) - return (0); - pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) { + while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN, + PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { + u16 sub_sys; + u16 sub_vendor; + + sub_vendor = dev_a4t->subsystem_vendor; + sub_sys = dev_a4t->subsystem_device; + if ((sub_sys == A4T_SUBSYS_ID) && (sub_vendor == A4T_SUBVEN_ID)) { + if (pci_enable_device(dev_a4t)) + return(0); found = 1; - pci_memaddr = pci_resource_start (dev_a4t, 0); + pci_memaddr = pci_resource_start(dev_a4t, 0); cs->irq = dev_a4t->irq; + break; } } if (!found) { diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 61e0bde3c..6f00073c6 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -17,29 +17,16 @@ #include "ipac.h" #include "hscx.h" #include "isdnl1.h" -#include "bkm_ax.h" #include <linux/pci.h> +#include "bkm_ax.h" + +#if CONFIG_PCI #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.9 $"; - -/* To survive the startup phase */ -typedef struct { - u_int active; /* true/false */ - u_int base; /* ipac base address */ -} IPAC_STATE; - -static IPAC_STATE ipac_state[4 + 1] __initdata = -{ - {0, 0}, /* dummy */ - {0, 0}, /* SCT_1 */ - {0, 0}, /* SCT_2 */ - {0, 0}, /* SCT_3 */ - {0, 0} /* SCT_4 */ -}; +const char sct_quadro_revision[] = "$Revision: 1.12 $"; static const char *sct_quadro_subtypes[] = { @@ -138,19 +125,13 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); } -/* Check whether the specified ipac is already active or not */ -static int -is_ipac_active(u_int ipac_nr) -{ - return (ipac_state[ipac_nr].active); -} - /* Set the specific ipac to active */ static void -set_ipac_active(u_int ipac_nr, u_int active) +set_ipac_active(struct IsdnCardState *cs, u_int active) { - /* set activation state */ - ipac_state[ipac_nr].active = active; + /* set irq mask */ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, + active ? 0xc0 : 0xff); } /* @@ -173,13 +154,14 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char ista, val, icnt = 5; - int i; + if (!cs) { printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n"); return; } ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - + if (!(ista & 0x3f)) /* not this IPAC */ + return; Start_IPAC: if (cs->debug & L1_DEB_IPAC) debugl1(cs, "IPAC ISTA %02X", ista); @@ -216,30 +198,15 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) sct_quadro_subtypes[cs->subtyp]); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); - - /* Read out all interrupt sources from currently not active ipacs */ - /* "Handle" all interrupts from currently not active ipac by reading the regs */ - for (i = SCT_1; i <= SCT_4; i++) - if (!is_ipac_active(i)) { - u_int base = ipac_state[i].base; - if (readreg(base, base + 4, 0xC1)) { - readreg(base, base + 4, 0xA0); - readreg(base, base + 4, 0xA4); - readreg(base, base + 4, 0x20); - readreg(base, base + 4, 0x24); - readreg(base, base + 4, 0x60); - readreg(base, base + 4, 0x64); - readreg(base, base + 4, 0xC1); - readreg(base, base + 4, ISAC_CIR0 + 0x80); - } - } } void release_io_sct_quadro(struct IsdnCardState *cs) { - /* ?? */ + release_region(cs->hw.ax.base & 0xffffffc0, 256); + if (cs->subtyp == SCT_1) + release_region(cs->hw.ax.plx_adr, 256); } static void @@ -249,11 +216,6 @@ enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) if (bEnable) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); else - /* Issue general di only if no ipac is active */ - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); } } @@ -263,26 +225,17 @@ reset_bkm(struct IsdnCardState *cs) { long flags; - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) { - /* Issue total reset only if no ipac is active */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); - - save_flags(flags); - sti(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - - /* Remove the soft reset */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - restore_flags(flags); - } + if (cs->subtyp == SCT_1) { + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); + save_flags(flags); + sti(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + /* Remove the soft reset */ + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + restore_flags(flags); } } @@ -292,20 +245,19 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) switch (mt) { case CARD_RESET: /* Disable ints */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); reset_bkm(cs); return (0); case CARD_RELEASE: /* Sanity */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); - reset_bkm(cs); release_io_sct_quadro(cs); return (0); case CARD_INIT: cs->debug |= L1_DEB_IPAC; - set_ipac_active(cs->subtyp, 1); + set_ipac_active(cs, 1); inithscxisac(cs, 3); /* Enable ints */ enable_bkm_int(cs, 1); @@ -316,18 +268,38 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return (0); } +__initfunc(int +sct_alloc_io(u_int adr, u_int len)) +{ + if (check_region(adr, len)) { + printk(KERN_WARNING + "HiSax: Scitel port %#x-%#x already in use\n", + adr, adr + len); + return (1); + } else { + request_region(adr, len, "scitel"); + } + return(0); +} + static struct pci_dev *dev_a8 __initdata = NULL; +static u16 sub_vendor_id __initdata = 0; +static u16 sub_sys_id __initdata = 0; +static u_char pci_bus __initdata = 0; +static u_char pci_device_fn __initdata = 0; +static u_char pci_irq __initdata = 0; + +#endif /* CONFIG_PCI */ __initfunc(int - setup_sct_quadro(struct IsdnCard *card)) +setup_sct_quadro(struct IsdnCard *card)) { +#if CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI - u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id; + u_char pci_rev_id; u_int found = 0; u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; -#endif strcpy(tmp, sct_quadro_revision); printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); @@ -339,32 +311,61 @@ __initfunc(int /* Identify subtype by para[0] */ if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) cs->subtyp = card->para[0]; - else + else { printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n", - CardType[card->typ]); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + CardType[card->typ]); return (0); } - if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) { - u_int sub_sys_id = 0; - - pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) { - found = 1; - pci_ioaddr1 = dev_a8->resource[ 1].start; - pci_irq = dev_a8->irq; - pci_bus = dev_a8->bus->number; - pci_device_fn = dev_a8->devfn; - } - } - if (!found) { - printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); + if ((cs->subtyp != SCT_1) && ((sub_sys_id != SCT_SUBSYS_ID) || + (sub_vendor_id != SCT_SUBVEN_ID))) return (0); + if (cs->subtyp == SCT_1) { + if (!pci_present()) { + printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + return (0); + } + while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX, + PCI_DEVICE_ID_PLX_9050, dev_a8))) { + + sub_vendor_id = dev_a8->subsystem_vendor; + sub_sys_id = dev_a8->subsystem_device; + if ((sub_sys_id == SCT_SUBSYS_ID) && + (sub_vendor_id == SCT_SUBVEN_ID)) { + if (pci_enable_device(dev_a8)) + return(0); + pci_ioaddr1 = pci_resource_start(dev_a8, 1); + pci_irq = dev_a8->irq; + pci_bus = dev_a8->bus->number; + pci_device_fn = dev_a8->devfn; + found = 1; + break; + } + } + if (!found) { + printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); + } +#ifdef ATTEMPT_PCI_REMAPPING +/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_REVISION_ID, &pci_rev_id); + if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { + printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + /* Restart PCI negotiation */ + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, (u_int) - 1); + /* Move up by 0x80 byte */ + pci_ioaddr1 += 0x80; + pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, pci_ioaddr1); + dev_a8->resource[ 1].start = pci_ioaddr1; + } +#endif /* End HACK */ } if (!pci_irq) { /* IRQ range check ?? */ printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n", @@ -372,25 +373,6 @@ __initfunc(int sct_quadro_subtypes[cs->subtyp]); return (0); } -#ifdef ATTEMPT_PCI_REMAPPING -/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ - pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id); - if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { - printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - /* Restart PCI negotiation */ - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, (u_int) - 1); - /* Move up by 0x80 byte */ - pci_ioaddr1 += 0x80; - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, pci_ioaddr1); - dev_a8->resource[ 1].start = pci_ioaddr1; - } -/* End HACK */ -#endif pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3); @@ -417,23 +399,42 @@ __initfunc(int /* pci_ioaddr5 is for the first subdevice only */ cs->hw.ax.plx_adr = pci_ioaddr1; /* Enter all ipac_base addresses */ - ipac_state[SCT_1].base = pci_ioaddr5 + 0x00; - ipac_state[SCT_2].base = pci_ioaddr4 + 0x08; - ipac_state[SCT_3].base = pci_ioaddr3 + 0x10; - ipac_state[SCT_4].base = pci_ioaddr2 + 0x20; - /* For isac and hscx control path */ - cs->hw.ax.base = ipac_state[cs->subtyp].base; + switch(cs->subtyp) { + case 1: + cs->hw.ax.base = pci_ioaddr5 + 0x00; + if (sct_alloc_io(pci_ioaddr1, 256)) + return(0); + if (sct_alloc_io(pci_ioaddr5, 256)) + return(0); + /* disable all IPAC */ + writereg(pci_ioaddr5, pci_ioaddr5 + 4, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24, + IPAC_MASK, 0xFF); + break; + case 2: + cs->hw.ax.base = pci_ioaddr4 + 0x08; + if (sct_alloc_io(pci_ioaddr4, 256)) + return(0); + break; + case 3: + cs->hw.ax.base = pci_ioaddr3 + 0x10; + if (sct_alloc_io(pci_ioaddr3, 256)) + return(0); + break; + case 4: + cs->hw.ax.base = pci_ioaddr2 + 0x20; + if (sct_alloc_io(pci_ioaddr2, 256)) + return(0); + break; + } /* For isac and hscx data path */ cs->hw.ax.data_adr = cs->hw.ax.base + 4; -#else - printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - return (0); -#endif /* CONFIG_PCI */ + printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n", CardType[card->typ], sct_quadro_subtypes[cs->subtyp], @@ -444,19 +445,6 @@ __initfunc(int test_and_set_bit(HW_IPAC, &cs->HW_Flags); - /* Disable all currently not active ipacs */ - if (!is_ipac_active(SCT_1)) - set_ipac_active(SCT_1, 0); - if (!is_ipac_active(SCT_2)) - set_ipac_active(SCT_2, 0); - if (!is_ipac_active(SCT_3)) - set_ipac_active(SCT_3, 0); - if (!is_ipac_active(SCT_4)) - set_ipac_active(SCT_4, 0); - - /* Perfom general reset (if possible) */ - reset_bkm(cs); - cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; @@ -473,4 +461,7 @@ __initfunc(int sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); +#else + printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); +#endif /* CONFIG_PCI */ } diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h index 418c4bd47..e513c81a6 100644 --- a/drivers/isdn/hisax/bkm_ax.h +++ b/drivers/isdn/hisax/bkm_ax.h @@ -19,13 +19,21 @@ /* A4T */ -#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */ -#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */ +#ifndef PCI_VENDOR_ID_ZORAN +#define PCI_VENDOR_ID_ZORAN 0x11DE +#endif +#ifndef PCI_DEVICE_ID_ZORAN_36120 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 +#endif #define A4T_SUBVEN_ID 0x0871 #define A4T_SUBSYS_ID 0xFFA4 /* Scitel Quadro */ -#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */ -#define PLX_VENDOR_ID 0x10B5 +#ifndef PCI_VENDOR_ID_PLX +#define PCI_VENDOR_ID_PLX 0x10B5 +#endif +#ifndef PCI_DEVICE_ID_PLX_9050 +#define PCI_DEVICE_ID_PLX_9050 0x9050 +#endif #define SCT_SUBVEN_ID 0x0871 #define SCT_SUBSYS_ID 0xFFA8 diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index 9ed33d0f3..4d3290392 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -366,7 +366,7 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) * No need to return "unknown" for calls without OAD, * cause that's handled in linklevel now (replaced by '0') */ - memcpy (&ic.parm.setup, &chanp->proc->para.setup, sizeof(ic.parm.setup)); + memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm)); ret = chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); @@ -383,12 +383,16 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_IN_PROCEED_SEND); chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); if (ret == 5) { - memcpy (&chanp->setup, &ic.parm.setup, sizeof(chanp->setup)); + memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } break; case 2: /* Rejecting Call */ break; + case 3: /* incomplete number */ + FsmDelTimer(&chanp->drel_timer, 61); + chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); + break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); @@ -795,6 +799,8 @@ static struct FsmNode fnlist[] HISAX_INITDATA = {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req}, {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req}, {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close}, + {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call}, + {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error}, {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in}, {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect}, {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject}, @@ -956,6 +962,9 @@ dchan_l3l4(struct PStack *st, int pr, void *arg) return; switch (pr) { + case (CC_MORE_INFO | INDICATION): + FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); + break; case (CC_DISCONNECT | INDICATION): FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); break; @@ -1103,7 +1112,7 @@ init_chan(int chan, struct IsdnCardState *csta) chanp->fi.printdebug = callc_debug; FsmInitTimer(&chanp->fi, &chanp->dial_timer); FsmInitTimer(&chanp->fi, &chanp->drel_timer); - if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { + if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) { init_d_st(chanp); } else { chanp->d_st = csta->channel->d_st; @@ -1176,9 +1185,12 @@ lldata_handler(struct PStack *st, int pr, void *arg) switch (pr) { case (DL_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lldata: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { + } else { + link_debug(chanp, 0, "lldata: channel not open"); dev_kfree_skb(skb); } break; @@ -1205,10 +1217,12 @@ lltrans_handler(struct PStack *st, int pr, void *arg) switch (pr) { case (PH_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lltrans: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { - link_debug(chanp, 0, "channel not open"); + } else { + link_debug(chanp, 0, "lltrans: channel not open"); dev_kfree_skb(skb); } break; @@ -1233,6 +1247,8 @@ ll_writewakeup(struct PStack *st, int len) struct Channel *chanp = st->lli.userdata; isdn_ctrl ic; + if (chanp->debug & 0x800) + link_debug(chanp, 0, "llwakeup: %d", len); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BSENT; ic.arg = chanp->chan; @@ -1506,7 +1522,7 @@ HiSax_command(isdn_ctrl * ic) link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", ic->parm.setup.eazmsn, ic->parm.setup.phone, ic->parm.setup.si1, ic->parm.setup.si2); - memcpy (&chanp->setup, &ic->parm.setup, sizeof (chanp->setup)); + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (!strcmp(chanp->setup.eazmsn, "0")) chanp->setup.eazmsn[0] = '\0'; /* this solution is dirty and may be change, if @@ -1526,6 +1542,7 @@ HiSax_command(isdn_ctrl * ic) break; case (ISDN_CMD_ACCEPTD): chanp = csta->channel + ic->arg; + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (chanp->debug & 1) link_debug(chanp, 1, "ACCEPTD"); FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); @@ -1722,7 +1739,7 @@ HiSax_command(isdn_ctrl * ic) chanp = csta->channel + ic->arg; if (chanp->debug & 1) link_debug(chanp, 1, "REDIR"); - memcpy (&chanp->setup, &ic->parm.setup, sizeof(chanp->setup)); + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); FsmEvent(&chanp->fi, EV_REDIR, NULL); break; diff --git a/drivers/isdn/hisax/cert.c b/drivers/isdn/hisax/cert.c index bf0c6465d..64f3bccc8 100644 --- a/drivers/isdn/hisax/cert.c +++ b/drivers/isdn/hisax/cert.c @@ -17,11 +17,9 @@ certification_check(int output) { #if CERTIFICATION == 0 if (output) { printk(KERN_INFO "HiSax: Approval certification valid\n"); - printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n"); - printk(KERN_INFO "HiSax: Approval registration numbers:\n"); - printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n"); - printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n"); + printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n"); printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n"); + printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n"); } return(0); #endif diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index cda0fe872..4ed7e4129 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -47,7 +47,7 @@ * 17 MIC card p0=irq p1=iobase * 18 ELSA Quickstep 1000PCI no parameter * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2 - * 20 Travers Technologies NETjet PCI card + * 20 Travers Technologies NETjet-S PCI card * 21 TELES PCI no parameter * 22 Sedlbauer Speed Star p0=irq p1=iobase * 23 reserved @@ -65,6 +65,7 @@ * 35 HFC 2BDS0 PCI none * 36 Winbond 6692 PCI none * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase + * 38 Travers Technologies NETspider-U PCI card * * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * @@ -76,11 +77,11 @@ const char *CardType[] = "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI", - "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", + "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", - "HFC 2BDS0 SX", + "HFC 2BDS0 SX", "NETspider-U", }; void HiSax_closecard(int cardnr); @@ -106,7 +107,6 @@ EXPORT_SYMBOL(elsa_init_pcmcia); #define DEFAULT_CFG {11,0x170,0,0} int avm_a1_init_pcmcia(void*, int, int*, int); EXPORT_SYMBOL(avm_a1_init_pcmcia); -EXPORT_SYMBOL(HiSax_closecard); #endif /* CONFIG_HISAX_AVM_A1_PCMCIA */ #ifdef CONFIG_HISAX_FRITZPCI @@ -198,7 +198,7 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #ifdef CONFIG_HISAX_NETJET #undef DEFAULT_CARD #undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NETJET +#define DEFAULT_CARD ISDN_CTYPE_NETJET_S #define DEFAULT_CFG {0,0,0,0} #endif @@ -280,22 +280,29 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #define DEFAULT_CFG {0,0,0,0} #endif +#ifdef CONFIG_HISAX_NETJET_U +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_NETJET_U +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_1TR6 #define DEFAULT_PROTO ISDN_PTYPE_1TR6 #define DEFAULT_PROTO_NAME "1TR6" #endif -#ifdef CONFIG_HISAX_EURO -#undef DEFAULT_PROTO -#define DEFAULT_PROTO ISDN_PTYPE_EURO -#undef DEFAULT_PROTO_NAME -#define DEFAULT_PROTO_NAME "EURO" -#endif #ifdef CONFIG_HISAX_NI1 #undef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_NI1 #undef DEFAULT_PROTO_NAME #define DEFAULT_PROTO_NAME "NI1" #endif +#ifdef CONFIG_HISAX_EURO +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_EURO +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "EURO" +#endif #ifndef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN #define DEFAULT_PROTO_NAME "UNKNOWN" @@ -304,6 +311,10 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #error "HiSax: No cards configured" #endif +int hisax_init_pcmcia(void *, int *, struct IsdnCard *); +EXPORT_SYMBOL(hisax_init_pcmcia); +EXPORT_SYMBOL(HiSax_closecard); + #define FIRST_CARD { \ DEFAULT_CARD, \ DEFAULT_PROTO, \ @@ -400,9 +411,9 @@ HiSaxVersion(void)) printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3e (module)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); @@ -546,8 +557,8 @@ extern int setup_sportster(struct IsdnCard *card); extern int setup_mic(struct IsdnCard *card); #endif -#if CARD_NETJET -extern int setup_netjet(struct IsdnCard *card); +#if CARD_NETJET_S +extern int setup_netjet_s(struct IsdnCard *card); #endif #if CARD_HFCS @@ -598,6 +609,10 @@ extern int setup_gazel(struct IsdnCard *card); extern int setup_w6692(struct IsdnCard *card); #endif +#if CARD_NETJET_U +extern int setup_netjet_u(struct IsdnCard *card); +#endif + /* * Find card with given driverId */ @@ -800,7 +815,7 @@ ll_stop(struct IsdnCardState *cs) ic.command = ISDN_STAT_STOP; ic.driver = cs->myid; cs->iif.statcallb(&ic); - CallcFreeChan(cs); +// CallcFreeChan(cs); } static void @@ -923,6 +938,8 @@ checkcard(int cardnr, char *id, int *busy_flag)) cs->busy_flag = busy_flag; cs->irq_flags = I4L_IRQ_FLAG; #if TEI_PER_CARD + if (card->protocol == ISDN_PTYPE_NI1) + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #else test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #endif @@ -1067,9 +1084,9 @@ checkcard(int cardnr, char *id, int *busy_flag)) ret = setup_mic(card); break; #endif -#if CARD_NETJET - case ISDN_CTYPE_NETJET: - ret = setup_netjet(card); +#if CARD_NETJET_S + case ISDN_CTYPE_NETJET_S: + ret = setup_netjet_s(card); break; #endif #if CARD_HFCS @@ -1133,6 +1150,11 @@ checkcard(int cardnr, char *id, int *busy_flag)) ret = setup_w6692(card); break; #endif +#if CARD_NETJET_U + case ISDN_CTYPE_NETJET_U: + ret = setup_netjet_u(card); + break; +#endif default: printk(KERN_WARNING "HiSax: Support for %s Card not selected\n", @@ -1252,6 +1274,9 @@ HiSax_closecard(int cardnr) if (cards[cardnr].cs) { ll_stop(cards[cardnr].cs); release_tei(cards[cardnr].cs); + + CallcFreeChan(cards[cardnr].cs); + closecard(cardnr); if (cards[cardnr].cs->irq) free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); @@ -1310,10 +1335,19 @@ HiSax_reportcard(int cardnr, int sel) __initfunc(int HiSax_init(void)) { - int i; + int i,j; #ifdef MODULE int nzproto = 0; + if (!type[0]) { + /* We 'll register drivers later, but init basic functions*/ + CallcNew(); + Isdnl3New(); + Isdnl2New(); + TeiNew(); + Isdnl1New(); + return 0; + } #ifdef CONFIG_HISAX_ELSA if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) { /* we have exported and return in this case */ @@ -1338,41 +1372,41 @@ HiSax_init(void)) #ifdef MODULE if (id) /* If id= string used */ HiSax_id = id; - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].typ = type[i]; + for (i = j = 0; j < HISAX_MAX_CARDS; i++) { + cards[j].typ = type[i]; if (protocol[i]) { - cards[i].protocol = protocol[i]; + cards[j].protocol = protocol[i]; nzproto++; } switch (type[i]) { case ISDN_CTYPE_16_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; - cards[i].para[2] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; + cards[j].para[2] = io[i]; break; case ISDN_CTYPE_8_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; break; #ifdef IO0_IO1 case ISDN_CTYPE_PNP: case ISDN_CTYPE_NICCY: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; break; case ISDN_CTYPE_COMPAQ_ISA: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; - cards[i].para[3] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; + cards[j].para[3] = io[i]; break; #endif case ISDN_CTYPE_ELSA: case ISDN_CTYPE_HFC_PCI: - cards[i].para[0] = io[i]; + cards[j].para[0] = io[i]; break; case ISDN_CTYPE_16_3: case ISDN_CTYPE_TELESPCMCIA: @@ -1396,26 +1430,42 @@ HiSax_init(void)) case ISDN_CTYPE_HSTSAPHIR: case ISDN_CTYPE_GAZEL: case ISDN_CTYPE_HFC_SX: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; break; case ISDN_CTYPE_ISURF: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].para[2] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; + cards[j].para[2] = mem[i]; break; case ISDN_CTYPE_ELSA_PCI: - case ISDN_CTYPE_NETJET: + case ISDN_CTYPE_NETJET_S: case ISDN_CTYPE_AMD7930: case ISDN_CTYPE_TELESPCI: case ISDN_CTYPE_W6692: + case ISDN_CTYPE_NETJET_U: break; case ISDN_CTYPE_BKM_A4T: - break; + break; case ISDN_CTYPE_SCT_QUADRO: - cards[i].para[0] = irq[i]; + if (irq[i]) { + cards[j].para[0] = irq[i]; + } else { + /* QUADRO is a 4 BRI card */ + cards[j++].para[0] = 1; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 2; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 3; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j].para[0] = 4; + } break; } + j++; } if (!nzproto) { printk(KERN_WARNING "HiSax: Warning - no protocol specified\n"); @@ -1620,3 +1670,21 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) return (0); } #endif + +int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) +{ + u_char ids[16]; + int ret = -1; + + cards[nrcards] = *card; + if (nrcards) + sprintf(ids, "HiSax%d", nrcards); + else + sprintf(ids, "HiSax"); + if (!checkcard(nrcards, ids, busy_flag)) { + return(-1); + } + ret = nrcards; + nrcards++; + return (ret); +} diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 002ee0d60..f39dd7558 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -47,12 +47,18 @@ const char *Diva_revision = "$Revision: 1.21 $"; #define DIVA_IPAC_PCI 4 /* PCI stuff */ -#define PCI_VENDOR_EICON_DIEHL 0x1133 -#define PCI_DIVA20PRO_ID 0xe001 -#define PCI_DIVA20_ID 0xe002 -#define PCI_DIVA20PRO_U_ID 0xe003 -#define PCI_DIVA20_U_ID 0xe004 -#define PCI_DIVA_201 0xe005 +#ifndef PCI_VENDOR_ID_EICON +#define PCI_VENDOR_ID_EICON 0x1133 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA20 +#define PCI_DEVICE_ID_EICON_DIVA20 0xe002 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA20_U +#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA201 +#define PCI_DEVICE_ID_EICON_DIVA201 0xe005 +#endif /* CTRL (Read) */ #define DIVA_IRQ_STAT 0x01 @@ -70,10 +76,16 @@ const char *Diva_revision = "$Revision: 1.21 $"; /* Siemens PITA */ #define PITA_MISC_REG 0x1c +#ifdef __BIG_ENDIAN +#define PITA_PARA_SOFTRESET 0x00000001 +#define PITA_PARA_MPX_MODE 0x00000004 +#define PITA_INT0_ENABLE 0x00000200 +#else #define PITA_PARA_SOFTRESET 0x01000000 #define PITA_PARA_MPX_MODE 0x04000000 #define PITA_INT0_ENABLE 0x00020000 -#define PITA_INT0_STATUS 0x00000002 +#endif +#define PITA_INT0_STATUS 0x02 static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -122,7 +134,7 @@ writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size static inline u_char memreadreg(unsigned long adr, u_char off) { - return(0xff & *((unsigned int *) + return(*((unsigned char *) (((unsigned int *)adr) + off))); } @@ -870,24 +882,24 @@ setup_diva(struct IsdnCard *card)) } cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_ID, dev_diva))) { + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { if (pci_enable_device(dev_diva)) - return (0); + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva->irq; cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_U_ID, dev_diva_u))) { + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { if (pci_enable_device(dev_diva_u)) - return (0); + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva_u->irq; cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA_201, dev_diva201))) { + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { if (pci_enable_device(dev_diva201)) - return (0); + return(0); cs->subtyp = DIVA_IPAC_PCI; cs->irq = dev_diva201->irq; cs->hw.diva.pci_cfg = diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 70cff176b..f2357cc4b 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -29,10 +29,10 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.20 $"; +const char *Elsa_revision = "$Revision: 2.23 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", + "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", "PCMCIA-IPAC" }; const char *ITACVer[] = @@ -66,9 +66,15 @@ const char *ITACVer[] = #define ELSA_PCMCIA_IPAC 11 /* PCI stuff */ -#define PCI_VENDOR_ELSA 0x1048 -#define PCI_QS1000_ID 0x1000 -#define PCI_QS3000_ID 0x3000 +#ifndef PCI_VENDOR_ID_ELSA +#define PCI_VENDOR_ID_ELSA 0x1048 +#endif +#ifndef PCI_DEVICE_ID_ELSA_MIRCOLINK +#define PCI_DEVICE_ID_ELSA_MIRCOLINK 0x1000 +#endif +#ifndef PCI_DEVICE_ID_ELSA_QS3000 +#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 +#endif #define ELSA_PCI_IRQ_MASK 0x04 /* ITAC Registeradressen (only Microlink PC) */ @@ -723,7 +729,8 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", cs->hw.elsa.counter); - if (abs(cs->hw.elsa.counter - 13) < 3) { + if ((cs->hw.elsa.counter > 10) && + (cs->hw.elsa.counter < 16)) { printk(KERN_INFO "Elsa: timer and irq OK\n"); ret = 0; } else { @@ -982,18 +989,18 @@ setup_elsa(struct IsdnCard *card) return(0); } cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID, - dev_qs1000))) { + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MIRCOLINK, dev_qs1000))) { if (pci_enable_device(dev_qs1000)) - return (0); + return(0); cs->subtyp = ELSA_QS1000PCI; cs->irq = dev_qs1000->irq; cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA, - PCI_QS3000_ID, dev_qs3000))) { - if (pci_enable_device(dev_qs1000)) - return (0); + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) + return(0); cs->subtyp = ELSA_QS3000PCI; cs->irq = dev_qs3000->irq; cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index 4693318dc..eb777b184 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -26,10 +26,18 @@ const char *gazel_revision = "$Revision: 2.8 $"; #define R742 4 /* Gazel R685 stuff */ -#define GAZEL_MANUFACTURER 0x10b5 -#define GAZEL_R685 0x1030 -#define GAZEL_R753 0x1152 -#define GAZEL_DJINN_ITOO 0x1151 +#ifndef PCI_VENDOR_ID_PLX +#define PCI_VENDOR_ID_PLX 0x10b5 +#endif +#ifndef PCI_DEVICE_ID_PLX_R685 +#define PCI_DEVICE_ID_PLX_R685 0x1030 +#endif +#ifndef PCI_DEVICE_ID_PLX_R753 +#define PCI_DEVICE_ID_PLX_R753 0x1152 +#endif +#ifndef PCI_DEVICE_ID_PLX_DJINN_ITOO +#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 +#endif #define PLX_CNTRL 0x50 /* registre de controle PLX */ #define RESET_GAZEL 0x4 @@ -565,25 +573,25 @@ setup_gazelpci(struct IsdnCardState *cs) printk(KERN_WARNING "Gazel: No PCI bus present\n"); return 1; } - seekcard = GAZEL_R685; + seekcard = PCI_DEVICE_ID_PLX_R685; for (nbseek = 0; nbseek < 3; nbseek++) { - if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) { + if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) { if (pci_enable_device(dev_tel)) return 1; pci_irq = dev_tel->irq; - pci_ioaddr0 = dev_tel->resource[ 1].start; - pci_ioaddr1 = dev_tel->resource[ 2].start; + pci_ioaddr0 = pci_resource_start(dev_tel, 1); + pci_ioaddr1 = pci_resource_start(dev_tel, 2); found = 1; } if (found) break; else { switch (seekcard) { - case GAZEL_R685: - seekcard = GAZEL_R753; + case PCI_DEVICE_ID_PLX_R685: + seekcard = PCI_DEVICE_ID_PLX_R753; break; - case GAZEL_R753: - seekcard = GAZEL_DJINN_ITOO; + case PCI_DEVICE_ID_PLX_R753: + seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO; break; } } @@ -612,7 +620,7 @@ setup_gazelpci(struct IsdnCardState *cs) cs->irq_flags |= SA_SHIRQ; switch (seekcard) { - case GAZEL_R685: + case PCI_DEVICE_ID_PLX_R685: printk(KERN_INFO "Gazel: Card PCI R685 found\n"); cs->subtyp = R685; cs->dc.isac.adf2 = 0x87; @@ -623,8 +631,8 @@ setup_gazelpci(struct IsdnCardState *cs) "Gazel: hscx A:0x%X hscx B:0x%X\n", cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); break; - case GAZEL_R753: - case GAZEL_DJINN_ITOO: + case PCI_DEVICE_ID_PLX_R753: + case PCI_DEVICE_ID_PLX_DJINN_ITOO: printk(KERN_INFO "Gazel: Card PCI R753 found\n"); cs->subtyp = R753; test_and_set_bit(HW_IPAC, &cs->HW_Flags); diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index f28585a84..bd1442046 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.14 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.15 2000/07/26 20:46:47 keil Exp $ * * specific routines for CCD's HFC 2BS0 * @@ -203,7 +203,7 @@ hfc_empty_fifo(struct BCState *bcs, int count) ptr = skb_put(skb, count); idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx < count - 3) && WaitNoBusy(cs)) { + while ((idx < count) && WaitNoBusy(cs)) { *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index ac673c227..c0ff9b642 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.30 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_pci.c,v 1.31 2000/08/20 07:32:55 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -34,7 +34,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.30 $"; +static const char *hfcpci_revision = "$Revision: 1.31 $"; /* table entry in the PCI devices list */ typedef struct { @@ -44,7 +44,9 @@ typedef struct { char *card_name; } PCI_ENTRY; -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ +#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ static const PCI_ENTRY id_list[] = { @@ -63,7 +65,10 @@ static const PCI_ENTRY id_list[] = {0x1051, 0x0100, "Motorola MC145575", "MC145575"}, {0x1397, 0xB100, "Seyeon", "B100"}, {0x15B0, 0x2BD0, "Zoltrix", "2BD0"}, - {0x114f, 0x71, "Digi intl.","Digicom"}, + {0x114F, 0x70,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"}, + {0x114F, 0x71,"Digi International", "Digi DataFire Micro V (Europe)"}, + {0x114F, 0x72,"Digi International", "Digi DataFire Micro V IOM2 (North America)"}, + {0x114F, 0x73,"Digi International", "Digi DataFire Micro V (North America)"}, {0, 0, NULL, NULL}, }; @@ -130,7 +135,7 @@ reset_hfcpci(struct IsdnCardState *cs) cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */ cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE; Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */ cs->hw.hfcpci.bswapped = 0; /* no exchange */ @@ -254,6 +259,9 @@ hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int cou (*(bdata + (zp->z1 - B_SUB_VAL)))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); +#ifdef ERROR_STATISTIC + bcs->err_inv++; +#endif bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ skb = NULL; @@ -320,6 +328,9 @@ receive_dmsg(struct IsdnCardState *cs) (df->data[zp->z1])) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); } else if ((skb = dev_alloc_skb(rcnt - 3))) { @@ -506,6 +517,9 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs) if (fcnt > (MAX_D_FRAMES - 1)) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif return; } /* now determine free bytes in FIFO buffer */ @@ -740,6 +754,7 @@ hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic) (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { save_flags(flags); cli(); + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */ Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ udelay(10); cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT; @@ -1625,6 +1640,9 @@ __initfunc(int int i; struct pci_dev *tmp_hfcpci = NULL; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); #if CONFIG_PCI @@ -1645,7 +1663,7 @@ __initfunc(int if (tmp_hfcpci) { if (pci_enable_device(tmp_hfcpci)) continue; - if ((card->para[0]) && (card->para[0] != pci_resource_start(tmp_hfcpci, 0))) + if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) continue; else break; diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 11d38baf2..abc215f87 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -39,8 +39,11 @@ #define HW_POWERUP 0x0008 #define HW_ACTIVATE 0x0010 #define HW_DEACTIVATE 0x0018 + +#define HW_INFO1 0x0010 #define HW_INFO2 0x0020 #define HW_INFO3 0x0030 +#define HW_INFO4 0x0040 #define HW_INFO4_P8 0x0040 #define HW_INFO4_P10 0x0048 #define HW_RSYNC 0x0060 @@ -90,6 +93,7 @@ #define CC_SUSPEND 0x0370 #define CC_PROCEED_SEND 0x0374 #define CC_REDIR 0x0378 +#define CC_T302 0x0382 #define CC_T303 0x0383 #define CC_T304 0x0384 #define CC_T305 0x0385 @@ -100,6 +104,7 @@ #define CC_T313 0x0393 #define CC_T318 0x0398 #define CC_T319 0x0399 +#define CC_TSPID 0x03A0 #define CC_NOSETUP_RSP 0x03E0 #define CC_SETUP_ERR 0x03E1 #define CC_SUSPEND_ERR 0x03E2 @@ -108,6 +113,7 @@ #define CC_RELEASE_ERR 0x03E5 #define CC_RESTART 0x03F4 #define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */ +#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */ /* define maximum number of possible waiting incoming calls */ #define MAX_WAITING_CALLS 2 @@ -115,13 +121,19 @@ #ifdef __KERNEL__ -/* include only l3dss1 specific process structures, but no other defines */ +/* include l3dss1 & ni1 specific process structures, but no other defines */ #ifdef CONFIG_HISAX_EURO #define l3dss1_process #include "l3dss1.h" #undef l3dss1_process #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + #define l3ni1_process + #include "l3ni1.h" + #undef l3ni1_process +#endif CONFIG_HISAX_NI1 + #define MAX_DFRAME_LEN 260 #define MAX_DFRAME_LEN_L1 300 #define HSCX_BUFMAX 4096 @@ -184,6 +196,7 @@ struct L3Timer { #define FLG_L1_ACTTIMER 4 #define FLG_L1_T3RUN 5 #define FLG_L1_PULL_REQ 6 +#define FLG_L1_UINT 7 struct Layer1 { void *hardware; @@ -298,7 +311,7 @@ struct PStack { struct Layer3 l3; struct LLInterface lli; struct Management ma; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ /* protocol specific data fields */ union @@ -306,6 +319,9 @@ struct PStack { #ifdef CONFIG_HISAX_EURO dss1_stk_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_stk_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -327,6 +343,9 @@ struct l3_process { #ifdef CONFIG_HISAX_EURO dss1_proc_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_proc_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -373,10 +392,17 @@ struct isar_hw { }; struct hdlc_stat_reg { +#ifdef __BIG_ENDIAN + u_char fill __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char cmd __attribute__((packed)); +#else u_char cmd __attribute__((packed)); u_char xml __attribute__((packed)); u_char mode __attribute__((packed)); u_char fill __attribute__((packed)); +#endif }; struct hdlc_hw { @@ -805,6 +831,22 @@ struct w6692_chip { int ph_state; }; +struct icc_chip { + int ph_state; + u_char *mon_tx; + u_char *mon_rx; + int mon_txp; + int mon_txc; + int mon_rxp; + struct arcofi_msg *arcofi_list; + struct timer_list arcofitimer; + wait_queue_head_t arcofi_wait; + u_char arcofi_bc; + u_char arcofi_state; + u_char mocr; + u_char adf2; +}; + #define HW_IOM1 0 #define HW_IPAC 1 #define HW_ISAR 2 @@ -815,6 +857,7 @@ struct w6692_chip { #define FLG_LOCK_ATOMIC 7 #define FLG_ARCOFI_TIMER 8 #define FLG_ARCOFI_ERROR 9 +#define FLG_HW_L1_UINT 10 struct IsdnCardState { unsigned char typ; @@ -883,6 +926,7 @@ struct IsdnCardState { struct hfcpci_chip hfcpci; struct hfcsx_chip hfcsx; struct w6692_chip w6692; + struct icc_chip icc; } dc; u_char *rcvbuf; int rcvidx; @@ -924,7 +968,7 @@ struct IsdnCardState { #define ISDN_CTYPE_MIC 17 #define ISDN_CTYPE_ELSA_PCI 18 #define ISDN_CTYPE_COMPAQ_ISA 19 -#define ISDN_CTYPE_NETJET 20 +#define ISDN_CTYPE_NETJET_S 20 #define ISDN_CTYPE_TELESPCI 21 #define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 #define ISDN_CTYPE_AMD7930 23 @@ -942,7 +986,8 @@ struct IsdnCardState { #define ISDN_CTYPE_HFC_PCI 35 #define ISDN_CTYPE_W6692 36 #define ISDN_CTYPE_HFC_SX 37 -#define ISDN_CTYPE_COUNT 37 +#define ISDN_CTYPE_NETJET_U 38 +#define ISDN_CTYPE_COUNT 38 #ifdef ISDN_CHIP_ISAC @@ -1091,12 +1136,12 @@ struct IsdnCardState { #endif #ifdef CONFIG_HISAX_NETJET -#define CARD_NETJET 1 +#define CARD_NETJET_S 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif #else -#define CARD_NETJET 0 +#define CARD_NETJET_S 0 #endif #ifdef CONFIG_HISAX_HFCS @@ -1204,17 +1249,19 @@ struct IsdnCardState { #define CARD_W6692 0 #endif -#define TEI_PER_CARD 0 - -#ifdef CONFIG_HISAX_1TR6 -#undef TEI_PER_CARD -#define TEI_PER_CARD 1 +#ifdef CONFIG_HISAX_NETJET_U +#define CARD_NETJET_U 1 +#ifndef ISDN_CHIP_ICC +#define ISDN_CHIP_ICC 1 +#endif +#ifndef HISAX_UINTERFACE +#define HISAX_UINTERFACE 1 +#endif +#else +#define CARD_NETJET_U 0 #endif -#ifdef CONFIG_HISAX_EURO -#undef TEI_PER_CARD #define TEI_PER_CARD 1 -#endif /* L1 Debug */ #define L1_DEB_WARN 0x01 @@ -1238,7 +1285,7 @@ extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, struct IsdnCard { int typ; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ unsigned int para[4]; struct IsdnCardState *cs; }; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c new file mode 100644 index 000000000..5f2740e9e --- /dev/null +++ b/drivers/isdn/hisax/icc.c @@ -0,0 +1,685 @@ +// $Id: icc.c,v 1.3 2000/08/20 07:34:04 keil Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.6.25 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#define __NO_VERSION__ +#include "hisax.h" +#include "icc.h" +// #include "arcofi.h" +#include "isdnl1.h" +#include <linux/interrupt.h> + +#define DBUSY_TIMER_VALUE 80 +#define ARCOFI_USE 0 + +static char *ICCVer[] HISAX_INITDATA = +{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; + +void +ICCVersion(struct IsdnCardState *cs, char *s) +{ + int val; + + val = cs->readisac(cs, ICC_RBCH); + printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]); +} + +static void +ph_command(struct IsdnCardState *cs, unsigned int command) +{ + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_command %x", command); + cs->writeisac(cs, ICC_CIX0, (command << 2) | 3); +} + + +static void +icc_new_ph(struct IsdnCardState *cs) +{ + switch (cs->dc.icc.ph_state) { + case (ICC_IND_EI1): + ph_command(cs, ICC_CMD_DI); + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + case (ICC_IND_DC): + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); + break; + case (ICC_IND_DR): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + case (ICC_IND_PU): + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + case (ICC_IND_FJ): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + case (ICC_IND_AR): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + case (ICC_IND_AI): + l1_msg(cs, HW_INFO4 | INDICATION, NULL); + break; + default: + break; + } +} + +static void +icc_bh(struct IsdnCardState *cs) +{ + struct PStack *stptr; + + if (!cs) + return; + if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { + if (cs->debug) + debugl1(cs, "D-Channel Busy cleared"); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr = stptr->next; + } + } + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) + icc_new_ph(cs); + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) + DChannel_proc_rcv(cs); + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) + DChannel_proc_xmt(cs); +#if ARCOFI_USE + if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) + return; + if (test_and_clear_bit(D_RX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_RX_END, NULL); + if (test_and_clear_bit(D_TX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_TX_END, NULL); +#endif +} + +void +icc_empty_fifo(struct IsdnCardState *cs, int count) +{ + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_empty_fifo"); + + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_empty_fifo overrun %d", + cs->rcvidx + count); + cs->writeisac(cs, ICC_CMDR, 0x80); + cs->rcvidx = 0; + return; + } + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + save_flags(flags); + cli(); + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, 0x80); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +static void +icc_fill_fifo(struct IsdnCardState *cs) +{ + int count, more; + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_fill_fifo"); + + if (!cs->tx_skb) + return; + + count = cs->tx_skb->len; + if (count <= 0) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + save_flags(flags); + cli(); + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); + if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + debugl1(cs, "icc_fill_fifo dbusytimer running"); + del_timer(&cs->dbusytimer); + } + init_timer(&cs->dbusytimer); + cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&cs->dbusytimer); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +void +icc_sched_event(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + queue_task(&cs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +void +icc_interrupt(struct IsdnCardState *cs, u_char val) +{ + u_char exval, v1; + struct sk_buff *skb; + unsigned int count; + long flags; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC interrupt %x", val); + if (val & 0x80) { /* RME */ + exval = cs->readisac(cs, ICC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RDO"); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif + } + if (!(exval & 0x20)) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC CRC error"); +#ifdef ERROR_STATISTIC + cs->err_crc++; +#endif + } + cs->writeisac(cs, ICC_CMDR, 0x80); + } else { + count = cs->readisac(cs, ICC_RBCL) & 0x1f; + if (count == 0) + count = 32; + icc_empty_fifo(cs, count); + save_flags(flags); + cli(); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "HiSax: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } + restore_flags(flags); + } + cs->rcvidx = 0; + icc_sched_event(cs, D_RCVBUFREADY); + } + if (val & 0x40) { /* RPF */ + icc_empty_fifo(cs, 32); + } + if (val & 0x20) { /* RSC */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + icc_fill_fifo(cs); + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else + icc_sched_event(cs, D_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + exval = cs->readisac(cs, ICC_CIR0); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR0 %02X", exval ); + if (exval & 2) { + cs->dc.icc.ph_state = (exval >> 2) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); + icc_sched_event(cs, D_L1STATECHANGE); + } + if (exval & 1) { + exval = cs->readisac(cs, ICC_CIR1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR1 %02X", exval ); + } + } + if (val & 0x02) { /* SIN */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = cs->readisac(cs, ICC_EXIR); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC EXIR %02x", exval); + if (exval & 0x80) { /* XMR */ + debugl1(cs, "ICC XMR"); + printk(KERN_WARNING "HiSax: ICC XMR\n"); + } + if (exval & 0x40) { /* XDU */ + debugl1(cs, "ICC XDU"); + printk(KERN_WARNING "HiSax: ICC XDU\n"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); + debugl1(cs, "ICC XDU no skb"); + } + } + if (exval & 0x04) { /* MOS */ + v1 = cs->readisac(cs, ICC_MOSR); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOSR %02x", v1); +#if ARCOFI_USE + if (v1 & 0x08) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR0; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR0; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + if (cs->dc.icc.mon_rxp == 1) { + cs->dc.icc.mocr |= 0x04; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + } + afterMONR0: + if (v1 & 0x80) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR1; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR1; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + cs->dc.icc.mocr |= 0x40; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + afterMONR1: + if (v1 & 0x04) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON0); + } + if (v1 & 0x40) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON1); + } + if (v1 & 0x02) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x08))) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + cs->writeisac(cs, ICC_MOX0, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX0: + if (v1 & 0x20) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x80))) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + cs->writeisac(cs, ICC_MOX1, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX1: +#endif + } + } +} + +static void +ICC_l1hw(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + int val; + + switch (pr) { + case (PH_DATA |REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + icc_fill_fifo(cs); + } + break; + case (PH_PULL |INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + icc_fill_fifo(cs); + break; + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (HW_RESET | REQUEST): + if ((cs->dc.icc.ph_state == ICC_IND_EI1) || + (cs->dc.icc.ph_state == ICC_IND_DR)) + ph_command(cs, ICC_CMD_DI); + else + ph_command(cs, ICC_CMD_RES); + break; + case (HW_ENABLE | REQUEST): + ph_command(cs, ICC_CMD_DI); + break; + case (HW_INFO1 | REQUEST): + ph_command(cs, ICC_CMD_AR); + break; + case (HW_INFO3 | REQUEST): + ph_command(cs, ICC_CMD_AI); + break; + case (HW_TESTLOOP | REQUEST): + val = 0; + if (1 & (long) arg) + val |= 0x0c; + if (2 & (long) arg) + val |= 0x3; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + if (!val) { + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + } else { + cs->writeisac(cs, ICC_SPCR, val); + cs->writeisac(cs, ICC_ADF1, 0xa); + } + } else { + /* IOM 2 Mode */ + cs->writeisac(cs, ICC_SPCR, val); + if (val) + cs->writeisac(cs, ICC_ADF1, 0x8); + else + cs->writeisac(cs, ICC_ADF1, 0x0); + } + break; + case (HW_DEACTIVATE | RESPONSE): + discard_queue(&cs->rq); + discard_queue(&cs->sq); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_skb = NULL; + } + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + break; + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_l1hw unknown %04x", pr); + break; + } +} + +void +setstack_icc(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = ICC_l1hw; +} + +void +DC_Close_icc(struct IsdnCardState *cs) { + if (cs->dc.icc.mon_rx) { + kfree(cs->dc.icc.mon_rx); + cs->dc.icc.mon_rx = NULL; + } + if (cs->dc.icc.mon_tx) { + kfree(cs->dc.icc.mon_tx); + cs->dc.icc.mon_tx = NULL; + } +} + +static void +dbusy_timer_handler(struct IsdnCardState *cs) +{ + struct PStack *stptr; + int rbch, star; + + if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + rbch = cs->readisac(cs, ICC_RBCH); + star = cs->readisac(cs, ICC_STAR); + if (cs->debug) + debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", + rbch, star); + if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */ + test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); + stptr = stptr->next; + } + } else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } else { + printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n"); + debugl1(cs, "D-Channel Busy no skb"); + } + cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ + cs->irq_func(cs->irq, cs, NULL); + } + } +} + +HISAX_INITFUNC(void +initicc(struct IsdnCardState *cs)) +{ + cs->tqueue.routine = (void *) (void *) icc_bh; + cs->setstack_d = setstack_icc; + cs->DC_Close = DC_Close_icc; + cs->dc.icc.mon_tx = NULL; + cs->dc.icc.mon_rx = NULL; + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + cs->writeisac(cs, ICC_MASK, 0xff); + cs->dc.icc.mocr = 0xaa; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + cs->writeisac(cs, ICC_ADF2, 0x0); + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xc9); + } else { + /* IOM 2 Mode */ + if (!cs->dc.icc.adf2) + cs->dc.icc.adf2 = 0x80; + cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); + cs->writeisac(cs, ICC_SQXR, 0xa0); + cs->writeisac(cs, ICC_SPCR, 0x20); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xca); + cs->writeisac(cs, ICC_TIMR, 0x00); + cs->writeisac(cs, ICC_ADF1, 0x20); + } + ph_command(cs, ICC_CMD_RES); + cs->writeisac(cs, ICC_MASK, 0x0); + ph_command(cs, ICC_CMD_DI); +} + +HISAX_INITFUNC(void +clear_pending_icc_ints(struct IsdnCardState *cs)) +{ + int val, eval; + + val = cs->readisac(cs, ICC_STAR); + debugl1(cs, "ICC STAR %x", val); + val = cs->readisac(cs, ICC_MODE); + debugl1(cs, "ICC MODE %x", val); + val = cs->readisac(cs, ICC_ADF2); + debugl1(cs, "ICC ADF2 %x", val); + val = cs->readisac(cs, ICC_ISTA); + debugl1(cs, "ICC ISTA %x", val); + if (val & 0x01) { + eval = cs->readisac(cs, ICC_EXIR); + debugl1(cs, "ICC EXIR %x", eval); + } + val = cs->readisac(cs, ICC_CIR0); + debugl1(cs, "ICC CIR0 %x", val); + cs->dc.icc.ph_state = (val >> 2) & 0xf; + icc_sched_event(cs, D_L1STATECHANGE); + /* Disable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0xFF); +} diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h new file mode 100644 index 000000000..b3ecbdcf8 --- /dev/null +++ b/drivers/isdn/hisax/icc.h @@ -0,0 +1,73 @@ +// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.7.14 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + + +/* All Registers original Siemens Spec */ + +#define ICC_MASK 0x20 +#define ICC_ISTA 0x20 +#define ICC_STAR 0x21 +#define ICC_CMDR 0x21 +#define ICC_EXIR 0x24 +#define ICC_ADF2 0x39 +#define ICC_SPCR 0x30 +#define ICC_ADF1 0x38 +#define ICC_CIR0 0x31 +#define ICC_CIX0 0x31 +#define ICC_CIR1 0x33 +#define ICC_CIX1 0x33 +#define ICC_STCR 0x37 +#define ICC_MODE 0x22 +#define ICC_RSTA 0x27 +#define ICC_RBCL 0x25 +#define ICC_RBCH 0x2A +#define ICC_TIMR 0x23 +#define ICC_SQXR 0x3b +#define ICC_MOSR 0x3a +#define ICC_MOCR 0x3a +#define ICC_MOR0 0x32 +#define ICC_MOX0 0x32 +#define ICC_MOR1 0x34 +#define ICC_MOX1 0x34 + +#define ICC_RBCH_XAC 0x80 + +#define ICC_CMD_TIM 0x0 +#define ICC_CMD_RES 0x1 +#define ICC_CMD_DU 0x3 +#define ICC_CMD_EI1 0x4 +#define ICC_CMD_SSP 0x5 +#define ICC_CMD_DT 0x6 +#define ICC_CMD_AR 0x8 +#define ICC_CMD_ARL 0xA +#define ICC_CMD_AI 0xC +#define ICC_CMD_DI 0xF + +#define ICC_IND_DR 0x0 +#define ICC_IND_FJ 0x2 +#define ICC_IND_EI1 0x4 +#define ICC_IND_INT 0x6 +#define ICC_IND_PU 0x7 +#define ICC_IND_AR 0x8 +#define ICC_IND_ARL 0xA +#define ICC_IND_AI 0xC +#define ICC_IND_AIL 0xE +#define ICC_IND_DC 0xF + +extern void ICCVersion(struct IsdnCardState *cs, char *s); +extern void initicc(struct IsdnCardState *cs); +extern void icc_interrupt(struct IsdnCardState *cs, u_char val); +extern void clear_pending_icc_ints(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 6f19d6cb6..d91f86f02 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -243,6 +243,14 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf) printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); goto reterror; } +#ifdef __BIG_ENDIAN + sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256; + blk_head.sadr = sadr; + sadr = (blk_head.len & 0xff)*256 + blk_head.len/256; + blk_head.len = sadr; + sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256; + blk_head.d_key = sadr; +#endif /* __BIG_ENDIAN */ cnt += BLK_HEAD_SIZE; p += BLK_HEAD_SIZE; printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", @@ -284,8 +292,13 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf) #endif sadr += noc; while(noc) { +#ifdef __BIG_ENDIAN + *mp++ = *sp % 256; + *mp++ = *sp / 256; +#else *mp++ = *sp / 256; *mp++ = *sp % 256; +#endif /* __BIG_ENDIAN */ sp++; noc--; } @@ -528,8 +541,9 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { @@ -538,6 +552,7 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); } + bcs->hw.isar.rcvidx = 0; } } break; @@ -606,13 +621,16 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) bcs->hw.isar.rcvidx += ireg->clsb; rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { + int len = bcs->hw.isar.rcvidx + + dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { - memcpy(skb_put(skb, bcs->hw.isar.rcvidx), + insert_dle((u_char *)skb_put(skb, len), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); skb_queue_tail(&bcs->rqueue, skb); @@ -620,8 +638,20 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) send_DLE_ETX(bcs); isar_sched_event(bcs, B_LL_OK); } + bcs->hw.isar.rcvidx = 0; } } + if (ireg->cmsb & SART_NMD) { /* ABORT */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: no more data"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + send_DLE_ETX(bcs); + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + bcs->hw.isar.state = STFAX_ESCAPE; + isar_sched_event(bcs, B_LL_NOCARRIER); + } break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); @@ -1044,6 +1074,9 @@ isar_pump_statev_fax(struct BCState *bcs, u_char devt) { debugl1(cs, "pump stev RSP_DISC"); if (bcs->hw.isar.state == STFAX_ESCAPE) { switch(bcs->hw.isar.newcmd) { + case 0: + bcs->hw.isar.state = STFAX_READY; + break; case PCTRL_CMD_FTH: case PCTRL_CMD_FTM: p1 = 10; diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h index 7726622ca..d34621834 100644 --- a/drivers/isdn/hisax/isar.h +++ b/drivers/isdn/hisax/isar.h @@ -186,7 +186,7 @@ #define HDLC_ERROR 0x1c #define HDLC_ERR_FAD 0x10 #define HDLC_ERR_RER 0x08 -#define HDLC_ERR_CER 0x01 +#define HDLC_ERR_CER 0x04 #define SART_NMD 0x01 #define BSTAT_RDM0 0x1 diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index d0e734357..f523f378d 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -28,7 +28,7 @@ struct Fsm l1fsm_b = {NULL, 0, 0, NULL, NULL}; static -struct Fsm l1fsm_d = +struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; enum { @@ -41,9 +41,9 @@ enum { ST_L1_F8, }; -#define L1D_STATE_COUNT (ST_L1_F8+1) +#define L1S_STATE_COUNT (ST_L1_F8+1) -static char *strL1DState[] = +static char *strL1SState[] = { "ST_L1_F2", "ST_L1_F3", @@ -54,6 +54,29 @@ static char *strL1DState[] = "ST_L1_F8", }; +#ifdef HISAX_UINTERFACE +static +struct Fsm l1fsm_u = +{NULL, 0, 0, NULL, NULL}; + +enum { + ST_L1_RESET, + ST_L1_DEACT, + ST_L1_SYNC2, + ST_L1_TRANS, +}; + +#define L1U_STATE_COUNT (ST_L1_TRANS+1) + +static char *strL1UState[] = +{ + "ST_L1_RESET", + "ST_L1_DEACT", + "ST_L1_SYNC2", + "ST_L1_TRANS", +}; +#endif + enum { ST_L1_NULL, ST_L1_WAIT_ACT, @@ -432,7 +455,7 @@ l1_deact_cnf(struct FsmInst *fi, int event, void *arg) } static void -l1_deact_req(struct FsmInst *fi, int event, void *arg) +l1_deact_req_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -442,7 +465,7 @@ l1_deact_req(struct FsmInst *fi, int event, void *arg) } static void -l1_power_up(struct FsmInst *fi, int event, void *arg) +l1_power_up_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -472,7 +495,12 @@ l1_info2_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F6); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_SYNC2); + else +#endif + FsmChangeState(fi, ST_L1_F6); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); } @@ -481,7 +509,12 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F7); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_TRANS); + else +#endif + FsmChangeState(fi, ST_L1_F7); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) FsmDelTimer(&st->l1.timer, 4); @@ -501,6 +534,10 @@ l1_timer3(struct FsmInst *fi, int event, void *arg) test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) L1deactivated(st->l1.hardware); + +#ifdef HISAX_UINTERFACE + if (!test_bit(FLG_L1_UINT, &st->l1.Flags)) +#endif if (st->l1.l1m.state != ST_L1_F6) { FsmChangeState(fi, ST_L1_F3); st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); @@ -529,7 +566,7 @@ l1_timer_deact(struct FsmInst *fi, int event, void *arg) } static void -l1_activate(struct FsmInst *fi, int event, void *arg) +l1_activate_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -547,9 +584,9 @@ l1_activate_no(struct FsmInst *fi, int event, void *arg) } } -static struct FsmNode L1DFnList[] HISAX_INITDATA = +static struct FsmNode L1SFnList[] HISAX_INITDATA = { - {ST_L1_F3, EV_PH_ACTIVATE, l1_activate}, + {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F3, EV_RESET_IND, l1_reset}, @@ -564,10 +601,10 @@ static struct FsmNode L1DFnList[] HISAX_INITDATA = {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F7, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F8, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F3, EV_POWER_UP, l1_power_up}, + {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, {ST_L1_F4, EV_RSYNC_IND, l1_go_F5}, {ST_L1_F6, EV_RSYNC_IND, l1_go_F8}, {ST_L1_F7, EV_RSYNC_IND, l1_go_F8}, @@ -595,7 +632,68 @@ static struct FsmNode L1DFnList[] HISAX_INITDATA = {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode)) +#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) + +#ifdef HISAX_UINTERFACE +static void +l1_deact_req_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_RESET); + FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); + test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); +} + +static void +l1_power_up_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); +} + +static void +l1_info0_ind(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_DEACT); +} + +static void +l1_activate_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL); +} + +static struct FsmNode L1UFnList[] HISAX_INITDATA = +{ + {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u}, + {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u}, + {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind}, + {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_DEACT, EV_TIMER3, l1_timer3}, + {ST_L1_SYNC2, EV_TIMER3, l1_timer3}, + {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act}, + {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, +}; + +#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) + +#endif static void l1b_activate(struct FsmInst *fi, int event, void *arg) @@ -645,11 +743,18 @@ static struct FsmNode L1BFnList[] HISAX_INITDATA = HISAX_INITFUNC(void Isdnl1New(void)) { - l1fsm_d.state_count = L1D_STATE_COUNT; - l1fsm_d.event_count = L1_EVENT_COUNT; - l1fsm_d.strEvent = strL1Event; - l1fsm_d.strState = strL1DState; - FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT); +#ifdef HISAX_UINTERFACE + l1fsm_u.state_count = L1U_STATE_COUNT; + l1fsm_u.event_count = L1_EVENT_COUNT; + l1fsm_u.strEvent = strL1Event; + l1fsm_u.strState = strL1UState; + FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); +#endif + l1fsm_s.state_count = L1S_STATE_COUNT; + l1fsm_s.event_count = L1_EVENT_COUNT; + l1fsm_s.strEvent = strL1Event; + l1fsm_s.strState = strL1SState; + FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); l1fsm_b.state_count = L1B_STATE_COUNT; l1fsm_b.event_count = L1_EVENT_COUNT; l1fsm_b.strEvent = strL1Event; @@ -659,7 +764,10 @@ HISAX_INITFUNC(void Isdnl1New(void)) void Isdnl1Free(void) { - FsmFree(&l1fsm_d); +#ifdef HISAX_UINTERFACE + FsmFree(&l1fsm_u); +#endif + FsmFree(&l1fsm_s); FsmFree(&l1fsm_b); } @@ -677,7 +785,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg) case (PH_ACTIVATE | REQUEST): if (cs->debug) debugl1(cs, "PH_ACTIVATE_REQ %s", - strL1DState[st->l1.l1m.state]); + st->l1.l1m.fsm->strState[st->l1.l1m.state]); if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else { @@ -757,8 +865,16 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) { st->l1.hardware = cs; st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm_d; + st->l1.l1m.fsm = &l1fsm_s; st->l1.l1m.state = ST_L1_F3; + st->l1.Flags = 0; +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) { + st->l1.l1m.fsm = &l1fsm_u; + st->l1.l1m.state = ST_L1_RESET; + st->l1.Flags = FLG_L1_UINT; + } +#endif st->l1.l1m.debug = cs->debug; st->l1.l1m.userdata = st; st->l1.l1m.userint = 0; @@ -768,7 +884,6 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) setstack_manager(st); st->l1.stlistp = &(cs->stlist); st->l2.l2l1 = dch_l2l1; - st->l1.Flags = 0; cs->setstack_d(st, cs); } diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index c20706553..b4e473670 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -234,7 +234,7 @@ no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic) extern void setstack_dss1(struct PStack *st); #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 extern void setstack_ni1(struct PStack *st); #endif @@ -356,7 +356,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp) setstack_dss1(st); } else #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 if (st->protocol == ISDN_PTYPE_NI1) { setstack_ni1(st); } else @@ -544,7 +544,6 @@ static struct FsmNode L3FnList[] HISAX_INITDATA = void l3_msg(struct PStack *st, int pr, void *arg) { - switch (pr) { case (DL_DATA | REQUEST): if (st->l3.l3m.state == ST_L3_LC_ESTAB) { diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index ee56447c8..831d788b5 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -1,4 +1,4 @@ -/* $Id: l3_1tr6.c,v 2.11 2000/06/26 08:59:14 keil Exp $ +/* $Id: l3_1tr6.c,v 2.12 2000/08/20 07:31:30 keil Exp $ * * German 1TR6 D-channel protocol * @@ -17,7 +17,7 @@ #include <linux/ctype.h> extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.11 $"; +const char *l3_1tr6_revision = "$Revision: 2.12 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -883,7 +883,7 @@ down1tr6(struct PStack *st, int pr, void *arg) } else { proc->chan = chan; chan->proc = proc; - memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 32ae7576f..8778bf3a0 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -721,6 +721,9 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) u_char *p, ie; int l, newpos, oldpos; int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; p = skb->data; /* skip cr */ @@ -729,20 +732,34 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) p += l; mt = *p++; oldpos = 0; -/* shift codeset procedure not implemented in the moment */ while ((p - skb->data) < skb->len) { - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; else - oldpos = newpos; + err_ureg++; } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; } ie = *p++; if (ie & 0x80) { @@ -752,12 +769,19 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) p += l; l += 2; } - if (l > getmax_ie_len(ie)) + if (!codeset && (l > getmax_ie_len(ie))) err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } } if (err_compr | err_ureg | err_len | err_seq) { if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d", + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", mt, err_compr, err_ureg, err_len, err_seq); if (err_compr) return(ERR_IE_COMPREHENSION); @@ -959,7 +983,7 @@ l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) #if EXT_BEARER_CAPS -u_char * +static u_char * EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb @@ -1024,7 +1048,7 @@ EncodeASyncParams(u_char * p, u_char si2) return p + 3; } -u_char +static u_char EncodeSyncParams(u_char si2, u_char ai) { @@ -1889,6 +1913,16 @@ l3dss1_proceed_req(struct l3_process *pc, u_char pr, pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); } +static void +l3dss1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + /********************************************/ /* deliver a incoming display message to HL */ /********************************************/ @@ -1926,7 +1960,7 @@ l3dss1_progress(struct l3_process *pc, u_char pr, void *arg) if (p[1] != 2) { err = 1; pc->para.cause = 100; - } else if (p[2] & 0x60) { + } else if (!(p[2] & 0x70)) { switch (p[2]) { case 0x80: case 0x81: @@ -2030,9 +2064,22 @@ l3dss1_information(struct l3_process *pc, u_char pr, void *arg) { int ret; struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; ret = check_infoelements(pc, skb, ie_INFORMATION); - l3dss1_std_ie_err(pc, ret); + if (ret) + l3dss1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } } /******************************/ @@ -2258,6 +2305,16 @@ l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg) } static void +l3dss1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3dss1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { @@ -2276,6 +2333,7 @@ static void l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2315,6 +2373,7 @@ static void l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2324,6 +2383,7 @@ static void l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); @@ -2713,32 +2773,36 @@ static struct stateentry downstatelist[] = CC_SETUP | REQUEST, l3dss1_setup_req}, {SBIT(0), CC_RESUME | REQUEST, l3dss1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(12), CC_RELEASE | REQUEST, l3dss1_release_req}, {ALL_STATES, CC_RESTART | REQUEST, l3dss1_restart}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_IGNORE | REQUEST, l3dss1_reset}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_REJECT | REQUEST, l3dss1_reject_req}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(6) | SBIT(9), + {SBIT(6), + CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3dss1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), CC_ALERTING | REQUEST, l3dss1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9), + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), CC_SETUP | RESPONSE, l3dss1_setup_rsp}, {SBIT(10), CC_SUSPEND | REQUEST, l3dss1_suspend_req}, - {SBIT(6), - CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(7) | SBIT(9), + {SBIT(7) | SBIT(9) | SBIT(25), CC_REDIR | REQUEST, l3dss1_redir_req}, {SBIT(6), CC_REDIR | REQUEST, l3dss1_redir_req_early}, {SBIT(9) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, + {SBIT(25), + CC_T302, l3dss1_t302}, {SBIT(1), CC_T303, l3dss1_t303}, {SBIT(2), @@ -3081,7 +3145,7 @@ dss1down(struct PStack *st, int pr, void *arg) if ((proc = dss1_new_l3_process(st, cr))) { proc->chan = chan; chan->proc = proc; - memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c new file mode 100644 index 000000000..ec28539a7 --- /dev/null +++ b/drivers/isdn/hisax/l3ni1.c @@ -0,0 +1,3171 @@ +// $Id: l3ni1.c,v 2.3 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. Thanks also for the +// code provided by Ragnar Paulson and Will Scales. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#define __NO_VERSION__ +#include "hisax.h" +#include "isdnl3.h" +#include "l3ni1.h" +#include <linux/ctype.h> + +extern char *HiSax_getrev(const char *revision); +const char *ni1_revision = "$Revision: 2.3 $"; + +#define EXT_BEARER_CAPS 1 + +#define MsgHead(ptr, cref, mty) \ + *ptr++ = 0x8; \ + if (cref == -1) { \ + *ptr++ = 0x0; \ + } else { \ + *ptr++ = 0x1; \ + *ptr++ = cref^0x80; \ + } \ + *ptr++ = mty + + +/**********************************************/ +/* get a new invoke id for remote operations. */ +/* Only a return value != 0 is valid */ +/**********************************************/ +static unsigned char new_invoke_id(struct PStack *p) +{ + unsigned char retval; + int flags,i; + + i = 32; /* maximum search depth */ + + save_flags(flags); + cli(); + + retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ + while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { + p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; + i--; + } + if (i) { + while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7))) + retval++; + } else + retval = 0; + p->prot.ni1.last_invoke_id = retval; + p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); + restore_flags(flags); + + return(retval); +} /* new_invoke_id */ + +/*************************/ +/* free a used invoke id */ +/*************************/ +static void free_invoke_id(struct PStack *p, unsigned char id) +{ int flags; + + if (!id) return; /* 0 = invalid value */ + + save_flags(flags); + cli(); + p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); + restore_flags(flags); +} /* free_invoke_id */ + + +/**********************************************************/ +/* create a new l3 process and fill in ni1 specific data */ +/**********************************************************/ +static struct l3_process +*ni1_new_l3_process(struct PStack *st, int cr) +{ struct l3_process *proc; + + if (!(proc = new_l3_process(st, cr))) + return(NULL); + + proc->prot.ni1.invoke_id = 0; + proc->prot.ni1.remote_operation = 0; + proc->prot.ni1.uus1_data[0] = '\0'; + + return(proc); +} /* ni1_new_l3_process */ + +/************************************************/ +/* free a l3 process and all ni1 specific data */ +/************************************************/ +static void +ni1_release_l3_process(struct l3_process *p) +{ + free_invoke_id(p->st,p->prot.ni1.invoke_id); + release_l3_process(p); +} /* ni1_release_l3_process */ + +/********************************************************/ +/* search a process with invoke id id and dummy callref */ +/********************************************************/ +static struct l3_process * +l3ni1_search_dummy_proc(struct PStack *st, int id) +{ struct l3_process *pc = st->l3.proc; /* start of processes */ + + if (!id) return(NULL); + + while (pc) + { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id)) + return(pc); + pc = pc->next; + } + return(NULL); +} /* l3ni1_search_dummy_proc */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return result is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_RES; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen); +} /* l3ni1_dummy_return_result */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return error is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_error_return(struct PStack *st, int id, ulong error) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= error; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error); +} /* l3ni1_error_return */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a invoke is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_invoke(struct PStack *st, int cr, int id, + int ident, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + + l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", + (cr == -1) ? "local" : "broadcast",id,ident,nlen); + if (cr >= -1) return; /* ignore local data */ + + cs = st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_BRD; + ic.parm.ni1_io.hl_id = id; + ic.parm.ni1_io.ll_id = 0; + ic.parm.ni1_io.proc = ident; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + + cs->iif.statcallb(&ic); +} /* l3ni1_dummy_invoke */ + +static void +l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, + int cr, u_char * p) +{ + int qd_len = 0; + unsigned char nlen = 0, ilen, cp_tag; + int ident, id; + ulong err_ret; + + if (pc) + st = pc->st; /* valid Stack */ + else + if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ + + p++; + qd_len = *p++; + if (qd_len == 0) { + l3_debug(st, "qd_len == 0"); + return; + } + if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ + l3_debug(st, "supplementary service != 0x11"); + return; + } + while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ + p++; + qd_len--; + } + if (qd_len < 2) { + l3_debug(st, "qd_len < 2"); + return; + } + p++; + qd_len--; + if ((*p & 0xE0) != 0xA0) { /* class and form */ + l3_debug(st, "class and form != 0xA0"); + return; + } + + cp_tag = *p & 0x1F; /* remember tag value */ + + p++; + qd_len--; + if (qd_len < 1) + { l3_debug(st, "qd_len < 1"); + return; + } + if (*p & 0x80) + { /* length format indefinite or limited */ + nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ + if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || + (nlen > 1)) + { l3_debug(st, "length format error or not implemented"); + return; + } + if (nlen == 1) + { nlen = *p++; /* complete length */ + qd_len--; + } + else + { qd_len -= 2; /* trailing null bytes */ + if ((*(p+qd_len)) || (*(p+qd_len+1))) + { l3_debug(st,"length format indefinite error"); + return; + } + nlen = qd_len; + } + } + else + { nlen = *p++; + qd_len--; + } + if (qd_len < nlen) + { l3_debug(st, "qd_len < nlen"); + return; + } + qd_len -= nlen; + + if (nlen < 2) + { l3_debug(st, "nlen < 2"); + return; + } + if (*p != 0x02) + { /* invoke identifier tag */ + l3_debug(st, "invoke identifier tag !=0x02"); + return; + } + p++; + nlen--; + if (*p & 0x80) + { /* length format */ + l3_debug(st, "invoke id length format 2"); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + id = 0; + while (ilen > 0) + { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ + ilen--; + } + + switch (cp_tag) { /* component tag */ + case 1: /* invoke */ + if (nlen < 2) { + l3_debug(st, "nlen < 2 22"); + return; + } + if (*p != 0x02) { /* operation value */ + l3_debug(st, "operation value !=0x02"); + return; + } + p++; + nlen--; + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) { + l3_debug(st, "ilen > nlen || ilen == 0 22"); + return; + } + nlen -= ilen; + ident = 0; + while (ilen > 0) { + ident = (ident << 8) | (*p++ & 0xFF); + ilen--; + } + + if (!pc) + { + l3ni1_dummy_invoke(st, cr, id, ident, p, nlen); + return; + } + l3_debug(st, "invoke break"); + break; + case 2: /* return result */ + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_return_result(st, id, p, nlen); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Diversion successfull */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = 0; /* success */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */ + else + l3_debug(st,"return error unknown identifier"); + break; + case 3: /* return error */ + err_ret = 0; + if (nlen < 2) + { l3_debug(st, "return error nlen < 2"); + return; + } + if (*p != 0x02) + { /* result tag */ + l3_debug(st, "invoke error tag !=0x02"); + return; + } + p++; + nlen--; + if (*p > 4) + { /* length format */ + l3_debug(st, "invoke return errlen > 4 "); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "error return ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + while (ilen > 0) + { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ + ilen--; + } + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_error_return(st, id, err_ret); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Deflection error */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = err_ret; /* result */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); + } /* Deflection error */ + else + l3_debug(st,"return result unknown identifier"); + break; + default: + l3_debug(st, "facility default break tag=0x%02x",cp_tag); + break; + } +} + +static void +l3ni1_message(struct l3_process *pc, u_char mt) +{ + struct sk_buff *skb; + u_char *p; + + if (!(skb = l3_alloc_skb(4))) + return; + p = skb_put(skb, 4); + MsgHead(p, pc->callref, mt); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, mt); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + MsgHead(p, pc->callref, MT_STATUS); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + + *p++ = IE_CALL_STATE; + *p++ = 0x1; + *p++ = pc->state & 0x3f; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) +{ + /* This routine is called if here was no SETUP made (checks in ni1up and in + * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code + * MT_STATUS_ENQUIRE in the NULL state is handled too + */ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + switch (pc->para.cause) { + case 81: /* invalid callreference */ + case 88: /* incomp destination */ + case 96: /* mandory IE missing */ + case 100: /* invalid IE contents */ + case 101: /* incompatible Callstate */ + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + break; + default: + printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n", + pc->para.cause); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + ni1_release_l3_process(pc); +} + +static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, + IE_USER_USER, -1}; +static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; +static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, + IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, + IE_CALLED_PN, -1}; +static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | + IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; +static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, + IE_SIGNAL, IE_USER_USER, -1}; +/* a RELEASE_COMPLETE with errors don't require special actions +static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +*/ +static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, + IE_DISPLAY, -1}; +static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, + IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS, + IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, + IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, + IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | + IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; +static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; +static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +/* not used + * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, + * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; + * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; + * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | + * IE_MANDATORY, -1}; + */ +static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; +static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1}; +static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1}; + +struct ie_len { + int ie; + int len; +}; + +static +struct ie_len max_ie_len[] = { + {IE_SEGMENT, 4}, + {IE_BEARER, 12}, + {IE_CAUSE, 32}, + {IE_CALL_ID, 10}, + {IE_CALL_STATE, 3}, + {IE_CHANNEL_ID, 34}, + {IE_FACILITY, 255}, + {IE_PROGRESS, 4}, + {IE_NET_FAC, 255}, + {IE_NOTIFY, 3}, + {IE_DISPLAY, 82}, + {IE_DATE, 8}, + {IE_KEYPAD, 34}, + {IE_SIGNAL, 3}, + {IE_INFORATE, 6}, + {IE_E2E_TDELAY, 11}, + {IE_TDELAY_SEL, 5}, + {IE_PACK_BINPARA, 3}, + {IE_PACK_WINSIZE, 4}, + {IE_PACK_SIZE, 4}, + {IE_CUG, 7}, + {IE_REV_CHARGE, 3}, + {IE_CALLING_PN, 24}, + {IE_CALLING_SUB, 23}, + {IE_CALLED_PN, 24}, + {IE_CALLED_SUB, 23}, + {IE_REDIR_NR, 255}, + {IE_TRANS_SEL, 255}, + {IE_RESTART_IND, 3}, + {IE_LLC, 18}, + {IE_HLC, 5}, + {IE_USER_USER, 131}, + {-1,0}, +}; + +static int +getmax_ie_len(u_char ie) { + int i = 0; + while (max_ie_len[i].ie != -1) { + if (max_ie_len[i].ie == ie) + return(max_ie_len[i].len); + i++; + } + return(255); +} + +static int +ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { + int ret = 1; + + while (*checklist != -1) { + if ((*checklist & 0xff) == ie) { + if (ie & 0x80) + return(-ret); + else + return(ret); + } + ret++; + checklist++; + } + return(0); +} + +static int +check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) +{ + int *cl = checklist; + u_char mt; + u_char *p, ie; + int l, newpos, oldpos; + int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; + + p = skb->data; + /* skip cr */ + p++; + l = (*p++) & 0xf; + p += l; + mt = *p++; + oldpos = 0; + while ((p - skb->data) < skb->len) { + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; + else + err_ureg++; + } + } + ie = *p++; + if (ie & 0x80) { + l = 1; + } else { + l = *p++; + p += l; + l += 2; + } + if (!codeset && (l > getmax_ie_len(ie))) + err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } + } + if (err_compr | err_ureg | err_len | err_seq) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", + mt, err_compr, err_ureg, err_len, err_seq); + if (err_compr) + return(ERR_IE_COMPREHENSION); + if (err_ureg) + return(ERR_IE_UNRECOGNIZED); + if (err_len) + return(ERR_IE_LENGTH); + if (err_seq) + return(ERR_IE_SEQUENCE); + } + return(0); +} + +/* verify if a message type exists and contain no IE error */ +static int +l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) +{ + switch (mt) { + case MT_ALERTING: + case MT_CALL_PROCEEDING: + case MT_CONNECT: + case MT_CONNECT_ACKNOWLEDGE: + case MT_DISCONNECT: + case MT_INFORMATION: + case MT_FACILITY: + case MT_NOTIFY: + case MT_PROGRESS: + case MT_RELEASE: + case MT_RELEASE_COMPLETE: + case MT_SETUP: + case MT_SETUP_ACKNOWLEDGE: + case MT_RESUME_ACKNOWLEDGE: + case MT_RESUME_REJECT: + case MT_SUSPEND_ACKNOWLEDGE: + case MT_SUSPEND_REJECT: + case MT_USER_INFORMATION: + case MT_RESTART: + case MT_RESTART_ACKNOWLEDGE: + case MT_CONGESTION_CONTROL: + case MT_STATUS: + case MT_STATUS_ENQUIRY: + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt); + break; + case MT_RESUME: /* RESUME only in user->net */ + case MT_SUSPEND: /* SUSPEND only in user->net */ + default: + if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt); + pc->para.cause = 97; + l3ni1_status_send(pc, 0, NULL); + return(1); + } + return(0); +} + +static void +l3ni1_std_ie_err(struct l3_process *pc, int ret) { + + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check_infoelements ret %d", ret); + switch(ret) { + case 0: + break; + case ERR_IE_COMPREHENSION: + pc->para.cause = 96; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_UNRECOGNIZED: + pc->para.cause = 99; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_LENGTH: + pc->para.cause = 100; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_SEQUENCE: + default: + break; + } +} + +static int +l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { + u_char *p; + + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + p++; + if (*p != 1) { /* len for BRI = 1 */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid len %d", *p); + return (-2); + } + p++; + if (*p & 0x60) { /* only base rate interface */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid %x", *p); + return (-3); + } + return(*p & 0x3); + } else + return(-1); +} + +static int +l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { + u_char l, i=0; + u_char *p; + + p = skb->data; + pc->para.cause = 31; + pc->para.loc = 0; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + p++; + l = *p++; + if (l>30) + return(1); + if (l) { + pc->para.loc = *p++; + l--; + } else { + return(2); + } + if (l && !(pc->para.loc & 0x80)) { + l--; + p++; /* skip recommendation */ + } + if (l) { + pc->para.cause = *p++; + l--; + if (!(pc->para.cause & 0x80)) + return(3); + } else + return(4); + while (l && (i<6)) { + pc->para.diag[i++] = *p++; + l--; + } + } else + return(-1); + return(0); +} + +static void +l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, cmd); + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_msg_with_uus */ + +static void +l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) +{ + StopAllL3Timer(pc); + newl3state(pc, 19); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_RELEASE); + else + l3ni1_msg_with_uus(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret); + } else if (ret < 0) + pc->para.cause = NO_CAUSE; + StopAllL3Timer(pc); + newl3state(pc, 0); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); + ni1_release_l3_process(pc); +} + +#if EXT_BEARER_CAPS + +static u_char * +EncodeASyncParams(u_char * p, u_char si2) +{ // 7c 06 88 90 21 42 00 bb + + p[0] = 0; + p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 + p[2] = 0x80; + if (si2 & 32) // 7 data bits + + p[2] += 16; + else // 8 data bits + + p[2] += 24; + + if (si2 & 16) // 2 stop bits + + p[2] += 96; + else // 1 stop bit + + p[2] += 32; + + if (si2 & 8) // even parity + + p[2] += 2; + else // no parity + + p[2] += 3; + + switch (si2 & 0x07) { + case 0: + p[0] = 66; // 1200 bit/s + + break; + case 1: + p[0] = 88; // 1200/75 bit/s + + break; + case 2: + p[0] = 87; // 75/1200 bit/s + + break; + case 3: + p[0] = 67; // 2400 bit/s + + break; + case 4: + p[0] = 69; // 4800 bit/s + + break; + case 5: + p[0] = 72; // 9600 bit/s + + break; + case 6: + p[0] = 73; // 14400 bit/s + + break; + case 7: + p[0] = 75; // 19200 bit/s + + break; + } + return p + 3; +} + +static u_char +EncodeSyncParams(u_char si2, u_char ai) +{ + + switch (si2) { + case 0: + return ai + 2; // 1200 bit/s + + case 1: + return ai + 24; // 1200/75 bit/s + + case 2: + return ai + 23; // 75/1200 bit/s + + case 3: + return ai + 3; // 2400 bit/s + + case 4: + return ai + 5; // 4800 bit/s + + case 5: + return ai + 8; // 9600 bit/s + + case 6: + return ai + 9; // 14400 bit/s + + case 7: + return ai + 11; // 19200 bit/s + + case 8: + return ai + 14; // 48000 bit/s + + case 9: + return ai + 15; // 56000 bit/s + + case 15: + return ai + 40; // negotiate bit/s + + default: + break; + } + return ai; +} + + +static u_char +DecodeASyncParams(u_char si2, u_char * p) +{ + u_char info; + + switch (p[5]) { + case 66: // 1200 bit/s + + break; // si2 don't change + + case 88: // 1200/75 bit/s + + si2 += 1; + break; + case 87: // 75/1200 bit/s + + si2 += 2; + break; + case 67: // 2400 bit/s + + si2 += 3; + break; + case 69: // 4800 bit/s + + si2 += 4; + break; + case 72: // 9600 bit/s + + si2 += 5; + break; + case 73: // 14400 bit/s + + si2 += 6; + break; + case 75: // 19200 bit/s + + si2 += 7; + break; + } + + info = p[7] & 0x7f; + if ((info & 16) && (!(info & 8))) // 7 data bits + + si2 += 32; // else 8 data bits + + if ((info & 96) == 96) // 2 stop bits + + si2 += 16; // else 1 stop bit + + if ((info & 2) && (!(info & 1))) // even parity + + si2 += 8; // else no parity + + return si2; +} + + +static u_char +DecodeSyncParams(u_char si2, u_char info) +{ + info &= 0x7f; + switch (info) { + case 40: // bit/s negotiation failed ai := 165 not 175! + + return si2 + 15; + case 15: // 56000 bit/s failed, ai := 0 not 169 ! + + return si2 + 9; + case 14: // 48000 bit/s + + return si2 + 8; + case 11: // 19200 bit/s + + return si2 + 7; + case 9: // 14400 bit/s + + return si2 + 6; + case 8: // 9600 bit/s + + return si2 + 5; + case 5: // 4800 bit/s + + return si2 + 4; + case 3: // 2400 bit/s + + return si2 + 3; + case 23: // 75/1200 bit/s + + return si2 + 2; + case 24: // 1200/75 bit/s + + return si2 + 1; + default: // 1200 bit/s + + return si2; + } +} + +static u_char +DecodeSI2(struct sk_buff *skb) +{ + u_char *p; //, *pend=skb->data + skb->len; + + if ((p = findie(skb->data, skb->len, 0x7c, 0))) { + switch (p[4] & 0x0f) { + case 0x01: + if (p[1] == 0x04) // sync. Bitratenadaption + + return DecodeSyncParams(160, p[5]); // V.110/X.30 + + else if (p[1] == 0x06) // async. Bitratenadaption + + return DecodeASyncParams(192, p); // V.110/X.30 + + break; + case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption + if (p[1] > 3) + return DecodeSyncParams(176, p[5]); // V.120 + break; + } + } + return 0; +} + +#endif + + +static void +l3ni1_setup_req(struct l3_process *pc, u_char pr, + void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + + u_char *teln; + u_char *sub; + u_char *sp; + int l; + + MsgHead(p, pc->callref, MT_SETUP); + + teln = pc->para.setup.phone; + + *p++ = 0xa1; /* complete indicator */ + /* + * Set Bearer Capability, Map info from 1TR6-convention to NI1 + */ + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_BEARER; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_BEARER; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + + sub = NULL; + sp = teln; + while (*sp) { + if ('.' == *sp) { + sub = sp; + *sp = 0; + } else + sp++; + } + + *p++ = IE_KEYPAD; + *p++ = strlen(teln); + while (*teln) + *p++ = (*teln++) & 0x7F; + + if (sub) + *sub++ = '.'; + +#if EXT_BEARER_CAPS + if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x04; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); + } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 + + *p++ = IE_LLC; + *p++ = 0x05; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x28; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); + *p++ = 0x82; + } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x06; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + p = EncodeASyncParams(p, pc->para.setup.si2 - 192); + } else { + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_LLC; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_LLC; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + } +#endif + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) +{ + return; +} + memcpy(skb_put(skb, l), tmp, l); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T303, CC_T303); + newl3state(pc, 1); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 3); + L3AddTimer(&pc->timer, T310, CC_T310); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); +} + +static void +l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 2); + L3AddTimer(&pc->timer, T304, CC_T304); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); +} + +static void +l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret; + u_char cause = 0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "DISC get_cause ret(%d)", ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + ret = check_infoelements(pc, skb, ie_DISCONNECT); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) + cause = 99; + ret = pc->state; + newl3state(pc, 12); + if (cause) + newl3state(pc, 19); + if (11 != ret) + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); + else if (!cause) + l3ni1_release_req(pc, pr, NULL); + if (cause) { + l3ni1_message_cause(pc, MT_RELEASE, cause); + L3AddTimer(&pc->timer, T308, CC_T308_1); + } +} + +static void +l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T310 */ + newl3state(pc, 10); + pc->para.chargeinfo = 0; + /* here should inserted COLP handling KKe */ + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); +} + +static void +l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_ALERTING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T304 */ + newl3state(pc, 4); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); +} + +static void +l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + int bcfound = 0; + char tmp[80]; + struct sk_buff *skb = arg; + int id; + int err = 0; + + /* + * Bearer Capabilities + */ + p = skb->data; + /* only the first occurence 'll be detected ! */ + if ((p = findie(p, skb->len, 0x04, 0))) { + if ((p[1] < 2) || (p[1] > 11)) + err = 1; + else { + pc->para.setup.si2 = 0; + switch (p[2] & 0x7f) { + case 0x00: /* Speech */ + case 0x10: /* 3.1 Khz audio */ + pc->para.setup.si1 = 1; + break; + case 0x08: /* Unrestricted digital information */ + pc->para.setup.si1 = 7; +/* JIM, 05.11.97 I wanna set service indicator 2 */ +#if EXT_BEARER_CAPS + pc->para.setup.si2 = DecodeSI2(skb); +#endif + break; + case 0x09: /* Restricted digital information */ + pc->para.setup.si1 = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + pc->para.setup.si1 = 3; + break; + case 0x18: /* Video */ + pc->para.setup.si1 = 4; + break; + default: + err = 2; + break; + } + switch (p[3] & 0x7f) { + case 0x40: /* packed mode */ + pc->para.setup.si1 = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + pc->para.moderate = p[3] & 0x7f; + break; + default: + err = 3; + break; + } + } + if (pc->debug & L3_DEB_SI) + l3_debug(pc->st, "SI=%d, AI=%d", + pc->para.setup.si1, pc->para.setup.si2); + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", + p[1], p[2], p[3]); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bearer capabilities"); + /* ETS 300-104 1.3.3 */ + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* + * Channel Identification + */ + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((pc->para.bchannel = id)) { + if ((3 == id) && (0x10 == pc->para.moderate)) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid %x", + id); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + bcfound++; + } else + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bchannel, call waiting"); + bcfound++; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid ret %d", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_SETUP); + if (ERR_IE_COMPREHENSION == err) { + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) + iecpy(pc->para.setup.eazmsn, p, 1); + else + pc->para.setup.eazmsn[0] = 0; + + p = skb->data; + if ((p = findie(p, skb->len, 0x71, 0))) { + /* Called party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.eazmsn, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong called subaddress"); + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6c, 0))) { + pc->para.setup.plan = p[2]; + if (p[2] & 0x80) { + iecpy(pc->para.setup.phone, p, 1); + pc->para.setup.screen = 0; + } else { + iecpy(pc->para.setup.phone, p, 2); + pc->para.setup.screen = p[3]; + } + } else { + pc->para.setup.phone[0] = 0; + pc->para.setup.plan = 0; + pc->para.setup.screen = 0; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6d, 0))) { + /* Calling party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.phone, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong calling subaddress"); + } + newl3state(pc, 6); + if (err) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, err); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); +} + +static void +l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) +{ + ni1_release_l3_process(pc); +} + +static void +l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + u_char cause = 16; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + StopAllL3Timer(pc); + + MsgHead(p, pc->callref, MT_DISCONNECT); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 11); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T305, CC_T305); +} + +static void +l3ni1_setup_rsp(struct l3_process *pc, u_char pr, + void *arg) +{ + if (!pc->para.bchannel) + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "D-chan connect for waiting call"); + l3ni1_disconnect_req(pc, pr, arg); + return; + } + newl3state(pc, 8); + l3ni1_message(pc, MT_CONNECT); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T313, CC_T313); +} + +static void +l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + newl3state(pc, 10); + L3DelTimer(&pc->timer); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); +} + +static void +l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char cause = 21; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_release(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret, cause=0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "REL get_cause ret(%d)", ret); + } else if (ret<0) + pc->para.cause = NO_CAUSE; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } + if ((ret<0) && (pc->state != 11)) + cause = 96; + else if (ret>0) + cause = 100; + ret = check_infoelements(pc, skb, ie_RELEASE); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) + cause = 99; + if (cause) + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); + else + l3ni1_message(pc, MT_RELEASE_COMPLETE); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_alert_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 7); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_ALERTING); + else + l3ni1_msg_with_uus(pc, MT_ALERTING); +} + +static void +l3ni1_proceed_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 9); + l3ni1_message(pc, MT_CALL_PROCEEDING); + pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); +} + +static void +l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + +/********************************************/ +/* deliver a incoming display message to HL */ +/********************************************/ +static void +l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) +{ u_char len; + isdn_ctrl ic; + struct IsdnCardState *cs; + char *p; + + if (*infp++ != IE_DISPLAY) return; + if ((len = *infp++) > 80) return; /* total length <= 82 */ + if (!pc->chan) return; + + p = ic.parm.display; + while (len--) + *p++ = *infp++; + *p = '\0'; + ic.command = ISDN_STAT_DISPLAY; + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.arg = pc->chan->chan; + cs->iif.statcallb(&ic); +} /* l3ni1_deliver_display */ + + +static void +l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { + if (p[1] != 2) { + err = 1; + pc->para.cause = 100; + } else if (!(p[2] & 0x70)) { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + case 0x84: + case 0x85: + case 0x87: + case 0x8a: + switch (p[3]) { + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x88: + break; + default: + err = 2; + pc->para.cause = 100; + break; + } + break; + default: + err = 3; + pc->para.cause = 100; + break; + } + } + } else { + pc->para.cause = 96; + err = 4; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "progress error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_PROGRESS); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); +} + +static void +l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { + if (p[1] != 1) { + err = 1; + pc->para.cause = 100; + } else { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + break; + default: + pc->para.cause = 100; + err = 2; + break; + } + } + } else { + pc->para.cause = 96; + err = 3; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "notify error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_NOTIFY); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); +} + +static void +l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + + ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); + l3ni1_std_ie_err(pc, ret); + pc->para.cause = 30; /* response to STATUS_ENQUIRY */ + l3ni1_status_send(pc, pr, NULL); +} + +static void +l3ni1_information(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; + + ret = check_infoelements(pc, skb, ie_INFORMATION); + if (ret) + l3ni1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } +} + +/******************************/ +/* handle deflection requests */ +/******************************/ +static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + u_char *subp; + u_char len_phone = 0; + u_char len_sub = 0; + int l; + + + strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */ + if (!pc->chan->setup.phone[0]) + { pc->para.cause = -1; + l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */ + return; + } /* only uus */ + + if (pc->prot.ni1.invoke_id) + free_invoke_id(pc->st,pc->prot.ni1.invoke_id); + + if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st))) + return; + + MsgHead(p, pc->callref, MT_FACILITY); + + for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ + if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ + + *p++ = 0x1c; /* Facility info element */ + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ + *p++ = 0x91; /* remote operations protocol */ + *p++ = 0xa1; /* invoke component */ + + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ + *p++ = 0x02; /* invoke id tag, integer */ + *p++ = 0x01; /* length */ + *p++ = pc->prot.ni1.invoke_id; /* invoke id */ + *p++ = 0x02; /* operation value tag, integer */ + *p++ = 0x01; /* length */ + *p++ = 0x0D; /* Call Deflect */ + + *p++ = 0x30; /* sequence phone number */ + *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ + + *p++ = 0x30; /* Deflected to UserNumber */ + *p++ = len_phone+2+len_sub; /* length */ + *p++ = 0x80; /* NumberDigits */ + *p++ = len_phone; /* length */ + for (l = 0; l < len_phone; l++) + *p++ = pc->chan->setup.phone[l]; + + if (len_sub) + { *p++ = 0x04; /* called party subadress */ + *p++ = len_sub - 2; + while (*subp) *p++ = *subp++; + } + + *p++ = 0x01; /* screening identifier */ + *p++ = 0x01; + *p++ = pc->chan->setup.screen; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) return; + memcpy(skb_put(skb, l), tmp, l); + + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_redir_req */ + +/********************************************/ +/* handle deflection request in early state */ +/********************************************/ +static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) +{ + l3ni1_proceed_req(pc,pr,arg); + l3ni1_redir_req(pc,pr,arg); +} /* l3ni1_redir_req_early */ + +/***********************************************/ +/* handle special commands for this protocol. */ +/* Examples are call independant services like */ +/* remote operations with dummy callref. */ +/***********************************************/ +static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) +{ u_char id; + u_char temp[265]; + u_char *p = temp; + int i, l, proc_len; + struct sk_buff *skb; + struct l3_process *pc = NULL; + + switch (ic->arg) + { case NI1_CMD_INVOKE: + if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */ + + for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++) + i = i >> 8; /* add one byte */ + l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */ + if (l > 255) + return(-2); /* too long */ + + if (!(id = new_invoke_id(st))) + return(0); /* first get a invoke id -> return if no available */ + + i = -1; + MsgHead(p, i, MT_FACILITY); /* build message head */ + *p++ = 0x1C; /* Facility IE */ + *p++ = l; /* length of ie */ + *p++ = 0x91; /* remote operations */ + *p++ = 0xA1; /* invoke */ + *p++ = l - 3; /* length of invoke */ + *p++ = 0x02; /* invoke id tag */ + *p++ = 0x01; /* length is 1 */ + *p++ = id; /* invoke id */ + *p++ = 0x02; /* operation */ + *p++ = proc_len; /* length of operation */ + + for (i = proc_len; i; i--) + *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF; + memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */ + l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */ + + if (ic->parm.ni1_io.timeout > 0) + if (!(pc = ni1_new_l3_process(st, -1))) + { free_invoke_id(st, id); + return(-2); + } + pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */ + pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */ + + if (!(skb = l3_alloc_skb(l))) + { free_invoke_id(st, id); + if (pc) ni1_release_l3_process(pc); + return(-2); + } + memcpy(skb_put(skb, l), temp, l); + + if (pc) + { pc->prot.ni1.invoke_id = id; /* remember id */ + L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST); + } + + l3_msg(st, DL_DATA | REQUEST, skb); + ic->parm.ni1_io.hl_id = id; /* return id */ + return(0); + + case NI1_CMD_INVOKE_ABORT: + if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id))) + { L3DelTimer(&pc->timer); /* remove timer */ + ni1_release_l3_process(pc); + return(0); + } + else + { l3_debug(st, "l3ni1_cmd_global abort unknown id"); + return(-2); + } + break; + + default: + l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg); + return(-1); + } /* switch ic-> arg */ + return(-1); +} /* l3ni1_cmd_global */ + +static void +l3ni1_io_timer(struct l3_process *pc) +{ isdn_ctrl ic; + struct IsdnCardState *cs = pc->st->l1.hardware; + + L3DelTimer(&pc->timer); /* remove timer */ + + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= -1; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + + ni1_release_l3_process(pc); +} /* l3ni1_io_timer */ + +static void +l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int callState = 0; + p = skb->data; + + if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) + callState = *p; + } + if (callState == 0) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 + * set down layer 3 without sending any message + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } else { + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); + } +} + +static void +l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) +{ +} + +static void +l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) +{ + if (pc->N303 > 0) { + pc->N303--; + L3DelTimer(&pc->timer); + l3ni1_setup_req(pc, pr, arg); + } else { + L3DelTimer(&pc->timer); + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); + +} + +static void +l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + u_char cause = 16; + + L3DelTimer(&pc->timer); + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 19); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); +} + +static void +l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 19); + L3DelTimer(&pc->timer); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_2); +} + +static void +l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 19); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); +} + +static void +l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_status(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int ret; + u_char cause = 0, callState = 0; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS get_cause ret(%d)",ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) { + callState = *p; + if (!ie_in_set(pc, *p, l3_valid_states)) + cause = 100; + } else + cause = 100; + } else + cause = 96; + if (!cause) { /* no error before */ + ret = check_infoelements(pc, skb, ie_STATUS); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if (ERR_IE_UNRECOGNIZED == ret) + cause = 99; + } + if (cause) { + u_char tmp; + + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); + tmp = pc->para.cause; + pc->para.cause = cause; + l3ni1_status_send(pc, 0, NULL); + if (cause == 99) + pc->para.cause = tmp; + else + return; + } + cause = pc->para.cause; + if (((cause & 0x7f) == 111) && (callState == 0)) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... + * if received MT_STATUS with cause == 111 and call + * state == 0, then we must set down layer 3 + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_FACILITY); + l3ni1_std_ie_err(pc, ret); + { + u_char *p; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } +} + +static void +l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->chan->setup.phone; + + MsgHead(p, pc->callref, MT_SUSPEND); + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 15); + L3AddTimer(&pc->timer, T319, CC_T319); +} + +static void +l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + L3DelTimer(&pc->timer); + newl3state(pc, 0); + pc->para.cause = NO_CAUSE; + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); + /* We don't handle suspend_ack for IE errors now */ + if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSPACK check ie(%d)",ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->para.setup.phone; + + MsgHead(p, pc->callref, MT_RESUME); + + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "RES wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 17); + L3AddTimer(&pc->timer, T318, CC_T318); +} + +static void +l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) > 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack without chid (ret %d)", id); + pc->para.cause = 96; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 0); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[32]; + u_char *p; + u_char ri, ch = 0, chan = 0; + int l; + struct sk_buff *skb = arg; + struct l3_process *up; + + newl3state(pc, 2); + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { + ri = p[2]; + l3_debug(pc->st, "Restart %x", ri); + } else { + l3_debug(pc->st, "Restart without restart IE"); + ri = 0x86; + } + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + chan = p[2] & 3; + ch = p[2]; + if (pc->st->l3.debug) + l3_debug(pc->st, "Restart for channel %d", chan); + } + newl3state(pc, 2); + up = pc->st->l3.proc; + while (up) { + if ((ri & 7) == 7) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + else if (up->para.bchannel == chan) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + up = up->next; + } + p = tmp; + MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); + if (chan) { + *p++ = IE_CHANNEL_ID; + *p++ = 1; + *p++ = ch | 0x80; + } + *p++ = 0x79; /* RESTART Ind */ + *p++ = 1; + *p++ = ri; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 0); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) +{ + pc->para.cause = 0x29; /* Temporary failure */ + pc->para.loc = 0; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 0); + pc->para.cause = 0x1b; /* Destination out of order */ + pc->para.loc = 0; + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + release_l3_process(pc); +} + +static void +l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T309, CC_T309); + l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); +} + +static void +l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + + pc->para.cause = 0x1F; /* normal, unspecified */ + l3ni1_status_send(pc, 0, NULL); +} + +static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState ) +{ + u_char * p; + char * pSPID; + struct Channel * pChan = pc->st->lli.userdata; + int l; + + if ( skb ) + dev_kfree_skb( skb); + + if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) ) + { + printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + return; + } + + l = strlen( ++pSPID ); + if ( !( skb = l3_alloc_skb( 5+l ) ) ) + { + printk( KERN_ERR "HiSax can't get memory to send SPID\n" ); + return; + } + + p = skb_put( skb, 5 ); + *p++ = PROTO_DIS_EURO; + *p++ = 0; + *p++ = MT_INFORMATION; + *p++ = IE_SPID; + *p++ = l; + + memcpy( skb_put( skb, l ), pSPID, l ); + + newl3state( pc, iNewState ); + + L3DelTimer( &pc->timer ); + L3AddTimer( &pc->timer, TSPID, CC_TSPID ); + + pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb ); +} + +static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg ) +{ + l3ni1_SendSpid( pc, pr, arg, 20 ); +} + +void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) +{ + struct sk_buff *skb = arg; + + if ( skb->data[ 1 ] == 0 ) + if ( skb->data[ 3 ] == IE_ENDPOINT_ID ) + { + L3DelTimer( &pc->timer ); + newl3state( pc, 0 ); + l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL ); + } + dev_kfree_skb( skb); +} + +static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg ) +{ + if ( pc->state < 22 ) + l3ni1_SendSpid( pc, pr, arg, pc->state+1 ); + else + { + L3DelTimer( &pc->timer ); + dev_kfree_skb( arg); + + printk( KERN_ERR "SPID not accepted\n" ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + } +} + +/* *INDENT-OFF* */ +static struct stateentry downstatelist[] = +{ + {SBIT(0), + CC_SETUP | REQUEST, l3ni1_setup_req}, + {SBIT(0), + CC_RESUME | REQUEST, l3ni1_resume_req}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(12), + CC_RELEASE | REQUEST, l3ni1_release_req}, + {ALL_STATES, + CC_RESTART | REQUEST, l3ni1_restart}, + {SBIT(6) | SBIT(25), + CC_IGNORE | REQUEST, l3ni1_reset}, + {SBIT(6) | SBIT(25), + CC_REJECT | REQUEST, l3ni1_reject_req}, + {SBIT(6) | SBIT(25), + CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req}, + {SBIT(6), + CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3ni1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), + CC_ALERTING | REQUEST, l3ni1_alert_req}, + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), + CC_SETUP | RESPONSE, l3ni1_setup_rsp}, + {SBIT(10), + CC_SUSPEND | REQUEST, l3ni1_suspend_req}, + {SBIT(7) | SBIT(9) | SBIT(25), + CC_REDIR | REQUEST, l3ni1_redir_req}, + {SBIT(6), + CC_REDIR | REQUEST, l3ni1_redir_req_early}, + {SBIT(9) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(25), + CC_T302, l3ni1_t302}, + {SBIT(1), + CC_T303, l3ni1_t303}, + {SBIT(2), + CC_T304, l3ni1_t304}, + {SBIT(3), + CC_T310, l3ni1_t310}, + {SBIT(8), + CC_T313, l3ni1_t313}, + {SBIT(11), + CC_T305, l3ni1_t305}, + {SBIT(15), + CC_T319, l3ni1_t319}, + {SBIT(17), + CC_T318, l3ni1_t318}, + {SBIT(19), + CC_T308_1, l3ni1_t308_1}, + {SBIT(19), + CC_T308_2, l3ni1_t308_2}, + {SBIT(10), + CC_T309, l3ni1_dl_release}, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), + CC_TSPID, l3ni1_spid_tout }, +}; + +#define DOWNSLLEN \ + (sizeof(downstatelist) / sizeof(struct stateentry)) + +static struct stateentry datastatelist[] = +{ + {ALL_STATES, + MT_STATUS_ENQUIRY, l3ni1_status_enq}, + {ALL_STATES, + MT_FACILITY, l3ni1_facility}, + {SBIT(19), + MT_STATUS, l3ni1_release_ind}, + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_SETUP, l3ni1_setup}, + {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | + SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_SETUP, l3ni1_dummy}, + {SBIT(1) | SBIT(2), + MT_CALL_PROCEEDING, l3ni1_call_proc}, + {SBIT(1), + MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack}, + {SBIT(2) | SBIT(3), + MT_ALERTING, l3ni1_alerting}, + {SBIT(2) | SBIT(3), + MT_PROGRESS, l3ni1_progress}, + {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_INFORMATION, l3ni1_information}, + {SBIT(10) | SBIT(11) | SBIT(15), + MT_NOTIFY, l3ni1_notify}, + {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_RELEASE_COMPLETE, l3ni1_release_cmpl}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), + MT_RELEASE, l3ni1_release}, + {SBIT(19), MT_RELEASE, l3ni1_release_ind}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), + MT_DISCONNECT, l3ni1_disconnect}, + {SBIT(19), + MT_DISCONNECT, l3ni1_dummy}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), + MT_CONNECT, l3ni1_connect}, + {SBIT(8), + MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack}, + {SBIT(15), + MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack}, + {SBIT(15), + MT_SUSPEND_REJECT, l3ni1_suspend_rej}, + {SBIT(17), + MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack}, + {SBIT(17), + MT_RESUME_REJECT, l3ni1_resume_rej}, +}; + +#define DATASLLEN \ + (sizeof(datastatelist) / sizeof(struct stateentry)) + +static struct stateentry globalmes_list[] = +{ + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_RESTART, l3ni1_global_restart}, +/* {SBIT(1), + MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack}, +*/ + { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, +}; +#define GLOBALM_LEN \ + (sizeof(globalmes_list) / sizeof(struct stateentry)) + +static struct stateentry manstatelist[] = +{ + {SBIT(2), + DL_ESTABLISH | INDICATION, l3ni1_dl_reset}, + {SBIT(10), + DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status}, + {SBIT(10), + DL_RELEASE | INDICATION, l3ni1_dl_reestablish}, + {ALL_STATES, + DL_RELEASE | INDICATION, l3ni1_dl_release}, +}; + +#define MANSLLEN \ + (sizeof(manstatelist) / sizeof(struct stateentry)) +/* *INDENT-ON* */ + + +static void +global_handler(struct PStack *st, int mt, struct sk_buff *skb) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + int i; + struct l3_process *proc = st->l3.global; + + if ( skb ) + proc->callref = skb->data[2]; /* cr flag */ + else + proc->callref = 0; + for (i = 0; i < GLOBALM_LEN; i++) + if ((mt == globalmes_list[i].primitive) && + ((1 << proc->state) & globalmes_list[i].state)) + break; + if (i == GLOBALM_LEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global state %d mt %x unhandled", + proc->state, mt); + } + MsgHead(p, proc->callref, MT_STATUS); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = 81 |0x80; /* invalid cr */ + *p++ = 0x14; /* CallState */ + *p++ = 0x1; + *p++ = proc->state & 0x3f; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(proc->st, DL_DATA | REQUEST, skb); + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global %d mt %x", + proc->state, mt); + } + globalmes_list[i].rout(proc, mt, skb); + } +} + +static void +ni1up(struct PStack *st, int pr, void *arg) +{ + int i, mt, cr, cause, callState; + char *ptr; + u_char *p; + struct sk_buff *skb = arg; + struct l3_process *proc; + + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + + case (DL_ESTABLISH | CONFIRM): + global_handler( st, MT_DL_ESTABLISHED, NULL ); + return; + + default: + printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr); + return; + } + if (skb->len < 3) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + + if (skb->data[0] != PROTO_DIS_EURO) { + if (st->l3.debug & L3_DEB_PROTERR) { + l3_debug(st, "ni1up%sunexpected discriminator %x message len %d", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + skb->data[0], skb->len); + } + dev_kfree_skb(skb); + return; + } + cr = getcallref(skb->data); + if (skb->len < ((skb->data[1] & 0x0f) + 3)) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + mt = skb->data[skb->data[1] + 2]; + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up cr %d", cr); + if (cr == -2) { /* wrong Callref */ + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up wrong Callref"); + dev_kfree_skb(skb); + return; + } else if (cr == -1) { /* Dummy Callref */ + if (mt == MT_FACILITY) + { + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(st, NULL, + (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); + dev_kfree_skb(skb); + return; + } + } + else + { + global_handler(st, mt, skb); + return; + } + + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up dummy Callref (no facility msg or ie)"); + dev_kfree_skb(skb); + return; + } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) || + (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up Global CallRef"); + global_handler(st, mt, skb); + dev_kfree_skb(skb); + return; + } else if (!(proc = getl3proc(st, cr))) { + /* No transaction process exist, that means no call with + * this callreference is active + */ + if (mt == MT_SETUP) { + /* Setup creates a new transaction process */ + if (skb->data[2] & 0x80) { + /* Setup with wrong CREF flag */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up wrong CRef flag"); + dev_kfree_skb(skb); + return; + } + if (!(proc = ni1_new_l3_process(st, cr))) { + /* May be to answer with RELEASE_COMPLETE and + * CAUSE 0x2f "Resource unavailable", but this + * need a new_l3_process too ... arghh + */ + dev_kfree_skb(skb); + return; + } + } else if (mt == MT_STATUS) { + cause = 0; + if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + cause = *ptr & 0x7f; + } + callState = 0; + if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + callState = *ptr; + } + /* ETS 300-104 part 2.4.1 + * if setup has not been made and a message type + * MT_STATUS is received with call state == 0, + * we must send nothing + */ + if (callState != 0) { + /* ETS 300-104 part 2.4.2 + * if setup has not been made and a message type + * MT_STATUS is received with call state != 0, + * we must send MT_RELEASE_COMPLETE cause 101 + */ + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 101; + l3ni1_msg_without_setup(proc, 0, NULL); + } + } + dev_kfree_skb(skb); + return; + } else if (mt == MT_RELEASE_COMPLETE) { + dev_kfree_skb(skb); + return; + } else { + /* ETS 300-104 part 2 + * if setup has not been made and a message type + * (except MT_SETUP and RELEASE_COMPLETE) is received, + * we must send MT_RELEASE_COMPLETE cause 81 */ + dev_kfree_skb(skb); + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 81; + l3ni1_msg_without_setup(proc, 0, NULL); + } + return; + } + } + if (l3ni1_check_messagetype_validity(proc, mt, skb)) { + dev_kfree_skb(skb); + return; + } + if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) + l3ni1_deliver_display(proc, pr, p); /* Display IE included */ + for (i = 0; i < DATASLLEN; i++) + if ((mt == datastatelist[i].primitive) && + ((1 << proc->state) & datastatelist[i].state)) + break; + if (i == DATASLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %#x unhandled", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { + proc->para.cause = 101; + l3ni1_status_send(proc, pr, skb); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %x", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + datastatelist[i].rout(proc, pr, skb); + } + dev_kfree_skb(skb); + return; +} + +static void +ni1down(struct PStack *st, int pr, void *arg) +{ + int i, cr; + struct l3_process *proc; + struct Channel *chan; + + if ((DL_ESTABLISH | REQUEST) == pr) { + l3_msg(st, pr, NULL); + return; + } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { + chan = arg; + cr = newcallref(); + cr |= 0x80; + if ((proc = ni1_new_l3_process(st, cr))) { + proc->chan = chan; + chan->proc = proc; + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); + proc->callref = cr; + } + } else { + proc = arg; + } + if (!proc) { + printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr); + return; + } + + if ( pr == (CC_TNI1_IO | REQUEST)) { + l3ni1_io_timer(proc); /* timer expires */ + return; + } + + for (i = 0; i < DOWNSLLEN; i++) + if ((pr == downstatelist[i].primitive) && + ((1 << proc->state) & downstatelist[i].state)) + break; + if (i == DOWNSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x unhandled", + proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x", + proc->state, pr); + } + downstatelist[i].rout(proc, pr, arg); + } +} + +static void +ni1man(struct PStack *st, int pr, void *arg) +{ + int i; + struct l3_process *proc = arg; + + if (!proc) { + printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); + return; + } + for (i = 0; i < MANSLLEN; i++) + if ((pr == manstatelist[i].primitive) && + ((1 << proc->state) & manstatelist[i].state)) + break; + if (i == MANSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", + proc->callref & 0x7f, proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x", + proc->callref & 0x7f, proc->state, pr); + } + manstatelist[i].rout(proc, pr, arg); + } +} + +void +setstack_ni1(struct PStack *st) +{ + char tmp[64]; + int i; + + st->lli.l4l3 = ni1down; + st->lli.l4l3_proto = l3ni1_cmd_global; + st->l2.l2l3 = ni1up; + st->l3.l3ml3 = ni1man; + st->l3.N303 = 1; + st->prot.ni1.last_invoke_id = 0; + st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ + i = 1; + while (i < 32) + st->prot.ni1.invoke_used[i++] = 0; + + if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { + printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n"); + } else { + st->l3.global->state = 0; + st->l3.global->callref = 0; + st->l3.global->next = NULL; + st->l3.global->debug = L3_DEB_WARN; + st->l3.global->st = st; + st->l3.global->N303 = 1; + st->l3.global->prot.ni1.invoke_id = 0; + + L3InitTimer(st->l3.global, &st->l3.global->timer); + } + strcpy(tmp, ni1_revision); + printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp)); +} diff --git a/drivers/isdn/hisax/l3ni1.h b/drivers/isdn/hisax/l3ni1.h new file mode 100644 index 000000000..24c919a17 --- /dev/null +++ b/drivers/isdn/hisax/l3ni1.h @@ -0,0 +1,136 @@ +// $Id: l3ni1.h,v 2.2 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. Thanks also for the +// code provided by Ragnar Paulson. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#ifndef l3ni1_process + +#define T302 15000 +#define T303 4000 +#define T304 30000 +#define T305 30000 +#define T308 4000 +/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ +/* This makes some tests easier and quicker */ +#define T309 40000 +#define T310 30000 +#define T313 4000 +#define T318 4000 +#define T319 4000 +#define TSPID 2000 + +/* + * Message-Types + */ + +#define MT_ALERTING 0x01 +#define MT_CALL_PROCEEDING 0x02 +#define MT_CONNECT 0x07 +#define MT_CONNECT_ACKNOWLEDGE 0x0f +#define MT_PROGRESS 0x03 +#define MT_SETUP 0x05 +#define MT_SETUP_ACKNOWLEDGE 0x0d +#define MT_RESUME 0x26 +#define MT_RESUME_ACKNOWLEDGE 0x2e +#define MT_RESUME_REJECT 0x22 +#define MT_SUSPEND 0x25 +#define MT_SUSPEND_ACKNOWLEDGE 0x2d +#define MT_SUSPEND_REJECT 0x21 +#define MT_USER_INFORMATION 0x20 +#define MT_DISCONNECT 0x45 +#define MT_RELEASE 0x4d +#define MT_RELEASE_COMPLETE 0x5a +#define MT_RESTART 0x46 +#define MT_RESTART_ACKNOWLEDGE 0x4e +#define MT_SEGMENT 0x60 +#define MT_CONGESTION_CONTROL 0x79 +#define MT_INFORMATION 0x7b +#define MT_FACILITY 0x62 +#define MT_NOTIFY 0x6e +#define MT_STATUS 0x7d +#define MT_STATUS_ENQUIRY 0x75 +#define MT_DL_ESTABLISHED 0xfe + +#define IE_SEGMENT 0x00 +#define IE_BEARER 0x04 +#define IE_CAUSE 0x08 +#define IE_CALL_ID 0x10 +#define IE_CALL_STATE 0x14 +#define IE_CHANNEL_ID 0x18 +#define IE_FACILITY 0x1c +#define IE_PROGRESS 0x1e +#define IE_NET_FAC 0x20 +#define IE_NOTIFY 0x27 +#define IE_DISPLAY 0x28 +#define IE_DATE 0x29 +#define IE_KEYPAD 0x2c +#define IE_SIGNAL 0x34 +#define IE_SPID 0x3a +#define IE_ENDPOINT_ID 0x3b +#define IE_INFORATE 0x40 +#define IE_E2E_TDELAY 0x42 +#define IE_TDELAY_SEL 0x43 +#define IE_PACK_BINPARA 0x44 +#define IE_PACK_WINSIZE 0x45 +#define IE_PACK_SIZE 0x46 +#define IE_CUG 0x47 +#define IE_REV_CHARGE 0x4a +#define IE_CONNECT_PN 0x4c +#define IE_CONNECT_SUB 0x4d +#define IE_CALLING_PN 0x6c +#define IE_CALLING_SUB 0x6d +#define IE_CALLED_PN 0x70 +#define IE_CALLED_SUB 0x71 +#define IE_REDIR_NR 0x74 +#define IE_TRANS_SEL 0x78 +#define IE_RESTART_IND 0x79 +#define IE_LLC 0x7c +#define IE_HLC 0x7d +#define IE_USER_USER 0x7e +#define IE_ESCAPE 0x7f +#define IE_SHIFT 0x90 +#define IE_MORE_DATA 0xa0 +#define IE_COMPLETE 0xa1 +#define IE_CONGESTION 0xb0 +#define IE_REPEAT 0xd0 + +#define IE_MANDATORY 0x0100 +/* mandatory not in every case */ +#define IE_MANDATORY_1 0x0200 + +#define ERR_IE_COMPREHENSION 1 +#define ERR_IE_UNRECOGNIZED -1 +#define ERR_IE_LENGTH -2 +#define ERR_IE_SEQUENCE -3 + +#else /* only l3ni1_process */ + +/* l3ni1 specific data in l3 process */ +typedef struct + { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ + ulong ll_id; /* remebered ll id */ + u_char remote_operation; /* handled remote operation, 0 = not active */ + int proc; /* rememered procedure */ + ulong remote_result; /* result of remote operation for statcallb */ + char uus1_data[35]; /* data send during alerting or disconnect */ + } ni1_proc_priv; + +/* l3dni1 specific data in protocol stack */ +typedef struct + { unsigned char last_invoke_id; /* last used value for invoking */ + unsigned char invoke_used[32]; /* 256 bits for 256 values */ + } ni1_stk_priv; + +#endif /* only l3dni1_process */ diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index 3ccbfc33a..a8e65d8b2 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -2,30 +2,32 @@ # This are valid md5sums for certificated HiSax driver. # The certification is valid only if the md5sums of all files match. -# The certification is valid only for ELSA QuickStep cards and -# Eicon Technology Diva 2.01 PCI cards in the moment. +# The certification is valid only for ELSA Microlink PCI, +# Eicon Technology Diva 2.01 PCI and Sedlbauer SpeedFax + +# cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -3fb9c99465857a4c136ae2881f4e30ba isac.c -dd3955847bbf680b41233478fe521d88 isdnl1.c -d362523462c424a8bce8b596ed5bdf2e isdnl2.c -92ea268891c222963a6ca70935bf1556 isdnl3.c -a23fbf8879c1432b04640b8b04bdf419 tei.c -838791b14269ec94c74ba4ae89c022e6 callc.c -bf9605b36429898f7be6630034e83230 cert.c -a30e6253837739f6f54d9dadcd42d9f2 l3dss1.c -a3a570781f828b6d59e6b231653133de l3_1tr6.c -4aeba32c4c3480d2a6b9af34600b974f elsa.c -a296edc459b508bf0346c3132815a4db diva.c +f4573d10ffe38b49f6c94e4c966b7bab isac.c +a29f5270c0c89626d8d6fa5dd09e7005 isdnl1.c +fbe41751c8130a8c3c607bfe1b41cb4e isdnl2.c +7915b7e802b98f6f4f05b931c4736ad4 isdnl3.c +7c31c12b3c2cfde33596bd2c406f775c tei.c +f1fbd532016f005e01decf36e5197d8f callc.c +a1834e9b2ec068440cff2e899eff4710 cert.c +a1f908f8b4f225c5c2f2a13842549b72 l3dss1.c +5bcab52f9937beb352aa02093182e039 l3_1tr6.c +030d4600ee59a2b246410d6a73977412 elsa.c +9e800b8e05c24542d731721eb192f305 diva.c +f32fae58dd9b2b3a73b2e5028f68dc4c sedlbauer.c # end of md5sums -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv -iQCVAwUBOPT2aTpxHvX/mS9tAQFJyAQAj+eY8MhPxQ2TS3rtfjK7bv8jrOGeJYu6 -P0YPnkkc09pCA6UdmYP6VSFkhtDS43HEZiGMb1MV/Y4LQ4wVDNrFDk9AyUNhP2/0 -gY+nYON6hT9ilXYqsbqoqGmh5qLaxj64p9mKu+MIgZ69CS4g7aj/OAXWB06zh7li -MiC65PNo6k0= -=d7xA +iQCVAwUBOaARmDpxHvX/mS9tAQFT7wP/TEEhtP96uKKgzr2o3GpJ5rRik0Q1HbKY +dzeA3U79QCEYqyptU09Uz96Av3dt1lNxpQyaahX419NjHH53HCaZgFCxgRxFWBYS +M9s4aSXLPTCSNM/kWiZkzWQ2lZ7ISNk2/+fF73w4l3G+4zF5y+VotjZCPx7OJj6i +R/L1m4vZXys= +=6DzE -----END PGP SIGNATURE----- diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index fd51217bf..6be8a493d 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -11,7 +11,6 @@ */ #define __NO_VERSION__ -#include <linux/config.h> #include "hisax.h" #include "isac.h" #include "hscx.h" @@ -19,6 +18,7 @@ #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/ppp_defs.h> +#include "netjet.h" #ifndef bus_to_virt #define bus_to_virt (u_int *) @@ -28,61 +28,12 @@ #define virt_to_bus (u_int) #endif -extern const char *CardType[]; - -const char *NETjet_revision = "$Revision: 1.18 $"; - -#define byteout(addr,val) outb(val,addr) -#define bytein(addr) inb(addr) - -/* PCI stuff */ -#define PCI_VENDOR_TRAVERSE_TECH 0xe159 -#define PCI_NETJET_ID 0x0001 - -#define NETJET_CTRL 0x00 -#define NETJET_DMACTRL 0x01 -#define NETJET_AUXCTRL 0x02 -#define NETJET_AUXDATA 0x03 -#define NETJET_IRQMASK0 0x04 -#define NETJET_IRQMASK1 0x05 -#define NETJET_IRQSTAT0 0x06 -#define NETJET_IRQSTAT1 0x07 -#define NETJET_DMA_READ_START 0x08 -#define NETJET_DMA_READ_IRQ 0x0c -#define NETJET_DMA_READ_END 0x10 -#define NETJET_DMA_READ_ADR 0x14 -#define NETJET_DMA_WRITE_START 0x18 -#define NETJET_DMA_WRITE_IRQ 0x1c -#define NETJET_DMA_WRITE_END 0x20 -#define NETJET_DMA_WRITE_ADR 0x24 -#define NETJET_PULSE_CNT 0x28 - -#define NETJET_ISAC_OFF 0xc0 -#define NETJET_ISACIRQ 0x10 -#define NETJET_IRQM0_READ 0x0c -#define NETJET_IRQM0_READ_1 0x04 -#define NETJET_IRQM0_READ_2 0x08 -#define NETJET_IRQM0_WRITE 0x03 -#define NETJET_IRQM0_WRITE_1 0x01 -#define NETJET_IRQM0_WRITE_2 0x02 - -#define NETJET_DMA_TXSIZE 512 -#define NETJET_DMA_RXSIZE 128 - -#define HDLC_ZERO_SEARCH 0 -#define HDLC_FLAG_SEARCH 1 -#define HDLC_FLAG_FOUND 2 -#define HDLC_FRAME_FOUND 3 -#define HDLC_NULL 4 -#define HDLC_PART 5 -#define HDLC_FULL 6 - -#define HDLC_FLAG_VALUE 0x7e +const char *NETjet_revision = "$Revision: 1.20 $"; /* Interface functions */ -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) +u_char +NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) { long flags; u_char ret; @@ -97,8 +48,8 @@ ReadISAC(struct IsdnCardState *cs, u_char offset) return(ret); } -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +void +NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) { long flags; @@ -111,8 +62,8 @@ WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) restore_flags(flags); } -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -155,8 +106,8 @@ __u16 fcstab[256] = 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -242,15 +193,6 @@ mode_tiger(struct BCState *bcs, int mode, int bc) bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); } -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return(5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { char tmp[128]; char *t = tmp; @@ -541,7 +483,7 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ bcs->hw.tiger.r_bitcnt = bitcnt; } -static void read_tiger(struct IsdnCardState *cs) { +void read_tiger(struct IsdnCardState *cs) { u_int *p; int cnt = NETJET_DMA_RXSIZE/2; @@ -572,7 +514,7 @@ static void read_tiger(struct IsdnCardState *cs) { static void write_raw(struct BCState *bcs, u_int *buf, int cnt); -static void fill_dma(struct BCState *bcs) +void netjet_fill_dma(struct BCState *bcs) { register u_int *p, *sp; register int cnt; @@ -687,7 +629,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - fill_dma(bcs); + netjet_fill_dma(bcs); } else { mask ^= 0xffffffff; if (s_cnt < cnt) { @@ -719,7 +661,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { } } -static void write_tiger(struct IsdnCardState *cs) { +void write_tiger(struct IsdnCardState *cs) { u_int *p, cnt = NETJET_DMA_TXSIZE/2; if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { @@ -935,88 +877,6 @@ releasetiger(struct IsdnCardState *cs) } } -static void -netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - long flags; - - if (!cs) { - printk(KERN_WARNING "NETjet: Spurious interrupt!\n"); - return; - } - if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & - NETJET_ISACIRQ)) { - val = ReadISAC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", sval, val); - if (val) { - isac_interrupt(cs, val); - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - } - } - save_flags(flags); - cli(); - if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - restore_flags(flags); - return; - } - cs->hw.njet.irqstat0 = sval; - restore_flags(flags); -/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", - sval, - bytein(cs->hw.njet.base + NETJET_DMACTRL), - bytein(cs->hw.njet.base + NETJET_IRQMASK0), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); -*/ -/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; -*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); -/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); -*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) - read_tiger(cs); - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) - write_tiger(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - restore_flags(flags); - -/* if (!testcnt--) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } -*/ -} - -static void -reset_netjet(struct IsdnCardState *cs) -{ - long flags; - - save_flags(flags); - sti(); - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - restore_flags(flags); - cs->hw.njet.auxd = 0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - void release_io_netjet(struct IsdnCardState *cs) { @@ -1026,100 +886,3 @@ release_io_netjet(struct IsdnCardState *cs) release_region(cs->hw.njet.base, 256); } - -static int -NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - switch (mt) { - case CARD_RESET: - reset_netjet(cs); - return(0); - case CARD_RELEASE: - release_io_netjet(cs); - return(0); - case CARD_INIT: - inittiger(cs); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - return(0); - case CARD_TEST: - return(0); - } - return(0); -} - -static struct pci_dev *dev_netjet __initdata = NULL; - -__initfunc(int -setup_netjet(struct IsdnCard *card)) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - char tmp[64]; -#if CONFIG_PCI -#endif - strcpy(tmp, NETjet_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET) - return(0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "Netjet: no PCI bus present\n"); - return(0); - } - if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH, - PCI_NETJET_ID, dev_netjet))) { - if (pci_enable_device(dev_netjet)) - return (0); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); - return(0); - } - } else { - printk(KERN_WARNING "NETjet: No PCI card found\n"); - return(0); - } - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - bytecnt = 256; -#else - printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n"); - printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - printk(KERN_INFO - "NETjet: PCI card configured at 0x%x IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (check_region(cs->hw.njet.base, bytecnt)) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } else { - request_region(cs->hw.njet.base, bytecnt, "netjet isdn"); - } - reset_netjet(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &fill_dma; - cs->cardmsg = &NETjet_card_msg; - cs->irq_func = &netjet_interrupt; - cs->irq_flags |= SA_SHIRQ; - ISACVersion(cs, "NETjet:"); - return (1); -} diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h new file mode 100644 index 000000000..d7dede4ff --- /dev/null +++ b/drivers/isdn/hisax/netjet.h @@ -0,0 +1,77 @@ +// $Id: netjet.h,v 2.3 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NETjet common header file +// +// Author Kerstern Keil repackaged by +// Matt Henderson - Traverse Technologies P/L www.traverse.com.au +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +extern const char *CardType[]; + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +/* PCI stuff */ +#ifndef PCI_VENDOR_ID_TIGERJET +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#endif +#ifndef PCI_DEVICE_ID_TIGERJET_300 +#define PCI_DEVICE_ID_TIGERJET_300 0x0001 +#endif +#define NETJET_CTRL 0x00 +#define NETJET_DMACTRL 0x01 +#define NETJET_AUXCTRL 0x02 +#define NETJET_AUXDATA 0x03 +#define NETJET_IRQMASK0 0x04 +#define NETJET_IRQMASK1 0x05 +#define NETJET_IRQSTAT0 0x06 +#define NETJET_IRQSTAT1 0x07 +#define NETJET_DMA_READ_START 0x08 +#define NETJET_DMA_READ_IRQ 0x0c +#define NETJET_DMA_READ_END 0x10 +#define NETJET_DMA_READ_ADR 0x14 +#define NETJET_DMA_WRITE_START 0x18 +#define NETJET_DMA_WRITE_IRQ 0x1c +#define NETJET_DMA_WRITE_END 0x20 +#define NETJET_DMA_WRITE_ADR 0x24 +#define NETJET_PULSE_CNT 0x28 + +#define NETJET_ISAC_OFF 0xc0 +#define NETJET_ISACIRQ 0x10 +#define NETJET_IRQM0_READ 0x0c +#define NETJET_IRQM0_READ_1 0x04 +#define NETJET_IRQM0_READ_2 0x08 +#define NETJET_IRQM0_WRITE 0x03 +#define NETJET_IRQM0_WRITE_1 0x01 +#define NETJET_IRQM0_WRITE_2 0x02 + +#define NETJET_DMA_TXSIZE 512 +#define NETJET_DMA_RXSIZE 128 + +#define HDLC_ZERO_SEARCH 0 +#define HDLC_FLAG_SEARCH 1 +#define HDLC_FLAG_FOUND 2 +#define HDLC_FRAME_FOUND 3 +#define HDLC_NULL 4 +#define HDLC_PART 5 +#define HDLC_FULL 6 + +#define HDLC_FLAG_VALUE 0x7e + +u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset); +void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value); +void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size); +void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size); + +void read_tiger(struct IsdnCardState *cs); +void write_tiger(struct IsdnCardState *cs); + +void netjet_fill_dma(struct BCState *bcs); +void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs); +__initfunc(void inittiger(struct IsdnCardState *cs)); +void release_io_netjet(struct IsdnCardState *cs); + diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 31f01355e..4428483b3 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -38,8 +38,12 @@ const char *niccy_revision = "$Revision: 1.12 $"; #define NICCY_PCI 2 /* PCI stuff */ -#define PCI_VENDOR_DR_NEUHAUS 0x1267 -#define PCI_NICCY_ID 0x1016 +#ifndef PCI_VENDOR_ID_SATSAGEM +#define PCI_VENDOR_ID_SATSAGEM 0x1267 +#endif +#ifndef PCI_DEVICE_ID_SATSAGEM_NICCY +#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 +#endif #define PCI_IRQ_CTRL_REG 0x38 #define PCI_IRQ_ENABLE 0x1f00 #define PCI_IRQ_DISABLE 0xff0000 @@ -284,26 +288,26 @@ setup_niccy(struct IsdnCard *card)) return(0); } cs->subtyp = 0; - if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS, - PCI_NICCY_ID, niccy_dev))) { + if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, + PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) { if (pci_enable_device(niccy_dev)) - return (0); + return(0); /* get IRQ */ if (!niccy_dev->irq) { printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); return(0); } cs->irq = niccy_dev->irq; - if (!niccy_dev->resource[ 0].start) { + cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); + if (!cs->hw.niccy.cfg_reg) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); return(0); } - cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); - if (!niccy_dev->resource[ 1].start) { + pci_ioaddr = pci_resource_start(niccy_dev, 1); + if (!pci_ioaddr) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr = pci_resource_start(niccy_dev, 1); cs->subtyp = NICCY_PCI; } else { printk(KERN_WARNING "Niccy: No PCI card found\n"); diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c new file mode 100644 index 000000000..2acb1a6de --- /dev/null +++ b/drivers/isdn/hisax/nj_s.c @@ -0,0 +1,257 @@ +// $Id: nj_s.c,v 2.3 2000/06/26 08:59:14 keil Exp $ +// +// This file is (c) under GNU PUBLIC LICENSE +// +#define __NO_VERSION__ +#include <linux/config.h> +#include "hisax.h" +#include "isac.h" +#include "isdnl1.h" +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ppp_defs.h> +#include "netjet.h" + +const char *NETjet_S_revision = "$Revision: 2.3 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETjet-S: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ISAC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + isac_interrupt(cs, val); + NETjet_WriteIC(cs, ISAC_MASK, 0xFF); + NETjet_WriteIC(cs, ISAC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); +/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", + sval, + bytein(cs->hw.njet.base + NETJET_DMACTRL), + bytein(cs->hw.njet.base + NETJET_IRQMASK0), + inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), + inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), + bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); +*/ +/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; +*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); +/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) + read_tiger(cs); + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) + write_tiger(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_s(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_s(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_isac_ints(cs); + initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +__initfunc(int +setup_netjet_s(struct IsdnCard *card)) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; +#if CONFIG_PCI +#endif +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_S_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_S) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + + for ( ;; ) + { + +#if CONFIG_PCI + + if (!pci_present()) { + printk(KERN_ERR "Netjet: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETjet-S: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) ) + { + case 0 : + break; + + case 3 : + printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETjet-S: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETjet-S: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn"); + } + reset_netjet_s(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_S_card_msg; + cs->irq_func = &netjet_s_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "NETjet-S:"); + return (1); +} diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c new file mode 100644 index 000000000..5ad977128 --- /dev/null +++ b/drivers/isdn/hisax/nj_u.c @@ -0,0 +1,260 @@ +/* $Id: nj_u.c,v 2.4 2000/06/26 11:42:16 keil Exp $ + * + * This file is (c) under GNU PUBLIC LICENSE + * + */ +#define __NO_VERSION__ +#include <linux/config.h> +#include "hisax.h" +#include "icc.h" +#include "isdnl1.h" +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ppp_defs.h> +#include "netjet.h" + +const char *NETjet_U_revision = "$Revision: 2.4 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETspider-U: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ICC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + icc_interrupt(cs, val); + NETjet_WriteIC(cs, ICC_MASK, 0xFF); + NETjet_WriteIC(cs, ICC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); +/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", + sval, + bytein(cs->hw.njet.base + NETJET_DMACTRL), + bytein(cs->hw.njet.base + NETJET_IRQMASK0), + inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), + inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), + bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); +*/ +/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; +*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); +/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) + read_tiger(cs); + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) + write_tiger(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_u(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_u(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_icc_ints(cs); + initicc(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +__initfunc(int +setup_netjet_u(struct IsdnCard *card)) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; +#if CONFIG_PCI +#endif +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_U_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_U) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + + for ( ;; ) + { + +#if CONFIG_PCI + + if (!pci_present()) { + printk(KERN_ERR "NETspider-U: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETspider-U: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) ) + { + case 3 : + break; + + case 0 : + printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETspider-U: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETspider-U: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netjet-u isdn"); + } + reset_netjet_u(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_U_card_msg; + cs->irq_func = &netjet_u_interrupt; + cs->irq_flags |= SA_SHIRQ; + ICCVersion(cs, "NETspider-U:"); + return (1); +} diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index 342e4e8fc..3f461883d 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -65,6 +65,24 @@ struct MessageType { 0xd, "SETUP ACKNOWLEDGE" }, { + 0x24, "HOLD" + }, + { + 0x28, "HOLD ACKNOWLEDGE" + }, + { + 0x30, "HOLD REJECT" + }, + { + 0x31, "RETRIEVE" + }, + { + 0x33, "RETRIEVE ACKNOWLEDGE" + }, + { + 0x37, "RETRIEVE REJECT" + }, + { 0x26, "RESUME" }, { @@ -638,6 +656,65 @@ prbearer(char *dest, u_char * p) return (dp - dest); } + +static +int +prbearer_ni1(char *dest, u_char * p) +{ + char *dp = dest; + u_char len; + + p++; + len = *p++; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x80: + dp += sprintf(dp, " Speech"); + break; + case 0x88: + dp += sprintf(dp, " Unrestricted digital information"); + break; + case 0x90: + dp += sprintf(dp, " 3.1 kHz audio"); + break; + default: + dp += sprintf(dp, " Unknown information-transfer capability"); + } + *dp++ = '\n'; + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x90: + dp += sprintf(dp, " 64 kbps, circuit mode"); + break; + case 0xc0: + dp += sprintf(dp, " Packet mode"); + break; + default: + dp += sprintf(dp, " Unknown transfer mode"); + } + *dp++ = '\n'; + if (len > 2) { + dp += sprintf(dp, " octet 5 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x21: + dp += sprintf(dp, " Rate adaption\n"); + dp += sprintf(dp, " octet 5a "); + dp += prbits(dp, *p, 8, 8); + break; + case 0xa2: + dp += sprintf(dp, " u-law"); + break; + default: + dp += sprintf(dp, " Unknown UI layer 1 protocol"); + } + *dp++ = '\n'; + } + return (dp - dest); +} + static int general(char *dest, u_char * p) { @@ -666,6 +743,33 @@ general(char *dest, u_char * p) } static int +general_ni1(char *dest, u_char * p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the information element */ + while (l--) { + dp += sprintf(dp, " octet %d%c ", octet, ch); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + + /* last octet in group? */ + if (*p++ & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + else + ch++; + } + return (dp - dest); +} + +static int prcharge(char *dest, u_char * p) { char *dp = dest; @@ -697,6 +801,112 @@ prtext(char *dest, u_char * p) *dp++ = '\n'; return (dp - dest); } + +static int +prfeatureind(char *dest, u_char * p) +{ + char *dp = dest; + + p += 2; /* skip id, len */ + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (!(*p++ & 80)) { + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + dp += sprintf(dp, " Status: "); + switch (*p) { + case 0: + dp += sprintf(dp, "Idle"); + break; + case 1: + dp += sprintf(dp, "Active"); + break; + case 2: + dp += sprintf(dp, "Prompt"); + break; + case 3: + dp += sprintf(dp, "Pending"); + break; + default: + dp += sprintf(dp, "(Reserved)"); + break; + } + *dp++ = '\n'; + return (dp - dest); +} + +static +struct DTag { /* Display tags */ + u_char nr; + char *descr; +} dtaglist[] = { + { 0x82, "Continuation" }, + { 0x83, "Called address" }, + { 0x84, "Cause" }, + { 0x85, "Progress indicator" }, + { 0x86, "Notification indicator" }, + { 0x87, "Prompt" }, + { 0x88, "Accumlated digits" }, + { 0x89, "Status" }, + { 0x8a, "Inband" }, + { 0x8b, "Calling address" }, + { 0x8c, "Reason" }, + { 0x8d, "Calling party name" }, + { 0x8e, "Called party name" }, + { 0x8f, "Orignal called name" }, + { 0x90, "Redirecting name" }, + { 0x91, "Connected name" }, + { 0x92, "Originating restrictions" }, + { 0x93, "Date & time of day" }, + { 0x94, "Call Appearance ID" }, + { 0x95, "Feature address" }, + { 0x96, "Redirection name" }, + { 0x9e, "Text" }, +}; +#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) + +static int +disptext_ni1(char *dest, u_char * p) +{ + char *dp = dest; + int l, tag, len, i; + + p++; + l = *p++ - 1; + if (*p++ != 0x80) { + dp += sprintf(dp, " Unknown display type\n"); + return (dp - dest); + } + /* Iterate over all tag,length,text fields */ + while (l > 0) { + tag = *p++; + len = *p++; + l -= len + 2; + /* Don't space or skip */ + if ((tag == 0x80) || (tag == 0x81)) p++; + else { + for (i = 0; i < DTAGSIZE; i++) + if (tag == dtaglist[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != DTAGSIZE) { + dp += sprintf(dp, " %s: ", dtaglist[i].descr); + while (len--) + *dp++ = *p++; + } else { + dp += sprintf(dp, " (unknown display tag %2x): ", tag); + while (len--) + *dp++ = *p++; + } + dp += sprintf(dp, "\n"); + } + } + return (dp - dest); +} static int display(char *dest, u_char * p) { @@ -867,6 +1077,49 @@ struct InformationElement { #define IESIZE sizeof(ielist)/sizeof(struct InformationElement) +static +struct InformationElement ielist_ni1[] = { + { 0x04, "Bearer Capability", prbearer_ni1 }, + { 0x08, "Cause", prcause }, + { 0x14, "Call State", general_ni1 }, + { 0x18, "Channel Identification", prchident }, + { 0x1e, "Progress Indicator", general_ni1 }, + { 0x27, "Notification Indicator", general_ni1 }, + { 0x2c, "Keypad Facility", prtext }, + { 0x32, "Information Request", general_ni1 }, + { 0x34, "Signal", general_ni1 }, + { 0x38, "Feature Activation", general_ni1 }, + { 0x39, "Feature Indication", prfeatureind }, + { 0x3a, "Service Profile Identification (SPID)", prtext }, + { 0x3b, "Endpoint Identifier", general_ni1 }, + { 0x6c, "Calling Party Number", prcalling }, + { 0x6d, "Calling Party Subaddress", general_ni1 }, + { 0x70, "Called Party Number", prcalled }, + { 0x71, "Called Party Subaddress", general_ni1 }, + { 0x74, "Redirecting Number", general_ni1 }, + { 0x78, "Transit Network Selection", general_ni1 }, + { 0x7c, "Low Layer Compatibility", general_ni1 }, + { 0x7d, "High Layer Compatibility", general_ni1 }, +}; + + +#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs5[] = { + { 0x1d, "Operator system access", general_ni1 }, + { 0x2a, "Display text", disptext_ni1 }, +}; + +#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs6[] = { + { 0x7b, "Call appearance", general_ni1 }, +}; + +#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) + static struct InformationElement we_0[] = { {WE0_cause, "Cause", prcause_1tr6}, @@ -1107,7 +1360,93 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) } buf += buf[1] + 2; } - } else if (buf[0] == 8) { /* EURO */ + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ + /* locate message type */ + buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == mt) + break; + + /* display message type if it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mtlist[i].descr); + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cset; + cset = *buf & 7; + cs_fest = *buf & 8; + break; + default: + dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cset == 0) { + for (i = 0; i < IESIZE; i++) + if (*buf == ielist_ni1[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE) { + dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); + dp += ielist_ni1[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 5) { + for (i = 0; i < IESIZE_NI1_CS5; i++) + if (*buf == ielist_ni1_cs5[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS5) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); + dp += ielist_ni1_cs5[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < IESIZE_NI1_CS6; i++) + if (*buf == ielist_ni1_cs6[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS6) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); + dp += ielist_ni1_cs6[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + + /* Skip to next element */ + if (cs_fest == 8) { + cset = cs_old; + cs_old = 0; + cs_fest = 0; + } + buf += buf[1] + 2; + } + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ /* locate message type */ buf++; cr_l = *buf++; diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index b463b154a..192c496b0 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -39,8 +39,6 @@ * For example: hisaxctrl <DriverID> 9 ISAR.BIN */ -#define SEDLBAUER_PCI 1 - #define __NO_VERSION__ #include <linux/config.h> #include "hisax.h" @@ -53,19 +51,23 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.20 $"; +const char *Sedlbauer_revision = "$Revision: 1.23 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", "speed win II / ISDN PC/104", "speed star II", "speed pci", - "speed fax+ pci"}; + "speed fax+ pyramid", "speed fax+ pci"}; -#ifdef SEDLBAUER_PCI -#define PCI_VENDOR_SEDLBAUER 0xe159 -#define PCI_SPEEDPCI_ID 0x02 -#define PCI_SUBVENDOR_SEDLBAUER 0x51 -#define PCI_SUB_ID_SPEEDFAXP 0x01 +#ifndef PCI_VENDOR_ID_TIGERJET +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#endif +#ifndef PCI_DEVICE_ID_TIGERJET_100 +#define PCI_DEVICE_ID_TIGERJET_100 0x0002 #endif +#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 +#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 +#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 +#define PCI_SUB_ID_SEDLBAUER 0x01 #define SEDL_SPEED_CARD_WIN 1 #define SEDL_SPEED_STAR 2 @@ -73,7 +75,8 @@ const char *Sedlbauer_Types[] = #define SEDL_SPEED_WIN2_PC104 4 #define SEDL_SPEED_STAR2 5 #define SEDL_SPEED_PCI 6 -#define SEDL_SPEEDFAX_PCI 7 +#define SEDL_SPEEDFAX_PYRAMID 7 +#define SEDL_SPEEDFAX_PCI 8 #define SEDL_CHIP_TEST 0 #define SEDL_CHIP_ISAC_HSCX 1 @@ -285,10 +288,10 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) } if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - printk(KERN_WARNING "Sedlbauer: card not available!\n"); - return; + /* The card tends to generate interrupts while being removed + causing us to just crash the kernel. bad. */ + printk(KERN_WARNING "Sedlbauer: card not available!\n"); + return; } val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); @@ -360,7 +363,8 @@ Start_IPAC: goto Start_IPAC; } if (!icnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); } @@ -398,7 +402,8 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs) goto Start_ISAC; } if (!cnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); @@ -508,7 +513,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) case CARD_TEST: return(0); case MDL_INFO_CONN: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; @@ -517,7 +522,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); break; case MDL_INFO_REL: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; @@ -529,9 +534,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -#ifdef SEDLBAUER_PCI static struct pci_dev *dev_sedl __initdata = NULL; -#endif __initfunc(int setup_sedlbauer(struct IsdnCard *card)) @@ -569,16 +572,15 @@ setup_sedlbauer(struct IsdnCard *card)) } } else { /* Probe for Sedlbauer speed pci */ -#if SEDLBAUER_PCI #if CONFIG_PCI if (!pci_present()) { printk(KERN_ERR "Sedlbauer: no PCI bus present\n"); return(0); } - if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER, - PCI_SPEEDPCI_ID, dev_sedl))) { + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { if (pci_enable_device(dev_sedl)) - return (0); + return(0); cs->irq = dev_sedl->irq; if (!cs->irq) { printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); @@ -597,13 +599,23 @@ setup_sedlbauer(struct IsdnCard *card)) sub_vendor_id, sub_id); printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", cs->hw.sedl.cfg_reg); - if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) && - (sub_id == PCI_SUB_ID_SPEEDFAXP)) { + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; cs->subtyp = SEDL_SPEEDFAX_PCI; - } else { + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { cs->hw.sedl.chip = SEDL_CHIP_IPAC; cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); } bytecnt = 256; cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; @@ -623,7 +635,6 @@ setup_sedlbauer(struct IsdnCard *card)) printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); return (0); #endif /* CONFIG_PCI */ -#endif /* SEDLBAUER_PCI */ } /* In case of the sedlbauer pcmcia card, this region is in use, @@ -683,7 +694,6 @@ setup_sedlbauer(struct IsdnCard *card)) if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - /* IPAC */ if (cs->hw.sedl.bus == SEDL_BUS_PCI) { cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c index 359e9932e..2a84aa2d2 100644 --- a/drivers/isdn/hisax/tei.c +++ b/drivers/isdn/hisax/tei.c @@ -154,7 +154,7 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg) if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ + if ((ost = findtei(st, tei))) { /* same tei is in use */ if (ri != ost->ma.ri) { st->ma.tei_m.printdebug(&st->ma.tei_m, "possible duplicate assignment tei %d", tei); @@ -181,10 +181,12 @@ tei_id_test_dup(struct FsmInst *fi, int event, void *arg) if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "foreign identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + if ((ost = findtei(st, tei))) { /* same tei is in use */ + if (ri != ost->ma.ri) { /* and it wasn't our request */ + st->ma.tei_m.printdebug(&st->ma.tei_m, + "possible duplicate assignment tei %d", tei); + FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + } } } diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index 856b73fd9..eb17ce331 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -27,6 +27,12 @@ const char *telespci_revision = "$Revision: 2.13 $"; #define ZORAN_PO_GREG1 0x00010000 #define ZORAN_PO_DMASK 0xFF +#ifndef PCI_VENDOR_ID_ZORAN +#define PCI_VENDOR_ID_ZORAN 0x11DE +#endif +#ifndef PCI_DEVICE_ID_ZORAN_36120 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 +#endif #define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0) #define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1) #define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1) @@ -282,6 +288,9 @@ setup_telespci(struct IsdnCard *card)) struct IsdnCardState *cs = card->cs; char tmp[64]; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) @@ -291,18 +300,18 @@ setup_telespci(struct IsdnCard *card)) printk(KERN_ERR "TelesPCI: no PCI bus present\n"); return(0); } - if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) { + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) - return (0); + return(0); cs->irq = dev_tel->irq; if (!cs->irq) { printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); return(0); } - cs->hw.teles0.membase = (u_long) ioremap(dev_tel->resource[ 0].start, + cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0), PAGE_SIZE); printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n", - dev_tel->resource[ 0].start, dev_tel->irq); + pci_resource_start(dev_tel, 0), dev_tel->irq); } else { printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index cea2f61df..eca66942e 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -17,13 +17,18 @@ #include <linux/interrupt.h> #include <linux/pci.h> -#define PCI_VEND_ASUSCOM 0x675 -#define PCI_DEV_ASUSCOMPCI1 0x1702 +#ifndef PCI_VENDOR_ID_ASUSCOM +#define PCI_VENDOR_ID_ASUSCOM 0x675 +#endif +#ifndef PCI_DEVICE_ID_ASUSCOM_TA1 +#define PCI_DEVICE_ID_ASUSCOM_TA1 0x1702 +#endif #ifndef PCI_VENDOR_ID_WINBOND2 #define PCI_VENDOR_ID_WINBOND2 0x1050 #endif -#define PCI_DEVICE_W6692 0x6692 - +#ifndef PCI_DEVICE_ID_WINBOND_6692 +#define PCI_DEVICE_ID_WINBOND_6692 0x6692 +#endif /* table entry in the PCI devices list */ typedef struct { int vendor_id; @@ -34,14 +39,14 @@ typedef struct { static const PCI_ENTRY id_list[] = { - {PCI_VEND_ASUSCOM, PCI_DEV_ASUSCOMPCI1, "AsusCom", "TA XXX"}, - {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_W6692, "Winbond", "W6692"}, + {PCI_VENDOR_ID_ASUSCOM, PCI_DEVICE_ID_ASUSCOM_TA1, "AsusCom", "TA XXX"}, + {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND_6692, "Winbond", "W6692"}, {0, 0, NULL, NULL} }; extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.4 $"; +const char *w6692_revision = "$Revision: 1.7 $"; #define DBUSY_TIMER_VALUE 80 @@ -239,7 +244,7 @@ W6692B_empty_fifo(struct BCState *bcs, int count) if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692B_empty_fifo: incoming packet too large"); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); bcs->hw.w6692.rcvidx = 0; return; } @@ -247,14 +252,14 @@ W6692B_empty_fifo(struct BCState *bcs, int count) bcs->hw.w6692.rcvidx += count; save_flags(flags); cli(); - READW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + READW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_empty_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -290,14 +295,14 @@ W6692B_fill_fifo(struct BCState *bcs) skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.w6692.count += count; - WRITEW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); + WRITEW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_fill_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -308,13 +313,11 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) { u_char val; u_char r; - struct BCState *bcs = cs->bcs; + struct BCState *bcs; struct sk_buff *skb; int count; - if (bcs->channel != bchan) - bcs++; /* hardware bchan must match ! */ - + bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1); val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); @@ -401,7 +404,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) bcs->tx_cnt += bcs->hw.w6692.count; bcs->hw.w6692.count = 0; } - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B EXIR %x Lost TX", val); } @@ -715,18 +718,16 @@ dbusy_timer_handler(struct IsdnCardState *cs) } static void -W6692Bmode(struct BCState *bcs, int mode, int bc) +W6692Bmode(struct BCState *bcs, int mode, int bchan) { struct IsdnCardState *cs = bcs->cs; - int bchan = bc; - - bcs->hw.w6692.bchan = bc; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "w6692 %c mode %d ichan %d", - '1' + bchan, mode, bc); + '1' + bchan, mode, bchan); bcs->mode = mode; - bcs->channel = bc; + bcs->channel = bchan; + bcs->hw.w6692.bchan = bchan; switch (mode) { case (L1_MODE_NULL): @@ -895,8 +896,6 @@ HISAX_INITFUNC(void initW6692(struct IsdnCardState *cs, int part)) cs->bcs[1].BC_SetStack = setstack_w6692; cs->bcs[0].BC_Close = close_w6692state; cs->bcs[1].BC_Close = close_w6692state; - cs->bcs[0].hw.w6692.bchan = 0; - cs->bcs[1].hw.w6692.bchan = 1; W6692Bmode(cs->bcs, 0, 0); W6692Bmode(cs->bcs + 1, 0, 0); } @@ -979,6 +978,9 @@ __initfunc(int setup_w6692(struct IsdnCard *card)) u_char pci_irq = 0; u_int pci_ioaddr = 0; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, w6692_revision); printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile index 626a6deaa..5613784b7 100644 --- a/drivers/isdn/hysdn/Makefile +++ b/drivers/isdn/hysdn/Makefile @@ -16,6 +16,9 @@ ifeq ($(CONFIG_PROC_FS),y) M_OBJS += hysdn.o O_TARGET += hysdn.o O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o + ifeq ($(CONFIG_HYSDN_CAPI),y) + O_OBJS += hycapi.o + endif OX_OBJS += hysdn_init.o endif endif diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 578e4a14d..54849eab1 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: boardergo.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, specific routines for ergo type boards. * @@ -25,6 +25,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: boardergo.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -33,6 +39,7 @@ */ #define __NO_VERSION__ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <asm/io.h> @@ -153,6 +160,9 @@ ergo_stopcard(hysdn_card * card) uchar val; hysdn_net_release(card); /* first release the net device if existing */ +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_stop(card); +#endif /* CONFIG_HYSDN_CAPI */ save_flags(flags); cli(); val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ @@ -238,7 +248,7 @@ ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs) uchar *dst; tErgDpram *dpram; int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */ - + if (card->debug_flags & LOG_POF_CARD) hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs); @@ -334,7 +344,6 @@ ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len) } /* while (nr_write) */ } /* while (len) */ - return (0); } /* ergo_writebootseq */ @@ -354,7 +363,6 @@ ergo_waitpofready(struct HYSDN_CARD *card) if (card->debug_flags & LOG_POF_CARD) hysdn_addlog(card, "ERGO: waiting for pof ready"); - while (timecnt--) { /* wait until timeout */ @@ -375,7 +383,6 @@ ergo_waitpofready(struct HYSDN_CARD *card) if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "ERGO: pof boot success"); - save_flags(flags); cli(); @@ -396,6 +403,11 @@ ergo_waitpofready(struct HYSDN_CARD *card) card->state = CARD_STATE_BOOTERR; return (i); } +#ifdef CONFIG_HYSDN_CAPI + if((i = hycapi_capi_create(card))) { + printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n"); + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* success */ } /* data has arrived */ sti(); diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c new file mode 100644 index 000000000..aabb28b8d --- /dev/null +++ b/drivers/isdn/hysdn/hycapi.c @@ -0,0 +1,859 @@ +/* $Id: hycapi.c,v 1.6 2000/07/25 08:07:42 ualbrecht Exp $ + * + * Linux driver for HYSDN cards, CAPI2.0-Interface. + * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH + * + * Copyright 2000 by Hypercope GmbH + * + * 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; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: hycapi.c,v $ + * Revision 1.6 2000/07/25 08:07:42 ualbrecht + * Fixed stupid re-registering bug resulting in system-freeze + * + * Revision 1.5 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.4 2000/06/13 09:13:06 ualbrecht + * Changed internal application handling: Registration is now deferred + * until a CAPI-message is actually sent to the controller (no good + * wasting memory on the card if it's never used anyways). + * Module will now unload more gracefully. + * + * Revision 1.2 2000/05/22 10:31:22 ualbrecht + * Parameter-checking for app-registration fixed + * + * Revision 1.1 2000/05/17 11:34:30 ualbrecht + * Initial release + * + * + */ + +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/version.h> +#include <linux/signal.h> +#include <linux/kernel.h> +#include <linux/skbuff.h> + + +#define VER_DRIVER 0 +#define VER_CARDTYPE 1 +#define VER_HWID 2 +#define VER_SERIAL 3 +#define VER_OPTION 4 +#define VER_PROTO 5 +#define VER_PROFILE 6 +#define VER_CAPI 7 + +#include "hysdn_defs.h" +#include <linux/kernelcapi.h> + +static char hycapi_revision[]="$Revision: 1.6 $"; + +typedef struct _hycapi_appl { + unsigned int ctrl_mask; + capi_register_params rp; + struct sk_buff *listen_req[CAPI_MAXCONTR]; +} hycapi_appl; + +static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; + +static inline int _hycapi_appCheck(int app_id, int ctrl_no) +{ + if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || + (app_id > CAPI_MAXAPPL)) + { + printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no); + return -1; + } + return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0); +} + +struct capi_driver_interface *hy_di = NULL; + +/****************************** +Kernel-Capi callback reset_ctr +******************************/ + +void +hycapi_reset_ctr(struct capi_ctr *ctrl) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); +#endif + ctrl->reseted(ctrl); +} + +/****************************** +Kernel-Capi callback remove_ctr +******************************/ + +void +hycapi_remove_ctr(struct capi_ctr *ctrl) +{ + int i; + hycapictrl_info *cinfo = NULL; + hysdn_card *card = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n"); +#endif + if(!hy_di) { + printk(KERN_ERR "No capi_driver_interface set!"); + return; + } + cinfo = (hycapictrl_info *)(ctrl->driverdata); + if(!cinfo) { + printk(KERN_ERR "No hycapictrl_info set!"); + return; + } + card = cinfo->card; + ctrl->suspend_output(ctrl); + for(i=0; i<CAPI_MAXAPPL;i++) { + if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { + kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]); + hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL; + } + } + hy_di->detach_ctr(ctrl); + ctrl->driverdata = 0; + kfree(card->hyctrlinfo); + + + card->hyctrlinfo = NULL; +} + +/*********************************************************** + +Queue a CAPI-message to the controller. + +***********************************************************/ + +static void +hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + + spin_lock_irq(&cinfo->lock); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_send_message\n"); +#endif + cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */ + if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->in_idx = 0; /* wrap around */ + cinfo->sk_count++; /* adjust counter */ + if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) { + /* inform upper layers we're full */ + printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n", + card->myid); + ctrl->suspend_output(ctrl); + } + cinfo->tx_skb = skb; + spin_unlock_irq(&cinfo->lock); + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/*********************************************************** +hycapi_register_internal + +Send down the CAPI_REGISTER-Command to the controller. +This functions will also be used if the adapter has been rebooted to +re-register any applications in the private list. + +************************************************************/ + +static void +hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*"; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa0, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; + __u16 MessageBufferSize = 0; + int slen = strlen(ExtFeatureDefaults); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_register_appl\n"); +#endif + MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen; + + len = CAPI_MSG_BASELEN + 8 + slen + 1; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16)); + memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen); + hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1)); + hycapi_send_message(ctrl, skb); +} + +/************************************************************ +hycapi_restart_internal + +After an adapter has been rebootet, re-register all applications and +send a LISTEN_REQ (if there has been such a thing ) + +*************************************************************/ + +static void hycapi_restart_internal(struct capi_ctr *ctrl) +{ + int i; + struct sk_buff *skb; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_WARNING "HYSDN: hycapi_restart_internal"); +#endif + for(i=0; i<CAPI_MAXAPPL; i++) { + if(_hycapi_appCheck(i+1, ctrl->cnr) == 1) { + hycapi_register_internal(ctrl, i+1, + &hycapi_applications[i].rp); + if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { + skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC); + hycapi_sendmsg_internal(ctrl, skb); + } + } + } +} + +/************************************************************* +Register an application. +Error-checking is done for CAPI-compliance. + +The application is recorded in the internal list. +*************************************************************/ + +void +hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk < 0) { + return; + } + if(chk == 1) { + printk(KERN_INFO "HYSDN: apl %d allready registered\n", appl); + return; + } + MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt; + rp->datablkcnt = MaxBDataBlocks; + MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ; + rp->datablklen = MaxBDataLen; + + MaxLogicalConnections = rp->level3cnt; + if (MaxLogicalConnections < 0) { + MaxLogicalConnections = card->bchans * -MaxLogicalConnections; + } + if (MaxLogicalConnections == 0) { + MaxLogicalConnections = card->bchans; + } + + rp->level3cnt = MaxLogicalConnections; + memcpy(&hycapi_applications[appl-1].rp, + rp, sizeof(capi_register_params)); + +/* MOD_INC_USE_COUNT; */ + ctrl->appl_registered(ctrl, appl); +} + +/********************************************************************* + +hycapi_release_internal + +Send down a CAPI_RELEASE to the controller. +*********************************************************************/ + +static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa1, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_release_appl\n"); +#endif + len = CAPI_MSG_BASELEN; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + hycapi_send_message(ctrl, skb); + hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1)); +} + +/****************************************************************** +hycapi_release_appl + +Release the application from the internal list an remove it's +registration at controller-level +******************************************************************/ + +void +hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + int chk; + + chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk<0) { + printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr); + return; + } + if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) { + kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL; + } + if(chk == 1) + { + hycapi_release_internal(ctrl, appl); + } + ctrl->appl_released(ctrl, appl); +/* MOD_DEC_USE_COUNT; */ +} + + +/************************************************************** +Kill a single controller. +**************************************************************/ + +int hycapi_capi_release(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_release\n"); +#endif + if(cinfo) { + ctrl = cinfo->capi_ctrl; + hycapi_remove_ctr(ctrl); + } + return 0; +} + +/************************************************************** +hycapi_capi_stop + +Stop CAPI-Output on a card. (e.g. during reboot) +***************************************************************/ + +int hycapi_capi_stop(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_stop\n"); +#endif + if(cinfo) { + if(cinfo->capi_ctrl) { + ctrl = cinfo->capi_ctrl; +/* ctrl->suspend_output(ctrl); */ + ctrl->reseted(ctrl); + + } else { + printk(KERN_NOTICE "hycapi_capi_stop: cinfo but no capi_ctrl\n"); + } + } + return 0; +} + +/*************************************************************** +hycapi_send_message + +Send a message to the controller. + +Messages are parsed for their Command/Subcommand-type, and appropriate +action's are performed. + +Note that we have to muck around with a 64Bit-DATA_REQ as there are +firmware-releases that do not check the MsgLen-Indication! + +***************************************************************/ + +void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + __u16 appl_id; + int _len, _len2; + __u8 msghead[64]; + + appl_id = CAPIMSG_APPID(skb->data); + switch(_hycapi_appCheck(appl_id, ctrl->cnr)) + { + case 0: +/* printk(KERN_INFO "Need to register\n"); */ + hycapi_register_internal(ctrl, + appl_id, + &(hycapi_applications[appl_id-1].rp)); + break; + case 1: + break; + default: + printk(KERN_ERR "HYCAPI: Controller mixup!\n"); + return; + } + switch(CAPIMSG_CMD(skb->data)) { + case CAPI_DISCONNECT_B3_RESP: + ctrl->free_ncci(ctrl, appl_id, + CAPIMSG_NCCI(skb->data)); + break; + case CAPI_DATA_B3_REQ: + _len = CAPIMSG_LEN(skb->data); + if (_len > 22) { + _len2 = _len - 22; + memcpy(msghead, skb->data, 22); + memcpy(skb->data + _len2, msghead, 22); + skb_pull(skb, _len2); + CAPIMSG_SETLEN(skb->data, 22); + } + break; + case CAPI_LISTEN_REQ: + if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]) + { + kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL; + } + if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC))) + { + printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n"); + } + break; + default: + break; + } + hycapi_sendmsg_internal(ctrl, skb); +} + +/********************************************************************* +hycapi_read_proc + +Informations provided in the /proc/capi-entries. + +*********************************************************************/ + +int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int len = 0; + char *s; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_read_proc\n"); +#endif + len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + + switch (card->brdtype) { + case BD_PCCARD: s = "HYSDN Hycard"; break; + case BD_ERGO: s = "HYSDN Ergo2"; break; + case BD_METRO: s = "HYSDN Metro4"; break; + case BD_CHAMP2: s = "HYSDN Champ2"; break; + case BD_PLEXUS: s = "HYSDN Plexus30"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if ((s = cinfo->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = cinfo->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = cinfo->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/************************************************************** +hycapi_load_firmware + +This does NOT load any firmware, but the callback somehow is needed +on capi-interface registration. + +**************************************************************/ + +int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_load_firmware\n"); +#endif + return 0; +} + + +char *hycapi_procinfo(struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_proc_info\n"); +#endif + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d %s", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->iobase : 0x0, + cinfo->card ? cinfo->card->irq : 0, + hycapi_revision + ); + return cinfo->infobuf; +} + +/****************************************************************** +hycapi_rx_capipkt + +Recieve a capi-message. + +All B3_DATA_IND are converted to 64K-extension compatible format. +New nccis are created if neccessary. +*******************************************************************/ + +void +hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len) +{ + struct sk_buff *skb; + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; + __u16 ApplId; + __u16 MsgLen, info; + __u16 len2, CapiCmd; + __u32 CP64[2] = {0,0}; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_rx_capipkt\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no HYCAPI-controller!\n", + card->myid); + return; + } + ctrl = cinfo->capi_ctrl; + if(!ctrl) + { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (1)!\n", + card->myid); + return; + } + if(len < CAPI_MSG_BASELEN) { + printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n", + card->myid, len); + return; + } + MsgLen = CAPIMSG_LEN(buf); + ApplId = CAPIMSG_APPID(buf); + CapiCmd = CAPIMSG_CMD(buf); + + if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) { + len2 = len + (30 - MsgLen); + if (!(skb = alloc_skb(len2, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, MsgLen), buf, MsgLen); + memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32)); + memcpy(skb_put(skb, len - MsgLen), buf + MsgLen, + len - MsgLen); + CAPIMSG_SETLEN(skb->data, 30); + } else { + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, len), buf, len); + } + switch(CAPIMSG_CMD(skb->data)) + { + case CAPI_CONNECT_B3_CONF: +/* Check info-field for error-indication: */ + info = CAPIMSG_U16(skb->data, 12); + switch(info) + { + case 0: + ctrl->new_ncci(ctrl, ApplId, CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + + break; + case 0x0001: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current " + "protocol. NCPI ignored.\n", card->myid); + break; + case 0x2001: + printk(KERN_ERR "HYSDN Card%d: Message not supported in" + " current state\n", card->myid); + break; + case 0x2002: + printk(KERN_ERR "HYSDN Card%d: illegal PLCI\n", card->myid); + break; + case 0x2004: + printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid); + break; + case 0x3008: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n", + card->myid); + break; + default: + printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n", + card->myid, info); + break; + } + break; + case CAPI_CONNECT_B3_IND: + ctrl->new_ncci(ctrl, ApplId, + CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + break; + default: + break; + } + ctrl->handle_capimsg(ctrl, ApplId, skb); +} + +/****************************************************************** +hycapi_tx_capiack + +Internally acknowledge a msg sent. This will remove the msg from the +internal queue. + +*******************************************************************/ + +void hycapi_tx_capiack(hysdn_card * card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_tx_capiack\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (2)!\n", + card->myid); + return; + } + spin_lock_irq(&cinfo->lock); + kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */ + cinfo->skbs[cinfo->out_idx++] = NULL; + if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->out_idx = 0; /* wrap around */ + + if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */ + cinfo->capi_ctrl->resume_output(cinfo->capi_ctrl); + spin_unlock_irq(&cinfo->lock); +} + +/*************************************************************** +hycapi_tx_capiget(hysdn_card *card) + +This is called when polling for messages to SEND. + +****************************************************************/ + +struct sk_buff * +hycapi_tx_capiget(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller! (3)\n", + card->myid); + return (struct sk_buff *)NULL; + } + if (!cinfo->sk_count) + return (struct sk_buff *)NULL; /* nothing available */ + + return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */ +} + + +static struct capi_driver hycapi_driver = { + "hysdn", + "0.0", + hycapi_load_firmware, + hycapi_reset_ctr, + hycapi_remove_ctr, + hycapi_register_appl, + hycapi_release_appl, + hycapi_send_message, + hycapi_procinfo, + hycapi_read_proc, + 0, /* use standard driver_read_proc */ + 0, /* no add_card function */ +}; + + +/********************************************************** +int hycapi_init() + +attach the capi-driver to the kernel-capi. + +***********************************************************/ + +int hycapi_init() +{ + struct capi_driver *driver; + int i; + if(hy_di) { + printk(KERN_NOTICE "HyDI allready set\n"); + return 0; + } + driver = &hycapi_driver; + printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n"); + hy_di = attach_capi_driver(driver); + if (!hy_di) { + printk(KERN_ERR "HYCAPI: failed to attach capi_driver\n"); + return(-1); + } + for(i=0;i<CAPI_MAXAPPL;i++) { + memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl)); + } + return(0); +} + +/************************************************************** +hycapi_cleanup(void) + +detach the capi-driver to the kernel-capi. Actually this should +free some more ressources. Do that later. +**************************************************************/ + +void +hycapi_cleanup(void) +{ + struct capi_driver *driver; + driver = &hycapi_driver; + if (!hy_di) { + printk(KERN_ERR "HYSDN: no capi-driver to detach (???)\n"); + return; + } + printk(KERN_NOTICE "HYSDN: Detaching capi-driver\n"); + detach_capi_driver(driver); + hy_di = 0; + return; +} + +/******************************************************************** +hycapi_capi_create(hysdn_card *card) + +Attach the card with it's capi-ctrl. +*********************************************************************/ + +static void hycapi_fill_profile(hysdn_card *card) +{ + hycapictrl_info *cinfo = NULL; + struct capi_ctr *ctrl = NULL; + cinfo = card->hyctrlinfo; + if(!cinfo) return; + ctrl = cinfo->capi_ctrl; + if(!ctrl) return; + strcpy(ctrl->manu, "Hypercope"); + ctrl->version.majorversion = 2; + ctrl->version.minorversion = 0; + ctrl->version.majormanuversion = 3; + ctrl->version.minormanuversion = 2; + ctrl->profile.ncontroller = card->myid; + ctrl->profile.nbchannel = card->bchans; + ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER | + GLOBAL_OPTION_B_CHANNEL_OPERATION; + ctrl->profile.support1 = B1_PROT_64KBIT_HDLC | + (card->faxchans ? B1_PROT_T30 : 0) | + B1_PROT_64KBIT_TRANSPARENT; + ctrl->profile.support2 = B2_PROT_ISO7776 | + (card->faxchans ? B2_PROT_T30 : 0) | + B2_PROT_TRANSPARENT; + ctrl->profile.support3 = B3_PROT_TRANSPARENT | + B3_PROT_T90NL | + (card->faxchans ? B3_PROT_T30 : 0) | + (card->faxchans ? B3_PROT_T30EXT : 0) | + B3_PROT_ISO8208; +} + +int +hycapi_capi_create(hysdn_card *card) +{ + hycapictrl_info *cinfo = NULL; + struct capi_ctr *ctrl = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_create\n"); +#endif + if (!card->hyctrlinfo) { + cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n"); + return -ENOMEM; + } + memset(cinfo, 0, sizeof(hycapictrl_info)); + card->hyctrlinfo = cinfo; + cinfo->card = card; + spin_lock_init(&cinfo->lock); + + switch (card->brdtype) { + case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break; + case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break; + case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break; + case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break; + case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break; + default: strcpy(cinfo->cardname,"HYSDN ???"); break; + } + + cinfo->capi_ctrl = hy_di->attach_ctr(&hycapi_driver, + cinfo->cardname, cinfo); + ctrl = cinfo->capi_ctrl; + if (!ctrl) { + printk(KERN_ERR "%s: attach controller failed.\n", + hycapi_driver.name); + return -EBUSY; + } + /* fill in the blanks: */ + hycapi_fill_profile(card); + ctrl->ready(ctrl); + } else { + /* resume output on stopped ctrl */ + ctrl = card->hyctrlinfo->capi_ctrl; + if(ctrl) { + hycapi_fill_profile(card); + ctrl->ready(ctrl); + hycapi_restart_internal(ctrl); +/* ctrl->resume_output(ctrl); */ + } else { + printk(KERN_WARNING "HYSDN: No ctrl???? How come?\n"); + } + } + return 0; +} diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c index 030c40de6..31eaa14cb 100644 --- a/drivers/isdn/hysdn/hysdn_boot.c +++ b/drivers/isdn/hysdn/hysdn_boot.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_boot.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_boot.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, specific routines for booting and pof handling. * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_boot.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -260,7 +266,6 @@ pof_write_buffer(hysdn_card * card, int datlen) } if ((boot->last_error = pof_handle_data(card, datlen)) < 0) return (boot->last_error); /* an error occured */ - boot->pof_recoffset += datlen; if (boot->pof_recoffset >= boot->pof_reclen) { boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h index cac76cb26..e5ad863d4 100644 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -1,4 +1,4 @@ -/* $Id: hysdn_defs.h,v 1.1 2000/02/10 19:44:30 werner Exp $ +/* $Id: hysdn_defs.h,v 1.3 2000/06/13 09:14:26 ualbrecht Exp $ * Linux driver for HYSDN cards, global definitions and exported vars and functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_defs.h,v $ + * Revision 1.3 2000/06/13 09:14:26 ualbrecht + * Removed obsolete struct for CAPI-application tracking. + * + * Revision 1.2 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * * Revision 1.1 2000/02/10 19:44:30 werner * * Initial release @@ -27,6 +33,10 @@ * */ +#ifndef HYSDN_DEFS_H +#define HYSDN_DEFS_H + +#include <linux/config.h> #include <linux/hysdn_if.h> #include <linux/interrupt.h> #include <linux/tqueue.h> @@ -42,6 +52,54 @@ #include "ince1pc.h" +#ifdef CONFIG_HYSDN_CAPI +#include <linux/capi.h> +#include "../avmb1/capicmd.h" +#include "../avmb1/capiutil.h" +#include "../avmb1/capilli.h" + +/***************************/ +/* CAPI-Profile values. */ +/***************************/ + +#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001 +#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002 +#define GLOBAL_OPTION_HANDSET 0x0004 +#define GLOBAL_OPTION_DTMF 0x0008 +#define GLOBAL_OPTION_SUPPL_SERVICES 0x0010 +#define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020 +#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040 + +#define B1_PROT_64KBIT_HDLC 0x0001 +#define B1_PROT_64KBIT_TRANSPARENT 0x0002 +#define B1_PROT_V110_ASYNCH 0x0004 +#define B1_PROT_V110_SYNCH 0x0008 +#define B1_PROT_T30 0x0010 +#define B1_PROT_64KBIT_INV_HDLC 0x0020 +#define B1_PROT_56KBIT_TRANSPARENT 0x0040 + +#define B2_PROT_ISO7776 0x0001 +#define B2_PROT_TRANSPARENT 0x0002 +#define B2_PROT_SDLC 0x0004 +#define B2_PROT_LAPD 0x0008 +#define B2_PROT_T30 0x0010 +#define B2_PROT_PPP 0x0020 +#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040 + +#define B3_PROT_TRANSPARENT 0x0001 +#define B3_PROT_T90NL 0x0002 +#define B3_PROT_ISO8208 0x0004 +#define B3_PROT_X25_DCE 0x0008 +#define B3_PROT_T30 0x0010 +#define B3_PROT_T30EXT 0x0020 + +#define HYSDN_MAXVERSION 8 + +/* Number of sendbuffers in CAPI-queue */ +#define HYSDN_MAX_CAPI_SKB 20 + +#endif /* CONFIG_HYSDN_CAPI*/ + /************************************************/ /* constants and bits for debugging/log outputs */ /************************************************/ @@ -176,8 +234,30 @@ typedef struct HYSDN_CARD { /* init and deinit stopcard for booting, too */ void (*stopcard) (struct HYSDN_CARD *); void (*releasehardware) (struct HYSDN_CARD *); +#ifdef CONFIG_HYSDN_CAPI + struct hycapictrl_info { + char cardname[32]; + spinlock_t lock; + int versionlen; + char versionbuf[1024]; + char *version[HYSDN_MAXVERSION]; + + char infobuf[128]; /* for function procinfo */ + + struct HYSDN_CARD *card; + struct capi_ctr *capi_ctrl; + struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB]; + int in_idx, out_idx; /* indexes to buffer ring */ + int sk_count; /* number of buffers currently in ring */ + struct sk_buff *tx_skb; /* buffer for tx operation */ + } *hyctrlinfo; +#endif /* CONFIG_HYSDN_CAPI */ } hysdn_card; +#ifdef CONFIG_HYSDN_CAPI +typedef struct hycapictrl_info hycapictrl_info; +#endif /* CONFIG_HYSDN_CAPI */ + /*****************/ /* exported vars */ @@ -227,3 +307,27 @@ extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */ extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */ extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */ extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */ + +#ifdef CONFIG_HYSDN_CAPI +extern struct capi_driver_interface *hy_di; +extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ +extern int hycapi_capi_release(hysdn_card *); /* delete the device */ +extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ +extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *); +extern void hycapi_reset_ctr(struct capi_ctr *); +extern void hycapi_remove_ctr(struct capi_ctr *); +extern void hycapi_register_appl(struct capi_ctr *, __u16 appl, + capi_register_params *); +extern void hycapi_release_appl(struct capi_ctr *, __u16 appl); +extern void hycapi_send_message(struct capi_ctr *, struct sk_buff *skb); +extern char *hycapi_procinfo(struct capi_ctr *); +extern int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *card); +extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len); +extern void hycapi_tx_capiack(hysdn_card * card); +extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); +extern int hycapi_init(void); +extern void hycapi_cleanup(void); +#endif /* CONFIG_HYSDN_CAPI */ + +#endif /* HYSDN_DEFS_H */ diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 23b79ddd9..6ae0c3a7f 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_init.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_init.c,v 1.5 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, init functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_init.c,v $ + * Revision 1.5 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.4 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.3 2000/06/13 09:15:07 ualbrecht + * Module will now unload more gracefully. + * + * Revision 1.2 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -37,7 +49,7 @@ #include "hysdn_defs.h" -static char *hysdn_init_revision = "$Revision: 1.1 $"; +static char *hysdn_init_revision = "$Revision: 1.5 $"; int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ @@ -77,7 +89,6 @@ search_cards(void) { struct pci_dev *akt_pcidev = NULL; hysdn_card *card, *card_last; - uchar irq; int i; card_root = NULL; @@ -218,6 +229,14 @@ init_module(void) free_resources(); /* proc file_sys not created */ return (-1); } +#ifdef CONFIG_HYSDN_CAPI + if(cardmax > 0) { + if(hycapi_init()) { + printk(KERN_ERR "HYCAPI: init failed\n"); + return(-1); + } + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* no error */ } /* init_module */ @@ -233,8 +252,18 @@ init_module(void) void cleanup_module(void) { - +#ifdef CONFIG_HYSDN_CAPI + hysdn_card *card; +#endif /* CONFIG_HYSDN_CAPI */ stop_cards(); +#ifdef CONFIG_HYSDN_CAPI + card = card_root; /* first in chain */ + while (card) { + hycapi_capi_release(card); + card = card->next; /* remove card from chain */ + } /* while card */ + hycapi_cleanup(); +#endif /* CONFIG_HYSDN_CAPI */ hysdn_procconf_release(); free_resources(); printk(KERN_NOTICE "HYSDN: module unloaded\n"); diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 538dfe6d4..61441da10 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_net.c,v 1.3 2000/02/14 19:24:12 werner Exp $ +/* $Id: hysdn_net.c,v 1.7 2000/05/23 06:48:54 ualbrecht Exp $ * Linux driver for HYSDN cards, net (ethernet type) handling routines. * @@ -24,6 +24,19 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_net.c,v $ + * Revision 1.7 2000/05/23 06:48:54 ualbrecht + * Reverted last change in dev->name assignment (broken netdevice.h in 2.3.99pre6?) + * + * Revision 1.6 2000/05/17 11:43:03 ualbrecht + * Fixed a NULL-pointer kernel-oops assigning the device-name + * + * Revision 1.5 2000/05/06 00:52:38 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * + * Revision 1.4 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.3 2000/02/14 19:24:12 werner * * Removed superflous file @@ -52,7 +65,7 @@ #include "hysdn_defs.h" /* store the actual version for log reporting */ -char *hysdn_net_revision = "$Revision: 1.3 $"; +char *hysdn_net_revision = "$Revision: 1.7 $"; #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ @@ -308,7 +321,10 @@ hysdn_net_create(hysdn_card * card) { struct net_device *dev; int i; - + if(!card) { + printk(KERN_WARNING "No card-pt in hysdn_net_create!\n"); + return (-ENOMEM); + } hysdn_net_release(card); /* release an existing net device */ if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); @@ -323,6 +339,9 @@ hysdn_net_create(hysdn_card * card) dev->base_addr = card->iobase; /* IO address */ dev->irq = card->irq; /* irq */ dev->init = net_init; /* the init function of the device */ + if(dev->name) { + strcpy(dev->name, ((struct net_local *) dev)->dev_name); + } if ((i = register_netdev(dev))) { printk(KERN_WARNING "HYSDN: unable to create network device\n"); kfree(dev); diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index c28aedc1f..aa17c1014 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_procconf.c,v 1.4 2000/03/03 16:37:12 kai Exp $ +/* $Id: hysdn_procconf.c,v 1.7 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_procconf.c,v $ + * Revision 1.7 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.6 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.5 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.4 2000/03/03 16:37:12 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS @@ -49,7 +58,7 @@ #include "hysdn_defs.h" -static char *hysdn_procconf_revision = "$Revision: 1.4 $"; +static char *hysdn_procconf_revision = "$Revision: 1.7 $"; #define INFO_OUT_LEN 80 /* length of info line including lf */ @@ -335,7 +344,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep) *cp++ = '\n'; /* and now the data */ - sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s", + sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s", card->myid, card->bus, PCI_SLOT(card->devfn), diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index ba454b9dc..a0ac125fe 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_proclog.c,v 1.4 2000/03/03 16:37:12 kai Exp $ +/* $Id: hysdn_proclog.c,v 1.7 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, /proc/net filesystem log functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_proclog.c,v $ + * Revision 1.7 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.6 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.5 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.4 2000/03/03 16:37:12 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS @@ -49,8 +58,6 @@ #include "hysdn_defs.h" -static char *hysdn_proclog_revision = "$Revision: 1.4 $"; - /* the proc subdir for the interface is defined in the procconf module */ extern struct proc_dir_entry *hysdn_proc_entry; @@ -456,7 +463,7 @@ hysdn_proclog_init(hysdn_card * card) sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { pd->log->proc_fops = &log_fops; - pd->log->owner = THIS_MODULE; + pd->log->owner = THIS_MODULE; } init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c index 0e5f9e7ba..64b8782f0 100644 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_sched.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_sched.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc. * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_sched.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -29,6 +35,7 @@ */ #define __NO_VERSION__ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <asm/io.h> @@ -60,7 +67,12 @@ hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan) if (card->err_log_state == ERRLOG_STATE_ON) card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ break; - +#ifdef CONFIG_HYSDN_CAPI + case CHAN_CAPI: +/* give packet to CAPI handler */ + hycapi_rx_capipkt(card, buf, len); + break; +#endif /* CONFIG_HYSDN_CAPI */ default: printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); break; @@ -125,6 +137,17 @@ hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile } else hysdn_tx_netack(card); /* aknowledge packet -> throw away */ } /* send a network packet if available */ +#ifdef CONFIG_HYSDN_CAPI + if((skb = hycapi_tx_capiget(card)) != NULL) { + if (skb->len <= maxlen) { + memcpy(buf, skb->data, skb->len); + *len = skb->len; + *chan = CHAN_CAPI; + hycapi_tx_capiack(card); + return (1); /* go and send the data */ + } + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* nothing to send */ } /* hysdn_sched_tx */ diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h index c22974d85..9f9d3104d 100644 --- a/drivers/isdn/hysdn/ince1pc.h +++ b/drivers/isdn/hysdn/ince1pc.h @@ -1,132 +1,132 @@ -#ifndef __INCE1PC_H__
-#define __INCE1PC_H__
-
-/****************************************************************************
-
- FILE: ince1pc.h
-
- AUTHOR: M.Steinkopf
-
- PURPOSE: common definitions for both sides of the bus:
- - conventions both spoolers must know
- - channel numbers agreed upon
-
-*****************************************************************************/
-
-/* basic scalar definitions have same meanning,
- * but their declaration location depends on environment
- */
-
-/*--------------------------------------channel numbers---------------------*/
-#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
-#define CHAN_ERRLOG 0x0005 /* error logger */
-#define CHAN_CAPI 0x0064 /* CAPI interface */
-#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
-
-/*--------------------------------------POF ready msg-----------------------*/
- /* NOTE: after booting POF sends system ready message to PC: */
-#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
-#define RDY_MAGIC_SIZE 4 /* size in bytes */
-
-#define MAX_N_TOK_BYTES 255
-
-#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
-#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
-
-#define SYSR_TOK_END 0
-#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
-#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
-#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
-#define SYSR_TOK_ESC 255 /* undefined data size yet */
- /* default values, if not corrected by token: */
-#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
-#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
-
-/* syntax of new SYSR token stream:
- * channel: CHAN_SYSTEM
- * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
- * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
- * msg : 0 1 2 3 {4 5 6 ..}
- * S Y S R MAX_N_TOK_BYTES bytes of TokenStream
- *
- * TokenStream := empty
- * | {NonEndTokenChunk} EndToken RotlCRC
- * NonEndTokenChunk:= NonEndTokenId DataLen [Data]
- * NonEndTokenId := 0x01 .. 0xFE 1 BYTE
- * DataLen := 0x00 .. 0xFF 1 BYTE
- * Data := DataLen bytes
- * EndToken := 0x00
- * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
- * s. RotlCRC algorithm
- *
- * RotlCRC algorithm:
- * ucSum= 0 1 uchar
- * for all NonEndTokenChunk bytes:
- * ROTL(ucSum,1) rotate left by 1
- * ucSum += Char; add current byte with swap around
- * RotlCRC= ~ucSum; invert all bits for result
- *
- * note:
- * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
- */
-
-/*--------------------------------------error logger------------------------*/
- /* note: pof needs final 0 ! */
-#define ERRLOG_CMD_REQ "ERRLOG ON"
-#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
-#define ERRLOG_CMD_STOP "ERRLOG OFF"
-#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
-
-#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
- /* remaining text size = 55 */
-#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
-
+#ifndef __INCE1PC_H__ +#define __INCE1PC_H__ + +/**************************************************************************** + + FILE: ince1pc.h + + AUTHOR: M.Steinkopf + + PURPOSE: common definitions for both sides of the bus: + - conventions both spoolers must know + - channel numbers agreed upon + +*****************************************************************************/ + +/* basic scalar definitions have same meanning, + * but their declaration location depends on environment + */ + +/*--------------------------------------channel numbers---------------------*/ +#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ +#define CHAN_ERRLOG 0x0005 /* error logger */ +#define CHAN_CAPI 0x0064 /* CAPI interface */ +#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ + +/*--------------------------------------POF ready msg-----------------------*/ + /* NOTE: after booting POF sends system ready message to PC: */ +#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ +#define RDY_MAGIC_SIZE 4 /* size in bytes */ + +#define MAX_N_TOK_BYTES 255 + +#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE +#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + +#define SYSR_TOK_END 0 +#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ +#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ +#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ +#define SYSR_TOK_ESC 255 /* undefined data size yet */ + /* default values, if not corrected by token: */ +#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ +#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ + +/* syntax of new SYSR token stream: + * channel: CHAN_SYSTEM + * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE + * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + * msg : 0 1 2 3 {4 5 6 ..} + * S Y S R MAX_N_TOK_BYTES bytes of TokenStream + * + * TokenStream := empty + * | {NonEndTokenChunk} EndToken RotlCRC + * NonEndTokenChunk:= NonEndTokenId DataLen [Data] + * NonEndTokenId := 0x01 .. 0xFE 1 BYTE + * DataLen := 0x00 .. 0xFF 1 BYTE + * Data := DataLen bytes + * EndToken := 0x00 + * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes + * s. RotlCRC algorithm + * + * RotlCRC algorithm: + * ucSum= 0 1 uchar + * for all NonEndTokenChunk bytes: + * ROTL(ucSum,1) rotate left by 1 + * ucSum += Char; add current byte with swap around + * RotlCRC= ~ucSum; invert all bits for result + * + * note: + * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! + */ + +/*--------------------------------------error logger------------------------*/ + /* note: pof needs final 0 ! */ +#define ERRLOG_CMD_REQ "ERRLOG ON" +#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ +#define ERRLOG_CMD_STOP "ERRLOG OFF" +#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ + +#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ + /* remaining text size = 55 */ +#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1) + typedef struct ErrLogEntry_tag { -
+ /*00 */ ulong ulErrType; -
+ /*04 */ ulong ulErrSubtype; -
+ /*08 */ uchar ucTextSize; -
+ /*09 */ uchar ucText[ERRLOG_TEXT_SIZE]; /* ASCIIZ of len ucTextSize-1 */ -
-/*40 */
+ +/*40 */ } tErrLogEntry; -
-#if defined(__TURBOC__)
-#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
-#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
-#endif /*
*/ -#endif /*
*/ -
-/*--------------------------------------DPRAM boot spooler------------------*/
- /* this is the struture used between pc and
- * hyperstone to exchange boot data
- */
-#define DPRAM_SPOOLER_DATA_SIZE 0x20
+ +#if defined(__TURBOC__) +#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE +#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE +#endif /* */ +#endif /* */ + +/*--------------------------------------DPRAM boot spooler------------------*/ + /* this is the struture used between pc and + * hyperstone to exchange boot data + */ +#define DPRAM_SPOOLER_DATA_SIZE 0x20 typedef struct DpramBootSpooler_tag { -
+ /*00 */ uchar Len; -
+ /*01 */ volatile uchar RdPtr; -
+ /*02 */ uchar WrPtr; -
+ /*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE]; -
-/*23 */
+ +/*23 */ } tDpramBootSpooler; -
-#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
-#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
-
-/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
- /* at DPRAM offset 0x1C00: */
-#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
-
-
-#endif /* __INCE1PC_H__ */
+ +#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ +#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ + +/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ + /* at DPRAM offset 0x1C00: */ +#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ + + +#endif /* __INCE1PC_H__ */ diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 727165387..74905bba0 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.62 1999/09/06 07:29:35 fritz Exp $ +/* $Id: icn.c,v 1.63 2000/05/06 00:52:39 kai Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.63 2000/05/06 00:52:39 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * * Revision 1.62 1999/09/06 07:29:35 fritz * Changed my mail-address. * @@ -247,7 +251,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.62 $"; +*revision = "$Revision: 1.63 $"; static int icn_addcard(int, char *, char *); diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index caf46b112..5dffb2770 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.108 2000/06/24 15:52:47 keil Exp $ +/* $Id: isdn_common.c,v 1.111 2000/08/20 07:40:14 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -48,7 +48,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.108 $"; +static char *isdn_revision = "$Revision: 1.111 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1660,6 +1660,8 @@ isdn_open(struct inode *ino, struct file *filep) uint minor = MINOR(ino->i_rdev); int drvidx; int chidx; + int retval = -ENODEV; + if (minor == ISDN_MINOR_STATUS) { infostruct *p; @@ -1670,41 +1672,47 @@ isdn_open(struct inode *ino, struct file *filep) dev->infochain = p; /* At opening we allow a single update */ filep->private_data = (char *) 1; - return 0; - } else - return -ENOMEM; + retval = 0; + goto out; + } else { + retval = -ENOMEM; + goto out; + } } if (!dev->channels) - return -ENODEV; + goto out; if (minor < ISDN_MINOR_CTRL) { printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) - return -ENODEV; + goto out; chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + goto out; if (!(dev->drv[drvidx]->online & (1 << chidx))) - return -ENODEV; + goto out; isdn_lock_drivers(); - return 0; + retval = 0; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) - return -ENODEV; + goto out; isdn_lock_drivers(); - return 0; + retval = 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { - int ret; - if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) + retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); + if (retval == 0) isdn_lock_drivers(); - return ret; + goto out; } #endif - return -ENODEV; + out: + return retval; } static int @@ -1724,31 +1732,28 @@ isdn_close(struct inode *ino, struct file *filep) else dev->infochain = (infostruct *) (p->next); kfree(p); - unlock_kernel(); - return 0; + goto out; } q = p; p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - unlock_kernel(); - return 0; + goto out; } isdn_unlock_drivers(); - if (minor < ISDN_MINOR_CTRL) { - unlock_kernel(); - return 0; - } + if (minor < ISDN_MINOR_CTRL) + goto out; if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) dev->profd = NULL; - unlock_kernel(); - return 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); #endif + + out: unlock_kernel(); return 0; } diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 4951bb29e..d33fb5135 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.134 2000/06/21 09:54:29 keil Exp $ +/* $Id: isdn_net.c,v 1.135 2000/08/10 22:52:46 kai Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -181,7 +181,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); -char *isdn_net_revision = "$Revision: 1.134 $"; +char *isdn_net_revision = "$Revision: 1.135 $"; /* * Code for raw-networking over ISDN diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h index 20ab41046..6587cf84a 100644 --- a/drivers/isdn/isdn_ppp.h +++ b/drivers/isdn/isdn_ppp.h @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.16 2000/05/18 23:14:18 keil Exp $ +/* $Id: isdn_ppp.h,v 1.17 2000/08/10 22:52:46 kai Exp $ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c index ed681f375..1a32c0825 100644 --- a/drivers/isdn/pcbit/capi.c +++ b/drivers/isdn/pcbit/capi.c @@ -304,7 +304,14 @@ int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb) data_len = skb->len; - skb_push(skb, 10); + if(skb_headroom(skb) < 10) + { + printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb); + } + else + { + skb_push(skb, 10); + } *((u16 *) (skb->data)) = chan->callref; skb->data[2] = chan->layer2link; diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 3c21adb9f..cd58e0d3b 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -162,7 +162,7 @@ int pcbit_init_dev(int board, int mem_base, int irq) dev->send_seq = 0; dev->unack_seq = 0; - dev->hl_hdrlen = 10; + dev->hl_hdrlen = 16; dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL); @@ -186,7 +186,7 @@ int pcbit_init_dev(int board, int mem_base, int irq) ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS ); dev_if->writebuf_skb = pcbit_xmit; - dev_if->hl_hdrlen = 10; + dev_if->hl_hdrlen = 16; dev_if->maxbufsize = MAXBUFSIZE; dev_if->command = pcbit_command; @@ -518,9 +518,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, struct callb_data cbdata; int complete, err; isdn_ctrl ictl; -#ifdef DEBUG - struct msg_fmt * fmsg; -#endif switch(msg) { @@ -734,9 +731,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, default: printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n", msg); - fmsg = (struct msg_fmt *) &msg; - printk(KERN_DEBUG "cmd=%02x sub=%02x\n", - fmsg->cmd, fmsg->scmd); break; #endif } diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 36bd6f8aa..98daf7558 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -8,6 +8,11 @@ */ /* + * 19991203 - Fernando Carvalho - takion@superbofh.org + * Hacked to compile with egcs and run with current version of isdn modules +*/ + +/* * PCBIT-D low-layer interface */ @@ -205,7 +210,7 @@ pcbit_transmit(struct pcbit_dev *dev) /* Type 0 frame */ - struct msg_fmt *msg; + ulong msg; if (frame->skb) totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len; @@ -214,7 +219,7 @@ pcbit_transmit(struct pcbit_dev *dev) flen = MIN(totlen, free); - msg = (struct msg_fmt *) &(frame->msg); + msg = frame->msg; /* * Board level 2 header @@ -222,9 +227,9 @@ pcbit_transmit(struct pcbit_dev *dev) pcbit_writew(dev, flen - FRAME_HDR_LEN); - pcbit_writeb(dev, msg->cpu); + pcbit_writeb(dev, GET_MSG_CPU(msg)); - pcbit_writeb(dev, msg->proc); + pcbit_writeb(dev, GET_MSG_PROC(msg)); /* TH */ pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); @@ -244,8 +249,8 @@ pcbit_transmit(struct pcbit_dev *dev) pcbit_writew(dev, 0); /* C + S */ - pcbit_writeb(dev, msg->cmd); - pcbit_writeb(dev, msg->scmd); + pcbit_writeb(dev, GET_MSG_CMD(msg)); + pcbit_writeb(dev, GET_MSG_SCMD(msg)); /* NUM */ pcbit_writew(dev, frame->refnum); @@ -312,8 +317,7 @@ void pcbit_deliver(void *data) { struct frame_buf *frame; - unsigned long flags; - struct msg_fmt msg; + unsigned long flags, msg; struct pcbit_dev *dev = (struct pcbit_dev *) data; save_flags(flags); @@ -323,10 +327,10 @@ pcbit_deliver(void *data) dev->read_queue = frame->next; restore_flags(flags); - msg.cpu = 0; - msg.proc = 0; - msg.cmd = frame->skb->data[2]; - msg.scmd = frame->skb->data[3]; + SET_MSG_CPU(msg, 0); + SET_MSG_PROC(msg, 0); + SET_MSG_CMD(msg, frame->skb->data[2]); + SET_MSG_SCMD(msg, frame->skb->data[3]); frame->refnum = *((ushort *) frame->skb->data + 4); frame->msg = *((ulong *) & msg); diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h index 2f56a5844..f8984f990 100644 --- a/drivers/isdn/pcbit/layer2.h +++ b/drivers/isdn/pcbit/layer2.h @@ -7,6 +7,11 @@ * the GNU Public License, incorporated herein by reference. */ +/* + * 19991203 - Fernando Carvalho - takion@superbofh.org + * Hacked to compile with egcs and run with current version of isdn modules +*/ + /* * PCBIT-D low-layer interface definitions */ @@ -84,21 +89,20 @@ Intel 1 2 3 4 */ -struct msg_fmt { -#ifdef __LITTLE_ENDIAN /* Little Endian */ - u_char scmd; - u_char cmd; - u_char proc; - u_char cpu; +#ifdef __LITTLE_ENDIAN +#define SET_MSG_SCMD(msg, ch) (msg = (msg & 0xffffff00) | (((ch) & 0xff))) +#define SET_MSG_CMD(msg, ch) (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8)) +#define SET_MSG_PROC(msg, ch) (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16)) +#define SET_MSG_CPU(msg, ch) (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24)) + +#define GET_MSG_SCMD(msg) ((msg) & 0xFF) +#define GET_MSG_CMD(msg) ((msg) >> 8 & 0xFF) +#define GET_MSG_PROC(msg) ((msg) >> 16 & 0xFF) +#define GET_MSG_CPU(msg) ((msg) >> 24) + #else #error "Non-Intel CPU" - u_char cpu; - u_char proc; - u_char cmd; - u_char scmd; #endif -}; - #define MAX_QUEUED 7 @@ -107,14 +111,13 @@ struct msg_fmt { #define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */ - struct frame_buf { ulong msg; - unsigned short refnum; - unsigned short dt_len; - unsigned short hdr_len; + unsigned int refnum; + unsigned int dt_len; + unsigned int hdr_len; struct sk_buff *skb; - unsigned short copied; + unsigned int copied; struct frame_buf * next; }; diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c index 9d3aa8007..c85f68688 100644 --- a/drivers/isdn/pcbit/module.c +++ b/drivers/isdn/pcbit/module.c @@ -46,8 +46,8 @@ int pcbit_init(void) num_boards = 0; - printk(KERN_INFO - "PCBIT-D device driver v 0.5 - " + printk(KERN_NOTICE + "PCBIT-D device driver v 0.5-fjpc0 19991204 - " "Copyright (C) 1996 Universidade de Lisboa\n"); if (mem[0] || irq[0]) @@ -97,7 +97,7 @@ void cleanup_module(void) for (board = 0; board < num_boards; board++) pcbit_terminate(board); - printk(KERN_INFO + printk(KERN_NOTICE "PCBIT-D module unloaded\n"); } diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c index 7cff7a727..1c355dc28 100644 --- a/drivers/isdn/sc/timer.c +++ b/drivers/isdn/sc/timer.c @@ -1,5 +1,5 @@ /* - * $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $ + * $Id: timer.c,v 1.3 2000/05/06 00:52:39 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/media/Config.in b/drivers/media/Config.in new file mode 100644 index 000000000..ad64c65d4 --- /dev/null +++ b/drivers/media/Config.in @@ -0,0 +1,13 @@ +# +# Multimedia device configuration +# +mainmenu_option next_comment +comment 'Multimedia devices' + +tristate 'Video For Linux' CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + source drivers/media/video/Config.in + source drivers/media/radio/Config.in +fi + +endmenu diff --git a/drivers/media/Makefile b/drivers/media/Makefile new file mode 100644 index 000000000..348687b5f --- /dev/null +++ b/drivers/media/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the kernel multimedia device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +MEDIAS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o)) + +SUB_DIRS := video radio +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := media.o +O_OBJS := happy.o $(MEDIAS) + +include $(TOPDIR)/Rules.make diff --git a/drivers/media/happy.c b/drivers/media/happy.c new file mode 100644 index 000000000..4954935c1 --- /dev/null +++ b/drivers/media/happy.c @@ -0,0 +1 @@ +/* This is here to keep the linker happy. */ diff --git a/drivers/media/radio/Config.in b/drivers/media/radio/Config.in new file mode 100644 index 000000000..34b396acf --- /dev/null +++ b/drivers/media/radio/Config.in @@ -0,0 +1,52 @@ +# +# Multimedia Video device configuration +# +mainmenu_option next_comment +comment 'Radio Adapters' + +dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV +dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then + hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f +fi +dep_tristate ' AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then + hex ' RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c +fi +dep_tristate ' Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then + hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 +fi +dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then + hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c +fi +dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV +dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then + hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 +fi +dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then + hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590 +fi +dep_tristate ' Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_TRUST" = "y" ]; then + hex ' Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350 +fi +dep_tristate ' Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV +if [ "$CONFIG_PROC_FS" = "y" ]; then + if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then + bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS + fi +fi +if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then + hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316 + int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500 +fi +dep_tristate ' Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then + hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c +fi + +endmenu diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile new file mode 100644 index 000000000..1b74d6b88 --- /dev/null +++ b/drivers/media/radio/Makefile @@ -0,0 +1,75 @@ +# +# Makefile for the kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +O_OBJS := +OX_OBJS := +M_OBJS := +MX_OBJS := + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := radio.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := + +list-multi := + +obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o +obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o +obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o +obj-$(CONFIG_RADIO_CADET) += radio-cadet.o +obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o +obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o +obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o +obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o +obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o +obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o +obj-$(CONFIG_RADIO_TRUST) += radio-trust.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +include $(TOPDIR)/Rules.make diff --git a/drivers/char/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index d716c54bd..d716c54bd 100644 --- a/drivers/char/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c diff --git a/drivers/char/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 2fb8714ad..2fb8714ad 100644 --- a/drivers/char/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c diff --git a/drivers/char/radio-cadet.c b/drivers/media/radio/radio-cadet.c index ed2056dea..ed2056dea 100644 --- a/drivers/char/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c diff --git a/drivers/char/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 8b53dbd0d..8b53dbd0d 100644 --- a/drivers/char/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c diff --git a/drivers/char/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 15985380b..1068467c8 100644 --- a/drivers/char/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -10,7 +10,7 @@ #include <linux/init.h> /* Initdata */ #include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev.h> /* kernel radio structs */ -#include "../sound/miroaci.h" /* ACI Control by acimixer */ +#include "../../sound/miroaci.h" /* ACI Control by acimixer */ static int users = 0; diff --git a/drivers/char/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index c060ded4a..c060ded4a 100644 --- a/drivers/char/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c diff --git a/drivers/char/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 55328a96f..55328a96f 100644 --- a/drivers/char/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c diff --git a/drivers/char/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 1dda1618e..1dda1618e 100644 --- a/drivers/char/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c diff --git a/drivers/char/radio-trust.c b/drivers/media/radio/radio-trust.c index 4e86bda90..4e86bda90 100644 --- a/drivers/char/radio-trust.c +++ b/drivers/media/radio/radio-trust.c diff --git a/drivers/char/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index a0bbf343f..a0bbf343f 100644 --- a/drivers/char/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c diff --git a/drivers/char/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index dd688935a..dd688935a 100644 --- a/drivers/char/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c diff --git a/drivers/media/video/Config.in b/drivers/media/video/Config.in new file mode 100644 index 000000000..617dcda93 --- /dev/null +++ b/drivers/media/video/Config.in @@ -0,0 +1,45 @@ +# +# Multimedia Video device configuration +# +mainmenu_option next_comment +comment 'Video For Linux' + +bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS +dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C + +comment 'Video Adapters' +if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT +fi +dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV +if [ "$CONFIG_ALL_PPC" = "y" ]; then + dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV +fi +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + fi +fi +dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then + if [ "CONFIG_PARPORT_1284" != "n" ]; then + dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT + fi + if [ "$CONFIG_USB" != "n" ]; then + dep_tristate ' CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB + fi +fi +dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C +dep_tristate ' SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_SGI" = "y" ]; then + dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI + fi + dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI +fi +dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN +dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C + +endmenu diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile new file mode 100644 index 000000000..fac6990c4 --- /dev/null +++ b/drivers/media/video/Makefile @@ -0,0 +1,96 @@ +# +# Makefile for the kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +O_OBJS := +OX_OBJS := +M_OBJS := +MX_OBJS := + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := video.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := i2c-old.o videodev.o bttv-if.o cpia.o + +list-multi := bttv.o zoran.o +bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o +zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o + +obj-$(CONFIG_VIDEO_DEV) += videodev.o + +obj-$(CONFIG_BUS_I2C) += i2c-old.o +obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \ + tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o tuner.o +obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o + +obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o +obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o +obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o +obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o +obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o +obj-$(CONFIG_VIDEO_PMS) += pms.o +obj-$(CONFIG_VIDEO_PLANB) += planb.o +obj-$(CONFIG_VIDEO_VINO) += vino.o +obj-$(CONFIG_VIDEO_STRADIS) += stradis.o +obj-$(CONFIG_VIDEO_CPIA) += cpia.o +obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o +obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o +obj-$(CONFIG_TUNER_3036) += tuner-3036.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +include $(TOPDIR)/Rules.make + +fastdep: + +zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o + $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o + +bttv.o: $(bttv-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(bttv-objs) diff --git a/drivers/char/audiochip.h b/drivers/media/video/audiochip.h index 23d1b1259..23d1b1259 100644 --- a/drivers/char/audiochip.h +++ b/drivers/media/video/audiochip.h diff --git a/drivers/char/bt848.h b/drivers/media/video/bt848.h index 340accf31..340accf31 100644 --- a/drivers/char/bt848.h +++ b/drivers/media/video/bt848.h diff --git a/drivers/char/bttv-cards.c b/drivers/media/video/bttv-cards.c index b2c26e35b..b2c26e35b 100644 --- a/drivers/char/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c diff --git a/drivers/char/bttv-driver.c b/drivers/media/video/bttv-driver.c index 6c88a757e..6c88a757e 100644 --- a/drivers/char/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c diff --git a/drivers/char/bttv-if.c b/drivers/media/video/bttv-if.c index a58e441db..a58e441db 100644 --- a/drivers/char/bttv-if.c +++ b/drivers/media/video/bttv-if.c diff --git a/drivers/char/bttv.h b/drivers/media/video/bttv.h index 6b35d23e5..6b35d23e5 100644 --- a/drivers/char/bttv.h +++ b/drivers/media/video/bttv.h diff --git a/drivers/char/buz.c b/drivers/media/video/buz.c index ca3cb4f47..ca3cb4f47 100644 --- a/drivers/char/buz.c +++ b/drivers/media/video/buz.c diff --git a/drivers/char/buz.h b/drivers/media/video/buz.h index 06b794a09..06b794a09 100644 --- a/drivers/char/buz.h +++ b/drivers/media/video/buz.h diff --git a/drivers/char/bw-qcam.c b/drivers/media/video/bw-qcam.c index 17f7d25dc..17f7d25dc 100644 --- a/drivers/char/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c diff --git a/drivers/char/bw-qcam.h b/drivers/media/video/bw-qcam.h index 723e8ad9e..723e8ad9e 100644 --- a/drivers/char/bw-qcam.h +++ b/drivers/media/video/bw-qcam.h diff --git a/drivers/char/c-qcam.c b/drivers/media/video/c-qcam.c index fa96cc925..fa96cc925 100644 --- a/drivers/char/c-qcam.c +++ b/drivers/media/video/c-qcam.c diff --git a/drivers/char/cpia.c b/drivers/media/video/cpia.c index d7d007f01..d7d007f01 100644 --- a/drivers/char/cpia.c +++ b/drivers/media/video/cpia.c diff --git a/drivers/char/cpia.h b/drivers/media/video/cpia.h index 579b5e153..579b5e153 100644 --- a/drivers/char/cpia.h +++ b/drivers/media/video/cpia.h diff --git a/drivers/char/cpia_pp.c b/drivers/media/video/cpia_pp.c index 7d4be2744..7d4be2744 100644 --- a/drivers/char/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c diff --git a/drivers/char/cpia_usb.c b/drivers/media/video/cpia_usb.c index 6b67fbc81..6b67fbc81 100644 --- a/drivers/char/cpia_usb.c +++ b/drivers/media/video/cpia_usb.c diff --git a/drivers/char/cs8420.h b/drivers/media/video/cs8420.h index 2b22f3a38..2b22f3a38 100644 --- a/drivers/char/cs8420.h +++ b/drivers/media/video/cs8420.h diff --git a/drivers/char/i2c-old.c b/drivers/media/video/i2c-old.c index bd9750fc3..c896057cd 100644 --- a/drivers/char/i2c-old.c +++ b/drivers/media/video/i2c-old.c @@ -36,10 +36,6 @@ static struct i2c_bus *busses[I2C_BUS_MAX]; static struct i2c_driver *drivers[I2C_DRIVER_MAX]; static int bus_count = 0, driver_count = 0; -#ifdef CONFIG_VIDEO_BT848 -extern int i2c_tuner_init(void); -extern int msp3400c_init(void); -#endif #ifdef CONFIG_VIDEO_BUZ extern int saa7111_init(void); extern int saa7185_init(void); @@ -54,10 +50,6 @@ int i2c_init(void) printk(KERN_INFO "i2c: initialized%s\n", scan ? " (i2c bus scan enabled)" : ""); /* anything to do here ? */ -#ifdef CONFIG_VIDEO_BT848 - i2c_tuner_init(); - msp3400c_init(); -#endif #ifdef CONFIG_VIDEO_BUZ saa7111_init(); saa7185_init(); diff --git a/drivers/char/i2c-parport.c b/drivers/media/video/i2c-parport.c index 00b574f60..00b574f60 100644 --- a/drivers/char/i2c-parport.c +++ b/drivers/media/video/i2c-parport.c diff --git a/drivers/char/ibmmpeg2.h b/drivers/media/video/ibmmpeg2.h index 68e10387c..68e10387c 100644 --- a/drivers/char/ibmmpeg2.h +++ b/drivers/media/video/ibmmpeg2.h diff --git a/drivers/char/msp3400.c b/drivers/media/video/msp3400.c index 2d2b1e89c..2d2b1e89c 100644 --- a/drivers/char/msp3400.c +++ b/drivers/media/video/msp3400.c diff --git a/drivers/char/planb.c b/drivers/media/video/planb.c index 94707619d..94707619d 100644 --- a/drivers/char/planb.c +++ b/drivers/media/video/planb.c diff --git a/drivers/char/planb.h b/drivers/media/video/planb.h index 98d5697c9..98d5697c9 100644 --- a/drivers/char/planb.h +++ b/drivers/media/video/planb.h diff --git a/drivers/char/pms.c b/drivers/media/video/pms.c index 1e50880a0..1e50880a0 100644 --- a/drivers/char/pms.c +++ b/drivers/media/video/pms.c diff --git a/drivers/char/saa5249.c b/drivers/media/video/saa5249.c index 1213e2ee5..1213e2ee5 100644 --- a/drivers/char/saa5249.c +++ b/drivers/media/video/saa5249.c diff --git a/drivers/char/saa7110.c b/drivers/media/video/saa7110.c index 6146b84b9..6146b84b9 100644 --- a/drivers/char/saa7110.c +++ b/drivers/media/video/saa7110.c diff --git a/drivers/char/saa7111.c b/drivers/media/video/saa7111.c index 1eeeca352..1eeeca352 100644 --- a/drivers/char/saa7111.c +++ b/drivers/media/video/saa7111.c diff --git a/drivers/char/saa7121.h b/drivers/media/video/saa7121.h index 74e37d405..74e37d405 100644 --- a/drivers/char/saa7121.h +++ b/drivers/media/video/saa7121.h diff --git a/drivers/char/saa7146.h b/drivers/media/video/saa7146.h index 481308e6c..481308e6c 100644 --- a/drivers/char/saa7146.h +++ b/drivers/media/video/saa7146.h diff --git a/drivers/char/saa7146reg.h b/drivers/media/video/saa7146reg.h index 6cc910f50..6cc910f50 100644 --- a/drivers/char/saa7146reg.h +++ b/drivers/media/video/saa7146reg.h diff --git a/drivers/char/saa7185.c b/drivers/media/video/saa7185.c index c30e6353b..c30e6353b 100644 --- a/drivers/char/saa7185.c +++ b/drivers/media/video/saa7185.c diff --git a/drivers/char/saa7196.h b/drivers/media/video/saa7196.h index f92f21cfb..f92f21cfb 100644 --- a/drivers/char/saa7196.h +++ b/drivers/media/video/saa7196.h diff --git a/drivers/char/stallion.c b/drivers/media/video/stallion.c index a0faeada4..a0faeada4 100644 --- a/drivers/char/stallion.c +++ b/drivers/media/video/stallion.c diff --git a/drivers/char/stradis.c b/drivers/media/video/stradis.c index 03ca27a25..03ca27a25 100644 --- a/drivers/char/stradis.c +++ b/drivers/media/video/stradis.c diff --git a/drivers/char/tda7432.c b/drivers/media/video/tda7432.c index 488091310..488091310 100644 --- a/drivers/char/tda7432.c +++ b/drivers/media/video/tda7432.c diff --git a/drivers/char/tda8425.c b/drivers/media/video/tda8425.c index a1dec22eb..a1dec22eb 100644 --- a/drivers/char/tda8425.c +++ b/drivers/media/video/tda8425.c diff --git a/drivers/char/tda985x.c b/drivers/media/video/tda985x.c index 73fb9bd52..73fb9bd52 100644 --- a/drivers/char/tda985x.c +++ b/drivers/media/video/tda985x.c diff --git a/drivers/char/tda9875.c b/drivers/media/video/tda9875.c index 9f6ecd332..9f6ecd332 100644 --- a/drivers/char/tda9875.c +++ b/drivers/media/video/tda9875.c diff --git a/drivers/char/tea6300.c b/drivers/media/video/tea6300.c index f5949c94f..f5949c94f 100644 --- a/drivers/char/tea6300.c +++ b/drivers/media/video/tea6300.c diff --git a/drivers/char/tea6420.c b/drivers/media/video/tea6420.c index 231ed9e4e..3a1d63517 100644 --- a/drivers/char/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -9,6 +9,9 @@ * This code is placed under the terms of the GNU General Public License * Code liberally copied from msp3400.c, which is by Gerd Knorr * + * Changes: + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000 + * - resource allocation fixes in tea6300_attach */ #include <linux/module.h> @@ -141,8 +144,10 @@ static int tea6420_attach(struct i2c_adapter *adap, int addr, client->addr = addr; client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); - if (!tea) + if (!tea) { + kfree(client); return -ENOMEM; + } memset(tea,0,sizeof *tea); do_tea6420_init(client); diff --git a/drivers/char/tuner-3036.c b/drivers/media/video/tuner-3036.c index 807ae339b..807ae339b 100644 --- a/drivers/char/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c diff --git a/drivers/char/tuner.c b/drivers/media/video/tuner.c index dfbf0f6af..dfbf0f6af 100644 --- a/drivers/char/tuner.c +++ b/drivers/media/video/tuner.c diff --git a/drivers/char/tuner.h b/drivers/media/video/tuner.h index 96fcd3021..96fcd3021 100644 --- a/drivers/char/tuner.h +++ b/drivers/media/video/tuner.h diff --git a/drivers/char/tvmixer.c b/drivers/media/video/tvmixer.c index e1034a152..e1034a152 100644 --- a/drivers/char/tvmixer.c +++ b/drivers/media/video/tvmixer.c diff --git a/drivers/char/videodev.c b/drivers/media/video/videodev.c index c806ff264..c806ff264 100644 --- a/drivers/char/videodev.c +++ b/drivers/media/video/videodev.c diff --git a/drivers/char/vino.c b/drivers/media/video/vino.c index a9ac3086b..1ef64ae81 100644 --- a/drivers/char/vino.c +++ b/drivers/media/video/vino.c @@ -1,4 +1,4 @@ -/* $Id: vino.c,v 1.4 1999/02/09 23:59:36 ulfc Exp $ +/* $Id: vino.c,v 1.5 1999/10/09 00:01:14 ralf Exp $ * drivers/char/vino.c * * (incomplete) Driver for the Vino Video input system found in SGI Indys. diff --git a/drivers/char/vino.h b/drivers/media/video/vino.h index 8caadc9aa..8caadc9aa 100644 --- a/drivers/char/vino.h +++ b/drivers/media/video/vino.h diff --git a/drivers/char/zr36057.h b/drivers/media/video/zr36057.h index b672357bc..b672357bc 100644 --- a/drivers/char/zr36057.h +++ b/drivers/media/video/zr36057.h diff --git a/drivers/char/zr36060.h b/drivers/media/video/zr36060.h index d94f56b0b..d94f56b0b 100644 --- a/drivers/char/zr36060.h +++ b/drivers/media/video/zr36060.h diff --git a/drivers/char/zr36120.c b/drivers/media/video/zr36120.c index 6e860021e..6e860021e 100644 --- a/drivers/char/zr36120.c +++ b/drivers/media/video/zr36120.c diff --git a/drivers/char/zr36120.h b/drivers/media/video/zr36120.h index e500de10d..e500de10d 100644 --- a/drivers/char/zr36120.h +++ b/drivers/media/video/zr36120.h diff --git a/drivers/char/zr36120_i2c.c b/drivers/media/video/zr36120_i2c.c index 0de59b9f1..0de59b9f1 100644 --- a/drivers/char/zr36120_i2c.c +++ b/drivers/media/video/zr36120_i2c.c diff --git a/drivers/char/zr36120_mem.c b/drivers/media/video/zr36120_mem.c index b4c6078d3..b4c6078d3 100644 --- a/drivers/char/zr36120_mem.c +++ b/drivers/media/video/zr36120_mem.c diff --git a/drivers/char/zr36120_mem.h b/drivers/media/video/zr36120_mem.h index aad117acc..aad117acc 100644 --- a/drivers/char/zr36120_mem.h +++ b/drivers/media/video/zr36120_mem.h diff --git a/drivers/mtd/Config.in b/drivers/mtd/Config.in index 5f7622572..9023f0a81 100644 --- a/drivers/mtd/Config.in +++ b/drivers/mtd/Config.in @@ -20,7 +20,7 @@ if [ "$CONFIG_MTD" != "n" ]; then fi fi dep_tristate ' Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD - dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD + dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI if [ "$CONFIG_MTD_PMC551" != "n" ]; then bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX fi diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 61b51eeaf..ad9178ab9 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -280,6 +280,13 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) int i; /* + * Reserve I/O resource for exclusive use by this driver + */ + + if (!request_region(ioaddr, EL1_IO_EXTENT, dev->name)) + return -ENODEV; + + /* * Read the station address PROM data from the special port. */ @@ -302,15 +309,10 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) { mname = "NP943"; } - else - return -ENODEV; - - /* - * Grab the region so we can find the another board if autoIRQ fails. - */ - - if (!request_region(ioaddr, EL1_IO_EXTENT,"3c501")) + else { + release_region(ioaddr, EL1_IO_EXTENT); return -ENODEV; + } /* * We auto-IRQ by shutting off the interrupt line and letting it float @@ -332,6 +334,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) { printk("%s probe at %#x failed to detect IRQ line.\n", mname, ioaddr); + release_region(ioaddr, EL1_IO_EXTENT); return -EAGAIN; } } @@ -360,8 +363,10 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) */ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) + if (dev->priv == NULL) { + release_region(ioaddr, EL1_IO_EXTENT); return -ENOMEM; + } memset(dev->priv, 0, sizeof(struct net_local)); lp=dev->priv; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 9bb2fa52f..fd01a6025 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -77,7 +77,29 @@ - Print a warning on out-of-memory (rate limited to 1 per 10 secs) - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland) + LK1.1.7 2 Jul 2000 andrewm + - Better handling of shared IRQs + - Reset the transmitter on a Tx reclaim error + - Fixed crash under OOM during vortex_open() (Mark Hemment) + - Fix Rx cessation problem during OOM (help from Mark Hemment) + - The spinlocks around the mdio access were blocking interrupts for 300uS. + Fix all this to use spin_lock_bh() within mdio_read/write + - Only write to TxFreeThreshold if it's a boomerang - other NICs don't + have one. + - Added 802.3x MAC-layer flow control support + + LK1.1.8 13 Aug 2000 andrewm + - Ignore request_region() return value - already reserved if Cardbus. + - Merged some additional Cardbus flags from Don's 0.99Qk + - Some fixes for 3c556 (Fred Maciel) + - Fix for EISA initialisation (Jan Rkorajski) + - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers + - Fixed MII_XCVR_PWR for 3CCFE575CT + - Added INVERT_LED_PWR, used it. + - Backed out the extra_reset stuff + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. + - Also see Documentation/networking/vortex.txt */ /* @@ -103,8 +125,6 @@ static const int rx_copybreak = 200; static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 32; -/* Give the NIC an extra reset at the end of vortex_up() */ -static int extra_reset = 0; /* Tx timeout interval (millisecs) */ static int watchdog = 400; @@ -163,16 +183,16 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #include <linux/delay.h> static char version[] __devinitdata = -"3c59x.c:v0.99L+LK1.1.6 28 May 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.97 $\n"; +"3c59x.c:LK1.1.8 13 Aug 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.25 $\n"; MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(extra_reset, "i"); MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); @@ -281,8 +301,9 @@ enum pci_flags_bit { }; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, - EEPROM_230=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ - HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, }; + EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ + HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, + INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400 }; enum vortex_chips { @@ -312,14 +333,16 @@ enum vortex_chips { CH_3CSOHO100_TX, CH_3C555, + CH_3C556, CH_3C575, CH_3C575_1, - CH_3CCFE575, + CH_3CCFE575, CH_3CCFE575CT, CH_3CCFE656, CH_3CCFEM656, CH_3CCFEM656_1, + CH_3C450, }; @@ -383,24 +406,26 @@ static struct vortex_chip_info { PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3c555 Laptop Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c556 10/100 Mini PCI Adapter", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, }, {"3c575 [Megahertz] 10/100 LAN CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, {"3c575 Boomerang CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, - {"3CCFE575 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, + {"3CCFE575BT Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, }, {"3CCFE575CT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, {"3CCFE656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3CCFEM656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3CCFEM656 Cyclone CardBus(0x6564)", /* From pcmcia-cs-3.1.5 */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + {"3CCFEM656B Cyclone+Winmodem CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + {"3CCFE656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, + {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, - {0,}, /* 0 terminated list. */ }; @@ -432,16 +457,17 @@ static struct pci_device_id vortex_pci_tbl[] __devinitdata = { { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, + { 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 }, { 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 }, { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, - { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, + { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 }, - { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, + { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, {0,} /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); @@ -612,16 +638,20 @@ struct vortex_private { /* The remainder are related to chip state, mostly media selection. */ struct timer_list timer; /* Media selection timer. */ + struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ int options; /* User-settable misc. driver options. */ unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ full_duplex:1, force_fd:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ + flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ + partner_flow_ctrl:1, /* Partner supports flow control */ tx_full:1, has_nway:1, - open:1; + open:1, + must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ + int drv_flags; int tx_reset_resume; /* Flag to retart timer after vortex_error handling */ u16 status_enable; u16 intr_enable; @@ -632,7 +662,8 @@ struct vortex_private { u16 deferred; /* Resend these interrupts when we * bale from the ISR */ u16 io_size; /* Size of PCI region (for release_region) */ - spinlock_t lock; + spinlock_t lock; /* Serialise access to device & its vortex_private */ + spinlock_t mdio_lock; /* Serialise access to mdio hardware */ }; /* The action to take with a media selection timer tick. @@ -669,9 +700,10 @@ static void vortex_up(struct net_device *dev); static void vortex_down(struct net_device *dev); static int vortex_open(struct net_device *dev); static void mdio_sync(long ioaddr, int bits); -static int mdio_read(long ioaddr, int phy_id, int location); -static void mdio_write(long ioaddr, int phy_id, int location, int value); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *vp, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); +static void rx_oom_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); static int vortex_rx(struct net_device *dev); @@ -692,7 +724,9 @@ static void acpi_set_WOL(struct net_device *dev); #define MAX_UNITS 8 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* #define dev_alloc_skb dev_alloc_skb_debug */ /* A list of all installed Vortex EISA devices, for removing the driver module. */ static struct net_device *root_vortex_eisa_dev = NULL; @@ -746,7 +780,7 @@ static int __init vortex_eisa_init (void) for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { int device_id; - if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL) + if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "3c59x") == NULL) continue; /* Check the standard EISA ID register for an encoded '3Com'. */ @@ -780,7 +814,6 @@ static int __init vortex_eisa_init (void) return vortex_cards_found - orig_cards_found; } - /* returns count (>= 0), or negative on error */ static int __devinit vortex_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -815,6 +848,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, if (!printed_version) { printk (KERN_INFO "%s", version); + printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); printed_version = 1; } @@ -836,6 +870,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; + vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; vp->io_size = vci->io_size; @@ -848,11 +883,9 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, /* PCI-only startup logic */ if (pdev) { /* EISA resources already marked, so only PCI needs to do this here */ - if (!request_region (ioaddr, vci->io_size, dev->name)) { - printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", - dev->name, vci->io_size, ioaddr); - retval = -EBUSY; - goto free_dev; + /* Ignore return value, because Cardbus drivers already allocate for us */ + if (request_region(ioaddr, vci->io_size, dev->name) != NULL) { + vp->must_free_region = 1; } /* wake up and enable device */ @@ -866,15 +899,15 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, pci_set_master (pdev); } - vp->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&vp->lock); + spin_lock_init(&vp->mdio_lock); vp->pdev = pdev; /* Makes sure rings are at least 16 byte aligned. */ vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); - if (vp->rx_ring == 0) - { + if (vp->rx_ring == 0) { retval = -ENOMEM; goto free_region; } @@ -888,8 +921,8 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, pdev->driver_data = dev; /* The lower four bits are the media type. */ - if (dev->mem_start) - { /* + if (dev->mem_start) { + /* * AKPM: ewww.. The 'options' param is passed in as the third arg to the * LILO 'ether=' argument for non-modular use */ @@ -900,24 +933,26 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, else option = -1; + vp->media_override = 7; if (option >= 0) { vp->media_override = ((option & 7) == 2) ? 0 : option & 15; vp->full_duplex = (option & 0x200) ? 1 : 0; vp->bus_master = (option & 16) ? 1 : 0; - } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - vp->full_duplex = 1; + + if (card_idx < MAX_UNITS) { + if (full_duplex[card_idx] > 0) + vp->full_duplex = 1; + if (flow_ctrl[card_idx] > 0) + vp->flow_ctrl = 1; + } vp->force_fd = vp->full_duplex; vp->options = option; /* Read the station address from the EEPROM. */ EL3WINDOW(0); { - int base = (vci->drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read; + int base = (vci->drv_flags & EEPROM_8BIT) ? 0x230 : EEPROM_Read; for (i = 0; i < 0x40; i++) { int timer; outw(base + i, ioaddr + Wn0EepromCmd); @@ -960,17 +995,21 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, if (pdev && vci->drv_flags & HAS_CB_FNS) { unsigned long fn_st_addr; /* Cardbus function status space */ + unsigned short n; + fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) vp->cb_fn_base = ioremap(fn_st_addr, 128); printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n", dev->name, fn_st_addr, vp->cb_fn_base); -#if 1 /* AKPM: the 575_cb and 905B LEDs seem OK without this */ - if (vortex_pci_tbl[chip_idx].device != 0x5257) { - EL3WINDOW(2); - outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); - } -#endif + EL3WINDOW(2); + + n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + if (vp->drv_flags & INVERT_LED_PWR) + n |= 0x10; + if (vp->drv_flags & INVERT_MII_PWR) + n |= 0x4000; + outw(n, ioaddr + Wn2_ResetOptions); } /* Extract our information from the EEPROM data. */ @@ -978,8 +1017,7 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; - if (vp->info1 & 0x8000) - { + if (vp->info1 & 0x8000) { vp->full_duplex = 1; printk(KERN_INFO "Full duplex capable\n"); } @@ -1018,10 +1056,10 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, EL3WINDOW(4); mii_preamble_required++; mii_preamble_required++; - mdio_read(ioaddr, 24, 1); + mdio_read(dev, 24, 1); for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { int mii_status, phyx = phy & 0x1f; - mii_status = mdio_read(ioaddr, phyx, 1); + mii_status = mdio_read(dev, phyx, 1); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; printk(KERN_INFO " MII transceiver found at address %d," @@ -1035,11 +1073,11 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { - vp->advertising = mdio_read(ioaddr, vp->phys[0], 4); + vp->advertising = mdio_read(dev, vp->phys[0], 4); if (vp->full_duplex) { /* Only advertise the FD media types. */ vp->advertising &= ~0x02A0; - mdio_write(ioaddr, vp->phys[0], 4, vp->advertising); + mdio_write(dev, vp->phys[0], 4, vp->advertising); } } } @@ -1056,20 +1094,21 @@ static int __devinit vortex_probe1(struct pci_dev *pdev, } /* The 3c59x-specific entries in the device structure. */ - dev->open = &vortex_open; - dev->hard_start_xmit = &vortex_start_xmit; - dev->stop = &vortex_close; - dev->get_stats = &vortex_get_stats; - dev->do_ioctl = &vortex_ioctl; - dev->set_multicast_list = &set_rx_mode; - dev->tx_timeout = &vortex_tx_timeout; + dev->open = vortex_open; + dev->hard_start_xmit = vp->full_bus_master_tx ? + boomerang_start_xmit : vortex_start_xmit; + dev->stop = vortex_close; + dev->get_stats = vortex_get_stats; + dev->do_ioctl = vortex_ioctl; + dev->set_multicast_list = set_rx_mode; + dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; return 0; free_region: - release_region (ioaddr, vci->io_size); -free_dev: + if (vp->must_free_region) + release_region(ioaddr, vci->io_size); unregister_netdev(dev); kfree (dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); @@ -1082,8 +1121,7 @@ static void wait_for_completion(struct net_device *dev, int cmd) int i = 4000; outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - { + while (--i > 0) { if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) return; } @@ -1136,9 +1174,13 @@ vortex_up(struct net_device *dev) init_timer(&vp->timer); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); vp->timer.data = (unsigned long)dev; - vp->timer.function = &vortex_timer; /* timer handler */ + vp->timer.function = vortex_timer; /* timer handler */ add_timer(&vp->timer); + init_timer(&vp->rx_oom_timer); + vp->rx_oom_timer.data = (unsigned long)dev; + vp->rx_oom_timer.function = rx_oom_timer; + if (vortex_debug > 1) printk(KERN_DEBUG "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1157,13 +1199,14 @@ vortex_up(struct net_device *dev) int mii_reg1, mii_reg5; EL3WINDOW(4); /* Read BMSR (reg1) only to clear old status. */ - mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); - mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + mii_reg1 = mdio_read(dev, vp->phys[0], 1); + mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) ; /* No MII device or no link partner report */ else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ vp->full_duplex = 1; + vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); if (vortex_debug > 1) printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," " setting %s-duplex.\n", dev->name, vp->phys[0], @@ -1172,8 +1215,10 @@ vortex_up(struct net_device *dev) } /* Set the full-duplex bit. */ - outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); + outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0) | + ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), + ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) { printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n", @@ -1199,15 +1244,10 @@ vortex_up(struct net_device *dev) outw(0, ioaddr + i); if (vp->cb_fn_base) { - u_short n = inw(ioaddr + Wn2_ResetOptions); -#if 0 /* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */ - /* Inverted LED polarity */ - if (device_id != 0x5257) - n |= 0x0010; -#endif - /* Inverted polarity of MII power bit */ - if ((device_id == 0x6560) || (device_id == 0x6562) || - (device_id == 0x5257)) + unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + if (vp->drv_flags & INVERT_LED_PWR) + n |= 0x10; + if (vp->drv_flags & INVERT_MII_PWR) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); } @@ -1245,9 +1285,9 @@ vortex_up(struct net_device *dev) outl(vp->rx_ring_dma, ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ - dev->hard_start_xmit = &boomerang_start_xmit; vp->cur_tx = vp->dirty_tx = 0; - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ + if (vp->drv_flags & IS_BOOMERANG) + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Rx, Tx rings. */ for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */ vp->rx_ring[i].status = 0; @@ -1277,17 +1317,6 @@ vortex_up(struct net_device *dev) outw(vp->intr_enable, ioaddr + EL3_CMD); if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ writel(0x8000, vp->cb_fn_base + 4); - - if (extra_reset) - { - /* AKPM: unjam the 3CCFE575CT */ - wait_for_completion(dev, TxReset); - if (vp->full_bus_master_tx) { - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); - outw(DownUnstall, ioaddr + EL3_CMD); - } - outw(TxEnable, ioaddr + EL3_CMD); - } netif_start_queue (dev); } @@ -1301,9 +1330,9 @@ vortex_open(struct net_device *dev) MOD_INC_USE_COUNT; /* Use the now-standard shared IRQ implementation. */ - if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, - SA_SHIRQ, dev->name, dev)) { - retval = -EAGAIN; + if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? + &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); goto out; } @@ -1323,6 +1352,17 @@ vortex_open(struct net_device *dev) skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } + if (i != RX_RING_SIZE) { + int j; + for (j = 0; j < RX_RING_SIZE; j++) { + if (vp->rx_skbuff[j]) { + dev_kfree_skb(vp->rx_skbuff[j]); + vp->rx_skbuff[j] = 0; + } + } + retval = -ENOMEM; + goto out_free_irq; + } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); } @@ -1330,10 +1370,13 @@ vortex_open(struct net_device *dev) vortex_up(dev); vp->open = 1; return 0; + +out_free_irq: + free_irq(dev->irq, dev); out: - MOD_DEC_USE_COUNT; if (vortex_debug > 1) - printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval); + printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); + MOD_DEC_USE_COUNT; return retval; } @@ -1346,7 +1389,7 @@ static void vortex_timer(unsigned long data) int ok = 0; int media_status, mii_status, old_window; - if (vortex_debug > 1) { + if (vortex_debug > 2) { printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); @@ -1369,16 +1412,13 @@ static void vortex_timer(unsigned long data) break; case XCVR_MII: case XCVR_NWAY: { - unsigned long flags; - spin_lock_irqsave(&vp->lock, flags); /* AKPM: protect mdio state */ - - mii_status = mdio_read(ioaddr, vp->phys[0], 1); + mii_status = mdio_read(dev, vp->phys[0], 1); ok = 1; - if (vortex_debug > 1) + if (vortex_debug > 2) printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", dev->name, mii_status); if (mii_status & 0x0004) { - int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + int mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (! vp->force_fd && mii_reg5 != 0xffff) { int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; @@ -1390,17 +1430,16 @@ static void vortex_timer(unsigned long data) vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ EL3WINDOW(3); /* AKPM: this was missing from 2.3.99 3c59x.c! */ - outb((vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), - ioaddr + Wn3_MAC_Ctrl); + outw( (vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0) | + ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), + ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n"); /* AKPM: bug: should reset Tx and Rx after setting Duplex. Page 180 */ } - next_tick = 60*HZ; } } - spin_unlock_irqrestore(&vp->lock, flags); } break; default: /* Other media types handled by Tx timeouts. */ @@ -1445,7 +1484,7 @@ static void vortex_timer(unsigned long data) EL3WINDOW(old_window); enable_irq(dev->irq); - if (vortex_debug > 1) + if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1506,7 +1545,8 @@ static void vortex_tx_timeout(struct net_device *dev) } if (vp->tx_full) netif_stop_queue (dev); - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); + if (vp->drv_flags & IS_BOOMERANG) + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); } else { vp->stats.tx_dropped++; @@ -1549,8 +1589,8 @@ vortex_error(struct net_device *dev, int status) if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; outb(0, ioaddr + TxStatus); - if (tx_status & 0x38) /* AKPM: tx reset after 16 collisions, despite what the manual says */ - do_tx_reset = 1; + if (tx_status & 0x3a) /* TxReset after 16 collisions, despite what the manual says */ + do_tx_reset = 1; /* Also reset on reclaim errors */ else /* Merely re-enable the transmitter. */ outw(TxEnable, ioaddr + EL3_CMD); } @@ -1592,7 +1632,7 @@ vortex_error(struct net_device *dev, int status) /* In this case, blow the card away */ vortex_down(dev); wait_for_completion(dev, TotalReset | 0xff); - vortex_up(dev); + vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */ } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { @@ -1706,12 +1746,13 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; unsigned long flags; - if (vortex_debug > 6) + if (vortex_debug > 6) { printk(KERN_DEBUG "boomerang_start_xmit()\n"); + if (vortex_debug > 3) + printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", + dev->name, vp->cur_tx); + } - if (vortex_debug > 3) - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); if (vp->tx_full) { if (vortex_debug > 0) printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", @@ -1765,15 +1806,18 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) long ioaddr; int status; int work_done = max_interrupt_work; - - spin_lock(&vp->lock); ioaddr = dev->base_addr; + spin_lock(&vp->lock); + status = inw(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk("vortex_interrupt(). status=0x%4x\n", status); + if ((status & IntLatch) == 0) + goto handler_exit; /* No interrupt: shared IRQs cause this */ + if (status & IntReq) { status |= vp->deferred; vp->deferred = 0; @@ -1785,6 +1829,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (vortex_debug > 4) printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, inb(ioaddr + Timer)); + do { if (vortex_debug > 5) printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", @@ -1841,9 +1886,6 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); if (vortex_debug > 4) @@ -1866,14 +1908,22 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) int status; int work_done = max_interrupt_work; - spin_lock(&vp->lock); - ioaddr = dev->base_addr; + + /* + * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout + * and boomerang_start_xmit + */ + spin_lock(&vp->lock); + status = inw(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); + if ((status & IntLatch) == 0) + goto handler_exit; /* No interrupt: shared IRQs can cause this */ + if (status == 0xffff) { /* AKPM: h/w no longer present (hotplug)? */ if (vortex_debug > 1) printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); @@ -2120,6 +2170,8 @@ boomerang_rx(struct net_device *dev) printk(KERN_WARNING "%s: memory shortage\n", dev->name); last_jif = jiffies; } + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) + mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1)); break; /* Bad news! */ } skb->dev = dev; /* Mark as being used by this device. */ @@ -2133,6 +2185,26 @@ boomerang_rx(struct net_device *dev) return 0; } +/* + * If we've hit a total OOM refilling the Rx ring we poll once a second + * for some memory. Otherwise there is no way to restart the rx process. + */ +static void +rx_oom_timer(unsigned long arg) +{ + struct net_device *dev = (struct net_device *)arg; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + + spin_lock_irq(&vp->lock); + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ + boomerang_rx(dev); + if (vortex_debug > 1) { + printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, + ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); + } + spin_unlock_irq(&vp->lock); +} + static void vortex_down(struct net_device *dev) { @@ -2141,6 +2213,7 @@ vortex_down(struct net_device *dev) netif_stop_queue (dev); + del_timer_sync(&vp->rx_oom_timer); del_timer_sync(&vp->timer); /* Turn off statistics ASAP. We update vp->stats below. */ @@ -2311,16 +2384,13 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) u16 *data = (u16 *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; int retval; - unsigned long flags; - - spin_lock_irqsave(&vp->lock, flags); switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ EL3WINDOW(4); - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); retval = 0; break; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ @@ -2328,7 +2398,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) retval = -EPERM; } else { EL3WINDOW(4); - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); retval = 0; } break; @@ -2337,7 +2407,6 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; } - spin_unlock_irqrestore(&vp->lock, flags); return retval; } @@ -2393,13 +2462,17 @@ static void mdio_sync(long ioaddr, int bits) } } -static int mdio_read(long ioaddr, int phy_id, int location) +static int mdio_read(struct net_device *dev, int phy_id, int location) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; int i; + long ioaddr = dev->base_addr; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned int retval = 0; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; + spin_lock_bh(&vp->mdio_lock); + if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2419,15 +2492,20 @@ static int mdio_read(long ioaddr, int phy_id, int location) outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } + spin_unlock_bh(&vp->mdio_lock); return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; } -static void mdio_write(long ioaddr, int phy_id, int location, int value) +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; + spin_lock_bh(&vp->mdio_lock); + if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2446,7 +2524,7 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value) outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } - + spin_unlock_bh(&vp->mdio_lock); return; } @@ -2458,7 +2536,7 @@ static void acpi_set_WOL(struct net_device *dev) long ioaddr = dev->base_addr; /* AKPM: This kills the 905 */ - if (vortex_debug > 0) { + if (vortex_debug > 1) { printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n"); } return; @@ -2493,7 +2571,8 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) */ unregister_netdev(dev); outw(TotalReset, dev->base_addr + EL3_CMD); - release_region(dev->base_addr, vp->io_size); + if (vp->must_free_region) + release_region(dev->base_addr, vp->io_size); kfree(dev); } @@ -2516,21 +2595,15 @@ static int __init vortex_init (void) { int rc; - rc = pci_module_init (&vortex_driver); - if (rc < 0) - goto out; - - if (rc >= 0) /* AKPM: had "> 0" */ + rc = pci_module_init(&vortex_driver); + if (rc < 0) { + rc = vortex_eisa_init(); + if (rc > 0) + vortex_have_eisa = 1; + } else { vortex_have_pci = 1; + } - rc = vortex_eisa_init (); - if (rc < 0) - goto out; - - if (rc > 0) - vortex_have_eisa = 1; - -out: return rc; } @@ -2575,8 +2648,6 @@ module_exit(vortex_cleanup); /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 2f9442b22..8a2aff56d 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -8,9 +8,10 @@ source drivers/net/appletalk/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER +tristate 'Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP + tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP fi fi @@ -143,15 +144,18 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM fi tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 - tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi + dep_tristate ' National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' PCI NE2000 support' CONFIG_NE2K_PCI $CONFIG_PCI - # tristate ' Sundance Alta support' CONFIG_ALTA + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129 fi tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 + # tristate ' Sundance Alta support' CONFIG_ALTA tristate ' TI ThunderLAN support' CONFIG_TLAN tristate ' VIA Rhine support' CONFIG_VIA_RHINE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e5ac867a6..5aa7f5858 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -136,7 +136,7 @@ obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_DM9102) += dmfe.o obj-$(CONFIG_YELLOWFIN) += yellowfin.o obj-$(CONFIG_ACENIC) += acenic.o - +obj-$(CONFIG_NATSEMI) += natsemi.o obj-$(CONFIG_STNIC) += stnic.o 8390.o ifeq ($(CONFIG_SK98LIN),y) @@ -273,7 +273,7 @@ obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o - +obj-$(CONFIG_TUN) += tun.o # # HIPPI adapters # diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 25257b052..5a64da542 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -102,11 +102,10 @@ extern int macsonic_probe(struct net_device *dev); extern int mac8390_probe(struct net_device *dev); extern int mac89x0_probe(struct net_device *dev); - /* Gigabit Ethernet adapters */ - extern int yellowfin_probe(struct net_device *dev); +/* Gigabit Ethernet adapters */ +extern int yellowfin_probe(struct net_device *dev); /* Detachable devices ("pocket adaptors") */ -extern int atp_init(struct net_device *); extern int de600_probe(struct net_device *); extern int de620_probe(struct net_device *); @@ -310,9 +309,6 @@ struct devprobe parport_probes[] __initdata = { #ifdef CONFIG_DE620 /* D-Link DE-620 adapter */ {de620_probe, 0}, #endif -#ifdef CONFIG_ATP /* AT-LAN-TEC (RealTek) pocket adaptor. */ - {atp_init, 0}, -#endif {NULL, 0}, }; @@ -681,8 +677,15 @@ static struct net_device tr0_dev = { #undef NEXT_DEV #define NEXT_DEV (&escon0_dev) #endif - - + +#ifdef CONFIG_TUN + extern int tun_init(struct net_device *dev); + static struct net_device tun_dev = { + "tun", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, tun_init }; +# undef NEXT_DEV +# define NEXT_DEV (&tun_dev) +#endif + /* * The loopback device is global so it can be directly referenced * by the network code. Also, it must be first on device list. diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 096dd03c5..a898fbb02 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -154,7 +154,7 @@ static void set_multicast_list(struct net_device *dev); (detachable devices only). */ -int __init atp_init(struct net_device *dev) +static int __init atp_init(struct net_device *dev) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; int base_addr = dev->base_addr; @@ -336,6 +336,9 @@ static int net_open(struct net_device *dev) return -EAGAIN; } hardware_init(dev); + + MOD_INC_USE_COUNT; + netif_start_queue(dev); return 0; } @@ -702,6 +705,8 @@ static int net_close(struct net_device *dev) /* Leave the hardware in a reset state. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET); + MOD_DEC_USE_COUNT; + return 0; } @@ -735,35 +740,27 @@ static void set_multicast_list(struct net_device *dev) lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal; write_reg_high(ioaddr, CMR2, lp->addr_mode); } - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c atp.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ - -#ifdef MODULE -static int io = 0; -static struct net_device atp_dev = { - "", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_init }; - +/* module stuff */ +static int io; +static struct net_device atp_dev = { init: atp_init }; +MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); +MODULE_DESCRIPTION("Realtek 8002/8012 Pocket Lan Adapter"); MODULE_PARM(io, "I/O port of the pocket adapter"); -int init_module(void) -{ +static int __init atp_init_module(void) { atp_dev.base_addr = io; + if (register_netdev(&atp_dev) != 0) return -EIO; + return 0; } -void cleanup_module(void) -{ +static void __exit atp_cleanup_module(void) { unregister_netdev(&atp_dev); } -#endif +module_init(atp_init_module); +module_exit(atp_cleanup_module); + diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index c343bc53c..485852c0e 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -23,6 +23,8 @@ Convert to new PCI driver interface 2000 Mar 24 Dragan Stancevic <visitor@valinux.com> Disabled FC and ER, to avoid lockups when when we get FCP interrupts. + 2000 Jul 17 Goutham Rao <goutham.rao@intel.com> + PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary */ static const char *version = @@ -515,6 +517,7 @@ struct speedo_private { spinlock_t lock; /* Group with Tx control cache line. */ u32 tx_threshold; /* The value for txdesc.count. */ struct RxFD *last_rxf; /* Last filled RX buffer. */ + dma_addr_t last_rxf_dma; unsigned int cur_rx, dirty_rx; /* The next free ring entry */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ const char *product_name; @@ -1213,19 +1216,24 @@ speedo_init_rx_ring(struct net_device *dev) sp->rx_ring_dma[i] = pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); skb_reserve(skb, sizeof(struct RxFD)); - if (last_rxf) + if (last_rxf) { last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); + } last_rxf = rxf; rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], sizeof(struct RxFD), PCI_DMA_TODEVICE); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = last_rxf; + sp->last_rxf_dma = sp->rx_ring_dma[RX_RING_SIZE-1]; } static void speedo_purge_tx(struct net_device *dev) @@ -1660,6 +1668,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); rxf->rx_buf_addr = 0xffffffff; + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD), PCI_DMA_TODEVICE); return rxf; } @@ -1672,7 +1681,9 @@ static inline void speedo_rx_link(struct net_device *dev, int entry, rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); sp->last_rxf->link = cpu_to_le32(rxf_dma); sp->last_rxf->status &= cpu_to_le32(~0xC0000000); + pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = rxf; + sp->last_rxf_dma = rxf_dma; } static int speedo_refill_rx_buf(struct net_device *dev, int force) @@ -1738,9 +1749,17 @@ speedo_rx(struct net_device *dev) if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ - while (sp->rx_ringp[entry] != NULL && - (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) { - int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; + while (sp->rx_ringp[entry] != NULL) { + int pkt_len; + + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + + if(!((status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete)) { + break; + } + + pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; if (--rx_work_limit < 0) break; @@ -1782,7 +1801,8 @@ speedo_rx(struct net_device *dev) skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE); + #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -2166,6 +2186,8 @@ static void set_rx_mode(struct net_device *dev) mc_setup_frm->link = cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); + pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, mc_blk->len, PCI_DMA_TODEVICE); + wait_for_cmd_done(ioaddr + SCBCmd); clear_suspend(last_cmd); /* Immediately trigger the command unit resume. */ diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index f1723670c..afa7538af 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -19,17 +19,30 @@ Information and updates available at http://www.scyld.com/network/epic100.html + + --------------------------------------------------------------------- Linux kernel-specific changes: LK1.1.2 (jgarzik): - * Merge becker version 1.09 + * Merge becker version 1.09 (4/08/2000) LK1.1.3: * Major bugfix to 1.09 driver (Francis Romieu) + + LK1.1.4 (jgarzik): + * Merge becker test version 1.09 (5/29/2000) */ +/* These identify the driver base version and may not be removed. */ +static const char version[] = +"epic100.c:v1.09 5/29/2000 Written by Donald Becker <becker@scyld.com>\n"; +static const char version2[] = +" http://www.scyld.com/network/epic100.html\n"; +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n"; + /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -44,11 +57,12 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 200; +static int rx_copybreak = 0; /* Operational parameters that are set at compile time. */ -/* Keep the ring sizes a power of two for efficiency. +/* Keep the ring sizes a power of two for operational efficiency. + The compiler will convert <unsigned>'%'<2^N> into a bit mask. Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ @@ -73,7 +87,12 @@ static int rx_copybreak = 200; #error You must compile this driver with "-O". #endif +#include <linux/version.h> #include <linux/module.h> +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) +#include <linux/modversions.h> +#endif + #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> @@ -91,15 +110,6 @@ static int rx_copybreak = 200; #include <asm/bitops.h> #include <asm/io.h> -/* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = -"epic100.c:v1.09+LK1.1.3 6/17/2000 Written by Donald Becker <becker@scyld.com>\n"; -static char version2[] __devinitdata = -" http://www.scyld.com/network/epic100.html\n"; - -#define EPIC100_MODULE_NAME "epic100" -#define PFX EPIC100_MODULE_NAME ": " - MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); MODULE_PARM(debug, "i"); @@ -133,7 +143,7 @@ IVb. References http://www.smsc.com/main/datasheets/83c171.pdf http://www.smsc.com/main/datasheets/83c175.pdf -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://scyld.com/expert/NWay.html http://www.national.com/pf/DP/DP83840A.html IVc. Errata @@ -149,10 +159,8 @@ enum pci_id_flags_bits { PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, }; - enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; - #define EPIC_TOTAL_SIZE 0x100 #ifdef USE_IO_OPS #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0 @@ -289,6 +297,7 @@ struct epic_private { int tx_threshold; unsigned char mc_filter[8]; signed char phys[4]; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ int mii_phy_cnt; unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Current duplex setting. */ @@ -332,7 +341,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev, card_idx++; if (!printed_version++) - printk (KERN_INFO "%s" KERN_INFO "%s", version, version2); + printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version, version2, version3); if ((pci_resource_len(pdev, 0) < ci->io_size) || (pci_resource_len(pdev, 1) < ci->io_size)) { @@ -357,12 +367,12 @@ static int __devinit epic_init_one (struct pci_dev *pdev, * to them */ if (!request_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0), dev->name)) { - printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx); + printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); goto err_out_free_netdev; } if (!request_mem_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1), dev->name)) { - printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx); + printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); goto err_out_free_pio; } @@ -372,7 +382,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ioaddr = pci_resource_start (pdev, 1); ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { - printk (KERN_ERR PFX "card %d: ioremap failed\n", card_idx); + printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx); goto err_out_free_mmio; } #endif @@ -387,7 +397,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, duplex = full_duplex[card_idx]; } - pdev->driver_data = dev; + pdev->driver_data = dev; dev->base_addr = ioaddr; dev->irq = pdev->irq; @@ -426,25 +436,26 @@ static int __devinit epic_init_one (struct pci_dev *pdev, /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ + takes much time and no cards have external MII. */ { - int phy, phy_idx; - for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys); - phy++) { + int phy, phy_idx = 0; + for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { int mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { + if (mii_status != 0xffff && mii_status != 0x0000) { ep->phys[phy_idx++] = phy; printk(KERN_INFO "%s: MII transceiver #%d control " - "%4.4x status %4.4x.\n" - KERN_INFO "%s: Autonegotiation advertising %4.4x " - "link partner %4.4x.\n", - dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status, - dev->name, mdio_read(ioaddr, phy, 4), - mdio_read(ioaddr, phy, 5)); + "%4.4x status %4.4x.\n", + dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status); } } ep->mii_phy_cnt = phy_idx; - if (phy_idx == 0 && (ep->chip_flags & NO_MII) == 0) { + if (phy_idx != 0) { + phy = ep->phys[0]; + ep->advertising = mdio_read(ioaddr, phy, 4); + printk( KERN_INFO "%s: Autonegotiation advertising %4.4x link " + "partner %4.4x.\n", + dev->name, ep->advertising, mdio_read(ioaddr, phy, 5)); + } else if ( ! (ep->chip_flags & NO_MII)) { printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", dev->name); /* Use the known PHY address of the EPII. */ @@ -668,7 +679,7 @@ static int epic_open(struct net_device *dev) if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " "%s-duplex.\n", - dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL), + dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL), ep->full_duplex ? "full" : "half"); /* Set the timer to switch to check for link beat and perhaps switch @@ -752,8 +763,8 @@ static void epic_restart(struct net_device *dev) ioaddr + INTMASK); printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", - dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL), - inl(ioaddr + INTSTAT)); + dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), + (int)inl(ioaddr + INTSTAT)); return; } @@ -764,18 +775,19 @@ static void epic_timer(unsigned long data) long ioaddr = dev->base_addr; int next_tick = 60*HZ; int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0; + int negotiated = mii_reg5 & ep->advertising; + int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (debug > 3) { printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", - dev->name, inl(ioaddr + TxSTAT)); + dev->name, (int)inl(ioaddr + TxSTAT)); printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x " "IntStatus %4.4x RxStatus %4.4x.\n", - dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT), - inl(ioaddr + RxSTAT)); + dev->name, (int)inl(ioaddr + INTMASK), + (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); } - if (! ep->force_fd && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + if (! ep->force_fd) { if (ep->full_duplex != duplex) { ep->full_duplex = duplex; printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" @@ -797,7 +809,7 @@ static void epic_tx_timeout(struct net_device *dev) if (debug > 0) { printk(KERN_WARNING "%s: Transmit timeout using MII device, " "Tx status %4.4x.\n", - dev->name, inw(ioaddr + TxSTAT)); + dev->name, (int)inw(ioaddr + TxSTAT)); if (debug > 1) { printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n", dev->name, ep->dirty_tx, ep->cur_tx); @@ -880,11 +892,11 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) ep->tx_skbuff[entry] = skb; ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data); - if (free_count < TX_RING_SIZE/2) {/* Typical path */ + if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ ctrl_word = cpu_to_le32(0x100000); /* No interrupt */ - } else if (free_count == TX_RING_SIZE/2) { + } else if (free_count == TX_QUEUE_LEN/2) { ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */ - } else if (free_count < TX_RING_SIZE - 1) { + } else if (free_count < TX_QUEUE_LEN - 1) { ctrl_word = cpu_to_le32(0x100000); /* No Tx-done intr. */ } else { /* Leave room for an additional entry. */ @@ -910,7 +922,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, " "flag %2.2x Tx status %8.8x.\n", dev->name, (int)skb->len, entry, ctrl_word, - inl(dev->base_addr + TxSTAT)); + (int)inl(dev->base_addr + TxSTAT)); return 0; } @@ -924,7 +936,8 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - spin_lock(&ep->lock); + if (!spin_trylock(&ep->lock)) + return; do { status = inl(ioaddr + INTSTAT); @@ -932,9 +945,9 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) outl(status & 0x00007fff, ioaddr + INTSTAT); if (debug > 4) - printk(KERN_DEBUG "%s: interrupt interrupt=%#8.8x new " + printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " "intstat=%#8.8x.\n", - dev->name, status, inl(ioaddr + INTSTAT)); + dev->name, status, (int)inl(ioaddr + INTSTAT)); if ((status & IntrSummary) == 0) break; @@ -995,7 +1008,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) #endif ep->dirty_tx = dirty_tx; if (ep->tx_full - && cur_tx - dirty_tx < TX_RING_SIZE + 2) { + && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { /* The ring is no longer full, clear tbusy. */ ep->tx_full = 0; netif_wake_queue(dev); @@ -1044,7 +1057,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + INTSTAT)); + dev->name, status); spin_unlock(&ep->lock); } @@ -1144,7 +1157,7 @@ static int epic_close(struct net_device *dev) if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inl(ioaddr + INTSTAT)); + dev->name, (int)inl(ioaddr + INTSTAT)); del_timer_sync(&ep->timer); epic_pause(dev); @@ -1333,7 +1346,7 @@ static void epic_resume (struct pci_dev *pdev) static struct pci_driver epic_driver = { - name: EPIC100_MODULE_NAME, + name: "epic100", id_table: epic_pci_tbl, probe: epic_init_one, remove: epic_remove_one, @@ -1356,14 +1369,3 @@ static void __exit epic_cleanup (void) module_init(epic_init); module_exit(epic_cleanup); - - -/* - * Local variables: - * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia/include/" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 6c5964d83..60cef746f 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -843,6 +843,7 @@ static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev) } } + lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb(skb); } else { /* return unused page to the free memory queue */ @@ -1010,6 +1011,7 @@ static int ewrk3_rx(struct net_device *dev) ** Update stats */ lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) { if (pkt_len < i * EWRK3_PKT_BIN_SZ) { lp->pktStats.bins[i]++; diff --git a/drivers/net/fc/Makefile b/drivers/net/fc/Makefile index 87e599863..a36b9f855 100644 --- a/drivers/net/fc/Makefile +++ b/drivers/net/fc/Makefile @@ -1,27 +1,15 @@ - +# # Makefile for linux/drivers/net/fc # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). +# 9 Aug 2000, Christoph Hellwig <hch@caldera.de> +# Rewritten to use lists instead of if-statements. # -L_TARGET := fc.a -L_OBJS := -M_OBJS := -MX_OBJS := -FC_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) +O_TARGET := fc.o -ifeq ($(CONFIG_IPHASE5526),y) -L_OBJS += iph5526.o -else - ifeq ($(CONFIG_IPHASE5526),m) - M_OBJS += iph5526.o - endif -endif +obj-$(CONFIG_IPHASE5526) += iph5526.o -include $(TOPDIR)/Rules.make - -clean: - rm *.o +O_OBJS := $(obj-y) +M_OBJS := $(obj-m) +include $(TOPDIR)/Rules.make diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile index c2fb726c3..7ca3c1efd 100644 --- a/drivers/net/hamradio/Makefile +++ b/drivers/net/hamradio/Makefile @@ -1,153 +1,55 @@ -# File: drivers/hamradio/Makefile # # Makefile for the Linux AX.25 and HFMODEM device drivers. # +# # 19971130 Moved the amateur radio related network drivers from # drivers/net/ to drivers/hamradio for easier maintainance. # Joerg Reuter DL1BKE <jreuter@poboxes.com> +# +# 20000806 Rewritten to use lists instead of if-statements. +# Christoph Hellwig <hch@caldera.de> +# SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) soundmodem O_TARGET := hamradio.o -O_OBJS := -M_OBJS := - -# Need these to keep track of whether the hdlc module should -# really go in the kernel or a module. -CONFIG_HDLCDRV_BUILTIN := -CONFIG_HDLCDRV_MODULE := - -ifeq ($(CONFIG_DMASCC),y) -O_OBJS += dmascc.o -else - ifeq ($(CONFIG_DMASCC),m) - M_OBJS += dmascc.o - endif -endif - -ifeq ($(CONFIG_SCC),y) -O_OBJS += scc.o -else - ifeq ($(CONFIG_SCC),m) - M_OBJS += scc.o - endif -endif - -ifeq ($(CONFIG_MKISS),y) -O_OBJS += mkiss.o -else - ifeq ($(CONFIG_MKISS),m) - M_OBJS += mkiss.o - endif -endif - -ifeq ($(CONFIG_6PACK),y) -O_OBJS += 6pack.o -else - ifeq ($(CONFIG_6PACK),m) - M_OBJS += 6pack.o - endif -endif - -ifeq ($(CONFIG_YAM),y) -O_OBJS += yam.o -else - ifeq ($(CONFIG_YAM),m) - M_OBJS += yam.o - endif -endif - -ifeq ($(CONFIG_PI),y) -O_OBJS += pi2.o -else - ifeq ($(CONFIG_PI),m) - M_OBJS += pi2.o - endif -endif -ifeq ($(CONFIG_PT),y) -O_OBJS += pt.o -else - ifeq ($(CONFIG_PT),m) - M_OBJS += pt.o - endif -endif - -ifeq ($(CONFIG_BPQETHER),y) -O_OBJS += bpqether.o -else - ifeq ($(CONFIG_BPQETHER),m) - M_OBJS += bpqether.o - endif -endif +export-objs = hdlcdrv.o -ifeq ($(CONFIG_BAYCOM_SER_FDX),y) -O_OBJS += baycom_ser_fdx.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_SER_FDX),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_ser_fdx.o - endif -endif -ifeq ($(CONFIG_BAYCOM_SER_HDX),y) -O_OBJS += baycom_ser_hdx.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_SER_HDX),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_ser_hdx.o - endif -endif - -ifeq ($(CONFIG_BAYCOM_PAR),y) -O_OBJS += baycom_par.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_PAR),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_par.o - endif -endif - -ifeq ($(CONFIG_BAYCOM_EPP),y) -O_OBJS += baycom_epp.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_EPP),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_epp.o - endif -endif +obj-$(CONFIG_DMASCC) += dmascc.o +obj-$(CONFIG_SCC) += scc.o +obj-$(CONFIG_MKISS) += mkiss.o +obj-$(CONFIG_6PACK) += 6pack.o +obj-$(CONFIG_YAM) += yam.o +obj-$(CONFIG_PI) += pi2.o +obj-$(CONFIG_PT) += pt.o +obj-$(CONFIG_BPQETHER) += bpqether.o +obj-$(CONFIG_BAYCOM_SER_FDX) += baycom_ser_fdx.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_SER_HDX) += baycom_ser_hdx.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_PAR) += baycom_par.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_EPP) += baycom_epp.o hdlcdrv.o +obj-$(CONFIG_SOUNDMODEM) += hdlcdrv.o ifeq ($(CONFIG_SOUNDMODEM),y) -ALL_SUB_DIRS += soundmodem SUB_DIRS += soundmodem O_OBJS += soundmodem/soundmodem.o -CONFIG_HDLCDRV_BUILTIN = y else ifeq ($(CONFIG_SOUNDMODEM),m) - CONFIG_HDLCDRV_MODULE = y - ALL_SUB_DIRS += soundmodem MOD_SUB_DIRS += soundmodem endif endif -# If anything built-in uses the hdlcdrv, then build it into the kernel also. -# If not, but a module uses it, build as a module. -ifdef CONFIG_HDLCDRV_BUILTIN -OX_OBJS += hdlcdrv.o -else - ifdef CONFIG_HDLCDRV_MODULE - MX_OBJS += hdlcdrv.o - endif -endif +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) -include $(TOPDIR)/Rules.make +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -clean: - rm -f core *.o *.a *.s +include $(TOPDIR)/Rules.make diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index cc60b41a3..99d8c65aa 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -120,8 +120,8 @@ please (!) contact me first. New versions of the driver will be announced on the linux-hams - mailing list on vger.rutgers.edu. To subscribe send an e-mail - to majordomo@vger.rutgers.edu with the following line in + mailing list on vger.kernel.org. To subscribe send an e-mail + to majordomo@vger.kernel.org with the following line in the body of the mail: subscribe linux-hams diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 53ee8867c..f923bf012 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -1,121 +1,40 @@ -# File: drivers/irda/Makefile # # Makefile for the Linux IrDA infrared port device drivers. # +# 9 Aug 2000, Christoph Hellwig <hch@caldera.de> +# Rewritten to use lists instead of if-statements. +# SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := irda_drivers.a -L_OBJS := -M_OBJS := - -ifeq ($(CONFIG_IRTTY_SIR),y) -L_OBJS += irtty.o -else - ifeq ($(CONFIG_IRTTY_SIR),m) - M_OBJS += irtty.o - endif -endif - -ifeq ($(CONFIG_IRPORT_SIR),y) -LX_OBJS += irport.o -else - ifeq ($(CONFIG_IRPORT_SIR),m) - MX_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_NSC_FIR),y) -L_OBJS += nsc-ircc.o -else - ifeq ($(CONFIG_NSC_FIR),m) - M_OBJS += nsc-ircc.o - endif -endif - -ifeq ($(CONFIG_WINBOND_FIR),y) -L_OBJS += w83977af_ir.o -else - ifeq ($(CONFIG_WINBOND_FIR),m) - M_OBJS += w83977af_ir.o - endif -endif - -ifeq ($(CONFIG_TOSHIBA_FIR),y) -L_OBJS += toshoboe.o -else - ifeq ($(CONFIG_TOSHIBA_FIR),m) - M_OBJS += toshoboe.o - endif -endif - -ifeq ($(CONFIG_SMC_IRCC_FIR),y) -L_OBJS += smc-ircc.o -LX_OBJS += irport.o -else - ifeq ($(CONFIG_SMC_IRCC_FIR),m) - M_OBJS += smc-ircc.o - MX_OBJS += irport.o - endif -endif +O_TARGET := irda.o -ifeq ($(CONFIG_ESI_DONGLE),y) -L_OBJS += esi.o -else - ifeq ($(CONFIG_ESI_DONGLE),m) - M_OBJS += esi.o - endif -endif +export-objs = irport.o -ifeq ($(CONFIG_TEKRAM_DONGLE),y) -L_OBJS += tekram.o -else - ifeq ($(CONFIG_TEKRAM_DONGLE),m) - M_OBJS += tekram.o - endif -endif -ifeq ($(CONFIG_ACTISYS_DONGLE),y) -L_OBJS += actisys.o -else - ifeq ($(CONFIG_ACTISYS_DONGLE),m) - M_OBJS += actisys.o - endif -endif +obj-$(CONFIG_IRTTY_SIR) += irtty.o +obj-$(CONFIG_IRPORT_SIR) += irport.o +obj-$(CONFIG_NSC_FIR) += nsc-ircc.o +obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o +obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o +obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o +obj-$(CONFIG_ESI_DONGLE) += esi.o +obj-$(CONFIG_TEKRAM_DONGLE) += tekram.o +obj-$(CONFIG_ACTISYS_DONGLE) += actisys.o +obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o +obj-$(CONFIG_LITELINK_DONGLE) += litelink.o +obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o -ifeq ($(CONFIG_GIRBIL_DONGLE),y) -L_OBJS += girbil.o -else - ifeq ($(CONFIG_GIRBIL_DONGLE),m) - M_OBJS += girbil.o - endif -endif -ifeq ($(CONFIG_LITELINK_DONGLE),y) -L_OBJS += litelink.o -else - ifeq ($(CONFIG_LITELINK_DONGLE),m) - M_OBJS += litelink.o - endif -endif +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) -ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y) -L_OBJS += old_belkin.o -else - ifeq ($(CONFIG_OLD_BELKIN_DONGLE),m) - M_OBJS += old_belkin.o - endif -endif +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make - -clean: - rm -f core *.o *.a *.s - - - - - - diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c new file mode 100644 index 000000000..565ddc52b --- /dev/null +++ b/drivers/net/natsemi.c @@ -0,0 +1,1186 @@ +/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP83810 series. */ +/* + Written/copyright 1999-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. License for under other terms may be + available. Contact the original author for details. + + The original author may be reached as becker@scyld.com, or at + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support information and updates available at + http://www.scyld.com/network/netsemi.html +*/ + +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"natsemi.c:v1.05 8/7/2000 Written by Donald Becker <becker@scyld.com>\n"; +static const char version2[] = +" http://www.scyld.com/network/natsemi.html\n"; +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.0.0, August 10, 2000)\n"; +/* Updated to recommendations in pci-skeleton v2.03. */ + +/* Automatically extracted configuration info: +probe-func: natsemi_probe +config-in: tristate 'National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI + +c-help-name: National Semiconductor DP83810 series PCI Ethernet support +c-help-symbol: CONFIG_NATSEMI +c-help: This driver is for the National Semiconductor DP83810 series, +c-help: including the 83815 chip. +c-help: More specific information and updates are available from +c-help: http://www.scyld.com/network/natsemi.html +*/ + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; +static int mtu = 0; +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + This chip uses a 512 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 100; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static int rx_copybreak = 0; + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert <unsigned>'%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 32 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <asm/processor.h> /* Processor type for cache alignment. */ +#include <asm/bitops.h> +#include <asm/io.h> + +/* Condensed operations for readability. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); +MODULE_DESCRIPTION("National Semiconductor DP83810 series PCI Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is designed for National Semiconductor DP83815 PCI Ethernet NIC. +It also works with other chips in in the DP83810 series. + +II. Board-specific settings + +This driver requires the PCI interrupt line to be valid. +It honors the EEPROM-set values. + +III. Driver operation + +IIIa. Ring buffers + +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. +The NatSemi design uses a 'next descriptor' pointer that the driver forms +into a list. + +IIIb/c. Transmit/Receive Structure + +This driver uses a zero-copy receive and transmit scheme. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the chip as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack. Buffers consumed this way are replaced by newly allocated +skbuffs in a later phase of receives. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. New boards are typically used in generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. When copying is done, the cost is usually mitigated by using +a combined copy/checksum routine. Copying also preloads the cache, which is +most useful with small frames. + +A subtle aspect of the operation is that unaligned buffers are not permitted +by the hardware. Thus the IP header at offset 14 in an ethernet frame isn't +longword aligned for further processing. On copies frames are put into the +skbuff at an offset of "+2", 16-byte aligning the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +NatSemi PCI network controllers are very uncommon. + +IVb. References + +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html +No NatSemi datasheet was publically available at the initial release date. + +IVc. Errata + +None characterised. +*/ + + + +enum pcistuff { + PCI_USES_IO = 0x01, + PCI_USES_MEM = 0x02, + PCI_USES_MASTER = 0x04, + PCI_ADDR0 = 0x08, + PCI_ADDR1 = 0x10, +}; + +/* MMIO operations required */ +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) + + +/* array of board data directly indexed by pci_tbl[x].driver_data */ +static struct { + const char *name; + unsigned long flags; +} natsemi_pci_info[] __devinitdata = { + { "NatSemi DP83815", PCI_IOTYPE }, +}; + +static struct pci_device_id natsemi_pci_tbl[] __devinitdata = { + { 0x100B, 0x0020, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl); + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. +*/ +enum register_offsets { + ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C, + IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, + TxRingPtr=0x20, TxConfig=0x24, + RxRingPtr=0x30, RxConfig=0x34, + WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, + BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, + RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, +}; + +/* Bit in ChipCmd. */ +enum ChipCmdBits { + ChipReset=0x100, RxReset=0x20, TxReset=0x10, RxOff=0x08, RxOn=0x04, + TxOff=0x02, TxOn=0x01, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008, + IntrRxIdle=0x0010, IntrRxOverrun=0x0020, + IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100, + IntrTxIdle=0x0200, IntrTxOverrun=0x0400, + StatsMax=0x0800, LinkChange=0x4000, + WOLPkt=0x2000, + RxResetDone=0x1000000, TxResetDone=0x2000000, + IntrPCIErr=0x00f00000, + IntrNormalSummary=0x0251, IntrAbnormalSummary=0xCD20, +}; + +/* Bits in the RxMode register. */ +enum rx_mode_bits { + AcceptErr=0x20, AcceptRunt=0x10, + AcceptBroadcast=0xC0000000, + AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000, + AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000, +}; + +/* The Rx and Tx buffer descriptors. */ +/* Note that using only 32 bit fields simplifies conversion to big-endian + architectures. */ +struct netdev_desc { + u32 next_desc; + s32 cmd_status; + u32 addr; + u32 software_use; +}; + +/* Bits in network_desc.status */ +enum desc_status_bits { + DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000, + DescNoCRC=0x10000000, + DescPktOK=0x08000000, RxTooLong=0x00400000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct netdev_desc rx_ring[RX_RING_SIZE]; + struct netdev_desc tx_ring[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + /* Frequently used values: keep some adjacent for cache effect. */ + struct pci_dev *pci_dev; + struct netdev_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* Rx filter. */ + u32 cur_rx_mode; + u32 rx_filter[16]; + /* FIFO and PCI burst thresholds. */ + int tx_config, rx_config; + /* MII transceiver section. */ + u16 advertising; /* NWay media advertisement */ + + unsigned int iosize; + spinlock_t lock; +}; + +static int eeprom_read(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(struct net_device *dev); +static int start_tx(struct sk_buff *skb, struct net_device *dev); +static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + +static int __devinit natsemi_probe1 (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct netdev_private *np; + int i, option, irq = pdev->irq, chip_idx = ent->driver_data; + static int find_cnt = -1; + static int printed_version; + unsigned long ioaddr; + const int pcibar = 1; /* PCI base address register */ + + if ((debug <= 1) && !printed_version++) + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); + + find_cnt++; + option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; + ioaddr = pci_resource_start(pdev, pcibar); + + if (pci_enable_device(pdev)) + return -EIO; + if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER) + pci_set_master(pdev); + + dev = init_etherdev(NULL, sizeof (struct netdev_private)); + if (!dev) + return -ENOMEM; + + { + void *mmio; + if (request_mem_region(ioaddr, pci_resource_len (pdev, pcibar), + dev->name) == NULL) { + unregister_netdev(dev); + kfree(dev); + return -EBUSY; + } + mmio = ioremap (ioaddr, pci_resource_len (pdev, pcibar)); + if (!mmio) { + release_mem_region(ioaddr, pci_resource_len (pdev, pcibar)); + unregister_netdev(dev); + kfree(dev); + return -ENOMEM; + } + ioaddr = (unsigned long) mmio; + } + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = be16_to_cpu(eeprom_read(ioaddr, i + 7)); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + +#if ! defined(final_version) /* Dump the EEPROM contents during development. */ + if (debug > 4) + for (i = 0; i < 64; i++) + printk("%4.4x%s", + eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n"); +#endif + + /* Reset the chip to erase previous misconfiguration. */ + writel(ChipReset, ioaddr + ChipCmd); + + dev->base_addr = ioaddr; + dev->irq = irq; + + np = dev->priv; + + np->pci_dev = pdev; + pdev->driver_data = dev; + np->iosize = pci_resource_len(pdev, pcibar); + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = &tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + if (mtu) + dev->mtu = mtu; + + np->advertising = readl(ioaddr + 0x90); + printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", + dev->name, (int)readl(ioaddr + 0x84), np->advertising); + + return 0; +} + + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. + The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need + a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that + made udelay() unreliable. + The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is + depricated. +*/ +#define eeprom_delay(ee_addr) readl(ee_addr) + +enum EEPROM_Ctrl_Bits { + EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02, +}; +#define EE_Write0 (EE_ChipSelect) +#define EE_Write1 (EE_ChipSelect | EE_DataIn) + +/* The EEPROM commands include the alway-set leading bit. */ +enum EEPROM_Cmds { + EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), +}; + +static int eeprom_read(long addr, int location) +{ + int i; + int retval = 0; + int ee_addr = addr + EECtrl; + int read_cmd = location | EE_ReadCmd; + writel(EE_Write0, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; + writel(dataval, ee_addr); + eeprom_delay(ee_addr); + writel(dataval | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + } + writel(EE_ChipSelect, ee_addr); + + for (i = 16; i > 0; i--) { + writel(EE_ChipSelect | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + retval = (retval << 1) | ((readl(ee_addr) & EE_DataOut) ? 1 : 0); + writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); + } + + /* Terminate the EEPROM access. */ + writel(EE_Write0, ee_addr); + writel(0, ee_addr); + return retval; +} + +/* MII transceiver control section. + The 83815 series has an internal transceiver, and we present the + management registers as if they were MII connected. */ + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + if (phy_id == 1 && location < 32) + return readl(dev->base_addr + 0x80 + (location<<2)) & 0xffff; + else + return 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + if (phy_id == 1 && location < 32) + writew(value, dev->base_addr + 0x80 + (location<<2)); +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Do we need to reset the chip??? */ + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (debug > 1) + printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + dev->name, dev->irq); + + init_ring(dev); + + writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); + writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + + for (i = 0; i < 6; i += 2) { + writel(i, ioaddr + RxFilterAddr); + writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8), + ioaddr + RxFilterData); + } + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + /* Configure for standard, in-spec Ethernet. */ + np->tx_config = 0x10800802; + writel(np->tx_config, ioaddr + TxConfig); + np->rx_config = 0x0020; + writel(np->rx_config, ioaddr + RxConfig); + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + netif_start_queue(dev); + + check_duplex(dev); + set_rx_mode(dev); + + /* Enable interrupts by setting the interrupt mask. */ + writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask); + writel(1, ioaddr + IntrEnable); + + writel(RxOn | TxOn, ioaddr + ChipCmd); + writel(4, ioaddr + StatsCtrl); /* Clear Stats */ + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", + dev->name, (int)readl(ioaddr + ChipCmd)); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = jiffies + 3*HZ; + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int duplex; + + if (np->duplex_lock) + return; + duplex = readl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug) + printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" + " capability.\n", dev->name, + duplex ? "full" : "half"); + if (duplex) { + np->rx_config |= 0x10000000; + np->tx_config |= 0xC0000000; + } else { + np->rx_config &= ~0x10000000; + np->tx_config &= ~0xC0000000; + } + writew(np->tx_config, ioaddr + TxConfig); + writew(np->rx_config, ioaddr + RxConfig); + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (debug > 3) + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + check_duplex(dev); + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].cmd_status); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->dirty_tx = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); + np->rx_ring[i].cmd_status = DescOwn; + np->rx_skbuff[i] = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[i].addr = virt_to_le32desc(skb->tail); + np->rx_ring[i].cmd_status = + cpu_to_le32(DescIntr | np->rx_buf_sz); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]); + np->tx_ring[i].cmd_status = 0; + } + np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]); + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + unsigned entry; + + /* Note: Ordering is important here, set the field with the + "ownership" bit last, and only then increment cur_tx. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + + np->tx_skbuff[entry] = skb; + + np->tx_ring[entry].addr = virt_to_le32desc(skb->data); + np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len); + np->cur_tx++; + + /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ + + if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) { + np->tx_full = 1; + netif_stop_queue(dev); + } + /* Wake the potentially-idle transmit channel. */ + writel(TxOn, dev->base_addr + ChipCmd); + + dev->trans_start = jiffies; + + if (debug > 4) { + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np; + long ioaddr; + int boguscnt = max_interrupt_work; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown " + "device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + np = (struct netdev_private *)dev->priv; + + if (!spin_trylock(&np->lock)) + return; + + do { + u32 intr_status = readl(ioaddr + IntrStatus); + + /* Acknowledge all of the current interrupt sources ASAP. */ + writel(intr_status & 0x000ffff, ioaddr + IntrStatus); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & (IntrRxDone | IntrRxIntr)) + netdev_rx(dev); + + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) + break; + if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) { + np->stats.tx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + np->stats.tx_bytes += np->tx_skbuff[entry]->len; +#endif + } else { /* Various Tx errors */ + int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status); + if (tx_status & 0x04010000) np->stats.tx_aborted_errors++; + if (tx_status & 0x02000000) np->stats.tx_fifo_errors++; + if (tx_status & 0x01000000) np->stats.tx_carrier_errors++; + if (tx_status & 0x00200000) np->stats.tx_window_errors++; + np->stats.tx_errors++; + } + /* Free the original skb. */ + dev_kfree_skb(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + } + if (np->tx_full + && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, wake queue. */ + np->tx_full = 0; + netif_wake_queue(dev); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & IntrAbnormalSummary) + netdev_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (!netif_running(dev) && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif + + spin_unlock(&np->lock); +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + + /* If the driver owns the next entry it's a new packet. Send it up. */ + while (desc_status < 0) { /* e.g. & DescOwn */ + if (debug > 4) + printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", + entry, desc_status); + if (--boguscnt < 0) + break; + if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { + if (desc_status & DescMore) { + printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " + "multiple buffers, entry %#x status %x.\n", + dev->name, np->cur_rx, desc_status); + np->stats.rx_length_errors++; + } else { + /* There was a error. */ + if (debug > 2) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + desc_status); + np->stats.rx_errors++; + if (desc_status & 0x06000000) np->stats.rx_over_errors++; + if (desc_status & 0x00600000) np->stats.rx_length_errors++; + if (desc_status & 0x00140000) np->stats.rx_frame_errors++; + if (desc_status & 0x00080000) np->stats.rx_crc_errors++; + } + } else { + struct sk_buff *skb; + int pkt_len = (desc_status & 0x0fff) - 4; /* Omit CRC size. */ + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if HAS_IP_COPYSUM + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { + char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ + if (le32desc_to_virt(np->rx_ring[entry].addr) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in netdev_rx: %p vs. %p / %p.\n", + dev->name, + le32desc_to_virt(np->rx_ring[entry].addr), + skb->head, temp); +#endif + } +#ifndef final_version /* Remove after testing. */ + /* You will want this info for the initial debug. */ + if (debug > 5) + printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" + "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " + "%d.%d.%d.%d.\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5], skb->data[6], skb->data[7], + skb->data[8], skb->data[9], skb->data[10], + skb->data[11], skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], + skb->data[17]); +#endif + skb->protocol = eth_type_trans(skb, dev); + /* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */ + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + np->stats.rx_bytes += pkt_len; +#endif + } + entry = (++np->cur_rx) % RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[entry]; + desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + } + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[entry].addr = virt_to_le32desc(skb->tail); + } + np->rx_ring[entry].cmd_status = + cpu_to_le32(DescIntr | np->rx_buf_sz); + } + + /* Restart Rx engine if stopped. */ + writel(RxOn, dev->base_addr + ChipCmd); + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (intr_status & LinkChange) { + printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" + " %4.4x partner %4.4x.\n", dev->name, + (int)readl(ioaddr + 0x90), (int)readl(ioaddr + 0x94)); + check_duplex(dev); + } + if (intr_status & StatsMax) { + get_stats(dev); + } + if ((intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|0x83ff)) + && debug) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* Hmmmmm, it's not clear how to recover from PCI faults. */ + if (intr_status & IntrPCIErr) { + np->stats.tx_fifo_errors++; + np->stats.rx_fifo_errors++; + } +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ + /* The chip only need report frame silently dropped. */ + np->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs); + np->stats.rx_missed_errors += readl(ioaddr + RxMissed); + + return &np->stats; +} + +/* The little-endian AUTODIN II ethernet CRC calculations. + A big-endian version is also available. + This is slow but compact code. Do not use this routine for bulk data, + use a table-based routine instead. + This is common code and should be moved to net/core/crc.c. + Chips may use the upper or lower CRC bits, and may reverse and/or invert + them. Select the endian-ness that results in minimal calculations. +*/ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + u16 mc_filter[32]; /* Multicast hash filter */ + u32 rx_mode; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys + | AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys; + } else { + struct dev_mc_list *mclist; + int i; + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + mc_filter); + } + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + for (i = 0; i < 32; i++) { + writew(0x200 + (i<<1), ioaddr + RxFilterAddr); + writew(cpu_to_be16(mc_filter[i]), ioaddr + RxFilterData); + } + } + writel(rx_mode, ioaddr + RxFilterAddr); + np->cur_rx_mode = rx_mode; +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = 1; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + netif_stop_queue(dev); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x " + "Int %2.2x.\n", + dev->name, (int)readl(ioaddr + ChipCmd), + (int)readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts using the mask. */ + writel(0, ioaddr + IntrMask); + writel(0, ioaddr + IntrEnable); + writel(2, ioaddr + StatsCtrl); /* Freeze Stats */ + + /* Stop the chip's Tx and Rx processes. */ + writel(RxOff | TxOff, ioaddr + ChipCmd); + + del_timer_sync(&np->timer); + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(np->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" #%d desc. %8.8x %8.8x.\n", + i, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(np->rx_ring)); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n", + i, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].cmd_status = 0; + np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + if (np->rx_skbuff[i]) { +#if LINUX_VERSION_CODE < 0x20100 + np->rx_skbuff[i]->free = 1; +#endif + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = 0; + } + +#if 0 + writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */ +#endif + + MOD_DEC_USE_COUNT; + + return 0; +} + + +static void __devexit natsemi_remove1 (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + unregister_netdev (dev); + release_mem_region(dev->base_addr, np->iosize); + iounmap ((char *) dev->base_addr); + kfree (dev); +} + +static struct pci_driver natsemi_driver = { + name: "natsemi", + id_table: natsemi_pci_tbl, + probe: natsemi_probe1, + remove: natsemi_remove1, +}; + +static int __init natsemi_init_mod (void) +{ + if (debug > 1) + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); + + return pci_module_init (&natsemi_driver); +} + +static void __exit natsemi_exit_mod (void) +{ + pci_unregister_driver (&natsemi_driver); +} + +module_init(natsemi_init_mod); +module_exit(natsemi_exit_mod); + diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in index e1070f8f0..4ad968390 100644 --- a/drivers/net/pcmcia/Config.in +++ b/drivers/net/pcmcia/Config.in @@ -15,7 +15,9 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA - dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA + if [ "$CONFIG_IBMTR" != "y" ]; then + dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA + fi if [ "$CONFIG_CARDBUS" = "y" ]; then tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index 46f37e946..0355f9e5d 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -2714,6 +2714,8 @@ tulip_down(struct net_device *dev) long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; + del_timer_sync(&tp->timer); + /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ @@ -2739,13 +2741,13 @@ tulip_close(struct net_device *dev) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + CSR5)); + del_timer_sync(&tp->timer); + netif_stop_queue(dev); if (netif_device_present(dev)) tulip_down(dev); - del_timer(&tp->timer); - free_irq(dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 0f624fccd..c71539c9a 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -5,19 +5,22 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.1 + * Version: 0.6.2 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against * simultaneous invocation of ppp_input * and ppp_unregister_channel. * 040800 : Respect reference count mechanisms on net-devices. + * 200800 : fix kfree(skb) in pppoe_rcv (acme) * * Module reference count is decremented in the right spot now, * guards against sock_put not actually freeing the sk * in pppoe_release. * * Author: Michal Ostrowski <mostrows@styx.uwaterloo.ca> + * Contributors: + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> * * License: * This program is free software; you can redistribute it and/or @@ -353,7 +356,7 @@ static int pppoe_rcv(struct sk_buff *skb, po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); if(!po){ - kfree(skb); + kfree_skb(skb); return 0; } diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 31521cfde..fba1949a8 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -18,6 +18,8 @@ . . author: . Erik Stahlman ( erik@vt.edu ) + . contributors: + . Arnaldo Carvalho de Melo <acme@conectiva.com.br> . . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) . @@ -47,6 +49,7 @@ . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory . allocation + . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet ----------------------------------------------------------------------------*/ static const char *version = @@ -623,7 +626,7 @@ static void smc_hardware_send_packet( struct net_device * dev ) if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); - kfree(skb); + kfree_skb(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 85089a8ea..fd453a2de 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -17,6 +17,8 @@ Support and updates available at http://www.scyld.com/network/starfire.html + ----------------------------------------------------------- + Linux kernel-specific changes: LK1.1.1 (jgarzik): @@ -29,8 +31,20 @@ LK1.1.3 (Andrew Morton) - Timer cleanups + + LK1.1.4 (jgarzik): + - Merge Becker version 1.03 */ +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n"; +static const char version2[] = +" Updates and info at http://www.scyld.com/network/starfire.html\n"; + +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n"; + /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -74,8 +88,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#define PFX "starfire: " - #if !defined(__OPTIMIZE__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. @@ -85,6 +97,10 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Include files, designed to support most kernel versions 2.0.0 and later. */ #include <linux/version.h> #include <linux/module.h> +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) +#include <linux/modversions.h> +#endif + #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> @@ -101,12 +117,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include <asm/bitops.h> #include <asm/io.h> -/* These identify the driver base version and may not be removed. */ -static char version1[] __devinitdata = -"starfire.c:v0.15+LK1.1.3 6/17/2000 Written by Donald Becker <becker@scyld.com>\n"; -static char version2[] __devinitdata = -" Updates and info at http://www.scyld.com/network/starfire.html\n"; - MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); @@ -187,18 +197,18 @@ IV. Notes IVb. References -The Adaptec Starfire manuals. -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - +The Adaptec Starfire manuals, available only from Adaptec. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata */ + enum chip_capability_flags {CanHaveMII=1, }; - +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0) #define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ #if 0 @@ -211,14 +221,12 @@ enum chipset { CH_6915 = 0, }; - static struct pci_device_id starfire_pci_tbl[] __devinitdata = { { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 }, { 0, } }; MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); - /* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */ static struct chip_info { const char *name; @@ -309,6 +317,7 @@ struct tx_done_report { #endif }; +#define PRIV_ALIGN 15 /* Required alignment mask */ struct ring_info { struct sk_buff *skb; dma_addr_t mapping; @@ -333,7 +342,6 @@ struct netdev_private { dma_addr_t tx_done_q_dma; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ - int chip_id, drv_flags; struct pci_dev *pci_dev; /* Frequently used values: keep some adjacent for cache effect. */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ @@ -341,11 +349,10 @@ struct netdev_private { unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int tx_full:1; /* The Tx queue is full. */ /* These values are keep track of the transceiver/media in use. */ - unsigned int duplex_lock:1; unsigned int full_duplex:1, /* Full-duplex operation requested. */ + medialock:1, /* Xcvr set to fixed speed/duplex. */ rx_flowctrl:1, tx_flowctrl:1; /* Use 802.3x flow control. */ - unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port:4; /* Last dev->if_port value. */ u32 tx_mode; u8 tx_threshold; @@ -383,30 +390,31 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, static int card_idx = -1; static int printed_version = 0; long ioaddr; - int io_size = netdrv_tbl[chip_idx].io_size; + int drv_flags, io_size = netdrv_tbl[chip_idx].io_size; card_idx++; option = card_idx < MAX_UNITS ? options[card_idx] : 0; if (!printed_version++) - printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); ioaddr = pci_resource_start (pdev, 0); if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { - printk (KERN_ERR PFX "card %d: no PCI MEM resources, aborting\n", card_idx); + printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx); return -ENODEV; } dev = init_etherdev(NULL, sizeof(*np)); if (!dev) { - printk (KERN_ERR PFX "card %d: cannot alloc etherdev, aborting\n", card_idx); + printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } irq = pdev->irq; if (request_mem_region (ioaddr, io_size, dev->name) == NULL) { - printk (KERN_ERR PFX "card %d: resource 0x%x @ 0x%lx busy, aborting\n", + printk (KERN_ERR "starfire %d: resource 0x%x @ 0x%lx busy, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_netdev; } @@ -416,7 +424,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, ioaddr = (long) ioremap (ioaddr, io_size); if (!ioaddr) { - printk (KERN_ERR PFX "card %d: cannot remap 0x%x @ 0x%lx, aborting\n", + printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_res; } @@ -436,7 +444,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, #if ! defined(final_version) /* Dump the EEPROM contents during development. */ if (debug > 4) for (i = 0; i < 0x20; i++) - printk("%2.2x%s", readb(ioaddr + EEPROMCtrl + i), + printk("%2.2x%s", (unsigned int)readb(ioaddr + EEPROMCtrl + i), i % 16 != 15 ? " " : "\n"); #endif @@ -446,16 +454,11 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, dev->base_addr = ioaddr; dev->irq = irq; - pdev->driver_data = dev; - - /* private struct aligned and zeroed by init_etherdev */ np = dev->priv; + pdev->driver_data = dev; np->pci_dev = pdev; - np->chip_id = chip_idx; - - /* save useful data, netdrv_tbl is __devinitdata and might be dropped */ - np->drv_flags = netdrv_tbl[chip_idx].drv_flags; + drv_flags = netdrv_tbl[chip_idx].drv_flags; if (dev->mem_start) option = dev->mem_start; @@ -472,7 +475,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, np->full_duplex = 1; if (np->full_duplex) - np->duplex_lock = 1; + np->medialock = 1; /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; @@ -487,7 +490,7 @@ static int __devinit starfire_init_one (struct pci_dev *pdev, if (mtu) dev->mtu = mtu; - if (np->drv_flags & CanHaveMII) { + if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); @@ -611,17 +614,18 @@ static int netdev_open(struct net_device *dev) /* Fill both the unused Tx SA register and the Rx perfect filter. */ for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + 6-i); + writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i); for (i = 0; i < 16; i++) { u16 *eaddrs = (u16 *)dev->dev_addr; long setup_frm = ioaddr + 0x56000 + i*16; - writew(eaddrs[0], setup_frm); setup_frm += 4; - writew(eaddrs[1], setup_frm); setup_frm += 4; - writew(eaddrs[2], setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; } /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ + np->tx_mode = 0; /* Initialized when TxMode set. */ np->tx_threshold = 4; writel(np->tx_threshold, ioaddr + TxThreshold); writel(interrupt_mitigation, ioaddr + IntrTimerCtrl); @@ -635,6 +639,7 @@ static int netdev_open(struct net_device *dev) printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); set_rx_mode(dev); + np->advertising = mdio_read(dev, np->phys[0], 4); check_duplex(dev, 1); /* Set the interrupt mask and enable PCI interrupts. */ @@ -666,23 +671,26 @@ static void check_duplex(struct net_device *dev, int startup) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; - int mii_reg5 = mdio_read(dev, np->phys[0], 5); - int negotiated = mii_reg5 & np->advertising; - int duplex, new_tx_mode ; - - new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0); - if (np->duplex_lock) - duplex = 1; - else - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (duplex) - new_tx_mode |= 2; - if (np->full_duplex != duplex) { - np->full_duplex = duplex; - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d" - " negotiated capability %4.4x.\n", dev->name, - duplex ? "full" : "half", np->phys[0], negotiated); + int new_tx_mode ; + + new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) + | (np->rx_flowctrl ? 0x0400:0); + if (np->medialock) { + if (np->full_duplex) + new_tx_mode |= 2; + } else { + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; + int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (duplex) + new_tx_mode |= 2; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug > 1) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d" + " negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + } } if (new_tx_mode != np->tx_mode) { np->tx_mode = new_tx_mode; @@ -700,7 +708,7 @@ static void netdev_timer(unsigned long data) if (debug > 3) { printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", - dev->name, readl(ioaddr + IntrStatus)); + dev->name, (int)readl(ioaddr + IntrStatus)); } check_duplex(dev, 0); #if ! defined(final_version) @@ -710,7 +718,7 @@ static void netdev_timer(unsigned long data) /* Bogus hardware IRQ: Fake an interrupt handler call. */ if (new_status & 1) { printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n", - dev->name, new_status, readl(ioaddr + IntrStatus)); + dev->name, new_status, (int)readl(ioaddr + IntrStatus)); intr_handler(dev->irq, dev, 0); } } @@ -726,7 +734,7 @@ static void tx_timeout(struct net_device *dev) long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", dev->name, readl(ioaddr + IntrStatus)); + " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus)); #ifndef __alpha__ { @@ -743,15 +751,13 @@ static void tx_timeout(struct net_device *dev) /* Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - /* XXX todo */ /* Trigger an immediate transmit demand. */ - /* XXX todo */ dev->trans_start = jiffies; np->stats.tx_errors++; + return; } @@ -952,7 +958,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) if (debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); + dev->name, (int)readl(ioaddr + IntrStatus)); #ifndef final_version /* Code that should never be run! Remove after testing.. */ @@ -1104,7 +1110,7 @@ static void netdev_error(struct net_device *dev, int intr_status) struct netdev_private *np = (struct netdev_private *)dev->priv; if (intr_status & LinkChange) { - printk(KERN_ERR "%s: Link changed: Autonegotiation advertising" + printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" " %4.4x partner %4.4x.\n", dev->name, mdio_read(dev, np->phys[0], 4), mdio_read(dev, np->phys[0], 5)); @@ -1132,9 +1138,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) long ioaddr = dev->base_addr; struct netdev_private *np = (struct netdev_private *)dev->priv; - /* We should lock this segment of code for SMP eventually, although - the vulnerability window is very small and statistics are - non-critical. */ + /* This adapter architecture needs no SMP locks. */ np->stats.tx_bytes = readl(ioaddr + 0x57010); np->stats.rx_bytes = readl(ioaddr + 0x57044); np->stats.tx_packets = readl(ioaddr + 0x57000); @@ -1201,9 +1205,9 @@ static void set_rx_mode(struct net_device *dev) for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count; i++, mclist = mclist->next) { u16 *eaddrs = (u16 *)mclist->dmi_addr; - writew(*eaddrs++, filter_addr); filter_addr += 4; - writew(*eaddrs++, filter_addr); filter_addr += 4; - writew(*eaddrs++, filter_addr); filter_addr += 8; + writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; } while (i++ < 16) { writew(0xffff, filter_addr); filter_addr += 4; @@ -1232,16 +1236,17 @@ static void set_rx_mode(struct net_device *dev) writew(mc_filter[i], filter_addr); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } - writel(rx_mode|AcceptAll, ioaddr + RxFilterMode); + writel(rx_mode, ioaddr + RxFilterMode); } static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct netdev_private *np = (struct netdev_private *)dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + data[0] = np->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); @@ -1249,6 +1254,21 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (data[0] == np->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + if (value & 0x9000) /* Autonegotiation. */ + np->medialock = 0; + else { + np->full_duplex = (value & 0x0100) ? 1 : 0; + np->medialock = 1; + } + break; + case 4: np->advertising = value; break; + } + check_duplex(dev, 0); + } mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; default: @@ -1267,8 +1287,8 @@ static int netdev_close(struct net_device *dev) del_timer_sync(&np->timer); if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was Int %4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 39d278bb1..ad98ac405 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.102 2000/06/30 10:18:35 davem Exp $ +/* $Id: sunlance.c,v 1.103 2000/08/12 19:23:38 anton Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -109,8 +109,6 @@ static char *lancestr = "LANCE"; #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <asm/machines.h> - /* Define: 2^4 Tx buffers and 2^4 Rx buffers */ #ifndef LANCE_LOG_TX_BUFFERS #define LANCE_LOG_TX_BUFFERS 4 diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 165d611b8..63dce60eb 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -97,6 +97,12 @@ * * v1.8a May 28, 2000 - Minor updates. * + * v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues. + * - Updated with timer fixes from Andrew Morton. + * - Fixed module race in TLan_Open. + * - Added routine to monitor PHY status. + * - Added activity led support for Proliant devices. + * *******************************************************************************/ @@ -138,7 +144,7 @@ static int debug = 0; static int bbuf = 0; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; -static const char *tlan_banner = "ThunderLAN driver v1.8a\n"; +static const char *tlan_banner = "ThunderLAN driver v1.9\n"; const char *media[] = { "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", @@ -181,7 +187,7 @@ static TLanAdapterEntry TLanAdapterList[] __initdata = { { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, "Compaq Netelligent Integrated 10/100 TX UTP", - TLAN_ADAPTER_NONE, + TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { PCI_VENDOR_ID_COMPAQ, @@ -272,6 +278,7 @@ static void TLan_PhyPowerUp( struct net_device * ); static void TLan_PhyReset( struct net_device * ); static void TLan_PhyStartLink( struct net_device * ); static void TLan_PhyFinishAutoNeg( struct net_device * ); +static void TLan_PhyMonitor( struct net_device * ); /* static int TLan_PhyNop( struct net_device * ); static int TLan_PhyInternalCheck( struct net_device * ); @@ -701,7 +708,8 @@ static int TLan_Open( struct net_device *dev ) if ( err ) { printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); - return -EAGAIN; + MOD_DEC_USE_COUNT; + return err; } netif_start_queue(dev); @@ -942,7 +950,7 @@ static int TLan_Close(struct net_device *dev) TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); if ( priv->timer.function != NULL ) { - del_timer( &priv->timer ); + del_timer_sync( &priv->timer ); priv->timer.function = NULL; } free_irq( dev->irq, dev ); @@ -1590,6 +1598,9 @@ void TLan_Timer( unsigned long data ) priv->timer.function = NULL; switch ( priv->timerType ) { + case TLAN_TIMER_LINK_BEAT: + TLan_PhyMonitor( dev ); + break; case TLAN_TIMER_PHY_PDOWN: TLan_PhyPowerDown( dev ); break; @@ -2041,6 +2052,12 @@ TLan_FinishReset( struct net_device *dev ) } TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + + /* We have link beat..for now anyway */ + priv->link = 1; + /*Enabling link beat monitoring */ + TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT ); + } } @@ -2062,7 +2079,8 @@ TLan_FinishReset( struct net_device *dev ) } outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); - } else { + + } else { printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; @@ -2329,12 +2347,14 @@ void TLan_PhyStartLink( struct net_device *dev ) TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); } else if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_HALF) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); } else { @@ -2418,9 +2438,9 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); mode = an_adv & an_lpa & 0x03E0; if ( mode & 0x0100 ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) { @@ -2450,6 +2470,61 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) + /********************************************************************* + * + * TLan_PhyMonitor + * + * Returns: + * None + * + * Params: + * dev The device structure of this device. + * + * + * This function monitors PHY condition by reading the status + * register via the MII bus. This can be used to give info + * about link changes (up/down), and possible switch to alternate + * media. + * + * ******************************************************************/ + +void TLan_PhyMonitor( struct net_device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 phy; + u16 phy_status; + + phy = priv->phy[priv->phyNum]; + + /* Get PHY status register */ + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); + + /* Check if link has been lost */ + if (!(phy_status & MII_GS_LINK)) { + if (priv->link) { + priv->link = 0; + printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); + dev->flags &= ~IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + return; + } + } + + /* Link restablished? */ + if ((phy_status & MII_GS_LINK) && !priv->link) { + priv->link = 1; + printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); + dev->flags |= IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + } + + /* Setup a new monitor */ + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + +} + + + /***************************************************************************** ****************************************************************************** diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index f04ca6996..1d032f4b0 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -187,6 +187,7 @@ typedef struct tlan_private_tag { u8 tlanFullDuplex; char devName[8]; spinlock_t lock; + u8 link; } TLanPrivateInfo; @@ -197,7 +198,7 @@ typedef struct tlan_private_tag { * ****************************************************************/ -#define TLAN_TIMER_LINK 1 +#define TLAN_TIMER_LINK_BEAT 1 #define TLAN_TIMER_ACTIVITY 2 #define TLAN_TIMER_PHY_PDOWN 3 #define TLAN_TIMER_PHY_PUP 4 @@ -381,9 +382,9 @@ typedef struct tlan_private_tag { #define MII_GIL_OUI 0xFC00 #define MII_GIL_MODEL 0x03F0 #define MII_GIL_REVISION 0x000F -#define MII_AN_ADV 0x04 -#define MII_AN_LPA 0x05 -#define MII_AN_EXP 0x06 +#define MII_AN_ADV 0x0004 +#define MII_AN_LPA 0x0005 +#define MII_AN_EXP 0x0006 /* ThunderLAN Specific MII/PHY Registers */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 4f6252383..4e2338bb3 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -28,7 +28,7 @@ #include <asm/unaligned.h> static char version[] __devinitdata = - "Linux Tulip driver version 0.9.8 (July 13, 2000)\n"; + "Linux Tulip driver version 0.9.9 (August 11, 2000)\n"; /* A few user-configurable values. */ @@ -165,6 +165,8 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = { { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x13D1, 0xAB02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x13D1, 0xAB03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, diff --git a/drivers/net/tun.c b/drivers/net/tun.c new file mode 100644 index 000000000..26282e38f --- /dev/null +++ b/drivers/net/tun.c @@ -0,0 +1,535 @@ +/* + * TUN - Universal TUN/TAP device driver. + * Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.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. + * + * 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. + * + * $Id: tun.c,v 1.1 2000/08/23 05:59:28 davem Exp $ + */ + +/* + * Daniel Podlejski <underley@underley.eu.org> + * Modifications for 2.3.99-pre5 kernel. + */ + +#define TUN_VER "1.1" + +#include <linux/module.h> + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/poll.h> +#include <linux/fcntl.h> +#include <linux/init.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/random.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/rtnetlink.h> +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/if_tun.h> + +#include <asm/system.h> +#include <asm/uaccess.h> + + +#ifdef TUN_DEBUG +static int debug=0; +#endif + +/* Network device part of the driver */ + +/* Net device open. */ +static int tun_net_open(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_open\n", tun->name); +#endif + + netif_start_queue(dev); + + return 0; +} + +/* Net device close. */ +static int tun_net_close(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_close\n", tun->name); +#endif + + netif_stop_queue(dev); + + return 0; +} + +/* Net device start xmit */ +static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->name, skb->len); + + + if (netif_queue_stopped(dev)) + return 1; + + tun->stats.tx_packets++; + + /* Queue frame */ + skb_queue_tail(&tun->txq, skb); + if (skb_queue_len(&tun->txq) >= TUN_TXQ_SIZE) + netif_stop_queue(dev); + + if (tun->flags & TUN_FASYNC) + kill_fasync(&tun->fasync, SIGIO, POLL_IN); + + /* Wake up process */ + wake_up_interruptible(&tun->read_wait); + + return 0; +} + +static void tun_net_mclist(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_mclist\n", tun->name); +#endif + + /* Nothing to do for multicast filters. + * We always accept all frames. + */ + return; +} + +static struct net_device_stats *tun_net_stats(struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + return &tun->stats; +} + +/* Initialize net device. */ +int tun_net_init(struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_init\n", tun->name); + + dev->open = tun_net_open; + dev->hard_start_xmit = tun_net_xmit; + dev->stop = tun_net_close; + dev->get_stats = tun_net_stats; + + switch (tun->flags & TUN_TYPE_MASK) { + case TUN_TUN_DEV: + /* Point-to-Point TUN Device */ + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->mtu = 1500; + + /* Type PPP seems most suitable */ + dev->type = ARPHRD_PPP; + dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->tx_queue_len = 10; + + dev_init_buffers(dev); + break; + + case TUN_TAP_DEV: + /* Ethernet TAP Device */ + dev->set_multicast_list = tun_net_mclist; + + /* Generate random Ethernet address. */ + *(u16 *)dev->dev_addr = htons(0x00FF); + get_random_bytes(dev->dev_addr + sizeof(u16), 4); + + ether_setup(dev); + break; + }; + + return 0; +} + +/* Character device part */ + +/* Poll */ +static unsigned int tun_chr_poll(struct file *file, poll_table * wait) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_poll\n", tun->name); + + poll_wait(file, &tun->read_wait, wait); + + if (skb_queue_len(&tun->txq)) + return POLLIN | POLLRDNORM; + + return POLLOUT | POLLWRNORM; +} + +/* Get packet from user space buffer(already verified) */ +static __inline__ ssize_t tun_get_user(struct tun_struct *tun, const char *buf, size_t count) +{ + struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) }; + register const char *ptr = buf; + register int len = count; + struct sk_buff *skb; + + if (len > TUN_MAX_FRAME) + return -EINVAL; + + if (!(tun->flags & TUN_NO_PI)) { + if ((len -= sizeof(pi)) < 0) + return -EINVAL; + + copy_from_user(&pi, ptr, sizeof(pi)); + ptr += sizeof(pi); + } + + if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { + tun->stats.rx_dropped++; + return -ENOMEM; + } + + skb_reserve(skb, 2); + copy_from_user(skb_put(skb, count), ptr, len); + + skb->dev = &tun->dev; + switch (tun->flags & TUN_TYPE_MASK) { + case TUN_TUN_DEV: + skb->mac.raw = skb->data; + skb->protocol = pi.proto; + break; + case TUN_TAP_DEV: + skb->protocol = eth_type_trans(skb, &tun->dev); + break; + }; + + if (tun->flags & TUN_NOCHECKSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_rx(skb); + + tun->stats.rx_packets++; + return count; +} + +/* Write */ +static ssize_t tun_chr_write(struct file * file, const char * buf, + size_t count, loff_t *pos) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_write %d\n", tun->name, count); + + if (!(tun->flags & TUN_IFF_SET)) + return -EBUSY; + + if (verify_area(VERIFY_READ, buf, count)) + return -EFAULT; + + return tun_get_user(tun, buf, count); +} + +/* Put packet to user space buffer(already verified) */ +static __inline__ ssize_t tun_put_user(struct tun_struct *tun, + struct sk_buff *skb, + char *buf, int count) +{ + struct tun_pi pi = { 0, skb->protocol }; + int len = count, total = 0; + char *ptr = buf; + + if (!(tun->flags & TUN_NO_PI)) { + if ((len -= sizeof(pi)) < 0) + return -EINVAL; + + if (len < skb->len) { + /* Packet will be striped */ + pi.flags |= TUN_PKT_STRIP; + } + + copy_to_user(ptr, &pi, sizeof(pi)); + + total += sizeof(pi); + ptr += sizeof(pi); + } + + len = MIN(skb->len, len); + copy_to_user(ptr, skb->data, len); + total += len; + + return total; +} + +/* Read */ +static ssize_t tun_chr_read(struct file * file, char * buf, + size_t count, loff_t *pos) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + DECLARE_WAITQUEUE(wait, current); + struct sk_buff *skb; + ssize_t ret = 0; + + DBG(KERN_INFO "%s: tun_chr_read\n", tun->name); + + add_wait_queue(&tun->read_wait, &wait); + while (count) { + current->state = TASK_INTERRUPTIBLE; + + /* Read frames from device queue */ + if (!(skb=skb_dequeue(&tun->txq))) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + /* Nothing to read, let's sleep */ + schedule(); + continue; + } + netif_start_queue(&tun->dev); + + if (!verify_area(VERIFY_WRITE, buf, count)) + ret = tun_put_user(tun, skb, buf, count); + else + ret = -EFAULT; + + kfree_skb(skb); + break; + } + + current->state = TASK_RUNNING; + remove_wait_queue(&tun->read_wait, &wait); + + return ret; +} + +static loff_t tun_chr_lseek(struct file * file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static int tun_set_iff(struct tun_struct *tun, unsigned long arg) +{ + struct ifreq ifr; + char *mask; + + if (copy_from_user(&ifr, (void *)arg, sizeof(ifr))) + return -EFAULT; + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + + if (tun->flags & TUN_IFF_SET) + return -EEXIST; + + /* Set dev type */ + if (ifr.ifr_flags & IFF_TUN) { + /* TUN device */ + tun->flags |= TUN_TUN_DEV; + mask = "tun%d"; + } else if (ifr.ifr_flags & IFF_TAP) { + /* TAP device */ + tun->flags |= TUN_TAP_DEV; + mask = "tap%d"; + } else + return -EINVAL; + + if (ifr.ifr_flags & IFF_NO_PI) + tun->flags |= TUN_NO_PI; + + if (*ifr.ifr_name) + strcpy(tun->dev.name, ifr.ifr_name); + else + strcpy(tun->dev.name, mask); + + /* Register net device */ + if (register_netdev(&tun->dev)) + return -EBUSY; + + tun->flags |= TUN_IFF_SET; + strcpy(tun->name, tun->dev.name); + + /* Return iface info to the user space */ + strcpy(ifr.ifr_name, tun->dev.name); + copy_to_user((void *)arg, &ifr, sizeof(ifr)); + + return 0; +} + +static int tun_chr_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_ioctl\n", tun->name); + + switch (cmd) { + case TUNSETIFF: + return tun_set_iff(tun, arg); + + case TUNSETNOCSUM: + /* Disable/Enable checksum on net iface */ + if (arg) + tun->flags |= TUN_NOCHECKSUM; + else + tun->flags &= ~TUN_NOCHECKSUM; + + DBG(KERN_INFO "%s: checksum %s\n", + tun->name, arg ? "disabled" : "enabled"); + break; + +#ifdef TUN_DEBUG + case TUNSETDEBUG: + tun->debug = arg; + break; +#endif + + default: + return -EINVAL; + }; + + return 0; +} + +static int tun_chr_fasync(int fd, struct file *file, int on) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + int ret; + + DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->name, on); + + if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0) + return ret; + + if (on) + tun->flags |= TUN_FASYNC; + else + tun->flags &= ~TUN_FASYNC; + + return 0; +} + +static int tun_chr_open(struct inode *inode, struct file * file) +{ + struct tun_struct *tun = NULL; + + DBG1(KERN_INFO "tunX: tun_chr_open\n"); + + tun = kmalloc(sizeof(struct tun_struct), GFP_KERNEL); + if (tun == NULL) + return -ENOMEM; + + memset(tun, 0, sizeof(struct tun_struct)); + file->private_data = tun; + + skb_queue_head_init(&tun->txq); + init_waitqueue_head(&tun->read_wait); + + sprintf(tun->name, "tunX"); + + tun->dev.init = tun_net_init; + tun->dev.priv = tun; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int tun_chr_close(struct inode *inode, struct file *file) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_close\n", tun->name); + + if (tun->flags & TUN_IFF_SET) { + rtnl_lock(); + dev_close(&tun->dev); + rtnl_unlock(); + + /* Drop TX queue */ + skb_queue_purge(&tun->txq); + + unregister_netdev(&tun->dev); + } + + kfree(tun); + file->private_data = NULL; + + MOD_DEC_USE_COUNT; + return 0; +} + +static struct file_operations tun_fops = { + owner: THIS_MODULE, + llseek: tun_chr_lseek, + read: tun_chr_read, + write: tun_chr_write, + poll: tun_chr_poll, + ioctl: tun_chr_ioctl, + open: tun_chr_open, + release:tun_chr_close, + fasync: tun_chr_fasync +}; + +static devfs_handle_t devfs_handle = NULL; + +int __init tun_init(void) +{ + printk(KERN_INFO "Universal TUN/TAP device driver %s " + "(C)1999-2000 Maxim Krasnyansky\n", TUN_VER); + + if (devfs_register_chrdev(TUN_MAJOR, "tun", &tun_fops)) { + printk(KERN_ERR "tun: Can't register char device %d\n", + TUN_MAJOR); + return -EIO; + } + + devfs_handle = devfs_register(NULL, "net/tun", DEVFS_FL_DEFAULT, + TUN_MAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR, + &tun_fops, NULL); + +#ifdef MODULE + return 0; +#else + /* If driver is not module, tun_init will be called from Space.c. + * Return non-zero not to register fake device. + */ + return 1; +#endif +} + +void tun_cleanup(void) +{ + devfs_unregister_chrdev(TUN_MAJOR,"tun"); + devfs_unregister(devfs_handle); +} + +module_init(tun_init); +module_exit(tun_cleanup); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 67db42e97..9d0947b05 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -51,8 +51,13 @@ - Urban Widmark: mdio locking, bounce buffer changes merges from Beckers 1.05 version added netif_running_on/off support + + LK1.1.6: + - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio) + set netif_running_on/off on startup, del_timer_sync */ + /* A few user-configurable values. These may be modified when a driver module is loaded. */ @@ -85,7 +90,7 @@ static const int multicast_filter_limit = 32; bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define RX_RING_SIZE 16 @@ -122,7 +127,7 @@ static const int multicast_filter_limit = 32; /* These identify the driver base version and may not be removed. */ static char version1[] __devinitdata = -"via-rhine.c:v1.05-LK1.1.5 5/2/2000 Written by Donald Becker\n"; +"via-rhine.c:v1.08b-LK1.1.6 8/9/2000 Written by Donald Becker\n"; static char version2[] __devinitdata = " http://www.scyld.com/network/via-rhine.html\n"; @@ -233,13 +238,13 @@ IV. Notes IVb. References Preliminary VT86C100A manual from http://www.via.com.tw/ -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata The VT86C100A manual is not reliable information. -The chip does not handle unaligned transmit or receive buffers, resulting +The 3043 chip does not handle unaligned transmit or receive buffers, resulting in significant performance degradation for bounce buffer copies on transmit and unaligned IP headers on receive. The chip does not pad to minimum transmit length. @@ -261,6 +266,7 @@ enum pci_flags_bit { enum via_rhine_chips { VT86C100A = 0, + VT6102, VT3043, }; @@ -272,24 +278,33 @@ struct via_rhine_chip_info { }; -enum chip_capability_flags {CanHaveMII=1, HasESIPhy=2 }; +enum chip_capability_flags { + CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, + ReqTxAlign=0x10, HasWOL=0x20, }; #if defined(VIA_USE_MEMORY) #define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) +#define RHINEII_IOSIZE 4096 #else #define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) +#define RHINEII_IOSIZE 256 #endif /* directly indexed by enum via_rhine_chips, above */ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { - { "VIA VT86C100A Rhine-II", RHINE_IOTYPE, 128, CanHaveMII }, - { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII } + { "VIA VT86C100A Rhine", RHINE_IOTYPE, 128, + CanHaveMII | ReqTxAlign }, + { "VIA VT6102 Rhine-II", RHINE_IOTYPE, RHINEII_IOSIZE, + CanHaveMII | HasWOL }, + { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, + CanHaveMII | ReqTxAlign } }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = { {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, + {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043}, {0,} /* terminate list */ }; @@ -304,7 +319,8 @@ enum register_offsets { RxRingPtr=0x18, TxRingPtr=0x1C, MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, - Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E, + Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E, + StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; /* Bits in the interrupt status/mask registers. */ @@ -585,6 +601,12 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, "0x%4.4x advertising %4.4x Link %4.4x.\n", dev->name, phy, mii_status, np->advertising, mdio_read(dev, phy, 5)); + + /* set IFF_RUNNING */ + if (mii_status & MIILink) + netif_carrier_on(dev); + else + netif_carrier_off(dev); } } } @@ -641,8 +663,20 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value long ioaddr = dev->base_addr; int boguscnt = 1024; - if (phy_id == np->phys[0] && regnum == 4) - np->advertising = value; + if (phy_id == np->phys[0]) { + switch (regnum) { + case 0: /* Is user forcing speed/duplex? */ + if (value & 0x9000) /* Autonegotiation. */ + np->duplex_lock = 0; + else + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: + np->advertising = value; + break; + } + } + /* Wait for a previous command to complete. */ while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; @@ -900,7 +934,8 @@ static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) np->tx_skbuff[entry] = skb; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ + if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) { + /* Must use alignment buffer. */ memcpy(np->tx_buf[entry], skb->data, skb->len); np->tx_skbuff_dma[entry] = 0; np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma + @@ -1154,10 +1189,11 @@ static void via_rhine_error(struct net_device *dev, int intr_status) spin_lock (&np->lock); if (intr_status & (IntrMIIChange | IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) + if (readb(ioaddr + MIIStatus) & 0x02) { /* Link failed, restart autonegotiation. */ - mdio_write(dev, np->phys[0], 0, 0x3300); - else + if (np->drv_flags & HasDavicomPhy) + mdio_write(dev, np->phys[0], 0, 0x3300); + } else via_rhine_check_duplex(dev); if (debug) printk(KERN_ERR "%s: MII status changed: Autonegotiation " @@ -1309,6 +1345,8 @@ static int via_rhine_close(struct net_device *dev) int i; unsigned long flags; + del_timer_sync(&np->timer); + spin_lock_irqsave(&np->lock, flags); netif_stop_queue(dev); @@ -1317,14 +1355,15 @@ static int via_rhine_close(struct net_device *dev) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", dev->name, readw(ioaddr + ChipCmd)); + /* Switch to loopback mode to avoid hardware races. */ + writeb(np->tx_thresh | 0x01, ioaddr + TxConfig); + /* Disable interrupts by clearing the interrupt mask. */ writew(0x0000, ioaddr + IntrEnable); /* Stop the chip's Tx and Rx processes. */ writew(CmdStop, ioaddr + ChipCmd); - del_timer(&np->timer); - spin_unlock_irqrestore(&np->lock, flags); /* Make sure there is no irq-handler running on a different CPU. */ diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in index 4621d3981..4c8517081 100644 --- a/drivers/net/wan/Config.in +++ b/drivers/net/wan/Config.in @@ -7,86 +7,87 @@ comment 'Wan interfaces' bool 'Wan interfaces support' CONFIG_WAN if [ "$CONFIG_WAN" = "y" ]; then +# There is no way to detect a comtrol sv11 - force it modular for now. - # There is no way to detect a comtrol sv11 - force it modular for now. - - dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m - - # The COSA/SRP driver has not been tested as non-modular yet. - - dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m - - # - # COMX drivers - # - - tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX - - # - # Lan Media's board. Currently 1000, 1200, 5200, 5245 - # - tristate 'LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA - - if [ "$CONFIG_COMX" != "n" ]; then - dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX - dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX - dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX - dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX - if [ "$CONFIG_LAPB" = "y" ]; then - dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX - fi - if [ "$CONFIG_LAPB" = "m" ]; then - dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_LAPB - fi - dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX - fi - - # There is no way to detect a Sealevel board. Force it modular - - dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m - - dep_tristate 'SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m - - tristate 'Frame relay DLCI support' CONFIG_DLCI - if [ "$CONFIG_DLCI" != "n" ]; then - int 'Max open DLCI' CONFIG_DLCI_COUNT 24 - int 'Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI - fi - - # Wan router core. - - if [ "$CONFIG_WAN_ROUTER" != "n" ]; then - bool 'WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then - dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then - int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 - bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR - bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 - fi - bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then - bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25 - fi - fi - fi - fi - - # X.25 network drivers - - dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25 - dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25 - - if [ "$CONFIG_X86" = "y" ]; then - tristate 'SBNI12-xx support' CONFIG_SBNI - fi + dep_tristate ' Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m + +# The COSA/SRP driver has not been tested as non-modular yet. + + dep_tristate ' COSA/SRP sync serial boards support' CONFIG_COSA m + +# +# COMX drivers +# + + tristate ' MultiGate (COMX) synchronous serial boards support' CONFIG_COMX + if [ "$CONFIG_COMX" != "n" ]; then + dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX + dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX + dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX + dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX + if [ "$CONFIG_LAPB" = "y" ]; then + dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX + fi + if [ "$CONFIG_LAPB" = "m" ]; then + dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_LAPB + fi + dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX + fi + +# +# Lan Media's board. Currently 1000, 1200, 5200, 5245 +# + + tristate ' LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA + +# There is no way to detect a Sealevel board. Force it modular + + dep_tristate ' Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + + dep_tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m + + tristate ' Frame relay DLCI support' CONFIG_DLCI + if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI + fi + +# Wan router core. + + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then + bool ' WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then + dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then + int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' WANPIPE Frame Relay support (OBSOLETE)' CONFIG_WANPIPE_FR + bool ' WANPIPE X.25 support (OBSOLETE)' CONFIG_WANPIPE_X25 + fi + bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then + bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25 + fi + fi + fi + fi + + +# X.25 network drivers + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' LAPB over Ethernet driver (EXPERIMENTAL)' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25 + dep_tristate ' X.25 async driver (EXPERIMENTAL)' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25 + fi + + if [ "$CONFIG_X86" = "y" ]; then + tristate ' SBNI12-xx support' CONFIG_SBNI + fi fi endmenu - diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index f7f3fe58a..5b13578e7 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -1,269 +1,86 @@ -# File: drivers/net/wan/Makefile # # Makefile for the Linux network (wan) device drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now inherited from the -# parent makefile. +# 3 Aug 2000, Christoph Hellwig <hch@caldera.de> +# Rewritten to use lists instead of if-statements. # SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) lmc -L_TARGET := wan.a -L_OBJS := -M_OBJS := - -# Need these to keep track of whether the 82530 or SYNCPPP -# modules should really go in the kernel or a module. -CONFIG_85230_BUILTIN := -CONFIG_85230_MODULE := -CONFIG_SYNCPPP_BUILTIN := -CONFIG_SYNCPPP_MODULE := - -ifeq ($(CONFIG_HOSTESS_SV11),y) -L_OBJS += hostess_sv11.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_HOSTESS_SV11),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += hostess_sv11.o - endif -endif - -ifeq ($(CONFIG_SEALEVEL_4021),y) -L_OBJS += sealevel.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_SEALEVEL_4021),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += sealevel.o - endif -endif - -ifeq ($(CONFIG_SYNCLINK_SYNCPPP),y) -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_SYNCLINK_SYNCPPP),m) - CONFIG_SYNCPPP_MODULE = y - endif -endif - -ifeq ($(CONFIG_COMX),y) -LX_OBJS += comx.o -else - ifeq ($(CONFIG_COMX),m) - MX_OBJS += comx.o - endif -endif - -ifeq ($(CONFIG_COMX_HW_COMX),y) -L_OBJS += comx-hw-comx.o -else - ifeq ($(CONFIG_COMX_HW_COMX),m) - M_OBJS += comx-hw-comx.o - endif -endif - -ifeq ($(CONFIG_COMX_HW_LOCOMX),y) -L_OBJS += comx-hw-locomx.o -CONFIG_85230_BUILTIN=y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COMX_HW_LOCOMX),m) - M_OBJS += comx-hw-locomx.o - CONFIG_85230_MODULE=y - CONFIG_SYNCPPP_MODULE = y - endif -endif +O_TARGET := wan.o -ifeq ($(CONFIG_COMX_HW_MIXCOM),y) -L_OBJS += comx-hw-mixcom.o -else - ifeq ($(CONFIG_COMX_HW_MIXCOM),m) - M_OBJS += comx-hw-mixcom.o - endif -endif +export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o +list-multi = wanpipe.o cyclomx.o -ifeq ($(CONFIG_COMX_PROTO_PPP),y) -L_OBJS += comx-proto-ppp.o -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COMX_PROTO_PPP),m) - M_OBJS += comx-proto-ppp.o - CONFIG_SYNCPPP_MODULE = y - endif -endif +wanpipe-objs = sdlamain.o $(wanpipe-y) +wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o +wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o +wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o +wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o -ifeq ($(CONFIG_COMX_PROTO_LAPB),y) -L_OBJS += comx-proto-lapb.o -else - ifeq ($(CONFIG_COMX_PROTO_LAPB),m) - M_OBJS += comx-proto-lapb.o - endif -endif +cyclomx-objs = cycx_main.o $(cyclomx-y) +cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o -ifeq ($(CONFIG_COMX_PROTO_FR),y) -L_OBJS += comx-proto-fr.o -else - ifeq ($(CONFIG_COMX_PROTO_FR),m) - M_OBJS += comx-proto-fr.o - endif -endif -ifeq ($(CONFIG_COSA),y) -L_OBJS += cosa.o -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COSA),m) - CONFIG_SYNCPPP_MODULE = y - M_OBJS += cosa.o - endif -endif +obj-$(CONFIG_HOSTESS_SV11) += z85230.o syncppp.o hostess_sv11.o +obj-$(CONFIG_SEALEVEL_4021) += z85230.o syncppp.o sealevel.o +obj-$(CONFIG_COMX) += comx.o +obj-$(CONFIG_COMX_HW_COMX) += comx-hw-comx.o +obj-$(CONFIG_COMX_HW_LOCOMX) += z85230.o syncppp.o comx-hw-locomx.o +obj-$(CONFIG_COMX_HW_MIXCOM) += comx-hw-mixcom.o +obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o +obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o +obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o +obj-$(CONFIG_COSA) += syncppp.o cosa.o +obj-$(CONFIG_LANMEDIA) += syncppp.o ifeq ($(CONFIG_LANMEDIA),y) SUB_DIRS += lmc MOD_IN_SUB_DIRS += lmc - L_OBJS += lmc/lmc.o - CONFIG_SYNCPPP_BUILTIN = y + obj-y += lmc/lmc.o else ifeq ($(CONFIG_LANMEDIA),m) - CONFIG_SYNCPPP_MODULE = y MOD_IN_SUB_DIRS += lmc endif endif - -# If anything built-in uses syncppp, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_SYNCPPP_BUILTIN -LX_OBJS += syncppp.o -else - ifdef CONFIG_SYNCPPP_MODULE - MX_OBJS += syncppp.o - endif -endif - -# If anything built-in uses Z85230, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_85230_BUILTIN -LX_OBJS += z85230.o -else - ifdef CONFIG_85230_MODULE - MX_OBJS += z85230.o - endif -endif - -ifeq ($(CONFIG_DLCI),y) -L_OBJS += dlci.o -else - ifeq ($(CONFIG_DLCI),m) - M_OBJS += dlci.o - endif -endif - -ifeq ($(CONFIG_SDLA),y) - L_OBJS += sdla.o -else - ifeq ($(CONFIG_SDLA),m) - M_OBJS += sdla.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),y) - LX_OBJS += sdladrv.o - L_OBJS += sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - L_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_CHDLC),y) - L_OBJS += sdla_chdlc.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - L_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - L_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),m) - MX_OBJS += sdladrv.o - M_OBJS += wanpipe.o - WANPIPE_OBJS = sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - WANPIPE_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - WANPIPE_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_CHDLC),y) - WANPIPE_OBJS += sdla_chdlc.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - WANPIPE_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),y) - LX_OBJS += cycx_drv.o - L_OBJS += cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - L_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),m) - MX_OBJS += cycx_drv.o - M_OBJS += cyclomx.o - CYCLOMX_OBJS = cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - CYCLOMX_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_X25_ASY),y) -L_OBJS += x25_asy.o -else - ifeq ($(CONFIG_X25_ASY),m) - M_OBJS += x25_asy.o - endif -endif - -ifeq ($(CONFIG_LAPBETHER),y) -L_OBJS += lapbether.o -else - ifeq ($(CONFIG_LAPBETHER),m) - M_OBJS += lapbether.o - endif -endif - -ifeq ($(CONFIG_SBNI),y) -L_OBJS += sbni.o -else - ifeq ($(CONFIG_SBNI),m) - M_OBJS += sbni.o - endif -endif +obj-$(CONFIG_DLCI) += dlci.o +obj-$(CONFIG_SDLA) += sdla.o +obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o +obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o +obj-$(CONFIG_LAPBETHER) += lapbether.o +obj-$(CONFIG_SBNI) += sbni.o + + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) include $(TOPDIR)/Rules.make -clean: - rm -f core *.o *.a *.s - -wanpipe.o: $(WANPIPE_OBJS) - $(LD) -r -o $@ $(WANPIPE_OBJS) +wanpipe.o: $(wanpipe-objs) + $(LD) -r -o $@ $(wanpipe-objs) -cyclomx.o: $(CYCLOMX_OBJS) - $(LD) -r -o $@ $(CYCLOMX_OBJS) +cyclomx.o: $(cyclomx-objs) + $(LD) -r -o $@ $(cyclomx-objs) diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 207c9e21c..0426143af 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -101,7 +101,7 @@ static cycx_t *card_array = NULL; /* adapter data space */ * < 0 error. * Context: process */ -static int __init cyclomx_init (void) +int __init cyclomx_init (void) { int cnt, err = 0; diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 09d6c9556..4c7bf4bf4 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -305,6 +305,7 @@ static struct sv11_device *sv11_init(int iobase, int irq) if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); + restore_flags(flags); goto dmafail2; } z8530_channel_load(&dev->chanB, z8530_dead_port); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 37ef27487..b4073b00f 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -448,6 +448,7 @@ static int __init sbni_probe1(struct net_device *dev, int ioaddr) if(dev->priv == NULL) { DP( printk("%s: cannot allocate memory\n", dev->name); ) + free_irq(dev->irq, dev); return -ENOMEM; } diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index f1a895e36..2128a386e 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -323,6 +323,7 @@ static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, i if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); + restore_flags(flags); goto dmafail2; } if(dev->type==Z85C30) diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 096d8164a..8a62cc8ed 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -866,7 +866,7 @@ EXPORT_SYMBOL(sppp_close); * * Close down any existing synchronous session and commence * from scratch. In the PPP case this means negotiating LCP/IPCP - * and friends, while for Cisco HDLC we simply need to staet sending + * and friends, while for Cisco HDLC we simply need to start sending * keepalives */ diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 0c3a2f533..bda378365 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -1468,6 +1468,7 @@ 10b7 3590 TokenLink Velocity XL Adapter 4500 3c450 Cyclone/unknown 5055 3c555 Laptop Hurricane + 6055 3c556 Laptop Hurricane 5057 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card 5157 3c575 [Megahertz] 10/100 LAN CardBus @@ -1934,7 +1935,7 @@ 1106 0686 VT82C686/A PCI to ISA Bridge 0691 VT82C693A/694x [Apollo PRO133x] 1458 0691 VT82C691 Apollo Pro System Controller - 0698 VT82C693A [Ppollo Pro133 AGP] + 0698 VT82C693A [Apollo Pro133 AGP] 0693 VT82C693 [Apollo Pro Plus] 0926 VT82C926 [Amazon] 1000 VT82C570MV @@ -1964,8 +1965,8 @@ 6100 VT85C100A [Rhine II] 8231 VT8231 [PCI-to-ISA Bridge] 8235 VT8235 Power Management - 8305 VT8365 [KM133 AGP] - 8391 VT8363/8371 [KT133/KX133 AGP] + 8305 VT8363/8365 [KT133/KM133 AGP] + 8391 VT8371 [KX133 AGP] 8501 VT8501 [Apollo MVP4 AGP] 8596 VT82C596 [Apollo PRO AGP] 8597 VT82C597 [Apollo VP3 AGP] @@ -4635,7 +4636,12 @@ 84c4 450KX/GX [Orion] - 82454KX/GX PCI bridge 84c5 450KX/GX [Orion] - 82453KX/GX Memory controller 84ca 450NX - 82451NX Memory & I/O Controller - 84cb 450NX - 82454NX PCI Expander Bridge + 84cb 450NX - 82454NX/84460GX PCI Expander Bridge + 84e0 460GX - 84460GX System Address Controller (SAC) + 84e1 460GX - 84460GX System Data Controller (SDC) + 84e2 460GX - 84460GX AGP Bridge (GXB) + 84e3 460GX - 84460GX Memory Address Controller (MAC) + 84e4 460GX - 84460GX Memory Data Controller (MDC) ffff 450NX/GX [Orion] - 82453KX/GX Memory controller [BUG] 8800 Trigem Computer Inc. 2008 Video assistent component diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 703b8c138..2a517f7d6 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -238,6 +238,13 @@ get_pci_dev_info(char *buf, char **start, off_t pos, int count) } else cnt += len; buf += len; + if (cnt >= count) + /* + * proc_file_read() gives us 1KB of slack so it's OK if the + * above printfs write a little beyond the buffer end (we + * never write more than 1KB beyond the buffer end). + */ + break; } } return (count > cnt) ? cnt : count; diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 9fac0e1ce..1a95544d8 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -60,7 +60,8 @@ static int pci_assign_bus_resource(const struct pci_bus *bus, struct resource *res, unsigned long size, unsigned long min, - unsigned int type_mask) + unsigned int type_mask, + int resno) { int i; @@ -83,7 +84,7 @@ static int pci_assign_bus_resource(const struct pci_bus *bus, continue; /* Update PCI config space. */ - pcibios_update_resource(dev, r, res, i); + pcibios_update_resource(dev, r, res, resno); return 0; } return -EBUSY; @@ -100,14 +101,14 @@ pci_assign_resource(struct pci_dev *dev, int i) min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; /* First, try exact prefetching match.. */ - if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH) < 0) { + if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH, i) < 0) { /* * That failed. * * But a prefetching area can handle a non-prefetching * window (it will just not perform as well). */ - if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0) < 0) { + if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) { printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->name); return -EBUSY; } diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 30995bbbe..93228e5b5 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -596,9 +596,11 @@ static void unreset_socket(socket_info_t *s) s->state &= ~SOCKET_SETUP_PENDING; } else { send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); - s->reset_handle->event_callback_args.info = NULL; - EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE, - CS_EVENT_PRI_LOW); + if (s->reset_handle) { + s->reset_handle->event_callback_args.info = NULL; + EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE, + CS_EVENT_PRI_LOW); + } s->state &= ~EVENT_MASK; } } /* unreset_socket */ diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index 0702f7a03..de875f5f6 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.21 2000/07/13 08:06:40 davem Exp $ +/* $Id: rtc.c,v 1.22 2000/08/22 06:56:33 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -8,7 +8,7 @@ * use the modified clock utility. * * Get the modified clock utility from: - * ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c + * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c */ #include <linux/module.h> diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index 6fb6678f7..05a92c82c 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.46 2000/07/06 01:41:37 davem Exp $ +/* $Id: sab82532.c,v 1.47 2000/08/16 21:12:14 ecd Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -412,10 +412,6 @@ static inline void receive_chars(struct sab82532 *info, *tty->flip.flag_buf_ptr++ = TTY_FRAME; info->icount.frame++; } -#ifdef CMSPAR - else if (status & SAB82532_RSTAT_PARITY) - *tty->flip.flag_buf_ptr++ = TTY_PARITY; -#endif else *tty->flip.flag_buf_ptr++ = TTY_NORMAL; } @@ -2173,7 +2169,7 @@ static void __init sab82532_kgdb_hook(int line) static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.46 $"; + char *revision = "$Revision: 1.47 $"; char *version, *p; version = strchr(revision, ' '); diff --git a/drivers/scsi/README.tmscsim b/drivers/scsi/README.tmscsim index 99ae1e5a7..207420eb3 100644 --- a/drivers/scsi/README.tmscsim +++ b/drivers/scsi/README.tmscsim @@ -382,7 +382,7 @@ Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and maybe the DC390 log messages to the report. Bug reports should be send to me (Kurt Garloff <dc390@garloff.de>) as well -as to the linux-scsi list (<linux-scsi@vger.rutgers.edu>), as sometimes bugs +as to the linux-scsi list (<linux-scsi@vger.kernel.org>), as sometimes bugs are caused by the SCSI mid-level code. I will ask you for some more details and probably I will also ask you to diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index 7cbbc3f1f..655107348 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -283,7 +283,7 @@ # define FALSE 0 #endif -#if defined(__powerpc__) || defined(__i386) +#if defined(__powerpc__) || defined(__i386__) # define MMAPIO #endif diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h index 0abe7a6cd..7b8c9df55 100644 --- a/drivers/scsi/imm.h +++ b/drivers/scsi/imm.h @@ -10,7 +10,7 @@ #ifndef _IMM_H #define _IMM_H -#define IMM_VERSION "2.03 (for Linux 2.0.0)" +#define IMM_VERSION "2.04 (for Linux 2.4.0)" /* * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega. @@ -59,6 +59,7 @@ * CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16 * added CONFIG_SCSI_IZIP_SLOW_CTR option * [2.03] + * Fix kernel panic on scsi timeout. 20Aug00 [2.04] */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ @@ -171,6 +172,7 @@ int imm_biosparam(Disk *, kdev_t, int *); eh_device_reset_handler: NULL, \ eh_bus_reset_handler: imm_reset, \ eh_host_reset_handler: imm_reset, \ + use_new_eh_code: 1, \ bios_param: imm_biosparam, \ this_id: 7, \ sg_tablesize: SG_ALL, \ diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index 7ab442bbb..74147c329 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h @@ -10,7 +10,7 @@ #ifndef _PPA_H #define _PPA_H -#define PPA_VERSION "2.04 (for Linux 2.2.x)" +#define PPA_VERSION "2.05 (for Linux 2.2.x)" /* * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu) @@ -57,6 +57,7 @@ * by Peter Cherriman <pjc@ecs.soton.ac.uk> and * Tim Waugh <twaugh@redhat.com> * [2.04] + * Fix kernel panic on scsi timeout, 2000-08-18 [2.05] */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ @@ -169,6 +170,7 @@ int ppa_biosparam(Disk *, kdev_t, int *); eh_device_reset_handler: NULL, \ eh_bus_reset_handler: ppa_reset, \ eh_host_reset_handler: ppa_reset, \ + use_new_eh_code: 1, \ bios_param: ppa_biosparam, \ this_id: -1, \ sg_tablesize: SG_ALL, \ diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 05fd57cb0..540fdb012 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -1312,7 +1312,7 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) } sg_count -= n; } - } else if (Cmnd->request_bufflen) { + } else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) { dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); @@ -1569,7 +1569,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) pci64_unmap_sg(hostdata->pci_dev, (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); - else if (Cmnd->request_bufflen) + else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6d1602d7e..3d6e45fcd 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -280,24 +280,7 @@ int scsi_block_when_processing_errors(Scsi_Device * SDpnt) STATIC void scsi_eh_times_out(Scsi_Cmnd * SCpnt) { - unsigned long flags; - int rtn = FAILED; - SCpnt->eh_state = SCSI_STATE_TIMEOUT; - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - - /* - * As far as the low level driver is concerned, this command is still - * active, so we must give the low level driver a chance to abort it. (DB) - */ - spin_lock_irqsave(&io_request_lock, flags); - if (SCpnt->host->hostt->eh_abort_handler) - rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - - SCpnt->request.rq_status = RQ_SCSI_DONE; - SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; - SCSI_LOG_ERROR_RECOVERY(5, printk("In scsi_eh_times_out %p\n", SCpnt)); if (SCpnt->host->eh_action != NULL) @@ -651,6 +634,26 @@ STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout) * In other words, we don't want a callback any more. */ if (SCpnt->eh_state == SCSI_STATE_TIMEOUT) { + SCpnt->owner = SCSI_OWNER_LOWLEVEL; + + /* + * As far as the low level driver is + * concerned, this command is still active, so + * we must give the low level driver a chance + * to abort it. (DB) + * + * FIXME(eric) - we are not tracking whether we could + * abort a timed out command or not. Not sure how + * we should treat them differently anyways. + */ + spin_lock_irqsave(&io_request_lock, flags); + if (SCpnt->host->hostt->eh_abort_handler) + SCpnt->host->hostt->eh_abort_handler(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + + SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; + SCpnt->eh_state = FAILED; } SCSI_LOG_ERROR_RECOVERY(5, printk("send_eh_cmnd: %p eh_state:%x\n", diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 6f6020290..4bb3981d5 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -24,6 +24,7 @@ #define START_STOP_TIMEOUT (60 * HZ) #define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ) #define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ) +#define READ_DEFECT_DATA_TIMEOUT (60 * HZ ) /* ZIP-250 on parallel port takes as long! */ #define MAX_BUF PAGE_SIZE @@ -284,6 +285,10 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) timeout = READ_ELEMENT_STATUS_TIMEOUT; retries = NORMAL_RETRIES; break; + case READ_DEFECT_DATA: + timeout = READ_DEFECT_DATA_TIMEOUT; + retries = 1; + break; default: timeout = IOCTL_NORMAL_TIMEOUT; retries = NORMAL_RETRIES; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7122c49bd..dd5d17866 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -12,7 +12,7 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Aug 6 23:02:13 2000 by makisara@kai.makisara.local + Last modified: Tue Aug 15 16:56:35 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support @@ -2909,6 +2909,8 @@ static int st_ioctl(struct inode *inode, struct file *file, i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || + mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || + mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || mtc.mt_op == MTCOMPRESSION; } i = flush_buffer(STp, i); @@ -3148,7 +3150,7 @@ static ST_buffer * priority = GFP_KERNEL; i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = (ST_buffer *) kmalloc(i, priority); + tb = kmalloc(i, priority); if (tb) { if (need_dma) priority |= GFP_DMA; @@ -3479,10 +3481,8 @@ static int st_attach(Scsi_Device * SDp) return 1; } - tmp_da = (Scsi_Tape **) kmalloc(tmp_dev_max * sizeof(Scsi_Tape *), - GFP_ATOMIC); - tmp_ba = (ST_buffer **) kmalloc(tmp_dev_max * sizeof(ST_buffer *), - GFP_ATOMIC); + tmp_da = kmalloc(tmp_dev_max * sizeof(Scsi_Tape *), GFP_ATOMIC); + tmp_ba = kmalloc(tmp_dev_max * sizeof(ST_buffer *), GFP_ATOMIC); if (tmp_da == NULL || tmp_ba == NULL) { if (tmp_da != NULL) kfree(tmp_da); @@ -3517,7 +3517,7 @@ static int st_attach(Scsi_Device * SDp) if (i >= st_template.dev_max) panic("scsi_devices corrupt (st)"); - tpnt = (Scsi_Tape *)kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC); + tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC); if (tpnt == NULL) { SDp->attached--; write_unlock_irqrestore(&st_dev_arr_lock, flags); diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index 640d9b219..fab74d348 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -15,6 +15,7 @@ if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then fi fi dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND +dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND @@ -85,7 +86,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then bool ' Persistent DMA buffers' CONFIG_SOUND_DMAP if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND + dep_tristate ' AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND_OSS fi dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS dep_tristate ' Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 879951c4c..ab1e1eb6f 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_SOUND_CMPCI) += cmpci.o obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o +obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o diff --git a/drivers/sound/aci.c b/drivers/sound/aci.c index 6970bec0d..5c3045f2a 100644 --- a/drivers/sound/aci.c +++ b/drivers/sound/aci.c @@ -537,10 +537,10 @@ aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations aci_mixer_operations = { - "ACI", - "ACI mixer", - aci_mixer_ioctl, - NULL + owner: THIS_MODULE, + id: "ACI", + name: "ACI mixer", + ioctl: aci_mixer_ioctl }; static unsigned char diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c index bdab8a85b..311cdab9b 100644 --- a/drivers/sound/ad1816.c +++ b/drivers/sound/ad1816.c @@ -36,7 +36,6 @@ #include <linux/isapnp.h> #include <linux/stddef.h> -#include "soundmodule.h" #include "sound_config.h" #define DEBUGNOISE(x) @@ -248,13 +247,6 @@ static void ad1816_start_input (int dev, unsigned long buf, int count, restore_flags (flags); } - -static int ad1816_ioctl (int dev, unsigned int cmd, caddr_t arg) -{ - return -(EINVAL); -} - - static int ad1816_prepare_for_input (int dev, int bsize, int bcount) { unsigned long flags; @@ -535,24 +527,20 @@ static void ad1816_close (int dev) /* close device */ static struct audio_driver ad1816_audio_driver = { - ad1816_open, - ad1816_close, - ad1816_output_block, - ad1816_start_input, - ad1816_ioctl, - ad1816_prepare_for_input, - ad1816_prepare_for_output, - ad1816_halt, - NULL, - NULL, - ad1816_halt_input, - ad1816_halt_output, - ad1816_trigger, - ad1816_set_speed, - ad1816_set_bits, - ad1816_set_channels, - NULL, - NULL + owner: THIS_MODULE, + open: ad1816_open, + close: ad1816_close, + output_block: ad1816_output_block, + start_input: ad1816_start_input, + prepare_for_input: ad1816_prepare_for_input, + prepare_for_output: ad1816_prepare_for_output, + halt_io: ad1816_halt, + halt_input: ad1816_halt_input, + halt_output: ad1816_halt_output, + trigger: ad1816_trigger, + set_speed: ad1816_set_speed, + set_bits: ad1816_set_bits, + set_channels: ad1816_set_channels, }; @@ -992,9 +980,10 @@ ad1816_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) /* Mixer structure */ static struct mixer_operations ad1816_mixer_operations = { - "AD1816", - "AD1816 Mixer", - ad1816_mixer_ioctl + owner: THIS_MODULE, + id: "AD1816", + name: "AD1816 Mixer", + ioctl: ad1816_mixer_ioctl }; @@ -1424,7 +1413,6 @@ static int __init init_ad1816(void) } attach_ad1816(&cfg); - SOUND_LOCK; return 0; } @@ -1441,7 +1429,6 @@ static void __exit cleanup_ad1816 (void) } nr_ad1816_devs=0; - SOUND_LOCK_END; #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE if(activated) if(ad1816_dev) diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 91485b6e0..3b867899b 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -39,8 +39,6 @@ #include <linux/stddef.h> #include <linux/pm.h> -#include "soundmodule.h" - #define DEB(x) #define DEB1(x) #include "sound_config.h" @@ -892,29 +890,28 @@ static unsigned int ad1848_set_bits(int dev, unsigned int arg) static struct audio_driver ad1848_audio_driver = { - ad1848_open, - ad1848_close, - ad1848_output_block, - ad1848_start_input, - NULL, - ad1848_prepare_for_input, - ad1848_prepare_for_output, - ad1848_halt, - NULL, - NULL, - ad1848_halt_input, - ad1848_halt_output, - ad1848_trigger, - ad1848_set_speed, - ad1848_set_bits, - ad1848_set_channels + owner: THIS_MODULE, + open: ad1848_open, + close: ad1848_close, + output_block: ad1848_output_block, + start_input: ad1848_start_input, + prepare_for_input: ad1848_prepare_for_input, + prepare_for_output: ad1848_prepare_for_output, + halt_io: ad1848_halt, + halt_input: ad1848_halt_input, + halt_output: ad1848_halt_output, + trigger: ad1848_trigger, + set_speed: ad1848_set_speed, + set_bits: ad1848_set_bits, + set_channels: ad1848_set_channels }; static struct mixer_operations ad1848_mixer_operations = { - "SOUNDPORT", - "AD1848/CS4248/CS4231", - ad1848_mixer_ioctl + owner: THIS_MODULE, + id: "SOUNDPORT", + name: "AD1848/CS4248/CS4231", + ioctl: ad1848_mixer_ioctl }; static int ad1848_open(int dev, int mode) @@ -1849,7 +1846,8 @@ int ad1848_detect(int io_base, int *ad_flags, int *osp) return 1; } -int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp) +int ad1848_init (char *name, int io_base, int irq, int dma_playback, + int dma_capture, int share_dma, int *osp, struct module *owner) { /* * NOTE! If irq < 0, there is another driver which has allocated the IRQ @@ -1901,7 +1899,10 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL); if(portc==NULL) return -1; - + + if (owner) + ad1848_audio_driver.owner = owner; + if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &ad1848_audio_driver, @@ -2498,7 +2499,7 @@ int probe_ms_sound(struct address_info *hw_config) return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); } -void attach_ms_sound(struct address_info *hw_config) +void attach_ms_sound(struct address_info *hw_config, struct module *owner) { static signed char interrupt_bits[12] = { @@ -2523,7 +2524,8 @@ void attach_ms_sound(struct address_info *hw_config) hw_config->irq, hw_config->dma, hw_config->dma2, 0, - hw_config->osp); + hw_config->osp, + owner); request_region(hw_config->io_base, 4, "WSS config"); return; } @@ -2581,7 +2583,8 @@ void attach_ms_sound(struct address_info *hw_config) hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, hw_config->irq, dma, dma2, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); request_region(hw_config->io_base, 4, "WSS config"); } @@ -2829,17 +2832,15 @@ static int __init init_ad1848(void) if(!probe_ms_sound(&cfg)) return -ENODEV; - attach_ms_sound(&cfg); + attach_ms_sound(&cfg, THIS_MODULE); loaded = 1; } - SOUND_LOCK; return 0; } static void __exit cleanup_ad1848(void) { - SOUND_LOCK_END; if(loaded) unload_ms_sound(&cfg); } diff --git a/drivers/sound/ad1848.h b/drivers/sound/ad1848.h index 2f2225546..234bbb823 100644 --- a/drivers/sound/ad1848.h +++ b/drivers/sound/ad1848.h @@ -15,14 +15,14 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, - int dma_capture, int share_dma, int *osp); + int dma_capture, int share_dma, int *osp, struct module *owner); void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma); int ad1848_detect (int io_base, int *flags, int *osp); int ad1848_control(int cmd, int arg); void adintr(int irq, void *dev_id, struct pt_regs * dummy); -void attach_ms_sound(struct address_info * hw_config); +void attach_ms_sound(struct address_info * hw_config, struct module * owner); int probe_ms_sound(struct address_info *hw_config); void unload_ms_sound(struct address_info *hw_info); diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c index 95974d444..1bc2f6653 100644 --- a/drivers/sound/adlib_card.c +++ b/drivers/sound/adlib_card.c @@ -14,13 +14,12 @@ #include <linux/init.h> #include "sound_config.h" -#include "soundmodule.h" #include "opl3.h" static void __init attach_adlib_card(struct address_info *hw_config) { - hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp); + hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp, THIS_MODULE); request_region(hw_config->io_base, 4, "OPL3/OPL2"); } @@ -50,7 +49,7 @@ static int __init init_adlib(void) if (probe_adlib(&cfg) == 0) return -ENODEV; attach_adlib_card(&cfg); - SOUND_LOCK; + return 0; } @@ -59,7 +58,6 @@ static void __exit cleanup_adlib(void) release_region(cfg.io_base, 4); sound_unload_synthdev(cfg.slots[0]); - SOUND_LOCK_END; } module_init(init_adlib); diff --git a/drivers/sound/aedsp16.c b/drivers/sound/aedsp16.c index 6ea812a38..166dbb52b 100644 --- a/drivers/sound/aedsp16.c +++ b/drivers/sound/aedsp16.c @@ -28,7 +28,6 @@ #include <linux/module.h> #include <linux/init.h> #include "sound_config.h" -#include "soundmodule.h" /* * Sanity checks @@ -1357,13 +1356,11 @@ static int __init do_init_aedsp16(void) { */ return -EINVAL; } - SOUND_LOCK; return 0; } static void __exit cleanup_aedsp16(void) { uninit_aedsp16(); - SOUND_LOCK_END; } module_init(do_init_aedsp16); diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index ffb88a7b4..09418df79 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -82,14 +82,15 @@ int audio_open(int dev, struct file *file) if (dev < 0 || dev >= num_audiodevs) return -ENXIO; + if (audio_devs[dev]->d->owner) + __MOD_INC_USE_COUNT (audio_devs[dev]->d->owner); + if ((ret = DMAbuf_open(dev, mode)) < 0) return ret; - if (audio_devs[dev]->coproc) - { + if (audio_devs[dev]->coproc) { if ((ret = audio_devs[dev]->coproc-> - open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) - { + open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) { audio_release(dev, file); printk(KERN_WARNING "Sound: Can't access coprocessor device\n"); return ret; @@ -178,6 +179,9 @@ void audio_release(int dev, struct file *file) if (audio_devs[dev]->coproc) audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc, COPR_PCM); DMAbuf_release(dev, mode); + + if (audio_devs[dev]->d->owner) + __MOD_DEC_USE_COUNT (audio_devs[dev]->d->owner); } static void translate_bytes(const unsigned char *table, unsigned char *buff, int n) diff --git a/drivers/sound/awe_wave.c b/drivers/sound/awe_wave.c index 4fee7b72f..a87c10ce3 100644 --- a/drivers/sound/awe_wave.c +++ b/drivers/sound/awe_wave.c @@ -31,7 +31,6 @@ #endif #include "sound_config.h" -#include "soundmodule.h" #include "awe_wave.h" #include "awe_hw.h" @@ -496,27 +495,28 @@ static int ctrls[AWE_MD_END]; static struct synth_operations awe_operations = { - "EMU8K", - &awe_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_AWE32, - awe_open, - awe_close, - awe_ioctl, - awe_kill_note, - awe_start_note, - awe_set_instr_2, - awe_reset, - awe_hw_control, - awe_load_patch, - awe_aftertouch, - awe_controller, - awe_panning, - awe_volume_method, - awe_bender, - awe_alloc, - awe_setup_voice + owner: THIS_MODULE, + id: "EMU8K", + info: &awe_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: SAMPLE_TYPE_AWE32, + open: awe_open, + close: awe_close, + ioctl: awe_ioctl, + kill_note: awe_kill_note, + start_note: awe_start_note, + set_instr: awe_set_instr_2, + reset: awe_reset, + hw_control: awe_hw_control, + load_patch: awe_load_patch, + aftertouch: awe_aftertouch, + controller: awe_controller, + panning: awe_panning, + volume_method: awe_volume_method, + bender: awe_bender, + alloc_voice: awe_alloc, + setup_voice: awe_setup_voice }; @@ -575,8 +575,6 @@ static int __init _attach_awe(void) awe_present = TRUE; - SOUND_LOCK; - return 1; } @@ -608,7 +606,6 @@ static void __exit _unload_awe(void) #endif sound_unload_synthdev(my_dev); awe_present = FALSE; - SOUND_LOCK_END; } } @@ -4293,8 +4290,10 @@ static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg); static int my_mixerdev = -1; static struct mixer_operations awe_mixer_operations = { - "AWE32 Equalizer", - awe_mixer_ioctl, + owner: THIS_MODULE, + id: "AWE", + name: "AWE32 Equalizer", + ioctl: awe_mixer_ioctl, }; static void __init attach_mixer(void) @@ -5225,17 +5224,13 @@ static int xg_control_change(MidiStatus *st, int cmd, int val); static struct midi_operations awe_midi_operations = { - {"AWE Midi Emu", 0, 0, SNDCARD_SB}, - NULL /*&std_midi_synth*/, - {0}, /* input_info */ - awe_midi_open, /*open*/ - awe_midi_close, /*close*/ - awe_midi_ioctl, /*ioctl*/ - awe_midi_outputc, /*outputc*/ - NULL /*start_read*/, - NULL /*end_read*/, - NULL, /* kick */ - NULL, /* command */ + owner: THIS_MODULE, + info: {"AWE Midi Emu", 0, 0, SNDCARD_SB}, + in_info: {0}, + open: awe_midi_open, /*open*/ + close: awe_midi_close, /*close*/ + ioctl: awe_midi_ioctl, /*ioctl*/ + outputc: awe_midi_outputc, /*outputc*/ }; static int my_mididev = -1; diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c index 6fcb896ac..fbba12583 100644 --- a/drivers/sound/cmpci.c +++ b/drivers/sound/cmpci.c @@ -238,8 +238,6 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 }; #define FMODE_DMFM 0x10 -#define SND_DEV_DSP16 5 - /* --------------------------------------------------------------------- */ struct cm_state { diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index 8c7f90777..32f230069 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -46,7 +46,6 @@ #include <linux/init.h> #include "sound_config.h" -#include "soundmodule.h" #include "cs4232.h" #include "ad1848.h" @@ -229,7 +228,8 @@ void attach_cs4232(struct address_info *hw_config) dma1, /* Playback DMA */ dma2, /* Capture DMA */ 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); if (hw_config->slots[0] != -1 && audio_devs[hw_config->slots[0]]->mixer_dev!=-1) @@ -258,7 +258,7 @@ void attach_cs4232(struct address_info *hw_config) if (probe_uart401(&hw_config2)) { mpu_detected = 1; - attach_uart401(&hw_config2); + attach_uart401(&hw_config2, THIS_MODULE); } else { @@ -266,7 +266,6 @@ void attach_cs4232(struct address_info *hw_config) } hw_config->slots[1] = hw_config2.slots[1]; } - SOUND_LOCK; } void unload_cs4232(struct address_info *hw_config) @@ -376,7 +375,6 @@ static int __init init_cs4232(void) static void __exit cleanup_cs4232(void) { unload_cs4232(&cfg); /* unloads MPU as well, if needed */ - SOUND_LOCK_END; } module_init(init_cs4232); diff --git a/drivers/sound/cs461x.h b/drivers/sound/cs461x.h new file mode 100644 index 000000000..e04f5faa9 --- /dev/null +++ b/drivers/sound/cs461x.h @@ -0,0 +1,1617 @@ +#ifndef __CS461X_H +#define __CS461X_H + +/* + * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Definitions for Cirrus Logic CS461x chips + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef PCI_VENDOR_ID_CIRRUS +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4610 +#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4612 +#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4615 +#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 +#endif + +/* + * Direct registers + */ + +/* + * The following define the offsets of the registers accessed via base address + * register zero on the CS461x part. + */ +#define BA0_HISR 0x00000000 +#define BA0_HSR0 0x00000004 +#define BA0_HICR 0x00000008 +#define BA0_DMSR 0x00000100 +#define BA0_HSAR 0x00000110 +#define BA0_HDAR 0x00000114 +#define BA0_HDMR 0x00000118 +#define BA0_HDCR 0x0000011C +#define BA0_PFMC 0x00000200 +#define BA0_PFCV1 0x00000204 +#define BA0_PFCV2 0x00000208 +#define BA0_PCICFG00 0x00000300 +#define BA0_PCICFG04 0x00000304 +#define BA0_PCICFG08 0x00000308 +#define BA0_PCICFG0C 0x0000030C +#define BA0_PCICFG10 0x00000310 +#define BA0_PCICFG14 0x00000314 +#define BA0_PCICFG18 0x00000318 +#define BA0_PCICFG1C 0x0000031C +#define BA0_PCICFG20 0x00000320 +#define BA0_PCICFG24 0x00000324 +#define BA0_PCICFG28 0x00000328 +#define BA0_PCICFG2C 0x0000032C +#define BA0_PCICFG30 0x00000330 +#define BA0_PCICFG34 0x00000334 +#define BA0_PCICFG38 0x00000338 +#define BA0_PCICFG3C 0x0000033C +#define BA0_CLKCR1 0x00000400 +#define BA0_CLKCR2 0x00000404 +#define BA0_PLLM 0x00000408 +#define BA0_PLLCC 0x0000040C +#define BA0_FRR 0x00000410 +#define BA0_CFL1 0x00000414 +#define BA0_CFL2 0x00000418 +#define BA0_SERMC1 0x00000420 +#define BA0_SERMC2 0x00000424 +#define BA0_SERC1 0x00000428 +#define BA0_SERC2 0x0000042C +#define BA0_SERC3 0x00000430 +#define BA0_SERC4 0x00000434 +#define BA0_SERC5 0x00000438 +#define BA0_SERBSP 0x0000043C +#define BA0_SERBST 0x00000440 +#define BA0_SERBCM 0x00000444 +#define BA0_SERBAD 0x00000448 +#define BA0_SERBCF 0x0000044C +#define BA0_SERBWP 0x00000450 +#define BA0_SERBRP 0x00000454 +#ifndef NO_CS4612 +#define BA0_ASER_FADDR 0x00000458 +#endif +#define BA0_ACCTL 0x00000460 +#define BA0_ACSTS 0x00000464 +#define BA0_ACOSV 0x00000468 +#define BA0_ACCAD 0x0000046C +#define BA0_ACCDA 0x00000470 +#define BA0_ACISV 0x00000474 +#define BA0_ACSAD 0x00000478 +#define BA0_ACSDA 0x0000047C +#define BA0_JSPT 0x00000480 +#define BA0_JSCTL 0x00000484 +#define BA0_JSC1 0x00000488 +#define BA0_JSC2 0x0000048C +#define BA0_MIDCR 0x00000490 +#define BA0_MIDSR 0x00000494 +#define BA0_MIDWP 0x00000498 +#define BA0_MIDRP 0x0000049C +#define BA0_JSIO 0x000004A0 +#ifndef NO_CS4612 +#define BA0_ASER_MASTER 0x000004A4 +#endif +#define BA0_CFGI 0x000004B0 +#define BA0_SSVID 0x000004B4 +#define BA0_GPIOR 0x000004B8 +#ifndef NO_CS4612 +#define BA0_EGPIODR 0x000004BC +#define BA0_EGPIOPTR 0x000004C0 +#define BA0_EGPIOTR 0x000004C4 +#define BA0_EGPIOWR 0x000004C8 +#define BA0_EGPIOSR 0x000004CC +#define BA0_SERC6 0x000004D0 +#define BA0_SERC7 0x000004D4 +#define BA0_SERACC 0x000004D8 +#define BA0_ACCTL2 0x000004E0 +#define BA0_ACSTS2 0x000004E4 +#define BA0_ACOSV2 0x000004E8 +#define BA0_ACCAD2 0x000004EC +#define BA0_ACCDA2 0x000004F0 +#define BA0_ACISV2 0x000004F4 +#define BA0_ACSAD2 0x000004F8 +#define BA0_ACSDA2 0x000004FC +#define BA0_IOTAC0 0x00000500 +#define BA0_IOTAC1 0x00000504 +#define BA0_IOTAC2 0x00000508 +#define BA0_IOTAC3 0x0000050C +#define BA0_IOTAC4 0x00000510 +#define BA0_IOTAC5 0x00000514 +#define BA0_IOTAC6 0x00000518 +#define BA0_IOTAC7 0x0000051C +#define BA0_IOTAC8 0x00000520 +#define BA0_IOTAC9 0x00000524 +#define BA0_IOTAC10 0x00000528 +#define BA0_IOTAC11 0x0000052C +#define BA0_IOTFR0 0x00000540 +#define BA0_IOTFR1 0x00000544 +#define BA0_IOTFR2 0x00000548 +#define BA0_IOTFR3 0x0000054C +#define BA0_IOTFR4 0x00000550 +#define BA0_IOTFR5 0x00000554 +#define BA0_IOTFR6 0x00000558 +#define BA0_IOTFR7 0x0000055C +#define BA0_IOTFIFO 0x00000580 +#define BA0_IOTRRD 0x00000584 +#define BA0_IOTFP 0x00000588 +#define BA0_IOTCR 0x0000058C +#define BA0_DPCID 0x00000590 +#define BA0_DPCIA 0x00000594 +#define BA0_DPCIC 0x00000598 +#define BA0_PCPCIR 0x00000600 +#define BA0_PCPCIG 0x00000604 +#define BA0_PCPCIEN 0x00000608 +#define BA0_EPCIPMC 0x00000610 +#endif + +/* + * The following define the offsets of the registers and memories accessed via + * base address register one on the CS461x part. + */ +#define BA1_SP_DMEM0 0x00000000 +#define BA1_SP_DMEM1 0x00010000 +#define BA1_SP_PMEM 0x00020000 +#define BA1_SP_REG 0x00030000 +#define BA1_SPCR 0x00030000 +#define BA1_DREG 0x00030004 +#define BA1_DSRWP 0x00030008 +#define BA1_TWPR 0x0003000C +#define BA1_SPWR 0x00030010 +#define BA1_SPIR 0x00030014 +#define BA1_FGR1 0x00030020 +#define BA1_SPCS 0x00030028 +#define BA1_SDSR 0x0003002C +#define BA1_FRMT 0x00030030 +#define BA1_FRCC 0x00030034 +#define BA1_FRSC 0x00030038 +#define BA1_OMNI_MEM 0x000E0000 + +/* + * The following defines are for the flags in the host interrupt status + * register. + */ +#define HISR_VC_MASK 0x0000FFFF +#define HISR_VC0 0x00000001 +#define HISR_VC1 0x00000002 +#define HISR_VC2 0x00000004 +#define HISR_VC3 0x00000008 +#define HISR_VC4 0x00000010 +#define HISR_VC5 0x00000020 +#define HISR_VC6 0x00000040 +#define HISR_VC7 0x00000080 +#define HISR_VC8 0x00000100 +#define HISR_VC9 0x00000200 +#define HISR_VC10 0x00000400 +#define HISR_VC11 0x00000800 +#define HISR_VC12 0x00001000 +#define HISR_VC13 0x00002000 +#define HISR_VC14 0x00004000 +#define HISR_VC15 0x00008000 +#define HISR_INT0 0x00010000 +#define HISR_INT1 0x00020000 +#define HISR_DMAI 0x00040000 +#define HISR_FROVR 0x00080000 +#define HISR_MIDI 0x00100000 +#ifdef NO_CS4612 +#define HISR_RESERVED 0x0FE00000 +#else +#define HISR_SBINT 0x00200000 +#define HISR_RESERVED 0x0FC00000 +#endif +#define HISR_H0P 0x40000000 +#define HISR_INTENA 0x80000000 + +/* + * The following defines are for the flags in the host signal register 0. + */ +#define HSR0_VC_MASK 0xFFFFFFFF +#define HSR0_VC16 0x00000001 +#define HSR0_VC17 0x00000002 +#define HSR0_VC18 0x00000004 +#define HSR0_VC19 0x00000008 +#define HSR0_VC20 0x00000010 +#define HSR0_VC21 0x00000020 +#define HSR0_VC22 0x00000040 +#define HSR0_VC23 0x00000080 +#define HSR0_VC24 0x00000100 +#define HSR0_VC25 0x00000200 +#define HSR0_VC26 0x00000400 +#define HSR0_VC27 0x00000800 +#define HSR0_VC28 0x00001000 +#define HSR0_VC29 0x00002000 +#define HSR0_VC30 0x00004000 +#define HSR0_VC31 0x00008000 +#define HSR0_VC32 0x00010000 +#define HSR0_VC33 0x00020000 +#define HSR0_VC34 0x00040000 +#define HSR0_VC35 0x00080000 +#define HSR0_VC36 0x00100000 +#define HSR0_VC37 0x00200000 +#define HSR0_VC38 0x00400000 +#define HSR0_VC39 0x00800000 +#define HSR0_VC40 0x01000000 +#define HSR0_VC41 0x02000000 +#define HSR0_VC42 0x04000000 +#define HSR0_VC43 0x08000000 +#define HSR0_VC44 0x10000000 +#define HSR0_VC45 0x20000000 +#define HSR0_VC46 0x40000000 +#define HSR0_VC47 0x80000000 + +/* + * The following defines are for the flags in the host interrupt control + * register. + */ +#define HICR_IEV 0x00000001 +#define HICR_CHGM 0x00000002 + +/* + * The following defines are for the flags in the DMA status register. + */ +#define DMSR_HP 0x00000001 +#define DMSR_HR 0x00000002 +#define DMSR_SP 0x00000004 +#define DMSR_SR 0x00000008 + +/* + * The following defines are for the flags in the host DMA source address + * register. + */ +#define HSAR_HOST_ADDR_MASK 0xFFFFFFFF +#define HSAR_DSP_ADDR_MASK 0x0000FFFF +#define HSAR_MEMID_MASK 0x000F0000 +#define HSAR_MEMID_SP_DMEM0 0x00000000 +#define HSAR_MEMID_SP_DMEM1 0x00010000 +#define HSAR_MEMID_SP_PMEM 0x00020000 +#define HSAR_MEMID_SP_DEBUG 0x00030000 +#define HSAR_MEMID_OMNI_MEM 0x000E0000 +#define HSAR_END 0x40000000 +#define HSAR_ERR 0x80000000 + +/* + * The following defines are for the flags in the host DMA destination address + * register. + */ +#define HDAR_HOST_ADDR_MASK 0xFFFFFFFF +#define HDAR_DSP_ADDR_MASK 0x0000FFFF +#define HDAR_MEMID_MASK 0x000F0000 +#define HDAR_MEMID_SP_DMEM0 0x00000000 +#define HDAR_MEMID_SP_DMEM1 0x00010000 +#define HDAR_MEMID_SP_PMEM 0x00020000 +#define HDAR_MEMID_SP_DEBUG 0x00030000 +#define HDAR_MEMID_OMNI_MEM 0x000E0000 +#define HDAR_END 0x40000000 +#define HDAR_ERR 0x80000000 + +/* + * The following defines are for the flags in the host DMA control register. + */ +#define HDMR_AC_MASK 0x0000F000 +#define HDMR_AC_8_16 0x00001000 +#define HDMR_AC_M_S 0x00002000 +#define HDMR_AC_B_L 0x00004000 +#define HDMR_AC_S_U 0x00008000 + +/* + * The following defines are for the flags in the host DMA control register. + */ +#define HDCR_COUNT_MASK 0x000003FF +#define HDCR_DONE 0x00004000 +#define HDCR_OPT 0x00008000 +#define HDCR_WBD 0x00400000 +#define HDCR_WBS 0x00800000 +#define HDCR_DMS_MASK 0x07000000 +#define HDCR_DMS_LINEAR 0x00000000 +#define HDCR_DMS_16_DWORDS 0x01000000 +#define HDCR_DMS_32_DWORDS 0x02000000 +#define HDCR_DMS_64_DWORDS 0x03000000 +#define HDCR_DMS_128_DWORDS 0x04000000 +#define HDCR_DMS_256_DWORDS 0x05000000 +#define HDCR_DMS_512_DWORDS 0x06000000 +#define HDCR_DMS_1024_DWORDS 0x07000000 +#define HDCR_DH 0x08000000 +#define HDCR_SMS_MASK 0x70000000 +#define HDCR_SMS_LINEAR 0x00000000 +#define HDCR_SMS_16_DWORDS 0x10000000 +#define HDCR_SMS_32_DWORDS 0x20000000 +#define HDCR_SMS_64_DWORDS 0x30000000 +#define HDCR_SMS_128_DWORDS 0x40000000 +#define HDCR_SMS_256_DWORDS 0x50000000 +#define HDCR_SMS_512_DWORDS 0x60000000 +#define HDCR_SMS_1024_DWORDS 0x70000000 +#define HDCR_SH 0x80000000 +#define HDCR_COUNT_SHIFT 0 + +/* + * The following defines are for the flags in the performance monitor control + * register. + */ +#define PFMC_C1SS_MASK 0x0000001F +#define PFMC_C1EV 0x00000020 +#define PFMC_C1RS 0x00008000 +#define PFMC_C2SS_MASK 0x001F0000 +#define PFMC_C2EV 0x00200000 +#define PFMC_C2RS 0x80000000 +#define PFMC_C1SS_SHIFT 0 +#define PFMC_C2SS_SHIFT 16 +#define PFMC_BUS_GRANT 0 +#define PFMC_GRANT_AFTER_REQ 1 +#define PFMC_TRANSACTION 2 +#define PFMC_DWORD_TRANSFER 3 +#define PFMC_SLAVE_READ 4 +#define PFMC_SLAVE_WRITE 5 +#define PFMC_PREEMPTION 6 +#define PFMC_DISCONNECT_RETRY 7 +#define PFMC_INTERRUPT 8 +#define PFMC_BUS_OWNERSHIP 9 +#define PFMC_TRANSACTION_LAG 10 +#define PFMC_PCI_CLOCK 11 +#define PFMC_SERIAL_CLOCK 12 +#define PFMC_SP_CLOCK 13 + +/* + * The following defines are for the flags in the performance counter value 1 + * register. + */ +#define PFCV1_PC1V_MASK 0xFFFFFFFF +#define PFCV1_PC1V_SHIFT 0 + +/* + * The following defines are for the flags in the performance counter value 2 + * register. + */ +#define PFCV2_PC2V_MASK 0xFFFFFFFF +#define PFCV2_PC2V_SHIFT 0 + +/* + * The following defines are for the flags in the clock control register 1. + */ +#define CLKCR1_OSCS 0x00000001 +#define CLKCR1_OSCP 0x00000002 +#define CLKCR1_PLLSS_MASK 0x0000000C +#define CLKCR1_PLLSS_SERIAL 0x00000000 +#define CLKCR1_PLLSS_CRYSTAL 0x00000004 +#define CLKCR1_PLLSS_PCI 0x00000008 +#define CLKCR1_PLLSS_RESERVED 0x0000000C +#define CLKCR1_PLLP 0x00000010 +#define CLKCR1_SWCE 0x00000020 +#define CLKCR1_PLLOS 0x00000040 + +/* + * The following defines are for the flags in the clock control register 2. + */ +#define CLKCR2_PDIVS_MASK 0x0000000F +#define CLKCR2_PDIVS_1 0x00000001 +#define CLKCR2_PDIVS_2 0x00000002 +#define CLKCR2_PDIVS_4 0x00000004 +#define CLKCR2_PDIVS_7 0x00000007 +#define CLKCR2_PDIVS_8 0x00000008 +#define CLKCR2_PDIVS_16 0x00000000 + +/* + * The following defines are for the flags in the PLL multiplier register. + */ +#define PLLM_MASK 0x000000FF +#define PLLM_SHIFT 0 + +/* + * The following defines are for the flags in the PLL capacitor coefficient + * register. + */ +#define PLLCC_CDR_MASK 0x00000007 +#ifndef NO_CS4610 +#define PLLCC_CDR_240_350_MHZ 0x00000000 +#define PLLCC_CDR_184_265_MHZ 0x00000001 +#define PLLCC_CDR_144_205_MHZ 0x00000002 +#define PLLCC_CDR_111_160_MHZ 0x00000003 +#define PLLCC_CDR_87_123_MHZ 0x00000004 +#define PLLCC_CDR_67_96_MHZ 0x00000005 +#define PLLCC_CDR_52_74_MHZ 0x00000006 +#define PLLCC_CDR_45_58_MHZ 0x00000007 +#endif +#ifndef NO_CS4612 +#define PLLCC_CDR_271_398_MHZ 0x00000000 +#define PLLCC_CDR_227_330_MHZ 0x00000001 +#define PLLCC_CDR_167_239_MHZ 0x00000002 +#define PLLCC_CDR_150_215_MHZ 0x00000003 +#define PLLCC_CDR_107_154_MHZ 0x00000004 +#define PLLCC_CDR_98_140_MHZ 0x00000005 +#define PLLCC_CDR_73_104_MHZ 0x00000006 +#define PLLCC_CDR_63_90_MHZ 0x00000007 +#endif +#define PLLCC_LPF_MASK 0x000000F8 +#ifndef NO_CS4610 +#define PLLCC_LPF_23850_60000_KHZ 0x00000000 +#define PLLCC_LPF_7960_26290_KHZ 0x00000008 +#define PLLCC_LPF_4160_10980_KHZ 0x00000018 +#define PLLCC_LPF_1740_4580_KHZ 0x00000038 +#define PLLCC_LPF_724_1910_KHZ 0x00000078 +#define PLLCC_LPF_317_798_KHZ 0x000000F8 +#endif +#ifndef NO_CS4612 +#define PLLCC_LPF_25580_64530_KHZ 0x00000000 +#define PLLCC_LPF_14360_37270_KHZ 0x00000008 +#define PLLCC_LPF_6100_16020_KHZ 0x00000018 +#define PLLCC_LPF_2540_6690_KHZ 0x00000038 +#define PLLCC_LPF_1050_2780_KHZ 0x00000078 +#define PLLCC_LPF_450_1160_KHZ 0x000000F8 +#endif + +/* + * The following defines are for the flags in the feature reporting register. + */ +#define FRR_FAB_MASK 0x00000003 +#define FRR_MASK_MASK 0x0000001C +#ifdef NO_CS4612 +#define FRR_CFOP_MASK 0x000000E0 +#else +#define FRR_CFOP_MASK 0x00000FE0 +#endif +#define FRR_CFOP_NOT_DVD 0x00000020 +#define FRR_CFOP_A3D 0x00000040 +#define FRR_CFOP_128_PIN 0x00000080 +#ifndef NO_CS4612 +#define FRR_CFOP_CS4280 0x00000800 +#endif +#define FRR_FAB_SHIFT 0 +#define FRR_MASK_SHIFT 2 +#define FRR_CFOP_SHIFT 5 + +/* + * The following defines are for the flags in the configuration load 1 + * register. + */ +#define CFL1_CLOCK_SOURCE_MASK 0x00000003 +#define CFL1_CLOCK_SOURCE_CS423X 0x00000000 +#define CFL1_CLOCK_SOURCE_AC97 0x00000001 +#define CFL1_CLOCK_SOURCE_CRYSTAL 0x00000002 +#define CFL1_CLOCK_SOURCE_DUAL_AC97 0x00000003 +#define CFL1_VALID_DATA_MASK 0x000000FF + +/* + * The following defines are for the flags in the configuration load 2 + * register. + */ +#define CFL2_VALID_DATA_MASK 0x000000FF + +/* + * The following defines are for the flags in the serial port master control + * register 1. + */ +#define SERMC1_MSPE 0x00000001 +#define SERMC1_PTC_MASK 0x0000000E +#define SERMC1_PTC_CS423X 0x00000000 +#define SERMC1_PTC_AC97 0x00000002 +#define SERMC1_PTC_DAC 0x00000004 +#define SERMC1_PLB 0x00000010 +#define SERMC1_XLB 0x00000020 + +/* + * The following defines are for the flags in the serial port master control + * register 2. + */ +#define SERMC2_LROE 0x00000001 +#define SERMC2_MCOE 0x00000002 +#define SERMC2_MCDIV 0x00000004 + +/* + * The following defines are for the flags in the serial port 1 configuration + * register. + */ +#define SERC1_SO1EN 0x00000001 +#define SERC1_SO1F_MASK 0x0000000E +#define SERC1_SO1F_CS423X 0x00000000 +#define SERC1_SO1F_AC97 0x00000002 +#define SERC1_SO1F_DAC 0x00000004 +#define SERC1_SO1F_SPDIF 0x00000006 + +/* + * The following defines are for the flags in the serial port 2 configuration + * register. + */ +#define SERC2_SI1EN 0x00000001 +#define SERC2_SI1F_MASK 0x0000000E +#define SERC2_SI1F_CS423X 0x00000000 +#define SERC2_SI1F_AC97 0x00000002 +#define SERC2_SI1F_ADC 0x00000004 +#define SERC2_SI1F_SPDIF 0x00000006 + +/* + * The following defines are for the flags in the serial port 3 configuration + * register. + */ +#define SERC3_SO2EN 0x00000001 +#define SERC3_SO2F_MASK 0x00000006 +#define SERC3_SO2F_DAC 0x00000000 +#define SERC3_SO2F_SPDIF 0x00000002 + +/* + * The following defines are for the flags in the serial port 4 configuration + * register. + */ +#define SERC4_SO3EN 0x00000001 +#define SERC4_SO3F_MASK 0x00000006 +#define SERC4_SO3F_DAC 0x00000000 +#define SERC4_SO3F_SPDIF 0x00000002 + +/* + * The following defines are for the flags in the serial port 5 configuration + * register. + */ +#define SERC5_SI2EN 0x00000001 +#define SERC5_SI2F_MASK 0x00000006 +#define SERC5_SI2F_ADC 0x00000000 +#define SERC5_SI2F_SPDIF 0x00000002 + +/* + * The following defines are for the flags in the serial port backdoor sample + * pointer register. + */ +#define SERBSP_FSP_MASK 0x0000000F +#define SERBSP_FSP_SHIFT 0 + +/* + * The following defines are for the flags in the serial port backdoor status + * register. + */ +#define SERBST_RRDY 0x00000001 +#define SERBST_WBSY 0x00000002 + +/* + * The following defines are for the flags in the serial port backdoor command + * register. + */ +#define SERBCM_RDC 0x00000001 +#define SERBCM_WRC 0x00000002 + +/* + * The following defines are for the flags in the serial port backdoor address + * register. + */ +#ifdef NO_CS4612 +#define SERBAD_FAD_MASK 0x000000FF +#else +#define SERBAD_FAD_MASK 0x000001FF +#endif +#define SERBAD_FAD_SHIFT 0 + +/* + * The following defines are for the flags in the serial port backdoor + * configuration register. + */ +#define SERBCF_HBP 0x00000001 + +/* + * The following defines are for the flags in the serial port backdoor write + * port register. + */ +#define SERBWP_FWD_MASK 0x000FFFFF +#define SERBWP_FWD_SHIFT 0 + +/* + * The following defines are for the flags in the serial port backdoor read + * port register. + */ +#define SERBRP_FRD_MASK 0x000FFFFF +#define SERBRP_FRD_SHIFT 0 + +/* + * The following defines are for the flags in the async FIFO address register. + */ +#ifndef NO_CS4612 +#define ASER_FADDR_A1_MASK 0x000001FF +#define ASER_FADDR_EN1 0x00008000 +#define ASER_FADDR_A2_MASK 0x01FF0000 +#define ASER_FADDR_EN2 0x80000000 +#define ASER_FADDR_A1_SHIFT 0 +#define ASER_FADDR_A2_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the AC97 control register. + */ +#define ACCTL_RSTN 0x00000001 +#define ACCTL_ESYN 0x00000002 +#define ACCTL_VFRM 0x00000004 +#define ACCTL_DCV 0x00000008 +#define ACCTL_CRW 0x00000010 +#define ACCTL_ASYN 0x00000020 +#ifndef NO_CS4612 +#define ACCTL_TC 0x00000040 +#endif + +/* + * The following defines are for the flags in the AC97 status register. + */ +#define ACSTS_CRDY 0x00000001 +#define ACSTS_VSTS 0x00000002 +#ifndef NO_CS4612 +#define ACSTS_WKUP 0x00000004 +#endif + +/* + * The following defines are for the flags in the AC97 output slot valid + * register. + */ +#define ACOSV_SLV3 0x00000001 +#define ACOSV_SLV4 0x00000002 +#define ACOSV_SLV5 0x00000004 +#define ACOSV_SLV6 0x00000008 +#define ACOSV_SLV7 0x00000010 +#define ACOSV_SLV8 0x00000020 +#define ACOSV_SLV9 0x00000040 +#define ACOSV_SLV10 0x00000080 +#define ACOSV_SLV11 0x00000100 +#define ACOSV_SLV12 0x00000200 + +/* + * The following defines are for the flags in the AC97 command address + * register. + */ +#define ACCAD_CI_MASK 0x0000007F +#define ACCAD_CI_SHIFT 0 + +/* + * The following defines are for the flags in the AC97 command data register. + */ +#define ACCDA_CD_MASK 0x0000FFFF +#define ACCDA_CD_SHIFT 0 + +/* + * The following defines are for the flags in the AC97 input slot valid + * register. + */ +#define ACISV_ISV3 0x00000001 +#define ACISV_ISV4 0x00000002 +#define ACISV_ISV5 0x00000004 +#define ACISV_ISV6 0x00000008 +#define ACISV_ISV7 0x00000010 +#define ACISV_ISV8 0x00000020 +#define ACISV_ISV9 0x00000040 +#define ACISV_ISV10 0x00000080 +#define ACISV_ISV11 0x00000100 +#define ACISV_ISV12 0x00000200 + +/* + * The following defines are for the flags in the AC97 status address + * register. + */ +#define ACSAD_SI_MASK 0x0000007F +#define ACSAD_SI_SHIFT 0 + +/* + * The following defines are for the flags in the AC97 status data register. + */ +#define ACSDA_SD_MASK 0x0000FFFF +#define ACSDA_SD_SHIFT 0 + +/* + * The following defines are for the flags in the joystick poll/trigger + * register. + */ +#define JSPT_CAX 0x00000001 +#define JSPT_CAY 0x00000002 +#define JSPT_CBX 0x00000004 +#define JSPT_CBY 0x00000008 +#define JSPT_BA1 0x00000010 +#define JSPT_BA2 0x00000020 +#define JSPT_BB1 0x00000040 +#define JSPT_BB2 0x00000080 + +/* + * The following defines are for the flags in the joystick control register. + */ +#define JSCTL_SP_MASK 0x00000003 +#define JSCTL_SP_SLOW 0x00000000 +#define JSCTL_SP_MEDIUM_SLOW 0x00000001 +#define JSCTL_SP_MEDIUM_FAST 0x00000002 +#define JSCTL_SP_FAST 0x00000003 +#define JSCTL_ARE 0x00000004 + +/* + * The following defines are for the flags in the joystick coordinate pair 1 + * readback register. + */ +#define JSC1_Y1V_MASK 0x0000FFFF +#define JSC1_X1V_MASK 0xFFFF0000 +#define JSC1_Y1V_SHIFT 0 +#define JSC1_X1V_SHIFT 16 + +/* + * The following defines are for the flags in the joystick coordinate pair 2 + * readback register. + */ +#define JSC2_Y2V_MASK 0x0000FFFF +#define JSC2_X2V_MASK 0xFFFF0000 +#define JSC2_Y2V_SHIFT 0 +#define JSC2_X2V_SHIFT 16 + +/* + * The following defines are for the flags in the MIDI control register. + */ +#define MIDCR_TXE 0x00000001 /* Enable transmitting. */ +#define MIDCR_RXE 0x00000002 /* Enable receiving. */ +#define MIDCR_RIE 0x00000004 /* Interrupt upon tx ready. */ +#define MIDCR_TIE 0x00000008 /* Interrupt upon rx ready. */ +#define MIDCR_MLB 0x00000010 /* Enable midi loopback. */ +#define MIDCR_MRST 0x00000020 /* Reset interface. */ + +/* + * The following defines are for the flags in the MIDI status register. + */ +#define MIDSR_TBF 0x00000001 /* Tx FIFO is full. */ +#define MIDSR_RBE 0x00000002 /* Rx FIFO is empty. */ + +/* + * The following defines are for the flags in the MIDI write port register. + */ +#define MIDWP_MWD_MASK 0x000000FF +#define MIDWP_MWD_SHIFT 0 + +/* + * The following defines are for the flags in the MIDI read port register. + */ +#define MIDRP_MRD_MASK 0x000000FF +#define MIDRP_MRD_SHIFT 0 + +/* + * The following defines are for the flags in the joystick GPIO register. + */ +#define JSIO_DAX 0x00000001 +#define JSIO_DAY 0x00000002 +#define JSIO_DBX 0x00000004 +#define JSIO_DBY 0x00000008 +#define JSIO_AXOE 0x00000010 +#define JSIO_AYOE 0x00000020 +#define JSIO_BXOE 0x00000040 +#define JSIO_BYOE 0x00000080 + +/* + * The following defines are for the flags in the master async/sync serial + * port enable register. + */ +#ifndef NO_CS4612 +#define ASER_MASTER_ME 0x00000001 +#endif + +/* + * The following defines are for the flags in the configuration interface + * register. + */ +#define CFGI_CLK 0x00000001 +#define CFGI_DOUT 0x00000002 +#define CFGI_DIN_EEN 0x00000004 +#define CFGI_EELD 0x00000008 + +/* + * The following defines are for the flags in the subsystem ID and vendor ID + * register. + */ +#define SSVID_VID_MASK 0x0000FFFF +#define SSVID_SID_MASK 0xFFFF0000 +#define SSVID_VID_SHIFT 0 +#define SSVID_SID_SHIFT 16 + +/* + * The following defines are for the flags in the GPIO pin interface register. + */ +#define GPIOR_VOLDN 0x00000001 +#define GPIOR_VOLUP 0x00000002 +#define GPIOR_SI2D 0x00000004 +#define GPIOR_SI2OE 0x00000008 + +/* + * The following defines are for the flags in the extended GPIO pin direction + * register. + */ +#ifndef NO_CS4612 +#define EGPIODR_GPOE0 0x00000001 +#define EGPIODR_GPOE1 0x00000002 +#define EGPIODR_GPOE2 0x00000004 +#define EGPIODR_GPOE3 0x00000008 +#define EGPIODR_GPOE4 0x00000010 +#define EGPIODR_GPOE5 0x00000020 +#define EGPIODR_GPOE6 0x00000040 +#define EGPIODR_GPOE7 0x00000080 +#define EGPIODR_GPOE8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO pin polarity/ + * type register. + */ +#ifndef NO_CS4612 +#define EGPIOPTR_GPPT0 0x00000001 +#define EGPIOPTR_GPPT1 0x00000002 +#define EGPIOPTR_GPPT2 0x00000004 +#define EGPIOPTR_GPPT3 0x00000008 +#define EGPIOPTR_GPPT4 0x00000010 +#define EGPIOPTR_GPPT5 0x00000020 +#define EGPIOPTR_GPPT6 0x00000040 +#define EGPIOPTR_GPPT7 0x00000080 +#define EGPIOPTR_GPPT8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO pin sticky + * register. + */ +#ifndef NO_CS4612 +#define EGPIOTR_GPS0 0x00000001 +#define EGPIOTR_GPS1 0x00000002 +#define EGPIOTR_GPS2 0x00000004 +#define EGPIOTR_GPS3 0x00000008 +#define EGPIOTR_GPS4 0x00000010 +#define EGPIOTR_GPS5 0x00000020 +#define EGPIOTR_GPS6 0x00000040 +#define EGPIOTR_GPS7 0x00000080 +#define EGPIOTR_GPS8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO ping wakeup + * register. + */ +#ifndef NO_CS4612 +#define EGPIOWR_GPW0 0x00000001 +#define EGPIOWR_GPW1 0x00000002 +#define EGPIOWR_GPW2 0x00000004 +#define EGPIOWR_GPW3 0x00000008 +#define EGPIOWR_GPW4 0x00000010 +#define EGPIOWR_GPW5 0x00000020 +#define EGPIOWR_GPW6 0x00000040 +#define EGPIOWR_GPW7 0x00000080 +#define EGPIOWR_GPW8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO pin status + * register. + */ +#ifndef NO_CS4612 +#define EGPIOSR_GPS0 0x00000001 +#define EGPIOSR_GPS1 0x00000002 +#define EGPIOSR_GPS2 0x00000004 +#define EGPIOSR_GPS3 0x00000008 +#define EGPIOSR_GPS4 0x00000010 +#define EGPIOSR_GPS5 0x00000020 +#define EGPIOSR_GPS6 0x00000040 +#define EGPIOSR_GPS7 0x00000080 +#define EGPIOSR_GPS8 0x00000100 +#endif + +/* + * The following defines are for the flags in the serial port 6 configuration + * register. + */ +#ifndef NO_CS4612 +#define SERC6_ASDO2EN 0x00000001 +#endif + +/* + * The following defines are for the flags in the serial port 7 configuration + * register. + */ +#ifndef NO_CS4612 +#define SERC7_ASDI2EN 0x00000001 +#define SERC7_POSILB 0x00000002 +#define SERC7_SIPOLB 0x00000004 +#define SERC7_SOSILB 0x00000008 +#define SERC7_SISOLB 0x00000010 +#endif + +/* + * The following defines are for the flags in the serial port AC link + * configuration register. + */ +#ifndef NO_CS4612 +#define SERACC_CODEC_TYPE_MASK 0x00000001 +#define SERACC_CODEC_TYPE_1_03 0x00000000 +#define SERACC_CODEC_TYPE_2_0 0x00000001 +#define SERACC_TWO_CODECS 0x00000002 +#define SERACC_MDM 0x00000004 +#define SERACC_HSP 0x00000008 +#endif + +/* + * The following defines are for the flags in the AC97 control register 2. + */ +#ifndef NO_CS4612 +#define ACCTL2_RSTN 0x00000001 +#define ACCTL2_ESYN 0x00000002 +#define ACCTL2_VFRM 0x00000004 +#define ACCTL2_DCV 0x00000008 +#define ACCTL2_CRW 0x00000010 +#define ACCTL2_ASYN 0x00000020 +#endif + +/* + * The following defines are for the flags in the AC97 status register 2. + */ +#ifndef NO_CS4612 +#define ACSTS2_CRDY 0x00000001 +#define ACSTS2_VSTS 0x00000002 +#endif + +/* + * The following defines are for the flags in the AC97 output slot valid + * register 2. + */ +#ifndef NO_CS4612 +#define ACOSV2_SLV3 0x00000001 +#define ACOSV2_SLV4 0x00000002 +#define ACOSV2_SLV5 0x00000004 +#define ACOSV2_SLV6 0x00000008 +#define ACOSV2_SLV7 0x00000010 +#define ACOSV2_SLV8 0x00000020 +#define ACOSV2_SLV9 0x00000040 +#define ACOSV2_SLV10 0x00000080 +#define ACOSV2_SLV11 0x00000100 +#define ACOSV2_SLV12 0x00000200 +#endif + +/* + * The following defines are for the flags in the AC97 command address + * register 2. + */ +#ifndef NO_CS4612 +#define ACCAD2_CI_MASK 0x0000007F +#define ACCAD2_CI_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the AC97 command data register + * 2. + */ +#ifndef NO_CS4612 +#define ACCDA2_CD_MASK 0x0000FFFF +#define ACCDA2_CD_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the AC97 input slot valid + * register 2. + */ +#ifndef NO_CS4612 +#define ACISV2_ISV3 0x00000001 +#define ACISV2_ISV4 0x00000002 +#define ACISV2_ISV5 0x00000004 +#define ACISV2_ISV6 0x00000008 +#define ACISV2_ISV7 0x00000010 +#define ACISV2_ISV8 0x00000020 +#define ACISV2_ISV9 0x00000040 +#define ACISV2_ISV10 0x00000080 +#define ACISV2_ISV11 0x00000100 +#define ACISV2_ISV12 0x00000200 +#endif + +/* + * The following defines are for the flags in the AC97 status address + * register 2. + */ +#ifndef NO_CS4612 +#define ACSAD2_SI_MASK 0x0000007F +#define ACSAD2_SI_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the AC97 status data register 2. + */ +#ifndef NO_CS4612 +#define ACSDA2_SD_MASK 0x0000FFFF +#define ACSDA2_SD_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the I/O trap address and control + * registers (all 12). + */ +#ifndef NO_CS4612 +#define IOTAC_SA_MASK 0x0000FFFF +#define IOTAC_MSK_MASK 0x000F0000 +#define IOTAC_IODC_MASK 0x06000000 +#define IOTAC_IODC_16_BIT 0x00000000 +#define IOTAC_IODC_10_BIT 0x02000000 +#define IOTAC_IODC_12_BIT 0x04000000 +#define IOTAC_WSPI 0x08000000 +#define IOTAC_RSPI 0x10000000 +#define IOTAC_WSE 0x20000000 +#define IOTAC_WE 0x40000000 +#define IOTAC_RE 0x80000000 +#define IOTAC_SA_SHIFT 0 +#define IOTAC_MSK_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the I/O trap fast read registers + * (all 8). + */ +#ifndef NO_CS4612 +#define IOTFR_D_MASK 0x0000FFFF +#define IOTFR_A_MASK 0x000F0000 +#define IOTFR_R_MASK 0x0F000000 +#define IOTFR_ALL 0x40000000 +#define IOTFR_VL 0x80000000 +#define IOTFR_D_SHIFT 0 +#define IOTFR_A_SHIFT 16 +#define IOTFR_R_SHIFT 24 +#endif + +/* + * The following defines are for the flags in the I/O trap FIFO register. + */ +#ifndef NO_CS4612 +#define IOTFIFO_BA_MASK 0x00003FFF +#define IOTFIFO_S_MASK 0x00FF0000 +#define IOTFIFO_OF 0x40000000 +#define IOTFIFO_SPIOF 0x80000000 +#define IOTFIFO_BA_SHIFT 0 +#define IOTFIFO_S_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the I/O trap retry read data + * register. + */ +#ifndef NO_CS4612 +#define IOTRRD_D_MASK 0x0000FFFF +#define IOTRRD_RDV 0x80000000 +#define IOTRRD_D_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the I/O trap FIFO pointer + * register. + */ +#ifndef NO_CS4612 +#define IOTFP_CA_MASK 0x00003FFF +#define IOTFP_PA_MASK 0x3FFF0000 +#define IOTFP_CA_SHIFT 0 +#define IOTFP_PA_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the I/O trap control register. + */ +#ifndef NO_CS4612 +#define IOTCR_ITD 0x00000001 +#define IOTCR_HRV 0x00000002 +#define IOTCR_SRV 0x00000004 +#define IOTCR_DTI 0x00000008 +#define IOTCR_DFI 0x00000010 +#define IOTCR_DDP 0x00000020 +#define IOTCR_JTE 0x00000040 +#define IOTCR_PPE 0x00000080 +#endif + +/* + * The following defines are for the flags in the direct PCI data register. + */ +#ifndef NO_CS4612 +#define DPCID_D_MASK 0xFFFFFFFF +#define DPCID_D_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the direct PCI address register. + */ +#ifndef NO_CS4612 +#define DPCIA_A_MASK 0xFFFFFFFF +#define DPCIA_A_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the direct PCI command register. + */ +#ifndef NO_CS4612 +#define DPCIC_C_MASK 0x0000000F +#define DPCIC_C_IOREAD 0x00000002 +#define DPCIC_C_IOWRITE 0x00000003 +#define DPCIC_BE_MASK 0x000000F0 +#endif + +/* + * The following defines are for the flags in the PC/PCI request register. + */ +#ifndef NO_CS4612 +#define PCPCIR_RDC_MASK 0x00000007 +#define PCPCIR_C_MASK 0x00007000 +#define PCPCIR_REQ 0x00008000 +#define PCPCIR_RDC_SHIFT 0 +#define PCPCIR_C_SHIFT 12 +#endif + +/* + * The following defines are for the flags in the PC/PCI grant register. + */ +#ifndef NO_CS4612 +#define PCPCIG_GDC_MASK 0x00000007 +#define PCPCIG_VL 0x00008000 +#define PCPCIG_GDC_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the PC/PCI master enable + * register. + */ +#ifndef NO_CS4612 +#define PCPCIEN_EN 0x00000001 +#endif + +/* + * The following defines are for the flags in the extended PCI power + * management control register. + */ +#ifndef NO_CS4612 +#define EPCIPMC_GWU 0x00000001 +#define EPCIPMC_FSPC 0x00000002 +#endif + +/* + * The following defines are for the flags in the SP control register. + */ +#define SPCR_RUN 0x00000001 +#define SPCR_STPFR 0x00000002 +#define SPCR_RUNFR 0x00000004 +#define SPCR_TICK 0x00000008 +#define SPCR_DRQEN 0x00000020 +#define SPCR_RSTSP 0x00000040 +#define SPCR_OREN 0x00000080 +#ifndef NO_CS4612 +#define SPCR_PCIINT 0x00000100 +#define SPCR_OINTD 0x00000200 +#define SPCR_CRE 0x00008000 +#endif + +/* + * The following defines are for the flags in the debug index register. + */ +#define DREG_REGID_MASK 0x0000007F +#define DREG_DEBUG 0x00000080 +#define DREG_RGBK_MASK 0x00000700 +#define DREG_TRAP 0x00000800 +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_TRAPX 0x00001000 +#endif +#endif +#define DREG_REGID_SHIFT 0 +#define DREG_RGBK_SHIFT 8 +#define DREG_RGBK_REGID_MASK 0x0000077F +#define DREG_REGID_R0 0x00000010 +#define DREG_REGID_R1 0x00000011 +#define DREG_REGID_R2 0x00000012 +#define DREG_REGID_R3 0x00000013 +#define DREG_REGID_R4 0x00000014 +#define DREG_REGID_R5 0x00000015 +#define DREG_REGID_R6 0x00000016 +#define DREG_REGID_R7 0x00000017 +#define DREG_REGID_R8 0x00000018 +#define DREG_REGID_R9 0x00000019 +#define DREG_REGID_RA 0x0000001A +#define DREG_REGID_RB 0x0000001B +#define DREG_REGID_RC 0x0000001C +#define DREG_REGID_RD 0x0000001D +#define DREG_REGID_RE 0x0000001E +#define DREG_REGID_RF 0x0000001F +#define DREG_REGID_RA_BUS_LOW 0x00000020 +#define DREG_REGID_RA_BUS_HIGH 0x00000038 +#define DREG_REGID_YBUS_LOW 0x00000050 +#define DREG_REGID_YBUS_HIGH 0x00000058 +#define DREG_REGID_TRAP_0 0x00000100 +#define DREG_REGID_TRAP_1 0x00000101 +#define DREG_REGID_TRAP_2 0x00000102 +#define DREG_REGID_TRAP_3 0x00000103 +#define DREG_REGID_TRAP_4 0x00000104 +#define DREG_REGID_TRAP_5 0x00000105 +#define DREG_REGID_TRAP_6 0x00000106 +#define DREG_REGID_TRAP_7 0x00000107 +#define DREG_REGID_INDIRECT_ADDRESS 0x0000010E +#define DREG_REGID_TOP_OF_STACK 0x0000010F +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_REGID_TRAP_8 0x00000110 +#define DREG_REGID_TRAP_9 0x00000111 +#define DREG_REGID_TRAP_10 0x00000112 +#define DREG_REGID_TRAP_11 0x00000113 +#define DREG_REGID_TRAP_12 0x00000114 +#define DREG_REGID_TRAP_13 0x00000115 +#define DREG_REGID_TRAP_14 0x00000116 +#define DREG_REGID_TRAP_15 0x00000117 +#define DREG_REGID_TRAP_16 0x00000118 +#define DREG_REGID_TRAP_17 0x00000119 +#define DREG_REGID_TRAP_18 0x0000011A +#define DREG_REGID_TRAP_19 0x0000011B +#define DREG_REGID_TRAP_20 0x0000011C +#define DREG_REGID_TRAP_21 0x0000011D +#define DREG_REGID_TRAP_22 0x0000011E +#define DREG_REGID_TRAP_23 0x0000011F +#endif +#endif +#define DREG_REGID_RSA0_LOW 0x00000200 +#define DREG_REGID_RSA0_HIGH 0x00000201 +#define DREG_REGID_RSA1_LOW 0x00000202 +#define DREG_REGID_RSA1_HIGH 0x00000203 +#define DREG_REGID_RSA2 0x00000204 +#define DREG_REGID_RSA3 0x00000205 +#define DREG_REGID_RSI0_LOW 0x00000206 +#define DREG_REGID_RSI0_HIGH 0x00000207 +#define DREG_REGID_RSI1 0x00000208 +#define DREG_REGID_RSI2 0x00000209 +#define DREG_REGID_SAGUSTATUS 0x0000020A +#define DREG_REGID_RSCONFIG01_LOW 0x0000020B +#define DREG_REGID_RSCONFIG01_HIGH 0x0000020C +#define DREG_REGID_RSCONFIG23_LOW 0x0000020D +#define DREG_REGID_RSCONFIG23_HIGH 0x0000020E +#define DREG_REGID_RSDMA01E 0x0000020F +#define DREG_REGID_RSDMA23E 0x00000210 +#define DREG_REGID_RSD0_LOW 0x00000211 +#define DREG_REGID_RSD0_HIGH 0x00000212 +#define DREG_REGID_RSD1_LOW 0x00000213 +#define DREG_REGID_RSD1_HIGH 0x00000214 +#define DREG_REGID_RSD2_LOW 0x00000215 +#define DREG_REGID_RSD2_HIGH 0x00000216 +#define DREG_REGID_RSD3_LOW 0x00000217 +#define DREG_REGID_RSD3_HIGH 0x00000218 +#define DREG_REGID_SRAR_HIGH 0x0000021A +#define DREG_REGID_SRAR_LOW 0x0000021B +#define DREG_REGID_DMA_STATE 0x0000021C +#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021D +#define DREG_REGID_NEXT_DMA_STREAM 0x0000021E +#define DREG_REGID_CPU_STATUS 0x00000300 +#define DREG_REGID_MAC_MODE 0x00000301 +#define DREG_REGID_STACK_AND_REPEAT 0x00000302 +#define DREG_REGID_INDEX0 0x00000304 +#define DREG_REGID_INDEX1 0x00000305 +#define DREG_REGID_DMA_STATE_0_3 0x00000400 +#define DREG_REGID_DMA_STATE_4_7 0x00000404 +#define DREG_REGID_DMA_STATE_8_11 0x00000408 +#define DREG_REGID_DMA_STATE_12_15 0x0000040C +#define DREG_REGID_DMA_STATE_16_19 0x00000410 +#define DREG_REGID_DMA_STATE_20_23 0x00000414 +#define DREG_REGID_DMA_STATE_24_27 0x00000418 +#define DREG_REGID_DMA_STATE_28_31 0x0000041C +#define DREG_REGID_DMA_STATE_32_35 0x00000420 +#define DREG_REGID_DMA_STATE_36_39 0x00000424 +#define DREG_REGID_DMA_STATE_40_43 0x00000428 +#define DREG_REGID_DMA_STATE_44_47 0x0000042C +#define DREG_REGID_DMA_STATE_48_51 0x00000430 +#define DREG_REGID_DMA_STATE_52_55 0x00000434 +#define DREG_REGID_DMA_STATE_56_59 0x00000438 +#define DREG_REGID_DMA_STATE_60_63 0x0000043C +#define DREG_REGID_DMA_STATE_64_67 0x00000440 +#define DREG_REGID_DMA_STATE_68_71 0x00000444 +#define DREG_REGID_DMA_STATE_72_75 0x00000448 +#define DREG_REGID_DMA_STATE_76_79 0x0000044C +#define DREG_REGID_DMA_STATE_80_83 0x00000450 +#define DREG_REGID_DMA_STATE_84_87 0x00000454 +#define DREG_REGID_DMA_STATE_88_91 0x00000458 +#define DREG_REGID_DMA_STATE_92_95 0x0000045C +#define DREG_REGID_TRAP_SELECT 0x00000500 +#define DREG_REGID_TRAP_WRITE_0 0x00000500 +#define DREG_REGID_TRAP_WRITE_1 0x00000501 +#define DREG_REGID_TRAP_WRITE_2 0x00000502 +#define DREG_REGID_TRAP_WRITE_3 0x00000503 +#define DREG_REGID_TRAP_WRITE_4 0x00000504 +#define DREG_REGID_TRAP_WRITE_5 0x00000505 +#define DREG_REGID_TRAP_WRITE_6 0x00000506 +#define DREG_REGID_TRAP_WRITE_7 0x00000507 +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_REGID_TRAP_WRITE_8 0x00000510 +#define DREG_REGID_TRAP_WRITE_9 0x00000511 +#define DREG_REGID_TRAP_WRITE_10 0x00000512 +#define DREG_REGID_TRAP_WRITE_11 0x00000513 +#define DREG_REGID_TRAP_WRITE_12 0x00000514 +#define DREG_REGID_TRAP_WRITE_13 0x00000515 +#define DREG_REGID_TRAP_WRITE_14 0x00000516 +#define DREG_REGID_TRAP_WRITE_15 0x00000517 +#define DREG_REGID_TRAP_WRITE_16 0x00000518 +#define DREG_REGID_TRAP_WRITE_17 0x00000519 +#define DREG_REGID_TRAP_WRITE_18 0x0000051A +#define DREG_REGID_TRAP_WRITE_19 0x0000051B +#define DREG_REGID_TRAP_WRITE_20 0x0000051C +#define DREG_REGID_TRAP_WRITE_21 0x0000051D +#define DREG_REGID_TRAP_WRITE_22 0x0000051E +#define DREG_REGID_TRAP_WRITE_23 0x0000051F +#endif +#endif +#define DREG_REGID_MAC0_ACC0_LOW 0x00000600 +#define DREG_REGID_MAC0_ACC1_LOW 0x00000601 +#define DREG_REGID_MAC0_ACC2_LOW 0x00000602 +#define DREG_REGID_MAC0_ACC3_LOW 0x00000603 +#define DREG_REGID_MAC1_ACC0_LOW 0x00000604 +#define DREG_REGID_MAC1_ACC1_LOW 0x00000605 +#define DREG_REGID_MAC1_ACC2_LOW 0x00000606 +#define DREG_REGID_MAC1_ACC3_LOW 0x00000607 +#define DREG_REGID_MAC0_ACC0_MID 0x00000608 +#define DREG_REGID_MAC0_ACC1_MID 0x00000609 +#define DREG_REGID_MAC0_ACC2_MID 0x0000060A +#define DREG_REGID_MAC0_ACC3_MID 0x0000060B +#define DREG_REGID_MAC1_ACC0_MID 0x0000060C +#define DREG_REGID_MAC1_ACC1_MID 0x0000060D +#define DREG_REGID_MAC1_ACC2_MID 0x0000060E +#define DREG_REGID_MAC1_ACC3_MID 0x0000060F +#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610 +#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611 +#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612 +#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613 +#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614 +#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615 +#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616 +#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617 +#define DREG_REGID_RSHOUT_LOW 0x00000620 +#define DREG_REGID_RSHOUT_MID 0x00000628 +#define DREG_REGID_RSHOUT_HIGH 0x00000630 + +/* + * The following defines are for the flags in the DMA stream requestor write + */ +#define DSRWP_DSR_MASK 0x0000000F +#define DSRWP_DSR_BG_RQ 0x00000001 +#define DSRWP_DSR_PRIORITY_MASK 0x00000006 +#define DSRWP_DSR_PRIORITY_0 0x00000000 +#define DSRWP_DSR_PRIORITY_1 0x00000002 +#define DSRWP_DSR_PRIORITY_2 0x00000004 +#define DSRWP_DSR_PRIORITY_3 0x00000006 +#define DSRWP_DSR_RQ_PENDING 0x00000008 + +/* + * The following defines are for the flags in the trap write port register. + */ +#define TWPR_TW_MASK 0x0000FFFF +#define TWPR_TW_SHIFT 0 + +/* + * The following defines are for the flags in the stack pointer write + * register. + */ +#define SPWR_STKP_MASK 0x0000000F +#define SPWR_STKP_SHIFT 0 + +/* + * The following defines are for the flags in the SP interrupt register. + */ +#define SPIR_FRI 0x00000001 +#define SPIR_DOI 0x00000002 +#define SPIR_GPI2 0x00000004 +#define SPIR_GPI3 0x00000008 +#define SPIR_IP0 0x00000010 +#define SPIR_IP1 0x00000020 +#define SPIR_IP2 0x00000040 +#define SPIR_IP3 0x00000080 + +/* + * The following defines are for the flags in the functional group 1 register. + */ +#define FGR1_F1S_MASK 0x0000FFFF +#define FGR1_F1S_SHIFT 0 + +/* + * The following defines are for the flags in the SP clock status register. + */ +#define SPCS_FRI 0x00000001 +#define SPCS_DOI 0x00000002 +#define SPCS_GPI2 0x00000004 +#define SPCS_GPI3 0x00000008 +#define SPCS_IP0 0x00000010 +#define SPCS_IP1 0x00000020 +#define SPCS_IP2 0x00000040 +#define SPCS_IP3 0x00000080 +#define SPCS_SPRUN 0x00000100 +#define SPCS_SLEEP 0x00000200 +#define SPCS_FG 0x00000400 +#define SPCS_ORUN 0x00000800 +#define SPCS_IRQ 0x00001000 +#define SPCS_FGN_MASK 0x0000E000 +#define SPCS_FGN_SHIFT 13 + +/* + * The following defines are for the flags in the SP DMA requestor status + * register. + */ +#define SDSR_DCS_MASK 0x000000FF +#define SDSR_DCS_SHIFT 0 +#define SDSR_DCS_NONE 0x00000007 + +/* + * The following defines are for the flags in the frame timer register. + */ +#define FRMT_FTV_MASK 0x0000FFFF +#define FRMT_FTV_SHIFT 0 + +/* + * The following defines are for the flags in the frame timer current count + * register. + */ +#define FRCC_FCC_MASK 0x0000FFFF +#define FRCC_FCC_SHIFT 0 + +/* + * The following defines are for the flags in the frame timer save count + * register. + */ +#define FRSC_FCS_MASK 0x0000FFFF +#define FRSC_FCS_SHIFT 0 + +/* + * The following define the various flags stored in the scatter/gather + * descriptors. + */ +#define DMA_SG_NEXT_ENTRY_MASK 0x00000FF8 +#define DMA_SG_SAMPLE_END_MASK 0x0FFF0000 +#define DMA_SG_SAMPLE_END_FLAG 0x10000000 +#define DMA_SG_LOOP_END_FLAG 0x20000000 +#define DMA_SG_SIGNAL_END_FLAG 0x40000000 +#define DMA_SG_SIGNAL_PAGE_FLAG 0x80000000 +#define DMA_SG_NEXT_ENTRY_SHIFT 3 +#define DMA_SG_SAMPLE_END_SHIFT 16 + +/* + * The following define the offsets of the fields within the on-chip generic + * DMA requestor. + */ +#define DMA_RQ_CONTROL1 0x00000000 +#define DMA_RQ_CONTROL2 0x00000004 +#define DMA_RQ_SOURCE_ADDR 0x00000008 +#define DMA_RQ_DESTINATION_ADDR 0x0000000C +#define DMA_RQ_NEXT_PAGE_ADDR 0x00000010 +#define DMA_RQ_NEXT_PAGE_SGDESC 0x00000014 +#define DMA_RQ_LOOP_START_ADDR 0x00000018 +#define DMA_RQ_POST_LOOP_ADDR 0x0000001C +#define DMA_RQ_PAGE_MAP_ADDR 0x00000020 + +/* + * The following defines are for the flags in the first control word of the + * on-chip generic DMA requestor. + */ +#define DMA_RQ_C1_COUNT_MASK 0x000003FF +#define DMA_RQ_C1_DESTINATION_SCATTER 0x00001000 +#define DMA_RQ_C1_SOURCE_GATHER 0x00002000 +#define DMA_RQ_C1_DONE_FLAG 0x00004000 +#define DMA_RQ_C1_OPTIMIZE_STATE 0x00008000 +#define DMA_RQ_C1_SAMPLE_END_STATE_MASK 0x00030000 +#define DMA_RQ_C1_FULL_PAGE 0x00000000 +#define DMA_RQ_C1_BEFORE_SAMPLE_END 0x00010000 +#define DMA_RQ_C1_PAGE_MAP_ERROR 0x00020000 +#define DMA_RQ_C1_AT_SAMPLE_END 0x00030000 +#define DMA_RQ_C1_LOOP_END_STATE_MASK 0x000C0000 +#define DMA_RQ_C1_NOT_LOOP_END 0x00000000 +#define DMA_RQ_C1_BEFORE_LOOP_END 0x00040000 +#define DMA_RQ_C1_2PAGE_LOOP_BEGIN 0x00080000 +#define DMA_RQ_C1_LOOP_BEGIN 0x000C0000 +#define DMA_RQ_C1_PAGE_MAP_MASK 0x00300000 +#define DMA_RQ_C1_PM_NONE_PENDING 0x00000000 +#define DMA_RQ_C1_PM_NEXT_PENDING 0x00100000 +#define DMA_RQ_C1_PM_RESERVED 0x00200000 +#define DMA_RQ_C1_PM_LOOP_NEXT_PENDING 0x00300000 +#define DMA_RQ_C1_WRITEBACK_DEST_FLAG 0x00400000 +#define DMA_RQ_C1_WRITEBACK_SRC_FLAG 0x00800000 +#define DMA_RQ_C1_DEST_SIZE_MASK 0x07000000 +#define DMA_RQ_C1_DEST_LINEAR 0x00000000 +#define DMA_RQ_C1_DEST_MOD16 0x01000000 +#define DMA_RQ_C1_DEST_MOD32 0x02000000 +#define DMA_RQ_C1_DEST_MOD64 0x03000000 +#define DMA_RQ_C1_DEST_MOD128 0x04000000 +#define DMA_RQ_C1_DEST_MOD256 0x05000000 +#define DMA_RQ_C1_DEST_MOD512 0x06000000 +#define DMA_RQ_C1_DEST_MOD1024 0x07000000 +#define DMA_RQ_C1_DEST_ON_HOST 0x08000000 +#define DMA_RQ_C1_SOURCE_SIZE_MASK 0x70000000 +#define DMA_RQ_C1_SOURCE_LINEAR 0x00000000 +#define DMA_RQ_C1_SOURCE_MOD16 0x10000000 +#define DMA_RQ_C1_SOURCE_MOD32 0x20000000 +#define DMA_RQ_C1_SOURCE_MOD64 0x30000000 +#define DMA_RQ_C1_SOURCE_MOD128 0x40000000 +#define DMA_RQ_C1_SOURCE_MOD256 0x50000000 +#define DMA_RQ_C1_SOURCE_MOD512 0x60000000 +#define DMA_RQ_C1_SOURCE_MOD1024 0x70000000 +#define DMA_RQ_C1_SOURCE_ON_HOST 0x80000000 +#define DMA_RQ_C1_COUNT_SHIFT 0 + +/* + * The following defines are for the flags in the second control word of the + * on-chip generic DMA requestor. + */ +#define DMA_RQ_C2_VIRTUAL_CHANNEL_MASK 0x0000003F +#define DMA_RQ_C2_VIRTUAL_SIGNAL_MASK 0x00000300 +#define DMA_RQ_C2_NO_VIRTUAL_SIGNAL 0x00000000 +#define DMA_RQ_C2_SIGNAL_EVERY_DMA 0x00000100 +#define DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG 0x00000200 +#define DMA_RQ_C2_SIGNAL_DEST_PINGPONG 0x00000300 +#define DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000 +#define DMA_RQ_C2_AC_NONE 0x00000000 +#define DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000 +#define DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000 +#define DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000 +#define DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000 +#define DMA_RQ_C2_LOOP_END_MASK 0x0FFF0000 +#define DMA_RQ_C2_LOOP_MASK 0x30000000 +#define DMA_RQ_C2_NO_LOOP 0x00000000 +#define DMA_RQ_C2_ONE_PAGE_LOOP 0x10000000 +#define DMA_RQ_C2_TWO_PAGE_LOOP 0x20000000 +#define DMA_RQ_C2_MULTI_PAGE_LOOP 0x30000000 +#define DMA_RQ_C2_SIGNAL_LOOP_BACK 0x40000000 +#define DMA_RQ_C2_SIGNAL_POST_BEGIN_PAGE 0x80000000 +#define DMA_RQ_C2_VIRTUAL_CHANNEL_SHIFT 0 +#define DMA_RQ_C2_LOOP_END_SHIFT 16 + +/* + * The following defines are for the flags in the source and destination words + * of the on-chip generic DMA requestor. + */ +#define DMA_RQ_SD_ADDRESS_MASK 0x0000FFFF +#define DMA_RQ_SD_MEMORY_ID_MASK 0x000F0000 +#define DMA_RQ_SD_SP_PARAM_ADDR 0x00000000 +#define DMA_RQ_SD_SP_SAMPLE_ADDR 0x00010000 +#define DMA_RQ_SD_SP_PROGRAM_ADDR 0x00020000 +#define DMA_RQ_SD_SP_DEBUG_ADDR 0x00030000 +#define DMA_RQ_SD_OMNIMEM_ADDR 0x000E0000 +#define DMA_RQ_SD_END_FLAG 0x40000000 +#define DMA_RQ_SD_ERROR_FLAG 0x80000000 +#define DMA_RQ_SD_ADDRESS_SHIFT 0 + +/* + * The following defines are for the flags in the page map address word of the + * on-chip generic DMA requestor. + */ +#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_MASK 0x00000FF8 +#define DMA_RQ_PMA_PAGE_TABLE_MASK 0xFFFFF000 +#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_SHIFT 3 +#define DMA_RQ_PMA_PAGE_TABLE_SHIFT 12 + +#define BA1_VARIDEC_BUF_1 0x000 + +#define BA1_PDTC 0x0c0 /* BA1_PLAY_DMA_TRANSACTION_COUNT_REG */ +#define BA1_PFIE 0x0c4 /* BA1_PLAY_FORMAT_&_INTERRUPT_ENABLE_REG */ +#define BA1_PBA 0x0c8 /* BA1_PLAY_BUFFER_ADDRESS */ +#define BA1_PVOL 0x0f8 /* BA1_PLAY_VOLUME_REG */ +#define BA1_PSRC 0x288 /* BA1_PLAY_SAMPLE_RATE_CORRECTION_REG */ +#define BA1_PCTL 0x2a4 /* BA1_PLAY_CONTROL_REG */ +#define BA1_PPI 0x2b4 /* BA1_PLAY_PHASE_INCREMENT_REG */ + +#define BA1_CCTL 0x064 /* BA1_CAPTURE_CONTROL_REG */ +#define BA1_CIE 0x104 /* BA1_CAPTURE_INTERRUPT_ENABLE_REG */ +#define BA1_CBA 0x10c /* BA1_CAPTURE_BUFFER_ADDRESS */ +#define BA1_CSRC 0x2c8 /* BA1_CAPTURE_SAMPLE_RATE_CORRECTION_REG */ +#define BA1_CCI 0x2d8 /* BA1_CAPTURE_COEFFICIENT_INCREMENT_REG */ +#define BA1_CD 0x2e0 /* BA1_CAPTURE_DELAY_REG */ +#define BA1_CPI 0x2f4 /* BA1_CAPTURE_PHASE_INCREMENT_REG */ +#define BA1_CVOL 0x2f8 /* BA1_CAPTURE_VOLUME_REG */ + +#define BA1_CFG1 0x134 /* BA1_CAPTURE_FRAME_GROUP_1_REG */ +#define BA1_CFG2 0x138 /* BA1_CAPTURE_FRAME_GROUP_2_REG */ +#define BA1_CCST 0x13c /* BA1_CAPTURE_CONSTANT_REG */ +#define BA1_CSPB 0x340 /* BA1_CAPTURE_SPB_ADDRESS */ + +/* + * + */ + +#define CS461X_MODE_OUTPUT (1<<0) /* MIDI UART - output */ +#define CS461X_MODE_INPUT (1<<1) /* MIDI UART - input */ + +#endif /* __CS461X_H */ diff --git a/drivers/sound/cs461x_image.h b/drivers/sound/cs461x_image.h new file mode 100644 index 000000000..6826aa9a6 --- /dev/null +++ b/drivers/sound/cs461x_image.h @@ -0,0 +1,3459 @@ +struct BA1struct BA1Struct = {
+{{ 0x00000000, 0x00003000 },{ 0x00010000, 0x00003800 },{ 0x00020000, 0x00007000 }},
+{0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000163,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00200040,0x00008010,0x00000000,
+0x00000000,0x80000001,0x00000001,0x00060000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00900080,0x00000173,0x00000000,
+0x00000000,0x00000010,0x00800000,0x00900000,
+0xf2c0000f,0x00000200,0x00000000,0x00010600,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000163,0x330300c2,
+0x06000000,0x00000000,0x80008000,0x80008000,
+0x3fc0000f,0x00000301,0x00010400,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00b00000,0x00d0806d,0x330480c3,
+0x04800000,0x00000001,0x00800001,0x0000ffff,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x066a0600,0x06350070,0x0000929d,0x929d929d,
+0x00000000,0x0000735a,0x00000600,0x00000000,
+0x929d735a,0x8734abfe,0x00010000,0x735a735a,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x0000804f,0x000000c3,
+0x05000000,0x00a00010,0x00000000,0x80008000,
+0x00000000,0x00000000,0x00000700,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000080,0x00a00000,0x0000809a,0x000000c2,
+0x07400000,0x00000000,0x80008000,0xffffffff,
+0x00c80028,0x00005555,0x00000000,0x000107a0,
+0x00c80028,0x000000c2,0x06800000,0x00000000,
+0x06e00080,0x00300000,0x000080bb,0x000000c9,
+0x07a00000,0x04000000,0x80008000,0xffffffff,
+0x00c80028,0x00005555,0x00000000,0x00000780,
+0x00c80028,0x000000c5,0xff800000,0x00000000,
+0x00640080,0x00c00000,0x00008197,0x000000c9,
+0x07800000,0x04000000,0x80008000,0xffffffff,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x0000805e,0x000000c1,
+0x00000000,0x00800000,0x80008000,0x80008000,
+0x00020000,0x0000ffff,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x929d0600,0x929d929d,0x929d929d,0x929d0000,
+0x929d929d,0x929d929d,0x929d929d,0x929d929d,
+0x929d929d,0x00100635,0x060b013f,0x00000004,
+0x00000001,0x007a0002,0x00000000,0x066e0610,
+0x0105929d,0x929d929d,0x929d929d,0x929d929d,
+0x929d929d,0xa431ac75,0x0001735a,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0x735a0051,
+0x00000000,0x929d929d,0x929d929d,0x929d929d,
+0x929d929d,0x929d929d,0x929d929d,0x929d929d,
+0x929d929d,0x929d929d,0x00000000,0x06400136,
+0x0000270f,0x00010000,0x007a0000,0x00000000,
+0x068e0645,0x0105929d,0x929d929d,0x929d929d,
+0x929d929d,0x929d929d,0xa431ac75,0x0001735a,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+0x735a0100,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00010004,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00001705,0x00001400,0x000a411e,0x00001003,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00009705,0x00001400,0x000a411e,0x00001003,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00011705,0x00001400,0x000a411e,0x00001003,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00019705,0x00001400,0x000a411e,0x00001003,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00021705,0x00001400,0x000a411e,0x00001003,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00029705,0x00001400,0x000a411e,0x00001003,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00031705,0x00001400,0x000a411e,0x00001003,
+0x00040730,0x00001002,0x000f619e,0x00001003,
+0x00039705,0x00001400,0x000a411e,0x00001003,
+0x000fe19e,0x00001003,0x0009c730,0x00001003,
+0x0008e19c,0x00001003,0x000083c1,0x00093040,
+0x00098730,0x00001002,0x000ee19e,0x00001003,
+0x00009705,0x00001400,0x000a211e,0x00001003,
+0x00098730,0x00001002,0x000ee19e,0x00001003,
+0x00011705,0x00001400,0x000a211e,0x00001003,
+0x00098730,0x00001002,0x000ee19e,0x00001003,
+0x00019705,0x00001400,0x000a211e,0x00001003,
+0x00098730,0x00001002,0x000ee19e,0x00001003,
+0x00021705,0x00001400,0x000a211e,0x00001003,
+0x00098730,0x00001002,0x000ee19e,0x00001003,
+0x00029705,0x00001400,0x000a211e,0x00001003,
+0x00098730,0x00001002,0x000ee19e,0x00001003,
+0x00031705,0x00001400,0x000a211e,0x00001003,
+0x00098730,0x00001002,0x000ee19e,0x00001003,
+0x00039705,0x00001400,0x000a211e,0x00001003,
+0x0000a730,0x00001008,0x000e2730,0x00001002,
+0x0000a731,0x00001002,0x0000a731,0x00001002,
+0x0000a731,0x00001002,0x0000a731,0x00001002,
+0x0000a731,0x00001002,0x0000a731,0x00001002,
+0x00000000,0x00000000,0x000f619c,0x00001003,
+0x0007f801,0x000c0000,0x00000037,0x00001000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000c0000,0x00000000,0x00000000,
+0x0000373c,0x00001000,0x00000000,0x00000000,
+0x000ee19c,0x00001003,0x0007f801,0x000c0000,
+0x00000037,0x00001000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x0000273c,0x00001000,
+0x00000033,0x00001000,0x000e679e,0x00001003,
+0x00007705,0x00001400,0x000ac71e,0x00001003,
+0x00087fc1,0x000c3be0,0x0007f801,0x000c0000,
+0x00000037,0x00001000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x0000a730,0x00001003,
+0x00000033,0x00001000,0x0007f801,0x000c0000,
+0x00000037,0x00001000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x000c0000,
+0x00000032,0x00001000,0x0000273d,0x00001000,
+0x0004a730,0x00001003,0x00000f41,0x00097140,
+0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
+0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
+0x00000000,0x00000000,0x0001bf05,0x0003fc40,
+0x00002725,0x000aa400,0x00013705,0x00093a00,
+0x0000002e,0x0009d6c0,0x00038630,0x00001004,
+0x0004ef0a,0x000eb785,0x0003fc8a,0x00000000,
+0x00000000,0x000c70e0,0x0007d182,0x0002c640,
+0x00000630,0x00001004,0x000799b8,0x0002c6c0,
+0x00031705,0x00092240,0x00039f05,0x000932c0,
+0x0003520a,0x00000000,0x00040731,0x0000100b,
+0x00010705,0x000b20c0,0x00000000,0x000eba44,
+0x00032108,0x000c60c4,0x00065208,0x000c2917,
+0x000406b0,0x00001007,0x00012f05,0x00036880,
+0x0002818e,0x000c0000,0x0004410a,0x00000000,
+0x00040630,0x00001007,0x00029705,0x000c0000,
+0x00000000,0x00000000,0x00003fc1,0x0003fc40,
+0x000037c1,0x00091b40,0x00003fc1,0x000911c0,
+0x000037c1,0x000957c0,0x00003fc1,0x000951c0,
+0x000037c1,0x00000000,0x00003fc1,0x000991c0,
+0x000037c1,0x00000000,0x00003fc1,0x0009d1c0,
+0x000037c1,0x00000000,0x0001ccc1,0x000915c0,
+0x0001c441,0x0009d800,0x0009cdc1,0x00091240,
+0x0001c541,0x00091d00,0x0009cfc1,0x00095240,
+0x0001c741,0x00095c80,0x000e8ca9,0x00099240,
+0x000e85ad,0x00095640,0x00069ca9,0x00099d80,
+0x000e952d,0x00099640,0x000eaca9,0x0009d6c0,
+0x000ea5ad,0x00091a40,0x0006bca9,0x0009de80,
+0x000eb52d,0x00095a40,0x000ecca9,0x00099ac0,
+0x000ec5ad,0x0009da40,0x000edca9,0x0009d300,
+0x000a6e0a,0x00001000,0x000ed52d,0x00091e40,
+0x000eeca9,0x00095ec0,0x000ee5ad,0x00099e40,
+0x0006fca9,0x00002500,0x000fb208,0x000c59a0,
+0x000ef52d,0x0009de40,0x00068ca9,0x000912c1,
+0x000683ad,0x00095241,0x00020f05,0x000991c1,
+0x00000000,0x00000000,0x00086f88,0x00001000,
+0x0009cf81,0x000b5340,0x0009c701,0x000b92c0,
+0x0009de81,0x000bd300,0x0009d601,0x000b1700,
+0x0001fd81,0x000b9d80,0x0009f501,0x000b57c0,
+0x000a0f81,0x000bd740,0x00020701,0x000b5c80,
+0x000a1681,0x000b97c0,0x00021601,0x00002500,
+0x000a0701,0x000b9b40,0x000a0f81,0x000b1bc0,
+0x00021681,0x00002d00,0x00020f81,0x000bd800,
+0x000a0701,0x000b5bc0,0x00021601,0x00003500,
+0x000a0f81,0x000b5f40,0x000a0701,0x000bdbc0,
+0x00021681,0x00003d00,0x00020f81,0x000b1d00,
+0x000a0701,0x000b1fc0,0x00021601,0x00020500,
+0x00020f81,0x000b1341,0x000a0701,0x000b9fc0,
+0x00021681,0x00020d00,0x00020f81,0x000bde80,
+0x000a0701,0x000bdfc0,0x00021601,0x00021500,
+0x00020f81,0x000b9341,0x00020701,0x000b53c1,
+0x00021681,0x00021d00,0x000a0f81,0x000d0380,
+0x0000b601,0x000b15c0,0x00007b01,0x00000000,
+0x00007b81,0x000bd1c0,0x00007b01,0x00000000,
+0x00007b81,0x000b91c0,0x00007b01,0x000b57c0,
+0x00007b81,0x000b51c0,0x00007b01,0x000b1b40,
+0x00007b81,0x000b11c0,0x00087b01,0x000c3dc0,
+0x0007e488,0x000d7e45,0x00000000,0x000d7a44,
+0x0007e48a,0x00000000,0x00011f05,0x00084080,
+0x00000000,0x00000000,0x00001705,0x000b3540,
+0x00008a01,0x000bf040,0x00007081,0x000bb5c0,
+0x00055488,0x00000000,0x0000d482,0x0003fc40,
+0x0003fc88,0x00000000,0x0001e401,0x000b3a00,
+0x0001ec81,0x000bd6c0,0x0004ef08,0x000eb784,
+0x000c86b0,0x00001007,0x00008281,0x000bb240,
+0x0000b801,0x000b7140,0x00007888,0x00000000,
+0x0000073c,0x00001000,0x0007f188,0x000c0000,
+0x00000000,0x00000000,0x00055288,0x000c555c,
+0x0005528a,0x000c0000,0x0009fa88,0x000c5d00,
+0x0000fa88,0x00000000,0x00000032,0x00001000,
+0x0000073d,0x00001000,0x0007f188,0x000c0000,
+0x00000000,0x00000000,0x0008c01c,0x00001003,
+0x00002705,0x00001008,0x0008b201,0x000c1392,
+0x0000ba01,0x00000000,0x00008731,0x00001400,
+0x0004c108,0x000fe0c4,0x00057488,0x00000000,
+0x000a6388,0x00001001,0x0008b334,0x000bc141,
+0x0003020e,0x00000000,0x000886b0,0x00001008,
+0x00003625,0x000c5dfa,0x000a638a,0x00001001,
+0x0008020e,0x00001002,0x0008a6b0,0x00001008,
+0x0007f301,0x00000000,0x00000000,0x00000000,
+0x00002725,0x000a8c40,0x000000ae,0x00000000,
+0x000d8630,0x00001008,0x00000000,0x000c74e0,
+0x0007d182,0x0002d640,0x000a8630,0x00001008,
+0x000799b8,0x0002d6c0,0x0000748a,0x000c3ec5,
+0x0007420a,0x000c0000,0x00062208,0x000c4117,
+0x00070630,0x00001009,0x00000000,0x000c0000,
+0x0001022e,0x00000000,0x0003a630,0x00001009,
+0x00000000,0x000c0000,0x00000036,0x00001000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x0002a730,0x00001008,0x0007f801,0x000c0000,
+0x00000037,0x00001000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x0002a730,0x00001008,
+0x00000033,0x00001000,0x0002a705,0x00001008,
+0x00007a01,0x000c0000,0x000e6288,0x000d550a,
+0x0006428a,0x00000000,0x00060730,0x0000100a,
+0x00000000,0x000c0000,0x00000000,0x00000000,
+0x0007aab0,0x00034880,0x00078fb0,0x0000100b,
+0x00057488,0x00000000,0x00033b94,0x00081140,
+0x000183ae,0x00000000,0x000786b0,0x0000100b,
+0x00022f05,0x000c3545,0x0000eb8a,0x00000000,
+0x00042731,0x00001003,0x0007aab0,0x00034880,
+0x00048fb0,0x0000100a,0x00057488,0x00000000,
+0x00033b94,0x00081140,0x000183ae,0x00000000,
+0x000806b0,0x0000100b,0x00022f05,0x00000000,
+0x00007401,0x00091140,0x00048f05,0x000951c0,
+0x00042731,0x00001003,0x0000473d,0x00001000,
+0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
+0x000fe19e,0x00001003,0x00000000,0x00000000,
+0x0008e19c,0x00001003,0x000083c1,0x00093040,
+0x00000f41,0x00097140,0x0000a841,0x0009b240,
+0x0000a0c1,0x0009f040,0x0001c641,0x00093540,
+0x0001cec1,0x0009b5c0,0x00000000,0x000fdc44,
+0x00055208,0x00000000,0x00010705,0x000a2880,
+0x0000a23a,0x00093a00,0x0003fc8a,0x000df6c5,
+0x0004ef0a,0x000c0000,0x00012f05,0x00036880,
+0x00065308,0x000c2997,0x000d86b0,0x0000100a,
+0x0004410a,0x000d40c7,0x00000000,0x00000000,
+0x00080730,0x00001004,0x00056f0a,0x000ea105,
+0x00000000,0x00000000,0x0000473d,0x00001000,
+0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
+0x0000273d,0x00001000,0x00000000,0x000eba44,
+0x00048f05,0x0000f440,0x00007401,0x0000f7c0,
+0x00000734,0x00001000,0x00010705,0x000a6880,
+0x00006a88,0x000c75c4,0x00000000,0x000e5084,
+0x00000000,0x000eba44,0x00087401,0x000e4782,
+0x00000734,0x00001000,0x00010705,0x000a6880,
+0x00006a88,0x000c75c4,0x0007c108,0x000c0000,
+0x0007e721,0x000bed40,0x00005f25,0x000badc0,
+0x0003ba97,0x000beb80,0x00065590,0x000b2e00,
+0x00033217,0x00003ec0,0x00065590,0x000b8e40,
+0x0003ed80,0x000491c0,0x00073fb0,0x00074c80,
+0x000283a0,0x0000100c,0x000ee388,0x00042970,
+0x00008301,0x00021ef2,0x000b8f14,0x0000000f,
+0x000c4d8d,0x0000001b,0x000d6dc2,0x000e06c6,
+0x000032ac,0x000c3916,0x0004edc2,0x00074c80,
+0x00078898,0x00001000,0x00038894,0x00000032,
+0x000c4d8d,0x00092e1b,0x000d6dc2,0x000e06c6,
+0x0004edc2,0x000c1956,0x0000722c,0x00034a00,
+0x00041705,0x0009ed40,0x00058730,0x00001400,
+0x000d7488,0x000c3a00,0x00048f05,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000}
+ };
diff --git a/drivers/sound/cs46xx.c b/drivers/sound/cs46xx.c new file mode 100644 index 000000000..6a9fec82b --- /dev/null +++ b/drivers/sound/cs46xx.c @@ -0,0 +1,2751 @@ +/* + * Crystal SoundFusion CS46xx driver + * + * Copyright 1999-2000 Jaroslav Kysela <perex@suse.cz> + * Copyright 2000 Alan Cox <alan@redhat.com> + * + * The core of this code is taken from the ALSA project driver by + * Jaroslav. Please send Jaroslav the credit for the driver and + * report bugs in this port to <alan@redhat.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. + * + * 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. + * + * Changes: + * 20000815 Updated driver to kernel 2.4, some cleanups/fixes + * Nils Faerber <nils@kernelconcepts.de> + * + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/sound.h> +#include <linux/malloc.h> +#include <linux/soundcard.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <linux/init.h> +#include <linux/poll.h> +#include <linux/spinlock.h> +#include <linux/ac97_codec.h> +#include <linux/wrapper.h> +#include <asm/uaccess.h> +#include <asm/hardirq.h> + +#include "cs461x.h" + +#define ADC_RUNNING 1 +#define DAC_RUNNING 2 + +#define CS_FMT_16BIT 1 /* These are fixed in fact */ +#define CS_FMT_STEREO 2 +#define CS_FMT_MASK 3 + +/* + * CS461x definitions + */ + +#define CS461X_BA0_SIZE 0x2000 +#define CS461X_BA1_DATA0_SIZE 0x3000 +#define CS461X_BA1_DATA1_SIZE 0x3800 +#define CS461X_BA1_PRG_SIZE 0x7000 +#define CS461X_BA1_REG_SIZE 0x0100 + +#define GOF_PER_SEC 200 + +/* + * Define this to enable recording, + * this is curently broken and using it will cause data corruption + * in kernel- and user-space! + */ +/* #define CS46XX_ENABLE_RECORD */ + +static int external_amp = 0; +static int thinkpad = 0; + + +/* an instance of the 4610 channel */ + +struct cs_channel +{ + int used; + int num; + void *state; +}; + +#define DRIVER_VERSION "0.09" + +/* magic numbers to protect our data structures */ +#define CS_CARD_MAGIC 0x46524F4D /* "FROM" */ +#define CS_STATE_MAGIC 0x414c5341 /* "ALSA" */ +#define NR_HW_CH 3 + +/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ +#define NR_AC97 2 + +/* minor number of /dev/dspW */ +#define SND_DEV_DSP8 1 + +/* minor number of /dev/dspW */ +#define SND_DEV_DSP16 1 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +/* "software" or virtual channel, an instance of opened /dev/dsp */ +struct cs_state { + unsigned int magic; + struct cs_card *card; /* Card info */ + + /* single open lock mechanism, only used for recording */ + struct semaphore open_sem; + wait_queue_head_t open_wait; + + /* file mode */ + mode_t open_mode; + + /* virtual channel number */ + int virt; + + struct dmabuf { + /* wave sample stuff */ + unsigned int rate; + unsigned char fmt, enable; + + /* hardware channel */ + struct cs_channel *channel; + int pringbuf; /* Software ring slot */ + int ppingbuf; /* Hardware ring slot */ + void *pbuf; /* 4K hardware DMA buffer */ + + /* OSS buffer management stuff */ + void *rawbuf; + dma_addr_t dma_handle; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + + /* our buffer acts like a circular ring */ + unsigned hwptr; /* where dma last started, updated by update_ptr */ + unsigned swptr; /* where driver last clear/filled, updated by read/write */ + int count; /* bytes to be comsumed or been generated by dma machine */ + unsigned total_bytes; /* total bytes dmaed by hardware */ + + unsigned error; /* number of over/underruns */ + wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ + + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned update_flag; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + } dmabuf; +}; + + +struct cs_card { + struct cs_channel channel[2]; + unsigned int magic; + + /* We keep cs461x cards in a linked list */ + struct cs_card *next; + + /* The cs461x has a certain amount of cross channel interaction + so we use a single per card lock */ + spinlock_t lock; + + /* PCI device stuff */ + struct pci_dev * pci_dev; + + unsigned int pctl, cctl; /* Hardware DMA flag sets */ + + /* soundcore stuff */ + int dev_audio; + + /* structures for abstraction of hardware facilities, codecs, banks and channels*/ + struct ac97_codec *ac97_codec[NR_AC97]; + struct cs_state *states[NR_HW_CH]; + + u16 ac97_features; + + int amplifier; /* Amplifier control */ + void (*amplifier_ctrl)(struct cs_card *, int); + + int active; /* Active clocking */ + void (*active_ctrl)(struct cs_card *, int); + + /* hardware resources */ + unsigned long ba0_addr; + unsigned long ba1_addr; + u32 irq; + + /* mappings */ + void *ba0; + union + { + struct + { + u8 *data0; + u8 *data1; + u8 *pmem; + u8 *reg; + } name; + u8 *idx[4]; + } ba1; + + /* Function support */ + struct cs_channel *(*alloc_pcm_channel)(struct cs_card *); + struct cs_channel *(*alloc_rec_pcm_channel)(struct cs_card *); + void (*free_pcm_channel)(struct cs_card *, int chan); +}; + +static struct cs_card *devs = NULL; + +static int cs_open_mixdev(struct inode *inode, struct file *file); +static int cs_release_mixdev(struct inode *inode, struct file *file); +static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); +static loff_t cs_llseek(struct file *file, loff_t offset, int origin); + +extern __inline__ unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + + +/* + * common I/O routines + */ + +static void cs461x_poke(struct cs_card *codec, unsigned long reg, unsigned int val) +{ + writel(val, codec->ba1.idx[(reg >> 16) & 3]+(reg&0xffff)); +} + +static unsigned int cs461x_peek(struct cs_card *codec, unsigned long reg) +{ + return readl(codec->ba1.idx[(reg >> 16) & 3]+(reg&0xffff)); +} + +static void cs461x_pokeBA0(struct cs_card *codec, unsigned long reg, unsigned int val) +{ + writel(val, codec->ba0+reg); +} + +static unsigned int cs461x_peekBA0(struct cs_card *codec, unsigned long reg) +{ + return readl(codec->ba0+reg); +} + + +static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg); +static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); + +static struct cs_channel *cs_alloc_pcm_channel(struct cs_card *card) +{ + if(card->channel[1].used==1) + return NULL; + card->channel[1].used=1; + card->channel[1].num=1; + return &card->channel[1]; +} + +static struct cs_channel *cs_alloc_rec_pcm_channel(struct cs_card *card) +{ + if(card->channel[0].used==1) + return NULL; + card->channel[0].used=1; + card->channel[0].num=0; + return &card->channel[0]; +} + +static void cs_free_pcm_channel(struct cs_card *card, int channel) +{ + card->channel[channel].state = NULL; + card->channel[channel].used=0; +} + +/* set playback sample rate */ +static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned int tmp1, tmp2; + unsigned int phiIncr; + unsigned int correctionPerGOF, correctionPerSec; + + /* + * Compute the values used to drive the actual sample rate conversion. + * The following formulas are being computed, using inline assembly + * since we need to use 64 bit arithmetic to compute the values: + * + * phiIncr = floor((Fs,in * 2^26) / Fs,out) + * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) / + * GOF_PER_SEC) + * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M + * GOF_PER_SEC * correctionPerGOF + * + * i.e. + * + * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out) + * correctionPerGOF:correctionPerSec = + * dividend:remainder(ulOther / GOF_PER_SEC) + */ + tmp1 = rate << 16; + phiIncr = tmp1 / 48000; + tmp1 -= phiIncr * 48000; + tmp1 <<= 10; + phiIncr <<= 10; + tmp2 = tmp1 / 48000; + phiIncr += tmp2; + tmp1 -= tmp2 * 48000; + correctionPerGOF = tmp1 / GOF_PER_SEC; + tmp1 -= correctionPerGOF * GOF_PER_SEC; + correctionPerSec = tmp1; + + /* + * Fill in the SampleRateConverter control block. + */ + + spin_lock_irq(&state->card->lock); + cs461x_poke(state->card, BA1_PSRC, + ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); + cs461x_poke(state->card, BA1_PPI, phiIncr); + spin_unlock_irq(&state->card->lock); + dmabuf->rate = rate; + + return rate; +} + +/* set recording sample rate */ +static unsigned int cs_set_adc_rate(struct cs_state * state, unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int phiIncr, coeffIncr, tmp1, tmp2; + unsigned int correctionPerGOF, correctionPerSec, initialDelay; + unsigned int frameGroupLength, cnt; + + /* + * We can only decimate by up to a factor of 1/9th the hardware rate. + * Correct the value if an attempt is made to stray outside that limit. + */ + if ((rate * 9) < 48000) + rate = 48000 / 9; + + /* + * We can not capture at at rate greater than the Input Rate (48000). + * Return an error if an attempt is made to stray outside that limit. + */ + if (rate > 48000) + rate = 48000; + + /* + * Compute the values used to drive the actual sample rate conversion. + * The following formulas are being computed, using inline assembly + * since we need to use 64 bit arithmetic to compute the values: + * + * coeffIncr = -floor((Fs,out * 2^23) / Fs,in) + * phiIncr = floor((Fs,in * 2^26) / Fs,out) + * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) / + * GOF_PER_SEC) + * correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - + * GOF_PER_SEC * correctionPerGOF + * initialDelay = ceil((24 * Fs,in) / Fs,out) + * + * i.e. + * + * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in)) + * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) + * correctionPerGOF:correctionPerSec = + * dividend:remainder(ulOther / GOF_PER_SEC) + * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out) + */ + + tmp1 = rate << 16; + coeffIncr = tmp1 / 48000; + tmp1 -= coeffIncr * 48000; + tmp1 <<= 7; + coeffIncr <<= 7; + coeffIncr += tmp1 / 48000; + coeffIncr ^= 0xFFFFFFFF; + coeffIncr++; + tmp1 = 48000 << 16; + phiIncr = tmp1 / rate; + tmp1 -= phiIncr * rate; + tmp1 <<= 10; + phiIncr <<= 10; + tmp2 = tmp1 / rate; + phiIncr += tmp2; + tmp1 -= tmp2 * rate; + correctionPerGOF = tmp1 / GOF_PER_SEC; + tmp1 -= correctionPerGOF * GOF_PER_SEC; + correctionPerSec = tmp1; + initialDelay = ((48000 * 24) + rate - 1) / rate; + + /* + * Fill in the VariDecimate control block. + */ + spin_lock_irq(&card->lock); + cs461x_poke(card, BA1_CSRC, + ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); + cs461x_poke(card, BA1_CCI, coeffIncr); + cs461x_poke(card, BA1_CD, + (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); + cs461x_poke(card, BA1_CPI, phiIncr); + spin_unlock_irq(&card->lock); + + /* + * Figure out the frame group length for the write back task. Basically, + * this is just the factors of 24000 (2^6*3*5^3) that are not present in + * the output sample rate. + */ + frameGroupLength = 1; + for (cnt = 2; cnt <= 64; cnt *= 2) { + if (((rate / cnt) * cnt) != rate) + frameGroupLength *= 2; + } + if (((rate / 3) * 3) != rate) { + frameGroupLength *= 3; + } + for (cnt = 5; cnt <= 125; cnt *= 5) { + if (((rate / cnt) * cnt) != rate) + frameGroupLength *= 5; + } + + /* + * Fill in the WriteBack control block. + */ + spin_lock_irq(&card->lock); + cs461x_poke(card, BA1_CFG1, frameGroupLength); + cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength)); + cs461x_poke(card, BA1_CCST, 0x0000FFFF); + cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000)); + cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF); + spin_unlock_irq(&card->lock); + dmabuf->rate = rate; + return rate; +} + +/* prepare channel attributes for playback */ +static void cs_play_setup(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int tmp, tmp1; + + tmp1=16; + if (!(dmabuf->fmt & CS_FMT_STEREO)) + tmp1>>=1; + cs461x_poke(card, BA1_PVOL, 0x80008000); + cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf)); + + tmp=cs461x_peek(card, BA1_PDTC); + tmp&=~0x000003FF; + tmp|=tmp1-1; + cs461x_poke(card, BA1_PDTC, tmp); + + tmp=cs461x_peek(card, BA1_PFIE); + tmp&=~0x0000F03F; + if(!(dmabuf->fmt & CS_FMT_STEREO)) + { + tmp|=0x00002000; + } + cs461x_poke(card, BA1_PFIE, tmp); + +} + +/* prepare channel attributes for recording */ +static void cs_rec_setup(struct cs_state *state) +{ + struct cs_card *card = state->card; + struct dmabuf *dmabuf = &state->dmabuf; + /* set the attenuation to 0dB */ + cs461x_poke(card, BA1_CVOL, 0x80008000); + cs461x_poke(card, BA1_CBA, virt_to_bus(dmabuf->pbuf)); +} + + +/* get current playback/recording dma buffer pointer (byte offset from LBA), + called with spinlock held! */ + +extern __inline__ unsigned cs_get_dma_addr(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + u32 offset; + + if (!dmabuf->enable) + return 0; + + offset = dmabuf->pringbuf * 2048; + return offset; +} + +static void resync_dma_ptrs(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + int offset; + + offset = 0; + dmabuf->hwptr=dmabuf->swptr = 0; + dmabuf->ppingbuf = dmabuf->pringbuf = 0; + dmabuf->ppingbuf = 1; + if(dmabuf->fmt&CS_FMT_16BIT) + memset(dmabuf->pbuf, 0, PAGE_SIZE); + else + memset(dmabuf->pbuf, 0x80, PAGE_SIZE); +} + +/* Stop recording (lock held) */ +extern __inline__ void __stop_adc(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int tmp; + + dmabuf->enable &= ~ADC_RUNNING; + + tmp=cs461x_peek(card, BA1_CCTL); + tmp&=0xFFFF; + cs461x_poke(card, BA1_CCTL, tmp); + +} + +static void stop_adc(struct cs_state *state) +{ + struct cs_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __stop_adc(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static void start_adc(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned long flags; + unsigned int tmp; + + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + dmabuf->enable |= ADC_RUNNING; + tmp=cs461x_peek(card, BA1_CCTL); + tmp&=0xFFFF; + tmp|=card->cctl; + cs461x_poke(card, BA1_CCTL, tmp); + } + spin_unlock_irqrestore(&card->lock, flags); +} + +/* stop playback (lock held) */ +extern __inline__ void __stop_dac(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int tmp; + + dmabuf->enable &= ~DAC_RUNNING; + + tmp=cs461x_peek(card, BA1_PCTL); + tmp&=0xFFFF; + cs461x_poke(card, BA1_PCTL, tmp); +} + +static void stop_dac(struct cs_state *state) +{ + struct cs_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __stop_dac(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static void start_dac(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned long flags; + int tmp; + + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { + if(!(dmabuf->enable&DAC_RUNNING)) + { + dmabuf->enable |= DAC_RUNNING; + tmp = cs461x_peek(card, BA1_PCTL); + tmp &= 0xFFFF; + tmp |= card->pctl; + cs461x_poke(card, BA1_PCTL, tmp); + } + } + spin_unlock_irqrestore(&card->lock, flags); +} + +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +/* allocate DMA buffer, playback and recording buffer should be allocated seperately */ +static int alloc_dmabuf(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + void *rawbuf = NULL; + int order; + struct page *page, *pend; + + /* alloc as big a chunk as we can */ + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) + break; + + if (!rawbuf) + return -ENOMEM; + +#ifdef DEBUG + printk("cs461x: allocated %ld (order = %d) bytes at %p\n", + PAGE_SIZE << order, order, rawbuf); +#endif + + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->rawbuf = rawbuf; + dmabuf->buforder = order; + + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); + for (page = virt_to_page(rawbuf); page <= pend; page++) + mem_map_reserve(page); + + return 0; +} + +/* free DMA buffer */ +static void dealloc_dmabuf(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct page *page, *pend; + + if (dmabuf->rawbuf) { + /* undo marking the pages as reserved */ + pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); + for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) + mem_map_unreserve(page); + pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, + dmabuf->rawbuf, dmabuf->dma_handle); + } + dmabuf->rawbuf = NULL; + dmabuf->mapped = dmabuf->ready = 0; +} + +static int prog_dmabuf(struct cs_state *state, unsigned rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned bytepersec; + unsigned bufsize; + unsigned long flags; + int ret; + + spin_lock_irqsave(&state->card->lock, flags); + resync_dma_ptrs(state); + dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + + /* allocate DMA buffer if not allocated yet */ + if (!dmabuf->rawbuf) + if ((ret = alloc_dmabuf(state))) + return ret; + + /* FIXME: figure out all this OSS fragment stuff */ + bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt]; + bufsize = PAGE_SIZE << dmabuf->buforder; + if (dmabuf->ossfragshift) { + if ((1000 << dmabuf->ossfragshift) < bytepersec) + dmabuf->fragshift = ld2(bytepersec/1000); + else + dmabuf->fragshift = dmabuf->ossfragshift; + } else { + /* lets hand out reasonable big ass buffers by default */ + dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + } + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { + dmabuf->fragshift--; + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + } + dmabuf->fragsize = 1 << dmabuf->fragshift; + if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) + dmabuf->numfrag = dmabuf->ossmaxfrags; + dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; + dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; + + memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, + dmabuf->dmasize); + + /* + * Now set up the ring + */ + + spin_lock_irqsave(&state->card->lock, flags); + if (rec) { + cs_rec_setup(state); + } else { + cs_play_setup(state); + } + spin_unlock_irqrestore(&state->card->lock, flags); + + /* set the ready flag for the dma buffer */ + dmabuf->ready = 1; + +#ifdef DEBUG + printk("cs461x: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, " + "fragsize = %d dmasize = %d\n", + dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, + dmabuf->fragsize, dmabuf->dmasize); +#endif + + return 0; +} + +static void cs_clear_tail(struct cs_state *state) +{ +} + +static int drain_dac(struct cs_state *state, int nonblock) +{ + DECLARE_WAITQUEUE(wait, current); + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned long tmo; + int count; + + if (dmabuf->mapped || !dmabuf->ready) + return 0; + + add_wait_queue(&dmabuf->wait, &wait); + for (;;) { + /* It seems that we have to set the current state to TASK_INTERRUPTIBLE + every time to make the process really go to sleep */ + current->state = TASK_INTERRUPTIBLE; + + spin_lock_irqsave(&state->card->lock, flags); + count = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (count <= 0) + break; + + if (signal_pending(current)) + break; + + if (nonblock) { + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + + tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; + tmo >>= sample_shift[dmabuf->fmt]; + tmo += (4096*HZ)/dmabuf->rate; + + if (!schedule_timeout(tmo ? tmo : 1) && tmo){ + printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count); + break; + } + } + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + + return 0; +} + +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ +static void cs_update_ptr(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned hwptr, swptr; + int clear_cnt = 0; + int diff; + unsigned char silence; + + /* update hardware pointer */ + hwptr = cs_get_dma_addr(state); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count -= diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count += diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_adc(state); + dmabuf->error++; + } + else if (!dmabuf->endcleared) { + swptr = dmabuf->swptr; + silence = (dmabuf->fmt & CS_FMT_16BIT ? 0 : 0x80); + if (dmabuf->count < (signed) dmabuf->fragsize) + { + clear_cnt = dmabuf->fragsize; + if ((swptr + clear_cnt) > dmabuf->dmasize) + clear_cnt = dmabuf->dmasize - swptr; + memset (dmabuf->rawbuf + swptr, silence, clear_cnt); + dmabuf->endcleared = 1; + } + } + wake_up(&dmabuf->wait); + } + } + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count += diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count -= diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_dac(state); + dmabuf->error++; + } + wake_up(&dmabuf->wait); + } + } +} + +static void cs_record_interrupt(struct cs_state *state) +{ + memcpy(state->dmabuf.rawbuf + (2048*state->dmabuf.pringbuf++), + state->dmabuf.pbuf+2048*state->dmabuf.ppingbuf++, 2048); + state->dmabuf.ppingbuf&=1; + if(state->dmabuf.pringbuf > (PAGE_SIZE<<state->dmabuf.buforder)/2048) + state->dmabuf.pringbuf=0; + cs_update_ptr(state); +} + +static void cs_play_interrupt(struct cs_state *state) +{ + memcpy(state->dmabuf.pbuf+2048*state->dmabuf.ppingbuf++, + state->dmabuf.rawbuf + (2048*state->dmabuf.pringbuf++), 2048); + state->dmabuf.ppingbuf&=1; + if(state->dmabuf.pringbuf >= (PAGE_SIZE<<state->dmabuf.buforder)/2048) + state->dmabuf.pringbuf=0; + cs_update_ptr(state); +} + +static void cs_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cs_card *card = (struct cs_card *)dev_id; + /* Single channel card */ + struct cs_state *recstate = card->channel[0].state; + struct cs_state *playstate = card->channel[1].state; + u32 status; + + spin_lock(&card->lock); + + status = cs461x_peekBA0(card, BA0_HISR); + + if((status&0x7fffffff)==0) + { + cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV); + spin_unlock(&card->lock); + return; + } + + if((status & HISR_VC0) && playstate && playstate->dmabuf.ready) + cs_play_interrupt(playstate); + if((status & HISR_VC1) && recstate && recstate->dmabuf.ready) + cs_record_interrupt(recstate); + + /* clear 'em */ + cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV); + spin_unlock(&card->lock); +} + +static loff_t cs_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to + the user's buffer. it is filled by the dma machine and drained by this loop. */ +static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + +#ifdef DEBUG + printk("cs461x: cs_read called, count = %d\n", count); +#endif + + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count > (signed) dmabuf->dmasize) { + /* buffer overrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr, make process flush the buffer */ + dmabuf->count = dmabuf->dmasize; + dmabuf->swptr = dmabuf->hwptr; + } + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count < cnt) + cnt = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (cnt > count) + cnt = count; + if (cnt <= 0) { + unsigned long tmo; + /* buffer is empty, start the dma machine and wait for data to be + recorded */ + start_adc(state); + if (file->f_flags & O_NONBLOCK) { + if (!ret) ret = -EAGAIN; + return ret; + } + /* This isnt strictly right for the 810 but it'll do */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer overrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "cs461x: recording schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); +#endif + /* a buffer overrun, we delay the recovery untill next time the + while loop begin and we REALLY have space to record */ + } + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + return ret; + } + continue; + } + + if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr = swptr; + dmabuf->count -= cnt; + spin_unlock_irqrestore(&state->card->lock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(state); + } + return ret; +} + +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to + the soundcard. it is drained by the dma machine and filled by this loop. */ +static ssize_t cs_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + +#ifdef DEBUG + printk("cs461x: cs_write called, count = %d\n", count); +#endif + + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count < 0) { + /* buffer underrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr */ + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + } + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count + cnt > dmabuf->dmasize) + cnt = dmabuf->dmasize - dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (cnt > count) + cnt = count; + if (cnt <= 0) { + unsigned long tmo; + /* buffer is full, start the dma machine and wait for data to be + played */ + start_dac(state); + if (file->f_flags & O_NONBLOCK) { + if (!ret) ret = -EAGAIN; + return ret; + } + /* Not strictly correct but works */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer underrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "cs461x: playback schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); +#endif + /* a buffer underrun, we delay the recovery untill next time the + while loop begin and we REALLY have data to play */ + } + if (signal_pending(current)) { + if (!ret) ret = -ERESTARTSYS; + return ret; + } + continue; + } + if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr = swptr; + dmabuf->count += cnt; + dmabuf->endcleared = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(state); + } + return ret; +} + +static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned int mask = 0; + + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &dmabuf->wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &dmabuf->wait, wait); + + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + if (file->f_mode & FMODE_READ) { + if (dmabuf->count >= (signed)dmabuf->fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (dmabuf->mapped) { + if (dmabuf->count >= (signed)dmabuf->fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&state->card->lock, flags); + + return mask; +} + +static int cs_mmap(struct file *file, struct vm_area_struct *vma) +{ + return -EINVAL; +#if 0 + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + int ret; + unsigned long size; + + + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(state, 0)) != 0) + return ret; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(state, 1)) != 0) + return ret; + } else + return -EINVAL; + + if (vma->vm_offset != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << dmabuf->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), + size, vma->vm_page_prot)) + return -EAGAIN; + dmabuf->mapped = 1; + + return 0; +#endif +} + +static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + + mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || + ((file->f_mode & FMODE_READ) && dmabuf->mapped); +#ifdef DEBUG + printk("cs461x: cs_ioctl, command = %2d, arg = 0x%08x\n", + _IOC_NR(cmd), arg ? *(int *)arg : 0); +#endif + + switch (cmd) + { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_RESET: + /* FIXME: spin_lock ? */ + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + synchronize_irq(); + dmabuf->ready = 0; + resync_dma_ptrs(state); + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + synchronize_irq(); + resync_dma_ptrs(state); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(state, file->f_flags & O_NONBLOCK); + return 0; + + case SNDCTL_DSP_SPEED: /* set smaple rate */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + cs_set_dac_rate(state, val); + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + cs_set_adc_rate(state, val); + } + } + return put_user(dmabuf->rate, (int *)arg); + + case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + if(val) + dmabuf->fmt |= CS_FMT_STEREO; + else + dmabuf->fmt &= ~CS_FMT_STEREO; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + if(val) + { + dmabuf->fmt |= CS_FMT_STEREO; + return put_user(1, (int *)arg); + } +#if 0 + /* Needs extra work to support this */ + + else + dmabuf->fmt &= ~CS_FMT_STEREO; +#endif + } + return 0; + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(state, 0))) + return val; + return put_user(dmabuf->fragsize, (int *)arg); + } + if (file->f_mode & FMODE_READ) { + if ((val = prog_dmabuf(state, 1))) + return val; + return put_user(dmabuf->fragsize, (int *)arg); + } + + case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ + return put_user(AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Select sample format */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + if(val==AFMT_S16_LE/* || val==AFMT_U8*/) + { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + } + if(val==AFMT_S16_LE) + dmabuf->fmt |= CS_FMT_16BIT; + else + dmabuf->fmt &= ~CS_FMT_16BIT; + } + } + if(dmabuf->fmt&CS_FMT_16BIT) + return put_user(AFMT_S16_LE, (int *)arg); + else + return put_user(AFMT_U8, (int *)arg); + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + if (val > 1) + dmabuf->fmt |= CS_FMT_STEREO; + else + dmabuf->fmt &= ~CS_FMT_STEREO; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + } + } + return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1, + (int *)arg); + + case SNDCTL_DSP_POST: + /* FIXME: the same as RESET ?? */ + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if (dmabuf->subdivision) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2) + return -EINVAL; + dmabuf->subdivision = val; + return 0; + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + + dmabuf->ossfragshift = val & 0xffff; + dmabuf->ossmaxfrags = (val >> 16) & 0xffff; + switch(dmabuf->ossmaxfrags) + { + case 1: + dmabuf->ossfragshift=12; + return 0; + default: + /* Fragments must be 2K long */ + dmabuf->ossfragshift = 11; + dmabuf->ossmaxfrags=2; + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, + (int *)arg); + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && dmabuf->enable) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && dmabuf->enable) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + start_adc(state); + } else + stop_adc(state); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + start_dac(state); + } else + stop_dac(state); + } + return 0; + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_SETDUPLEX: + return -EINVAL; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + val = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + return put_user(val, (int *)arg); + + case SOUND_PCM_READ_RATE: + return put_user(dmabuf->rate, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1, + (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user(AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } + return -EINVAL; +} + + +/* + * AMP control - null AMP + */ + +static void amp_none(struct cs_card *card, int change) +{ +} + +/* + * Crystal EAPD mode + */ + +static void amp_voyetra(struct cs_card *card, int change) +{ + /* Manage the EAPD bit on the Crystal 4297 */ + int old=card->amplifier; + + card->amplifier+=change; + if(card->amplifier && !old) + { + /* Turn the EAPD amp on */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, + cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) | + 0x8000); + } + else if(old && !card->amplifier) + { + /* Turn the EAPD amp off */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, + cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + ~0x8000); + } +} + + + +/* + * Untested + */ +#if 0 +static void amp_voyetra_4294(struct cs_card *card, int change) +{ + struct ac97_codec *c=card->ac97_codec[0]; + int old = card->amplifier; + + card->amplifier+=change; + + if(card->amplifier) + { + /* Switch the GPIO pins 7 and 8 to open drain */ + cs_ac97_set(c, 0x4C, cs_ac97_get(c, 0x4C) & 0xFE7F); + cs_ac97_set(c, 0x4E, cs_ac97_get(c, 0x4E) | 0x0180); + /* Now wake the AMP (this might be backwards) */ + cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) & ~0x0180); + } + else + { + cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) | 0x0180); + } +} +#endif + +/* + * Handle the CLKRUN on a thinkpad. We must disable CLKRUN support + * whenever we need to beat on the chip. + * + * The original idea and code for this hack comes from David Kaiser at + * Linuxcare. Perhaps one day Crystal will document their chips well + * enough to make them useful. + */ + +static void clkrun_hack(struct cs_card *card, int change) +{ + struct pci_dev *acpi_dev; + u16 control; + u8 pp; + unsigned long port; + int old=card->amplifier; + + card->amplifier += change; + + acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + if(acpi_dev == NULL) + return; /* Not a thinkpad thats for sure */ + + + /* Find the control port */ + pci_read_config_byte(acpi_dev, 0x41, &pp); + port = pp<<8; + + /* Read ACPI port */ + control = inw(port+0x10); + + /* Flip CLKRUN off while running */ + if(!card->amplifier && old) + outw(control|0x2000, port+0x10); + else if(card->amplifier && !old) + outw(control&~0x2000, port+0x10); +} + + +static int cs_open(struct inode *inode, struct file *file) +{ + int i = 0; + struct cs_card *card = devs; + struct cs_state *state = NULL; + struct dmabuf *dmabuf = NULL; + +#ifndef CS46XX_ENABLE_RECORD + if (file->f_mode & FMODE_READ) + return -ENODEV; +#endif + + /* find an avaiable virtual channel (instance of /dev/dsp) */ + while (card != NULL) { + for (i = 0; i < NR_HW_CH; i++) { + if (card->states[i] == NULL) { + state = card->states[i] = (struct cs_state *) + kmalloc(sizeof(struct cs_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + memset(state, 0, sizeof(struct cs_state)); + dmabuf = &state->dmabuf; + dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL); + if(dmabuf->pbuf==NULL) + { + kfree(state); + card->states[i]=NULL; + return -ENOMEM; + } + goto found_virt; + } + } + card = card->next; + } + /* no more virtual channel avaiable */ + if (!state) + return -ENODEV; + + found_virt: + /* found a free virtual channel, allocate hardware channels */ + if(file->f_mode & FMODE_READ) + dmabuf->channel = card->alloc_rec_pcm_channel(card); + else + dmabuf->channel = card->alloc_pcm_channel(card); + + if (dmabuf->channel == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; + return -ENODEV; + } + + /* Now turn on external AMP if needed */ + state->card = card; + state->card->active_ctrl(state->card,1); + state->card->amplifier_ctrl(state->card,1); + + dmabuf->channel->state = state; + /* initialize the virtual channel */ + state->virt = i; + state->magic = CS_STATE_MAGIC; + init_waitqueue_head(&dmabuf->wait); + init_MUTEX(&state->open_sem); + file->private_data = state; + + down(&state->open_sem); + + /* set default sample format. According to OSS Programmer's Guide /dev/dsp + should be default to unsigned 8-bits, mono, with sample rate 8kHz and + /dev/dspW will accept 16-bits sample */ + if (file->f_mode & FMODE_WRITE) { + /* Output is 16bit only mono or stereo */ + dmabuf->fmt &= ~CS_FMT_MASK; + dmabuf->fmt |= CS_FMT_16BIT; + dmabuf->ossfragshift = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; + cs_set_dac_rate(state, 8000); + } + + if (file->f_mode & FMODE_READ) { + /* Input is 16bit stereo only */ + dmabuf->fmt &= ~CS_FMT_MASK; + dmabuf->fmt |= CS_FMT_16BIT|CS_FMT_STEREO; + dmabuf->ossfragshift = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; + cs_set_adc_rate(state, 8000); + } + + state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + up(&state->open_sem); + + + MOD_INC_USE_COUNT; + return 0; +} + +static int cs_release(struct inode *inode, struct file *file) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + + if (file->f_mode & FMODE_WRITE) { + /* FIXME :.. */ + cs_clear_tail(state); + drain_dac(state, file->f_flags & O_NONBLOCK); + } + + /* stop DMA state machine and free DMA buffers/channels */ + down(&state->open_sem); + + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dealloc_dmabuf(state); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dealloc_dmabuf(state); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); + } + + free_page((unsigned long)state->dmabuf.pbuf); + + /* we're covered by the open_sem */ + up(&state->open_sem); + state->card->states[state->virt] = NULL; + state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + + /* Now turn off external AMP if needed */ + state->card->amplifier_ctrl(state->card, -1); + state->card->active_ctrl(state->card, -1); + + kfree(state); + MOD_DEC_USE_COUNT; + return 0; +} + +static /*const*/ struct file_operations cs461x_fops = { + llseek: cs_llseek, + read: cs_read, + write: cs_write, + poll: cs_poll, + ioctl: cs_ioctl, + mmap: cs_mmap, + open: cs_open, + release: cs_release, +}; + +/* Write AC97 codec registers */ + + +static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg) +{ + struct cs_card *card = dev->private_data; + int count; + + /* + * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address + * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 + * 3. Write ACCTL = Control Register = 460h for initiating the write + * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h + * 5. if DCV not cleared, break and return error + * 6. Read ACSTS = Status Register = 464h, check VSTS bit + */ + + + cs461x_peekBA0(card, BA0_ACSDA); + + /* + * Setup the AC97 control registers on the CS461x to send the + * appropriate command to the AC97 to perform the read. + * ACCAD = Command Address Register = 46Ch + * ACCDA = Command Data Register = 470h + * ACCTL = Control Register = 460h + * set DCV - will clear when process completed + * set CRW - Read command + * set VFRM - valid frame enabled + * set ESYN - ASYNC generation enabled + * set RSTN - ARST# inactive, AC97 codec not reset + */ + + cs461x_pokeBA0(card, BA0_ACCAD, reg); + cs461x_pokeBA0(card, BA0_ACCDA, 0); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW | + ACCTL_VFRM | ACCTL_ESYN | + ACCTL_RSTN); + + + /* + * Wait for the read to occur. + */ + for (count = 0; count < 500; count++) { + /* + * First, we want to wait for a short time. + */ + udelay(10); + /* + * Now, check to see if the read has completed. + * ACCTL = 460h, DCV should be reset by now and 460h = 17h + */ + if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) + break; + } + + /* + * Make sure the read completed. + */ + if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) { + printk(KERN_WARNING "cs461x: AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); + return 0xffff; + } + + /* + * Wait for the valid status bit to go active. + */ + for (count = 0; count < 100; count++) { + /* + * Read the AC97 status register. + * ACSTS = Status Register = 464h + * VSTS - Valid Status + */ + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS) + break; + udelay(10); + } + + /* + * Make sure we got valid status. + */ + if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)) { + printk(KERN_WARNING "cs461x: AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg); + return 0xffff; + } + + /* + * Read the data returned from the AC97 register. + * ACSDA = Status Data Register = 474h + */ +#if 0 + printk("e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg, + cs461x_peekBA0(card, BA0_ACSDA), + cs461x_peekBA0(card, BA0_ACCAD)); +#endif + return cs461x_peekBA0(card, BA0_ACSDA); +} + +static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val) +{ + struct cs_card *card = dev->private_data; + int count; + + /* + * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address + * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 + * 3. Write ACCTL = Control Register = 460h for initiating the write + * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h + * 5. if DCV not cleared, break and return error + */ + + /* + * Setup the AC97 control registers on the CS461x to send the + * appropriate command to the AC97 to perform the read. + * ACCAD = Command Address Register = 46Ch + * ACCDA = Command Data Register = 470h + * ACCTL = Control Register = 460h + * set DCV - will clear when process completed + * reset CRW - Write command + * set VFRM - valid frame enabled + * set ESYN - ASYNC generation enabled + * set RSTN - ARST# inactive, AC97 codec not reset + */ + cs461x_pokeBA0(card, BA0_ACCAD, reg); + cs461x_pokeBA0(card, BA0_ACCDA, val); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM | + ACCTL_ESYN | ACCTL_RSTN); + for (count = 0; count < 1000; count++) { + /* + * First, we want to wait for a short time. + */ + udelay(10); + /* + * Now, check to see if the write has completed. + * ACCTL = 460h, DCV should be reset by now and 460h = 07h + */ + if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) + break; + } + /* + * Make sure the write completed. + */ + if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) + printk(KERN_WARNING "cs461x: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val); +} + + +/* OSS /dev/mixer file operation methods */ + +static int cs_open_mixdev(struct inode *inode, struct file *file) +{ + int i; + int minor = MINOR(inode->i_rdev); + struct cs_card *card = devs; + + for (card = devs; card != NULL; card = card->next) + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL && + card->ac97_codec[i]->dev_mixer == minor) + goto match; + + if (!card) + return -ENODEV; + + match: + file->private_data = card->ac97_codec[i]; + + card->active_ctrl(card,1); + MOD_INC_USE_COUNT; + return 0; +} + +static int cs_release_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct cs_card *card = devs; + int i; + + for (card = devs; card != NULL; card = card->next) + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL && + card->ac97_codec[i]->dev_mixer == minor) + goto match; + + if (!card) + return -ENODEV; +match: + card->active_ctrl(card, -1); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + + return codec->mixer_ioctl(codec, cmd, arg); +} + +static /*const*/ struct file_operations cs_mixer_fops = { + llseek: cs_llseek, + ioctl: cs_ioctl_mixdev, + open: cs_open_mixdev, + release: cs_release_mixdev, +}; + +/* AC97 codec initialisation. */ +static int __init cs_ac97_init(struct cs_card *card) +{ + int num_ac97 = 0; + int ready_2nd = 0; + struct ac97_codec *codec; + u16 eid; + + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(codec, 0, sizeof(struct ac97_codec)); + + /* initialize some basic codec information, other fields will be filled + in ac97_probe_codec */ + codec->private_data = card; + codec->id = num_ac97; + + codec->codec_read = cs_ac97_get; + codec->codec_write = cs_ac97_set; + + if (ac97_probe_codec(codec) == 0) + break; + + eid = cs_ac97_get(codec, AC97_EXTENDED_ID); + + if(eid==0xFFFFFF) + { + printk(KERN_WARNING "cs461x: no codec attached ?\n"); + kfree(codec); + break; + } + + card->ac97_features = eid; + + + if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) { + printk(KERN_ERR "cs461x: couldn't register mixer!\n"); + kfree(codec); + break; + } + + card->ac97_codec[num_ac97] = codec; + + /* if there is no secondary codec at all, don't probe any more */ + if (!ready_2nd) + return num_ac97+1; + } + return num_ac97; +} + +/* Boot the card + */ + +static void cs461x_download(struct cs_card *card, u32 *src, unsigned long offset, unsigned long len) +{ + unsigned long counter; + void *dst; + + dst = card->ba1.idx[(offset>>16)&3]; + dst += (offset&0xFFFF)<<2; + for(counter=0;counter<len;counter+=4) + writel(*src++, dst+counter); +} + +/* 3*1024 parameter, 3.5*1024 sample, 2*3.5*1024 code */ +#define BA1_DWORD_SIZE (13 * 1024 + 512) +#define BA1_MEMORY_COUNT 3 + +struct BA1struct { + struct { + unsigned long offset; + unsigned long size; + } memory[BA1_MEMORY_COUNT]; + unsigned int map[BA1_DWORD_SIZE]; +}; + +#include "cs461x_image.h" + +static void cs461x_download_image(struct cs_card *card) +{ + int idx; + unsigned long offset = 0; + + for (idx = 0; idx < BA1_MEMORY_COUNT; idx++) { + cs461x_download(card,&BA1Struct.map[offset], + BA1Struct.memory[idx].offset, + BA1Struct.memory[idx].size); + offset += BA1Struct.memory[idx].size >> 2; + } +} + +/* + * Chip reset + */ + +static void cs461x_reset(struct cs_card *card) +{ + int idx; + + /* + * Write the reset bit of the SP control register. + */ + cs461x_poke(card, BA1_SPCR, SPCR_RSTSP); + + /* + * Write the control register. + */ + cs461x_poke(card, BA1_SPCR, SPCR_DRQEN); + + /* + * Clear the trap registers. + */ + for (idx = 0; idx < 8; idx++) { + cs461x_poke(card, BA1_DREG, DREG_REGID_TRAP_SELECT + idx); + cs461x_poke(card, BA1_TWPR, 0xFFFF); + } + cs461x_poke(card, BA1_DREG, 0); + + /* + * Set the frame timer to reflect the number of cycles per frame. + */ + cs461x_poke(card, BA1_FRMT, 0xadf); +} + +static void cs461x_clear_serial_FIFOs(struct cs_card *card) +{ + int idx, loop, powerdown = 0; + unsigned int tmp; + + /* + * See if the devices are powered down. If so, we must power them up first + * or they will not respond. + */ + if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) { + cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE); + powerdown = 1; + } + + /* + * We want to clear out the serial port FIFOs so we don't end up playing + * whatever random garbage happens to be in them. We fill the sample FIFOS + * with zero (silence). + */ + cs461x_pokeBA0(card, BA0_SERBWP, 0); + + /* + * Fill all 256 sample FIFO locations. + */ + for (idx = 0; idx < 256; idx++) { + /* + * Make sure the previous FIFO write operation has completed. + */ + for (loop = 0; loop < 5; loop++) { + udelay(50); + if (!(cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY)) + break; + } + if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) { + if (powerdown) + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + } + /* + * Write the serial port FIFO index. + */ + cs461x_pokeBA0(card, BA0_SERBAD, idx); + /* + * Tell the serial port to load the new value into the FIFO location. + */ + cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC); + } + /* + * Now, if we powered up the devices, then power them back down again. + * This is kinda ugly, but should never happen. + */ + if (powerdown) + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); +} + +static void cs461x_powerup_dac(struct cs_card *card) +{ + int count; + unsigned int tmp; + + /* + * Power on the DACs on the AC97 card. We turn off the DAC + * powerdown bit and write the new value of the power control + * register. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & 2) /* already */ + return; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfdff); + + /* + * Now, we wait until we sample a DAC ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(50); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2)) + printk(KERN_WARNING "cs461x: powerup DAC failed\n"); +} + +static void cs461x_powerup_adc(struct cs_card *card) +{ + int count; + unsigned int tmp; + + /* + * Power on the ADCs on the AC97 card. We turn off the DAC + * powerdown bit and write the new value of the power control + * register. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & 1) /* already */ + return; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfeff); + + /* + * Now, we wait until we sample a ADC ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(50); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1)) + printk(KERN_WARNING "cs461x: powerup ADC failed\n"); +} + +static void cs461x_proc_start(struct cs_card *card) +{ + int cnt; + + /* + * Set the frame timer to reflect the number of cycles per frame. + */ + cs461x_poke(card, BA1_FRMT, 0xadf); + /* + * Turn on the run, run at frame, and DMA enable bits in the local copy of + * the SP control register. + */ + cs461x_poke(card, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN); + /* + * Wait until the run at frame bit resets itself in the SP control + * register. + */ + for (cnt = 0; cnt < 25; cnt++) { + udelay(50); + if (!(cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR)) + break; + } + + if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR) + printk(KERN_WARNING "cs461x: SPCR_RUNFR never reset\n"); +} + +static void cs461x_proc_stop(struct cs_card *card) +{ + /* + * Turn off the run, run at frame, and DMA enable bits in the local copy of + * the SP control register. + */ + cs461x_poke(card, BA1_SPCR, 0); +} + + + +static int cs_hardware_init(struct cs_card *card) +{ + unsigned long end_time; + unsigned int tmp; + + /* + * First, blast the clock control register to zero so that the PLL starts + * out in a known state, and blast the master serial port control register + * to zero so that the serial ports also start out in a known state. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, 0); + cs461x_pokeBA0(card, BA0_SERMC1, 0); + + /* + * If we are in AC97 mode, then we must set the part to a host controlled + * AC-link. Otherwise, we won't be able to bring up the link. + */ + cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_1_03); /* 1.03 card */ + /* cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_2_0); */ /* 2.00 card */ + + /* + * Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97 + * spec) and then drive it high. This is done for non AC97 modes since + * there might be logic external to the CS461x that uses the ARST# line + * for a reset. + */ + cs461x_pokeBA0(card, BA0_ACCTL, 0); + udelay(500); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN); + + /* + * The first thing we do here is to enable sync generation. As soon + * as we start receiving bit clock, we'll start producing the SYNC + * signal. + */ + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN); + + /* + * Now wait for a short while to allow the AC97 part to start + * generating bit clock (so we don't try to start the PLL without an + * input clock). + */ + mdelay(10); /* 1 should be enough ?? */ + + /* + * Set the serial port timing configuration, so that + * the clock control circuit gets its clock from the correct place. + */ + cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97); + + /* + * Write the selected clock control setup to the hardware. Do not turn on + * SWCE yet (if requested), so that the devices clocked by the output of + * PLL are not clocked until the PLL is stable. + */ + cs461x_pokeBA0(card, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ); + cs461x_pokeBA0(card, BA0_PLLM, 0x3a); + cs461x_pokeBA0(card, BA0_CLKCR2, CLKCR2_PDIVS_8); + + /* + * Power up the PLL. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, CLKCR1_PLLP); + + /* + * Wait until the PLL has stabilized. + */ + mdelay(100); /* Again 1 should be enough ?? */ + + /* + * Turn on clocking of the core so that we can setup the serial ports. + */ + tmp = cs461x_peekBA0(card, BA0_CLKCR1) | CLKCR1_SWCE; + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + + /* + * Fill the serial port FIFOs with silence. + */ + cs461x_clear_serial_FIFOs(card); + + /* + * Set the serial port FIFO pointer to the first sample in the FIFO. + */ + /* cs461x_pokeBA0(card, BA0_SERBSP, 0); */ + + /* + * Write the serial port configuration to the part. The master + * enable bit is not set until all other values have been written. + */ + cs461x_pokeBA0(card, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN); + cs461x_pokeBA0(card, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN); + cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE); + + + mdelay(5); /* Shouldnt be needed ?? */ + + /* + * Wait for the card ready signal from the AC97 card. + */ + end_time = jiffies + 3 * (HZ >> 2); + do { + /* + * Read the AC97 status register to see if we've seen a CODEC READY + * signal from the AC97 card. + */ + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + + /* + * Make sure CODEC is READY. + */ + if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) { + printk(KERN_WARNING "cs461x: create - never read card ready from AC'97\n"); + printk(KERN_WARNING "cs461x: it is probably not a bug, try using the CS4232 driver\n"); + return -EIO; + } + + /* + * Assert the vaid frame signal so that we can start sending commands + * to the AC97 card. + */ + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); + + /* + * Wait until we've sampled input slots 3 and 4 as valid, meaning that + * the card is pumping ADC data across the AC-link. + */ + end_time = jiffies + 3 * (HZ >> 2); + do { + /* + * Read the input slot valid register and see if input slots 3 and + * 4 are valid yet. + */ + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + + /* + * Make sure input slots 3 and 4 are valid. If not, then return + * an error. + */ + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) { + printk(KERN_WARNING "cs461x: create - never read ISV3 & ISV4 from AC'97\n"); + return -EIO; + } + + /* + * Now, assert valid frame and the slot 3 and 4 valid bits. This will + * commense the transfer of digital audio data to the AC97 card. + */ + cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4); + + /* + * Power down the DAC and ADC. We will power them up (if) when we need + * them. + */ + /* cs461x_pokeBA0(card, BA0_AC97_POWERDOWN, 0x300); */ + + /* + * Turn off the Processor by turning off the software clock enable flag in + * the clock control register. + */ + /* tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; */ + /* cs461x_pokeBA0(card, BA0_CLKCR1, tmp); */ + + /* + * Reset the processor. + */ + cs461x_reset(card); + + /* + * Download the image to the processor. + */ + + cs461x_download_image(card); + + /* + * Stop playback DMA. + */ + tmp = cs461x_peek(card, BA1_PCTL); + card->pctl = tmp & 0xffff0000; + cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff); + + /* + * Stop capture DMA. + */ + tmp = cs461x_peek(card, BA1_CCTL); + card->cctl = tmp & 0x0000ffff; + cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); + + /* initialize AC97 codec and register /dev/mixer */ + if (cs_ac97_init(card) <= 0) + return -EIO; + + mdelay(5); /* Do we need this ?? */ + + cs461x_powerup_adc(card); + cs461x_powerup_dac(card); + + cs461x_proc_start(card); + + /* + * Enable interrupts on the part. + */ + cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM); + + tmp = cs461x_peek(card, BA1_PFIE); + tmp &= ~0x0000f03f; + cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt enable */ + + tmp = cs461x_peek(card, BA1_CIE); + tmp &= ~0x0000003f; + tmp |= 0x00000001; + cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */ + return 0; +} + +/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered + until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ + + +/* + * Card subid table + */ + +struct cs_card_type +{ + u16 vendor; + u16 id; + char *name; + void (*amp)(struct cs_card *, int); + void (*active)(struct cs_card *, int); +}; + +static struct cs_card_type __init cards[]={ + {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL}, + {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL}, + /* MI6020/21 use the same chipset as the Thinkpads, maybe needed */ + {0x1071, 0x6003, "Mitac MI6020/21", amp_none, clkrun_hack}, + /* Not sure if the 570 needs the clkrun hack */ + {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL}, + {0, 0, NULL, NULL} +}; + +static int __init cs_install(struct pci_dev *pci_dev) +{ + struct cs_card *card; + struct cs_card_type *cp = &cards[0]; + u16 ss_card, ss_vendor; + + + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor); + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card); + + if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "cs461x: out of memory\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(*card)); + + card->ba0_addr = pci_dev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK; + card->ba1_addr = pci_dev->resource[1].start&PCI_BASE_ADDRESS_MEM_MASK; + card->pci_dev = pci_dev; + card->irq = pci_dev->irq; + card->magic = CS_CARD_MAGIC; + spin_lock_init(&card->lock); + + pci_set_master(pci_dev); + + printk(KERN_INFO "cs461x: Card found at 0x%08lx and 0x%08lx, IRQ %d\n", + card->ba0_addr, card->ba1_addr, card->irq); + + card->alloc_pcm_channel = cs_alloc_pcm_channel; + card->alloc_rec_pcm_channel = cs_alloc_rec_pcm_channel; + card->free_pcm_channel = cs_free_pcm_channel; + card->amplifier_ctrl = amp_none; + card->active_ctrl = amp_none; + + while(cp->name) + { + if(cp->vendor == ss_vendor && cp->id == ss_card) + { + card->amplifier_ctrl = cp->amp; + if(cp->active) + card->active_ctrl = cp->active; + break; + } + cp++; + } + if(cp->name==NULL) + { + printk(KERN_INFO "cs461x: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", + ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq); + } + else + { + printk(KERN_INFO "cs461x: %s at 0x%08lx/0x%08lx, IRQ %d\n", + cp->name, card->ba0_addr, card->ba1_addr, card->irq); + } + + if(card->amplifier_ctrl==NULL) + { + printk(KERN_ERR "cs461x: Unsupported configuration due to lack of documentation.\n"); + kfree(card); + return -EINVAL; + } + + if(external_amp == 1) + { + printk(KERN_INFO "cs461x: Crystal EAPD support forced on.\n"); + card->amplifier_ctrl = amp_voyetra; + } + + if(thinkpad == 1) + { + card->active_ctrl = clkrun_hack; + printk(KERN_INFO "cs461x: Activating CLKRUN hack for Thinkpad.\n"); + } + + card->active_ctrl(card, 1); + + /* claim our iospace and irq */ + + card->ba0 = ioremap(card->ba0_addr, CS461X_BA0_SIZE); + card->ba1.name.data0 = ioremap(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); + card->ba1.name.data1 = ioremap(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); + card->ba1.name.pmem = ioremap(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); + card->ba1.name.reg = ioremap(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); + + if(card->ba0 == 0 || card->ba1.name.data0 == 0 || + card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 || + card->ba1.name.reg == 0) + goto fail2; + + if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs461x", card)) { + printk(KERN_ERR "cs461x: unable to allocate irq %d\n", card->irq); + goto fail2; + } + /* register /dev/dsp */ + if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) { + printk(KERN_ERR "cs461x: unable to register dsp\n"); + goto fail; + } + + if (cs_hardware_init(card)<0) + { + unregister_sound_dsp(card->dev_audio); + goto fail; + } + card->next = devs; + devs = card; + + card->active_ctrl(card, -1); + return 0; + +fail: + free_irq(card->irq, card); +fail2: + if(card->ba0) + iounmap(card->ba0); + if(card->ba1.name.data0) + iounmap(card->ba1.name.data0); + if(card->ba1.name.data1) + iounmap(card->ba1.name.data1); + if(card->ba1.name.pmem) + iounmap(card->ba1.name.pmem); + if(card->ba1.name.reg) + iounmap(card->ba1.name.reg); + kfree(card); + return -ENODEV; + +} + +static void cs_remove(struct cs_card *card) +{ + int i; + unsigned int tmp; + + card->active_ctrl(card,1); + + tmp = cs461x_peek(card, BA1_PFIE); + tmp &= ~0x0000f03f; + tmp |= 0x00000010; + cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */ + + tmp = cs461x_peek(card, BA1_CIE); + tmp &= ~0x0000003f; + tmp |= 0x00000011; + cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */ + + /* + * Stop playback DMA. + */ + tmp = cs461x_peek(card, BA1_PCTL); + cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff); + + /* + * Stop capture DMA. + */ + tmp = cs461x_peek(card, BA1_CCTL); + cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); + + /* + * Reset the processor. + */ + cs461x_reset(card); + + cs461x_proc_stop(card); + + /* + * Power down the DAC and ADC. We will power them up (if) when we need + * them. + */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x300); + + /* + * Power down the PLL. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, 0); + + /* + * Turn off the Processor by turning off the software clock enable flag in + * the clock control register. + */ + tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + + card->active_ctrl(card,-1); + + /* free hardware resources */ + free_irq(card->irq, card); + iounmap(card->ba0); + iounmap(card->ba1.name.data0); + iounmap(card->ba1.name.data1); + iounmap(card->ba1.name.pmem); + iounmap(card->ba1.name.reg); + + /* unregister audio devices */ + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); + kfree (card->ac97_codec[i]); + } + unregister_sound_dsp(card->dev_audio); + kfree(card); +} + +MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela"); +MODULE_DESCRIPTION("Crystal SoundFusion Audio Support"); + +int __init cs_probe(void) +{ + struct pci_dev *pcidev = NULL; + int foundone=0; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + + printk(KERN_INFO "Crystal 4280/461x + AC97 Audio, version " + DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6001 , pcidev))!=NULL ) { + if (cs_install(pcidev)==0) + foundone++; + } + while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6003 , pcidev))!=NULL ) { + if (cs_install(pcidev)==0) + foundone++; + } + while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6004 , pcidev))!=NULL ) { + if (cs_install(pcidev)==0) + foundone++; + } + + printk(KERN_INFO "cs461x: Found %d audio device(s).\n", + foundone); + return foundone; +} + +#ifdef MODULE + +int init_module(void) +{ + if(cs_probe()==0) + printk(KERN_ERR "cs461x: No devices found.\n"); + return 0; +} + +void cleanup_module (void) +{ + struct cs_card *next; + while(devs) + { + next=devs->next; + cs_remove(devs); + devs=next; + } +} + +MODULE_PARM(external_amp, "i"); +MODULE_PARM(thinkpad, "i"); + +#endif diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 4c71c1265..56c1b33fa 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -160,6 +160,7 @@ typedef struct coproc_operations struct audio_driver { + struct module *owner; int (*open) (int dev, int mode); void (*close) (int dev); void (*output_block) (int dev, unsigned long buf, @@ -239,6 +240,7 @@ int *load_mixer_volumes(char *name, int *levels, int present); struct mixer_operations { + struct module *owner; char id[16]; char name[64]; int (*ioctl) (int dev, unsigned int cmd, caddr_t arg); @@ -249,6 +251,7 @@ struct mixer_operations struct synth_operations { + struct module *owner; char *id; /* Unique identifier (ASCII) max 29 char */ struct synth_info *info; int midi_dev; @@ -301,6 +304,7 @@ struct midi_input_info struct midi_operations { + struct module *owner; struct midi_info info; struct synth_operations *converter; struct midi_input_info in_info; @@ -332,6 +336,7 @@ struct sound_lowlev_timer struct sound_timer_operations { + struct module *owner; struct sound_timer_info info; int priority; int devlink; diff --git a/drivers/sound/emu10k1/8010.h b/drivers/sound/emu10k1/8010.h index 8f4526013..f79ec65cd 100644 --- a/drivers/sound/emu10k1/8010.h +++ b/drivers/sound/emu10k1/8010.h @@ -37,18 +37,23 @@ #ifndef _8010_H #define _8010_H -/* ------------------- DEFINES -------------------- */ +#include <linux/types.h> -#define EMUPAGESIZE 4096 /* don't change */ -#define RESERVED 0 -#define NUM_G 64 /* use all channels */ -#define NUM_FXSENDS 4 /* don't change */ -#define MAXPAGES (32768 * NUM_G / EMUPAGESIZE) /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */ +/* ------------------- DEFINES -------------------- */ -#define TMEMSIZE 256*1024 -#define TMEMSIZEREG 4 +#define CMD_WRITEFN0 0x0 +#define CMD_READFN0 0x1 +#define CMD_WRITEPTR 0x2 +#define CMD_READPTR 0x3 +#define CMD_SETRECSRC 0x4 +#define CMD_GETRECSRC 0x5 +#define CMD_GETVOICEPARAM 0x6 +#define CMD_SETVOICEPARAM 0x7 -#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL)) +struct mixer_private_ioctl { + u32 cmd; + u32 val[10]; +}; /************************************************************************************************/ /* PCI function 0 registers, address = <val> + PCIBASE0 */ @@ -174,14 +179,16 @@ #define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */ #define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */ #define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */ +#define HCFG_AC3ENABLE_GPSPDIF 0x00000020 /* Channels 0 and 1 replace GPSPDIF */ #define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */ /* will automatically mute their output when */ /* they are not rate-locked to the external */ /* async audio source */ #define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */ /* NOTE: This should generally never be used. */ -#define HCFG_LOCKTANKCACHE 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ +#define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ /* NOTE: This should generally never be used. */ +#define HCFG_LOCKTANKCACHE 0x01020014 #define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */ /* NOTE: This is a 'cheap' way to implement a */ /* master mute function on the mute button, and */ @@ -256,7 +263,7 @@ #define AC97_RECORDSELECT 0x1a #define AC97_RECORDGAIN 0x1c #define AC97_RECORDGAINMIC 0x1e -#define AC97_GENERALPUPOSE 0x20 +#define AC97_GENERALPURPOSE 0x20 #define AC97_3DCONTROL 0x22 #define AC97_MODEMRATE 0x24 #define AC97_POWERDOWN 0x26 @@ -335,10 +342,12 @@ #define CCCA_CURRADDR 0x18000008 #define CCR 0x09 /* Cache control register */ -#define CCR_CACHEINVALIDSIZE 0xfe000000 /* Number of invalid samples cache for this channel */ +#define CCR_CACHEINVALIDSIZE 0x07190009 +#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */ #define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */ #define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */ #define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */ +#define CCR_READADDRESS 0x06100009 #define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */ #define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */ /* NOTE: This is valid only if CACHELOOPFLAG is set */ diff --git a/drivers/sound/emu10k1/Makefile b/drivers/sound/emu10k1/Makefile index 3f4d227f1..0ae315140 100644 --- a/drivers/sound/emu10k1/Makefile +++ b/drivers/sound/emu10k1/Makefile @@ -4,21 +4,19 @@ ifeq ($(CONFIG_SOUND_EMU10K1),y) O_TARGET := emu10k1.o - O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \ emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ - osutils.o recmgr.o timer.o voicemgr.o + recmgr.o timer.o voicemgr.o else ifeq ($(CONFIG_SOUND_EMU10K1),m) M_OBJS := emu10k1.o O_TARGET := emu10k1.o - O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \ emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ - osutils.o recmgr.o timer.o voicemgr.o + recmgr.o timer.o voicemgr.o endif endif -EXTRA_CFLAGS += -I. - ifdef DEBUG EXTRA_CFLAGS += -DEMU10K1_DEBUG endif diff --git a/drivers/sound/emu10k1/audio.c b/drivers/sound/emu10k1/audio.c index 4d81c1a46..dca8d564d 100644 --- a/drivers/sound/emu10k1/audio.c +++ b/drivers/sound/emu10k1/audio.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * audio.c -- /dev/dsp interface for emu10k1 driver @@ -31,20 +30,30 @@ ********************************************************************** */ +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/poll.h> +#include <linux/malloc.h> +#include <linux/version.h> +#include <linux/bitops.h> +#include <asm/io.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/wrapper.h> + + #include "hwaccess.h" #include "cardwo.h" #include "cardwi.h" #include "recmgr.h" +#include "irqmgr.h" #include "audio.h" -#include <linux/sched.h> -#include <linux/smp_lock.h> -#include <linux/wrapper.h> static void calculate_ofrag(struct woinst *); static void calculate_ifrag(struct wiinst *); /* Audio file operations */ -static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin) +static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } @@ -53,11 +62,10 @@ static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in; ssize_t ret = 0; unsigned long flags; - DPD(4, "emu10k1_audio_read(), buffer=%p, count=%x\n", buffer, (u32) count); + DPD(3, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count); if (ppos != &file->f_pos) return -ESPIPE; @@ -67,23 +75,21 @@ static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, spin_lock_irqsave(&wiinst->lock, flags); - if (wiinst->mapped) { + if (wiinst->mmapped) { spin_unlock_irqrestore(&wiinst->lock, flags); return -ENXIO; } - if (!wiinst->wave_in) { + if (wiinst->state == WAVE_STATE_CLOSED) { calculate_ifrag(wiinst); - while (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + while (emu10k1_wavein_open(wave_dev) < 0) { spin_unlock_irqrestore(&wiinst->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&wave_dev->card->open_wait); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return -ERESTARTSYS; @@ -92,26 +98,25 @@ static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, } } - wave_in = wiinst->wave_in; - spin_unlock_irqrestore(&wiinst->lock, flags); while (count > 0) { - u32 bytestocopy, dummy; + u32 bytestocopy; spin_lock_irqsave(&wiinst->lock, flags); - if ((wave_in->state != CARDWAVE_STATE_STARTED) + if (!(wiinst->state & WAVE_STATE_STARTED) && (wave_dev->enablebits & PCM_ENABLE_INPUT)) emu10k1_wavein_start(wave_dev); - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + emu10k1_wavein_update(wave_dev->card, wiinst); + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(4, "bytestocopy --> %x\n", bytestocopy); + DPD(3, "bytestocopy --> %d\n", bytestocopy); - if ((bytestocopy >= wiinst->fragment_size) + if ((bytestocopy >= wiinst->buffer.fragment_size) || (bytestocopy >= count)) { bytestocopy = min(bytestocopy, count); @@ -127,9 +132,7 @@ static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, || (!(wave_dev->enablebits & PCM_ENABLE_INPUT))) return (ret ? ret : -EAGAIN); - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&wiinst->wait_queue); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return (ret ? ret : -ERESTARTSYS); @@ -137,7 +140,7 @@ static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, } } - DPD(4, "bytes copied -> %x\n", (u32) ret); + DPD(3, "bytes copied -> %d\n", (u32) ret); return ret; } @@ -146,13 +149,10 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; ssize_t ret; unsigned long flags; - GET_INODE_STRUCT(); - - DPD(4, "emu10k1_audio_write(), buffer=%p, count=%x\n", buffer, (u32) count); + DPD(3, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count); if (ppos != &file->f_pos) return -ESPIPE; @@ -162,23 +162,21 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t spin_lock_irqsave(&woinst->lock, flags); - if (woinst->mapped) { + if (woinst->mmapped) { spin_unlock_irqrestore(&woinst->lock, flags); return -ENXIO; } - if (!woinst->wave_out) { + if (woinst->state == WAVE_STATE_CLOSED) { calculate_ofrag(woinst); - while (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + while (emu10k1_waveout_open(wave_dev) < 0) { spin_unlock_irqrestore(&woinst->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&wave_dev->card->open_wait); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return -ERESTARTSYS; @@ -187,23 +185,20 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t } } - wave_out = woinst->wave_out; - spin_unlock_irqrestore(&woinst->lock, flags); ret = 0; while (count > 0) { - u32 bytestocopy, pending, dummy; + u32 bytestocopy; spin_lock_irqsave(&woinst->lock, flags); - - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); spin_unlock_irqrestore(&woinst->lock, flags); - DPD(4, "bytestocopy --> %x\n", bytestocopy); + DPD(3, "bytestocopy --> %d\n", bytestocopy); - if ((bytestocopy >= woinst->fragment_size) + if ((bytestocopy >= woinst->buffer.fragment_size) || (bytestocopy >= count)) { bytestocopy = min(bytestocopy, count); @@ -217,16 +212,11 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t spin_lock_irqsave(&woinst->lock, flags); woinst->total_copied += bytestocopy; - if ((wave_out->state != CARDWAVE_STATE_STARTED) + if (!(woinst->state & WAVE_STATE_STARTED) && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) - && (woinst->total_copied >= woinst->fragment_size)) { + && (woinst->total_copied >= woinst->buffer.fragment_size)) + emu10k1_waveout_start(wave_dev); - if (emu10k1_waveout_start(wave_dev) != CTSTATUS_SUCCESS) { - spin_unlock_irqrestore(&woinst->lock, flags); - ERROR(); - return -EFAULT; - } - } spin_unlock_irqrestore(&woinst->lock, flags); } @@ -235,16 +225,14 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT))) return (ret ? ret : -EAGAIN); - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&woinst->wait_queue); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return (ret ? ret : -ERESTARTSYS); } } - DPD(4, "bytes copied -> %x\n", (u32) ret); + DPD(3, "bytes copied -> %d\n", (u32) ret); return ret; } @@ -252,29 +240,19 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; - int val = 0; struct woinst *woinst = NULL; - struct wave_out *wave_out = NULL; struct wiinst *wiinst = NULL; - struct wave_in *wave_in = NULL; - u32 pending, bytestocopy, dummy; + int val = 0; + u32 bytestocopy; unsigned long flags; DPF(4, "emu10k1_audio_ioctl()\n"); - if (file->f_mode & FMODE_WRITE) { + if (file->f_mode & FMODE_WRITE) woinst = wave_dev->woinst; - spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - spin_unlock_irqrestore(&woinst->lock, flags); - } - if (file->f_mode & FMODE_READ) { + if (file->f_mode & FMODE_READ) wiinst = wave_dev->wiinst; - spin_lock_irqsave(&wiinst->lock, flags); - wave_in = wiinst->wave_in; - spin_unlock_irqrestore(&wiinst->lock, flags); - } switch (cmd) { case OSS_GETVERSION: @@ -288,13 +266,22 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); - if (wave_out) + if (woinst->state & WAVE_STATE_OPEN) { + if (woinst->mmapped) { + int i; + + /* Undo marking the pages as reserved */ + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); + } + emu10k1_waveout_close(wave_dev); + } + woinst->mmapped = 0; woinst->total_copied = 0; woinst->total_played = 0; woinst->blocks = 0; - woinst->curpos = 0; spin_unlock_irqrestore(&woinst->lock, flags); } @@ -302,12 +289,12 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); + wiinst->mmapped = 0; wiinst->total_recorded = 0; wiinst->blocks = 0; - wiinst->curpos = 0; spin_unlock_irqrestore(&wiinst->lock, flags); } @@ -318,10 +305,11 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (file->f_mode & FMODE_WRITE) { - if (wave_out) { - spin_lock_irqsave(&woinst->lock, flags); + spin_lock_irqsave(&woinst->lock, flags); + + if (woinst->state & WAVE_STATE_OPEN) { - if (wave_out->state == CARDWAVE_STATE_STARTED) + if (woinst->state & WAVE_STATE_STARTED) while ((woinst->total_played < woinst->total_copied) && !signal_pending(current)) { spin_unlock_irqrestore(&woinst->lock, flags); @@ -329,25 +317,34 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned spin_lock_irqsave(&woinst->lock, flags); } - emu10k1_waveout_close(wave_dev); - woinst->total_copied = 0; - woinst->total_played = 0; - woinst->blocks = 0; - woinst->curpos = 0; + if (woinst->mmapped) { + int i; - spin_unlock_irqrestore(&woinst->lock, flags); + /* Undo marking the pages as reserved */ + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); + } + + emu10k1_waveout_close(wave_dev); } + + woinst->mmapped = 0; + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + + spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); + wiinst->mmapped = 0; wiinst->total_recorded = 0; wiinst->blocks = 0; - wiinst->curpos = 0; spin_unlock_irqrestore(&wiinst->lock, flags); } @@ -367,43 +364,49 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned get_user_ret(val, (int *) arg, -EFAULT); DPD(2, "val is %d\n", val); - if (val >= 0) { - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (val > 0) { + if (file->f_mode & FMODE_READ) { + struct wave_format format; - woinst->wave_fmt.samplingrate = val; + spin_lock_irqsave(&wiinst->lock, flags); + + format = wiinst->format; + format.samplingrate = val; - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.samplingrate; + val = wiinst->format.samplingrate; - spin_unlock_irqrestore(&woinst->lock, flags); + spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set playback sampling rate -> %d\n", val); + DPD(2, "set recording sampling rate -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; + + spin_lock_irqsave(&woinst->lock, flags); - wiinst->wave_fmt.samplingrate = val; + format = woinst->format; + format.samplingrate = val; - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.samplingrate; + val = woinst->format.samplingrate; - spin_unlock_irqrestore(&wiinst->lock, flags); + spin_unlock_irqrestore(&woinst->lock, flags); - DPD(2, "set recording sampling rate -> %d\n", val); + DPD(2, "set playback sampling rate -> %d\n", val); } return put_user(val, (int *) arg); } else { if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.samplingrate; + val = wiinst->format.samplingrate; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.samplingrate; + val = woinst->format.samplingrate; return put_user(val, (int *) arg); } @@ -415,33 +418,39 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned get_user_ret(val, (int *) arg, -EFAULT); DPD(2, " val is %d\n", val); - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (file->f_mode & FMODE_READ) { + struct wave_format format; - woinst->wave_fmt.channels = val ? 2 : 1; + spin_lock_irqsave(&wiinst->lock, flags); - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + format = wiinst->format; + format.channels = val ? 2 : 1; + + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.channels - 1; + val = wiinst->format.channels - 1; - spin_unlock_irqrestore(&woinst->lock, flags); - - DPD(2, "set playback stereo -> %d\n", val); + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording stereo -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; + + spin_lock_irqsave(&woinst->lock, flags); - wiinst->wave_fmt.channels = val ? 2 : 1; + format = woinst->format; + format.channels = val ? 2 : 1; - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.channels - 1; + val = woinst->format.channels - 1; - spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set recording stereo -> %d\n", val); + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(2, "set playback stereo -> %d\n", val); } return put_user(val, (int *) arg); @@ -454,41 +463,47 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned get_user_ret(val, (int *) arg, -EFAULT); DPD(2, " val is %d\n", val); - if (val != 0) { - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (val > 0) { + if (file->f_mode & FMODE_READ) { + struct wave_format format; + + spin_lock_irqsave(&wiinst->lock, flags); - woinst->wave_fmt.channels = val; + format = wiinst->format; + format.channels = val; - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.channels; + val = wiinst->format.channels; - spin_unlock_irqrestore(&woinst->lock, flags); - DPD(2, "set playback number of channels -> %d\n", val); + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording number of channels -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; + + spin_lock_irqsave(&woinst->lock, flags); - wiinst->wave_fmt.channels = val; + format = woinst->format; + format.channels = val; - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.channels; + val = woinst->format.channels; - spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set recording number of channels -> %d\n", val); + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback number of channels -> %d\n", val); } return put_user(val, (int *) arg); } else { if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.channels; + val = wiinst->format.channels; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.channels; + val = woinst->format.channels; return put_user(val, (int *) arg); } @@ -511,40 +526,46 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned DPD(2, " val is %d\n", val); if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (file->f_mode & FMODE_READ) { + struct wave_format format; + + spin_lock_irqsave(&wiinst->lock, flags); - woinst->wave_fmt.bitsperchannel = val; + format = wiinst->format; + format.bitsperchannel = val; - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.bitsperchannel; + val = wiinst->format.bitsperchannel; - spin_unlock_irqrestore(&woinst->lock, flags); - DPD(2, "set playback sample size -> %d\n", val); + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording sample size -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; - wiinst->wave_fmt.bitsperchannel = val; + spin_lock_irqsave(&woinst->lock, flags); - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + format = woinst->format; + format.bitsperchannel = val; + + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.bitsperchannel; + val = woinst->format.bitsperchannel; - spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set recording sample size -> %d\n", val); + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback sample size -> %d\n", val); } return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); } else { if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.bitsperchannel; + val = wiinst->format.bitsperchannel; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.bitsperchannel; + val = woinst->format.bitsperchannel; return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); } @@ -553,27 +574,27 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned case SOUND_PCM_READ_BITS: if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.bitsperchannel; + val = wiinst->format.bitsperchannel; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.bitsperchannel; + val = woinst->format.bitsperchannel; return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); case SOUND_PCM_READ_RATE: if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.samplingrate; + val = wiinst->format.samplingrate; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.samplingrate; + val = woinst->format.samplingrate; return put_user(val, (int *) arg); case SOUND_PCM_READ_CHANNELS: if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.channels; + val = wiinst->format.channels; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.channels; + val = woinst->format.channels; return put_user(val, (int *) arg); @@ -594,6 +615,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)) val |= PCM_ENABLE_OUTPUT; + if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT)) val |= PCM_ENABLE_INPUT; @@ -609,11 +631,11 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (val & PCM_ENABLE_OUTPUT) { wave_dev->enablebits |= PCM_ENABLE_OUTPUT; - if (wave_out) + if (woinst->state & WAVE_STATE_OPEN) emu10k1_waveout_start(wave_dev); } else { wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT; - if (wave_out) + if (woinst->state & WAVE_STATE_STARTED) emu10k1_waveout_stop(wave_dev); } @@ -625,11 +647,11 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (val & PCM_ENABLE_INPUT) { wave_dev->enablebits |= PCM_ENABLE_INPUT; - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_start(wave_dev); } else { wave_dev->enablebits &= ~PCM_ENABLE_INPUT; - if (wave_in) + if (wiinst->state & WAVE_STATE_STARTED) emu10k1_wavein_stop(wave_dev); } @@ -646,23 +668,21 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (wave_out) { - spin_lock_irqsave(&woinst->lock, flags); - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - spin_unlock_irqrestore(&woinst->lock, flags); + spin_lock_irqsave(&woinst->lock, flags); + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); info.bytes = bytestocopy; } else { - spin_lock_irqsave(&woinst->lock, flags); calculate_ofrag(woinst); - spin_unlock_irqrestore(&woinst->lock, flags); - - info.bytes = woinst->numfrags * woinst->fragment_size; + info.bytes = woinst->buffer.size; } + spin_unlock_irqrestore(&woinst->lock, flags); - info.fragstotal = woinst->numfrags; - info.fragments = info.bytes / woinst->fragment_size; - info.fragsize = woinst->fragment_size; + info.fragstotal = woinst->buffer.numfrags; + info.fragments = info.bytes / woinst->buffer.fragment_size; + info.fragsize = woinst->buffer.fragment_size; if (copy_to_user((int *) arg, &info, sizeof(info))) return -EFAULT; @@ -678,23 +698,20 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (wave_in) { - spin_lock_irqsave(&wiinst->lock, flags); - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); - spin_unlock_irqrestore(&wiinst->lock, flags); - + spin_lock_irqsave(&wiinst->lock, flags); + if (wiinst->state & WAVE_STATE_OPEN) { + emu10k1_wavein_update(wave_dev->card, wiinst); + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); info.bytes = bytestocopy; } else { - spin_lock_irqsave(&wiinst->lock, flags); calculate_ifrag(wiinst); - spin_unlock_irqrestore(&wiinst->lock, flags); - info.bytes = 0; } + spin_unlock_irqrestore(&wiinst->lock, flags); - info.fragstotal = wiinst->numfrags; - info.fragments = info.bytes / wiinst->fragment_size; - info.fragsize = wiinst->fragment_size; + info.fragstotal = wiinst->buffer.numfrags; + info.fragments = info.bytes / wiinst->buffer.fragment_size; + info.fragsize = wiinst->buffer.fragment_size; if (copy_to_user((int *) arg, &info, sizeof(info))) return -EFAULT; @@ -713,15 +730,16 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (wave_out) { - spin_lock_irqsave(&woinst->lock, flags); - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - spin_unlock_irqrestore(&woinst->lock, flags); - - val = pending; + spin_lock_irqsave(&woinst->lock, flags); + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); + val = woinst->buffer.size - bytestocopy; } else val = 0; + spin_unlock_irqrestore(&woinst->lock, flags); + return put_user(val, (int *) arg); case SNDCTL_DSP_GETIPTR: @@ -735,17 +753,16 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in) { - emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, (u32 *) & cinfo.ptr); - cinfo.bytes = - cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags); - cinfo.blocks = cinfo.bytes / wiinst->fragment_size - wiinst->blocks; - wiinst->blocks = cinfo.bytes / wiinst->fragment_size; + if (wiinst->state & WAVE_STATE_OPEN) { + emu10k1_wavein_update(wave_dev->card, wiinst); + cinfo.ptr = wiinst->buffer.hw_pos; + cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % wiinst->buffer.size; + cinfo.blocks = cinfo.bytes / wiinst->buffer.fragment_size - wiinst->blocks; + wiinst->blocks = cinfo.bytes / wiinst->buffer.fragment_size; } else { cinfo.ptr = 0; cinfo.bytes = 0; cinfo.blocks = 0; - wiinst->blocks = 0; } spin_unlock_irqrestore(&wiinst->lock, flags); @@ -766,17 +783,19 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned spin_lock_irqsave(&woinst->lock, flags); - if (wave_out) { - emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, (u32 *) & cinfo.ptr); - cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags); - cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->blocks; - woinst->blocks = cinfo.bytes / woinst->fragment_size; + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + cinfo.ptr = woinst->buffer.hw_pos; + cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % woinst->buffer.size; + cinfo.blocks = cinfo.bytes / woinst->buffer.fragment_size - woinst->blocks; + woinst->blocks = cinfo.bytes / woinst->buffer.fragment_size; } else { cinfo.ptr = 0; cinfo.bytes = 0; cinfo.blocks = 0; - woinst->blocks = 0; } + if(woinst->mmapped) + woinst->buffer.bytestocopy %= woinst->buffer.fragment_size; spin_unlock_irqrestore(&woinst->lock, flags); @@ -792,7 +811,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned spin_lock_irqsave(&woinst->lock, flags); calculate_ofrag(woinst); - val = woinst->fragment_size; + val = woinst->buffer.fragment_size; spin_unlock_irqrestore(&woinst->lock, flags); } @@ -801,7 +820,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned spin_lock_irqsave(&wiinst->lock, flags); calculate_ifrag(wiinst); - val = wiinst->fragment_size; + val = wiinst->buffer.fragment_size; spin_unlock_irqrestore(&wiinst->lock, flags); } @@ -811,7 +830,17 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned break; case SNDCTL_DSP_POST: - DPF(2, "SNDCTL_DSP_POST: not implemented\n"); + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + if (!(woinst->state & WAVE_STATE_STARTED) + && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) + && (woinst->total_copied > 0)) + emu10k1_waveout_start(wave_dev); + + spin_unlock_irqrestore(&woinst->lock, flags); + } + break; case SNDCTL_DSP_SUBDIVIDE: @@ -823,25 +852,25 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned get_user_ret(val, (int *) arg, -EFAULT); - DPD(2, "val is %x\n", val); + DPD(2, "val is 0x%x\n", val); if (val == 0) return -EIO; if (file->f_mode & FMODE_WRITE) { - if (wave_out) + if (woinst->state & WAVE_STATE_OPEN) return -EINVAL; /* too late to change */ - woinst->ossfragshift = val & 0xffff; - woinst->numfrags = (val >> 16) & 0xffff; + woinst->buffer.ossfragshift = val & 0xffff; + woinst->buffer.numfrags = (val >> 16) & 0xffff; } if (file->f_mode & FMODE_READ) { - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) return -EINVAL; /* too late to change */ - wiinst->ossfragshift = val & 0xffff; - wiinst->numfrags = (val >> 16) & 0xffff; + wiinst->buffer.ossfragshift = val & 0xffff; + wiinst->buffer.numfrags = (val >> 16) & 0xffff; } break; @@ -859,15 +888,15 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned if ((buf.command != 1) && (buf.command != 2)) return -EINVAL; - if (((buf.offs < 0x100) && (buf.command == 2)) + if ((buf.offs < 0x100) || (buf.offs < 0x000) || (buf.offs + buf.len > 0x800) || (buf.len > 1000)) return -EINVAL; if (buf.command == 1) { for (i = 0; i < buf.len; i++) - ((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0); + if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf))) return -EFAULT; } else { @@ -878,7 +907,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned } default: /* Default is unrecognized command */ - DPD(2, "default: %x\n", cmd); + DPD(2, "default: 0x%x\n", cmd); return -EINVAL; } return 0; @@ -894,51 +923,46 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) return -ENXIO; lock_kernel(); + if (vma->vm_flags & VM_WRITE) { struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; u32 size; unsigned long flags; int i; spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - - if (!wave_out) { + if (woinst->state == WAVE_STATE_CLOSED) { calculate_ofrag(woinst); - if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + if (emu10k1_waveout_open(wave_dev) < 0) { spin_unlock_irqrestore(&woinst->lock, flags); ERROR(); unlock_kernel(); return -EINVAL; } - wave_out = woinst->wave_out; - /* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */ - for (i = 0; i < wave_out->wavexferbuf->numpages; i++) - mem_map_reserve(virt_to_page(wave_out->pagetable[i])); + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); } size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) { + if (size > (PAGE_SIZE * woinst->buffer.pages)) { spin_unlock_irqrestore(&woinst->lock, flags); unlock_kernel(); return -EINVAL; } - for (i = 0; i < wave_out->wavexferbuf->numpages; i++) { - if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) { + for (i = 0; i < woinst->buffer.pages; i++) { + if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(woinst->buffer.addr[i]), PAGE_SIZE, vma->vm_page_prot)) { spin_unlock_irqrestore(&woinst->lock, flags); - unlock_kernel(); return -EAGAIN; } } - woinst->mapped = 1; + woinst->mmapped = 1; spin_unlock_irqrestore(&woinst->lock, flags); } @@ -948,9 +972,10 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) unsigned long flags; spin_lock_irqsave(&wiinst->lock, flags); - wiinst->mapped = 1; + wiinst->mmapped = 1; spin_unlock_irqrestore(&wiinst->lock, flags); } + unlock_kernel(); return 0; @@ -970,7 +995,7 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) list_for_each(entry, &emu10k1_devs) { card = list_entry(entry, struct emu10k1_card, list); - if (card->audio1_num == minor || card->audio2_num == minor) + if (!((card->audio_num ^ minor) & ~0xf) || !((card->audio1_num ^ minor) & ~0xf)) break; } @@ -988,6 +1013,56 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) wave_dev->woinst = NULL; wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* Default */ + if (file->f_mode & FMODE_READ) { + /* Recording */ + struct wiinst *wiinst; + + if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { + ERROR(); + return -ENODEV; + } + + wiinst->recsrc = card->wavein.recsrc; + wiinst->fxwc = card->wavein.fxwc; + + switch (wiinst->recsrc) { + case WAVERECORD_AC97: + wiinst->format.samplingrate = 8000; + wiinst->format.bitsperchannel = 16; + wiinst->format.channels = 1; + break; + case WAVERECORD_MIC: + wiinst->format.samplingrate = 8000; + wiinst->format.bitsperchannel = 16; + wiinst->format.channels = 1; + break; + case WAVERECORD_FX: + wiinst->format.samplingrate = 48000; + wiinst->format.bitsperchannel = 16; + wiinst->format.channels = hweight32(wiinst->fxwc); + break; + default: + BUG(); + break; + } + + wiinst->state = WAVE_STATE_CLOSED; + + wiinst->buffer.ossfragshift = 0; + wiinst->buffer.fragment_size = 0; + wiinst->buffer.numfrags = 0; + + init_waitqueue_head(&wiinst->wait_queue); + + wiinst->mmapped = 0; + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->lock = SPIN_LOCK_UNLOCKED; + tasklet_init(&wiinst->timer.tasklet, emu10k1_wavein_bh, (unsigned long) wave_dev); + wave_dev->wiinst = wiinst; + emu10k1_wavein_setformat(wave_dev, &wiinst->format); + } + if (file->f_mode & FMODE_WRITE) { struct woinst *woinst; @@ -996,24 +1071,31 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) return -ENODEV; } - woinst->wave_fmt.samplingrate = 8000; - woinst->wave_fmt.bitsperchannel = 8; - woinst->wave_fmt.channels = 1; - woinst->ossfragshift = 0; - woinst->fragment_size = 0; - woinst->numfrags = 0; - woinst->device = (card->audio2_num == minor); - woinst->wave_out = NULL; + if (wave_dev->wiinst != NULL) { + woinst->format = wave_dev->wiinst->format; + } else { + woinst->format.samplingrate = 8000; + woinst->format.bitsperchannel = 8; + woinst->format.channels = 1; + } + + woinst->state = WAVE_STATE_CLOSED; + + woinst->buffer.fragment_size = 0; + woinst->buffer.ossfragshift = 0; + woinst->buffer.numfrags = 0; + woinst->device = (card->audio1_num == minor); init_waitqueue_head(&woinst->wait_queue); - woinst->mapped = 0; + woinst->mmapped = 0; woinst->total_copied = 0; woinst->total_played = 0; woinst->blocks = 0; - woinst->curpos = 0; woinst->lock = SPIN_LOCK_UNLOCKED; + tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev); wave_dev->woinst = woinst; + emu10k1_waveout_setformat(wave_dev, &woinst->format); #ifdef PRIVATE_PCM_VOLUME { @@ -1038,69 +1120,27 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) if (i == MAX_PCM_CHANNELS) { // add new entry if (j < 0) - printk("TOO MANY WRITTERS!!!\n"); + printk(KERN_WARNING "emu10k1: too many writters!\n"); i = (j >= 0) ? j : 0; DPD(2, "new pcm private %p\n", current->files); sblive_pcm_volume[i].files = current->files; - sblive_pcm_volume[i].mixer = 0x6464; // max + sblive_pcm_volume[i].mixer = pcm_last_mixer; sblive_pcm_volume[i].attn_l = 0; sblive_pcm_volume[i].attn_r = 0; sblive_pcm_volume[i].channel_l = NUM_G; sblive_pcm_volume[i].channel_r = NUM_G; - } + } else + DPD(2, "old pcm private %p 0x%x\n", current->files, + sblive_pcm_volume[i].mixer); + sblive_pcm_volume[i].opened++; } #endif } - if (file->f_mode & FMODE_READ) { - /* Recording */ - struct wiinst *wiinst; - - if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { - ERROR(); - return -ENODEV; - } - - switch (card->wavein->recsrc) { - case WAVERECORD_AC97: - wiinst->wave_fmt.samplingrate = 8000; - wiinst->wave_fmt.bitsperchannel = 8; - wiinst->wave_fmt.channels = 1; - break; - case WAVERECORD_MIC: - wiinst->wave_fmt.samplingrate = 8000; - wiinst->wave_fmt.bitsperchannel = 8; - wiinst->wave_fmt.channels = 1; - break; - case WAVERECORD_FX: - wiinst->wave_fmt.samplingrate = 48000; - wiinst->wave_fmt.bitsperchannel = 16; - wiinst->wave_fmt.channels = 2; - break; - default: - break; - } - - wiinst->recsrc = card->wavein->recsrc; - wiinst->ossfragshift = 0; - wiinst->fragment_size = 0; - wiinst->numfrags = 0; - wiinst->wave_in = NULL; - - init_waitqueue_head(&wiinst->wait_queue); - - wiinst->mapped = 0; - wiinst->total_recorded = 0; - wiinst->blocks = 0; - wiinst->curpos = 0; - wiinst->lock = SPIN_LOCK_UNLOCKED; - wave_dev->wiinst = wiinst; - } - file->private_data = (void *) wave_dev; - return 0; /* Success? */ + return 0; } static int emu10k1_audio_release(struct inode *inode, struct file *file) @@ -1111,37 +1151,35 @@ static int emu10k1_audio_release(struct inode *inode, struct file *file) lock_kernel(); card = wave_dev->card; + DPF(2, "emu10k1_audio_release()\n"); if (file->f_mode & FMODE_WRITE) { struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - - if (wave_out) { - if ((wave_out->state == CARDWAVE_STATE_STARTED) - && !(file->f_flags & O_NONBLOCK)) { - while (!signal_pending(current) - && (woinst->total_played < woinst->total_copied)) { - DPF(4, "Buffer hasn't been totally played, sleep....\n"); - spin_unlock_irqrestore(&woinst->lock, flags); - interruptible_sleep_on(&woinst->wait_queue); - spin_lock_irqsave(&woinst->lock, flags); + if (woinst->state & WAVE_STATE_OPEN) { + if (woinst->state & WAVE_STATE_STARTED) { + if (!(file->f_flags & O_NONBLOCK)) { + while (!signal_pending(current) + && (woinst->total_played < woinst->total_copied)) { + DPF(4, "Buffer hasn't been totally played, sleep....\n"); + spin_unlock_irqrestore(&woinst->lock, flags); + interruptible_sleep_on(&woinst->wait_queue); + spin_lock_irqsave(&woinst->lock, flags); + } } } - if (woinst->mapped && wave_out->pagetable) { + if (woinst->mmapped) { int i; /* Undo marking the pages as reserved */ - for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++) - mem_map_reserve(virt_to_page(woinst->wave_out->pagetable[i])); + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); } - woinst->mapped = 0; emu10k1_waveout_close(wave_dev); } #ifdef PRIVATE_PCM_VOLUME @@ -1159,22 +1197,21 @@ static int emu10k1_audio_release(struct inode *inode, struct file *file) } #endif spin_unlock_irqrestore(&woinst->lock, flags); + /* wait for the tasklet (bottom-half) to finish */ + tasklet_unlock_wait(&woinst->timer.tasklet); kfree(wave_dev->woinst); } if (file->f_mode & FMODE_READ) { struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in; spin_lock_irqsave(&wiinst->lock, flags); - wave_in = wiinst->wave_in; - - if (wave_in) { - wiinst->mapped = 0; + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); - } + spin_unlock_irqrestore(&wiinst->lock, flags); + tasklet_unlock_wait(&wiinst->timer.tasklet); kfree(wave_dev->wiinst); } @@ -1192,7 +1229,7 @@ static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_stru struct woinst *woinst = wave_dev->woinst; struct wiinst *wiinst = wave_dev->wiinst; unsigned int mask = 0; - u32 bytestocopy, pending, dummy; + u32 bytestocopy; unsigned long flags; DPF(4, "emu10k1_audio_poll()\n"); @@ -1204,49 +1241,44 @@ static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_stru poll_wait(file, &wiinst->wait_queue, wait); if (file->f_mode & FMODE_WRITE) { - struct wave_out *wave_out; - spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - - if (wave_out) { + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - - if (bytestocopy >= woinst->fragment_size) + if (bytestocopy >= woinst->buffer.fragment_size) mask |= POLLOUT | POLLWRNORM; } else mask |= POLLOUT | POLLWRNORM; + if(woinst->mmapped) { + spin_unlock_irqrestore(&woinst->lock, flags); + return mask; + } + spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { - struct wave_in *wave_in; - spin_lock_irqsave(&wiinst->lock, flags); - wave_in = wiinst->wave_in; - - if (!wave_in) { + if (wiinst->state == WAVE_STATE_CLOSED) { calculate_ifrag(wiinst); - if (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + if (emu10k1_wavein_open(wave_dev) < 0) { spin_unlock_irqrestore(&wiinst->lock, flags); return (mask |= POLLERR); } - - wave_in = wiinst->wave_in; } - if (wave_in->state != CARDWAVE_STATE_STARTED) { + if (!(wiinst->state & WAVE_STATE_STARTED)) { wave_dev->enablebits |= PCM_ENABLE_INPUT; emu10k1_wavein_start(wave_dev); } + emu10k1_wavein_update(wave_dev->card, wiinst); + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); - - if (bytestocopy >= wiinst->fragment_size) + if (bytestocopy >= wiinst->buffer.fragment_size) mask |= POLLIN | POLLRDNORM; spin_unlock_irqrestore(&wiinst->lock, flags); @@ -1257,136 +1289,169 @@ static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_stru static void calculate_ofrag(struct woinst *woinst) { - u32 fragsize, bytespersec; + struct waveout_buffer *buffer = &woinst->buffer; + u32 fragsize; - if (woinst->fragment_size) + if (buffer->fragment_size) return; - bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitsperchannel >> 3) * woinst->wave_fmt.samplingrate; - - if (!woinst->ossfragshift) { - fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1; + if (!buffer->ossfragshift) { + fragsize = (woinst->format.bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1; while (fragsize) { fragsize >>= 1; - woinst->ossfragshift++; + buffer->ossfragshift++; } } - if (woinst->ossfragshift < WAVEOUT_MINFRAGSHIFT) - woinst->ossfragshift = WAVEOUT_MINFRAGSHIFT; + if (buffer->ossfragshift < WAVEOUT_MINFRAGSHIFT) + buffer->ossfragshift = WAVEOUT_MINFRAGSHIFT; - woinst->fragment_size = 1 << woinst->ossfragshift; + buffer->fragment_size = 1 << buffer->ossfragshift; - if (!woinst->numfrags) { + if (!buffer->numfrags) { u32 numfrags; - numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN) / (woinst->fragment_size * 1000) - 1; + numfrags = (woinst->format.bytespersec * WAVEOUT_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1; - woinst->numfrags = 1; + buffer->numfrags = 1; while (numfrags) { numfrags >>= 1; - woinst->numfrags <<= 1; + buffer->numfrags <<= 1; } } - if (woinst->numfrags < MINFRAGS) - woinst->numfrags = MINFRAGS; + if (buffer->numfrags < MINFRAGS) + buffer->numfrags = MINFRAGS; - if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE) { - woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size; + if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE) { + buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size; - if (woinst->numfrags < MINFRAGS) { - woinst->numfrags = MINFRAGS; - woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS; + if (buffer->numfrags < MINFRAGS) { + buffer->numfrags = MINFRAGS; + buffer->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS; } - } else if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE) - woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size; + } else if (buffer->numfrags * buffer->fragment_size < WAVEOUT_MINBUFSIZE) + buffer->numfrags = WAVEOUT_MINBUFSIZE / buffer->fragment_size; + + buffer->size = buffer->fragment_size * buffer->numfrags; + buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0); - DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size); - DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags); + DPD(2, " calculated playback fragment_size -> %d\n", buffer->fragment_size); + DPD(2, " calculated playback numfrags -> %d\n", buffer->numfrags); + + return; } static void calculate_ifrag(struct wiinst *wiinst) { - u32 fragsize, bytespersec; + struct wavein_buffer *buffer = &wiinst->buffer; + u32 fragsize, bufsize, size[4]; + int i, j; - if (wiinst->fragment_size) + if (buffer->fragment_size) return; - bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitsperchannel >> 3) * wiinst->wave_fmt.samplingrate; - - if (!wiinst->ossfragshift) { - fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1; + if (!buffer->ossfragshift) { + fragsize = (wiinst->format.bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1; while (fragsize) { fragsize >>= 1; - wiinst->ossfragshift++; + buffer->ossfragshift++; } } - if (wiinst->ossfragshift < WAVEIN_MINFRAGSHIFT) - wiinst->ossfragshift = WAVEIN_MINFRAGSHIFT; + if (buffer->ossfragshift < WAVEIN_MINFRAGSHIFT) + buffer->ossfragshift = WAVEIN_MINFRAGSHIFT; - wiinst->fragment_size = 1 << wiinst->ossfragshift; + buffer->fragment_size = 1 << buffer->ossfragshift; - if (!wiinst->numfrags) - wiinst->numfrags = (bytespersec * WAVEIN_DEFAULTBUFLEN) / (wiinst->fragment_size * 1000) - 1; + if (!buffer->numfrags) + buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1; - if (wiinst->numfrags < MINFRAGS) - wiinst->numfrags = MINFRAGS; + if (buffer->numfrags < MINFRAGS) + buffer->numfrags = MINFRAGS; - if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) { - wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size; + if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE) { + buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size; - if (wiinst->numfrags < MINFRAGS) { - wiinst->numfrags = MINFRAGS; - wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS; + if (buffer->numfrags < MINFRAGS) { + buffer->numfrags = MINFRAGS; + buffer->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS; + } + } else if (buffer->numfrags * buffer->fragment_size < WAVEIN_MINBUFSIZE) + buffer->numfrags = WAVEIN_MINBUFSIZE / buffer->fragment_size; + + bufsize = buffer->fragment_size * buffer->numfrags; + + if (bufsize >= 0x10000) { + buffer->size = 0x10000; + buffer->sizeregval = 0x1f; + } else { + buffer->size = 0; + size[0] = 384; + size[1] = 448; + size[2] = 512; + size[3] = 640; + + for (i = 0; i < 8; i++) + for (j = 0; j < 4; j++) + if (bufsize >= size[j]) { + buffer->size = size[j]; + size[j] *= 2; + buffer->sizeregval = i * 4 + j + 1; + } else + goto exitloop; + exitloop: + if (buffer->size == 0) { + buffer->size = 384; + buffer->sizeregval = 0x01; } - } else if (wiinst->numfrags * wiinst->fragment_size < WAVEIN_MINBUFSIZE) - wiinst->numfrags = WAVEIN_MINBUFSIZE / wiinst->fragment_size; + } + + buffer->numfrags = buffer->size / buffer->fragment_size; + + if (buffer->size % buffer->fragment_size) + BUG(); + + DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size); + DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags); + DPD(2, " buffer size register -> 0x%2x\n", buffer->sizeregval); - DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size); - DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags); + return; } void emu10k1_wavein_bh(unsigned long refdata) { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in = wiinst->wave_in; - u32 bytestocopy, curpos; + u32 bytestocopy; unsigned long flags; spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in->state == CARDWAVE_STATE_STOPPED) { + if (!(wiinst->state & WAVE_STATE_STARTED)) { spin_unlock_irqrestore(&wiinst->lock, flags); return; } - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &curpos); - - wiinst->total_recorded += curpos - wiinst->curpos; - - if (curpos < wiinst->curpos) - wiinst->total_recorded += wiinst->fragment_size * wiinst->numfrags; - - wiinst->curpos = curpos; + emu10k1_wavein_update(wave_dev->card, wiinst); - if (wiinst->mapped) { + if (wiinst->mmapped) { spin_unlock_irqrestore(&wiinst->lock, flags); return; } + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); + spin_unlock_irqrestore(&wiinst->lock, flags); - if (bytestocopy >= wiinst->fragment_size) + if (bytestocopy >= wiinst->buffer.fragment_size) wake_up_interruptible(&wiinst->wait_queue); else - DPD(4, "Not enough transfer size, %d\n", bytestocopy); + DPD(3, "Not enough transfer size, %d\n", bytestocopy); return; } @@ -1395,53 +1460,41 @@ void emu10k1_waveout_bh(unsigned long refdata) { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out = woinst->wave_out; - u32 bytestocopy, pending, curpos; + u32 bytestocopy; unsigned long flags; spin_lock_irqsave(&woinst->lock, flags); - if (wave_out->state == CARDWAVE_STATE_STOPPED) { + if (!(woinst->state & WAVE_STATE_STARTED)) { spin_unlock_irqrestore(&woinst->lock, flags); return; } - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &curpos); - - woinst->total_played += curpos - woinst->curpos; - - if (curpos < woinst->curpos) - woinst->total_played += woinst->fragment_size * woinst->numfrags; - - woinst->curpos = curpos; - - if (woinst->mapped) { - spin_unlock_irqrestore(&woinst->lock, flags); - return; - } + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); - if (wave_out->fill_silence) { + if (woinst->buffer.fill_silence) { spin_unlock_irqrestore(&woinst->lock, flags); emu10k1_waveout_fillsilence(woinst); } else spin_unlock_irqrestore(&woinst->lock, flags); - if (bytestocopy >= woinst->fragment_size) + if (bytestocopy >= woinst->buffer.fragment_size) wake_up_interruptible(&woinst->wait_queue); else - DPD(4, "Not enough transfer size -> %x\n", bytestocopy); + DPD(3, "Not enough transfer size -> %d\n", bytestocopy); return; } struct file_operations emu10k1_audio_fops = { - owner:THIS_MODULE, - llseek:emu10k1_audio_llseek, - read:emu10k1_audio_read, - write:emu10k1_audio_write, - poll:emu10k1_audio_poll, - ioctl:emu10k1_audio_ioctl, - mmap:emu10k1_audio_mmap, - open:emu10k1_audio_open, - release:emu10k1_audio_release, + owner: THIS_MODULE, + llseek: emu10k1_audio_llseek, + read: emu10k1_audio_read, + write: emu10k1_audio_write, + poll: emu10k1_audio_poll, + ioctl: emu10k1_audio_ioctl, + mmap: emu10k1_audio_mmap, + open: emu10k1_audio_open, + release: emu10k1_audio_release, }; diff --git a/drivers/sound/emu10k1/audio.h b/drivers/sound/emu10k1/audio.h index 357479acb..2f0464c21 100644 --- a/drivers/sound/emu10k1/audio.h +++ b/drivers/sound/emu10k1/audio.h @@ -33,13 +33,16 @@ #ifndef _AUDIO_H #define _AUDIO_H -#define __NO_VERSION__ -#include <linux/module.h> -#include <linux/poll.h> -#include <asm/uaccess.h> - #define MINFRAGS 2 /* _don't_ got bellow 2 */ +struct emu10k1_wavedevice +{ + struct emu10k1_card *card; + struct wiinst *wiinst; + struct woinst *woinst; + u16 enablebits; +}; + void emu10k1_waveout_bh(unsigned long); void emu10k1_wavein_bh(unsigned long); diff --git a/drivers/sound/emu10k1/cardmi.c b/drivers/sound/emu10k1/cardmi.c index f741b9d6d..e39e8f0f8 100644 --- a/drivers/sound/emu10k1/cardmi.c +++ b/drivers/sound/emu10k1/cardmi.c @@ -31,8 +31,13 @@ ********************************************************************** */ +#include <linux/malloc.h> +#include <linux/sched.h> + #include "hwaccess.h" +#include "8010.h" #include "cardmi.h" +#include "irqmgr.h" static struct { int (*Fn) (struct emu10k1_mpuin *, u8); @@ -76,7 +81,7 @@ int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo DPF(2, "emu10k1_mpuin_open\n"); if (!(card_mpuin->status & FLAGS_AVAILABLE)) - return CTSTATUS_INUSE; + return -1; /* Copy open info and mark channel as in use */ card_mpuin->openinfo = *openinfo; @@ -93,7 +98,7 @@ int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo emu10k1_mpu_reset(card); emu10k1_mpu_acquire(card); - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpuin_close(struct emu10k1_card *card) @@ -105,7 +110,7 @@ int emu10k1_mpuin_close(struct emu10k1_card *card) /* Check if there are pending input SysEx buffers */ if (card_mpuin->firstmidiq != NULL) { ERROR(); - return CTSTATUS_ERROR; + return -1; } /* Disable RX interrupt */ @@ -116,7 +121,7 @@ int emu10k1_mpuin_close(struct emu10k1_card *card) card_mpuin->status |= FLAGS_AVAILABLE; /* set */ card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ - return CTSTATUS_SUCCESS; + return 0; } /* Adds MIDI buffer to local queue list */ @@ -134,7 +139,7 @@ int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr * if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) { /* Message lost */ - return CTSTATUS_ERROR; + return -1; } midiq->next = NULL; @@ -156,7 +161,7 @@ int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr * spin_unlock_irqrestore(&card_mpuin->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } /* First set the Time Stamp if MIDI IN has not started. */ @@ -174,7 +179,7 @@ int emu10k1_mpuin_start(struct emu10k1_card *card) if (card_mpuin->status & FLAGS_MIDM_STARTED) { DPF(2, "Time Stamp not changed\n"); } else { - while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS); + while (!emu10k1_mpu_read_data(card, &dummy)); card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */ @@ -188,7 +193,7 @@ int emu10k1_mpuin_start(struct emu10k1_card *card) emu10k1_irq_enable(card, INTE_MIDIRXENABLE); } - return CTSTATUS_SUCCESS; + return 0; } /* Disable the RX Irq. If a partial recorded buffer */ @@ -229,7 +234,7 @@ int emu10k1_mpuin_stop(struct emu10k1_card *card) } } - return CTSTATUS_SUCCESS; + return 0; } /* Disable the RX Irq. If any buffer */ @@ -259,7 +264,7 @@ int emu10k1_mpuin_reset(struct emu10k1_card *card) card_mpuin->lastmidiq = NULL; card_mpuin->status &= ~FLAGS_MIDM_STARTED; - return CTSTATUS_SUCCESS; + return 0; } /* Passes the message with the data back to the client */ @@ -302,7 +307,7 @@ int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned l /* Notify client that Sysex buffer has been sent */ emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg); - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_mpuin_bh(unsigned long refdata) @@ -344,13 +349,13 @@ int emu10k1_mpuin_irqhandler(struct emu10k1_card *card) idx = card_mpuin->qtail; while (1) { - if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) { + if (emu10k1_mpu_read_data(card, &MPUIvalue) < 0) { + break; + } else { ++count; card_mpuin->midiq[idx].data = MPUIvalue; card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ; idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE; - } else { - break; } } @@ -360,7 +365,7 @@ int emu10k1_mpuin_irqhandler(struct emu10k1_card *card) tasklet_hi_schedule(&card_mpuin->tasklet); } - return CTSTATUS_SUCCESS; + return 0; } /*****************************************************************************/ @@ -380,7 +385,7 @@ int sblive_miStateInit(struct emu10k1_mpuin *card_mpuin) card_mpuin->timestart = 0; card_mpuin->timein = 0; - return CTSTATUS_SUCCESS; + return 0; } /* FIXME: This should be a macro */ @@ -425,7 +430,7 @@ int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data) case 0x7: emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0); - return CTSTATUS_ERROR; + return -1; case 0x2: card_mpuin->laststate = card_mpuin->curstate; @@ -447,7 +452,7 @@ int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data) default: DPF(2, "BUG: default case hit\n"); - return CTSTATUS_ERROR; + return -1; } return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data); @@ -489,7 +494,7 @@ int sblive_miState3ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->data = data; @@ -520,7 +525,7 @@ int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = STIN_3BYTE; @@ -532,7 +537,7 @@ int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -573,7 +578,7 @@ int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = STIN_2BYTE; @@ -583,7 +588,7 @@ int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -615,7 +620,7 @@ int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = card_mpuin->laststate; @@ -625,7 +630,7 @@ int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -657,7 +662,7 @@ int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->data = data; @@ -689,7 +694,7 @@ int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = card_mpuin->laststate; @@ -701,7 +706,7 @@ int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -739,7 +744,7 @@ int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data) kfree(midiq); } - return CTSTATUS_ERROR; + return -1; } if (card_mpuin->firstmidiq) { @@ -775,7 +780,7 @@ int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data) kfree(midiq); } - return CTSTATUS_SUCCESS; + return 0; } if (card_mpuin->firstmidiq) { diff --git a/drivers/sound/emu10k1/cardmi.h b/drivers/sound/emu10k1/cardmi.h index f78fc1f70..bd922c017 100644 --- a/drivers/sound/emu10k1/cardmi.h +++ b/drivers/sound/emu10k1/cardmi.h @@ -34,6 +34,7 @@ #define _CARDMI_H #include "icardmid.h" +#include <linux/interrupt.h> typedef enum { diff --git a/drivers/sound/emu10k1/cardmo.c b/drivers/sound/emu10k1/cardmo.c index e7a8612d2..726a83424 100644 --- a/drivers/sound/emu10k1/cardmo.c +++ b/drivers/sound/emu10k1/cardmo.c @@ -31,8 +31,12 @@ ********************************************************************** */ +#include <linux/malloc.h> + #include "hwaccess.h" +#include "8010.h" #include "cardmo.h" +#include "irqmgr.h" /* Installs the IRQ handler for the MPU out port * * and initialize parameters */ @@ -44,7 +48,7 @@ int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinf DPF(2, "emu10k1_mpuout_open()\n"); if (!(card_mpuout->status & FLAGS_AVAILABLE)) - return CTSTATUS_INUSE; + return -1; /* Copy open info and mark channel as in use */ card_mpuout->intr = 0; @@ -57,7 +61,7 @@ int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinf emu10k1_mpu_reset(card); emu10k1_mpu_acquire(card); - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpuout_close(struct emu10k1_card *card) @@ -92,7 +96,7 @@ int emu10k1_mpuout_close(struct emu10k1_card *card) spin_unlock_irqrestore(&card_mpuout->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } /* If there isn't enough buffer space, reject Midi Buffer. * @@ -109,14 +113,14 @@ int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihd DPF(2, "emu10k1_mpuout_add_buffer()\n"); if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND) - return CTSTATUS_SUCCESS; + return 0; midihdr->flags |= MIDIBUF_INQUEUE; midihdr->flags &= ~MIDIBUF_DONE; if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) { /* Message lost */ - return CTSTATUS_NOMEMORY; + return -1; } midiq->next = NULL; @@ -143,7 +147,7 @@ int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihd spin_unlock_irqrestore(&card_mpuout->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_mpuout_bh(unsigned long refdata) @@ -151,7 +155,6 @@ void emu10k1_mpuout_bh(unsigned long refdata) struct emu10k1_card *card = (struct emu10k1_card *) refdata; struct emu10k1_mpuout *card_mpuout = card->mpuout; int cByteSent = 0; - int status; struct midi_queue *midiq; struct midi_queue *doneq = NULL; unsigned long flags; @@ -162,14 +165,12 @@ void emu10k1_mpuout_bh(unsigned long refdata) midiq = card_mpuout->firstmidiq; while (cByteSent < 4 && midiq->sizeLeft) { - status = emu10k1_mpu_write_data(card, *midiq->midibyte); - - if (status == CTSTATUS_SUCCESS) { + if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) { + DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); + } else { ++cByteSent; --midiq->sizeLeft; ++midiq->midibyte; - } else { - DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); } } @@ -225,5 +226,5 @@ int emu10k1_mpuout_irqhandler(struct emu10k1_card *card) tasklet_hi_schedule(&card_mpuout->tasklet); - return CTSTATUS_SUCCESS; + return 0; } diff --git a/drivers/sound/emu10k1/cardmo.h b/drivers/sound/emu10k1/cardmo.h index 83871185e..7026eb3a8 100644 --- a/drivers/sound/emu10k1/cardmo.h +++ b/drivers/sound/emu10k1/cardmo.h @@ -34,6 +34,7 @@ #define _CARDMO_H #include "icardmid.h" +#include <linux/interrupt.h> #define CARDMIDIOUT_STATE_DEFAULT 0x00000000 #define CARDMIDIOUT_STATE_SUSPEND 0x00000001 diff --git a/drivers/sound/emu10k1/cardwi.c b/drivers/sound/emu10k1/cardwi.c index fce4f0fdf..01f551619 100644 --- a/drivers/sound/emu10k1/cardwi.c +++ b/drivers/sound/emu10k1/cardwi.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * cardwi.c - PCM input HAL for emu10k1 driver @@ -30,7 +29,9 @@ ********************************************************************** */ +#include <linux/poll.h> #include "hwaccess.h" +#include "timer.h" #include "recmgr.h" #include "audio.h" #include "cardwi.h" @@ -41,7 +42,7 @@ void query_format(int recsrc, struct wave_format *wave_fmt) switch (recsrc) { case WAVERECORD_AC97: - if ((wave_fmt->channels != 2) && (wave_fmt->channels != 1)) + if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2)) wave_fmt->channels = 2; if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2) @@ -61,110 +62,41 @@ void query_format(int recsrc, struct wave_format *wave_fmt) else wave_fmt->samplingrate = 0x1F40; - if ((wave_fmt->bitsperchannel != 16) && (wave_fmt->bitsperchannel != 8)) + if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16)) wave_fmt->bitsperchannel = 16; break; + /* these can't be changed from the original values */ case WAVERECORD_MIC: - wave_fmt->channels = 1; - wave_fmt->samplingrate = 0x1F40; - wave_fmt->bitsperchannel = 8; - break; - case WAVERECORD_FX: - wave_fmt->channels = 2; - wave_fmt->samplingrate = 0xBB80; - wave_fmt->bitsperchannel = 16; break; default: + BUG(); break; } + wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3; + wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel; + wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate; + return; } -static int alloc_recbuffer(struct wave_in *wave_in, u32 * bufsize, u8 ** buffer) +static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer) { - u32 reqsize; - int i, j; - u32 size[4]; - - /* NOTE: record buffer size only can be certain sizes. If the requested - * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */ - if (!wave_in->rec_ptr->is_16bit) - *bufsize <<= 1; - - if (*bufsize >= 0x10000) { - *bufsize = reqsize = 0x10000; - wave_in->rec_ptr->bufsize = 31; - } else { - reqsize = 0; - size[0] = 384; - size[1] = 448; - size[2] = 512; - size[3] = 640; - - for (i = 0; i < 8; i++) - for (j = 0; j < 4; j++) - if (*bufsize >= size[j]) { - reqsize = size[j]; - size[j] = size[j] * 2; - wave_in->rec_ptr->bufsize = i * 4 + j + 1; - } else - goto exitloop; - exitloop: - if (reqsize == 0) { - reqsize = 384; - wave_in->rec_ptr->bufsize = 1; - } - - *bufsize = reqsize; - } - - DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsize); + if ((buffer->addr = pci_alloc_consistent(card->pci_dev, buffer->size * buffer->cov, &buffer->dma_handle)) == NULL) + return -1; - /* Recording buffer must be continuous and page-aligned */ - if ((wave_in->memhandle = emu10k1_alloc_memphysical(reqsize)) == NULL) - return CTSTATUS_ERROR; - - DPD(2, "recbufsize: %x\n", *bufsize); - - *buffer = (u8 *) wave_in->memhandle->virtaddx; - - return CTSTATUS_SUCCESS; + return 0; } -static int get_recbuffer(struct emu10k1_card *card, struct wave_in *wave_in, u32 * size) +static void free_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer) { - u8 *buffer; + if (buffer->addr != NULL) + pci_free_consistent(card->pci_dev, buffer->size * buffer->cov, buffer->addr, buffer->dma_handle); - wave_in->rec_ptr->card = card; - wave_in->rec_ptr->recpos = 0; - wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate; - wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0; - wave_in->rec_ptr->is_16bit = (wave_in->wave_fmt.bitsperchannel == 16) ? 1 : 0; - - /* Allocate buffer here */ - if (alloc_recbuffer(wave_in, size, &buffer) != CTSTATUS_SUCCESS) { - ERROR(); - return CTSTATUS_ERROR; - } - - /* recbufsize contains actual record buffer size */ - /* for 8 bit samples the size is twice the requested */ - /* value since we only make use of one in every two bytes */ - wave_in->rec_ptr->recbufsize = *size; - wave_in->rec_ptr->recbuffer = buffer; - wave_in->rec_ptr->busaddx = wave_in->memhandle->busaddx; - - return CTSTATUS_SUCCESS; -} - -static void dealloc_recbuffer(struct wave_in *wave_in) -{ - emu10k1_free_memphysical(wave_in->memhandle); return; } @@ -172,301 +104,264 @@ int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in; - struct wave_in **wave_in_tmp = NULL; - u32 buffsize, bytespersec, delay; + struct wiinst **wiinst_tmp = NULL; + u32 delay; unsigned long flags; DPF(2, "emu10k1_wavein_open()\n"); - if ((wave_in = (struct wave_in *) kmalloc(sizeof(struct wave_in), GFP_KERNEL)) == NULL) { - ERROR(); - return CTSTATUS_ERROR; - } - - wave_in->state = CARDWAVE_STATE_STOPPED; - wave_in->wave_fmt = wiinst->wave_fmt; - wave_in->memhandle = NULL; - wave_in->timer = NULL; - switch (wiinst->recsrc) { case WAVERECORD_AC97: - wave_in_tmp = &card->wavein->ac97; + wiinst_tmp = &card->wavein.ac97; break; case WAVERECORD_MIC: - wave_in_tmp = &card->wavein->mic; + wiinst_tmp = &card->wavein.mic; break; case WAVERECORD_FX: - wave_in_tmp = &card->wavein->fx; + wiinst_tmp = &card->wavein.fx; break; default: + BUG(); break; } spin_lock_irqsave(&card->lock, flags); - if (*wave_in_tmp != NULL) { + if (*wiinst_tmp != NULL) { spin_unlock_irqrestore(&card->lock, flags); - kfree(wave_in); - return CTSTATUS_ERROR; + return -1; } - *wave_in_tmp = wave_in; + *wiinst_tmp = wiinst; spin_unlock_irqrestore(&card->lock, flags); - wiinst->wave_in = wave_in; + /* handle 8 bit recording */ + if (wiinst->format.bytesperchannel == 1) { + if (wiinst->buffer.size > 0x8000) { + wiinst->buffer.size = 0x8000; + wiinst->buffer.sizeregval = 0x1f; + } else + wiinst->buffer.sizeregval += 4; - if ((wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)) == NULL) { - ERROR(); - emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; - } + wiinst->buffer.cov = 2; + } else + wiinst->buffer.cov = 1; - buffsize = wiinst->fragment_size * wiinst->numfrags; - - if (get_recbuffer(card, wave_in, &buffsize) != CTSTATUS_SUCCESS) { + if (alloc_buffer(card, &wiinst->buffer) < 0) { ERROR(); emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - wiinst->fragment_size = buffsize / wiinst->numfrags; - - /* This callback size returned is the size in the play buffer. - * For 8-bit samples, callbacksize of user buffer should be - * half of the callbacksize in play buffer. */ - if (wave_in->wave_fmt.bitsperchannel == 8) - wiinst->fragment_size >>= 1; + emu10k1_set_record_src(card, wiinst); - wave_in->callbacksize = wiinst->fragment_size; + delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec; - emu10k1_set_record_src(wave_in->rec_ptr, wiinst->recsrc); + emu10k1_timer_install(card, &wiinst->timer, delay / 2); - bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); - delay = (48000 * wave_in->callbacksize) / bytespersec; - - if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; - } + wiinst->state = WAVE_STATE_OPEN; - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_in *wave_in = wave_dev->wiinst->wave_in; + struct wiinst *wiinst = wave_dev->wiinst; unsigned long flags; - if (wave_in->state != CARDWAVE_STATE_STOPPED) - emu10k1_wavein_stop(wave_dev); + DPF(2, "emu10k1_wavein_close()\n"); - if (wave_in->timer != NULL) - emu10k1_timer_uninstall(card, wave_in->timer); + emu10k1_wavein_stop(wave_dev); - if (wave_in->memhandle != NULL) - dealloc_recbuffer(wave_in); + emu10k1_timer_uninstall(card, &wiinst->timer); - if (wave_in->rec_ptr != NULL) - kfree(wave_in->rec_ptr); + free_buffer(card, &wiinst->buffer); spin_lock_irqsave(&card->lock, flags); switch (wave_dev->wiinst->recsrc) { case WAVERECORD_AC97: - card->wavein->ac97 = NULL; + card->wavein.ac97 = NULL; break; case WAVERECORD_MIC: - card->wavein->mic = NULL; + card->wavein.mic = NULL; break; case WAVERECORD_FX: - card->wavein->fx = NULL; + card->wavein.fx = NULL; break; default: + BUG(); break; } spin_unlock_irqrestore(&card->lock, flags); - kfree(wave_in); - wave_dev->wiinst->wave_in = NULL; + wiinst->state = WAVE_STATE_CLOSED; return; } void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev) { - struct wave_in *wave_in = wave_dev->wiinst->wave_in; + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; DPF(2, "emu10k1_wavein_start()\n"); - if (wave_in->state == CARDWAVE_STATE_STARTED) - return; + emu10k1_start_record(card, &wiinst->buffer); + emu10k1_timer_enable(wave_dev->card, &wiinst->timer); - emu10k1_start_record(wave_in->rec_ptr); - wave_in->state = CARDWAVE_STATE_STARTED; + wiinst->buffer.hw_pos = 0; + wiinst->buffer.pos = 0; + wiinst->buffer.bytestocopy = 0; - emu10k1_timer_enable(wave_dev->card, wave_in->timer); + wiinst->state |= WAVE_STATE_STARTED; return; } void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev) { - struct wave_in *wave_in = wave_dev->wiinst->wave_in; + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; DPF(2, "emu10k1_wavein_stop()\n"); - emu10k1_stop_record(wave_in->rec_ptr); - emu10k1_timer_disable(wave_dev->card, wave_in->timer); + if (!(wiinst->state & WAVE_STATE_STARTED)) + return; - wave_in->rec_ptr->recpos = 0; - wave_in->state = CARDWAVE_STATE_STOPPED; + emu10k1_timer_disable(card, &wiinst->timer); + emu10k1_stop_record(card, &wiinst->buffer); + + wiinst->state &= ~WAVE_STATE_STARTED; return; } -int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev) +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format) { struct emu10k1_card *card = wave_dev->card; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in = wiinst->wave_in; - u32 bytespersec, delay; + u32 delay; DPF(2, "emu10k1_wavein_setformat()\n"); - query_format(wiinst->recsrc, &wiinst->wave_fmt); + if (wiinst->state & WAVE_STATE_STARTED) + return -1; - if (!wave_in) - return CTSTATUS_SUCCESS; + query_format(wiinst->recsrc, format); - if (wave_in->state == CARDWAVE_STATE_STARTED) { - wiinst->wave_fmt = wave_in->wave_fmt; - return CTSTATUS_SUCCESS; - } + if ((wiinst->format.samplingrate != format->samplingrate) + || (wiinst->format.bitsperchannel != format->bitsperchannel) + || (wiinst->format.channels != format->channels)) { - if ((wave_in->wave_fmt.samplingrate != wiinst->wave_fmt.samplingrate) - || (wave_in->wave_fmt.bitsperchannel != wiinst->wave_fmt.bitsperchannel) - || (wave_in->wave_fmt.channels != wiinst->wave_fmt.channels)) { + wiinst->format = *format; - emu10k1_timer_uninstall(card, wave_in->timer); + if (wiinst->state == WAVE_STATE_CLOSED) + return 0; - wave_in->wave_fmt = wiinst->wave_fmt; + wiinst->buffer.size *= wiinst->buffer.cov; - bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); - delay = (48000 * wave_in->callbacksize) / bytespersec; + if (wiinst->format.bytesperchannel == 1) { + wiinst->buffer.cov = 2; + wiinst->buffer.size /= wiinst->buffer.cov; + } else + wiinst->buffer.cov = 1; - if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; - } + emu10k1_timer_uninstall(card, &wiinst->timer); + + delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec; + + emu10k1_timer_install(card, &wiinst->timer, delay / 2); } - return CTSTATUS_SUCCESS; + return 0; } -void emu10k1_wavein_getxfersize(struct wave_in *wave_in, u32 * size, u32 * curpos) +void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size) { - struct record *rec_ptr = wave_in->rec_ptr; - - /* Get position of current address, this is in no. of bytes in play buffer */ - emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, curpos); + struct wavein_buffer *buffer = &wiinst->buffer; - *size = *curpos - rec_ptr->recpos; + *size = buffer->bytestocopy; - /* Recpos is the actual position in user buffer and play buffer */ - if (*curpos < rec_ptr->recpos) - *size += rec_ptr->recbufsize; - - if (!rec_ptr->is_16bit) - *size >>= 1; + if (*size > buffer->size) { + *size = buffer->size; + buffer->pos = buffer->hw_pos; + buffer->bytestocopy = buffer->size; + DPF(1, "buffer overrun\n"); + } return; } -static void copy_s16_to_u8(u8 * dstbuf, s16 * srcbuf, u32 size) +static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov) { - u16 sample; - u8 byte; - - while (size--) { - sample = (*srcbuf) + 32767; - byte = (u8) (sample >> 8); - copy_to_user(dstbuf, &byte, 1); - dstbuf++; - srcbuf++; + if (cov == 1) + copy_to_user(dst, src + str, len); + else { + u8 byte; + u32 i; + + src += 1 + 2 * str; + + for (i = 0; i < len; i++) { + byte = src[2 * i] ^ 0x80; + copy_to_user(dst + i, &byte, 1); + } } + + return; } -/* transfer the data from the wave device. */ void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size) { - struct wave_in *wave_in = wiinst->wave_in; - struct record *rec_ptr = wave_in->rec_ptr; + struct wavein_buffer *buffer = &wiinst->buffer; u32 sizetocopy, sizetocopy_now, start; unsigned long flags; - sizetocopy = min(rec_ptr->recbufsize * (rec_ptr->is_16bit + 1) / 2, *size); + sizetocopy = min(buffer->size, *size); *size = sizetocopy; if (!sizetocopy) return; spin_lock_irqsave(&wiinst->lock, flags); + start = buffer->pos; + buffer->pos += sizetocopy; + buffer->pos %= buffer->size; + buffer->bytestocopy -= sizetocopy; + sizetocopy_now = buffer->size - start; - sizetocopy_now = (rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is_16bit + 1) / 2; - - start = rec_ptr->recpos; + spin_unlock_irqrestore(&wiinst->lock, flags); if (sizetocopy > sizetocopy_now) { sizetocopy -= sizetocopy_now; - rec_ptr->recpos = sizetocopy * 2 / (rec_ptr->is_16bit + 1); - - spin_unlock_irqrestore(&wiinst->lock, flags); - if (rec_ptr->is_16bit) { - copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy_now); - copy_to_user(data + sizetocopy_now, rec_ptr->recbuffer, sizetocopy); - } else { - copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy_now); - copy_s16_to_u8(data + sizetocopy_now, (s16 *) rec_ptr->recbuffer, sizetocopy); - } + copy_block(data, buffer->addr, start, sizetocopy_now, buffer->cov); + copy_block(data + sizetocopy_now, buffer->addr, 0, sizetocopy, buffer->cov); } else { - if (sizetocopy == sizetocopy_now) - rec_ptr->recpos = 0; - else - rec_ptr->recpos += sizetocopy * 2 / (rec_ptr->is_16bit + 1); - - spin_unlock_irqrestore(&wiinst->lock, flags); - - if (rec_ptr->is_16bit) - copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy); - else - copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy); + copy_block(data, buffer->addr, start, sizetocopy, buffer->cov); } return; } -/* get the specified control value of the wave device. */ - -int emu10k1_wavein_getcontrol(struct wave_in *wave_in, u32 ctrlid, u32 * value) +void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst) { - switch (ctrlid) { - case WAVECURPOS: - /* There is no actual start yet */ - if (wave_in->state == CARDWAVE_STATE_STOPPED) { - *value = 0; - } else { - /* value is in byte units */ - *value = sblive_readptr(wave_in->rec_ptr->card, wave_in->rec_ptr->bufidxreg, 0); - } - - break; + u32 hw_pos; + u32 diff; - default: - return CTSTATUS_ERROR; + /* There is no actual start yet */ + if (!(wiinst->state & WAVE_STATE_STARTED)) { + hw_pos = wiinst->buffer.hw_pos; + } else { + /* hw_pos in byte units */ + hw_pos = sblive_readptr(card, wiinst->buffer.idxreg, 0) / wiinst->buffer.cov; } - return CTSTATUS_SUCCESS; + diff = (wiinst->buffer.size + hw_pos - wiinst->buffer.hw_pos) % wiinst->buffer.size; + wiinst->total_recorded += diff; + wiinst->buffer.bytestocopy += diff; + + wiinst->buffer.hw_pos = hw_pos; + + return; } diff --git a/drivers/sound/emu10k1/cardwi.h b/drivers/sound/emu10k1/cardwi.h index 2d781033d..f0c44057d 100644 --- a/drivers/sound/emu10k1/cardwi.h +++ b/drivers/sound/emu10k1/cardwi.h @@ -32,45 +32,42 @@ #define _CARDWI_H #include "icardwav.h" +#include "audio.h" +#include "timer.h" -struct wave_in -{ - struct list_head list; - - u32 state; - struct record *rec_ptr; - struct memhandle *memhandle; - struct emu_timer *timer; - u32 callbacksize; - struct wave_format wave_fmt; +struct wavein_buffer { + u16 ossfragshift; + u32 fragment_size; + u32 numfrags; + u32 hw_pos; /* hardware cursor position */ + u32 pos; /* software cursor position */ + u32 bytestocopy; /* bytes of recorded data available */ + u32 size; + u32 sizereg; + u32 sizeregval; + u32 addrreg; + u32 idxreg; + u32 adcctl; + void *addr; + u8 cov; + dma_addr_t dma_handle; }; struct wiinst { - struct wave_in *wave_in; - struct wave_format wave_fmt; - u16 ossfragshift; - u32 fragment_size; - u32 numfrags; + u8 state; + struct emu_timer timer; + struct wave_format format; + struct wavein_buffer buffer; wait_queue_head_t wait_queue; - int mapped; - u32 total_recorded; + u8 mmapped; + u32 total_recorded; /* total bytes read() from device */ u32 blocks; - u32 curpos; spinlock_t lock; u8 recsrc; + u16 fxwc; }; -struct emu10k1_wavein -{ - struct wave_in *ac97; - struct wave_in *mic; - struct wave_in *fx; - - u8 recsrc; -}; - - #define WAVEIN_MAXBUFSIZE 65536 #define WAVEIN_MINBUFSIZE 368 @@ -83,10 +80,10 @@ int emu10k1_wavein_open(struct emu10k1_wavedevice *); void emu10k1_wavein_close(struct emu10k1_wavedevice *); void emu10k1_wavein_start(struct emu10k1_wavedevice *); void emu10k1_wavein_stop(struct emu10k1_wavedevice *); -void emu10k1_wavein_getxfersize(struct wave_in *, u32 *, u32 *); +void emu10k1_wavein_getxfersize(struct wiinst *, u32 *); void emu10k1_wavein_xferdata(struct wiinst *, u8 *, u32 *); -int emu10k1_wavein_setformat(struct emu10k1_wavedevice *); -int emu10k1_wavein_getcontrol(struct wave_in *, u32, u32 *); +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *); +void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *); #endif /* _CARDWI_H */ diff --git a/drivers/sound/emu10k1/cardwo.c b/drivers/sound/emu10k1/cardwo.c index 2423df032..48d67b03a 100644 --- a/drivers/sound/emu10k1/cardwo.c +++ b/drivers/sound/emu10k1/cardwo.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * cardwo.c - PCM output HAL for emu10k1 driver @@ -30,47 +29,17 @@ ********************************************************************** */ +#include <linux/poll.h> #include "hwaccess.h" +#include "8010.h" +#include "voicemgr.h" #include "cardwo.h" #include "audio.h" -/* Volume calcs */ - -static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left) +static u32 samplerate_to_linearpitch(u32 samplingrate) { - /* only applicable for playback */ - u32 volL, volR, vol = 0; - - volL = (wave_out->localvol & 0xffff); - volR = ((wave_out->localvol >> 16) & 0xffff); - - if (wave_out->globalvolFactor) { - volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff; - volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff; - } - - /* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */ - /* New volume and pan */ - - if (volL == volR) { - vol = volL; - left->send_c = 0xff; - left->send_b = 0xff; - } else { - if (volL > volR) { - vol = volL; - left->send_c = 0xff; - left->send_b = (char) ((volR * 255) / vol); - } else { - vol = volR; - left->send_b = 0xff; - left->send_c = (char) ((volL * 255) / vol); - } - } - - left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); - - return vol; + samplingrate = (samplingrate << 8) / 375; + return (samplingrate >> 1) + (samplingrate & 1); } static void query_format(struct wave_format *wave_fmt) @@ -78,593 +47,404 @@ static void query_format(struct wave_format *wave_fmt) if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2)) wave_fmt->channels = 2; - if (wave_fmt->samplingrate >= 0x2EE00) - wave_fmt->samplingrate = 0x2EE00; + if (wave_fmt->samplingrate >= 0x2ee00) + wave_fmt->samplingrate = 0x2ee00; if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16)) wave_fmt->bitsperchannel = 16; + wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3; + wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel; + wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate; + return; } -static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer) +static int alloc_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer) { - u32 numpages, reqsize, pageindex, pagecount; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u32 pageindex, pagecount; unsigned long busaddx; int i; - reqsize = *size; - numpages = reqsize / PAGE_SIZE; - - /* If size is not a multiple of PAGE_SIZE then we need to round up */ - if (reqsize % PAGE_SIZE) - numpages += 1; - - DPD(2, "requested pages is: %d\n", numpages); - - wavexferbuf->numpages = numpages; - - /* Only for playback, request for emu address space */ - /* Support non page-aligned buffer, don't need interpolation page */ + DPD(2, "requested pages is: %d\n", buffer->pages); - if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0) - return CTSTATUS_ERROR; - - if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL) - return CTSTATUS_ERROR; + if ((buffer->emupageindex = emu10k1_addxmgr_alloc(buffer->pages * PAGE_SIZE, card)) < 0) + return -1; /* Fill in virtual memory table */ - for (pagecount = 0; pagecount < numpages; pagecount++) { - if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) { - wavexferbuf->numpages = pagecount; - return CTSTATUS_ERROR; + for (pagecount = 0; pagecount < buffer->pages; pagecount++) { + if ((buffer->addr[pagecount] = pci_alloc_consistent(card->pci_dev, PAGE_SIZE, &buffer->dma_handle[pagecount])) == NULL) { + buffer->pages = pagecount; + return -1; } - DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]); + DPD(2, "Virtual Addx: %p\n", buffer->addr[pagecount]); for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { - busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE); + busaddx = buffer->dma_handle[pagecount] + i * EMUPAGESIZE; DPD(3, "Bus Addx: %lx\n", busaddx); - pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; - ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex; + ((u32 *) card->virtualpagetable.addr)[pageindex] = (busaddx * 2) | pageindex; } } - *buffer = wave_out->pagetable; - - return CTSTATUS_SUCCESS; -} - -static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size) -{ - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - void **buffer; - - wavexferbuf->xferpos = 0; - wavexferbuf->silence_xferpos = 0; - wavexferbuf->stopposition = 0; - wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; - wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; - wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); - - if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS) - return CTSTATUS_ERROR; - - /* xferbufsize contains actual transfer buffer size */ - wavexferbuf->xferbufsize = *size; - wavexferbuf->xferbuffer = buffer; - - return CTSTATUS_SUCCESS; + return 0; } -static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out) +static void free_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer) { u32 pagecount, pageindex; int i; - if (wave_out->pagetable != NULL) { - for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) { - free_page((unsigned long) wave_out->pagetable[pagecount]); + if (buffer->emupageindex < 0) + return; + + for (pagecount = 0; pagecount < buffer->pages; pagecount++) { + pci_free_consistent(card->pci_dev, PAGE_SIZE, buffer->addr[pagecount], buffer->dma_handle[pagecount]); - for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { - pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; - ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex; - } + for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { + pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + ((u32 *) card->virtualpagetable.addr)[pageindex] = (card->silentpage.dma_handle * 2) | pageindex; } - kfree(wave_out->pagetable); } - emu10k1_addxmgr_free(card, wave_out->emupageindex); + emu10k1_addxmgr_free(card, buffer->emupageindex); + buffer->emupageindex = -1; return; } -static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device) +static int get_voice(struct emu10k1_card *card, struct woinst *woinst) { - struct emu10k1_waveout *card_waveout = card->waveout; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - struct voice_allocdesc voice_allocdesc; - struct voice_param *left, *right; - u32 size; - + struct emu_voice *voice = &woinst->voice; /* Allocate voices here, if no voices available, return error. * Init voice_allocdesc first.*/ - voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK; - - voice_allocdesc.flags = 0; - - if (device == 1) - voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2; - - if (wave_out->wave_fmt.channels == 1) - voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO; + voice->usage = VOICE_USAGE_PLAYBACK; - if (wave_out->wave_fmt.bitsperchannel == 16) - voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT; + voice->flags = 0; - if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL) - return CTSTATUS_ERROR; + if (woinst->format.channels == 2) + voice->flags |= VOICE_FLAGS_STEREO; - /* voice initialization */ + if (woinst->format.bitsperchannel == 16) + voice->flags |= VOICE_FLAGS_16BIT; - left = &wave_out->voice->params; + if (emu10k1_voice_alloc(card, voice) < 0) + return -1; /* Calculate pitch */ - left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8); + voice->initial_pitch = (u16) (srToPitch(woinst->format.samplingrate) >> 8); + voice->pitch_target = samplerate_to_linearpitch(woinst->format.samplingrate); - DPD(2, "Initial pitch --> %x\n", left->initial_pitch); + DPD(2, "Initial pitch --> 0x%x\n", voice->initial_pitch); - /* Easy way out.. gotta calculate value */ - left->pitch_target = 0; - left->volume_target = 0; - left->FC_target = 0; + voice->startloop = (woinst->buffer.emupageindex << 12) / woinst->format.bytespersample; + voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespersample; + voice->start = voice->startloop; - left->byampl_env_sustain = 0x7f; - left->byampl_env_decay = 0x7f; + if (voice->flags & VOICE_FLAGS_STEREO) { + voice->params[0].send_a = card->waveout.send_a[1]; + voice->params[0].send_b = card->waveout.send_b[1]; + voice->params[0].send_c = card->waveout.send_c[1]; + voice->params[0].send_d = card->waveout.send_d[1]; - if (wave_out->globalreverbFactor) { - u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff); + if (woinst->device) + voice->params[0].send_routing = 0xd23c; + else + voice->params[0].send_routing = card->waveout.send_routing[1]; - left->send_a = (t > 255) ? 255 : t; - } else { - left->send_a = 0; - } + voice->params[0].volume_target = 0xffff; + voice->params[0].initial_fc = 0xff; + voice->params[0].initial_attn = 0x00; + voice->params[0].byampl_env_sustain = 0x7f; + voice->params[0].byampl_env_decay = 0x7f; - if (wave_out->globalchorusFactor) { - u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff); + voice->params[1].send_a = card->waveout.send_a[2]; + voice->params[1].send_b = card->waveout.send_b[2]; + voice->params[1].send_c = card->waveout.send_c[2]; + voice->params[1].send_d = card->waveout.send_d[2]; + + if (woinst->device) + voice->params[1].send_routing = 0xd23c; + else + voice->params[1].send_routing = card->waveout.send_routing[2]; - left->send_d = (t > 255) ? 255 : t; + voice->params[1].volume_target = 0xffff; + voice->params[1].initial_fc = 0xff; + voice->params[1].initial_attn = 0x00; + voice->params[1].byampl_env_sustain = 0x7f; + voice->params[1].byampl_env_decay = 0x7f; } else { - left->send_d = 0; + voice->params[0].send_a = card->waveout.send_a[0]; + voice->params[0].send_b = card->waveout.send_b[0]; + voice->params[0].send_c = card->waveout.send_c[0]; + voice->params[0].send_d = card->waveout.send_d[0]; + + if (woinst->device) + voice->params[0].send_routing = 0xd23c; + else + voice->params[0].send_routing = card->waveout.send_routing[0]; + + voice->params[0].volume_target = 0xffff; + voice->params[0].initial_fc = 0xff; + voice->params[0].initial_attn = 0x00; + voice->params[0].byampl_env_sustain = 0x7f; + voice->params[0].byampl_env_decay = 0x7f; } - set_volume_instance(card_waveout, wave_out, left); - - left->pan_target = left->send_c; - left->aux_target = left->send_b; - - size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample; - left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample; - left->end = left->start + size; - left->startloop = left->start; - left->endloop = left->end; - - if (wave_out->voice->linked_voice) { - DPF(2, "is stereo\n"); - right = &wave_out->voice->linked_voice->params; - - right->initial_pitch = left->initial_pitch; + DPD(2, "voice: startloop=0x%x, endloop=0x%x\n", voice->startloop, voice->endloop); - /* Easy way out.. gotta calculate value */ - right->pitch_target = 0; - right->volume_target = 0; - right->FC_target = 0; + emu10k1_voice_playback_setup(voice); - right->byampl_env_sustain = 0x7f; - right->byampl_env_decay = 0x7f; - - right->send_d = left->send_d; - right->send_a = left->send_a; - - /* Left output of right channel is always zero */ - right->send_c = 0; - - /* Update right channel aux */ - right->pan_target = 0; - right->send_b = left->send_b; - right->aux_target = right->send_b; - - /* Zero out right output of left channel */ - left->send_b = 0; - left->aux_target = 0; - - /* Update right channel attenuation */ - right->initial_attn = left->initial_attn; - - right->start = left->start; - right->end = left->end; - right->startloop = left->startloop; - right->endloop = left->endloop; - - } - - DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop); - - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; - u32 bytespersec, delay; - u32 buffsize; + u32 delay; DPF(2, "emu10k1_waveout_open()\n"); - if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } - - woinst->wave_out = wave_out; - - /* Init channel object */ - wave_out->state = CARDWAVE_STATE_STOPPED; - wave_out->wave_fmt = woinst->wave_fmt; - wave_out->voice = NULL; - wave_out->emupageindex = -1; - wave_out->wavexferbuf = NULL; - wave_out->pagetable = NULL; - wave_out->timer = NULL; - - /* Assign default local volume */ - /* FIXME: Should we be maxing the initial values like this? */ - wave_out->localvol = 0xffffffff; - wave_out->localreverb = 0xffffffff; - wave_out->localchorus = 0xffffffff; - wave_out->globalvolFactor = 0xffff; - wave_out->globalreverbFactor = 0xffff; - wave_out->globalchorusFactor = 0xffff; - - wave_out->setpos = 0; - wave_out->position = 0; - - wave_out->fill_silence = 0; - - if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) { + if (alloc_buffer(card, &woinst->buffer) < 0) { ERROR(); emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - buffsize = woinst->fragment_size * woinst->numfrags; + woinst->buffer.fill_silence = 0; + woinst->buffer.silence_bytes = 0; + woinst->buffer.silence_pos = 0; + woinst->buffer.hw_pos = 0; + woinst->buffer.bytestocopy = woinst->buffer.size; - if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) { + if (get_voice(card, woinst) < 0) { ERROR(); emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - woinst->fragment_size = buffsize / woinst->numfrags; - wave_out->callbacksize = woinst->fragment_size; + delay = (48000 * woinst->buffer.fragment_size) / woinst->format.bytespersec; - if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } + emu10k1_timer_install(card, &woinst->timer, delay / 2); - bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); - delay = (48000 * wave_out->callbacksize) / bytespersec; + woinst->state = WAVE_STATE_OPEN; - if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } - - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_out *wave_out = wave_dev->woinst->wave_out; + struct woinst *woinst = wave_dev->woinst; DPF(2, "emu10k1_waveout_close()\n"); - if (wave_out->state != CARDWAVE_STATE_STOPPED) - emu10k1_waveout_stop(wave_dev); + emu10k1_waveout_stop(wave_dev); - if (wave_out->timer != NULL) - emu10k1_timer_uninstall(card, wave_out->timer); + emu10k1_timer_uninstall(card, &woinst->timer); - if (wave_out->voice != NULL) - emu10k1_voice_free(&card->voicemgr, wave_out->voice); + emu10k1_voice_free(&woinst->voice); - if (wave_out->emupageindex >= 0) - dealloc_xferbuffer(card, wave_out); + free_buffer(card, &woinst->buffer); - if (wave_out->wavexferbuf != NULL) - kfree(wave_out->wavexferbuf); - - kfree(wave_out); - wave_dev->woinst->wave_out = NULL; + woinst->state = WAVE_STATE_CLOSED; return; } -int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev) +void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_out *wave_out = wave_dev->woinst->wave_out; - u32 start, startPosition; + struct woinst *woinst = wave_dev->woinst; DPF(2, "emu10k1_waveout_start()\n"); - - /* If already started, return success */ - if (wave_out->state == CARDWAVE_STATE_STARTED) - return CTSTATUS_SUCCESS; - - if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos) - startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample); - else - startPosition = wave_out->wavexferbuf->stopposition; - - start = wave_out->voice->params.start; - wave_out->voice->params.start += startPosition; - - DPD(2, "CA is %x\n", wave_out->voice->params.start); - - emu10k1_voice_playback_setup(wave_out->voice); - - wave_out->voice->params.start = start; - /* Actual start */ - emu10k1_voice_start(wave_out->voice); - wave_out->state = CARDWAVE_STATE_STARTED; - wave_out->setpos = 0; + emu10k1_voice_start(&woinst->voice, woinst->total_played); - emu10k1_timer_enable(card, wave_out->timer); + emu10k1_timer_enable(card, &woinst->timer); - return CTSTATUS_SUCCESS; + woinst->state |= WAVE_STATE_STARTED; + + return; } -int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev) +int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format) { struct emu10k1_card *card = wave_dev->card; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out = woinst->wave_out; - u32 bytespersec, delay; + u32 delay; DPF(2, "emu10k1_waveout_setformat()\n"); - query_format(&woinst->wave_fmt); + if (woinst->state & WAVE_STATE_STARTED) + return -1; - if (wave_out == NULL) - return CTSTATUS_SUCCESS; - - if (wave_out->state == CARDWAVE_STATE_STARTED) { - woinst->wave_fmt = wave_out->wave_fmt; - return CTSTATUS_SUCCESS; - } + query_format(format); - if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate) - || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel) - || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) { - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + if (woinst->format.samplingrate != format->samplingrate || + woinst->format.channels != format->channels || + woinst->format.bitsperchannel != format->bitsperchannel) { - emu10k1_timer_uninstall(card, wave_out->timer); + woinst->format = *format; - emu10k1_voice_free(&card->voicemgr, wave_out->voice); + if (woinst->state == WAVE_STATE_CLOSED) + return 0; - wave_out->wave_fmt = woinst->wave_fmt; - wave_out->timer = NULL; + emu10k1_timer_uninstall(card, &woinst->timer); + emu10k1_voice_free(&woinst->voice); - wavexferbuf->xferpos = 0; - wavexferbuf->silence_xferpos = 0; - wavexferbuf->stopposition = 0; - wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; - wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; - wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); - - if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { + if (get_voice(card, woinst) < 0) { ERROR(); emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); - delay = (48000 * wave_out->callbacksize) / bytespersec; + delay = (48000 * woinst->buffer.fragment_size) / woinst->format.bytespersec; - if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } + emu10k1_timer_install(card, &woinst->timer, delay / 2); } - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_out *wave_out = wave_dev->woinst->wave_out; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - u32 samples = 32; - u32 position; + struct woinst *woinst = wave_dev->woinst; DPF(2, "emu10k1_waveout_stop()\n"); - if (wave_out->state == CARDWAVE_STATE_STOPPED) + if (!(woinst->state & WAVE_STATE_STARTED)) return; - emu10k1_timer_disable(card, wave_out->timer); + emu10k1_timer_disable(card, &woinst->timer); /* Stop actual voice */ - emu10k1_voice_stop(wave_out->voice); - - /* Save the stop position */ - emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition); - - wavexferbuf->stopposition -= wave_out->voice->params.start; - - /* Refer to voicemgr.c, CA is not started at zero. We need to take this into account. */ - position = wavexferbuf->stopposition * wavexferbuf->bytespersample; + emu10k1_voice_stop(&woinst->voice); - if (!wavexferbuf->is_16bit) - samples <<= 1; + emu10k1_waveout_update(woinst); - if (wavexferbuf->is_stereo) - samples <<= 1; - - samples -= 4; - - if (position >= samples * (wavexferbuf->is_16bit + 1)) - position -= samples * (wavexferbuf->is_16bit + 1); - else - position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1); - - wavexferbuf->stopposition = position / wavexferbuf->bytespersample; - - DPD(2, "position is %x\n", wavexferbuf->stopposition); - - wave_out->state = CARDWAVE_STATE_STOPPED; - wave_out->setpos = 0; - wave_out->position = 0; + woinst->state &= ~WAVE_STATE_STARTED; return; } -void emu10k1_waveout_getxfersize(struct wave_out *wave_out, u32 * size, u32 * pending, u32 * curpos) +void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 * size) { - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - - /* Get position of current address, this is in no. of bytes in play buffer */ - emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, curpos); - - if ((*curpos > wavexferbuf->silence_xferpos) - || ((*curpos == wavexferbuf->silence_xferpos) - && (wave_out->state == CARDWAVE_STATE_STARTED)) - || ((*curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0) - && (wave_out->state == CARDWAVE_STATE_STOPPED))) { - *size = *curpos - wavexferbuf->silence_xferpos; - *pending = wavexferbuf->xferbufsize - *size; - } else { - *pending = wavexferbuf->silence_xferpos - *curpos; - *size = wavexferbuf->xferbufsize - *pending; + struct waveout_buffer *buffer = &woinst->buffer; + int pending; + + if (woinst->mmapped) { + *size = buffer->bytestocopy; + return; } - if (wavexferbuf->silence_xferpos != wavexferbuf->xferpos) { - if (*pending < wave_out->callbacksize) { - wave_out->fill_silence = 2; - *pending = 0; - *size = wavexferbuf->xferbufsize; - wavexferbuf->xferpos = *curpos; - } else { - if (wave_out->fill_silence == 2) { - *pending = 0; - *size = wavexferbuf->xferbufsize; - wavexferbuf->xferpos = *curpos; - } else { - *pending -= wave_out->callbacksize; - *size += wave_out->callbacksize; - } - } + pending = buffer->size - buffer->bytestocopy; + + buffer->fill_silence = (pending < (signed) buffer->fragment_size) ? 1 : 0; + + if (pending > (signed) buffer->silence_bytes) { + *size = buffer->bytestocopy + buffer->silence_bytes; } else { - if (*pending < wave_out->callbacksize) - wave_out->fill_silence = 1; - else - wave_out->fill_silence = 0; + *size = buffer->size; + buffer->silence_bytes = pending; + if (pending < 0) { + buffer->silence_pos = buffer->hw_pos; + buffer->silence_bytes = 0; + buffer->bytestocopy = buffer->size; + DPF(1, "buffer underrun\n"); + } } return; } -static void copy_block(u32 dst, u8 * src, u32 len, void **pt) +static void copy_block(void **dst, u32 str, u8 *src, u32 len) { int i, j, k; - i = dst / PAGE_SIZE; - j = dst % PAGE_SIZE; - k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; - copy_from_user(pt[i] + j, src, k); - len -= k; - while (len >= PAGE_SIZE) { - copy_from_user(pt[++i], src + k, PAGE_SIZE); - k += PAGE_SIZE; - len -= PAGE_SIZE; - } - copy_from_user(pt[++i], src + k, len); + i = str / PAGE_SIZE; + j = str % PAGE_SIZE; + + if (len > PAGE_SIZE - j) { + k = PAGE_SIZE - j; + copy_from_user(dst[i] + j, src, k); + len -= k; + while (len > PAGE_SIZE) { + copy_from_user(dst[++i], src + k, PAGE_SIZE); + k += PAGE_SIZE; + len -= PAGE_SIZE; + } + copy_from_user(dst[++i], src + k, len); + + } else + copy_from_user(dst[i] + j, src, len); return; } -static void fill_block(u32 dst, u8 val, u32 len, void **pt) +static void fill_block(void **dst, u32 str, u8 src, u32 len) { int i, j, k; - i = dst / PAGE_SIZE; - j = dst % PAGE_SIZE; - k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; - memset(pt[i] + j, val, k); - len -= k; - while (len >= PAGE_SIZE) { - memset(pt[++i], val, PAGE_SIZE); - len -= PAGE_SIZE; - } - memset(pt[++i], val, len); + i = str / PAGE_SIZE; + j = str % PAGE_SIZE; + + if (len > PAGE_SIZE - j) { + k = PAGE_SIZE - j; + memset(dst[i] + j, src, k); + len -= k; + while (len > PAGE_SIZE) { + memset(dst[++i], src, PAGE_SIZE); + len -= PAGE_SIZE; + } + memset(dst[++i], src, len); + + } else + memset(dst[i] + j, src, len); return; } -void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size) +void emu10k1_waveout_xferdata(struct woinst *woinst, u8 *data, u32 *size) { - struct wave_out *wave_out = woinst->wave_out; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + struct waveout_buffer *buffer = &woinst->buffer; u32 sizetocopy, sizetocopy_now, start; unsigned long flags; - sizetocopy = min(wavexferbuf->xferbufsize, *size); + sizetocopy = min(buffer->size, *size); *size = sizetocopy; if (!sizetocopy) return; spin_lock_irqsave(&woinst->lock, flags); + start = (buffer->size + buffer->silence_pos - buffer->silence_bytes) % buffer->size; - sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos; + if(sizetocopy > buffer->silence_bytes) { + buffer->silence_pos += sizetocopy - buffer->silence_bytes; + buffer->bytestocopy -= sizetocopy - buffer->silence_bytes; + buffer->silence_bytes = 0; + } else + buffer->silence_bytes -= sizetocopy; - start = wavexferbuf->xferpos; + sizetocopy_now = buffer->size - start; + + spin_unlock_irqrestore(&woinst->lock, flags); if (sizetocopy > sizetocopy_now) { sizetocopy -= sizetocopy_now; - wavexferbuf->xferpos = sizetocopy; - wavexferbuf->silence_xferpos = wavexferbuf->xferpos; - spin_unlock_irqrestore(&woinst->lock, flags); - - copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer); - copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer); + copy_block(buffer->addr, start, data, sizetocopy_now); + copy_block(buffer->addr, 0, data + sizetocopy_now, sizetocopy); } else { - if (sizetocopy == sizetocopy_now) - wavexferbuf->xferpos = 0; - else - wavexferbuf->xferpos += sizetocopy; - - wavexferbuf->silence_xferpos = wavexferbuf->xferpos; - spin_unlock_irqrestore(&woinst->lock, flags); - - copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer); + copy_block(buffer->addr, start, data, sizetocopy); } return; @@ -672,84 +452,63 @@ void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size) void emu10k1_waveout_fillsilence(struct woinst *woinst) { - struct wave_out *wave_out = woinst->wave_out; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + struct waveout_buffer *buffer = &woinst->buffer; u16 filldata; u32 sizetocopy, sizetocopy_now, start; unsigned long flags; - sizetocopy = wave_out->callbacksize; + sizetocopy = woinst->buffer.fragment_size; - if (wave_out->wave_fmt.bitsperchannel == 8) - filldata = 0x8080; - else + if (woinst->format.bitsperchannel == 16) filldata = 0x0000; + else + filldata = 0x8080; spin_lock_irqsave(&woinst->lock, flags); + buffer->silence_bytes += sizetocopy; + buffer->bytestocopy -= sizetocopy; + buffer->silence_pos %= buffer->size; + start = buffer->silence_pos; + buffer->silence_pos += sizetocopy; + sizetocopy_now = buffer->size - start; - sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos; - start = wavexferbuf->silence_xferpos; + spin_unlock_irqrestore(&woinst->lock, flags); if (sizetocopy > sizetocopy_now) { sizetocopy -= sizetocopy_now; - wavexferbuf->silence_xferpos = sizetocopy; - spin_unlock_irqrestore(&woinst->lock, flags); - fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer); - fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer); + fill_block(buffer->addr, start, filldata, sizetocopy_now); + fill_block(buffer->addr, 0, filldata, sizetocopy); } else { - if (sizetocopy == sizetocopy_now) - wavexferbuf->silence_xferpos = 0; - else - wavexferbuf->silence_xferpos += sizetocopy; - - spin_unlock_irqrestore(&woinst->lock, flags); - - fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer); + fill_block(buffer->addr, start, filldata, sizetocopy); } return; } -/* get the specified control value of the wave device. */ - -int emu10k1_waveout_getcontrol(struct wave_out *wave_out, u32 ctrl_id, u32 * value) +void emu10k1_waveout_update(struct woinst *woinst) { - switch (ctrl_id) { - case WAVECURPOS: - /* There is no actual start yet */ - if (wave_out->state == CARDWAVE_STATE_STOPPED) { - if (wave_out->setpos) - *value = wave_out->position; - else - *value = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample; - } else { - emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, value); - - *value -= wave_out->voice->params.start; - - /* Get number of bytes in play buffer per channel. - * If 8 bit mode is enabled, this needs to be changed. */ - { - u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1); - - *value *= wave_out->wavexferbuf->bytespersample; - - /* Refer to voicemgr.c, CA is not started at zero. - * We need to take this into account. */ - - samples -= 4 * (wave_out->wavexferbuf->is_16bit + 1); - - if (*value >= samples) - *value -= samples; - else - *value += wave_out->wavexferbuf->xferbufsize - samples; - } - } + u32 hw_pos; + u32 diff; + + /* There is no actual start yet */ + if (!(woinst->state & WAVE_STATE_STARTED)) { + hw_pos = woinst->buffer.hw_pos; + } else { + /* hw_pos in sample units */ + hw_pos = sblive_readptr(woinst->voice.card, CCCA_CURRADDR, woinst->voice.num); - break; - default: - return CTSTATUS_ERROR; + if(hw_pos < woinst->voice.start) + hw_pos += woinst->buffer.size / woinst->format.bytespersample - woinst->voice.start; + else + hw_pos -= woinst->voice.start; + + hw_pos *= woinst->format.bytespersample; } - return CTSTATUS_SUCCESS; + diff = (woinst->buffer.size + hw_pos - woinst->buffer.hw_pos) % woinst->buffer.size; + woinst->total_played += diff; + woinst->buffer.bytestocopy += diff; + woinst->buffer.hw_pos = hw_pos; + + return; } diff --git a/drivers/sound/emu10k1/cardwo.h b/drivers/sound/emu10k1/cardwo.h index 20391432a..2e31846a2 100644 --- a/drivers/sound/emu10k1/cardwo.h +++ b/drivers/sound/emu10k1/cardwo.h @@ -33,86 +33,59 @@ #define _CARDWO_H #include "icardwav.h" +#include "audio.h" +#include "voicemgr.h" +#include "timer.h" -struct wave_xferbuf -{ - u32 xferpos; - u32 silence_xferpos; - u32 xferbufsize; /* transfer buffer size */ - u32 numpages; /* number of pages in transfer buffer */ - void **xferbuffer; /* pointer to the transfer buffer */ - int is_stereo; - int is_16bit; - int bytespersample; - u32 stopposition; -}; - -struct wave_out -{ - u32 state; - struct emu_voice *voice; - int emupageindex; - struct emu_timer *timer; - struct wave_xferbuf *wavexferbuf; - void **pagetable; - u32 callbacksize; - u32 localvol; - u32 localreverb; - u32 localchorus; - u32 globalvolFactor; - u32 globalreverbFactor; - u32 globalchorusFactor; - int setpos; - u32 position; - struct wave_format wave_fmt; - int fill_silence; -}; +/* setting this to other than a power of two may break some applications */ +#define WAVEOUT_MAXBUFSIZE MAXBUFSIZE +#define WAVEOUT_MINBUFSIZE 64 -/* setting this to other than a power of two - may break some applications */ -#define WAVEOUT_MAXBUFSIZE 32768 -#define WAVEOUT_MINBUFSIZE 64 +#define WAVEOUT_DEFAULTFRAGLEN 20 /* Time to play a fragment in ms (latency) */ +#define WAVEOUT_DEFAULTBUFLEN 500 /* Time to play the entire buffer in ms */ -#define WAVEOUT_DEFAULTFRAGLEN 100 /* Time to play a fragment in ms (latency) */ -#define WAVEOUT_DEFAULTBUFLEN 1000 /* Time to play the entire buffer in ms */ +#define WAVEOUT_MINFRAGSHIFT 6 -#define WAVEOUT_MINFRAGSHIFT 4 +struct waveout_buffer { + u16 ossfragshift; + u32 numfrags; + u32 fragment_size; /* in bytes units */ + u32 size; /* in bytes units */ + u32 pages; /* buffer size in page units*/ + int emupageindex; + void *addr[BUFMAXPAGES]; + dma_addr_t dma_handle[BUFMAXPAGES]; + u32 silence_pos; /* software cursor position (including silence) */ + u32 hw_pos; /* hardware cursor position */ + u32 bytestocopy; /* free space on buffer (including silence) */ + u8 fill_silence; + u32 silence_bytes; /* silence bytes in buffer */ +}; struct woinst { - struct wave_out *wave_out; - struct wave_format wave_fmt; - u16 ossfragshift; - u32 fragment_size; - u32 numfrags; + u8 state; + struct emu_voice voice; + struct emu_timer timer; + struct wave_format format; + struct waveout_buffer buffer; wait_queue_head_t wait_queue; - int mapped; - u32 total_copied; - u32 total_played; + u8 mmapped; + u32 total_copied; /* total number of bytes written() to the buffer (excluding silence) */ + u32 total_played; /* total number of bytes played including silence */ u32 blocks; - u32 curpos; - u32 device; + u8 device; spinlock_t lock; }; -struct emu10k1_waveout -{ - u32 globalvol; - u32 mute; - u32 left; - u32 right; - u32 globalreverb; - u32 globalchorus; -}; - int emu10k1_waveout_open(struct emu10k1_wavedevice *); void emu10k1_waveout_close(struct emu10k1_wavedevice *); -int emu10k1_waveout_start(struct emu10k1_wavedevice *); +void emu10k1_waveout_start(struct emu10k1_wavedevice *); void emu10k1_waveout_stop(struct emu10k1_wavedevice *); -void emu10k1_waveout_getxfersize(struct wave_out *, u32 *, u32 *, u32 *); +void emu10k1_waveout_getxfersize(struct woinst*, u32 *); void emu10k1_waveout_xferdata(struct woinst*, u8*, u32 *); void emu10k1_waveout_fillsilence(struct woinst*); -int emu10k1_waveout_setformat(struct emu10k1_wavedevice*); -int emu10k1_waveout_getcontrol(struct wave_out*, u32, u32 *); +int emu10k1_waveout_setformat(struct emu10k1_wavedevice*, struct wave_format*); +void emu10k1_waveout_update(struct woinst*); #endif /* _CARDWO_H */ diff --git a/drivers/sound/emu10k1/ecard.c b/drivers/sound/emu10k1/ecard.c new file mode 100644 index 000000000..9d56e0b73 --- /dev/null +++ b/drivers/sound/emu10k1/ecard.c @@ -0,0 +1,155 @@ +/* + ********************************************************************** + * ecard.c - E-card initialization code + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#include "ecard.h" +#include "hwaccess.h" + +/* Private routines */ +static void ecard_setadcgain(struct emu10k1_card *, struct ecard_state *, u16); +static void ecard_write(struct emu10k1_card *, u32); + +/************************************************************************** + * @func Set the gain of the ECARD's CS3310 Trim/gain controller. The + * trim value consists of a 16bit value which is composed of two + * 8 bit gain/trim values, one for the left channel and one for the + * right channel. The following table maps from the Gain/Attenuation + * value in decibels into the corresponding bit pattern for a single + * channel. + */ + +static void ecard_setadcgain(struct emu10k1_card *card, struct ecard_state *ecard, u16 gain) +{ + u32 currbit; + ecard->adc_gain = gain; + + /* Enable writing to the TRIM registers */ + ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN); + + /* Do it again to insure that we meet hold time requirements */ + ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN); + + for (currbit = (1L << 15); currbit; currbit >>= 1) { + + u32 value = ecard->control_bits & ~(EC_TRIM_CSN|EC_TRIM_SDATA); + + if (gain & currbit) + value |= EC_TRIM_SDATA; + + /* Clock the bit */ + ecard_write(card, value); + ecard_write(card, value | EC_TRIM_SCLK); + ecard_write(card, value); + } + + ecard_write(card, ecard->control_bits); +} + +/************************************************************************** + * @func Clock bits into the Ecard's control latch. The Ecard uses a + * control latch will is loaded bit-serially by toggling the Modem control + * lines from function 2 on the E8010. This function hides these details + * and presents the illusion that we are actually writing to a distinct + * register. + */ +static void ecard_write(struct emu10k1_card *card, u32 value) +{ + u16 count; + u32 data, hcvalue; + + hcvalue = emu10k1_readfn0(card, HCFG) & ~(HOOKN_BIT|HANDN_BIT|PULSEN_BIT); + + emu10k1_writefn0(card, HCFG, hcvalue); + + for (count = 0 ; count < EC_NUM_CONTROL_BITS; count++) { + + /* Set up the value */ + data = ((value & 0x1) ? PULSEN_BIT : 0); + value >>= 1; + + emu10k1_writefn0(card, HCFG, hcvalue | data); + + /* Clock the shift register */ + emu10k1_writefn0(card, HCFG, hcvalue | data | HANDN_BIT); + emu10k1_writefn0(card, HCFG, hcvalue | data); + } + + /* Latch the bits */ + emu10k1_writefn0(card, HCFG, hcvalue | HOOKN_BIT); + emu10k1_writefn0(card, HCFG, hcvalue); +} + +int __devinit emu10k1_ecard_init(struct emu10k1_card *card) +{ + u32 hcvalue; + struct ecard_state ecard; + + /* Set up the initial settings */ + ecard.mux0_setting = EC_DEFAULT_SPDIF0_SEL; + ecard.mux1_setting = EC_DEFAULT_SPDIF1_SEL; + ecard.mux2_setting = 0; + ecard.adc_gain = EC_DEFAULT_ADC_GAIN; + ecard.control_bits = EC_RAW_RUN_MODE | + EC_SPDIF0_SELECT(ecard.mux0_setting) | + EC_SPDIF1_SELECT(ecard.mux1_setting); + + + /* Step 0: Set the codec type in the hardware control register + * and enable audio output */ + hcvalue = emu10k1_readfn0(card, HCFG); + emu10k1_writefn0(card, HCFG, hcvalue | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S); + emu10k1_readfn0(card, HCFG); + + /* Step 1: Turn off the led and deassert TRIM_CS */ + ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN); + + /* Step 2: Calibrate the ADC and DAC */ + ecard_write(card, EC_DACCAL | EC_LEDN | EC_TRIM_CSN); + + /* Step 3: Wait for awhile; FIXME: Is this correct? */ + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + + /* Step 4: Switch off the DAC and ADC calibration. Note + * That ADC_CAL is actually an inverted signal, so we assert + * it here to stop calibration. */ + ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN); + + /* Step 4: Switch into run mode */ + ecard_write(card, ecard.control_bits); + + /* Step 5: Set the analog input gain */ + ecard_setadcgain(card, &ecard, ecard.adc_gain); + + return 0; +} + + diff --git a/drivers/sound/emu10k1/ecard.h b/drivers/sound/emu10k1/ecard.h new file mode 100644 index 000000000..0d55960e1 --- /dev/null +++ b/drivers/sound/emu10k1/ecard.h @@ -0,0 +1,113 @@ +/* + ********************************************************************** + * ecard.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * 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., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + ********************************************************************** + */ + +#ifndef _ECARD_H +#define _ECARD_H + +#include "8010.h" +#include "hwaccess.h" +#include <linux/init.h> + +/* In A1 Silicon, these bits are in the HC register */ +#define HOOKN_BIT (1L << 12) +#define HANDN_BIT (1L << 11) +#define PULSEN_BIT (1L << 10) + +#define EC_GDI1 (1 << 13) +#define EC_GDI0 (1 << 14) + +#define EC_NUM_CONTROL_BITS 20 + +#define EC_AC3_DATA_SELN 0x0001L +#define EC_EE_DATA_SEL 0x0002L +#define EC_EE_CNTRL_SELN 0x0004L +#define EC_EECLK 0x0008L +#define EC_EECS 0x0010L +#define EC_EESDO 0x0020L +#define EC_TRIM_CSN 0x0040L +#define EC_TRIM_SCLK 0x0080L +#define EC_TRIM_SDATA 0x0100L +#define EC_TRIM_MUTEN 0x0200L +#define EC_ADCCAL 0x0400L +#define EC_ADCRSTN 0x0800L +#define EC_DACCAL 0x1000L +#define EC_DACMUTEN 0x2000L +#define EC_LEDN 0x4000L + +#define EC_SPDIF0_SEL_SHIFT 15 +#define EC_SPDIF1_SEL_SHIFT 17 +#define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT) +#define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT) +#define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK) +#define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK) +#define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should + * be incremented any time the EEPROM's + * format is changed. */ + +#define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */ + +/* Addresses for special values stored in to EEPROM */ +#define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */ +#define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */ +#define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */ + +#define EC_LAST_PROMFILE_ADDR 0x2f + +#define EC_SERIALNUM_ADD 0x30 /* First word of serial number. The number + * can be up to 30 characters in length + * and is stored as a NULL-terminated + * ASCII string. Any unused bytes must be + * filled with zeros */ +#define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */ + + + +/* Most of this stuff is pretty self-evident. According to the hardware + * dudes, we need to leave the ADCCAL bit low in order to avoid a DC + * offset problem. Weird. + */ +#define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | EC_TRIM_CSN) + + +#define EC_DEFAULT_ADC_GAIN 0xC4C4 +#define EC_DEFAULT_SPDIF0_SEL 0x0 +#define EC_DEFAULT_SPDIF1_SEL 0x4 + +#define HC_EA 0x01L + +/* ECARD state structure. This structure maintains the state + * for various portions of the the ECARD's onboard hardware. + */ +struct ecard_state { + u32 control_bits; + u16 adc_gain; + u16 mux0_setting; + u16 mux1_setting; + u16 mux2_setting; +}; + +int emu10k1_ecard_init(struct emu10k1_card *) __devinit; + +#endif /* _ECARD_H */ diff --git a/drivers/sound/emu10k1/efxmgr.c b/drivers/sound/emu10k1/efxmgr.c deleted file mode 100644 index 1b4e01a21..000000000 --- a/drivers/sound/emu10k1/efxmgr.c +++ /dev/null @@ -1,34 +0,0 @@ - -/* - ********************************************************************** - * sblive_fx.c - * Copyright 1999, 2000 Creative Labs, Inc. - * - ********************************************************************** - * - * Date Author Summary of changes - * ---- ------ ------------------ - * October 20, 1999 Bertrand Lee base code release - * - ********************************************************************** - * - * 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., 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - ********************************************************************** - */ - -#include "hwaccess.h" -#include "efxmgr.h" diff --git a/drivers/sound/emu10k1/emu_wrapper.h b/drivers/sound/emu10k1/emu_wrapper.h index f0010d40e..20cb56464 100644 --- a/drivers/sound/emu10k1/emu_wrapper.h +++ b/drivers/sound/emu10k1/emu_wrapper.h @@ -3,9 +3,11 @@ #include <linux/wrapper.h> -#define UP_INODE_SEM(a) -#define DOWN_INODE_SEM(a) +#define PCI_SET_DMA_MASK(pdev,mask) (((pdev)->dma_mask) = (mask)) -#define GET_INODE_STRUCT() +#ifndef PCI_GET_DRIVER_DATA + #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) + #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) +#endif /* PCI_GET_DRIVER_DATA */ #endif diff --git a/drivers/sound/emu10k1/emuadxmg.c b/drivers/sound/emu10k1/emuadxmg.c index 94243c874..d7d2d4caf 100644 --- a/drivers/sound/emu10k1/emuadxmg.c +++ b/drivers/sound/emu10k1/emuadxmg.c @@ -44,14 +44,15 @@ int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card) /* Convert bytes to pages */ numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0); - while (index < (MAXPAGES - RESERVED - 1)) { + spin_lock_irqsave(&card->lock, flags); + + while (index < (MAXPAGES - 1)) { if (pagetable[index] & 0x8000) { /* This block of pages is in use, jump to the start of the next block. */ index += (pagetable[index] & 0x7fff); } else { /* Found free block */ if (pagetable[index] >= numpages) { - spin_lock_irqsave(&card->lock, flags); /* Block is large enough */ @@ -72,6 +73,8 @@ int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card) } } + spin_unlock_irqrestore(&card->lock, flags); + return -1; } diff --git a/drivers/sound/emu10k1/hwaccess.c b/drivers/sound/emu10k1/hwaccess.c index fda2baa22..581467845 100644 --- a/drivers/sound/emu10k1/hwaccess.c +++ b/drivers/sound/emu10k1/hwaccess.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * hwaccess.c -- Hardware access layer @@ -31,7 +30,10 @@ ********************************************************************** */ +#include <asm/io.h> + #include "hwaccess.h" +#include "8010.h" #include "icardmid.h" /************************************************************************* @@ -86,7 +88,7 @@ u32 srToPitch(u32 sampleRate) }; if (sampleRate == 0) - return (0); /* Bail out if no leading "1" */ + return 0; /* Bail out if no leading "1" */ sampleRate *= 11185; /* Scale 48000 to 0x20002380 */ @@ -131,51 +133,58 @@ u8 sumVolumeToAttenuation(u32 value) /******************************************* * write/read PCI function 0 registers * ********************************************/ -void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data) +void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data) { unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - outl(data, card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); - - return; -} - -void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data) -{ - unsigned long flags; + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; - data &= mask; + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + data = (data << offset) & mask; + reg &= 0x7f; - spin_lock_irqsave(&card->lock, flags); - data |= inl(card->iobase + reg) & ~mask; - outl(data, card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); + spin_lock_irqsave(&card->lock, flags); + data |= inl(card->iobase + reg) & ~mask; + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + } else { + spin_lock_irqsave(&card->lock, flags); + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + } return; } -u32 sblive_readfn0(struct emu10k1_card * card, u8 reg) +u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg) { u32 val; unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - val = inl(card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); - return val; -} + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; -u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask) -{ - u32 val; - unsigned long flags; + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + reg &= 0x7f; - spin_lock_irqsave(&card->lock, flags); - val = inl(card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); - return val & mask; + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + + return (val & mask) >> offset; + } else { + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + return val; + } } /************************************************************************ @@ -209,6 +218,37 @@ void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data) outl(data, card->iobase + DATA); spin_unlock_irqrestore(&card->lock, flags); } +} + +/* ... : data, reg, ... , TAGLIST_END */ +void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...) +{ + va_list args; + + unsigned long flags; + u32 reg; + + va_start(args, channel); + + spin_lock_irqsave(&card->lock, flags); + while ((reg = va_arg(args, u32)) != TAGLIST_END) { + u32 data = va_arg(args, u32); + u32 regptr = (((reg << 16) & PTR_ADDRESS_MASK) + | (channel & PTR_CHANNELNUM_MASK)); + outl(regptr, card->iobase + PTR); + if (reg & 0xff000000) { + int size = (reg >> 24) & 0x3f; + int offset = (reg >> 16) & 0x1f; + u32 mask = ((1 << size) - 1) << offset; + data = (data << offset) & mask; + + data |= inl(card->iobase + DATA) & ~mask; + } + outl(data, card->iobase + DATA); + } + spin_unlock_irqrestore(&card->lock, flags); + + va_end(args); return; } @@ -244,6 +284,34 @@ u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel) } } +void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask) +{ + u32 val; + unsigned long flags; + + DPF(2,"emu10k1_irq_enable()\n"); + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + INTE) | irq_mask; + outl(val, card->iobase + INTE); + spin_unlock_irqrestore(&card->lock, flags); + return; +} + +void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask) +{ + u32 val; + unsigned long flags; + + DPF(2,"emu10k1_irq_disable()\n"); + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + INTE) & ~irq_mask; + outl(val, card->iobase + INTE); + spin_unlock_irqrestore(&card->lock, flags); + return; +} + void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum) { /* Voice interrupt */ @@ -271,11 +339,11 @@ static void sblive_wcwait(struct emu10k1_card *card, u32 wait) volatile unsigned uCount; u32 newtime = 0, curtime; - curtime = READ_FN0(card, WC_SAMPLECOUNTER); + curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); while (wait--) { uCount = 0; while (uCount++ < TIMEOUT) { - newtime = READ_FN0(card, WC_SAMPLECOUNTER); + newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); if (newtime != curtime) break; } @@ -293,12 +361,12 @@ int sblive_readac97(struct emu10k1_card *card, u8 index, u16 * data) spin_lock_irqsave(&card->lock, flags); - outb(index, card->mixeraddx + 2); - *data = inw(card->mixeraddx); + outb(index, card->iobase + AC97ADDRESS); + *data = inw(card->iobase + AC97DATA); spin_unlock_irqrestore(&card->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data) @@ -307,12 +375,12 @@ int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data) spin_lock_irqsave(&card->lock, flags); - outb(index, card->mixeraddx + 2); - outw(data, card->mixeraddx); + outb(index, card->iobase + AC97ADDRESS); + outw(data, card->iobase + AC97DATA); spin_unlock_irqrestore(&card->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask) @@ -322,16 +390,16 @@ int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask) spin_lock_irqsave(&card->lock, flags); - outb(index, card->mixeraddx + 2); - temp = inw(card->mixeraddx); + outb(index, card->iobase + AC97ADDRESS); + temp = inw(card->iobase + AC97DATA); temp &= ~mask; data &= mask; temp |= data; - outw(temp, card->mixeraddx); + outw(temp, card->iobase + AC97DATA); spin_unlock_irqrestore(&card->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } /********************************************************* @@ -347,9 +415,9 @@ int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data) if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { outb(data, card->iobase + MUDATA); - ret = CTSTATUS_SUCCESS; + ret = 0; } else - ret = CTSTATUS_BUSY; + ret = -1; spin_unlock_irqrestore(&card->lock, flags); @@ -365,9 +433,9 @@ int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data) if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) { *data = inb(card->iobase + MUDATA); - ret = CTSTATUS_SUCCESS; + ret = 0; } else - ret = CTSTATUS_NODATA; + ret = -1; spin_unlock_irqrestore(&card->lock, flags); @@ -405,12 +473,12 @@ int emu10k1_mpu_reset(struct emu10k1_card *card) spin_unlock_irqrestore(&card->lock, flags); if (status == 0xfe) - return CTSTATUS_SUCCESS; + return 0; else - return CTSTATUS_ERROR; + return -1; } - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpu_acquire(struct emu10k1_card *card) @@ -418,7 +486,7 @@ int emu10k1_mpu_acquire(struct emu10k1_card *card) /* FIXME: This should be a macro */ ++card->mpuacqcount; - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpu_release(struct emu10k1_card *card) @@ -426,5 +494,5 @@ int emu10k1_mpu_release(struct emu10k1_card *card) /* FIXME: this should be a macro */ --card->mpuacqcount; - return CTSTATUS_SUCCESS; + return 0; } diff --git a/drivers/sound/emu10k1/hwaccess.h b/drivers/sound/emu10k1/hwaccess.h index 0dba188d3..769a06ab6 100644 --- a/drivers/sound/emu10k1/hwaccess.h +++ b/drivers/sound/emu10k1/hwaccess.h @@ -32,28 +32,20 @@ #ifndef _HWACCESS_H #define _HWACCESS_H -#include <linux/version.h> -#include <linux/kernel.h> #include <linux/fs.h> -#include <linux/ioport.h> #include <linux/sound.h> -#include <linux/malloc.h> #include <linux/soundcard.h> #include <linux/pci.h> -#include <linux/interrupt.h> -#include <asm/io.h> -#include <asm/dma.h> +#include "emu_wrapper.h" -#include <emu_wrapper.h> - -enum GlobalErrorCode -{ - CTSTATUS_SUCCESS = 0x0000, - CTSTATUS_ERROR, - CTSTATUS_NOMEMORY, - CTSTATUS_INUSE, -}; +#define EMUPAGESIZE 4096 /* don't change */ +#define NUM_G 64 /* use all channels */ +#define NUM_FXSENDS 4 /* don't change */ +/* setting this to other than a power of two may break some applications */ +#define MAXBUFSIZE 65536 +#define MAXPAGES 8192 +#define BUFMAXPAGES (MAXBUFSIZE / PAGE_SIZE) #define FLAGS_AVAILABLE 0x0001 #define FLAGS_READY 0x0002 @@ -62,50 +54,57 @@ enum GlobalErrorCode struct memhandle { - unsigned long busaddx; - void *virtaddx; - u32 order; + dma_addr_t dma_handle; + void *addr; + u32 size; }; -struct memhandle *emu10k1_alloc_memphysical(u32); -void emu10k1_free_memphysical(struct memhandle *); - #define DEBUG_LEVEL 2 #ifdef EMU10K1_DEBUG # define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0) # define DPF(level,x) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0) -#define ERROR() DPF(1,"error\n"); #else -# define DPD(level,x,y...) /* not debugging: nothing */ -# define DPF(level,x) -#define ERROR() +# define DPD(level,x,y...) do { } while (0) /* not debugging: nothing */ +# define DPF(level,x) do { } while (0) #endif /* EMU10K1_DEBUG */ -#include "8010.h" -#include "voicemgr.h" +#define ERROR() DPF(1,"error\n") -int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *); -void emu10k1_addxmgr_free(struct emu10k1_card *, int); +/* DATA STRUCTURES */ -#include "timer.h" -#include "irqmgr.h" +struct emu10k1_waveout +{ + u16 send_routing[3]; + + u8 send_a[3]; + u8 send_b[3]; + u8 send_c[3]; + u8 send_d[3]; +}; + +struct emu10k1_wavein +{ + struct wiinst *ac97; + struct wiinst *mic; + struct wiinst *fx; + + u8 recsrc; + u32 fxwc; +}; -/* DATA STRUCTURES */ struct emu10k1_card { struct list_head list; - struct memhandle *virtualpagetable; - - struct memhandle *tankmem; - u32 tmemsize; - struct memhandle *silentpage; + struct memhandle virtualpagetable; + struct memhandle tankmem; + struct memhandle silentpage; spinlock_t lock; - struct voice_manager voicemgr; + u8 voicetable[NUM_G]; u16 emupagetable[MAXPAGES]; struct list_head timers; @@ -114,22 +113,23 @@ struct emu10k1_card struct pci_dev *pci_dev; unsigned long iobase; - unsigned long mixeraddx; - u32 irq; + unsigned long length; + unsigned short model; + unsigned int irq; - unsigned long audio1_num; - unsigned long audio2_num; - unsigned long mixer_num; - unsigned long midi_num; + int audio_num; + int audio1_num; + int mixer_num; + int midi_num; - struct emu10k1_waveout *waveout; - struct emu10k1_wavein *wavein; + struct emu10k1_waveout waveout; + struct emu10k1_wavein wavein; struct emu10k1_mpuout *mpuout; struct emu10k1_mpuin *mpuin; u16 arrwVol[SOUND_MIXER_NRDEVICES + 1]; /* array is used from the member 1 to save (-1) operation */ - u32 digmix[96]; + u32 digmix[9 * 6 * 2]; unsigned int modcnt; struct semaphore open_sem; mode_t open_mode; @@ -139,8 +139,13 @@ struct emu10k1_card u32 has_toslink; // TOSLink detection u8 chiprev; /* Chip revision */ + + int isaps; }; +int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *); +void emu10k1_addxmgr_free(struct emu10k1_card *, int); + #ifdef PRIVATE_PCM_VOLUME #define MAX_PCM_CHANNELS NUM_G @@ -154,16 +159,9 @@ struct sblive_pcm_volume_rec { int opened; // counter - locks element }; extern struct sblive_pcm_volume_rec sblive_pcm_volume[]; - +extern u16 pcm_last_mixer; #endif - -#define ENABLE 0xffffffff -#define DISABLE 0x00000000 - -#define ENV_ON 0x80 -#define ENV_OFF 0x00 - #define TIMEOUT 16384 u32 srToPitch(u32); @@ -173,19 +171,17 @@ extern struct list_head emu10k1_devs; /* Hardware Abstraction Layer access functions */ -#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f)) - -#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f) - -void sblive_writefn0(struct emu10k1_card *, u8 , u32 ); -void sblive_wrtmskfn0(struct emu10k1_card *, u8 , u32 , u32 ); - -u32 sblive_readfn0(struct emu10k1_card *, u8 ); -u32 sblive_rdmskfn0(struct emu10k1_card *, u8, u32 ); +void emu10k1_writefn0(struct emu10k1_card *, u32 , u32 ); +u32 emu10k1_readfn0(struct emu10k1_card *, u32 ); void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 ); +void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...); +#define TAGLIST_END 0 + u32 sblive_readptr(struct emu10k1_card *, u32 , u32 ); +void emu10k1_irq_enable(struct emu10k1_card *, u32); +void emu10k1_irq_disable(struct emu10k1_card *, u32); void emu10k1_set_stop_on_loop(struct emu10k1_card *, u32); void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32); diff --git a/drivers/sound/emu10k1/icardwav.h b/drivers/sound/emu10k1/icardwav.h index a141e7396..8a8f999aa 100644 --- a/drivers/sound/emu10k1/icardwav.h +++ b/drivers/sound/emu10k1/icardwav.h @@ -32,21 +32,19 @@ #ifndef _ICARDWAV_H #define _ICARDWAV_H -/* Enumeration for SetControl */ -enum -{ - WAVECURPOS = 0x10, -}; - struct wave_format { - u32 samplingrate; - u32 bitsperchannel; - u32 channels; /* 1 = Mono, 2 = Stereo */ + int samplingrate; + u8 bitsperchannel; + u8 channels; /* 1 = Mono, 2 = Stereo */ + u8 bytesperchannel; + u8 bytespersample; + int bytespersec; }; /* emu10k1_wave states */ -#define CARDWAVE_STATE_STOPPED 0x0001 -#define CARDWAVE_STATE_STARTED 0x0002 +#define WAVE_STATE_OPEN 0x01 +#define WAVE_STATE_STARTED 0x02 +#define WAVE_STATE_CLOSED 0x04 #endif /* _ICARDWAV_H */ diff --git a/drivers/sound/emu10k1/irqmgr.c b/drivers/sound/emu10k1/irqmgr.c index 96bffcfe4..6a047ba02 100644 --- a/drivers/sound/emu10k1/irqmgr.c +++ b/drivers/sound/emu10k1/irqmgr.c @@ -31,6 +31,7 @@ */ #include "hwaccess.h" +#include "8010.h" #include "cardmi.h" #include "cardmo.h" #include "irqmgr.h" @@ -40,16 +41,13 @@ void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct emu10k1_card *card = (struct emu10k1_card *) dev_id; - u32 irqstatus, ptr, tmp; + u32 irqstatus, tmp; - if (!(irqstatus = sblive_readfn0(card, IPR))) + if (!(irqstatus = emu10k1_readfn0(card, IPR))) return; DPD(4, "emu10k1_interrupt called, irq = %u\n", irq); - /* Preserve PTR register */ - ptr = sblive_readfn0(card, PTR); - /* ** NOTE : ** We do a 'while loop' here cos on certain machines, with both @@ -85,43 +83,10 @@ void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (irqstatus) emu10k1_irq_disable(card, irqstatus); - sblive_writefn0(card, IPR, tmp); - - } while ((irqstatus = sblive_readfn0(card, IPR))); + emu10k1_writefn0(card, IPR, tmp); - sblive_writefn0(card, PTR, ptr); + } while ((irqstatus = emu10k1_readfn0(card, IPR))); return; } -/* Enables the specified irq service */ - -int emu10k1_irq_enable(struct emu10k1_card *card, u32 irqtype) -{ - /* - * TODO : - * put protection here so that we don't accidentally - * screw-up another cardxxx objects irqs - */ - - DPD(4, "emu10k1_irq_enable %x\n", irqtype); - sblive_wrtmskfn0(card, INTE, irqtype, ENABLE); - - return CTSTATUS_SUCCESS; -} - -/* Disables the specified irq service */ - -int emu10k1_irq_disable(struct emu10k1_card *card, u32 irqtype) -{ - /* - * TODO : - * put protection here so that we don't accidentally - * screw-up another cardxxx objects irqs - */ - - DPD(4, "emu10k1_irq_disable %x\n", irqtype); - sblive_wrtmskfn0(card, INTE, irqtype, DISABLE); - - return CTSTATUS_SUCCESS; -} diff --git a/drivers/sound/emu10k1/irqmgr.h b/drivers/sound/emu10k1/irqmgr.h index 886a7374e..76166f804 100644 --- a/drivers/sound/emu10k1/irqmgr.h +++ b/drivers/sound/emu10k1/irqmgr.h @@ -43,17 +43,6 @@ #define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE) #define IRQTYPE_DSP IPR_FXDSP -struct emu10k1_wavedevice -{ - struct emu10k1_card *card; - struct wiinst *wiinst; - struct woinst *woinst; - u16 enablebits; -}; - void emu10k1_timer_irqhandler(struct emu10k1_card *); -int emu10k1_irq_enable(struct emu10k1_card *, u32); -int emu10k1_irq_disable(struct emu10k1_card *, u32); - #endif /* _IRQ_H */ diff --git a/drivers/sound/emu10k1/main.c b/drivers/sound/emu10k1/main.c index acb65d7e5..c8ddfb2b4 100644 --- a/drivers/sound/emu10k1/main.c +++ b/drivers/sound/emu10k1/main.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * main.c - Creative EMU10K1 audio driver @@ -42,24 +41,35 @@ * 0.4 Added rear-channel, SPDIF support. * 0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes, * moved bh's to tasklets, moved to the new PCI driver initialization style. + * 0.6 Make use of pci_alloc_consistent, improve compatibility layer for 2.2 kernels, + * code reorganization and cleanup. + * 0.7 Support for the Emu-APS. Bug fixes for voice cache setup, mmaped sound + poll(). + * Support for setting external TRAM size. + * ********************************************************************** */ /* These are only included once per module */ +#include <linux/version.h> #include <linux/module.h> +#include <linux/malloc.h> #include <linux/init.h> +#include <linux/delay.h> #include "hwaccess.h" +#include "8010.h" #include "efxmgr.h" #include "cardwo.h" #include "cardwi.h" #include "cardmo.h" #include "cardmi.h" #include "recmgr.h" +#include "ecard.h" -#define DRIVER_VERSION "0.5" +#define DRIVER_VERSION "0.7" /* FIXME: is this right? */ +/* does the card support 32 bit bus master?*/ #define EMU10K1_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ #ifndef PCI_VENDOR_ID_CREATIVE @@ -70,8 +80,8 @@ #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 #endif -#define EMU10K1_EXTENT 0x20 /* 32 byte I/O space */ - +#define EMU_APS_SUBID 0x40011102 + enum { EMU10K1 = 0, }; @@ -80,7 +90,7 @@ static char *card_names[] __devinitdata = { "EMU10K1", }; -static struct pci_device_id emu10k1_pci_tbl[] __devinitdata = { +static struct pci_device_id emu10k1_pci_tbl[] = { {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1}, {0,} @@ -99,32 +109,38 @@ extern struct file_operations emu10k1_midi_fops; extern void emu10k1_interrupt(int, void *, struct pt_regs *s); extern int emu10k1_mixer_wrch(struct emu10k1_card *, unsigned int, int); -static int __devinit audio_init(struct emu10k1_card *card) +static void __devinit audio_init(struct emu10k1_card *card) { - if ((card->waveout = kmalloc(sizeof(struct emu10k1_waveout), GFP_KERNEL)) == NULL) { - printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_waveout: out of memory\n"); - return CTSTATUS_ERROR; - } - memset(card->waveout, 0, sizeof(struct emu10k1_waveout)); - - /* Assign default global volume, reverb, chorus */ - card->waveout->globalvol = 0xffffffff; - card->waveout->left = 0xffff; - card->waveout->right = 0xffff; - card->waveout->mute = 0; - card->waveout->globalreverb = 0xffffffff; - card->waveout->globalchorus = 0xffffffff; - - if ((card->wavein = kmalloc(sizeof(struct emu10k1_wavein), GFP_KERNEL)) - == NULL) { - printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_wavein: out of memory\n"); - return CTSTATUS_ERROR; - } - memset(card->wavein, 0, sizeof(struct emu10k1_wavein)); + /* Assign default playback voice parameters */ + /* mono voice */ + card->waveout.send_a[0] = 0x00; + card->waveout.send_b[0] = 0xff; + card->waveout.send_c[0] = 0xff; + card->waveout.send_d[0] = 0x00; + card->waveout.send_routing[0] = 0xd01c; + + /* stereo voice */ + card->waveout.send_a[1] = 0x00; + card->waveout.send_b[1] = 0xff; + card->waveout.send_c[1] = 0x00; + card->waveout.send_d[1] = 0x00; + card->waveout.send_routing[1] = 0xd01c; + + card->waveout.send_a[2] = 0x00; + card->waveout.send_b[2] = 0x00; + card->waveout.send_c[2] = 0xff; + card->waveout.send_d[2] = 0x00; + card->waveout.send_routing[2] = 0xd01c; + + /* Assign default recording parameters */ + if(card->isaps) + card->wavein.recsrc = WAVERECORD_FX; + else + card->wavein.recsrc = WAVERECORD_AC97; + + card->wavein.fxwc = 0x0003; - card->wavein->recsrc = WAVERECORD_AC97; - - return CTSTATUS_SUCCESS; + return; } static void __devinit mixer_init(struct emu10k1_card *card) @@ -141,61 +157,64 @@ static void __devinit mixer_init(struct emu10k1_card *card) SOUND_MIXER_PHONEIN, 0x3232}, { SOUND_MIXER_MIC, 0x0000}, { SOUND_MIXER_LINE, 0x0000}, { - SOUND_MIXER_CD, 0x3232}, { - SOUND_MIXER_LINE1, 0x3232}, { + SOUND_MIXER_CD, 0x4b4b}, { + SOUND_MIXER_LINE1, 0x4b4b}, { SOUND_MIXER_LINE3, 0x3232}, { SOUND_MIXER_DIGITAL1, 0x6464}, { SOUND_MIXER_DIGITAL2, 0x6464}, { SOUND_MIXER_PCM, 0x6464}, { - SOUND_MIXER_RECLEV, 0x3232}, { + SOUND_MIXER_RECLEV, 0x0404}, { SOUND_MIXER_TREBLE, 0x3232}, { SOUND_MIXER_BASS, 0x3232}, { - SOUND_MIXER_LINE2, 0x4b4b}}; + SOUND_MIXER_LINE2, 0x4b4b}}; - int initdig[] = { 0, 1, 2, 3, 6, 7, 16, 17, 18, 19, 22, 23, 64, 65, 66, 67, 70, 71, - 84, 85 + int initdig[] = { 0, 1, 2, 3, 6, 7, 18, 19, 20, 21, 24, 25, 72, 73, 74, 75, 78, 79, + 94, 95 }; - /* Reset */ - sblive_writeac97(card, AC97_RESET, 0); - -#if 0 - /* Check status word */ - { - u16 reg; - - sblive_readac97(card, AC97_RESET, ®); - DPD(2, "RESET 0x%x\n", reg); - sblive_readac97(card, AC97_MASTERTONE, ®); - DPD(2, "MASTER_TONE 0x%x\n", reg); + for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) { + card->digmix[count] = 0x80000000; + sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0); } -#endif - /* Set default recording source to mic in */ - sblive_writeac97(card, AC97_RECORDSELECT, 0); + card->modcnt = 0; // Should this be here or in open() ? - /* Set default AC97 "PCM" volume to acceptable max */ - //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); - //sblive_writeac97(card, AC97_LINE2, 0); + if (!card->isaps) { - /* Set default volumes for all mixer channels */ + for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) { + card->digmix[initdig[count]] = 0x7fffffff; + sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff); + } - for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) { - card->digmix[count] = 0x80000000; - sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0); - } + /* Reset */ + sblive_writeac97(card, AC97_RESET, 0); + +#if 0 + /* Check status word */ + { + u16 reg; + + sblive_readac97(card, AC97_RESET, ®); + DPD(2, "RESET 0x%x\n", reg); + sblive_readac97(card, AC97_MASTERTONE, ®); + DPD(2, "MASTER_TONE 0x%x\n", reg); + } +#endif - for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) { - card->digmix[initdig[count]] = 0x7fffffff; - sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff); + /* Set default recording source to mic in */ + sblive_writeac97(card, AC97_RECORDSELECT, 0); + + /* Set default AC97 "PCM" volume to acceptable max */ + //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); + //sblive_writeac97(card, AC97_LINE2, 0); } + /* Set default volumes for all mixer channels */ + for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++) { emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol); } - card->modcnt = 0; // Should this be here or in open() ? - return; } @@ -204,7 +223,7 @@ static int __devinit midi_init(struct emu10k1_card *card) if ((card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); - return CTSTATUS_ERROR; + return -1; } memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout)); @@ -220,7 +239,7 @@ static int __devinit midi_init(struct emu10k1_card *card) if ((card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL)) == NULL) { kfree(card->mpuout); printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n"); - return CTSTATUS_ERROR; + return -1; } memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin)); @@ -232,31 +251,20 @@ static int __devinit midi_init(struct emu10k1_card *card) spin_lock_init(&card->mpuin->lock); /* Reset the MPU port */ - if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) { + if (emu10k1_mpu_reset(card) < 0) { ERROR(); - return CTSTATUS_ERROR; + return -1; } - return CTSTATUS_SUCCESS; + return 0; } static void __devinit voice_init(struct emu10k1_card *card) { - struct voice_manager *voicemgr = &card->voicemgr; - struct emu_voice *voice; int i; - voicemgr->card = card; - voicemgr->lock = SPIN_LOCK_UNLOCKED; - - voice = voicemgr->voice; - for (i = 0; i < NUM_G; i++) { - voice->card = card; - voice->usage = VOICEMGR_USAGE_FREE; - voice->num = i; - voice->linked_voice = NULL; - voice++; - } + for (i = 0; i < NUM_G; i++) + card->voicetable[i] = VOICE_USAGE_FREE; return; } @@ -280,21 +288,27 @@ static void __devinit addxmgr_init(struct emu10k1_card *card) /* Mark first page as used */ /* This page is reserved by the driver */ card->emupagetable[0] = 0x8001; - card->emupagetable[1] = MAXPAGES - RESERVED - 1; + card->emupagetable[1] = MAXPAGES - 1; return; } static void __devinit fx_init(struct emu10k1_card *card) { - int i, j, k, l; + int i, j, k; +#ifdef TONE_CONTROL + int l; +#endif u32 pc = 0; for (i = 0; i < 512; i++) OP(6, 0x40, 0x40, 0x40, 0x40); for (i = 0; i < 256; i++) - sblive_writeptr(card, FXGPREGBASE + i, 0, 0); + sblive_writeptr_tag(card, 0, + FXGPREGBASE + i, 0, + TANKMEMADDRREGBASE + i, 0, + TAGLIST_END); pc = 0; @@ -304,7 +318,7 @@ static void __devinit fx_init(struct emu10k1_card *card) OP(4, 0x101, 0x40, j + 2, 0x44); for (i = 0; i < 6; i++) { - k = i * 16 + j; + k = i * 18 + j; OP(0, 0x102, 0x40, 0x110 + k, 0x100); OP(0, 0x102, 0x102, 0x112 + k, 0x101); OP(0, 0x102, 0x102, 0x114 + k, 0x10 + j); @@ -313,25 +327,32 @@ static void __devinit fx_init(struct emu10k1_card *card) OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j); OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j); OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j); - - k = 0x190 + i * 8 + j * 4; - OP(0, 0x40, 0x40, 0x102, 0x170 + j); - OP(7, k + 1, k, k + 1, 0x174 + j); - OP(7, k, 0x102, k, 0x172 + j); - OP(7, k + 3, k + 2, k + 3, 0x178 + j); - OP(0, k + 2, 0x56, k + 2, 0x176 + j); +#ifdef TONE_CONTROL + OP(0, 0x102, 0x102, 0x120 + k, 0x1c + j); + + k = 0x1a0 + i * 8 + j * 4; + OP(0, 0x40, 0x40, 0x102, 0x180 + j); + OP(7, k + 1, k, k + 1, 0x184 + j); + OP(7, k, 0x102, k, 0x182 + j); + OP(7, k + 3, k + 2, k + 3, 0x188 + j); + OP(0, k + 2, 0x56, k + 2, 0x186 + j); OP(6, k + 2, k + 2, k + 2, 0x40); - l = 0x1c0 + i * 8 + j * 4; - OP(0, 0x40, 0x40, k + 2, 0x180 + j); - OP(7, l + 1, l, l + 1, 0x184 + j); - OP(7, l, k + 2, l, 0x182 + j); - OP(7, l + 3, l + 2, l + 3, 0x188 + j); - OP(0, l + 2, 0x56, l + 2, 0x186 + j); + l = 0x1d0 + i * 8 + j * 4; + OP(0, 0x40, 0x40, k + 2, 0x190 + j); + OP(7, l + 1, l, l + 1, 0x194 + j); + OP(7, l, k + 2, l, 0x192 + j); + OP(7, l + 3, l + 2, l + 3, 0x198 + j); + OP(0, l + 2, 0x56, l + 2, 0x196 + j); OP(4, l + 2, 0x40, l + 2, 0x46); - OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40); - + if ((i == 0) && !card->isaps) + OP(4, 0x20 + (i * 2) + j, 0x40, l + 2, 0x50); /* FIXME: Is this really needed? */ + else + OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40); +#else + OP(0, 0x20 + (i * 2) + j, 0x102, 0x120 + k, 0x1c + j); +#endif } } sblive_writeptr(card, DBG, 0, 0); @@ -342,63 +363,64 @@ static void __devinit fx_init(struct emu10k1_card *card) static int __devinit hw_init(struct emu10k1_card *card) { int nCh; - -#ifdef TANKMEM - u32 size = 0; -#endif - u32 sizeIdx = 0; - u32 pagecount, tmp; + u32 pagecount; /* tmp */ /* Disable audio and lock cache */ - sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); + emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE); /* Reset recording buffers */ - sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, MICBA, 0, 0); - sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, FXBA, 0, 0); - sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, ADCBA, 0, 0); + sblive_writeptr_tag(card, 0, + MICBS, ADCBS_BUFSIZE_NONE, + MICBA, 0, + FXBS, ADCBS_BUFSIZE_NONE, + FXBA, 0, + ADCBS, ADCBS_BUFSIZE_NONE, + ADCBA, 0, + TAGLIST_END); /* Disable channel interrupt */ - sblive_writefn0(card, INTE, DISABLE); - sblive_writeptr(card, CLIEL, 0, 0); - sblive_writeptr(card, CLIEH, 0, 0); - sblive_writeptr(card, SOLEL, 0, 0); - sblive_writeptr(card, SOLEH, 0, 0); + emu10k1_writefn0(card, INTE, 0); + sblive_writeptr_tag(card, 0, + CLIEL, 0, + CLIEH, 0, + SOLEL, 0, + SOLEH, 0, + TAGLIST_END); /* Init envelope engine */ for (nCh = 0; nCh < NUM_G; nCh++) { - sblive_writeptr(card, DCYSUSV, nCh, ENV_OFF); - sblive_writeptr(card, IP, nCh, 0); - sblive_writeptr(card, VTFT, nCh, 0xffff); - sblive_writeptr(card, CVCF, nCh, 0xffff); - sblive_writeptr(card, PTRX, nCh, 0); - sblive_writeptr(card, CPF, nCh, 0); - sblive_writeptr(card, CCR, nCh, 0); - - sblive_writeptr(card, PSST, nCh, 0); - sblive_writeptr(card, DSL, nCh, 0x10); - sblive_writeptr(card, CCCA, nCh, 0); - sblive_writeptr(card, Z1, nCh, 0); - sblive_writeptr(card, Z2, nCh, 0); - sblive_writeptr(card, FXRT, nCh, 0xd01c0000); - - sblive_writeptr(card, ATKHLDM, nCh, 0); - sblive_writeptr(card, DCYSUSM, nCh, 0); - sblive_writeptr(card, IFATN, nCh, 0xffff); - sblive_writeptr(card, PEFE, nCh, 0); - sblive_writeptr(card, FMMOD, nCh, 0); - sblive_writeptr(card, TREMFRQ, nCh, 24); /* 1 Hz */ - sblive_writeptr(card, FM2FRQ2, nCh, 24); /* 1 Hz */ - sblive_writeptr(card, TEMPENV, nCh, 0); - - /*** These are last so OFF prevents writing ***/ - sblive_writeptr(card, LFOVAL2, nCh, 0); - sblive_writeptr(card, LFOVAL1, nCh, 0); - sblive_writeptr(card, ATKHLDV, nCh, 0); - sblive_writeptr(card, ENVVOL, nCh, 0); - sblive_writeptr(card, ENVVAL, nCh, 0); + sblive_writeptr_tag(card, nCh, + DCYSUSV, 0, + IP, 0, + VTFT, 0xffff, + CVCF, 0xffff, + PTRX, 0, + CPF, 0, + CCR, 0, + + PSST, 0, + DSL, 0x10, + CCCA, 0, + Z1, 0, + Z2, 0, + FXRT, 0xd01c0000, + + ATKHLDM, 0, + DCYSUSM, 0, + IFATN, 0xffff, + PEFE, 0, + FMMOD, 0, + TREMFRQ, 24, /* 1 Hz */ + FM2FRQ2, 24, /* 1 Hz */ + TEMPENV, 0, + + /*** These are last so OFF prevents writing ***/ + LFOVAL2, 0, + LFOVAL1, 0, + ATKHLDV, 0, + ENVVOL, 0, + ENVVAL, 0, + TAGLIST_END); } /* @@ -416,73 +438,57 @@ static int __devinit hw_init(struct emu10k1_card *card) ** P = 0 (Consumer) */ - /* SPDIF0 */ - sblive_writeptr(card, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + sblive_writeptr_tag(card, 0, - /* SPDIF1 */ - sblive_writeptr(card, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + /* SPDIF0 */ + SPCS0, (SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT), - /* SPDIF2 & SPDIF3 */ - sblive_writeptr(card, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + /* SPDIF1 */ + SPCS1, (SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT), - fx_init(card); /* initialize effects engine */ + /* SPDIF2 & SPDIF3 */ + SPCS2, (SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT), - card->tankmem = NULL; + TAGLIST_END); -#ifdef TANKMEM - size = TMEMSIZE; - sizeIdx = TMEMSIZEREG; - while (size > 16384) { - if ((card->tankmem = emu10k1_alloc_memphysical(size)) != NULL) - break; - - size /= 2; - sizeIdx -= 1; - } + fx_init(card); /* initialize effects engine */ - if (card->tankmem == NULL) { - card->tmemsize = 0; - return CTSTATUS_ERROR; - } + card->tankmem.size = 0; - card->tmemsize = size; -#else /* !TANKMEM */ - card->tmemsize = 0; -#endif /* TANKMEM */ + card->virtualpagetable.size = MAXPAGES * sizeof(u32); - if ((card->virtualpagetable = emu10k1_alloc_memphysical((MAXPAGES - RESERVED) * sizeof(u32))) == NULL) { + if ((card->virtualpagetable.addr = pci_alloc_consistent(card->pci_dev, card->virtualpagetable.size, &card->virtualpagetable.dma_handle)) == + NULL) { ERROR(); - emu10k1_free_memphysical(card->tankmem); - return CTSTATUS_ERROR; + return -1; } - if ((card->silentpage = emu10k1_alloc_memphysical(EMUPAGESIZE)) == NULL) { - ERROR(); - emu10k1_free_memphysical(card->tankmem); - emu10k1_free_memphysical(card->virtualpagetable); - return CTSTATUS_ERROR; - } else - memset(card->silentpage->virtaddx, 0, EMUPAGESIZE); + card->silentpage.size = EMUPAGESIZE; - for (pagecount = 0; pagecount < (MAXPAGES - RESERVED); pagecount++) + if ((card->silentpage.addr = pci_alloc_consistent(card->pci_dev, card->silentpage.size, &card->silentpage.dma_handle)) == NULL) { + ERROR(); + pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle); + return -1; + } - ((u32 *) card->virtualpagetable->virtaddx)[pagecount] = (card->silentpage->busaddx * 2) | pagecount; + for (pagecount = 0; pagecount < MAXPAGES; pagecount++) + ((u32 *) card->virtualpagetable.addr)[pagecount] = (card->silentpage.dma_handle * 2) | pagecount; /* Init page table & tank memory base register */ - sblive_writeptr(card, PTB, 0, card->virtualpagetable->busaddx); -#ifdef TANKMEM - sblive_writeptr(card, TCB, 0, card->tankmem->busaddx); -#else - sblive_writeptr(card, TCB, 0, 0); -#endif - sblive_writeptr(card, TCBS, 0, sizeIdx); + sblive_writeptr_tag(card, 0, + PTB, card->virtualpagetable.dma_handle, + TCB, 0, + TCBS, 0, + TAGLIST_END); for (nCh = 0; nCh < NUM_G; nCh++) { - sblive_writeptr(card, MAPA, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); - sblive_writeptr(card, MAPB, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + sblive_writeptr_tag(card, nCh, + MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + TAGLIST_END); } /* Hokay, now enable the AUD bit */ @@ -497,12 +503,16 @@ static int __devinit hw_init(struct emu10k1_card *card) sblive_writeac97(card, AC97_MASTERVOLUME, 0); sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); - sblive_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE); + if(card->model == 0x20 || card->model == 0xc400 || + (card->model == 0x21 && card->chiprev < 6)) + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE); + else + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE); - /* TOSLink detection */ + /* FIXME: TOSLink detection */ card->has_toslink = 0; - tmp = sblive_readfn0(card, HCFG); +/* tmp = sblive_readfn0(card, HCFG); if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { sblive_writefn0(card, HCFG, tmp | 0x800); @@ -513,30 +523,23 @@ static int __devinit hw_init(struct emu10k1_card *card) sblive_writefn0(card, HCFG, tmp); } } - - return CTSTATUS_SUCCESS; +*/ + return 0; } static int __devinit emu10k1_init(struct emu10k1_card *card) { /* Init Card */ - if (hw_init(card) != CTSTATUS_SUCCESS) - return CTSTATUS_ERROR; + if (hw_init(card) < 0) + return -1; voice_init(card); timer_init(card); addxmgr_init(card); - DPD(2, " hw control register -> %x\n", sblive_readfn0(card, HCFG)); - - return CTSTATUS_SUCCESS; -} + DPD(2, " hw control register -> 0x%x\n", emu10k1_readfn0(card, HCFG)); -static void __devexit audio_exit(struct emu10k1_card *card) -{ - kfree(card->waveout); - kfree(card->wavein); - return; + return 0; } static void __devexit midi_exit(struct emu10k1_card *card) @@ -550,50 +553,57 @@ static void __devexit midi_exit(struct emu10k1_card *card) return; } -static void __devexit emu10k1_exit(struct emu10k1_card *card) +static void __devinit emu10k1_exit(struct emu10k1_card *card) { int ch; - sblive_writefn0(card, INTE, DISABLE); + emu10k1_writefn0(card, INTE, 0); /** Shutdown the chip **/ for (ch = 0; ch < NUM_G; ch++) - sblive_writeptr(card, DCYSUSV, ch, ENV_OFF); + sblive_writeptr(card, DCYSUSV, ch, 0); for (ch = 0; ch < NUM_G; ch++) { - sblive_writeptr(card, VTFT, ch, 0); - sblive_writeptr(card, CVCF, ch, 0); - sblive_writeptr(card, PTRX, ch, 0); - sblive_writeptr(card, CPF, ch, 0); + sblive_writeptr_tag(card, ch, + VTFT, 0, + CVCF, 0, + PTRX, 0, + CPF, 0, + TAGLIST_END); } - /* Reset recording buffers */ - sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, MICBA, 0, 0); - sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, FXBA, 0, 0); - sblive_writeptr(card, FXWC, 0, 0); - sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, ADCBA, 0, 0); - sblive_writeptr(card, TCBS, 0, TCBS_BUFFSIZE_16K); - sblive_writeptr(card, TCB, 0, 0); - sblive_writeptr(card, DBG, 0, 0x8000); - - /* Disable channel interrupt */ - sblive_writeptr(card, CLIEL, 0, 0); - sblive_writeptr(card, CLIEH, 0, 0); - sblive_writeptr(card, SOLEL, 0, 0); - sblive_writeptr(card, SOLEH, 0, 0); - /* Disable audio and lock cache */ - sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); - sblive_writeptr(card, PTB, 0, 0); + emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE); + + sblive_writeptr_tag(card, 0, + PTB, 0, + + /* Reset recording buffers */ + MICBS, ADCBS_BUFSIZE_NONE, + MICBA, 0, + FXBS, ADCBS_BUFSIZE_NONE, + FXBA, 0, + FXWC, 0, + ADCBS, ADCBS_BUFSIZE_NONE, + ADCBA, 0, + TCBS, 0, + TCB, 0, + DBG, 0x8000, + + /* Disable channel interrupt */ + CLIEL, 0, + CLIEH, 0, + SOLEL, 0, + SOLEH, 0, + TAGLIST_END); + + + pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle); + pci_free_consistent(card->pci_dev, card->silentpage.size, card->silentpage.addr, card->silentpage.dma_handle); + + if(card->tankmem.size != 0) + pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle); - emu10k1_free_memphysical(card->silentpage); - emu10k1_free_memphysical(card->virtualpagetable); -#ifdef TANKMEM - emu10k1_free_memphysical(card->tankmem); -#endif return; } @@ -601,6 +611,7 @@ static void __devexit emu10k1_exit(struct emu10k1_card *card) static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct emu10k1_card *card; + u32 subsysvid; if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "emu10k1: out of memory\n"); @@ -608,7 +619,6 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev } memset(card, 0, sizeof(struct emu10k1_card)); -#if LINUX_VERSION_CODE > 0x020320 if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) { printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); kfree(card); @@ -623,27 +633,17 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev pci_set_master(pci_dev); card->iobase = pci_resource_start(pci_dev, 0); + card->length = pci_resource_len(pci_dev, 0); - if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) { + if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) { printk(KERN_ERR "emu10k1: IO space in use\n"); kfree(card); return -ENODEV; } - pci_dev->driver_data = card; - pci_dev->dma_mask = EMU10K1_DMA_MASK; -#else - pci_set_master(pci_dev); - card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + PCI_SET_DRIVER_DATA(pci_dev, card); + PCI_SET_DMA_MASK(pci_dev, EMU10K1_DMA_MASK); - if (check_region(card->iobase, EMU10K1_EXTENT)) { - printk(KERN_ERR "emu10k1: IO space in use\n"); - kfree(card); - return -ENODEV; - } - - request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]); -#endif card->irq = pci_dev->irq; card->pci_dev = pci_dev; @@ -654,22 +654,27 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev } pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev); + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &card->model); - printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq); + printk(KERN_INFO "emu10k1: %s rev %d model 0x%x found, IO at 0x%04lx-0x%04lx, IRQ %d\n", + card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase, + card->iobase + card->length - 1, card->irq); + + pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid); + card->isaps = (subsysvid == EMU_APS_SUBID); spin_lock_init(&card->lock); - card->mixeraddx = card->iobase + AC97DATA; init_MUTEX(&card->open_sem); card->open_mode = 0; init_waitqueue_head(&card->open_wait); /* Register devices */ - if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + if ((card->audio_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register first audio device!\n"); goto err_dev0; } - if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register second audio device!\n"); goto err_dev1; } @@ -684,33 +689,27 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev goto err_dev3; } - if (emu10k1_init(card) != CTSTATUS_SUCCESS) { + if (emu10k1_init(card) < 0) { printk(KERN_ERR "emu10k1: cannot initialize device!\n"); goto err_emu10k1_init; } - if (audio_init(card) != CTSTATUS_SUCCESS) { - printk(KERN_ERR "emu10k1: cannot initialize audio!\n"); - goto err_audio_init; - } - - if (midi_init(card) != CTSTATUS_SUCCESS) { + if (midi_init(card) < 0) { printk(KERN_ERR "emu10k1: cannot initialize midi!\n"); goto err_midi_init; } + audio_init(card); mixer_init(card); - DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize); + if (card->isaps) + emu10k1_ecard_init(card); list_add(&card->list, &emu10k1_devs); return 0; err_midi_init: - audio_exit(card); - - err_audio_init: emu10k1_exit(card); err_emu10k1_init: @@ -720,16 +719,16 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev unregister_sound_mixer(card->mixer_num); err_dev2: - unregister_sound_dsp(card->audio2_num); + unregister_sound_dsp(card->audio1_num); err_dev1: - unregister_sound_dsp(card->audio1_num); + unregister_sound_dsp(card->audio_num); err_dev0: free_irq(card->irq, card); err_irq: - release_region(card->iobase, EMU10K1_EXTENT); + release_region(card->iobase, card->length); kfree(card); return -ENODEV; @@ -737,26 +736,25 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev static void __devexit emu10k1_remove(struct pci_dev *pci_dev) { -#if LINUX_VERSION_CODE > 0x020320 - struct emu10k1_card *card = pci_dev->driver_data; -#else - struct emu10k1_card *card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); -#endif + struct emu10k1_card *card = PCI_GET_DRIVER_DATA(pci_dev); + midi_exit(card); - audio_exit(card); emu10k1_exit(card); unregister_sound_midi(card->midi_num); + unregister_sound_mixer(card->mixer_num); - unregister_sound_dsp(card->audio2_num); + unregister_sound_dsp(card->audio1_num); + unregister_sound_dsp(card->audio_num); free_irq(card->irq, card); - release_region(card->iobase, EMU10K1_EXTENT); + release_region(card->iobase, card->length); list_del(&card->list); kfree(card); + return; } @@ -770,7 +768,6 @@ static struct pci_driver emu10k1_pci_driver = { remove:emu10k1_remove, }; -#if LINUX_VERSION_CODE > 0x020320 static int __init emu10k1_init_module(void) { printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); @@ -781,44 +778,9 @@ static int __init emu10k1_init_module(void) static void __exit emu10k1_cleanup_module(void) { pci_unregister_driver(&emu10k1_pci_driver); - return; -} - -#else - -static int __init emu10k1_init_module(void) -{ - struct pci_dev *dev = NULL; - const struct pci_device_id *pci_id = emu10k1_pci_driver.id_table; - - printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); - - if (!pci_present()) - return -ENODEV; - - while (pci_id->vendor) { - while ((dev = pci_find_device(pci_id->vendor, pci_id->device, dev))) - emu10k1_probe(dev, pci_id); - - pci_id++; - } - return 0; -} - -static void __exit emu10k1_cleanup_module(void) -{ - struct emu10k1_card *card; - - while (!list_empty(&emu10k1_devs)) { - card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); - - emu10k1_remove(card->pci_dev); - } return; } -#endif - module_init(emu10k1_init_module); module_exit(emu10k1_cleanup_module); diff --git a/drivers/sound/emu10k1/midi.c b/drivers/sound/emu10k1/midi.c index d7e0a4a87..f94d3b6a4 100644 --- a/drivers/sound/emu10k1/midi.c +++ b/drivers/sound/emu10k1/midi.c @@ -32,6 +32,8 @@ #define __NO_VERSION__ #include <linux/module.h> +#include <linux/malloc.h> +#include <linux/version.h> #include <linux/sched.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -64,20 +66,20 @@ static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hd if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) { ERROR(); kfree(midihdr); - return CTSTATUS_ERROR; + return -1; } - if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) { + if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) < 0) { ERROR(); kfree(midihdr->data); kfree(midihdr); - return CTSTATUS_ERROR; + return -1; } *midihdrptr = midihdr; list_add_tail(&midihdr->list, &midi_dev->mid_hdrs); - return CTSTATUS_SUCCESS; + return 0; } static int emu10k1_midi_open(struct inode *inode, struct file *file) @@ -138,20 +140,19 @@ static int emu10k1_midi_open(struct inode *inode, struct file *file) dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; - if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) - != CTSTATUS_SUCCESS) { + if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) < 0) { ERROR(); kfree(midi_dev); return -ENODEV; } /* Add two buffers to receive sysex buffer */ - if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) { + if (midiin_add_buffer(midi_dev, &midihdr1) < 0) { kfree(midi_dev); return -ENODEV; } - if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) { + if (midiin_add_buffer(midi_dev, &midihdr2) < 0) { list_del(&midihdr1->list); kfree(midihdr1->data); kfree(midihdr1); @@ -165,8 +166,7 @@ static int emu10k1_midi_open(struct inode *inode, struct file *file) dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; - if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) - != CTSTATUS_SUCCESS) { + if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) { ERROR(); kfree(midi_dev); return -ENODEV; @@ -188,6 +188,7 @@ static int emu10k1_midi_release(struct inode *inode, struct file *file) struct emu10k1_card *card; lock_kernel(); + card = midi_dev->card; DPF(2, "emu10k1_midi_release()\n"); @@ -231,6 +232,7 @@ static int emu10k1_midi_release(struct inode *inode, struct file *file) card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE)); up(&card->open_sem); wake_up_interruptible(&card->open_wait); + unlock_kernel(); return 0; @@ -252,8 +254,7 @@ static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, return -EFAULT; if (midi_dev->mistate == MIDIIN_STATE_STOPPED) { - if (emu10k1_mpuin_start(midi_dev->card) - != CTSTATUS_SUCCESS) { + if (emu10k1_mpuin_start(midi_dev->card) < 0) { ERROR(); return -EINVAL; } @@ -348,7 +349,7 @@ static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t spin_lock_irqsave(&midi_spinlock, flags); - if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) { + if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) < 0) { ERROR(); kfree(midihdr->data); kfree(midihdr); @@ -422,20 +423,20 @@ int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned lon break; default: /* Unknown message */ - return CTSTATUS_ERROR; + return -1; } spin_unlock_irqrestore(&midi_spinlock, flags); - return CTSTATUS_SUCCESS; + return 0; } /* MIDI file operations */ struct file_operations emu10k1_midi_fops = { - owner:THIS_MODULE, - read:emu10k1_midi_read, - write:emu10k1_midi_write, - poll:emu10k1_midi_poll, - open:emu10k1_midi_open, - release:emu10k1_midi_release, + owner: THIS_MODULE, + read: emu10k1_midi_read, + write: emu10k1_midi_write, + poll: emu10k1_midi_poll, + open: emu10k1_midi_open, + release: emu10k1_midi_release, }; diff --git a/drivers/sound/emu10k1/mixer.c b/drivers/sound/emu10k1/mixer.c index 62796146f..f28787f87 100644 --- a/drivers/sound/emu10k1/mixer.c +++ b/drivers/sound/emu10k1/mixer.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * mixer.c - /dev/mixer interface for emu10k1 driver @@ -36,9 +35,13 @@ #define __NO_VERSION__ /* Kernel version only defined once */ #include <linux/module.h> +#include <linux/version.h> +#include <linux/bitops.h> #include <asm/uaccess.h> #include "hwaccess.h" +#include "8010.h" +#include "recmgr.h" #define AC97_PESSIMISTIC #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -49,31 +52,13 @@ #define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31) #define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15) +#define DM_MUTE 0x80000000 + #ifdef PRIVATE_PCM_VOLUME struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS]; +u16 pcm_last_mixer = 0x6464; #endif -/* --------------------------------------------------------------------- */ - -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word - */ - -#ifdef hweight32 -#undef hweight32 -#endif - -extern __inline__ unsigned int hweight32(unsigned int w) -{ - unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); - - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); - res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); - return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); -} - /* Mapping arrays */ static const unsigned int recsrc[] = { SOUND_MASK_MIC, @@ -84,10 +69,10 @@ static const unsigned int recsrc[] = { SOUND_MASK_VOLUME, SOUND_MASK_OGAIN, /* Used to be PHONEOUT */ SOUND_MASK_PHONEIN, +#ifdef TONE_CONTROL SOUND_MASK_TREBLE, SOUND_MASK_BASS, - SOUND_MASK_MONITOR, - SOUND_MASK_PCM, +#endif }; static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { @@ -115,7 +100,7 @@ static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { /* 4 bit mono */ [SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC, /* test code */ - [SOUND_MIXER_BASS] = AC97_GENERALPUPOSE, + [SOUND_MIXER_BASS] = AC97_GENERALPURPOSE, [SOUND_MIXER_TREBLE] = AC97_MASTERTONE, [SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME, [SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME @@ -134,12 +119,25 @@ static int mixer_rdch(struct emu10k1_card *card, unsigned int ch, int *arg) int nL, nR; switch (ch) { + case SOUND_MIXER_PCM: + case SOUND_MIXER_VOLUME: +#ifdef TONE_CONTROL + case SOUND_MIXER_TREBLE: + case SOUND_MIXER_BASS: +#endif + return put_user(0x0000, (int *) arg); + default: + break; + } + + if(card->isaps) + return -EINVAL; + + switch (ch) { case SOUND_MIXER_LINE: case SOUND_MIXER_CD: case SOUND_MIXER_VIDEO: case SOUND_MIXER_LINE1: - case SOUND_MIXER_PCM: - case SOUND_MIXER_VOLUME: sblive_readac97(card, volreg[ch], ®); nL = ((~(reg >> 8) & 0x1f) * 100) / 32; nR = (~(reg & 0x1f) * 100) / 32; @@ -165,9 +163,6 @@ static int mixer_rdch(struct emu10k1_card *card, unsigned int ch, int *arg) nR = (~(reg & 0x1f) * 100) / 16; return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg); - case SOUND_MIXER_TREBLE: - case SOUND_MIXER_BASS: - return put_user(0x0000, (int *) arg); default: return -EINVAL; } @@ -204,7 +199,9 @@ static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_DIGITAL2] = 19 }; -u32 bass_table[41][5] = { +#ifdef TONE_CONTROL + +static const u32 bass_table[41][5] = { { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 }, { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d }, { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee }, @@ -248,7 +245,7 @@ u32 bass_table[41][5] = { { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 } }; -u32 treble_table[41][5] = { +static const u32 treble_table[41][5] = { { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 }, { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 }, { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 }, @@ -299,8 +296,8 @@ static void set_bass(struct emu10k1_card *card, int l, int r) l = (l * 40 + 50) / 100; r = (r * 40 + 50) / 100; for (i = 0; i < 5; i++) { - sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2), 0, bass_table[l][i]); - sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2) + 1, 0, bass_table[r][i]); + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, bass_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, bass_table[r][i]); } } @@ -311,12 +308,14 @@ static void set_treble(struct emu10k1_card *card, int l, int r) l = (l * 40 + 50) / 100; r = (r * 40 + 50) / 100; for (i = 0; i < 5; i++) { - sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, treble_table[l][i]); - sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, treble_table[r][i]); + sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2), 0, treble_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2) + 1, 0, treble_table[r][i]); } } -u32 db_table[101] = { +#endif + +static const u32 db_table[101] = { 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1, @@ -340,6 +339,29 @@ u32 db_table[101] = { 0x7fffffff, }; +static void aps_update_digital(struct emu10k1_card *card) +{ + int i, l1, r1, l2, r2; + + i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]]; + l1 = (i & 0xff); + r1 = ((i >> 8) & 0xff); + + i = card->arrwVol[volidx[SOUND_MIXER_PCM]]; + l2 = (i & 0xff); + r2 = ((i >> 8) & 0xff); + + for (i = 0; i < 108; i++) { + if (card->digmix[i] != DM_MUTE) { + if ((i % 18 >= 0) && (i % 18 < 4)) + card->digmix[i] = ((i & 1) ? ((u64) db_table[r1] * (u64) db_table[r2]) : ((u64) db_table[l1] * (u64) db_table[l2])) >> 31; + else + card->digmix[i] = (i & 1) ? db_table[r1] : db_table[l1]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); + } + } +} + static void update_digital(struct emu10k1_card *card) { int i, k, l1, r1, l2, r2, l3, r3, l4, r4; @@ -376,11 +398,11 @@ static void update_digital(struct emu10k1_card *card) l1 = i; } - for (i = 0; i < 16; i++) { - if (card->digmix[i] != 0x80000000) { - if ((i >= 0) && (i < 4)) + for (i = 0; i < 36; i++) { + if (card->digmix[i] != DM_MUTE) { + if (((i >= 0) && (i < 4)) || ((i >= 18) && (i < 22))) j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]); - else if ((i == 6) || (i == 7)) + else if ((i == 6) || (i == 7) || (i == 24) || (i == 25)) j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]); else j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31; @@ -389,11 +411,11 @@ static void update_digital(struct emu10k1_card *card) } } - for (i = 64; i < 80; i++) { - if (card->digmix[i] != 0x80000000) { - if ((i >= 64) && (i < 68)) + for (i = 72; i < 90; i++) { + if (card->digmix[i] != DM_MUTE) { + if ((i >= 72) && (i < 76)) j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]); - else if ((i == 70) || (i == 71)) + else if ((i == 78) || (i == 79)) j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]); else j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31; @@ -402,18 +424,18 @@ static void update_digital(struct emu10k1_card *card) } } - for (i = 16; i <= 80; i += 16) { - if (i != 64) { + for (i = 36; i <= 90; i += 18) { + if (i != 72) { for (k = 0; k < 4; k++) - if (card->digmix[i + k] != 0x80000000) { + if (card->digmix[i + k] != DM_MUTE) { card->digmix[i + k] = db_table[l3]; sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]); } - if (card->digmix[i + 6] != 0x80000000) { + if (card->digmix[i + 6] != DM_MUTE) { card->digmix[i + 6] = db_table[l4]; sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]); } - if (card->digmix[i + 7] != 0x80000000) { + if (card->digmix[i + 7] != DM_MUTE) { card->digmix[i + 7] = db_table[r4]; sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]); } @@ -428,9 +450,9 @@ static void update_digital(struct emu10k1_card *card) static int set_pcm_attn(struct emu10k1_card *card, int ch, int l) { #ifndef PCMLEVEL -#define PCMLEVEL 140 // almost silence +#define PCMLEVEL 110 /* almost silence */ #endif - int vol = IFATN_ATTENUATION_MASK; // silence + int vol = IFATN_ATTENUATION_MASK; /* silence */ if (l > 0) vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100); @@ -454,29 +476,29 @@ static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1) for (i = 0; i < MAX_PCM_CHANNELS; i++) { if (sblive_pcm_volume[i].files == current->files) { - sblive_pcm_volume[i].mixer = mixer; + sblive_pcm_volume[i].mixer = pcm_last_mixer = mixer; if (sblive_pcm_volume[i].opened) { if (sblive_pcm_volume[i].channel_r < NUM_G) { + sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1); if (sblive_pcm_volume[i].channel_l < NUM_G) sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1); - sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1); } else { - // mono voice + /* mono voice */ if (sblive_pcm_volume[i].channel_l < NUM_G) sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1); - // to correctly handle mono voice here we would need - // to go into stereo mode and move the voice to the right & left - // looks a bit overcomlicated... + /* to correctly handle mono voice here we would need + to go into stereo mode and move the voice to the right & left + looks a bit overcomplicated... */ } - } + return 1; + } } - if (i == MAX_PCM_CHANNELS) - card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer; + card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer; return 0; } #endif @@ -505,10 +527,11 @@ int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val) switch (ch) { case SOUND_MIXER_VOLUME: - case SOUND_MIXER_DIGITAL1: - case SOUND_MIXER_LINE3: - DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3"); - update_digital(card); + DPF(4, "SOUND_MIXER_VOLUME:\n"); + if (card->isaps) + aps_update_digital(card); + else + update_digital(card); return 0; case SOUND_MIXER_PCM: DPF(4, "SOUND_MIXER_PCM\n"); @@ -516,6 +539,34 @@ int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val) if (update_pcm_attn(card, l1, r1)) return 0; #endif + if (card->isaps) + aps_update_digital(card); + else + update_digital(card); + return 0; +#ifdef TONE_CONTROL + case SOUND_MIXER_TREBLE: + DPF(4, "SOUND_MIXER_TREBLE:\n"); + set_treble(card, l1, r1); + return 0; + + case SOUND_MIXER_BASS: + DPF(4, "SOUND_MIXER_BASS:\n"); + set_bass(card, l1, r1); + return 0; +#endif + default: + break; + } + + + if (card->isaps) + return -EINVAL; + + switch (ch) { + case SOUND_MIXER_DIGITAL1: + case SOUND_MIXER_LINE3: + DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3"); update_digital(card); return 0; case SOUND_MIXER_DIGITAL2: @@ -549,7 +600,7 @@ int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val) DPF(4, "SOUND_MIXER_MIC:\n"); i = 0; if (l1 >= 30) - // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 + /* 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 */ { l1 -= 30; i = 0x40; @@ -572,16 +623,6 @@ int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val) sblive_writeac97(card, volreg[ch], wval); return 0; - case SOUND_MIXER_TREBLE: - DPF(4, "SOUND_MIXER_TREBLE:\n"); - set_treble(card, l1, r1); - return 0; - - case SOUND_MIXER_BASS: - DPF(4, "SOUND_MIXER_BASS:\n"); - set_bass(card, l1, r1); - return 0; - default: DPF(2, "Got unknown SOUND_MIXER ioctl\n"); return -EINVAL; @@ -597,6 +638,10 @@ static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin) /* Mixer file operations */ /* FIXME: Do we need spinlocks in here? */ +/* WARNING! not all the ioctl's are supported by the emu-APS + (anything AC97 related). As a general rule keep the AC97 related ioctls + separate from the rest. This will make it easier to rewrite the mixer + using the kernel AC97 interface. */ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { static const char id[] = "SBLive"; @@ -658,10 +703,201 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned return -EFAULT; for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++) - sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]); + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & DM_MUTE) ? 0 : card->digmix[i]); return 0; break; + case SOUND_MIXER_PRIVATE3: { + struct mixer_private_ioctl ctl; + + if (copy_from_user(&ctl, (void *) arg, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + switch (ctl.cmd) { +#ifdef EMU10K1_DEBUG + case CMD_WRITEFN0: + emu10k1_writefn0(card, ctl.val[0], ctl.val[1]); + return 0; + break; + + case CMD_WRITEPTR: + if(ctl.val[1] >= 0x40) + return -EINVAL; + + if(ctl.val[0] > 0xff) + return -EINVAL; + + if((ctl.val[0] & 0x7ff) > 0x3f) + ctl.val[1] = 0x00; + + sblive_writeptr(card, ctl.val[0], ctl.val[1], ctl.val[2]); + + return 0; + break; +#endif + case CMD_READFN0: + ctl.val[2] = emu10k1_readfn0(card, ctl.val[0]); + + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_READPTR: + if(ctl.val[1] >= 0x40) + return -EINVAL; + + if((ctl.val[0] & 0x7ff) > 0xff) + return -EINVAL; + + if((ctl.val[0] & 0x7ff) > 0x3f) + ctl.val[1] = 0x00; + + ctl.val[2] = sblive_readptr(card, ctl.val[0], ctl.val[1]); + + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_SETRECSRC: + switch(ctl.val[0]){ + case WAVERECORD_AC97: + if(card->isaps) + return -EINVAL; + card->wavein.recsrc = WAVERECORD_AC97; + break; + case WAVERECORD_MIC: + card->wavein.recsrc = WAVERECORD_MIC; + break; + case WAVERECORD_FX: + card->wavein.recsrc = WAVERECORD_FX; + card->wavein.fxwc = ctl.val[1] & 0xffff; + if(!card->wavein.fxwc) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; + break; + + case CMD_GETRECSRC: + ctl.val[0] = card->wavein.recsrc; + ctl.val[1] = card->wavein.fxwc; + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_GETVOICEPARAM: + + ctl.val[0] = card->waveout.send_routing[0]; + ctl.val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 | + card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24; + + ctl.val[2] = card->waveout.send_routing[1]; + ctl.val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 | + card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24; + + ctl.val[4] = card->waveout.send_routing[2]; + ctl.val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 | + card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24; + + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_SETVOICEPARAM: + card->waveout.send_routing[0] = ctl.val[0] & 0xffff; + card->waveout.send_a[0] = ctl.val[1] & 0xff; + card->waveout.send_b[0] = (ctl.val[1] >> 8) & 0xff; + card->waveout.send_c[0] = (ctl.val[1] >> 16) & 0xff; + card->waveout.send_d[0] = (ctl.val[1] >> 24) & 0xff; + + card->waveout.send_routing[1] = ctl.val[2] & 0xffff; + card->waveout.send_a[1] = ctl.val[3] & 0xff; + card->waveout.send_b[1] = (ctl.val[3] >> 8) & 0xff; + card->waveout.send_c[1] = (ctl.val[3] >> 16) & 0xff; + card->waveout.send_d[1] = (ctl.val[3] >> 24) & 0xff; + + card->waveout.send_routing[2] = ctl.val[4] & 0xffff; + card->waveout.send_a[2] = ctl.val[5] & 0xff; + card->waveout.send_b[2] = (ctl.val[5] >> 8) & 0xff; + card->waveout.send_c[2] = (ctl.val[5] >> 16) & 0xff; + card->waveout.send_d[2] = (ctl.val[5] >> 24) & 0xff; + + return 0; + break; + + default: + return -EINVAL; + break; + } + } + break; + + case SOUND_MIXER_PRIVATE4:{ + u32 size; + int size_reg = 0; + + if (copy_from_user(&size, (void *) arg, sizeof(size))) + return -EFAULT; + + DPD(2,"External tram size 0x%x\n", size); + + if(size > 0x1fffff) + return -EINVAL; + + if (size != 0) { + size = (size - 1) >> 14; + + while (size) { + size >>= 1; + size_reg++; + } + + size = 0x4000 << size_reg; + } + + DPD(2,"External tram size 0x%x 0x%x\n", size, size_reg); + + if (size != card->tankmem.size) { + if (card->tankmem.size > 0) { + emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1); + + sblive_writeptr_tag(card, 0, TCB, 0, + TCBS, 0, + TAGLIST_END); + + pci_free_consistent(card->pci_dev, card->tankmem.size, + card->tankmem.addr, card->tankmem.dma_handle); + + card->tankmem.size = 0; + } + + if (size != 0) { + if ((card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size, + &card->tankmem.dma_handle)) == NULL) + return -ENOMEM; + + card->tankmem.size = size; + + sblive_writeptr_tag(card, 0, TCB, card->tankmem.dma_handle, + TCBS, size_reg, + TAGLIST_END); + + emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0); + } + } + return 0; + } + break; default: break; @@ -672,57 +908,107 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned if (_IOC_DIR(cmd) == _IOC_READ) { switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - DPF(2, "SOUND_MIXER_READ_RECSRC\n"); - sblive_readac97(card, AC97_RECORDSELECT, ®); - return put_user(recsrc[reg & 7], (int *) arg); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - DPF(4, "SOUND_MIXER_READ_DEVMASK\n"); + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + DPF(4, "SOUND_MIXER_READ_DEVMASK\n"); + if (card->isaps) +#ifdef TONE_CONTROL + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_BASS | SOUND_MASK_TREBLE, + (int *) arg); +#else + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME, + (int *) arg); +#endif + +#ifdef TONE_CONTROL + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_PHONEIN | SOUND_MASK_MIC | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | + SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | + SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | + SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); +#else return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_PHONEIN | SOUND_MASK_MIC | + SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | + SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | + SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); +#endif + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + DPF(2, "SOUND_MIXER_READ_RECMASK\n"); + if (card->isaps) + return put_user(0, (int *) arg); + + return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | + SOUND_MASK_LINE1 | SOUND_MASK_LINE | + SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | + SOUND_MASK_PHONEIN, (int *) arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + DPF(2, "SOUND_MIXER_READ_STEREODEVS\n"); + + if (card->isaps) +#ifdef TONE_CONTROL + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_BASS | SOUND_MASK_TREBLE, + (int *) arg); +#else + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME, + (int *) arg); +#endif + +#ifdef TONE_CONTROL + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME | - SOUND_MASK_PHONEIN | SOUND_MASK_MIC | SOUND_MASK_BASS | SOUND_MASK_TREBLE | - SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | - SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | - SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - DPF(2, "SOUND_MIXER_READ_RECMASK\n"); - return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | - SOUND_MASK_LINE1 | SOUND_MASK_LINE | - SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | - SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR | - SOUND_MASK_PCM, (int *) arg); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - DPF(2, "SOUND_MIXER_READ_STEREODEVS\n"); - return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_RECLEV | SOUND_MASK_LINE3 | + SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | + SOUND_MASK_LINE2, (int *) arg); +#else + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME | - SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | SOUND_MASK_LINE3 | - SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | + SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); +#endif - case SOUND_MIXER_CAPS: - DPF(2, "SOUND_MIXER_READ_CAPS\n"); - return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); - + case SOUND_MIXER_CAPS: + DPF(2, "SOUND_MIXER_READ_CAPS\n"); + return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); #ifdef PRIVATE_PCM_VOLUME - case SOUND_MIXER_PCM: - // needs to be before default: !! - { - int i; - - for (i = 0; i < MAX_PCM_CHANNELS; i++) { - if (sblive_pcm_volume[i].files == current->files) { - return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg); - } - } - } + case SOUND_MIXER_PCM: + /* needs to be before default: !!*/ + { + int i; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg); + } + } + } #endif default: + break; + } + + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + DPF(2, "SOUND_MIXER_READ_RECSRC\n"); + if (card->isaps) + return put_user(0, (int *) arg); + + sblive_readac97(card, AC97_RECORDSELECT, ®); + return put_user(recsrc[reg & 7], (int *) arg); + + default: i = _IOC_NR(cmd); DPD(4, "SOUND_MIXER_READ(%d)\n", i); if (i >= SOUND_MIXER_NRDEVICES) @@ -737,6 +1023,7 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned #endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } + /* End of _IOC_READ */ if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE)) return -EINVAL; @@ -748,10 +1035,13 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ DPF(2, "SOUND_MIXER_WRITE_RECSRC\n"); + if (card->isaps) + return -EINVAL; + get_user_ret(val, (int *) arg, -EFAULT); i = hweight32(val); if (i == 0) - return 0; /*val = mixer_recmask(s); */ + return 0; /* val = mixer_recmask(s); */ else if (i > 1) { sblive_readac97(card, AC97_RECORDSELECT, ®); val &= ~recsrc[reg & 7]; @@ -809,14 +1099,14 @@ static int emu10k1_mixer_open(struct inode *inode, struct file *file) static int emu10k1_mixer_release(struct inode *inode, struct file *file) { - DPF(3, "emu10k1_mixer_release()\n"); + DPF(4, "emu10k1_mixer_release()\n"); return 0; } struct file_operations emu10k1_mixer_fops = { - owner:THIS_MODULE, - llseek:emu10k1_mixer_llseek, - ioctl:emu10k1_mixer_ioctl, - open:emu10k1_mixer_open, - release:emu10k1_mixer_release, + owner: THIS_MODULE, + llseek: emu10k1_mixer_llseek, + ioctl: emu10k1_mixer_ioctl, + open: emu10k1_mixer_open, + release: emu10k1_mixer_release, }; diff --git a/drivers/sound/emu10k1/osutils.c b/drivers/sound/emu10k1/osutils.c deleted file mode 100644 index c0f5f63ac..000000000 --- a/drivers/sound/emu10k1/osutils.c +++ /dev/null @@ -1,91 +0,0 @@ - -/* - ********************************************************************** - * osutils.c - OS Services layer for emu10k1 driver - * Copyright 1999, 2000 Creative Labs, Inc. - * - ********************************************************************** - * - * Date Author Summary of changes - * ---- ------ ------------------ - * October 20, 1999 Bertrand Lee base code release - * November 2, 1999 Alan Cox cleaned up - * - ********************************************************************** - * - * 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., 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - ********************************************************************** - */ - -#include "hwaccess.h" - -struct memhandle *emu10k1_alloc_memphysical(u32 size) -{ - struct memhandle *handle; - u32 reqpage, order; - - if ((handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL)) == NULL) - return handle; - - DPD(3, "kmalloc: [%p]\n", handle); - - order = 0; - reqpage = size / PAGE_SIZE; - - if (size % PAGE_SIZE) - reqpage++; - - if (reqpage != 0) { - reqpage--; - while (reqpage > 0) { - reqpage >>= 1; - order++; - } - } - - if ((handle->virtaddx = (void *) __get_free_pages(GFP_KERNEL, order)) == NULL) { - kfree(handle); - - DPD(3, "kfree: [%p]\n", handle); - return (void *) NULL; - } - - /* in linux, we can directly access physical address, don't need to do - * phys_to_virt. - * In linux kernel 2.0.36, virt_to_bus does nothing, get_free_pages - * returns physical address. But in kernel 2.2.1 upwards, - * get_free_pages returns virtual address, we need to convert it - * to physical address. Then this physical address can be used to - * program hardware registers. */ - handle->busaddx = virt_to_bus(handle->virtaddx); - handle->order = order; - - DPD(3, "__get_free_pages: [%p] %lx\n", handle->virtaddx, handle->busaddx); - - return handle; -} - -void emu10k1_free_memphysical(struct memhandle *handle) -{ - free_pages((unsigned long) handle->virtaddx, handle->order); - kfree(handle); - - DPD(3, "free_pages: [%p]\n", handle->virtaddx); - DPD(3, "kfree: [%p]\n", handle); - - return; -} diff --git a/drivers/sound/emu10k1/recmgr.c b/drivers/sound/emu10k1/recmgr.c index 18980ce4e..81af4419e 100644 --- a/drivers/sound/emu10k1/recmgr.c +++ b/drivers/sound/emu10k1/recmgr.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * recmgr.c -- Recording manager for emu10k1 driver @@ -30,110 +29,110 @@ ********************************************************************** */ -#include "hwaccess.h" +#include "8010.h" #include "recmgr.h" -void emu10k1_start_record(struct record *rec_ptr) +void emu10k1_start_record(struct emu10k1_card *card, struct wavein_buffer *buffer) { - struct emu10k1_card *hw_ptr = rec_ptr->card; - DPF(2, "emu10k1_start_record()\n"); - DPD(2, "bus addx: %lx\n", rec_ptr->busaddx); - sblive_writeptr(hw_ptr, rec_ptr->bufaddrreg, 0, rec_ptr->busaddx); - sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, rec_ptr->bufsize); + sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval); - if (rec_ptr->adcctl) - sblive_writeptr(hw_ptr, ADCCR, 0, rec_ptr->adcctl); + if (buffer->adcctl) + sblive_writeptr(card, ADCCR, 0, buffer->adcctl); return; } -void emu10k1_stop_record(struct record *rec_ptr) +void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer) { - struct emu10k1_card *hw_ptr = rec_ptr->card; - DPF(2, "emu10k1_stop_record()\n"); /* Disable record transfer */ - if (rec_ptr->adcctl) - sblive_writeptr(hw_ptr, ADCCR, 0, 0); + if (buffer->adcctl) + sblive_writeptr(card, ADCCR, 0, 0); - sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, buffer->sizereg, 0, ADCBS_BUFSIZE_NONE); return; } -void emu10k1_set_record_src(struct record *rec_ptr, u8 recsrc) +void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst) { + struct wavein_buffer *buffer = &wiinst->buffer; + DPF(2, "emu10k1_set_record_src()\n"); - switch (recsrc) { + switch (wiinst->recsrc) { case WAVERECORD_AC97: DPF(2, "recording source: AC97\n"); - rec_ptr->bufsizereg = ADCBS; - rec_ptr->bufaddrreg = ADCBA; - rec_ptr->bufidxreg = ADCIDX_IDX; + buffer->sizereg = ADCBS; + buffer->addrreg = ADCBA; + buffer->idxreg = ADCIDX_IDX; - switch (rec_ptr->samplingrate) { + switch (wiinst->format.samplingrate) { case 0xBB80: - rec_ptr->adcctl = ADCCR_SAMPLERATE_48; + buffer->adcctl = ADCCR_SAMPLERATE_48; break; case 0xAC44: - rec_ptr->adcctl = ADCCR_SAMPLERATE_44; + buffer->adcctl = ADCCR_SAMPLERATE_44; break; case 0x7D00: - rec_ptr->adcctl = ADCCR_SAMPLERATE_32; + buffer->adcctl = ADCCR_SAMPLERATE_32; break; case 0x5DC0: - rec_ptr->adcctl = ADCCR_SAMPLERATE_24; + buffer->adcctl = ADCCR_SAMPLERATE_24; break; case 0x5622: - rec_ptr->adcctl = ADCCR_SAMPLERATE_22; + buffer->adcctl = ADCCR_SAMPLERATE_22; break; case 0x3E80: - rec_ptr->adcctl = ADCCR_SAMPLERATE_16; + buffer->adcctl = ADCCR_SAMPLERATE_16; break; case 0x2B11: - rec_ptr->adcctl = ADCCR_SAMPLERATE_11; + buffer->adcctl = ADCCR_SAMPLERATE_11; break; case 0x1F40: - rec_ptr->adcctl = ADCCR_SAMPLERATE_8; + buffer->adcctl = ADCCR_SAMPLERATE_8; break; default: + BUG(); break; } - rec_ptr->adcctl |= ADCCR_LCHANENABLE; + buffer->adcctl |= ADCCR_LCHANENABLE; - if (rec_ptr->is_stereo) - rec_ptr->adcctl |= ADCCR_RCHANENABLE; - - // rec_ptr->fxwc = 0; + if (wiinst->format.channels == 2) + buffer->adcctl |= ADCCR_RCHANENABLE; break; case WAVERECORD_MIC: DPF(2, "recording source: MIC\n"); - rec_ptr->bufsizereg = MICBS; - rec_ptr->bufaddrreg = MICBA; - rec_ptr->bufidxreg = MICIDX_IDX; - rec_ptr->adcctl = 0; - // rec_ptr->fxwc = 0; + buffer->sizereg = MICBS; + buffer->addrreg = MICBA; + buffer->idxreg = MICIDX_IDX; + buffer->adcctl = 0; break; case WAVERECORD_FX: DPF(2, "recording source: FX\n"); - rec_ptr->bufsizereg = FXBS; - rec_ptr->bufaddrreg = FXBA; - rec_ptr->bufidxreg = FXIDX_IDX; - rec_ptr->adcctl = 0; - // rec_ptr->fxwc = 0x000ffff; + buffer->sizereg = FXBS; + buffer->addrreg = FXBA; + buffer->idxreg = FXIDX_IDX; + buffer->adcctl = 0; + + sblive_writeptr(card, FXWC, 0, wiinst->fxwc); break; default: + BUG(); break; } + DPD(2, "bus addx: %x\n", buffer->dma_handle); + + sblive_writeptr(card, buffer->addrreg, 0, buffer->dma_handle); + return; } diff --git a/drivers/sound/emu10k1/recmgr.h b/drivers/sound/emu10k1/recmgr.h index 1fbde606b..6ee3f7795 100644 --- a/drivers/sound/emu10k1/recmgr.h +++ b/drivers/sound/emu10k1/recmgr.h @@ -32,31 +32,17 @@ #ifndef _RECORDMGR_H #define _RECORDMGR_H -struct record -{ - struct emu10k1_card *card; - u8 *recbuffer; - u32 recpos; - int is_stereo; - int is_16bit; - u32 recbufsize; - u32 bufsize; - u32 bufsizereg; - u32 bufaddrreg; - u32 bufidxreg; - u32 adcctl; - unsigned long busaddx; - u32 samplingrate; -}; +#include "hwaccess.h" +#include "cardwi.h" /* Recording resources */ #define WAVERECORD_AC97 0x01 #define WAVERECORD_MIC 0x02 #define WAVERECORD_FX 0x03 -void emu10k1_start_record(struct record *); -void emu10k1_stop_record(struct record *); -void emu10k1_set_record_src(struct record *, u8); +void emu10k1_start_record(struct emu10k1_card *, struct wavein_buffer *); +void emu10k1_stop_record(struct emu10k1_card *, struct wavein_buffer *); +void emu10k1_set_record_src(struct emu10k1_card *, struct wiinst *wiinst); #endif /* _RECORDMGR_H */ diff --git a/drivers/sound/emu10k1/timer.c b/drivers/sound/emu10k1/timer.c index 1614b464d..8167010bd 100644 --- a/drivers/sound/emu10k1/timer.c +++ b/drivers/sound/emu10k1/timer.c @@ -29,6 +29,9 @@ /* 4/3/2000 Implemented timer list using list.h Rui Sousa */ #include "hwaccess.h" +#include "8010.h" +#include "irqmgr.h" +#include "timer.h" /* Try to schedule only once per fragment */ @@ -42,7 +45,7 @@ void emu10k1_timer_irqhandler(struct emu10k1_card *card) list_for_each(entry, &card->timers) { t = list_entry(entry, struct emu_timer, list); - if (t->active) { + if (t->state & TIMER_STATE_ACTIVE) { t->count++; if (t->count == t->count_max) { t->count = 0; @@ -56,22 +59,17 @@ void emu10k1_timer_irqhandler(struct emu10k1_card *card) return; } -struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) (unsigned long), unsigned long data, u32 delay) +void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u32 delay) { - struct emu_timer *timer; struct emu_timer *t; struct list_head *entry; unsigned long flags; - if ((timer = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL)) == NULL) - return timer; - if (delay < 5) delay = 5; timer->delay = delay; - tasklet_init(&timer->tasklet, func, data); - timer->active = 0; + timer->state = TIMER_STATE_INSTALLED; spin_lock_irqsave(&card->timer_lock, flags); @@ -87,7 +85,7 @@ struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) card->timer_delay = delay; delay = (delay < 1024 ? delay : 1024); - WRITE_FN0(card, TIMER_RATE, delay); + emu10k1_writefn0(card, TIMER_RATE, delay); list_for_each(entry, &card->timers) { t = list_entry(entry, struct emu_timer, list); @@ -103,7 +101,7 @@ struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) spin_unlock_irqrestore(&card->timer_lock, flags); - return timer; + return; } void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) @@ -113,6 +111,9 @@ void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) u32 delay = TIMER_STOPPED; unsigned long flags; + if (timer->state == TIMER_STATE_UNINSTALLED) + return; + spin_lock_irqsave(&card->timer_lock, flags); list_del(&timer->list); @@ -132,7 +133,7 @@ void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) else { delay = (delay < 1024 ? delay : 1024); - WRITE_FN0(card, TIMER_RATE, delay); + emu10k1_writefn0(card, TIMER_RATE, delay); list_for_each(entry, &card->timers) { t = list_entry(entry, struct emu_timer, list); @@ -147,8 +148,7 @@ void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) spin_unlock_irqrestore(&card->timer_lock, flags); - tasklet_unlock_wait(&timer->tasklet); - kfree(timer); + timer->state = TIMER_STATE_UNINSTALLED; return; } @@ -158,7 +158,7 @@ void emu10k1_timer_enable(struct emu10k1_card *card, struct emu_timer *timer) unsigned long flags; spin_lock_irqsave(&card->timer_lock, flags); - timer->active = 1; + timer->state |= TIMER_STATE_ACTIVE; spin_unlock_irqrestore(&card->timer_lock, flags); return; @@ -169,7 +169,7 @@ void emu10k1_timer_disable(struct emu10k1_card *card, struct emu_timer *timer) unsigned long flags; spin_lock_irqsave(&card->timer_lock, flags); - timer->active = 0; + timer->state &= ~TIMER_STATE_ACTIVE; spin_unlock_irqrestore(&card->timer_lock, flags); return; diff --git a/drivers/sound/emu10k1/timer.h b/drivers/sound/emu10k1/timer.h index 39e1ee2c9..979576a3c 100644 --- a/drivers/sound/emu10k1/timer.h +++ b/drivers/sound/emu10k1/timer.h @@ -27,21 +27,27 @@ #ifndef _TIMER_H #define _TIMER_H +#include <linux/interrupt.h> +#include "hwaccess.h" + struct emu_timer { struct list_head list; struct tasklet_struct tasklet; - int active; + u8 state; u32 count; /* current number of interrupts */ u32 count_max; /* number of interrupts needed to schedule the bh */ u32 delay; /* timer delay */ }; -struct emu_timer *emu10k1_timer_install(struct emu10k1_card *, void (*)(unsigned long), unsigned long, u32); +void emu10k1_timer_install(struct emu10k1_card *, struct emu_timer *, u32); void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *); void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *); void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *); -#define TIMER_STOPPED 0xffffffff +#define TIMER_STOPPED 0xffffffff +#define TIMER_STATE_INSTALLED 0x01 +#define TIMER_STATE_ACTIVE 0x02 +#define TIMER_STATE_UNINSTALLED 0x04 #endif /* _TIMER_H */ diff --git a/drivers/sound/emu10k1/voicemgr.c b/drivers/sound/emu10k1/voicemgr.c index de94a453e..c61ffb92e 100644 --- a/drivers/sound/emu10k1/voicemgr.c +++ b/drivers/sound/emu10k1/voicemgr.c @@ -1,4 +1,3 @@ - /* ********************************************************************** * voicemgr.c - Voice manager for emu10k1 driver @@ -30,320 +29,288 @@ ********************************************************************** */ -#include "hwaccess.h" +#include "voicemgr.h" +#include "8010.h" -struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc) +int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice) { - struct emu10k1_card *card = voicemgr->card; - struct emu_voice *voice_tmp = voicemgr->voice; - struct emu_voice *voice = NULL; + u8 *voicetable = card->voicetable; int i; unsigned long flags; DPF(2, "emu10k1_voice_alloc()\n"); - spin_lock_irqsave(&voicemgr->lock, flags); + spin_lock_irqsave(&card->lock, flags); - if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) { - for (i = 0; i < NUM_G; i++) - if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) { - voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; - voice_tmp[i].usage = voiceallocdesc->usage; - voice = &voice_tmp[i]; + if (voice->flags & VOICE_FLAGS_STEREO) { + for (i = 0; i < NUM_G; i += 2) + if ((voicetable[i] == VOICE_USAGE_FREE) && (voicetable[i + 1] == VOICE_USAGE_FREE)) { + voicetable[i] = voice->usage; + voicetable[i + 1] = voice->usage; break; } } else { - for (i = 0; i < NUM_G; i += 2) - if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE) - && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) { - voice_tmp[i].linked_voice = &voice_tmp[i + 1]; - voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; - voice_tmp[i].usage = voiceallocdesc->usage; - voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags; - voice_tmp[i + 1].usage = voiceallocdesc->usage; - voice = &voice_tmp[i]; + for (i = 0; i < NUM_G; i++) + if (voicetable[i] == VOICE_USAGE_FREE) { + voicetable[i] = voice->usage; break; } } - spin_unlock_irqrestore(&voicemgr->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); - voice_tmp = voice; + if (i >= NUM_G) + return -1; - while (voice_tmp != NULL) { + voice->card = card; + voice->num = i; - DPD(2, " voice allocated -> %d\n", voice_tmp->num); +#ifdef PRIVATE_PCM_VOLUME - sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff); - sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF); - sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff); - sblive_writeptr(card, PTRX, voice_tmp->num, 0); + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + sblive_pcm_volume[i].channel_l = voice->num; + DPD(2, "preset left: %d\n", voice->num); + if (voice->flags & VOICE_FLAGS_STEREO) { + sblive_pcm_volume[i].channel_r = voice->num + 1; + DPD(2, "preset right: %d\n", voice->num + 1); + } + break; + } + } +#endif + + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + DPD(2, " voice allocated -> %d\n", voice->num + i); - voice_tmp = voice_tmp->linked_voice; + sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff, + DCYSUSV, 0, + VTFT, 0x0000ffff, + PTRX, 0, + TAGLIST_END); } - return voice; + return 0; } -void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice) +void emu10k1_voice_free(struct emu_voice *voice) { struct emu10k1_card *card = voice->card; - struct emu_voice *voice_tmp; - unsigned dcysusv; - u32 cra, sample; int i; unsigned long flags; DPF(2, "emu10k1_voice_free()\n"); - voice_tmp = voice; - - while (voice_tmp != NULL) { - - DPD(2, " voice freed -> %d\n", voice_tmp->num); + if (voice->usage == VOICE_USAGE_FREE) + return; - sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK); - sblive_writeptr(card, IP, voice_tmp->num, 0); +#ifdef PRIVATE_PCM_VOLUME + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + if (voice->num == sblive_pcm_volume[i].channel_l) + sblive_pcm_volume[i].channel_l = NUM_G; + if ((voice->flags & VOICE_FLAGS_STEREO) + && (voice->num + 1) == sblive_pcm_volume[i].channel_r) { + sblive_pcm_volume[i].channel_r = NUM_G; + } + break; + } + } +#endif - dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK); - sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF); + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + DPD(2, " voice released -> %d\n", voice->num + i); - sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK); - sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0); - sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK); - sblive_writeptr(card, CPF, voice_tmp->num, 0); + sblive_writeptr_tag(card, voice->num + i, DCYSUSV, 0, + VTFT, 0x0000ffff, + PTRX_PITCHTARGET, 0, + CVCF, 0x0000ffff, + CPF, 0, + TAGLIST_END); + } - sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080; - cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK; - sblive_writeptr(card, CCR, voice_tmp->num, cra); - cra = (cra >> 18) & 0xf; - sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); - cra = (cra + 0x1) & 0xf; - sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); + voice->usage = VOICE_USAGE_FREE; - for (i = 0; i < NUM_FXSENDS; i++) - voice_tmp->sendhandle[i] = 0; + spin_lock_irqsave(&card->lock, flags); - voice_tmp->flags = 0; + card->voicetable[voice->num] = VOICE_USAGE_FREE; - spin_lock_irqsave(&voicemgr->lock, flags); - voice_tmp->usage = VOICEMGR_USAGE_FREE; + if (voice->flags & VOICE_FLAGS_STEREO) + card->voicetable[voice->num + 1] = VOICE_USAGE_FREE; - voice_tmp = voice_tmp->linked_voice; - voice->linked_voice = NULL; - spin_unlock_irqrestore(&voicemgr->lock, flags); - } + spin_unlock_irqrestore(&card->lock, flags); return; } -/* Sets up a voices for Wave Playback */ - void emu10k1_voice_playback_setup(struct emu_voice *voice) { struct emu10k1_card *card = voice->card; - u32 sample, cra = 0, start = 0; + u32 start; + int i; DPF(2, "emu10k1_voice_playback_setup()\n"); - while (voice != NULL) { - sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF); - sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK); - sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK); - sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000); - - /* Stop CA */ - /* Assumption that PT is alreadt 0 so no harm overwriting */ - sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b); - - if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) { - if (voice->linked_voice != NULL) { - /* Set stereo bit */ - cra = 64; - sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK); - sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK); - } else { - cra = 32; - sblive_writeptr(card, CPF, voice->num, 0); - } - - if (voice->flags & VOICEMGR_FLAGS_16BIT) - sample = 0; - else { - cra = cra * 2; - sample = 0x80808080; - } - cra -= 4; - - if (voice->linked_voice != NULL) { - /* CCR_READADDRESS_MASK */ - sblive_writeptr(card, CCR, voice->num, 0x3c << 16); - sblive_writeptr(card, CCR, voice->num + 1, cra << 16); - sblive_writeptr(card, CDE, voice->num + 1, sample); - sblive_writeptr(card, CDF, voice->num + 1, sample); - start = voice->params.start + cra / 2; - } else { - sblive_writeptr(card, CCR, voice->num, 0x1c << 16); /* FIXME: Is 0x1c correct? */ - sblive_writeptr(card, CDE, voice->num, sample); - sblive_writeptr(card, CDF, voice->num, sample); - start = voice->params.start + cra; - } - - if (start > voice->params.endloop) { - start -= voice->params.endloop; - - if (voice->linked_voice != NULL) - cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9); - else - cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9); - - start += voice->params.startloop; - - if (start >= voice->params.endloop) - start = voice->params.endloop - 1; - } else if (voice->linked_voice != NULL) - cra = (cra << 25) | (0x3c << 16); - else - cra = (cra << 25) | (0x1c << 16); - - start |= CCCA_INTERPROM_0; - } - - /* CSL, ST, CA */ - sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24)); - sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24)); + if (voice->flags & VOICE_FLAGS_STEREO) { + /* Set stereo bit */ + start = 28; + sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK); + sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK); + } else { + start = 30; + sblive_writeptr(card, CPF, voice->num, 0); + } - if (voice->flags & VOICEMGR_FLAGS_16BIT) - sblive_writeptr(card, CCCA, voice->num, start); - else - sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT); + if(!(voice->flags & VOICE_FLAGS_16BIT)) + start *= 2; - /* Clear filter delay memory */ - sblive_writeptr(card, Z1, voice->num, 0); - sblive_writeptr(card, Z2, voice->num, 0); + voice->start += start; - /* Invalidate maps */ - sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); - sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16); - /* Fill cache */ - if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) - sblive_writeptr(card, CCR, voice->num, cra); - - sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK); - sblive_writeptr(card, LFOVAL1, voice->num, 0x8000); - sblive_writeptr(card, ATKHLDM, voice->num, 0); - sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK); - sblive_writeptr(card, LFOVAL2, voice->num, 0x8000); - sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch); - sblive_writeptr(card, PEFE, voice->num, 0x7f); - sblive_writeptr(card, FMMOD, voice->num, 0); - sblive_writeptr(card, TREMFRQ, voice->num, 0); - sblive_writeptr(card, FM2FRQ2, voice->num, 0); - sblive_writeptr(card, ENVVAL, voice->num, 0xbfff); - sblive_writeptr(card, ENVVOL, voice->num, 0xbfff); + /* Stop CA */ + /* Assumption that PT is already 0 so no harm overwriting */ + sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b); + + sblive_writeptr_tag(card, voice->num + i, + /* CSL, ST, CA */ + DSL, voice->endloop | (voice->params[i].send_d << 24), + PSST, voice->startloop | (voice->params[i].send_c << 24), + CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT), + /* Clear filter delay memory */ + Z1, 0, + Z2, 0, + /* Invalidate maps */ + MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + /* modulation envelope */ + CVCF, 0x0000ffff, + VTFT, 0x0000ffff, + ATKHLDM, 0, + DCYSUSM, 0x007f, + LFOVAL1, 0x8000, + LFOVAL2, 0x8000, + FMMOD, 0, + TREMFRQ, 0, + FM2FRQ2, 0, + ENVVAL, 0x8000, + /* volume envelope */ + ATKHLDV, 0x7f7f, + ENVVOL, 0x8000, + /* filter envelope */ + PEFE_FILTERAMOUNT, 0x7f, + /* pitch envelope */ + PEFE_PITCHAMOUNT, 0, TAGLIST_END); #ifdef PRIVATE_PCM_VOLUME - { - int i; - - for (i = 0; i < MAX_PCM_CHANNELS; i++) { - if (sblive_pcm_volume[i].channel_l == voice->num) { - voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l : - // test for mono channel (reverse logic is correct here!) - (sblive_pcm_volume[i].attn_r > - sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r; - DPD(2, "set left volume %d\n", voice->params.initial_attn); - break; - } else if (sblive_pcm_volume[i].channel_r == voice->num) { - voice->params.initial_attn = sblive_pcm_volume[i].attn_r; - DPD(2, "set right volume %d\n", voice->params.initial_attn); - break; - } - } - } +{ +int j; + for (j = 0; j < MAX_PCM_CHANNELS; j++) { + if (sblive_pcm_volume[j].channel_l == voice->num + i) { + voice->params[i].initial_attn = (sblive_pcm_volume[j].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l : + // test for mono channel (reverse logic is correct here!) + (sblive_pcm_volume[j].attn_r > + sblive_pcm_volume[j].attn_l) ? sblive_pcm_volume[j].attn_l : sblive_pcm_volume[j].attn_r; + DPD(2, "set left volume %d\n", voice->params[i].initial_attn); + break; + } else if (sblive_pcm_volume[j].channel_r == voice->num + i) { + voice->params[i].initial_attn = sblive_pcm_volume[j].attn_r; + DPD(2, "set right volume %d\n", voice->params[i].initial_attn); + break; + } + } + } #endif - sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn); - - voice->params.FC_target = 0xffff; - voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16); - voice = voice->linked_voice; + voice->params[i].fc_target = 0xffff; } return; } -void emu10k1_voice_start(struct emu_voice *voice) +void emu10k1_voice_start(struct emu_voice *voice, int set) { struct emu10k1_card *card = voice->card; + int i; DPF(2, "emu10k1_voice_start()\n"); - while (voice != NULL) { - sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target); - - if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) - sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target); - - sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16) - | voice->params.FC_target); - sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16) - | voice->params.FC_target); - sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8) - | ENV_ON | voice->params.byampl_env_decay); - - /* Using StopOnLoop for MIDI stops the playback - too early, which may cause a DC level to be played - until the note is released. */ - - if (voice->usage == VOICEMGR_USAGE_MIDI) - emu10k1_clear_stop_on_loop(card, voice->num); - else { - if (voice->params.startloop > voice->params.end) - emu10k1_set_stop_on_loop(card, voice->num); - else - emu10k1_clear_stop_on_loop(card, voice->num); + if (!set) { + u32 cra, ccis, cs, sample; + if (voice->flags & VOICE_FLAGS_STEREO) { + cra = 64; + ccis = 28; + cs = 4; + } else { + cra = 64; + ccis = 30; + cs = 2; } - voice = voice->linked_voice; - } - return; -} + if(voice->flags & VOICE_FLAGS_16BIT) { + sample = 0x00000000; + } else { + sample = 0x80808080; + ccis *= 2; + } -void emu10k1_voice_stop(struct emu_voice *voice) -{ - struct emu10k1_card *card = voice->card; + for(i = 0; i < cs; i++) + sblive_writeptr(card, CD0 + i, voice->num, sample); - DPF(2, "emu10k1_voice_stop()\n"); + /* Reset cache */ + sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, 0); + if (voice->flags & VOICE_FLAGS_STEREO) + sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num + 1, 0); + + sblive_writeptr(card, CCR_READADDRESS, voice->num, cra); + + if (voice->flags & VOICE_FLAGS_STEREO) + sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra); - while (voice != NULL) { - sblive_writeptr(card, IFATN, voice->num, 0xffff); - sblive_writeptr(card, IP, voice->num, 0); - sblive_writeptr(card, VTFT, voice->num, 0xffff); - sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0); - voice = voice->linked_voice; + /* Fill cache */ + sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis); } - return; -} + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + sblive_writeptr_tag(card, voice->num + i, + IFATN, (voice->params[i].initial_fc << 8) | voice->params[i].initial_attn, + VTFT, (voice->params[i].volume_target << 16) | voice->params[i].fc_target, + CVCF, (voice->params[i].volume_target << 16) | voice->params[i].fc_target, + DCYSUSV, (voice->params[i].byampl_env_sustain << 8) | voice->params[i].byampl_env_decay, + TAGLIST_END); -void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam) -{ - struct emu10k1_card *card = voice->card; - int count; + emu10k1_clear_stop_on_loop(card, voice->num + i); + + sblive_writeptr(card, PTRX_PITCHTARGET, voice->num + i, voice->pitch_target); - for (count = 0; count < numparam; count++) - sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value); + if (i == 0) + sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->pitch_target); + + sblive_writeptr(card, IP, voice->num + i, voice->initial_pitch); + } return; } -void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value) +void emu10k1_voice_stop(struct emu_voice *voice) { struct emu10k1_card *card = voice->card; + int i; - *value = sblive_readptr(card, controlid, voice->num); + DPF(2, "emu10k1_voice_stop()\n"); + + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + sblive_writeptr_tag(card, voice->num + i, + PTRX_PITCHTARGET, 0, + CPF_CURRENTPITCH, 0, + IFATN, 0xffff, + VTFT, 0x0000ffff, + CVCF, 0x0000ffff, + IP, 0, + TAGLIST_END); + } return; } + diff --git a/drivers/sound/emu10k1/voicemgr.h b/drivers/sound/emu10k1/voicemgr.h index bef340d8b..58ab55f2d 100644 --- a/drivers/sound/emu10k1/voicemgr.h +++ b/drivers/sound/emu10k1/voicemgr.h @@ -31,120 +31,61 @@ #ifndef _VOICEMGR_H #define _VOICEMGR_H + +#include "hwaccess.h" + /* struct emu_voice.usage flags */ -#define VOICEMGR_USAGE_FREE 0x00000000 -#define VOICEMGR_USAGE_MIDI 0x00000001 -#define VOICEMGR_USAGE_PLAYBACK 0x00000002 +#define VOICE_USAGE_FREE 0x01 +#define VOICE_USAGE_MIDI 0x02 +#define VOICE_USAGE_PLAYBACK 0x04 /* struct emu_voice.flags flags */ -#define VOICEMGR_FLAGS_MONO 0x00000002 -#define VOICEMGR_FLAGS_16BIT 0x00000004 -#define VOICEMGR_FLAGS_STEREOSLAVE 0x00000008 -#define VOICEMGR_FLAGS_VOICEMASTER 0x80000000 -#define VOICEMGR_FLAGS_FXRT2 0x00000010 +#define VOICE_FLAGS_STEREO 0x02 +#define VOICE_FLAGS_16BIT 0x04 struct voice_param { - /* Sound engine */ - u32 start; - u32 startloop; - u32 endloop; - u32 end; - - u16 current_pitch; - u16 pitch_target; - - u16 current_volume; - u16 volume_target; - - u16 current_FC; - u16 FC_target; - - u8 pan_target; - u8 aux_target; - /* FX bus amount send */ + u32 send_routing; + u32 send_a; u32 send_b; u32 send_c; u32 send_d; - /* Envelope engine */ - u16 ampl_env_delay; - u8 byampl_env_attack; - u8 byampl_env_hold; - u8 byampl_env_decay; - u8 byampl_env_sustain; - u8 byampl_env_release; - - u16 aux_env_delay; - u8 byaux_env_attack; - u8 byaux_env_hold; - u8 byaux_env_decay; - u8 byaux_env_sustain; - u8 byaux_env_release; - - u16 mod_LFO_delay; /* LFO1 */ - u16 vib_LFO_delay; /* LFO2 */ - u8 mod_LFO_freq; /* LFO1 */ - u8 vib_LFO_freq; /* LFO2 */ - - s8 aux_env_to_pitch; - s8 aux_env_to_FC; - s8 mod_LFO_to_pitch; - s8 vib_LFO_to_pitch; - s8 mod_LFO_to_FC; - s8 mod_LFO_to_volume; - - u16 sample_pitch; - u16 initial_pitch; - u8 initial_attn; - u8 initial_FC; -}; + u32 initial_fc; + u32 fc_target; -struct voice_allocdesc -{ - u32 usage; /* playback, Midi */ - u32 flags; /* stereo/mono rec/playback 8/16 bit*/ + u32 initial_attn; + u32 volume_target; + + u32 byampl_env_sustain; + u32 byampl_env_decay; }; + struct emu_voice { - struct list_head list; - struct emu10k1_card *card; - u32 usage; /* Free, MIDI, playback */ - u32 num; /* Voice ID */ - u32 flags; /* Stereo/mono, rec/playback, 8/16 bit */ - - struct voice_param params; - - struct emu_voice *linked_voice; /*for stereo voice*/ - - u32 sendhandle[NUM_FXSENDS]; -}; + u8 usage; /* Free, MIDI, playback */ + u8 num; /* Voice ID */ + u8 flags; /* Stereo/mono, 8/16 bit */ -struct voice_manager -{ - struct emu10k1_card *card; - spinlock_t lock; + u32 startloop; + u32 endloop; + u32 start; - struct emu_voice voice[NUM_G]; -}; + u32 initial_pitch; + u32 pitch_target; -struct voice_cntlset -{ - u32 paramID; - u32 value; + struct voice_param params[2]; }; -struct emu_voice *emu10k1_voice_alloc(struct voice_manager *, struct voice_allocdesc *); -void emu10k1_voice_free(struct voice_manager *, struct emu_voice *); +int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *); +void emu10k1_voice_free(struct emu_voice *); void emu10k1_voice_playback_setup(struct emu_voice *); -void emu10k1_voice_start(struct emu_voice *); +void emu10k1_voice_start(struct emu_voice *, int); void emu10k1_voice_stop(struct emu_voice *); -void emu10k1_voice_setcontrol(struct emu_voice *, struct voice_cntlset *, u32); -void emu10k1_voice_getcontrol(struct emu_voice *, u32, u32 *); #endif /* _VOICEMGR_H */ diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index a5bb668f2..01f2cf46f 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -302,8 +302,6 @@ static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 }; #define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) #define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) -#define SND_DEV_DSP16 5 - /* --------------------------------------------------------------------- */ struct es1370_state { diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index df362e8bb..4e340c3cc 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -364,8 +364,6 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 }; #define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) #define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) -#define SND_DEV_DSP16 5 - #define ES1371_MODULE_NAME "es1371" #define PFX ES1371_MODULE_NAME ": " diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index 1029f179a..30d02d226 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "gus.h" #include "gus_hw.h" @@ -184,7 +183,8 @@ static void __init attach_gus_db16(struct address_info *hw_config) hw_config->irq, hw_config->dma, hw_config->dma, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); } static void __exit unload_gus_db16(struct address_info *hw_config) @@ -259,7 +259,7 @@ static int __init init_gus(void) if (!probe_gus(&cfg)) return -ENODEV; attach_gus(&cfg); - SOUND_LOCK; + return 0; } @@ -270,7 +270,6 @@ static void __exit cleanup_gus(void) unload_gus_db16(&cfg); #endif unload_gus(&cfg); - SOUND_LOCK_END; } module_init(init_gus); diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c index 1594afb1a..1705d0df2 100644 --- a/drivers/sound/gus_midi.c +++ b/drivers/sound/gus_midi.c @@ -186,23 +186,17 @@ static int gus_midi_buffer_status(int dev) static struct midi_operations gus_midi_operations = { - { - "Gravis UltraSound Midi", 0, 0, SNDCARD_GUS - }, - &std_midi_synth, - {0}, - gus_midi_open, - gus_midi_close, - NULL, /* ioctl */ - gus_midi_out, - gus_midi_start_read, - gus_midi_end_read, - gus_midi_kick, - NULL, /* - * command - */ - gus_midi_buffer_status, - NULL + owner: THIS_MODULE, + info: {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, + converter: &std_midi_synth, + in_info: {0}, + open: gus_midi_open, + close: gus_midi_close, + outputc: gus_midi_out, + start_read: gus_midi_start_read, + end_read: gus_midi_end_read, + kick: gus_midi_kick, + buffer_status: gus_midi_buffer_status, }; void gus_midi_init(struct address_info *hw_config) diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 30ba0ede3..26853486e 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -2613,16 +2613,16 @@ static int gus_local_qlen(int dev) static struct audio_driver gus_audio_driver = { - gus_audio_open, - gus_audio_close, - gus_audio_output_block, - gus_audio_start_input, - gus_audio_ioctl, - gus_audio_prepare_for_input, - gus_audio_prepare_for_output, - gus_audio_reset, - gus_local_qlen, - NULL + owner: THIS_MODULE, + open: gus_audio_open, + close: gus_audio_close, + output_block: gus_audio_output_block, + start_input: gus_audio_start_input, + ioctl: gus_audio_ioctl, + prepare_for_input: gus_audio_prepare_for_input, + prepare_for_output: gus_audio_prepare_for_output, + halt_io: gus_audio_reset, + local_qlen: gus_local_qlen, }; static void guswave_setup_voice(int dev, int voice, int chn) @@ -2702,27 +2702,28 @@ static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *al static struct synth_operations guswave_operations = { - "GUS", - &gus_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_GUS, - guswave_open, - guswave_close, - guswave_ioctl, - guswave_kill_note, - guswave_start_note, - guswave_set_instr, - guswave_reset, - guswave_hw_control, - guswave_load_patch, - guswave_aftertouch, - guswave_controller, - guswave_panning, - guswave_volume_method, - guswave_bender, - guswave_alloc, - guswave_setup_voice + owner: THIS_MODULE, + id: "GUS", + info: &gus_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: SAMPLE_TYPE_GUS, + open: guswave_open, + close: guswave_close, + ioctl: guswave_ioctl, + kill_note: guswave_kill_note, + start_note: guswave_start_note, + set_instr: guswave_set_instr, + reset: guswave_reset, + hw_control: guswave_hw_control, + load_patch: guswave_load_patch, + aftertouch: guswave_aftertouch, + controller: guswave_controller, + panning: guswave_panning, + volume_method: guswave_volume_method, + bender: guswave_bender, + alloc_voice: guswave_alloc, + setup_voice: guswave_setup_voice }; static void set_input_volumes(void) @@ -2894,9 +2895,10 @@ int gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations gus_mixer_operations = { - "GUS", - "Gravis Ultrasound", - gus_default_mixer_ioctl + owner: THIS_MODULE, + id: "GUS", + name: "Gravis Ultrasound", + ioctl: gus_default_mixer_ioctl }; static int gus_default_mixer_init(void) @@ -3050,7 +3052,8 @@ void gus_wave_init(struct address_info *hw_config) -irq, gus_dma2, /* Playback DMA */ gus_dma, /* Capture DMA */ 1, /* Share DMA channels with GF1 */ - hw_config->osp); + hw_config->osp, + THIS_MODULE); if (num_mixers > old_num_mixers) { diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c index 27a1c243b..15b469cf5 100644 --- a/drivers/sound/i810_audio.c +++ b/drivers/sound/i810_audio.c @@ -189,12 +189,6 @@ enum { /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ #define NR_AC97 2 -/* minor number of /dev/dspW */ -#define SND_DEV_DSP8 1 - -/* minor number of /dev/dspW */ -#define SND_DEV_DSP16 1 - static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; diff --git a/drivers/sound/ics2101.c b/drivers/sound/ics2101.c index 3b97a157b..84ca968df 100644 --- a/drivers/sound/ics2101.c +++ b/drivers/sound/ics2101.c @@ -206,9 +206,10 @@ static int ics2101_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations ics2101_mixer_operations = { - "ICS2101", - "ICS2101 Multimedia Mixer", - ics2101_mixer_ioctl + owner: THIS_MODULE, + id: "ICS2101", + name: "ICS2101 Multimedia Mixer", + ioctl: ics2101_mixer_ioctl }; int diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 5290b42ed..7d071ee69 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -73,7 +73,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "ad1848.h" #include "sb.h" @@ -710,7 +709,8 @@ static void __init attach_mad16(struct address_info *hw_config) hw_config->irq, dma, dma2, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); request_region(hw_config->io_base, 4, "MAD16 WSS config"); } @@ -724,7 +724,7 @@ static void __init attach_mad16_mpu(struct address_info *hw_config) hw_config->io_base = 0x220; hw_config->name = "Mad16/Mozart"; - sb_dsp_init(hw_config); + sb_dsp_init(hw_config, THIS_MODULE); return; #endif @@ -733,7 +733,7 @@ static void __init attach_mad16_mpu(struct address_info *hw_config) hw_config->driver_use_1 = SB_MIDI_ONLY; hw_config->name = "Mad16/Mozart"; - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); } static int __init probe_mad16_mpu(struct address_info *hw_config) @@ -1094,7 +1094,6 @@ static int __init init_mad16(void) if (found_mpu) attach_mad16_mpu(&cfg_mpu); - SOUND_LOCK; return 0; } @@ -1103,7 +1102,6 @@ static void __exit cleanup_mad16(void) if (found_mpu) unload_mad16_mpu(&cfg_mpu); unload_mad16(&cfg); - SOUND_LOCK_END; } module_init(init_mad16); diff --git a/drivers/sound/maestro.c b/drivers/sound/maestro.c index 6c664aea4..9d848e2a7 100644 --- a/drivers/sound/maestro.c +++ b/drivers/sound/maestro.c @@ -301,8 +301,6 @@ static int use_pm=2; /* set to 1 for force */ #define NR_DSPS (1<<dsps_order) #define NR_IDRS 32 -#define SND_DEV_DSP16 5 - #define NR_APUS 64 #define NR_APU_REGS 16 diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c index 797150997..d9226d406 100644 --- a/drivers/sound/maui.c +++ b/drivers/sound/maui.c @@ -30,7 +30,6 @@ #define USE_SIMPLE_MACROS #include "sound_config.h" -#include "soundmodule.h" #include "sound_firmware.h" #include "mpu401.h" @@ -375,7 +374,7 @@ static void __init attach_maui(struct address_info *hw_config) hw_config->irq *= -1; hw_config->name = "Maui"; - attach_mpu401(hw_config); + attach_mpu401(hw_config, THIS_MODULE); if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ { struct synth_operations *synth; @@ -443,7 +442,7 @@ static int __init init_maui(void) if (probe_maui(&cfg) == 0) return -ENODEV; attach_maui(&cfg); - SOUND_LOCK; + return 0; } @@ -452,7 +451,6 @@ static void __exit cleanup_maui(void) if (fw_load && maui_os) vfree(maui_os); unload_maui(&cfg); - SOUND_LOCK_END; } module_init(init_maui); diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c index 9f1b9ef59..b0e96c519 100644 --- a/drivers/sound/midi_synth.c +++ b/drivers/sound/midi_synth.c @@ -431,9 +431,6 @@ midi_synth_open(int dev, int mode) if ((err = midi_devs[orig_dev]->open(orig_dev, mode, midi_synth_input, midi_synth_output)) < 0) return err; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif inc = &midi_devs[orig_dev]->in_info; save_flags(flags); @@ -461,9 +458,6 @@ midi_synth_close(int dev) midi_devs[orig_dev]->outputc(orig_dev, 0xfe); midi_devs[orig_dev]->close(orig_dev); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif } void diff --git a/drivers/sound/midi_synth.h b/drivers/sound/midi_synth.h index 1509b2255..40c8f705f 100644 --- a/drivers/sound/midi_synth.h +++ b/drivers/sound/midi_synth.h @@ -22,27 +22,26 @@ static struct synth_info std_synth_info = static struct synth_operations std_midi_synth = { - "MIDI", - &std_synth_info, - 0, - SYNTH_TYPE_MIDI, - 0, - midi_synth_open, - midi_synth_close, - midi_synth_ioctl, - midi_synth_kill_note, - midi_synth_start_note, - midi_synth_set_instr, - midi_synth_reset, - midi_synth_hw_control, - midi_synth_load_patch, - midi_synth_aftertouch, - midi_synth_controller, - midi_synth_panning, - NULL, - midi_synth_bender, - NULL, /* alloc_voice */ - midi_synth_setup_voice, - midi_synth_send_sysex + owner: THIS_MODULE, + id: "MIDI", + info: &std_synth_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_MIDI, + synth_subtype: 0, + open: midi_synth_open, + close: midi_synth_close, + ioctl: midi_synth_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + hw_control: midi_synth_hw_control, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice, + send_sysex: midi_synth_send_sysex }; #endif diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index 913493a4a..d0db7d5d2 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -172,6 +172,9 @@ int MIDIbuf_open(int dev, struct file *file) * Interrupts disabled. Be careful */ + if (midi_devs[dev]->owner) + __MOD_INC_USE_COUNT (midi_devs[dev]->owner); + if ((err = midi_devs[dev]->open(dev, mode, midi_input_intr, midi_output_intr)) < 0) return err; @@ -257,6 +260,9 @@ void MIDIbuf_release(int dev, struct file *file) if (open_devs < 2) del_timer(&poll_timer);; open_devs--; + + if (midi_devs[dev]->owner) + __MOD_DEC_USE_COUNT (midi_devs[dev]->owner); } int MIDIbuf_write(int dev, struct file *file, const char *buf, int count) diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index a329f0e72..de587668a 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -15,14 +15,13 @@ * Alan Cox modularisation, use normal request_irq, use dev_id */ -#include <linux/init.h> #include <linux/module.h> +#include <linux/init.h> #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" -#include "soundmodule.h" #include "coproc.h" #include "mpu401.h" @@ -866,47 +865,45 @@ static void mpu_synth_close(int dev) static struct synth_operations mpu401_synth_proto = { - "MPU401", - NULL, - 0, - SYNTH_TYPE_MIDI, - 0, - mpu_synth_open, - mpu_synth_close, - mpu_synth_ioctl, - midi_synth_kill_note, - midi_synth_start_note, - midi_synth_set_instr, - midi_synth_reset, - midi_synth_hw_control, - midi_synth_load_patch, - midi_synth_aftertouch, - midi_synth_controller, - midi_synth_panning, - NULL, - midi_synth_bender, - NULL, /* alloc */ - midi_synth_setup_voice, - midi_synth_send_sysex + owner: THIS_MODULE, + id: "MPU401", + info: NULL, + midi_dev: 0, + synth_type: SYNTH_TYPE_MIDI, + synth_subtype: 0, + open: mpu_synth_open, + close: mpu_synth_close, + ioctl: mpu_synth_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + hw_control: midi_synth_hw_control, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice, + send_sysex: midi_synth_send_sysex }; static struct synth_operations *mpu401_synth_operations[MAX_MIDI_DEV]; static struct midi_operations mpu401_midi_proto = { - {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - NULL, - {0}, - mpu401_open, - mpu401_close, - mpu401_ioctl, - mpu401_out, - mpu401_start_read, - mpu401_end_read, - mpu401_kick, - NULL, - mpu401_buffer_status, - mpu401_prefix_cmd + owner: THIS_MODULE, + info: {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, + in_info: {0}, + open: mpu401_open, + close: mpu401_close, + ioctl: mpu401_ioctl, + outputc: mpu401_out, + start_read: mpu401_start_read, + end_read: mpu401_end_read, + kick: mpu401_kick, + buffer_status: mpu401_buffer_status, + prefix_cmd: mpu401_prefix_cmd }; static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; @@ -942,7 +939,7 @@ static void __init mpu401_chk_version(int n, struct mpu_config *devc) restore_flags(flags); } -void __init attach_mpu401(struct address_info *hw_config) +void __init attach_mpu401(struct address_info *hw_config, struct module *owner) { unsigned long flags; char revision_char; @@ -1089,6 +1086,10 @@ void __init attach_mpu401(struct address_info *hw_config) hw_config->slots[2] = mpu_timer_init(m); midi_devs[m] = &mpu401_midi_operations[devc->devno]; + + if (owner) + midi_devs[m]->owner = owner; + hw_config->slots[1] = m; sequencer_init(); } @@ -1574,15 +1575,16 @@ static void mpu_timer_arm(int dev, long time) static struct sound_timer_operations mpu_timer = { - {"MPU-401 Timer", 0}, - 10, /* Priority */ - 0, /* Local device link */ - mpu_timer_open, - mpu_timer_close, - mpu_timer_event, - mpu_timer_get_time, - mpu_timer_ioctl, - mpu_timer_arm + owner: THIS_MODULE, + info: {"MPU-401 Timer", 0}, + priority: 10, /* Priority */ + devlink: 0, /* Local device link */ + open: mpu_timer_open, + close: mpu_timer_close, + event: mpu_timer_event, + get_time: mpu_timer_get_time, + ioctl: mpu_timer_ioctl, + arm_timer: mpu_timer_arm }; static void mpu_timer_interrupt(void) @@ -1731,10 +1733,9 @@ int init_mpu401(void) cfg.io_base = io; if (probe_mpu401(&cfg) == 0) return -ENODEV; - attach_mpu401(&cfg); + attach_mpu401(&cfg, THIS_MODULE); } - SOUND_LOCK; return 0; } @@ -1744,7 +1745,6 @@ void cleanup_mpu401(void) /* Check for use by, for example, sscape driver */ unload_mpu401(&cfg); } - SOUND_LOCK_END; } module_init(init_mpu401); diff --git a/drivers/sound/mpu401.h b/drivers/sound/mpu401.h index a6a41cbde..a74f7285a 100644 --- a/drivers/sound/mpu401.h +++ b/drivers/sound/mpu401.h @@ -7,14 +7,14 @@ /* From uart401.c */ int probe_uart401 (struct address_info *hw_config); -void attach_uart401 (struct address_info *hw_config); +void attach_uart401 (struct address_info *hw_config, struct module *owner); void unload_uart401 (struct address_info *hw_config); void uart401intr (int irq, void *dev_id, struct pt_regs * dummy); /* From mpu401.c */ int probe_mpu401(struct address_info *hw_config); -void attach_mpu401(struct address_info * hw_config); +void attach_mpu401(struct address_info * hw_config, struct module *owner); void unload_mpu401(struct address_info *hw_info); int intchk_mpu401(void *dev_id); diff --git a/drivers/sound/nm256_audio.c b/drivers/sound/nm256_audio.c index e9ec909f6..a07029ad6 100644 --- a/drivers/sound/nm256_audio.c +++ b/drivers/sound/nm256_audio.c @@ -20,7 +20,6 @@ #include <linux/pm.h> #include <linux/delay.h> #include "sound_config.h" -#include "soundmodule.h" #include "nm256.h" #include "nm256_coeff.h" @@ -926,9 +925,10 @@ nm256_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) } static struct mixer_operations nm256_mixer_operations = { - "NeoMagic", - "NM256AC97Mixer", - nm256_default_mixer_ioctl + owner: THIS_MODULE, + id: "NeoMagic", + name: "NM256AC97Mixer", + ioctl: nm256_default_mixer_ioctl }; /* @@ -1621,22 +1621,16 @@ nm256_audio_local_qlen(int dev) static struct audio_driver nm256_audio_driver = { - nm256_audio_open, /* open */ - nm256_audio_close, /* close */ - nm256_audio_output_block, /* output_block */ - nm256_audio_start_input, /* start_input */ - nm256_audio_ioctl, /* ioctl */ - nm256_audio_prepare_for_input, /* prepare_for_input */ - nm256_audio_prepare_for_output, /* prepare_for_output */ - nm256_audio_reset, /* reset */ - nm256_audio_local_qlen, /*+local_qlen */ - NULL, /*+copy_from_user */ - NULL, /*+halt_input */ - NULL, /* halt_output */ - NULL, /*+trigger */ - NULL, /*+set_speed */ - NULL, /*+set_bits */ - NULL, /*+set_channels */ + owner: THIS_MODULE, + open: nm256_audio_open, + close: nm256_audio_close, + output_block: nm256_audio_output_block, + start_input: nm256_audio_start_input, + ioctl: nm256_audio_ioctl, + prepare_for_input: nm256_audio_prepare_for_input, + prepare_for_output:nm256_audio_prepare_for_output, + halt_io: nm256_audio_reset, + local_qlen: nm256_audio_local_qlen, }; EXPORT_SYMBOL(init_nm256); @@ -1654,7 +1648,6 @@ static int __init do_init_nm256(void) printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n"); if (init_nm256 () == 0) { - SOUND_LOCK; loaded = 1; return 0; } @@ -1668,8 +1661,6 @@ static void __exit cleanup_nm256 (void) struct nm256_info *card; struct nm256_info *next_card; - SOUND_LOCK_END; - for (card = nmcard_list; card != NULL; card = next_card) { stopPlay (card); stopRecord (card); diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index 951dfe4d3..74d714945 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -31,7 +31,6 @@ */ #include "sound_config.h" -#include "soundmodule.h" #include "opl3.h" #include "opl3_hw.h" @@ -769,7 +768,6 @@ static int opl3_open(int dev, int mode) if (devc->busy) return -EBUSY; - MOD_INC_USE_COUNT; devc->busy = 1; devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; @@ -798,7 +796,6 @@ static void opl3_close(int dev) devc->fm_info.perc_mode = 0; opl3_reset(dev); - MOD_DEC_USE_COUNT; } static void opl3_hw_control(int dev, unsigned char *event) @@ -1061,30 +1058,31 @@ static void opl3_setup_voice(int dev, int voice, int chn) static struct synth_operations opl3_operations = { - "OPL", - NULL, - 0, - SYNTH_TYPE_FM, - FM_TYPE_ADLIB, - opl3_open, - opl3_close, - opl3_ioctl, - opl3_kill_note, - opl3_start_note, - opl3_set_instr, - opl3_reset, - opl3_hw_control, - opl3_load_patch, - opl3_aftertouch, - opl3_controller, - opl3_panning, - opl3_volume_method, - opl3_bender, - opl3_alloc_voice, - opl3_setup_voice + owner: THIS_MODULE, + id: "OPL", + info: NULL, + midi_dev: 0, + synth_type: SYNTH_TYPE_FM, + synth_subtype: FM_TYPE_ADLIB, + open: opl3_open, + close: opl3_close, + ioctl: opl3_ioctl, + kill_note: opl3_kill_note, + start_note: opl3_start_note, + set_instr: opl3_set_instr, + reset: opl3_reset, + hw_control: opl3_hw_control, + load_patch: opl3_load_patch, + aftertouch: opl3_aftertouch, + controller: opl3_controller, + panning: opl3_panning, + volume_method: opl3_volume_method, + bender: opl3_bender, + alloc_voice: opl3_alloc_voice, + setup_voice: opl3_setup_voice }; -int opl3_init(int ioaddr, int *osp) +int opl3_init(int ioaddr, int *osp, struct module *owner) { int i; int me; @@ -1131,6 +1129,10 @@ int opl3_init(int ioaddr, int *osp) opl3_operations.info = &devc->fm_info; synth_devs[me] = &opl3_operations; + + if (owner) + synth_devs[me]->owner = owner; + sequencer_init(); devc->v_alloc = &opl3_operations.alloc; devc->chn_info = &opl3_operations.chn_info[0]; @@ -1198,11 +1200,11 @@ static int __init init_opl3 (void) { return -ENODEV; } - me = opl3_init(io, NULL); + me = opl3_init(io, NULL, THIS_MODULE); request_region(io, 4, devc->fm_info.name); } - SOUND_LOCK; + return 0; } @@ -1216,7 +1218,6 @@ static void __exit cleanup_opl3(void) devc = NULL; sound_unload_synthdev(me); } - SOUND_LOCK_END; } module_init(init_opl3); diff --git a/drivers/sound/opl3.h b/drivers/sound/opl3.h index 6ef00614b..104ae9ff4 100644 --- a/drivers/sound/opl3.h +++ b/drivers/sound/opl3.h @@ -6,6 +6,6 @@ */ int opl3_detect (int ioaddr, int *osp); -int opl3_init(int ioaddr, int *osp); +int opl3_init(int ioaddr, int *osp, struct module *owner); void enable_opl3_mode(int left, int right, int both); diff --git a/drivers/sound/opl3sa.c b/drivers/sound/opl3sa.c index 6b82d2a17..fc8be2cd5 100644 --- a/drivers/sound/opl3sa.c +++ b/drivers/sound/opl3sa.c @@ -25,7 +25,6 @@ #undef SB_OK #include "sound_config.h" -#include "soundmodule.h" #include "ad1848.h" #include "mpu401.h" @@ -167,7 +166,7 @@ static void __init attach_opl3sa_wss(struct address_info *hw_config) int nm = num_mixers; /* FIXME */ - attach_ms_sound(hw_config); + attach_ms_sound(hw_config, THIS_MODULE); if (num_mixers > nm) /* A mixer was installed */ { AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); @@ -180,7 +179,7 @@ static void __init attach_opl3sa_wss(struct address_info *hw_config) static void __init attach_opl3sa_mpu(struct address_info *hw_config) { hw_config->name = "OPL3-SA (MPU401)"; - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); } static int __init probe_opl3sa_mpu(struct address_info *hw_config) @@ -313,7 +312,7 @@ static int __init init_opl3sa(void) attach_opl3sa_wss(&cfg); if(found_mpu) attach_opl3sa_mpu(&cfg_mpu); - SOUND_LOCK; + return 0; } @@ -322,7 +321,6 @@ static void __exit cleanup_opl3sa(void) if(found_mpu) unload_opl3sa_mpu(&cfg_mpu); unload_opl3sa_wss(&cfg); - SOUND_LOCK_END; } module_init(init_opl3sa); diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c index 23f85733e..e1b315347 100644 --- a/drivers/sound/opl3sa2.c +++ b/drivers/sound/opl3sa2.c @@ -41,7 +41,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "ad1848.h" #include "mpu401.h" @@ -436,9 +435,10 @@ static int opl3sa2_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations opl3sa2_mixer_operations = { - "Yamaha", - "", - opl3sa2_mixer_ioctl + owner: THIS_MODULE, + id: "Yamaha", + name: "", /* hmm? */ + ioctl: opl3sa2_mixer_ioctl }; /* End of mixer-related stuff */ @@ -452,7 +452,7 @@ static inline int __init probe_opl3sa2_mpu(struct address_info *hw_config) static inline void __init attach_opl3sa2_mpu(struct address_info *hw_config) { - attach_mpu401(hw_config); + attach_mpu401(hw_config, THIS_MODULE); } @@ -493,7 +493,7 @@ static void __init attach_opl3sa2_mss(struct address_info *hw_config) opl3sa2_mixer_reset(devc); - attach_ms_sound(hw_config); /* Slot 0 */ + attach_ms_sound(hw_config, THIS_MODULE); /* Slot 0 */ if(hw_config->slots[0] != -1) { /* Did the MSS driver install? */ @@ -699,7 +699,7 @@ static int __init init_opl3sa2(void) attach_opl3sa2_mpu(&cfg_mpu); } } - SOUND_LOCK; + return 0; } @@ -711,7 +711,6 @@ static void __exit cleanup_opl3sa2(void) } unload_opl3sa2_mss(&cfg2); unload_opl3sa2(&cfg); - SOUND_LOCK_END; } module_init(init_opl3sa2); diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index 68936e577..52e0d2865 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -8,7 +8,6 @@ #include <linux/init.h> #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "pas2.h" #include "sb.h" @@ -426,14 +425,13 @@ static int __init init_pas2(void) if (!probe_pas(&cfg)) return -ENODEV; attach_pas_card(&cfg); - SOUND_LOCK; + return 0; } static void __exit cleanup_pas2(void) { unload_pas(&cfg); - SOUND_LOCK_END; } module_init(init_pas2); diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c index 385bdd1db..979e2a8ec 100644 --- a/drivers/sound/pas2_midi.c +++ b/drivers/sound/pas2_midi.c @@ -191,19 +191,17 @@ static int pas_buffer_status(int dev) static struct midi_operations pas_midi_operations = { - {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, - &std_midi_synth, - {0}, - pas_midi_open, - pas_midi_close, - NULL, - pas_midi_out, - pas_midi_start_read, - pas_midi_end_read, - pas_midi_kick, - NULL, - pas_buffer_status, - NULL + owner: THIS_MODULE, + info: {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, + converter: &std_midi_synth, + in_info: {0}, + open: pas_midi_open, + close: pas_midi_close, + outputc: pas_midi_out, + start_read: pas_midi_start_read, + end_read: pas_midi_end_read, + kick: pas_midi_kick, + buffer_status: pas_buffer_status, }; void pas_midi_init(void) diff --git a/drivers/sound/pas2_mixer.c b/drivers/sound/pas2_mixer.c index fa85a9278..00cadcc93 100644 --- a/drivers/sound/pas2_mixer.c +++ b/drivers/sound/pas2_mixer.c @@ -309,9 +309,10 @@ static int pas_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations pas_mixer_operations = { - "PAS16", - "Pro Audio Spectrum 16", - pas_mixer_ioctl + owner: THIS_MODULE, + id: "PAS16", + name: "Pro Audio Spectrum 16", + ioctl: pas_mixer_ioctl }; int diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c index 5a79ebb86..90d461ed0 100644 --- a/drivers/sound/pas2_pcm.c +++ b/drivers/sound/pas2_pcm.c @@ -373,19 +373,16 @@ static int pas_audio_prepare_for_output(int dev, int bsize, int bcount) static struct audio_driver pas_audio_driver = { - pas_audio_open, - pas_audio_close, - pas_audio_output_block, - pas_audio_start_input, - pas_audio_ioctl, - pas_audio_prepare_for_input, - pas_audio_prepare_for_output, - pas_audio_reset, - NULL, - NULL, - NULL, - NULL, - pas_audio_trigger + owner: THIS_MODULE, + open: pas_audio_open, + close: pas_audio_close, + output_block: pas_audio_output_block, + start_input: pas_audio_start_input, + ioctl: pas_audio_ioctl, + prepare_for_input: pas_audio_prepare_for_input, + prepare_for_output: pas_audio_prepare_for_output, + halt_io: pas_audio_reset, + trigger: pas_audio_trigger }; void pas_pcm_init(struct address_info *hw_config) diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 7e883a625..a1c7693f3 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -35,7 +35,6 @@ #include "sound_config.h" #include "sound_firmware.h" -#include "soundmodule.h" #include "ad1848.h" #include "mpu401.h" @@ -569,9 +568,10 @@ static int pss_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations pss_mixer_operations = { - "SOUNDPORT", - "PSS-AD1848", - pss_mixer_ioctl + owner: THIS_MODULE, + id: "SOUNDPORT", + name: "PSS-AD1848", + ioctl: pss_mixer_ioctl }; void attach_pss(struct address_info *hw_config) @@ -918,7 +918,7 @@ static coproc_operations pss_coproc_operations = static void __init attach_pss_mpu(struct address_info *hw_config) { - attach_mpu401(hw_config); /* Slot 1 */ + attach_mpu401(hw_config, THIS_MODULE); /* Slot 1 */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; } @@ -987,7 +987,7 @@ static void __init attach_pss_mss(struct address_info *hw_config) } } pss_mixer_reset(devc); - attach_ms_sound(hw_config); /* Slot 0 */ + attach_ms_sound(hw_config, THIS_MODULE); /* Slot 0 */ if (hw_config->slots[0] != -1) { @@ -1087,7 +1087,7 @@ static int __init init_pss(void) pssmss = 1; attach_pss_mss(&cfg2); } - SOUND_LOCK; + return 0; } @@ -1100,7 +1100,6 @@ static void __exit cleanup_pss(void) if (pssmpu) unload_pss_mpu(&cfg_mpu); unload_pss(&cfg); - SOUND_LOCK_END; } module_init(init_pss); diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index f0afbe177..dbadb8ea6 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -158,14 +158,14 @@ int sb_dsp_reset (sb_devc *devc); void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo); -int sb_dsp_init (struct address_info *hw_config); +int sb_dsp_init (struct address_info *hw_config, struct module *owner); void sb_dsp_unload(struct address_info *hw_config, int sbmpu); -int sb_mixer_init(sb_devc *devc); +int sb_mixer_init(sb_devc *devc, struct module *owner); void sb_mixer_unload(sb_devc *devc); void sb_mixer_set_stereo (sb_devc *devc, int mode); void smw_mixer_init(sb_devc *devc); -void sb_dsp_midi_init (sb_devc *devc); -void sb_audio_init (sb_devc *devc, char *name); +void sb_dsp_midi_init (sb_devc *devc, struct module *owner); +void sb_audio_init (sb_devc *devc, char *name, struct module *owner); void sb_midi_interrupt (sb_devc *devc); void sb_chgmixer (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val); int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right); @@ -178,7 +178,7 @@ extern sb_devc *last_sb; /* From sb_common.c */ void sb_dsp_disable_midi(int port); void sb_dsp_disable_recording(int port); -void attach_sbmpu (struct address_info *hw_config); +void attach_sbmpu (struct address_info *hw_config, struct module *owner); int probe_sbmpu (struct address_info *hw_config); void unload_sbmpu (struct address_info *hw_config); diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c index bba7baba8..4e05c48a3 100644 --- a/drivers/sound/sb_audio.c +++ b/drivers/sound/sb_audio.c @@ -933,128 +933,103 @@ sb16_audio_mmap(int dev) static struct audio_driver sb1_audio_driver = /* SB1.x */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - NULL, /* ioctl */ - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb1_audio_trigger, - sb1_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb1_audio_prepare_for_input, + prepare_for_output: sb1_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb1_audio_trigger, + set_speed: sb1_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: sb1_audio_set_channels }; static struct audio_driver sb20_audio_driver = /* SB2.0 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - NULL, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sb1_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb1_audio_prepare_for_input, + prepare_for_output: sb1_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: sb1_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: sb1_audio_set_channels }; static struct audio_driver sb201_audio_driver = /* SB2.01 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - NULL, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sb201_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb1_audio_prepare_for_input, + prepare_for_output: sb1_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: sb201_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: sb1_audio_set_channels }; static struct audio_driver sbpro_audio_driver = /* SB Pro */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - NULL, - sbpro_audio_prepare_for_input, - sbpro_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sbpro_audio_set_speed, - sb1_audio_set_bits, - sbpro_audio_set_channels + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sbpro_audio_prepare_for_input, + prepare_for_output: sbpro_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: sbpro_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: sbpro_audio_set_channels }; static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - NULL, - sbpro_audio_prepare_for_input, - sbpro_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - jazz16_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sbpro_audio_prepare_for_input, + prepare_for_output: sbpro_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: jazz16_audio_set_speed, + set_bits: sb16_audio_set_bits, + set_channels: sbpro_audio_set_channels }; static struct audio_driver sb16_audio_driver = /* SB16 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - NULL, - sb16_audio_prepare_for_input, - sb16_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - sb16_copy_from_user, /* copy_from_user */ - NULL, - NULL, - sb16_audio_trigger, - sb16_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels, - NULL, - NULL, - sb16_audio_mmap + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb16_audio_prepare_for_input, + prepare_for_output: sb16_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + copy_user: sb16_copy_from_user, + trigger: sb16_audio_trigger, + set_speed: sb16_audio_set_speed, + set_bits: sb16_audio_set_bits, + set_channels: sbpro_audio_set_channels, + mmap: sb16_audio_mmap }; -void sb_audio_init(sb_devc * devc, char *name) +void sb_audio_init(sb_devc * devc, char *name, struct module *owner) { int audio_flags = 0; int format_mask = AFMT_U8; @@ -1111,6 +1086,9 @@ void sb_audio_init(sb_devc * devc, char *name) driver = &sbpro_audio_driver; } + if (owner) + driver->owner = owner; + if ((devc->dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name,driver, sizeof(struct audio_driver), audio_flags, format_mask, devc, diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index f66c0b604..9828aab41 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -44,7 +44,9 @@ * * 25-05-2000 Added Creative SB AWE64 Gold (CTL00B2). * Pål-Kristian Engstad <engstad@att.net> - * + * + * 12-08-2000 Added Creative SB32 PnP (CTL009F). + * Kasatenko Ivan Alex. <skywriter@rnc.ru> */ #include <linux/config.h> @@ -54,7 +56,6 @@ #include <linux/isapnp.h> #include "sound_config.h" -#include "soundmodule.h" #include "sb_mixer.h" #include "sb.h" @@ -88,7 +89,7 @@ static int __initdata sm_games = 0; /* Logitech soundman games? */ static void __init attach_sb_card(struct address_info *hw_config) { - if(!sb_dsp_init(hw_config)) + if(!sb_dsp_init(hw_config, THIS_MODULE)) hw_config->slots[0] = -1; } @@ -189,7 +190,7 @@ struct pci_dev *sb_dev[SB_CARDS_MAX] = {NULL}, #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE static int isapnp = 1; static int isapnpjump = 0; -static int multiple = 0; +static int multiple = 1; static int reverse = 0; static int uart401 = 0; @@ -198,7 +199,7 @@ static int mpu_activated[SB_CARDS_MAX] = {0}; static int opl_activated[SB_CARDS_MAX] = {0}; #else static int isapnp = 0; -static int multiple = 1; +static int multiple = 0; #endif MODULE_DESCRIPTION("Soundblaster driver"); @@ -277,7 +278,7 @@ static struct { ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, 0,1,1,-1}, - {"Sound Blaster 16", + {"Sound Blaster 16", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002a), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, @@ -342,6 +343,11 @@ static struct { ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0,0,0,0, 0,1,1,-1}, + {"Creative SB32 PnP", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009F), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), + 0,0,0,0, + 0,1,1,-1}, {"Sound Blaster AWE 64", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009D), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), @@ -436,7 +442,7 @@ static struct { ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0,-1,0,0}, {"ALS100", - ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001), + ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001), ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), @@ -468,10 +474,6 @@ static struct { {0} }; -/* That's useful. */ - -#define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start) - static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev) { int err; @@ -636,7 +638,7 @@ int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info * return 0; } } - i += reverse ? -1 : 1; + i += reverse ? -1 : 1; } return -ENODEV; @@ -679,16 +681,14 @@ static int __init init_sb(void) if(cfg[card].slots[0]==-1) return -ENODEV; - if (!isapnp) + if (!isapnp) cfg_mpu[card].io_base = mpu_io; if (probe_sbmpu(&cfg_mpu[card])) sbmpu[card] = 1; if (sbmpu[card]) - attach_sbmpu(&cfg_mpu[card]); + attach_sbmpu(&cfg_mpu[card], THIS_MODULE); } - SOUND_LOCK; - if(isapnp) printk(KERN_NOTICE "sb: %d Soundblaster PnP card(s) found.\n", sb_cards_num); @@ -718,7 +718,6 @@ static void __exit cleanup_sb(void) opl_dev[i]->deactivate(opl_dev[i]); #endif } - SOUND_LOCK_END; } module_init(init_sb); diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 58d5ef474..4e3503bab 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -634,7 +634,7 @@ int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_ return 1; } -int sb_dsp_init(struct address_info *hw_config) +int sb_dsp_init(struct address_info *hw_config, struct module *owner) { sb_devc *devc; char name[100]; @@ -812,10 +812,10 @@ int sb_dsp_init(struct address_info *hw_config) if (!(devc->caps & SB_NO_MIXER)) if (devc->major == 3 || devc->major == 4) - sb_mixer_init(devc); + sb_mixer_init(devc, owner); if (!(devc->caps & SB_NO_MIDI)) - sb_dsp_midi_init(devc); + sb_dsp_midi_init(devc, owner); if (hw_config->name == NULL) hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; @@ -861,7 +861,7 @@ int sb_dsp_init(struct address_info *hw_config) if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) printk(KERN_WARNING "Sound Blaster: can't allocate 16 bit DMA channel %d.\n", devc->dma16); } - sb_audio_init(devc, name); + sb_audio_init(devc, name, owner); hw_config->slots[0]=devc->dev; } else @@ -1190,18 +1190,18 @@ static int init_Jazz16_midi(sb_devc * devc, struct address_info *hw_config) return 1; } -void attach_sbmpu(struct address_info *hw_config) +void attach_sbmpu(struct address_info *hw_config, struct module *owner) { if (last_sb->model == MDL_ESS) { #if defined(CONFIG_SOUND_MPU401) - attach_mpu401(hw_config); + attach_mpu401(hw_config, owner); if (last_sb->irq == -hw_config->irq) { last_sb->midi_irq_cookie=(void *)hw_config->slots[1]; } #endif return; } - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; } diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c index dfb59016b..a52fd18e2 100644 --- a/drivers/sound/sb_ess.c +++ b/drivers/sound/sb_ess.c @@ -707,22 +707,18 @@ static short ess_audio_set_channels(int dev, short channels) static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ { - sb_audio_open, - sb_audio_close, - ess_set_output_parms, - ess_set_input_parms, - NULL, - ess_audio_prepare_for_input, - ess_audio_prepare_for_output, - ess_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - ess_audio_trigger, - ess_audio_set_speed, - ess_audio_set_bits, - ess_audio_set_channels + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: ess_set_output_parms, + start_input: ess_set_input_parms, + prepare_for_input: ess_audio_prepare_for_input, + prepare_for_output: ess_audio_prepare_for_output, + halt_io: ess_audio_halt_xfer, + trigger: ess_audio_trigger, + set_speed: ess_audio_set_speed, + set_bits: ess_audio_set_bits, + set_channels: ess_audio_set_channels }; /* diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index 59cbfca03..f5f6e3d6c 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -147,24 +147,19 @@ void sb_midi_interrupt(sb_devc * devc) static struct midi_operations sb_midi_operations = { - { - "Sound Blaster", 0, 0, SNDCARD_SB - }, - &std_midi_synth, - {0}, - sb_midi_open, - sb_midi_close, - sb_midi_ioctl, - sb_midi_out, - sb_midi_start_read, - sb_midi_end_read, - NULL, - NULL, - NULL, - NULL + owner: THIS_MODULE, + info: {"Sound Blaster", 0, 0, SNDCARD_SB}, + converter: &std_midi_synth, + in_info: {0}, + open: sb_midi_open, + close: sb_midi_close, + ioctl: sb_midi_ioctl, + outputc: sb_midi_out, + start_read: sb_midi_start_read, + end_read: sb_midi_end_read, }; -void sb_dsp_midi_init(sb_devc * devc) +void sb_dsp_midi_init(sb_devc * devc, struct module *owner) { int dev; @@ -189,6 +184,9 @@ void sb_dsp_midi_init(sb_devc * devc) memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, sizeof(struct midi_operations)); + if (owner) + midi_devs[dev]->owner = owner; + midi_devs[dev]->devc = devc; diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index 5a5487b16..6745cac22 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -626,16 +626,18 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations sb_mixer_operations = { - "SB", - "Sound Blaster", - sb_mixer_ioctl + owner: THIS_MODULE, + id: "SB", + name: "Sound Blaster", + ioctl: sb_mixer_ioctl }; static struct mixer_operations als007_mixer_operations = { - "ALS007", - "Avance ALS-007", - sb_mixer_ioctl + owner: THIS_MODULE, + id: "ALS007", + name: "Avance ALS-007", + ioctl: sb_mixer_ioctl }; static void sb_mixer_reset(sb_devc * devc) @@ -658,7 +660,7 @@ static void sb_mixer_reset(sb_devc * devc) }; } -int sb_mixer_init(sb_devc * devc) +int sb_mixer_init(sb_devc * devc, struct module *owner) { int mixer_type = 0; int m; @@ -735,6 +737,10 @@ int sb_mixer_init(sb_devc * devc) memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations)); mixer_devs[m]->devc = devc; + + if (owner) + mixer_devs[m]->owner = owner; + devc->my_mixerdev = m; sb_mixer_reset(devc); return 1; diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 270d489d6..117280d1a 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -1068,6 +1068,9 @@ int sequencer_open(int dev, struct file *file) if (synth_devs[i]==NULL) continue; + if (synth_devs[i]->owner) + __MOD_INC_USE_COUNT (synth_devs[i]->owner); + if ((tmp = synth_devs[i]->open(i, mode)) < 0) { printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); @@ -1101,6 +1104,9 @@ int sequencer_open(int dev, struct file *file) for (i = 0; i < max_mididev; i++) if (!midi_opened[i] && midi_devs[i]) { + if (midi_devs[i]->owner) + __MOD_INC_USE_COUNT (midi_devs[i]->owner); + if ((retval = midi_devs[i]->open(i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) { @@ -1108,8 +1114,12 @@ int sequencer_open(int dev, struct file *file) } } } - if (seq_mode == SEQ_2) + + if (seq_mode == SEQ_2) { + if (tmr->owner) + __MOD_INC_USE_COUNT (tmr->owner); tmr->open(tmr_no, seq_mode); + } init_waitqueue_head(&seq_sleeper); init_waitqueue_head(&midi_sleeper); @@ -1191,6 +1201,9 @@ void sequencer_release(int dev, struct file *file) { synth_devs[i]->close(i); + if (synth_devs[i]->owner) + __MOD_DEC_USE_COUNT (synth_devs[i]->owner); + if (synth_devs[i]->midi_dev) midi_opened[synth_devs[i]->midi_dev] = 0; } @@ -1198,12 +1211,18 @@ void sequencer_release(int dev, struct file *file) for (i = 0; i < max_mididev; i++) { - if (midi_opened[i]) + if (midi_opened[i]) { midi_devs[i]->close(i); + if (midi_devs[i]->owner) + __MOD_DEC_USE_COUNT (midi_devs[i]->owner); + } } - if (seq_mode == SEQ_2) + if (seq_mode == SEQ_2) { tmr->close(tmr_no); + if (tmr->owner) + __MOD_DEC_USE_COUNT (tmr->owner); + } if (obsolete_api_used) printk(KERN_WARNING "/dev/music: Obsolete (4 byte) API was used by %s\n", current->comm); diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c index 7c02ee8b2..ef0e4199c 100644 --- a/drivers/sound/sgalaxy.c +++ b/drivers/sound/sgalaxy.c @@ -22,8 +22,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" - #include "ad1848.h" static void sleep( unsigned howlong ) @@ -115,7 +113,7 @@ static void __init attach_sgalaxy( struct address_info *ai ) request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB" ); - attach_ms_sound( ai ); + attach_ms_sound(ai, THIS_MODULE); n=ai->slots[0]; if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) { @@ -163,14 +161,12 @@ static int __init init_sgalaxy(void) attach_sgalaxy(&cfg); - SOUND_LOCK; return 0; } static void __exit cleanup_sgalaxy(void) { unload_sgalaxy(&cfg); - SOUND_LOCK_END; } module_init(init_sgalaxy); diff --git a/drivers/sound/skeleton.c b/drivers/sound/skeleton.c index fcd5c9ed1..9d5d4ac22 100644 --- a/drivers/sound/skeleton.c +++ b/drivers/sound/skeleton.c @@ -27,7 +27,6 @@ #include <asm/io.h> #include "sound_config.h" -#include "soundmodule.h" /* * Define our PCI vendor ID here @@ -137,7 +136,13 @@ static int mycard_install(struct pci_dev *pcidev) */ mss_data[cards].slots[3] = ad1848_init("MyCard MSS 16bit", - mssbase, mss_data[cards].irq); + mssbase, + mss_data[cards].irq, + mss_data[cards].dma, + mss_data[cards].dma, + 0, + 0, + THIS_MODULE); cards++; return 1; @@ -187,17 +192,13 @@ int init_module(void) printk(KERN_ERR "No "CARD_NAME" cards found.\n"); return -ENODEV; } - /* - * Binds us to the sound subsystem - */ - SOUND_LOCK; + return 0; } /* * This is called when it is removed. It will only be removed - * when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK - * macros hide the entire work for this. + * when its use count is 0. */ void cleanup_module(void) @@ -218,9 +219,5 @@ void cleanup_module(void) */ sound_unload_audiodevice(mss_data[i].slots[3]); } - /* - * Final clean up with the sound layer - */ - SOUND_LOCK_END; } diff --git a/drivers/sound/softoss.c b/drivers/sound/softoss.c index 0ef54e6d0..d478e243d 100644 --- a/drivers/sound/softoss.c +++ b/drivers/sound/softoss.c @@ -32,7 +32,6 @@ #define NO_SAMPLE 0xffff #include "sound_config.h" -#include "soundmodule.h" #include "softoss.h" #include <linux/ultrasound.h> @@ -1394,27 +1393,28 @@ static void softsyn_reset(int devno) static struct synth_operations softsyn_operations = { - "SoftOSS", - &softsyn_info, - 0, - SYNTH_TYPE_SAMPLE, - 0, - softsyn_open, - softsyn_close, - softsyn_ioctl, - softsyn_kill_note, - softsyn_start_note, - softsyn_set_instr, - softsyn_reset, - softsyn_hw_control, - softsyn_load_patch, - softsyn_aftertouch, - softsyn_controller, - softsyn_panning, - softsyn_volume_method, - softsyn_bender, - softsyn_alloc_voice, - softsyn_setup_voice + owner: THIS_MODULE, + id: "SoftOSS", + info: &softsyn_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: 0, + open: softsyn_open, + close: softsyn_close, + ioctl: softsyn_ioctl, + kill_note: softsyn_kill_note, + start_note: softsyn_start_note, + set_instr: softsyn_set_instr, + reset: softsyn_reset, + hw_control: softsyn_hw_control, + load_patch: softsyn_load_patch, + aftertouch: softsyn_aftertouch, + controller: softsyn_controller, + panning: softsyn_panning, + volume_method: softsyn_volume_method, + bender: softsyn_bender, + alloc_voice: softsyn_alloc_voice, + setup_voice: softsyn_setup_voice }; /* @@ -1517,7 +1517,7 @@ static int __init init_softoss(void) if (!probe_softsyn(&cfg)) return -ENODEV; attach_softsyn_card(&cfg); - SOUND_LOCK; + return 0; } @@ -1526,7 +1526,6 @@ static void __exit cleanup_softoss(void) unload_softsyn(&cfg); sound_unload_synthdev(devc->synthdev); sound_unload_timerdev(devc->timerdev); - SOUND_LOCK_END; } module_init(init_softoss); diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 526ba929a..099bbf1ab 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -282,8 +282,6 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 }; #define FMODE_DMFM 0x10 -#define SND_DEV_DSP16 5 - /* --------------------------------------------------------------------- */ struct sv_state { diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h index 35c39e947..050c38df5 100644 --- a/drivers/sound/sound_config.h +++ b/drivers/sound/sound_config.h @@ -53,28 +53,7 @@ #define SBFM_MAXINSTR (256) /* Size of the FM Instrument bank */ /* 128 instruments for general MIDI setup and 16 unassigned */ -/* - * Minor numbers for the sound driver. - * - * Unfortunately Creative called the codec chip of SB as a DSP. For this - * reason the /dev/dsp is reserved for digitized audio use. There is a - * device for true DSP processors but it will be called something else. - * In v3.0 it's /dev/sndproc but this could be a temporary solution. - */ - #define SND_NDEVS 256 /* Number of supported devices */ -#define SND_DEV_CTL 0 /* Control port /dev/mixer */ -#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM - synthesizer and MIDI output) */ -#define SND_DEV_MIDIN 2 /* Raw midi access */ -#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ -#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ -#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ -#define SND_DEV_STATUS 6 /* /dev/sndstat */ -#define SND_DEV_AWFM 7 /* Reserved */ -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ -#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ -#define SND_DEV_PSS SND_DEV_SNDPROC #define DSP_DEFAULT_SPEED 8000 diff --git a/drivers/sound/sound_syms.c b/drivers/sound/sound_syms.c index a3601dcf6..764687756 100644 --- a/drivers/sound/sound_syms.c +++ b/drivers/sound/sound_syms.c @@ -52,11 +52,5 @@ EXPORT_SYMBOL(conf_printf2); extern int softoss_dev; EXPORT_SYMBOL(softoss_dev); -/* Locking */ -extern struct notifier_block *sound_locker; -extern void sound_notifier_chain_register(struct notifier_block *); -EXPORT_SYMBOL(sound_locker); -EXPORT_SYMBOL(sound_notifier_chain_register); - MODULE_DESCRIPTION("OSS Sound subsystem"); MODULE_AUTHOR("Hannu Savolainen, et al."); diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c index 33901aa1b..2aabeb309 100644 --- a/drivers/sound/sound_timer.c +++ b/drivers/sound/sound_timer.c @@ -264,15 +264,16 @@ static void timer_arm(int dev, long time) static struct sound_timer_operations sound_timer = { - {"Sound Timer", 0}, - 1, /* Priority */ - 0, /* Local device link */ - timer_open, - timer_close, - timer_event, - timer_get_time, - timer_ioctl, - timer_arm + owner: THIS_MODULE, + info: {"Sound Timer", 0}, + priority: 1, /* Priority */ + devlink: 0, /* Local device link */ + open: timer_open, + close: timer_close, + event: timer_event, + get_time: timer_get_time, + ioctl: timer_ioctl, + arm_timer: timer_arm }; void sound_timer_interrupt(void) diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index d56b8f77f..fc715db83 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -43,11 +43,6 @@ #include <linux/delay.h> #include <linux/proc_fs.h> #include <linux/smp_lock.h> -#include <linux/notifier.h> - - -struct notifier_block *sound_locker=(struct notifier_block *)0; -static int lock_depth = 0; /* * This ought to be moved into include/asm/dma.h @@ -78,7 +73,6 @@ static char dma_alloc_map[MAX_DMA_CHANNELS] = {0}; #define DMA_MAP_BUSY 2 -static int in_use = 0; /* Total # of open devices */ unsigned long seq_time = 0; /* Time for /dev/sequencer */ /* @@ -221,7 +215,7 @@ static int sound_open(struct inode *inode, struct file *file) DEB(printk("sound_open(dev=%d)\n", dev)); if ((dev >= SND_NDEVS) || (dev < 0)) { - /* printk(KERN_ERR "Invalid minor device %d\n", dev);*/ + printk(KERN_ERR "Invalid minor device %d\n", dev); return -ENXIO; } switch (dev & 0x0f) { @@ -234,6 +228,9 @@ static int sound_open(struct inode *inode, struct file *file) } if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) return -ENXIO; + + if (mixer_devs[dev]->owner) + __MOD_INC_USE_COUNT (mixer_devs[dev]->owner); break; case SND_DEV_SEQ: @@ -258,10 +255,6 @@ static int sound_open(struct inode *inode, struct file *file) printk(KERN_ERR "Invalid minor device %d\n", dev); return -ENXIO; } - in_use++; - - notifier_call_chain(&sound_locker, 1, 0); - lock_depth++; return 0; } @@ -274,6 +267,8 @@ static int sound_release(struct inode *inode, struct file *file) DEB(printk("sound_release(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_CTL: + if (mixer_devs[dev]->owner) + __MOD_DEC_USE_COUNT (mixer_devs[dev]->owner); break; case SND_DEV_SEQ: @@ -294,10 +289,6 @@ static int sound_release(struct inode *inode, struct file *file) default: printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); } - in_use--; - - notifier_call_chain(&sound_locker, 0, 0); - lock_depth--; unlock_kernel(); return 0; @@ -811,27 +802,3 @@ void conf_printf2(char *name, int base, int irq, int dma, int dma2) printk("\n"); #endif } - -/* - * Module and lock management - */ - -/* - * When a sound module is registered we need to bring it to the current - * lock level... - */ - -void sound_notifier_chain_register(struct notifier_block *bl) -{ - int ct=0; - - notifier_chain_register(&sound_locker, bl); - /* - * Normalise the lock count by calling the entry directly. We - * have to call the module as it owns its own use counter - */ - while(ct<lock_depth) { - bl->notifier_call(bl, 1, 0); - ct++; - } -} diff --git a/drivers/sound/soundmodule.h b/drivers/sound/soundmodule.h deleted file mode 100644 index 2187f1c9b..000000000 --- a/drivers/sound/soundmodule.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _SOUNDMODULE_H -#define _SOUNDMODULE_H - -#include <linux/notifier.h> -#include <linux/module.h> - -extern struct notifier_block *sound_locker; -extern void sound_notifier_chain_register(struct notifier_block *); - -#define SOUND_LOCK sound_notifier_chain_register(&sound_notifier); -#define SOUND_LOCK_END notifier_chain_unregister(&sound_locker, &sound_notifier) - -static int my_notifier_call(struct notifier_block *b, unsigned long foo, void *bar) -{ - if(foo) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; - return NOTIFY_DONE; -} - -static struct notifier_block sound_notifier= -{ - my_notifier_call, - (void *)0, - 0 -}; - -#endif /* _SOUNDMODULE_H */ diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index 21fd2ea2e..1c399bd5c 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "sound_firmware.h" #include <linux/types.h> @@ -728,7 +727,7 @@ void attach_sscape(struct address_info *hw_config) hw_config->name = "SoundScape"; hw_config->irq *= -1; /* Negative value signals IRQ sharing */ - attach_mpu401(hw_config); + attach_mpu401(hw_config, THIS_MODULE); hw_config->irq *= -1; /* Restore it */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ @@ -1378,21 +1377,16 @@ static void __init attach_ss_ms_sound(struct address_info *hw_config) if (hw_config->irq == devc->irq) printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n"); - if (! sscape_is_pnp ) - hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp); - - else - hw_config->slots[0] = ad1848_init("SoundScape PNP", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp); + hw_config->slots[0] = ad1848_init( + sscape_is_pnp ? "SoundScape" : "SoundScape PNP", + hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, + 0, + devc->osp, + THIS_MODULE); + if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ { @@ -1497,7 +1491,7 @@ static int __init init_sscape(void) if (mss) attach_ss_ms_sound(&cfg); - SOUND_LOCK; + return 0; } @@ -1505,7 +1499,6 @@ static void __exit cleanup_sscape(void) { if (mss) unload_ss_ms_sound(&cfg); - SOUND_LOCK_END; unload_sscape(&cfg_mpu); } diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c index 2d0cc953f..ba6a572a0 100644 --- a/drivers/sound/sys_timer.c +++ b/drivers/sound/sys_timer.c @@ -274,13 +274,14 @@ def_tmr_arm(int dev, long time) struct sound_timer_operations default_sound_timer = { - {"System clock", 0}, - 0, /* Priority */ - 0, /* Local device link */ - def_tmr_open, - def_tmr_close, - def_tmr_event, - def_tmr_get_time, - def_tmr_ioctl, - def_tmr_arm + owner: THIS_MODULE, + info: {"System clock", 0}, + priority: 0, /* Priority */ + devlink: 0, /* Local device link */ + open: def_tmr_open, + close: def_tmr_close, + event: def_tmr_event, + get_time: def_tmr_get_time, + ioctl: def_tmr_ioctl, + arm_timer: def_tmr_arm }; diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index 27a29e42d..c85d40991 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -130,12 +130,6 @@ have 2 SDATA_IN lines (currently) */ #define NR_AC97 2 -/* minor number of /dev/dspW */ -#define SND_DEV_DSP8 3 - -/* minor number of /dev/dspW */ -#define SND_DEV_DSP16 5 - /* minor number of /dev/swmodem (temporary, experimental) */ #define SND_DEV_SWMODEM 7 diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index c1d71750e..d3cc76046 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -21,7 +21,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "sb.h" #include "sound_firmware.h" @@ -259,7 +258,8 @@ static void __init attach_trix_wss(struct address_info *hw_config) dma1, dma2, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); request_region(hw_config->io_base, 4, "MSS config"); if (num_mixers > old_num_mixers) /* Mixer got installed */ @@ -332,7 +332,7 @@ static void __init attach_trix_sb(struct address_info *hw_config) old_quiet = sb_be_quiet; sb_be_quiet = 1; - sb_dsp_init(hw_config); + sb_dsp_init(hw_config, THIS_MODULE); sb_be_quiet = old_quiet; } @@ -340,7 +340,7 @@ static void __init attach_trix_sb(struct address_info *hw_config) static void __init attach_trix_mpu(struct address_info *hw_config) { hw_config->name = "AudioTrix Pro"; - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); } static int __init probe_trix_mpu(struct address_info *hw_config) @@ -515,7 +515,7 @@ static int __init init_trix(void) if (mpu) attach_trix_mpu(&cfg_mpu); } - SOUND_LOCK; + return 0; } @@ -528,7 +528,6 @@ static void __exit cleanup_trix(void) if (mpu) unload_trix_mpu(&cfg_mpu); unload_trix_wss(&cfg); - SOUND_LOCK_END; } module_init(init_trix); diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c index 71721dd3e..0b7eb3297 100644 --- a/drivers/sound/uart401.c +++ b/drivers/sound/uart401.c @@ -24,7 +24,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "mpu401.h" @@ -206,21 +205,17 @@ static inline int uart401_buffer_status(int dev) static struct midi_operations uart401_operations = { - { - "MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401 - }, - &std_midi_synth, - {0}, - uart401_open, - uart401_close, - NULL, /* ioctl */ - uart401_out, - uart401_start_read, - uart401_end_read, - uart401_kick, - NULL, - uart401_buffer_status, - NULL + owner: THIS_MODULE, + info: {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, + converter: &std_midi_synth, + in_info: {0}, + open: uart401_open, + close: uart401_close, + outputc: uart401_out, + start_read: uart401_start_read, + end_read: uart401_end_read, + kick: uart401_kick, + buffer_status: uart401_buffer_status, }; static void enter_uart_mode(uart401_devc * devc) @@ -246,7 +241,7 @@ static void enter_uart_mode(uart401_devc * devc) restore_flags(flags); } -void attach_uart401(struct address_info *hw_config) +void attach_uart401(struct address_info *hw_config, struct module *owner) { uart401_devc *devc; char *name = "MPU-401 (UART) MIDI"; @@ -311,6 +306,9 @@ void attach_uart401(struct address_info *hw_config) memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations, sizeof(struct midi_operations)); + if (owner) + midi_devs[devc->my_dev]->owner = owner; + midi_devs[devc->my_dev]->devc = devc; midi_devs[devc->my_dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL); if (midi_devs[devc->my_dev]->converter == NULL) @@ -473,9 +471,9 @@ static int __init init_uart401(void) printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); if (probe_uart401(&cfg_mpu) == 0) return -ENODEV; - attach_uart401(&cfg_mpu); + attach_uart401(&cfg_mpu, THIS_MODULE); } - SOUND_LOCK; + return 0; } @@ -483,7 +481,6 @@ static void __exit cleanup_uart401(void) { if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) unload_uart401(&cfg_mpu); - SOUND_LOCK_END; } module_init(init_uart401); diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index 2bff6a655..e42e7d16c 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -26,7 +26,6 @@ */ #include "sound_config.h" -#include "soundmodule.h" static int uart6850_base = 0x330; @@ -148,7 +147,6 @@ static int uart6850_open(int dev, int mode, return -EBUSY; }; - MOD_INC_USE_COUNT; uart6850_cmd(UART_RESET); uart6850_input_loop(); midi_input_intr = input; @@ -165,7 +163,6 @@ static void uart6850_close(int dev) uart6850_cmd(UART_MODE_ON); del_timer(&uart6850_timer); uart6850_opened = 0; - MOD_DEC_USE_COUNT; } static int uart6850_out(int dev, unsigned char midi_byte) @@ -234,18 +231,18 @@ static inline int uart6850_buffer_status(int dev) static struct midi_operations uart6850_operations = { - {"6850 UART", 0, 0, SNDCARD_UART6850}, - &std_midi_synth, - {0}, - uart6850_open, - uart6850_close, - NULL, /* ioctl */ - uart6850_out, - uart6850_start_read, - uart6850_end_read, - uart6850_kick, - uart6850_command, - uart6850_buffer_status + owner: THIS_MODULE, + info: {"6850 UART", 0, 0, SNDCARD_UART6850}, + converter: &std_midi_synth, + in_info: {0}, + open: uart6850_open, + close: uart6850_close, + outputc: uart6850_out, + start_read: uart6850_start_read, + end_read: uart6850_end_read, + kick: uart6850_kick, + command: uart6850_command, + buffer_status: uart6850_buffer_status }; @@ -338,14 +335,12 @@ static int __init init_uart6850(void) if (probe_uart6850(&cfg_mpu)) return -ENODEV; - SOUND_LOCK; return 0; } static void __exit cleanup_uart6850(void) { unload_uart6850(&cfg_mpu); - SOUND_LOCK_END; } module_init(init_uart6850); diff --git a/drivers/sound/v_midi.c b/drivers/sound/v_midi.c index 9c18ff5c8..4362de346 100644 --- a/drivers/sound/v_midi.c +++ b/drivers/sound/v_midi.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include "sound_config.h" -#include "soundmodule.h" #include "v_midi.h" @@ -136,36 +135,30 @@ static inline int v_midi_ioctl (int dev, unsigned cmd, caddr_t arg) static struct midi_operations v_midi_operations = { - {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI}, - &std_midi_synth, - {0}, - v_midi_open, - v_midi_close, - v_midi_ioctl, - v_midi_out, - v_midi_start_read, - v_midi_end_read, - NULL, - NULL, - NULL, - NULL + owner: THIS_MODULE, + info: {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI}, + converter: &std_midi_synth, + in_info: {0}, + open: v_midi_open, + close: v_midi_close, + ioctl: v_midi_ioctl, + outputc: v_midi_out, + start_read: v_midi_start_read, + end_read: v_midi_end_read, }; static struct midi_operations v_midi_operations2 = { - {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI}, - &std_midi_synth, - {0}, - v_midi_open, - v_midi_close, - v_midi_ioctl, - v_midi_out, - v_midi_start_read, - v_midi_end_read, - NULL, - NULL, - NULL, - NULL + owner: THIS_MODULE, + info: {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI}, + converter: &std_midi_synth, + in_info: {0}, + open: v_midi_open, + close: v_midi_close, + ioctl: v_midi_ioctl, + outputc: v_midi_out, + start_read: v_midi_start_read, + end_read: v_midi_end_read, }; /* @@ -284,15 +277,12 @@ static int __init init_vmidi(void) return -ENODEV; attach_v_midi(&cfg); - SOUND_LOCK; - return 0; } static void __exit cleanup_vmidi(void) { unload_v_midi(&cfg); - SOUND_LOCK_END; } module_init(init_vmidi); diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c index be3b1c9ca..7ed78c980 100644 --- a/drivers/sound/via82cxxx_audio.c +++ b/drivers/sound/via82cxxx_audio.c @@ -36,10 +36,6 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> -/* much better to duplicate this value than include - * drivers/sound/sound_config.h just for this definition */ -#define SND_DEV_DSP16 5 - #undef VIA_DEBUG /* define to enable debugging output and checks */ #ifdef VIA_DEBUG diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c index 01fb315ab..aa7e3121b 100644 --- a/drivers/sound/vidc.c +++ b/drivers/sound/vidc.c @@ -26,7 +26,6 @@ #include <asm/system.h> #include "sound_config.h" -#include "soundmodule.h" #include "vidc.h" #ifndef _SIOC_TYPE @@ -362,6 +361,7 @@ static void vidc_audio_trigger(int dev, int enable_bits) static struct audio_driver vidc_audio_driver = { + owner: THIS_MODULE, open: vidc_audio_open, close: vidc_audio_close, output_block: vidc_audio_output_block, @@ -377,6 +377,7 @@ static struct audio_driver vidc_audio_driver = }; static struct mixer_operations vidc_mixer_operations = { + owner: THIS_MODULE, id: "VIDC", name: "VIDCsound", ioctl: vidc_mixer_ioctl @@ -519,16 +520,12 @@ static void __exit unload_vidc(struct address_info *hw_config) } static struct address_info cfg; -/* - * Note! Module use count is handled by SOUNDLOCK/SOUND_LOCK_END - */ static int __init init_vidc(void) { if (probe_vidc(&cfg) == 0) return -ENODEV; - SOUND_LOCK; attach_vidc(&cfg); return 0; @@ -537,7 +534,6 @@ static int __init init_vidc(void) static void __exit cleanup_vidc(void) { unload_vidc(&cfg); - SOUND_LOCK_END; } module_init(init_vidc); diff --git a/drivers/sound/waveartist.c b/drivers/sound/waveartist.c index 75d1a8977..9eac1e3d8 100644 --- a/drivers/sound/waveartist.c +++ b/drivers/sound/waveartist.c @@ -40,9 +40,9 @@ #include <asm/dec21285.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/system.h> -#include "soundmodule.h" #include "sound_config.h" #include "waveartist.h" @@ -801,22 +801,21 @@ waveartist_set_bits(int dev, unsigned int arg) } static struct audio_driver waveartist_audio_driver = { - waveartist_open, - waveartist_close, - waveartist_output_block, - waveartist_start_input, - waveartist_ioctl, - waveartist_prepare_for_input, - waveartist_prepare_for_output, - waveartist_halt, - NULL, - NULL, - waveartist_halt_input, - waveartist_halt_output, - waveartist_trigger, - waveartist_set_speed, - waveartist_set_bits, - waveartist_set_channels + owner: THIS_MODULE, + open: waveartist_open, + close: waveartist_close, + output_block: waveartist_output_block, + start_input: waveartist_start_input, + ioctl: waveartist_ioctl, + prepare_for_input: waveartist_prepare_for_input, + prepare_for_output: waveartist_prepare_for_output, + halt_io: waveartist_halt, + halt_input: waveartist_halt_input, + halt_output: waveartist_halt_output, + trigger: waveartist_trigger, + set_speed: waveartist_set_speed, + set_bits: waveartist_set_bits, + set_channels: waveartist_set_channels }; @@ -1186,9 +1185,10 @@ waveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) static struct mixer_operations waveartist_mixer_operations = { - "WaveArtist", - "WaveArtist NetWinder", - waveartist_mixer_ioctl + owner: THIS_MODULE, + id: "WaveArtist", + name: "WaveArtist NetWinder", + ioctl: waveartist_mixer_ioctl }; static int @@ -1794,16 +1794,13 @@ static int __init init_waveartist(void) attach_waveartist(&cfg); attached = 1; - SOUND_LOCK; return 0; } static void __exit cleanup_waveartist(void) { - if (attached) { - SOUND_LOCK_END; + if (attached) unload_waveartist(&cfg); - } } module_init(init_waveartist); diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index 3fb7cce2e..5a1a161d9 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -78,7 +78,6 @@ #include <linux/delay.h> #include "sound_config.h" -#include "soundmodule.h" #include <linux/wavefront.h> @@ -2115,28 +2114,25 @@ wavefront_oss_load_patch (int devno, int format, const char *addr, static struct synth_operations wavefront_operations = { - "WaveFront", - &wavefront_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_WAVEFRONT, - wavefront_oss_open, - wavefront_oss_close, - wavefront_oss_ioctl, - - midi_synth_kill_note, - midi_synth_start_note, - midi_synth_set_instr, - midi_synth_reset, - NULL, /* hw_control */ - midi_synth_load_patch, - midi_synth_aftertouch, - midi_synth_controller, - midi_synth_panning, - NULL, /* volume method */ - midi_synth_bender, - NULL, /* alloc voice */ - midi_synth_setup_voice + owner: THIS_MODULE, + id: "WaveFront", + info: &wavefront_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: SAMPLE_TYPE_WAVEFRONT, + open: wavefront_oss_open, + close: wavefront_oss_close, + ioctl: wavefront_oss_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice }; #endif OSS_SUPPORT_SEQ @@ -3569,14 +3565,12 @@ static int __init init_wavfront (void) return -EIO; } - SOUND_LOCK; return 0; } static void __exit cleanup_wavfront (void) { uninstall_wavefront (); - SOUND_LOCK_END; } module_init(init_wavfront); diff --git a/drivers/sound/wf_midi.c b/drivers/sound/wf_midi.c index 2d7d50fe9..59e5a04da 100644 --- a/drivers/sound/wf_midi.c +++ b/drivers/sound/wf_midi.c @@ -51,7 +51,6 @@ #include <linux/init.h> #include "sound_config.h" -#include "soundmodule.h" #include <linux/wavefront.h> @@ -550,19 +549,16 @@ static struct midi_operations wf_mpu_midi_operations[2]; static struct midi_operations wf_mpu_midi_proto = { - {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - NULL, /*converter*/ - {0}, /* in_info */ - wf_mpu_open, - wf_mpu_close, - wf_mpu_ioctl, - wf_mpu_out, - wf_mpu_start_read, - wf_mpu_end_read, - NULL, - NULL, - wf_mpu_buffer_status, - NULL + owner: THIS_MODULE, + info: {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, + in_info: {0}, /* in_info */ + open: wf_mpu_open, + close: wf_mpu_close, + ioctl: wf_mpu_ioctl, + outputc: wf_mpu_out, + start_read: wf_mpu_start_read, + end_read: wf_mpu_end_read, + buffer_status: wf_mpu_buffer_status, }; static struct synth_info wf_mpu_synth_info_proto = @@ -671,28 +667,27 @@ wf_mpu_synth_close (int dev) static struct synth_operations wf_mpu_synth_proto = { - "WaveFront (ICS2115)", - NULL, /* info field, filled in during configuration */ - 0, /* MIDI dev XXX should this be -1 ? */ - SYNTH_TYPE_MIDI, - SAMPLE_TYPE_WAVEFRONT, - wf_mpu_synth_open, - wf_mpu_synth_close, - wf_mpu_synth_ioctl, - midi_synth_kill_note, - midi_synth_start_note, - midi_synth_set_instr, - midi_synth_reset, - midi_synth_hw_control, - midi_synth_load_patch, - midi_synth_aftertouch, - midi_synth_controller, - midi_synth_panning, - NULL, - midi_synth_bender, - NULL, /* alloc */ - midi_synth_setup_voice, - midi_synth_send_sysex + owner: THIS_MODULE, + id: "WaveFront (ICS2115)", + info: NULL, /* info field, filled in during configuration */ + midi_dev: 0, /* MIDI dev XXX should this be -1 ? */ + synth_type: SYNTH_TYPE_MIDI, + synth_subtype: SAMPLE_TYPE_WAVEFRONT, + open: wf_mpu_synth_open, + close: wf_mpu_synth_close, + ioctl: wf_mpu_synth_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + hw_control: midi_synth_hw_control, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice, + send_sysex: midi_synth_send_sysex }; static int diff --git a/drivers/sound/ymf_sb.c b/drivers/sound/ymf_sb.c index a221a05d0..5762eea13 100644 --- a/drivers/sound/ymf_sb.c +++ b/drivers/sound/ymf_sb.c @@ -54,7 +54,6 @@ #include <asm/io.h> #include "sound_config.h" -#include "soundmodule.h" #include "sb.h" #include "724hwmcode.h" @@ -64,11 +63,6 @@ /* ---------------------------------------------------------------------- */ -#ifndef SOUND_LOCK -#define SOUND_LOCK do {} while (0) -#define SOUND_LOCK_END do {} while (0) -#endif - #ifndef PCI_VENDOR_ID_YAMAHA #define PCI_VENDOR_ID_YAMAHA 0x1073 #endif @@ -641,7 +635,7 @@ static int __init ymf7xx_init(struct pci_dev *pcidev) static void __init ymf7xxsb_attach_sb(struct address_info *hw_config) { - if(!sb_dsp_init(hw_config)) + if(!sb_dsp_init(hw_config, THIS_MODULE)) hw_config->slots[0] = -1; } @@ -784,7 +778,7 @@ static int __init ymf7xxsb_init_one (struct pci_dev *pcidev, const struct pci_de ymf7xxsb_unload_sb (&sb_data[cards], 0); return -ENODEV; } - ymf7xxsb_attach_midi (&mpu_data[cards]); + ymf7xxsb_attach_midi (&mpu_data[cards], THIS_MODULE); } #endif @@ -804,11 +798,6 @@ static int __init init_ymf7xxsb_module(void) { int i; - /* - * Binds us to the sound subsystem - */ - SOUND_LOCK; - if ( master_vol < 0 ) master_vol = 50; if ( master_vol > 100 ) master_vol = 100; @@ -816,10 +805,8 @@ static int __init init_ymf7xxsb_module(void) ymfbase[i] = NULL; i = pci_module_init (&ymf7xxsb_driver); - if (i < 0) { - SOUND_LOCK_END; + if (i < 0) return i; - } printk (KERN_INFO PFX YMFSB_CARD_NAME " loaded\n"); @@ -853,10 +840,6 @@ static void __exit cleanup_ymf7xxsb_module(void) free_iomaps(); - /* - * Final clean up with the sound layer - */ - SOUND_LOCK_END; } MODULE_AUTHOR("Daisuke Nagano, breeze.nagano@nifty.ne.jp"); diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 1edbfcb44..496faba61 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -68,31 +68,23 @@ comment 'USB Devices' dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET - dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET + dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB fi -comment 'USB HID' - dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB - if [ "$CONFIG_USB_HID" != "y" ]; then - dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB - dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB - fi - dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB - dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_USB - if [ "$CONFIG_INPUT_IFORCE_USB" != "n" ]; then - define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_USB + comment 'USB Human Interface Devices (HID)' + if [ "$CONFIG_INPUT" = "n" ]; then + comment ' Input core support is needed for USB HID' + else + dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT + if [ "$CONFIG_USB_HID" != "y" ]; then + dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT + dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT fi - dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB - dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB - if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then - int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 - int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 + dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT fi - dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB - dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB fi endmenu diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 5831dd1d9..7112ae635 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -17,7 +17,7 @@ O_OBJS := # Objects that export symbols. -export-objs := usb.o input.o +export-objs := usb.o # Multipart objects. @@ -37,27 +37,6 @@ obj-m := obj-n := obj- := -# Object files in subdirectories - -ifeq ($(CONFIG_USB_SERIAL),y) - SUB_DIRS += serial - obj-y += serial/usb-serial.o -else - ifeq ($(CONFIG_USB_SERIAL),m) - MOD_IN_SUB_DIRS += serial - endif -endif - -ifeq ($(CONFIG_USB_STORAGE),y) - SUB_DIRS += storage - obj-y += storage/usb-storage.o -else - ifeq ($(CONFIG_USB_STORAGE),m) - MOD_IN_SUB_DIRS += storage - endif -endif - - # Each configuration option enables a list of files. obj-$(CONFIG_USB) += usbcore.o @@ -65,15 +44,10 @@ obj-$(CONFIG_USB_UHCI) += usb-uhci.o obj-$(CONFIG_USB_UHCI_ALT) += uhci.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o -obj-$(CONFIG_USB_MOUSE) += usbmouse.o input.o -obj-$(CONFIG_USB_HID) += hid.o input.o -obj-$(CONFIG_USB_KBD) += usbkbd.o input.o -obj-$(CONFIG_USB_WACOM) += wacom.o input.o -obj-$(CONFIG_INPUT_IFORCE) += iforce.o input.o -obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o input.o -obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o input.o -obj-$(CONFIG_INPUT_JOYDEV) += joydev.o input.o -obj-$(CONFIG_INPUT_EVDEV) += evdev.o input.o +obj-$(CONFIG_USB_MOUSE) += usbmouse.o +obj-$(CONFIG_USB_HID) += hid.o +obj-$(CONFIG_USB_KBD) += usbkbd.o +obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_SCANNER) += scanner.o obj-$(CONFIG_USB_ACM) += acm.o @@ -92,6 +66,26 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_MICROTEK) += microtek.o obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o +# Object files in subdirectories + +ifeq ($(CONFIG_USB_SERIAL),y) + SUB_DIRS += serial + obj-y += serial/usb-serial.o +else + ifeq ($(CONFIG_USB_SERIAL),m) + MOD_IN_SUB_DIRS += serial + endif +endif + +ifeq ($(CONFIG_USB_STORAGE),y) + SUB_DIRS += storage + obj-y += storage/usb-storage.o +else + ifeq ($(CONFIG_USB_STORAGE),m) + MOD_IN_SUB_DIRS += storage + endif +endif + # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. @@ -111,8 +105,8 @@ obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) # Translate to Rules.make lists. -O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) -OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c index 4ee29a702..fd239671b 100644 --- a/drivers/usb/bluetooth.c +++ b/drivers/usb/bluetooth.c @@ -1,5 +1,5 @@ /* - * bluetooth.c Version 0.3 + * bluetooth.c Version 0.4 * * Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com> * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu> @@ -7,6 +7,13 @@ * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B * * + * (07/11/2000) Version 0.4 gkh + * Fixed bug in disconnect for when we call tty_hangup + * Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not + * getting attached to the control urb properly. + * Fixed bug in bluetooth_write where we pay attention to the result + * of bluetooth_ctrl_msg. + * * (08/03/2000) Version 0.3 gkh mdc * Merged in Mark's changes to make the driver play nice with the Axis * stack. @@ -251,7 +258,7 @@ static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int dr->length = cpu_to_le16p(&len); FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0), - (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, 0); + (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, bluetooth); /* send it down the pipe */ status = usb_submit_urb(urb); @@ -400,7 +407,10 @@ static int bluetooth_write (struct tty_struct * tty, int from_user, const unsign else memcpy (new_buffer, buf+1, count-1); - bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1); + if (bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1) != 0) { + kfree (new_buffer); + return 0; + } /* need to free new_buffer somehow... FIXME */ return count; @@ -1099,6 +1109,9 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr) int i; if (bluetooth) { + if ((bluetooth->active) && (bluetooth->tty)) + tty_hangup(bluetooth->tty); + bluetooth->active = 0; if (bluetooth->read_urb) { @@ -1117,9 +1130,6 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr) tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor); - if (bluetooth->tty) - tty_hangup(bluetooth->tty); - for (i = 0; i < NUM_BULK_URBS; ++i) { if (bluetooth->write_urb_pool[i]) { usb_unlink_urb (bluetooth->write_urb_pool[i]); diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c index bb960a4af..67a55ab46 100644 --- a/drivers/usb/dc2xx.c +++ b/drivers/usb/dc2xx.c @@ -43,6 +43,7 @@ * added timeouts to bulk_msg calls. Minor updates, docs. * 03 Nov, 1999 -- update for 2.3.25 kernel API changes. * 08 Jan, 2000 .. multiple camera support + * 12 Aug, 2000 .. add some real locking, remove an Oops * * Thanks to: the folk who've provided USB product IDs, sent in * patches, and shared their sucesses! @@ -60,7 +61,6 @@ #include <linux/module.h> #undef DEBUG #include <linux/usb.h> -#include <linux/smp_lock.h> @@ -114,7 +114,7 @@ struct camera_state { int outEP; /* write endpoint */ const struct camera *info; /* DC-240, etc */ int subminor; /* which minor dev #? */ - int isActive; /* I/O taking place? */ + struct semaphore sem; /* locks this struct */ /* this is non-null iff the device is open */ char *buf; /* buffer for I/O */ @@ -127,21 +127,25 @@ struct camera_state { /* Support multiple cameras, possibly of different types. */ static struct camera_state *minor_data [MAX_CAMERAS]; +/* make this an rwlock if contention becomes an issue */ +static DECLARE_MUTEX (state_table_mutex); static ssize_t camera_read (struct file *file, char *buf, size_t len, loff_t *ppos) { struct camera_state *camera; int retries; + int retval = 0; if (len > MAX_PACKET_SIZE) return -EINVAL; camera = (struct camera_state *) file->private_data; - if (!camera->dev) + down (&camera->sem); + if (!camera->dev) { + up (&camera->sem); return -ENODEV; - if (camera->isActive++) - return -EBUSY; + } /* Big reads are common, for image downloading. Smaller ones * are also common (even "directory listing" commands don't @@ -150,37 +154,33 @@ static ssize_t camera_read (struct file *file, */ for (retries = 0; retries < MAX_READ_RETRY; retries++) { int count; - int result; if (signal_pending (current)) { - camera->isActive = 0; - return -EINTR; - } - if (!camera->dev) { - camera->isActive = 0; - return -ENODEV; + retval = -EINTR; + break; } - result = usb_bulk_msg (camera->dev, + retval = usb_bulk_msg (camera->dev, usb_rcvbulkpipe (camera->dev, camera->inEP), camera->buf, len, &count, HZ*10); - dbg ("read (%d) - 0x%x %d", len, result, count); + dbg ("read (%d) - 0x%x %d", len, retval, count); - if (!result) { + if (!retval) { if (copy_to_user (buf, camera->buf, count)) - return -EFAULT; - camera->isActive = 0; - return count; + retval = -EFAULT; + else + retval = count; + break; } - if (result != USB_ST_TIMEOUT) + if (retval != USB_ST_TIMEOUT) break; interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT); dbg ("read (%d) - retry", len); } - camera->isActive = 0; - return -EIO; + up (&camera->sem); + return retval; } static ssize_t camera_write (struct file *file, @@ -193,10 +193,11 @@ static ssize_t camera_write (struct file *file, return -EINVAL; camera = (struct camera_state *) file->private_data; - if (!camera->dev) + down (&camera->sem); + if (!camera->dev) { + up (&camera->sem); return -ENODEV; - if (camera->isActive++) - return -EBUSY; + } /* most writes will be small: simple commands, sometimes with * parameters. putting images (like borders) into the camera @@ -224,18 +225,13 @@ static ssize_t camera_write (struct file *file, bytes_written = -EINTR; goto done; } - if (!camera->dev) { - if (!bytes_written) - bytes_written = -ENODEV; - goto done; - } result = usb_bulk_msg (camera->dev, usb_sndbulkpipe (camera->dev, camera->outEP), obuf, thistime, &count, HZ*10); if (result) - dbg ("write USB err - %x", result); + dbg ("write USB err - %d", result); if (count) { obuf += count; @@ -264,49 +260,69 @@ static ssize_t camera_write (struct file *file, buf += copy_size; } done: - camera->isActive = 0; + up (&camera->sem); dbg ("wrote %d", bytes_written); return bytes_written; } static int camera_open (struct inode *inode, struct file *file) { - struct camera_state *camera; + struct camera_state *camera = NULL; int subminor; + int value = 0; + down (&state_table_mutex); subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE; if (subminor < 0 || subminor >= MAX_CAMERAS || !(camera = minor_data [subminor])) { + up (&state_table_mutex); return -ENODEV; } + down (&camera->sem); + up (&state_table_mutex); + + if (camera->buf) { + value = -EBUSY; + goto done; + } if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) { - return -ENOMEM; + value = -ENOMEM; + goto done; } - dbg ("open"); + dbg ("open #%d", subminor); - camera->isActive = 0; file->private_data = camera; - return 0; +done: + up (&camera->sem); + return value; } static int camera_release (struct inode *inode, struct file *file) { - struct camera_state *camera; + struct camera_state *camera; + int subminor; camera = (struct camera_state *) file->private_data; - kfree (camera->buf); + down (&state_table_mutex); + down (&camera->sem); + + if (camera->buf) { + kfree (camera->buf); + camera->buf = 0; + } + subminor = camera->subminor; /* If camera was unplugged with open file ... */ - lock_kernel(); if (!camera->dev) { - minor_data [camera->subminor] = NULL; + minor_data [subminor] = NULL; kfree (camera); } - unlock_kernel(); + up (&camera->sem); + up (&state_table_mutex); - dbg ("close"); + dbg ("close #%d", subminor); return 0; } @@ -333,7 +349,7 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum) struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; int direction, ep; - struct camera_state *camera; + struct camera_state *camera = NULL; /* Is it a supported camera? */ for (i = 0; i < sizeof (cameras) / sizeof (struct camera); i++) { @@ -368,27 +384,30 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum) /* select "subminor" number (part of a minor number) */ + down (&state_table_mutex); for (i = 0; i < MAX_CAMERAS; i++) { if (!minor_data [i]) break; } if (i >= MAX_CAMERAS) { info ("Ignoring additional USB Camera"); - return NULL; + up (&state_table_mutex); + goto bye; } /* allocate & init camera state */ camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL); if (!camera) { err ("no memory!"); - return NULL; + up (&state_table_mutex); + goto bye; } + + init_MUTEX (&camera->sem); camera->info = camera_info; camera->subminor = i; - camera->isActive = 0; camera->buf = NULL; init_waitqueue_head (&camera->wait); - info ("USB Camera #%d connected", camera->subminor); /* get input and output endpoints (either order) */ @@ -417,19 +436,19 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum) goto error; } - - if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) { - err ("Failed usb_set_configuration"); - goto error; - } + info ("USB Camera #%d connected", camera->subminor); camera->dev = dev; - return camera; + usb_inc_dev_use (dev); + goto bye; error: minor_data [camera->subminor] = NULL; kfree (camera); - return NULL; + camera = NULL; +bye: + up (&state_table_mutex); + return camera; } static void camera_disconnect(struct usb_device *dev, void *ptr) @@ -437,6 +456,9 @@ static void camera_disconnect(struct usb_device *dev, void *ptr) struct camera_state *camera = (struct camera_state *) ptr; int subminor = camera->subminor; + down (&state_table_mutex); + down (&camera->sem); + /* If camera's not opened, we can clean up right away. * Else apps see a disconnect on next I/O; the release cleans. */ @@ -447,6 +469,10 @@ static void camera_disconnect(struct usb_device *dev, void *ptr) camera->dev = NULL; info ("USB Camera #%d disconnected", subminor); + usb_dec_dev_use (dev); + + up (&camera->sem); + up (&state_table_mutex); } static /* const */ struct usb_driver camera_driver = { diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c index 5609ae1c2..00bd135e8 100644 --- a/drivers/usb/devio.c +++ b/drivers/usb/devio.c @@ -733,8 +733,7 @@ static int proc_clearhalt(struct dev_state *ps, void *arg) else pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); - usb_clear_halt(ps->dev, pipe); - return 0; + return usb_clear_halt(ps->dev, pipe); } diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c index 68a981e27..189cbbdfc 100644 --- a/drivers/usb/hid.c +++ b/drivers/usb/hid.c @@ -1,5 +1,5 @@ /* - * $Id: hid.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $ + * $Id: hid.c,v 1.14 2000/08/14 21:05:26 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000 Vojtech Pavlik @@ -65,8 +65,8 @@ static unsigned char hid_keyboard[256] = { 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114,unk,unk,unk,unk,unk,124,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + 115,114,unk,unk,unk,124,unk,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, @@ -149,7 +149,7 @@ static int open_collection(struct hid_parser *parser, unsigned type) usage = parser->local.usage[0]; - if (type == HID_COLLECTION_APPLICATION) + if (type == HID_COLLECTION_APPLICATION && !parser->device->application) parser->device->application = usage; if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */ @@ -197,7 +197,7 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) static int hid_add_usage(struct hid_parser *parser, unsigned usage) { - if (parser->local.usage_index >= MAX_USAGES) { + if (parser->local.usage_index >= HID_MAX_USAGES) { dbg("usage index exceeded"); return -1; } @@ -346,7 +346,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) return 0; case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - if ((parser->global.report_count = item_udata(item)) > MAX_USAGES) { + if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { dbg("invalid report_count %d", parser->global.report_count); return -1; } @@ -1224,10 +1224,31 @@ static int hid_find_field(struct hid_device *hid, unsigned int type, unsigned in return -1; } +static int hid_submit_out(struct hid_device *hid) +{ + hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; + hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; + hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); + + if (usb_submit_urb(&hid->urbout)) { + err("usb_submit_urb(out) failed"); + return -1; + } + + return 0; +} + static void hid_ctrl(struct urb *urb) { + struct hid_device *hid = urb->context; + if (urb->status) - warn("ctrl urb status %d received", urb->status); + warn("ctrl urb status %d received", urb->status); + + hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + + if (hid->outhead != hid->outtail) + hid_submit_out(hid); } static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -1242,22 +1263,18 @@ static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code } hid_set_field(field, offset, value); + hid_output_report(field->report, hid->out[hid->outhead].buffer); - if (hid->urbout.status == -EINPROGRESS) { - warn("had to kill output urb"); - usb_unlink_urb(&hid->urbout); - } + hid->out[hid->outhead].dr.value = 0x200 | field->report->id; + hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1; - hid_output_report(field->report, hid->bufout); + hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); - hid->dr.value = 0x200 | field->report->id; - hid->dr.length = ((field->report->size - 1) >> 3) + 1; - hid->urbout.transfer_buffer_length = hid->dr.length; + if (hid->outhead == hid->outtail) + hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (usb_submit_urb(&hid->urbout)) { - err("usb_submit_urb(out) failed"); - return -1; - } + if (hid->urbout.status != -EINPROGRESS) + hid_submit_out(hid); return 0; } @@ -1364,7 +1381,7 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT) rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); - if (!rsize || rsize > 1024) { + if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dbg("weird size of report descriptor (%u)", rsize); return NULL; } @@ -1420,11 +1437,11 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c hid->dev = dev; hid->ifnum = interface->bInterfaceNumber; - hid->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - hid->dr.request = USB_REQ_SET_REPORT; - hid->dr.value = 0x200; - hid->dr.index = hid->ifnum; - hid->dr.length = 1; + for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { + hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + hid->out[n].dr.request = USB_REQ_SET_REPORT; + hid->out[n].dr.index = hid->ifnum; + } hid->input.name = hid->name; hid->input.idbus = BUS_USB; @@ -1441,7 +1458,7 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c hid->input.idvendor, hid->input.idproduct); FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0), - (void*) &hid->dr, hid->bufout, 1, hid_ctrl, hid); + (void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid); if (interface->bInterfaceSubClass == 1) usb_set_protocol(dev, hid->ifnum, 1); diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h index 88ab5eaca..98abc8a76 100644 --- a/drivers/usb/hid.h +++ b/drivers/usb/hid.h @@ -2,7 +2,7 @@ #define __HID_H /* - * $Id: hid.h,v 1.4 2000/05/29 09:01:52 vojtech Exp $ + * $Id: hid.h,v 1.7 2000/05/31 22:57:48 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000 Vojtech Pavlik @@ -208,10 +208,11 @@ struct hid_global { * This is the local enviroment. It is resistent up the the next main-item. */ -#define MAX_USAGES 1024 +#define HID_MAX_DESCRIPTOR_SIZE 4096 +#define HID_MAX_USAGES 1024 struct hid_local { - unsigned usage[MAX_USAGES]; /* usage array */ + unsigned usage[HID_MAX_USAGES]; /* usage array */ unsigned usage_index; unsigned usage_minimum; unsigned delimiter_depth; @@ -275,6 +276,14 @@ struct hid_report_enum { #define HID_REPORT_TYPES 3 +#define HID_BUFFER_SIZE 32 +#define HID_CONTROL_FIFO_SIZE 8 + +struct hid_control_fifo { + devrequest dr; + char buffer[HID_BUFFER_SIZE]; +}; + struct hid_device { /* device report descriptor */ __u8 *rdesc; unsigned rsize; @@ -286,11 +295,13 @@ struct hid_device { /* device report descriptor */ struct usb_device *dev; /* USB device */ int ifnum; /* USB interface number */ - char buffer[32]; /* Receive buffer */ - char bufout[32]; /* Transmit buffer */ - devrequest dr; /* Startup packet */ struct urb urb; /* USB URB structure */ + char buffer[HID_BUFFER_SIZE]; /* Rx buffer */ + struct urb urbout; /* Output URB */ + struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE]; /* Transmit buffer */ + unsigned char outhead, outtail; /* Tx buffer head & tail */ + struct input_dev input; /* input device structure */ int open; /* is the device open by input? */ int quirks; /* Various nasty tricks the device can pull on us */ diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c index 50970155b..b55073398 100644 --- a/drivers/usb/inode.c +++ b/drivers/usb/inode.c @@ -290,14 +290,14 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill i = filp->f_pos; switch (i) { case 0: - if (filldir(dirent, ".", 1, i, IROOT) < 0) + if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0) return 0; filp->f_pos++; i++; /* fall through */ case 1: - if (filldir(dirent, "..", 2, i, IROOT) < 0) + if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0) return 0; filp->f_pos++; i++; @@ -307,7 +307,7 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill while (i >= 2 && i < 2+NRSPECIAL) { spec = &special[filp->f_pos-2]; - if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0) + if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0) return 0; filp->f_pos++; i++; @@ -323,7 +323,7 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill } bus = list_entry(list, struct usb_bus, bus_list); sprintf(numbuf, "%03d", bus->busnum); - if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0) + if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0) break; filp->f_pos++; } @@ -343,7 +343,7 @@ static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struc if (pos > 0) pos--; else { - if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0) + if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0) return -1; filp->f_pos++; } @@ -368,13 +368,13 @@ static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filld return -EINVAL; switch ((unsigned int)filp->f_pos) { case 0: - if (filldir(dirent, ".", 1, filp->f_pos, ino) < 0) + if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0) return 0; filp->f_pos++; /* fall through */ case 1: - if (filldir(dirent, "..", 2, filp->f_pos, IROOT) < 0) + if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0) return 0; filp->f_pos++; /* fall through */ diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c index 0a264faaf..96a28da5e 100644 --- a/drivers/usb/pegasus.c +++ b/drivers/usb/pegasus.c @@ -1,7 +1,7 @@ /* ** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller ** -** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@spct.net) +** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg) ** ** ** ChangeLog: @@ -42,16 +42,26 @@ #include <linux/usb.h> -static const char *version = __FILE__ ": v0.4.0 2000/06/15 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n"; +static const char *version = __FILE__ ": v0.4.3 2000/08/22 (C) 1999-2000 Petko Manolov (petkan@dce.bg)\n"; + + +#define PEGASUS_USE_WAITQ #define PEGASUS_MTU 1500 #define PEGASUS_MAX_MTU 1536 -#define SROM_WRITE 0x01 -#define SROM_READ 0x02 -#define PEGASUS_TX_TIMEOUT (HZ*5) -#define PEGASUS_CTRL_TIMEOUT 1000 -#define PEGASUS_RESET 1 +#define EPROM_WRITE 0x01 +#define EPROM_READ 0x02 +#define PEGASUS_TX_TIMEOUT (HZ*10) +#define PEGASUS_CTRL_TIMEOUT (HZ*5) +#define PEGASUS_CTRL_WAIT (1<<31) +#define PEGASUS_RUNNING 1 +#define PEGASUS_REQT_READ 0xc0 +#define PEGASUS_REQT_WRITE 0x40 +#define PEGASUS_REQ_GET_REGS 0xf0 +#define PEGASUS_REQ_SET_REGS 0xf1 +#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS +#define NUM_CTRL_URBS 0x10 #define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) @@ -75,16 +85,26 @@ enum pegasus_registers { }; +struct pegasus; +struct ctrl_urb_pool { + struct pegasus *pegasus; + struct urb urb; + devrequest dr; + __u8 busy; +}; + + struct pegasus { struct usb_device *usb; struct net_device *net; struct net_device_stats stats; int flags; - spinlock_t pegasus_lock, ctrl_lock; - struct urb rx_urb, tx_urb, intr_urb, ctrl_urb; - devrequest dr; - unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); - unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); + struct urb rx_urb, tx_urb, intr_urb; + struct ctrl_urb_pool ALIGN(ctrl[NUM_CTRL_URBS]); + wait_queue_head_t ctrl_wait; + struct semaphore ctrl_sem; + unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); + unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(intr_buff[8]); }; @@ -100,10 +120,11 @@ static int loopback = 0; static int multicast_filter_limit = 32; -MODULE_AUTHOR("Petko Manolov <petkan@spct.net>"); +MODULE_AUTHOR("Petko Manolov <petkan@dce.bg>"); MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver"); MODULE_PARM(loopback, "i"); -MODULE_PARM_DESC(loopback, "Enable loopback mode (Bit 0) and ??? (Bit 1)"); +MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); + static struct usb_eth_dev usb_dev_id[] = { {"Billionton USB-100", 0x08dd, 0x0986, NULL}, @@ -112,8 +133,10 @@ static struct usb_eth_dev usb_dev_id[] = { {"D-Link DSB-650TX", 0x2001, 0x4001, NULL}, {"D-Link DSB-650TX", 0x2001, 0x4002, NULL}, {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL}, + {"D-Link DSB-650", 0x2001, 0xabc1, NULL}, {"D-Link DU-E10", 0x07b8, 0xabc1, NULL}, {"D-Link DU-E100", 0x07b8, 0x4002, NULL}, + {"Linksys USB10TX", 0x066b, 0x2202, NULL}, {"Linksys USB100TX", 0x066b, 0x2203, NULL}, {"Linksys USB100TX", 0x066b, 0x2204, NULL}, {"Linksys USB Ethernet Adapter", 0x066b, 0x2206, NULL}, @@ -122,112 +145,149 @@ static struct usb_eth_dev usb_dev_id[] = { {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL}, {"IO DATA USB ET/TX", 0x04bb, 0x0904, NULL}, {"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, NULL}, + {"SOHOware NUB100 Ethernet", 0x15e8, 0x9100, NULL}, {NULL, 0, 0, NULL} }; - -static void pegasus_ctrl_end( urb_t *urb ) +static void pegasus_unlink_ctrl_urbs( struct pegasus *pegasus ) { - if ( urb->status ) - warn("ctrl_urb end status %d", urb->status); + int i; + + for ( i=0; i < NUM_CTRL_URBS; i++ ) { + if ( pegasus->ctrl[i].urb.status == -EINPROGRESS ) + usb_unlink_urb( &pegasus->ctrl[i].urb ); + } } -static int pegasus_ctrl_timeout( urb_t *ctrl_urb ) +static int pegasus_find_ctrl_urb( struct pegasus *pegasus ) { - int timeout=0; - - while ( ctrl_urb->status == -EINPROGRESS ) { - if ( timeout++ < PEGASUS_CTRL_TIMEOUT ) { - udelay(100); - continue; - } - err("ctrl urb busy %d", ctrl_urb->status); - usb_unlink_urb( ctrl_urb ); - return ctrl_urb->status; - } - return 0; + int i=0; + + while( i < NUM_CTRL_URBS && (pegasus->ctrl[i].busy == 1 || + (pegasus->ctrl[i].urb.status == -EINPROGRESS)) ) + i++; + + return i; } -static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +static void pegasus_ctrl_end( urb_t *urb ) { - int ret; + struct ctrl_urb_pool *ctrl = urb->context; + struct pegasus *pegasus = ctrl->pegasus; - spin_lock( &pegasus->ctrl_lock ); - pegasus->dr.requesttype = 0xc0; - pegasus->dr.request = 0xf0; - pegasus->dr.value = 0x0; - pegasus->dr.index = indx; - pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size; + if ( !pegasus ) + return; - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, - usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, - data, size, pegasus_ctrl_end, pegasus ); + if ( urb->status ) + warn("ctrl_urb end status %d", urb->status); + ctrl->busy = 0; +#ifdef PEGASUS_USE_WAITQ + wake_up_interruptible( &pegasus->ctrl_wait ); +#endif +} - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) - err("BAD CTRLs %d", ret); - else - ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); - spin_unlock( &pegasus->ctrl_lock ); +static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +{ + int ret, i; + struct ctrl_urb_pool *ctrl; + + if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { + return -1; + } + ctrl = &pegasus->ctrl[i]; + ctrl->busy = 1; + ctrl->pegasus = pegasus; + + ctrl->dr.requesttype = PEGASUS_REQT_READ; + ctrl->dr.request = PEGASUS_REQ_GET_REGS; + ctrl->dr.value = 0; + ctrl->dr.index = cpu_to_le16p(&indx); + ctrl->dr.length = + ctrl->urb.transfer_buffer_length = cpu_to_le16p(&size); + + FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + usb_rcvctrlpipe(pegasus->usb,0), + (char *)&ctrl->dr, + data, size, pegasus_ctrl_end, ctrl ); + + if ( (ret = usb_submit_urb( &ctrl->urb )) ) + err( __FUNCTION__ " BAD CTRLs %d", ret); +#ifdef PEGASUS_USE_WAITQ + interruptible_sleep_on( &pegasus->ctrl_wait ); +#endif return ret; } static int pegasus_set_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) { - int ret; - - - spin_lock( &pegasus->ctrl_lock ); - pegasus->dr.requesttype = 0x40; - pegasus->dr.request = 0xf1; - pegasus->dr.value = 0x0; - pegasus->dr.index = indx; - pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size; - - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, - data, size, pegasus_ctrl_end, pegasus ); - - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) - err("BAD CTRL %d", ret); - else - ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); - - spin_unlock( &pegasus->ctrl_lock ); + int ret, i; + struct ctrl_urb_pool *ctrl; + + if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { + return -1; + } + ctrl = &pegasus->ctrl[i]; + ctrl->busy = 1; + ctrl->pegasus = pegasus; + + ctrl->dr.requesttype = PEGASUS_REQT_WRITE; + ctrl->dr.request = PEGASUS_REQ_SET_REGS; + ctrl->dr.value = 0; + ctrl->dr.index = cpu_to_le16p( &indx ); + ctrl->dr.length = + ctrl->urb.transfer_buffer_length = cpu_to_le16p( &size ); + + FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb,0), + (char *)&ctrl->dr, + data, size, pegasus_ctrl_end, ctrl ); + + if ( (ret = usb_submit_urb( &ctrl->urb )) ) + err( __FUNCTION__ " BAD CTRL %d", ret); +#ifdef PEGASUS_USE_WAITQ + interruptible_sleep_on( &pegasus->ctrl_wait ); +#endif return ret; } static int pegasus_set_register( struct pegasus *pegasus, __u16 indx,__u8 data ) { - int ret; - - - spin_lock( &pegasus->ctrl_lock ); - pegasus->dr.requesttype = 0x40; - pegasus->dr.request = 0xf1; - pegasus->dr.value = data; - pegasus->dr.index = indx; - pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1; - - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, - &data, 1, pegasus_ctrl_end, pegasus ); - - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) - err("BAD CTRL %d", ret); - else - ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); - - spin_unlock( &pegasus->ctrl_lock ); + int ret, i; + struct ctrl_urb_pool *ctrl; + + if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { + return -1; + } + ctrl = &pegasus->ctrl[i]; + ctrl->busy = 1; + ctrl->pegasus = pegasus; + + ctrl->dr.requesttype = PEGASUS_REQT_WRITE; + ctrl->dr.request = PEGASUS_REQ_SET_REG; + ctrl->dr.value = cpu_to_le16p( &data ); + ctrl->dr.index = cpu_to_le16p( &indx ); + ctrl->dr.length = ctrl->urb.transfer_buffer_length = 1; + + FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb,0), + (char *)&ctrl->dr, + &data, 1, pegasus_ctrl_end, ctrl ); + + if ( (ret = usb_submit_urb( &ctrl->urb )) ) + err( __FUNCTION__ " BAD CTRL %d", ret); +#ifdef PEGASUS_USE_WAITQ + interruptible_sleep_on( &pegasus->ctrl_wait ); +#endif return ret; } @@ -244,10 +304,9 @@ static int pegasus_read_phy_word(struct pegasus *pegasus, __u8 index, __u16 *reg *regdata = *(__u16 *)(data); return 0; } - udelay(100); } - warn("read_phy_word() failed"); + return 1; } @@ -262,10 +321,9 @@ static int pegasus_write_phy_word(struct pegasus *pegasus, __u8 index, __u16 reg pegasus_get_registers(pegasus, PhyCtrl, 1, data); if (data[0] & 0x80) return 0; - udelay(100); } - warn("write_phy_word() failed"); + return 1; } @@ -284,8 +342,8 @@ static int pegasus_rw_eprom_word(struct pegasus *pegasus, __u8 index, __u16 *ret return 0; } } - warn("pegasus_rw_eprom_word() failed"); + return 1; } @@ -294,7 +352,7 @@ static int pegasus_get_node_id(struct pegasus *pegasus, __u8 *id) { int i; for (i = 0; i < 3; i++) - if (pegasus_rw_eprom_word(pegasus,i,(__u16 *)&id[i*2],SROM_READ)) + if (pegasus_rw_eprom_word(pegasus, i, (__u16 *)&id[i*2], EPROM_READ)) return 1; return 0; } @@ -311,8 +369,6 @@ static int pegasus_reset_mac(struct pegasus *pegasus) if (~data & 0x08) { if (loopback & 1) return 0; - if (loopback & 2) - pegasus_write_phy_word(pegasus, 0, 0x4000); pegasus_set_register(pegasus, Gpio0, 0x24); pegasus_set_register(pegasus, Gpio0, 0x27); return 0; @@ -348,7 +404,6 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb) if ((partmedia & 0x1f) != 1) { warn("party FAIL %x", partmedia); - /* return 5; FIXME */ } data[0] = 0xc9; @@ -361,15 +416,21 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb) } -static void pegasus_read_bulk(struct urb *urb) +static void pegasus_read_bulk_callback( struct urb *urb ) { struct pegasus *pegasus = urb->context; - struct net_device *net = pegasus->net; + struct net_device *net; /* = pegasus->net;*/ int count = urb->actual_length, res; - int rx_status = *(int *)(pegasus->rx_buff + count - 4); + int rx_status; /*= *(int *)(pegasus->rx_buff + count - 4);*/ struct sk_buff *skb; __u16 pkt_len; + if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) ) + return; + + net = pegasus->net; + rx_status = *(int *)(pegasus->rx_buff + count - 4); + if (urb->status) { dbg("%s: RX status %d", net->name, urb->status); goto goon; @@ -408,31 +469,30 @@ static void pegasus_read_bulk(struct urb *urb) pegasus->stats.rx_bytes += pkt_len; goon: - if ((res = usb_submit_urb(&pegasus->rx_urb))) + if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) warn("(prb)failed rx_urb %d", res); } -static void pegasus_irq(urb_t *urb) +static void pegasus_irq_callback( urb_t *urb ) { __u8 *d = urb->transfer_buffer; - + + if ( d[0] ) dbg("txst0=0x%2x", d[0]); } -static void pegasus_write_bulk(struct urb *urb) +static void pegasus_write_bulk_callback(struct urb *urb) { struct pegasus *pegasus = urb->context; + if ( !pegasus ) + return; if (urb->status) info("%s: TX status %d", pegasus->net->name, urb->status); -#if 1 /* Should be fixed */ - if (urb->status == -ETIMEDOUT) - pegasus_reset_mac(pegasus); -#endif netif_wake_queue(pegasus->net); } @@ -440,10 +500,11 @@ static void pegasus_tx_timeout(struct net_device *net) { struct pegasus *pegasus = net->priv; + if ( !pegasus ) + return; usb_unlink_urb(&pegasus->tx_urb); - warn("%s: Tx timed out. Reseting...", net->name); - pegasus_reset_mac( pegasus ); + warn("%s: Tx timed out.", net->name); pegasus->stats.tx_errors++; net->trans_start = jiffies; @@ -457,13 +518,14 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3; int res; - spin_lock(&pegasus->pegasus_lock); - netif_stop_queue(net); + if ( !(pegasus->flags & PEGASUS_RUNNING) ) + return 0; ((__u16 *)pegasus->tx_buff)[0] = skb->len; memcpy(pegasus->tx_buff+2, skb->data, skb->len); - (&pegasus->tx_urb)->transfer_buffer_length = count; + pegasus->tx_urb.transfer_buffer_length = count; + pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK; if ((res = usb_submit_urb(&pegasus->tx_urb))) { warn("failed tx_urb %d", res); @@ -477,8 +539,6 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) dev_kfree_skb(skb); - spin_unlock(&pegasus->pegasus_lock); - return 0; } @@ -489,6 +549,15 @@ static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) } +static inline void pegasus_stop_net( struct pegasus *pegasus ) +{ + int tmp; + + pegasus_get_registers( pegasus, EthCtrl0, 1, &tmp ); + pegasus_set_register( pegasus, EthCtrl0, tmp & 0x3f ); +} + + static int pegasus_open(struct net_device *net) { struct pegasus *pegasus = (struct pegasus *)net->priv; @@ -506,8 +575,7 @@ static int pegasus_open(struct net_device *net) warn("(open)failed intr_urb %d", res); netif_start_queue(net); - - MOD_INC_USE_COUNT; + pegasus->flags |= PEGASUS_RUNNING; return 0; } @@ -517,18 +585,15 @@ static int pegasus_close(struct net_device *net) { struct pegasus *pegasus = net->priv; + pegasus->flags &= ~PEGASUS_RUNNING; + pegasus_stop_net( pegasus ); + netif_stop_queue(net); - if ( pegasus->ctrl_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->ctrl_urb); - if ( pegasus->rx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->rx_urb); - if ( pegasus->tx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->tx_urb); - if ( pegasus->intr_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->intr_urb); - - MOD_DEC_USE_COUNT; + usb_unlink_urb(&pegasus->rx_urb); + usb_unlink_urb(&pegasus->tx_urb); + usb_unlink_urb(&pegasus->intr_urb); + pegasus_unlink_ctrl_urbs( pegasus ); return 0; } @@ -558,24 +623,32 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) static void pegasus_set_rx_mode(struct net_device *net) { +#ifndef PEGASUS_USE_WAITQ struct pegasus *pegasus = net->priv; __u8 tmp; +#endif netif_stop_queue(net); if (net->flags & IFF_PROMISC) { - info("%s: Promiscuous mode enabled", net->name); +#ifndef PEGASUS_USE_WAITQ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); - pegasus_set_register(pegasus, EthCtrl2, tmp | 4); + pegasus_set_register(pegasus, EthCtrl2, tmp | 4); +#endif + info("%s: Promiscuous mode enabled", net->name); } else if ((net->mc_count > multicast_filter_limit) || (net->flags & IFF_ALLMULTI)) { +#ifndef PEGASUS_USE_WAITQ pegasus_set_register(pegasus, EthCtrl0, 0xfa); pegasus_set_register(pegasus, EthCtrl2, 0); +#endif info("%s set allmulti", net->name); } else { - info("%s: set Rx mode", net->name); +#ifndef PEGASUS_USE_WAITQ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); - pegasus_set_register(pegasus, EthCtrl2, tmp & ~4); + pegasus_set_register(pegasus, EthCtrl2, tmp & ~4); +#endif + info("%s: set Rx mode", net->name); } netif_wake_queue(net); @@ -629,27 +702,32 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum) net->get_stats = pegasus_netdev_stats; net->mtu = PEGASUS_MTU; + init_MUTEX( &pegasus-> ctrl_sem ); + init_waitqueue_head( &pegasus->ctrl_wait ); + pegasus->usb = dev; pegasus->net = net; - pegasus->pegasus_lock = SPIN_LOCK_UNLOCKED; - pegasus->ctrl_lock = SPIN_LOCK_UNLOCKED; - - FILL_BULK_URB(&pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1), - pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus_read_bulk, - pegasus); - FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2), - pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk, - pegasus); - FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3), - pegasus->intr_buff, 8, pegasus_irq, pegasus, 500); + + FILL_BULK_URB( &pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1), + pegasus->rx_buff, PEGASUS_MAX_MTU, + pegasus_read_bulk_callback, pegasus ); + FILL_BULK_URB( &pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2), + pegasus->tx_buff, PEGASUS_MAX_MTU, + pegasus_write_bulk_callback, pegasus ); + FILL_INT_URB( &pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3), + pegasus->intr_buff, 8, pegasus_irq_callback, + pegasus, 128 ); if (pegasus_reset_mac(pegasus)) { err("can't reset MAC"); kfree(pegasus); + pegasus = NULL; return NULL; } - printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name); + info( "%s: %s\n", net->name, usb_dev_id[dev_indx].name ); + + MOD_INC_USE_COUNT; return pegasus; } @@ -664,21 +742,18 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr) return; } - if (pegasus->net->flags & IFF_UP) - dev_close(pegasus->net); - + pegasus->flags &= ~PEGASUS_RUNNING; unregister_netdev(pegasus->net); - - if ( pegasus->ctrl_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->ctrl_urb); - if ( pegasus->rx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->rx_urb); - if ( pegasus->tx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->tx_urb); - if ( pegasus->intr_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->intr_urb); + + usb_unlink_urb(&pegasus->rx_urb); + usb_unlink_urb(&pegasus->tx_urb); + usb_unlink_urb(&pegasus->intr_urb); + pegasus_unlink_ctrl_urbs( pegasus ); kfree(pegasus); + pegasus = NULL; + + MOD_DEC_USE_COUNT; } @@ -690,7 +765,7 @@ static struct usb_driver pegasus_driver = { int __init pegasus_init(void) { - printk( version ); + info( "%s", version ); return usb_register(&pegasus_driver); } diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 96fa971d8..bbbc05f33 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -1,10 +1,10 @@ /* - * printer.c Version 0.5 + * printer.c Version 0.6 * * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com> * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> - * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2000 Randy Dunlap <randy.dunlap@intel.com> + * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> * * USB Printer Device Class driver for USB printers and printer cables * @@ -16,6 +16,7 @@ * v0.3 - cleaner again, waitqueue fixes * v0.4 - fixes in unidirectional mode * v0.5 - add DEVICE_ID string support + * v0.6 - never time out */ /* @@ -71,7 +72,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 -#define USBLP_WRITE_TIMEOUT (60*60*HZ) /* 60 minutes */ +#define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */ struct usblp { struct usb_device *dev; /* USB device */ @@ -83,10 +84,10 @@ struct usblp { unsigned char used; /* True if open */ unsigned char bidir; /* interface is bidirectional */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ - /* first 2 bytes are (big-endian) length */ + /* first 2 bytes are (big-endian) length */ }; -static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ }; +static struct usblp *usblp_table[USBLP_MINORS]; /* * Functions for usblp control messages. @@ -121,7 +122,8 @@ static void usblp_bulk(struct urb *urb) return; if (urb->status) - warn("nonzero read/write bulk status received: %d", urb->status); + warn("usblp%d: nonzero read/write bulk status received: %d", + usblp->minor, urb->status); wake_up_interruptible(&usblp->wait); } @@ -130,29 +132,27 @@ static void usblp_bulk(struct urb *urb) * Get and print printer errors. */ -static int usblp_check_status(struct usblp *usblp) +static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; + +static int usblp_check_status(struct usblp *usblp, int err) { - unsigned char status; + unsigned char status, newerr = 0; if (usblp_read_status(usblp, &status)) { - err("failed reading usblp status"); - return -EIO; + err("usblp%d: failed reading printer status", usblp->minor); + return 0; } if (~status & LP_PERRORP) { - if (status & LP_POUTPA) { - info("usblp%d: out of paper", usblp->minor); - return -ENOSPC; - } - if (~status & LP_PSELECD) { - info("usblp%d: off-line", usblp->minor); - return -EIO; - } - info("usblp%d: on fire", usblp->minor); - return -EIO; + newerr = 3; + if (status & LP_POUTPA) newerr = 1; + if (~status & LP_PSELECD) newerr = 2; } - return 0; + if (newerr != err) + info("usblp%d: %s", usblp->minor, usblp_messages[newerr]); + + return newerr; } /* @@ -179,8 +179,10 @@ static int usblp_open(struct inode *inode, struct file *file) if (usblp->used) goto out; - if ((retval = usblp_check_status(usblp))) + if ((retval = usblp_check_status(usblp, 0))) { + retval = retval > 1 ? -EIO : -ENOSPC; goto out; + } usblp->used = 1; file->private_data = usblp; @@ -228,27 +230,30 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int length; struct usblp *usblp = file->private_data; + int length; if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ)) return -EINVAL; switch (_IOC_NR(cmd)) { - case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ -#if 0 - dbg ("usblp_ioctl GET_DEVICE_ID: actlen=%d, user size=%d, string='%s'", - length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); -#endif - if (length > _IOC_SIZE(cmd)) - length = _IOC_SIZE(cmd); /* truncate */ - if (copy_to_user ((unsigned char *)arg, usblp->device_id_string, (unsigned long) length)) - return -EFAULT; - break; - default: - return -EINVAL; + case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ + + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ + + dbg ("usblp_ioctl GET_DEVICE_ID actlen: %d, size: %d, string: '%s'", + length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); + + if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ + + if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length)) + return -EFAULT; + + break; + + default: + return -EINVAL; } return 0; @@ -257,7 +262,7 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - int retval, timeout, writecount = 0; + int timeout, err = 0, writecount = 0; while (writecount < count) { @@ -276,28 +281,17 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, } } - if (usblp->writeurb.status == -EINPROGRESS) { - usb_unlink_urb(&usblp->writeurb); - err("usblp%d: timed out", usblp->minor); - return -EIO; - } - if (!usblp->dev) return -ENODEV; - if (!usblp->writeurb.status) { - writecount += usblp->writeurb.transfer_buffer_length; - usblp->writeurb.transfer_buffer_length = 0; - } else { - if (!(retval = usblp_check_status(usblp))) { - err("usblp%d: error %d writing to printer (retval=%d)", - usblp->minor, usblp->writeurb.status, retval); - return -EIO; - } - - return retval; + if (usblp->writeurb.status) { + err = usblp_check_status(usblp, err); + continue; } + writecount += usblp->writeurb.transfer_buffer_length; + usblp->writeurb.transfer_buffer_length = 0; + if (writecount == count) continue; @@ -368,14 +362,14 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum) interface = &dev->actconfig->interface[ifnum].altsetting[i]; if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 || - (interface->bInterfaceProtocol != 1 && interface->bInterfaceProtocol != 2) || - (interface->bInterfaceProtocol > interface->bNumEndpoints)) + interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 || + (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2)) continue; if (alts == -1) alts = i; - if (!bidir && interface->bInterfaceProtocol == 2) { + if (!bidir && interface->bInterfaceProtocol > 1) { bidir = 1; alts = i; } diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index c5c403b2b..f168b1bfc 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -14,6 +14,58 @@ * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) * +* (8/8/2000) pberger and borchers +* -- Fixed close so that +* - it can timeout while waiting for transmit idle, if needed; +* - it ignores interrupts when flushing the port, turning +* of modem signalling, and so on; +* - it waits for the flush to really complete before returning. +* -- Read_bulk_callback and write_bulk_callback check for a closed +* port before using the tty struct or writing to the port. +* -- The two changes above fix the oops caused by interrupted closes. +* -- Added interruptible args to write_oob_command and set_modem_signals +* and added a timeout arg to transmit_idle; needed for fixes to +* close. +* -- Added code for rx_throttle and rx_unthrottle so that input flow +* control works. +* -- Added code to set overrun, parity, framing, and break errors +* (untested). +* -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length +* bulk writes are done. These hung the Digi USB device. The +* 0 length bulk writes were a new feature of usb-uhci added in +* the 2.4.0-test6 kernels. +* -- Fixed mod inc race in open; do mod inc before sleeping to wait +* for a close to finish. +* +* (7/31/2000) pberger +* -- Fixed bugs with hardware handshaking: +* - Added code to set/clear tty->hw_stopped in digi_read_oob_callback() +* and digi_set_termios() +* -- Added code in digi_set_termios() to +* - add conditional in code handling transition from B0 to only +* set RTS if RTS/CTS flow control is either not in use or if +* the port is not currently throttled. +* - handle turning off CRTSCTS. +* +* (7/30/2000) borchers +* -- Added support for more than one Digi USB device by moving +* globals to a private structure in the pointed to from the +* usb_serial structure. +* -- Moved the modem change and transmit idle wait queues into +* the port private structure, so each port has its own queue +* rather than sharing global queues. +* -- Added support for break signals. +* +* (7/25/2000) pberger +* -- Added USB-2 support. Note: the USB-2 supports 3 devices: two +* serial and a parallel port. The parallel port is implemented +* as a serial-to-parallel converter. That is, the driver actually +* presents all three USB-2 interfaces as serial ports, but the third +* one physically connects to a parallel device. Thus, for example, +* one could plug a parallel printer into the USB-2's third port, +* but from the kernel's (and userland's) point of view what's +* actually out there is a serial device. +* * (7/15/2000) borchers * -- Fixed race in open when a close is in progress. * -- Keep count of opens and dec the module use count for each @@ -24,8 +76,8 @@ * callbacks, and no longer restart read chains if there is * a status error or a sanity error. This fixed the seg * faults and other errors we used to get on disconnect. -* -- Port->active is once again a flag, not a count, as it was -* intended by usb-serial. Since it was only a char it would +* -- Port->active is once again a flag as usb-serial intended it +* to be, not a count. Since it was only a char it would * have been limited to 256 simultaneous opens. Now the open * count is kept in the port private structure in dp_open_count. * -- Added code for modularization of the digi_acceleport driver. @@ -51,7 +103,7 @@ * * (6/4/2000) pberger and borchers * -- Replaced separate calls to spin_unlock_irqrestore and -* interruptible_sleep_on_interruptible with a new function +* interruptible_sleep_on_timeout with a new function * cond_wait_interruptible_timeout_irqrestore. This eliminates * the race condition where the wake up could happen after * the unlock and before the sleep. @@ -157,7 +209,7 @@ * - Following Documentation/DocBook/kernel-locking.pdf no spin locks * are held when calling copy_to/from_user or printk. * -* $Id: digi_acceleport.c,v 1.5 2000/07/18 04:52:43 root Exp $ +* $Id: digi_acceleport.c,v 1.80 2000/08/09 06:36:18 root Exp $ */ #include <linux/config.h> @@ -188,9 +240,13 @@ /* Defines */ -/* port buffer length -- must be <= transfer buffer length - 2 */ +/* port output buffer length -- must be <= transfer buffer length - 2 */ /* so we can be sure to send the full buffer in one urb */ -#define DIGI_PORT_BUF_LEN 8 +#define DIGI_OUT_BUF_SIZE 8 + +/* port input buffer length -- must be >= transfer buffer length - 3 */ +/* so we can be sure to hold at least one full buffer from one urb */ +#define DIGI_IN_BUF_SIZE 64 /* retry timeout while sleeping */ #define DIGI_RETRY_TIMEOUT (HZ/10) @@ -205,7 +261,8 @@ /* ids */ #define DIGI_VENDOR_ID 0x05c5 -#define DIGI_ID 0x0004 +#define DIGI_2_ID 0x0002 /* USB-2 */ +#define DIGI_4_ID 0x0004 /* USB-4 */ /* commands * "INB": can be used on the in-band endpoint @@ -335,29 +392,45 @@ /* Structures */ -typedef struct digi_private { - int dp_port_num; +typedef struct digi_serial { + spinlock_t ds_serial_lock; + struct usb_serial_port *ds_oob_port; /* out-of-band port */ + int ds_oob_port_num; /* index of out-of-band port */ + int ds_device_started; +} digi_serial_t; + +typedef struct digi_port { spinlock_t dp_port_lock; - int dp_buf_len; - unsigned char dp_buf[DIGI_PORT_BUF_LEN]; + int dp_port_num; + int dp_out_buf_len; + unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE]; + int dp_in_buf_len; + unsigned char dp_in_buf[DIGI_IN_BUF_SIZE]; + unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE]; unsigned int dp_modem_signals; + wait_queue_head_t dp_modem_change_wait; int dp_open_count; /* inc on open, dec on close */ int dp_transmit_idle; + wait_queue_head_t dp_transmit_idle_wait; + int dp_throttled; + int dp_throttle_restart; + wait_queue_head_t dp_flush_wait; int dp_in_close; /* close in progress */ wait_queue_head_t dp_close_wait; /* wait queue for close */ struct tq_struct dp_wakeup_task; -} digi_private_t; +} digi_port_t; /* Local Function Declarations */ static void digi_wakeup_write( struct usb_serial_port *port ); static void digi_wakeup_write_lock( struct usb_serial_port *port ); -static int digi_write_oob_command( unsigned char *buf, int count ); +static int digi_write_oob_command( struct usb_serial_port *port, + unsigned char *buf, int count, int interruptible ); static int digi_write_inb_command( struct usb_serial_port *port, - unsigned char *buf, int count ) __attribute__((unused)); + unsigned char *buf, int count, unsigned long timeout ); static int digi_set_modem_signals( struct usb_serial_port *port, - unsigned int modem_signals ); + unsigned int modem_signals, int interruptible ); static int digi_transmit_idle( struct usb_serial_port *port, unsigned long timeout ); static void digi_rx_throttle (struct usb_serial_port *port); @@ -386,25 +459,40 @@ static int digi_read_oob_callback( struct urb *urb ); /* device info needed for the Digi serial converter */ static u16 digi_vendor_id = DIGI_VENDOR_ID; -static u16 digi_product_id = DIGI_ID; - -/* out of band port */ -static int oob_port_num; /* index of out-of-band port */ -static struct usb_serial_port *oob_port; /* out-of-band port */ -static int device_startup = 0; - -spinlock_t startup_lock; /* used by startup_device */ - -static wait_queue_head_t modem_change_wait; -static wait_queue_head_t transmit_idle_wait; +static u16 digi_product_2_id = DIGI_2_ID; /* USB 2 */ +static u16 digi_product_4_id = DIGI_4_ID; /* USB 4 */ +static struct usb_serial_device_type digi_acceleport_2_device = { + name: "Digi USB", + idVendor: &digi_vendor_id, + idProduct: &digi_product_2_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 0, + num_bulk_in: 4, + num_bulk_out: 4, + num_ports: 3, + open: digi_open, + close: digi_close, + write: digi_write, + write_room: digi_write_room, + write_bulk_callback: digi_write_bulk_callback, + read_bulk_callback: digi_read_bulk_callback, + chars_in_buffer: digi_chars_in_buffer, + throttle: digi_rx_throttle, + unthrottle: digi_rx_unthrottle, + ioctl: digi_ioctl, + set_termios: digi_set_termios, + break_ctl: digi_break_ctl, + startup: digi_startup, + shutdown: digi_shutdown, +}; -/* Globals */ - -struct usb_serial_device_type digi_acceleport_device = { +static struct usb_serial_device_type digi_acceleport_4_device = { name: "Digi USB", idVendor: &digi_vendor_id, - idProduct: &digi_product_id, + idProduct: &digi_product_4_id, needs_interrupt_in: DONT_CARE, needs_bulk_in: MUST_HAVE, needs_bulk_out: MUST_HAVE, @@ -479,7 +567,7 @@ static void digi_wakeup_write_lock( struct usb_serial_port *port ) { unsigned long flags; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -515,20 +603,23 @@ static void digi_wakeup_write( struct usb_serial_port *port ) * Write commands on the out of band port. Commands are 4 * bytes each, multiple commands can be sent at once, and * no command will be split across USB packets. Returns 0 -* if successful, -EINTR if interrupted while sleeping, or -* a negative error returned by usb_submit_urb. +* if successful, -EINTR if interrupted while sleeping and +* the interruptible flag is true, or a negative error +* returned by usb_submit_urb. */ -static int digi_write_oob_command( unsigned char *buf, int count ) +static int digi_write_oob_command( struct usb_serial_port *port, + unsigned char *buf, int count, int interruptible ) { int ret = 0; int len; - digi_private_t *oob_priv = (digi_private_t *)(oob_port->private); + struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port; + digi_port_t *oob_priv = (digi_port_t *)oob_port->private; unsigned long flags = 0; -dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count ); +dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count ); spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); @@ -538,7 +629,7 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count ); cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags ); - if( signal_pending(current) ) { + if( interruptible && signal_pending(current) ) { return( -EINTR ); } spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); @@ -562,8 +653,8 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count ); spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); if( ret ) { - dbg( "digi_write_oob_command: usb_submit_urb failed, ret=%d", - ret ); + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d", + ret ); } return( ret ); @@ -576,17 +667,20 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count ); * * Write commands on the given port. Commands are 4 * bytes each, multiple commands can be sent at once, and -* no command will be split across USB packets. Returns 0 -* if successful, or a negative error returned by digi_write. +* no command will be split across USB packets. If timeout +* is non-zero, write in band command will return after +* waiting unsuccessfully for the URB status to clear for +* timeout ticks. Returns 0 if successful, or a negative +* error returned by digi_write. */ static int digi_write_inb_command( struct usb_serial_port *port, - unsigned char *buf, int count ) + unsigned char *buf, int count, unsigned long timeout ) { int ret = 0; int len; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; @@ -594,11 +688,17 @@ static int digi_write_inb_command( struct usb_serial_port *port, dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num, count ); + if( timeout ) + timeout += jiffies; + else + timeout = ULONG_MAX; + spin_lock_irqsave( &priv->dp_port_lock, flags ); - while( count > 0 ) { + while( count > 0 && ret == 0 ) { - while( port->write_urb->status == -EINPROGRESS ) { + while( port->write_urb->status == -EINPROGRESS + && jiffies < timeout ) { cond_wait_interruptible_timeout_irqrestore( &port->write_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); @@ -611,25 +711,26 @@ count ); /* len must be a multiple of 4 and small enough to */ /* guarantee the write will send buffered data first, */ /* so commands are in order with data and not split */ - len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len ); + len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len ); if( len > 4 ) len &= ~3; /* write any buffered data first */ - if( priv->dp_buf_len > 0 ) { + if( priv->dp_out_buf_len > 0 ) { data[0] = DIGI_CMD_SEND_DATA; - data[1] = priv->dp_buf_len; - memcpy( data+2, priv->dp_buf, priv->dp_buf_len ); - memcpy( data+2+priv->dp_buf_len, buf, len ); + data[1] = priv->dp_out_buf_len; + memcpy( data+2, priv->dp_out_buf, + priv->dp_out_buf_len ); + memcpy( data+2+priv->dp_out_buf_len, buf, len ); port->write_urb->transfer_buffer_length - = priv->dp_buf_len+2+len; + = priv->dp_out_buf_len+2+len; } else { memcpy( data, buf, len ); port->write_urb->transfer_buffer_length = len; } if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; count -= len; buf += len; } @@ -639,8 +740,8 @@ count ); spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( ret ) { - dbg( "digi_write_inb_command: usb_submit_urb failed, ret=%d", - ret ); + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, priv->dp_port_num ); } return( ret ); @@ -659,13 +760,14 @@ count ); */ static int digi_set_modem_signals( struct usb_serial_port *port, - unsigned int modem_signals ) + unsigned int modem_signals, int interruptible ) { int ret; + digi_port_t *port_priv = (digi_port_t *)port->private; + struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port; + digi_port_t *oob_priv = (digi_port_t *)oob_port->private; unsigned char *data = oob_port->write_urb->transfer_buffer; - digi_private_t *port_priv = (digi_private_t *)(port->private); - digi_private_t *oob_priv = (digi_private_t *)(oob_port->private); unsigned long flags = 0; @@ -680,7 +782,7 @@ port_priv->dp_port_num, modem_signals ); cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags ); - if( signal_pending(current) ) { + if( interruptible && signal_pending(current) ) { return( -EINTR ); } spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); @@ -711,7 +813,7 @@ port_priv->dp_port_num, modem_signals ); spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); if( ret ) { - dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d", + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d", ret ); } @@ -738,7 +840,7 @@ static int digi_transmit_idle( struct usb_serial_port *port, int ret; unsigned char buf[2]; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned long flags = 0; @@ -749,16 +851,16 @@ static int digi_transmit_idle( struct usb_serial_port *port, buf[0] = DIGI_CMD_TRANSMIT_IDLE; buf[1] = 0; - if( (ret=digi_write_inb_command( port, buf, 2 )) != 0 ) - return( ret ); - timeout += jiffies; + if( (ret=digi_write_inb_command( port, buf, 2, timeout-jiffies )) != 0 ) + return( ret ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); while( jiffies < timeout && !priv->dp_transmit_idle ) { cond_wait_interruptible_timeout_irqrestore( - &transmit_idle_wait, DIGI_RETRY_TIMEOUT, + &priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); if( signal_pending(current) ) { return( -EINTR ); @@ -777,21 +879,18 @@ static int digi_transmit_idle( struct usb_serial_port *port, static void digi_rx_throttle( struct usb_serial_port *port ) { -#ifdef DEBUG - digi_private_t *priv = (digi_private_t *)(port->private); -#endif + unsigned long flags; + digi_port_t *priv = (digi_port_t *)(port->private); dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num ); - /* stop receiving characters. We just turn off the URB request, and - let chars pile up in the device. If we're doing hardware - flowcontrol, the device will signal the other end when its buffer - fills up. If we're doing XON/XOFF, this would be a good time to - send an XOFF, although it might make sense to foist that off - upon the device too. */ - - // usb_unlink_urb(port->interrupt_in_urb); + /* stop receiving characters by not resubmitting the read urb */ + spin_lock_irqsave( &priv->dp_port_lock, flags ); + priv->dp_throttled = 1; + priv->dp_throttle_restart = 0; + priv->dp_in_buf_len = 0; + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); } @@ -799,16 +898,43 @@ dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num ); static void digi_rx_unthrottle( struct usb_serial_port *port ) { -#ifdef DEBUG - digi_private_t *priv = (digi_private_t *)(port->private); -#endif + int ret = 0; + int len; + unsigned long flags; + digi_port_t *priv = (digi_port_t *)(port->private); + struct tty_struct *tty = port->tty; dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); - /* just restart the receive interrupt URB */ - //if (usb_submit_urb(port->interrupt_in_urb)) - // dbg( "digi_rx_unthrottle: usb_submit_urb failed" ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); + + /* send any buffered chars from throttle time on to tty subsystem */ + len = MIN( priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count ); + if( len > 0 ) { + memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len ); + memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len ); + tty->flip.char_buf_ptr += len; + tty->flip.flag_buf_ptr += len; + tty->flip.count += len; + tty_flip_buffer_push( tty ); + } + + /* restart read chain */ + if( priv->dp_throttle_restart ) + ret = usb_submit_urb( port->read_urb ); + + /* turn throttle off */ + priv->dp_throttled = 0; + priv->dp_in_buf_len = 0; + priv->dp_throttle_restart = 0; + + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + + if( ret ) { + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, priv->dp_port_num ); + } } @@ -817,12 +943,13 @@ static void digi_set_termios( struct usb_serial_port *port, struct termios *old_termios ) { - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned int iflag = port->tty->termios->c_iflag; unsigned int cflag = port->tty->termios->c_cflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int old_cflag = old_termios->c_cflag; unsigned char buf[32]; + unsigned int modem_signals; int arg,ret; int i = 0; @@ -837,13 +964,18 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol /* reassert DTR and (maybe) RTS on transition from B0 */ if( (old_cflag&CBAUD) == B0 ) { /* don't set RTS if using hardware flow control */ - /* and throttling input -- not implemented yet */ - digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS ); + /* and throttling input */ + modem_signals = TIOCM_DTR; + if( !(port->tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &port->tty->flags) ) { + modem_signals |= TIOCM_RTS; + } + digi_set_modem_signals( port, modem_signals, 1 ); } switch( (cflag&CBAUD) ) { /* drop DTR and RTS on transition to B0 */ - case B0: digi_set_modem_signals( port, 0 ); break; + case B0: digi_set_modem_signals( port, 0, 1 ); break; case B50: arg = DIGI_BAUD_50; break; case B75: arg = DIGI_BAUD_75; break; case B110: arg = DIGI_BAUD_110; break; @@ -947,10 +1079,20 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol else arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF; - if( (cflag&CRTSCTS) ) + if( (cflag&CRTSCTS) ) { + arg |= DIGI_INPUT_FLOW_CONTROL_RTS; - else + + /* On USB-4 it is necessary to assert RTS prior */ + /* to selecting RTS input flow control. */ + buf[i++] = DIGI_CMD_SET_RTS_SIGNAL; + buf[i++] = priv->dp_port_num; + buf[i++] = DIGI_RTS_ACTIVE; + buf[i++] = 0; + + } else { arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS; + } buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; buf[i++] = priv->dp_port_num; @@ -960,8 +1102,8 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol } /* set output flow control */ - /*if( (iflag&IXON) != (old_iflag&IXON) - || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) )*/ { + if( (iflag&IXON) != (old_iflag&IXON) + || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) { arg = 0; @@ -970,10 +1112,12 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol else arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; - if( (cflag&CRTSCTS) ) + if( (cflag&CRTSCTS) ) { arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS; - else + } else { arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS; + port->tty->hw_stopped = 0; + } buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; buf[i++] = priv->dp_port_num; @@ -997,7 +1141,7 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol } - if( (ret=digi_write_oob_command( buf, i )) != 0 ) + if( (ret=digi_write_oob_command( port, buf, i, 1 )) != 0 ) dbg( "digi_set_termios: write oob failed, ret=%d", ret ); } @@ -1006,12 +1150,15 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol static void digi_break_ctl( struct usb_serial_port *port, int break_state ) { -#ifdef DEBUG - digi_private_t *priv = (digi_private_t *)(port->private); -#endif + unsigned char buf[4]; -dbg( "digi_break_ctl: TOP: port=%d", priv->dp_port_num ); + buf[0] = DIGI_CMD_BREAK_CONTROL; + buf[1] = 2; /* length */ + buf[2] = break_state ? 1 : 0; + buf[3] = 0; /* pad */ + + digi_write_inb_command( port, buf, 4, 0 ); } @@ -1020,7 +1167,7 @@ static int digi_ioctl( struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg ) { - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned int val; unsigned long flags = 0; @@ -1048,7 +1195,7 @@ dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd ); else if( cmd == TIOCMBIC ) val = priv->dp_modem_signals & ~val; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); - return( digi_set_modem_signals( port, val ) ); + return( digi_set_modem_signals( port, val, 1 ) ); case TIOCMIWAIT: /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ @@ -1072,7 +1219,7 @@ static int digi_write( struct usb_serial_port *port, int from_user, { int ret,data_len,new_len; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned char *data = port->write_urb->transfer_buffer; unsigned char user_buf[64]; /* 64 bytes is max USB bulk packet */ unsigned long flags = 0; @@ -1098,9 +1245,10 @@ priv->dp_port_num, count, from_user, in_interrupt() ); /* buffer data if count is 1 (probably put_char) if possible */ if( count == 1 ) { new_len = MIN( count, - DIGI_PORT_BUF_LEN-priv->dp_buf_len ); - memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len ); - priv->dp_buf_len += new_len; + DIGI_OUT_BUF_SIZE-priv->dp_out_buf_len ); + memcpy( priv->dp_out_buf+priv->dp_out_buf_len, buf, + new_len ); + priv->dp_out_buf_len += new_len; } else { new_len = 0; } @@ -1113,8 +1261,8 @@ priv->dp_port_num, count, from_user, in_interrupt() ); /* allow space for any buffered data and for new data, up to */ /* transfer buffer size - 2 (for command and length bytes) */ - new_len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len ); - data_len = new_len + priv->dp_buf_len; + new_len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len ); + data_len = new_len + priv->dp_out_buf_len; if( data_len == 0 ) { spin_unlock_irqrestore( &priv->dp_port_lock, flags ); @@ -1127,22 +1275,24 @@ priv->dp_port_num, count, from_user, in_interrupt() ); *data++ = data_len; /* copy in buffered data first */ - memcpy( data, priv->dp_buf, priv->dp_buf_len ); - data += priv->dp_buf_len; + memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len ); + data += priv->dp_out_buf_len; /* copy in new data */ memcpy( data, from_user ? user_buf : buf, new_len ); if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { ret = new_len; - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; } /* return length of new data written, or error */ spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( ret < 0 ) { - dbg( "digi_write: usb_submit_urb failed, ret=%d", ret ); + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, priv->dp_port_num ); } + dbg( "digi_write: returning %d", ret ); return( ret ); @@ -1154,21 +1304,27 @@ static void digi_write_bulk_callback( struct urb *urb ) struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial; - digi_private_t *priv; + digi_port_t *priv; int ret = 0; -dbg( "digi_write_bulk_callback: TOP" ); +dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status ); - /* port sanity check */ - if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) { + /* port and serial sanity check */ + if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) { err( __FUNCTION__ ": port or port->private is NULL, status=%d", urb->status ); return; } + serial = port->serial; + if( serial == NULL || serial->private == NULL ) { + err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status ); + return; + } /* handle oob callback */ - if( priv->dp_port_num == oob_port_num ) { + if( priv->dp_port_num + == ((digi_serial_t *)(serial->private))->ds_oob_port_num ) { dbg( "digi_write_bulk_callback: oob callback" ); spin_lock( &priv->dp_port_lock ); wake_up_interruptible( &port->write_wait ); @@ -1176,29 +1332,29 @@ dbg( "digi_write_bulk_callback: TOP" ); return; } - /* sanity checks */ - if( port_paranoia_check( port, "digi_write_bulk_callback" ) ) - return; - serial = port->serial; - if( serial_paranoia_check( serial, "digi_write_bulk_callback" ) ) + /* further sanity checks */ + if( port_paranoia_check( port, __FUNCTION__ ) + || serial_paranoia_check( serial, __FUNCTION__ ) ) return; - /* try to send any buffered data on this port */ + /* try to send any buffered data on this port, if it is open */ spin_lock( &priv->dp_port_lock ); - if( port->write_urb->status != -EINPROGRESS && priv->dp_buf_len > 0 ) { + if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS + && priv->dp_out_buf_len > 0 ) { *((unsigned char *)(port->write_urb->transfer_buffer)) = (unsigned char)DIGI_CMD_SEND_DATA; *((unsigned char *)(port->write_urb->transfer_buffer)+1) - = (unsigned char)priv->dp_buf_len; + = (unsigned char)priv->dp_out_buf_len; - port->write_urb->transfer_buffer_length = priv->dp_buf_len+2; + port->write_urb->transfer_buffer_length + = priv->dp_out_buf_len+2; - memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf, - priv->dp_buf_len ); + memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf, + priv->dp_out_buf_len ); if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; } } @@ -1224,7 +1380,7 @@ static int digi_write_room( struct usb_serial_port *port ) { int room; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned long flags = 0; @@ -1233,7 +1389,7 @@ static int digi_write_room( struct usb_serial_port *port ) if( port->write_urb->status == -EINPROGRESS ) room = 0; else - room = port->bulk_out_size - 2 - priv->dp_buf_len; + room = port->bulk_out_size - 2 - priv->dp_out_buf_len; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); @@ -1246,7 +1402,7 @@ dbg( "digi_write_room: port=%d, room=%d", priv->dp_port_num, room ); static int digi_chars_in_buffer( struct usb_serial_port *port ) { - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); if( port->write_urb->status == -EINPROGRESS ) { @@ -1254,8 +1410,8 @@ dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_ou /* return( port->bulk_out_size - 2 ); */ return( 256 ); } else { -dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_buf_len ); - return( priv->dp_buf_len ); +dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len ); + return( priv->dp_out_buf_len ); } } @@ -1266,7 +1422,7 @@ static int digi_open( struct usb_serial_port *port, struct file *filp ) int ret; unsigned char buf[32]; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); struct termios not_termios; unsigned long flags = 0; @@ -1285,12 +1441,18 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por return( -EAGAIN ); } + /* inc module use count before sleeping to wait for closes */ + ++priv->dp_open_count; + MOD_INC_USE_COUNT; + /* wait for a close in progress to finish */ while( priv->dp_in_close ) { cond_wait_interruptible_timeout_irqrestore( &priv->dp_close_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); if( signal_pending(current) ) { + --priv->dp_open_count; + MOD_DEC_USE_COUNT; return( -EINTR ); } spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -1299,16 +1461,12 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por /* if port is already open, just return */ /* be sure exactly one open proceeds */ if( port->active ) { - ++priv->dp_open_count; - MOD_INC_USE_COUNT; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return( 0 ); } - /* open is certain */ + /* first open, mark port as active */ port->active = 1; - ++priv->dp_open_count; - MOD_INC_USE_COUNT; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); /* read modem signals automatically whenever they change */ @@ -1323,7 +1481,7 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; buf[7] = 0; - if( (ret=digi_write_oob_command( buf, 8 )) != 0 ) + if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 ) dbg( "digi_open: write oob failed, ret=%d", ret ); /* set termios settings */ @@ -1332,7 +1490,7 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por digi_set_termios( port, ¬_termios ); /* set DTR and RTS */ - digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS ); + digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 ); return( 0 ); @@ -1345,7 +1503,7 @@ static void digi_close( struct usb_serial_port *port, struct file *filp ) int ret; unsigned char buf[32]; struct tty_struct *tty = port->tty; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)port->private; unsigned long flags = 0; @@ -1386,7 +1544,7 @@ dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, po } /* drop DTR and RTS */ - digi_set_modem_signals( port, 0 ); + digi_set_modem_signals( port, 0, 0 ); /* disable input flow control */ buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; @@ -1406,29 +1564,24 @@ dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, po buf[10] = DIGI_DISABLE; buf[11] = 0; - /* flush fifos */ - buf[12] = DIGI_CMD_IFLUSH_FIFO; + /* disable receive */ + buf[12] = DIGI_CMD_RECEIVE_ENABLE; buf[13] = priv->dp_port_num; - buf[14] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; + buf[14] = DIGI_DISABLE; buf[15] = 0; - /* disable receive */ - buf[16] = DIGI_CMD_RECEIVE_ENABLE; + /* flush fifos */ + buf[16] = DIGI_CMD_IFLUSH_FIFO; buf[17] = priv->dp_port_num; - buf[18] = DIGI_DISABLE; + buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; buf[19] = 0; - if( (ret=digi_write_oob_command( buf, 20 )) != 0 ) + if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 ) dbg( "digi_close: write oob failed, ret=%d", ret ); /* wait for final commands on oob port to complete */ - while( oob_port->write_urb->status == -EINPROGRESS ) { - interruptible_sleep_on_timeout( &oob_port->write_wait, - DIGI_RETRY_TIMEOUT ); - if( signal_pending(current) ) { - break; - } - } + interruptible_sleep_on_timeout( &priv->dp_flush_wait, + DIGI_CLOSE_TIMEOUT ); /* shutdown any outstanding bulk writes */ usb_unlink_urb (port->write_urb); @@ -1458,23 +1611,31 @@ static int digi_startup_device( struct usb_serial *serial ) { int i,ret = 0; + digi_serial_t *serial_priv = (digi_serial_t *)serial->private; + struct usb_serial_port *port; /* be sure this happens exactly once */ - spin_lock( &startup_lock ); - if( device_startup ) { - spin_unlock( &startup_lock ); + spin_lock( &serial_priv->ds_serial_lock ); + if( serial_priv->ds_device_started ) { + spin_unlock( &serial_priv->ds_serial_lock ); return( 0 ); } - device_startup = 1; - spin_unlock( &startup_lock ); + serial_priv->ds_device_started = 1; + spin_unlock( &serial_priv->ds_serial_lock ); /* start reading from each bulk in endpoint for the device */ - for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) { + /* set USB_DISABLE_SPD flag for write bulk urbs */ + for( i=0; i<serial->type->num_ports+1; i++ ) { - if( (ret=usb_submit_urb(serial->port[i].read_urb)) != 0 ) { - dbg( "digi_startup_device: usb_submit_urb failed, port=%d, ret=%d", - i, ret ); + port = &serial->port[i]; + + port->write_urb->transfer_flags |= USB_DISABLE_SPD; + + if( (ret=usb_submit_urb(port->read_urb)) != 0 ) { + err( + __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, i ); break; } @@ -1489,51 +1650,68 @@ static int digi_startup( struct usb_serial *serial ) { int i; - digi_private_t *priv; + digi_port_t *priv; + digi_serial_t *serial_priv; dbg( "digi_startup: TOP" ); - spin_lock_init( &startup_lock ); - init_waitqueue_head( &modem_change_wait ); - init_waitqueue_head( &transmit_idle_wait ); - /* allocate the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ - for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) { + for( i=0; i<serial->type->num_ports+1; i++ ) { serial->port[i].active = 0; - /* allocate private structure */ + /* allocate port private structure */ priv = serial->port[i].private = - (digi_private_t *)kmalloc( sizeof(digi_private_t), + (digi_port_t *)kmalloc( sizeof(digi_port_t), GFP_KERNEL ); - if( priv == (digi_private_t *)0 ) + if( priv == (digi_port_t *)0 ) { + while( --i >= 0 ) + kfree( serial->port[i].private ); return( 1 ); /* error */ + } - /* initialize private structure */ + /* initialize port private structure */ + spin_lock_init( &priv->dp_port_lock ); priv->dp_port_num = i; - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; + priv->dp_in_buf_len = 0; priv->dp_modem_signals = 0; + init_waitqueue_head( &priv->dp_modem_change_wait ); priv->dp_open_count = 0; priv->dp_transmit_idle = 0; + init_waitqueue_head( &priv->dp_transmit_idle_wait ); + priv->dp_throttled = 0; + priv->dp_throttle_restart = 0; + init_waitqueue_head( &priv->dp_flush_wait ); priv->dp_in_close = 0; init_waitqueue_head( &priv->dp_close_wait ); priv->dp_wakeup_task.next = NULL; priv->dp_wakeup_task.sync = 0; priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock; priv->dp_wakeup_task.data = (void *)(&serial->port[i]); - spin_lock_init( &priv->dp_port_lock ); /* initialize write wait queue for this port */ - init_waitqueue_head(&serial->port[i].write_wait); + init_waitqueue_head( &serial->port[i].write_wait ); + + } + /* allocate serial private structure */ + serial_priv = serial->private = + (digi_serial_t *)kmalloc( sizeof(digi_serial_t), + GFP_KERNEL ); + if( serial_priv == (digi_serial_t *)0 ) { + for( i=0; i<serial->type->num_ports+1; i++ ) + kfree( serial->port[i].private ); + return( 1 ); /* error */ } - /* initialize out of band port info */ - oob_port_num = digi_acceleport_device.num_ports; - oob_port = &serial->port[oob_port_num]; - device_startup = 0; + /* initialize serial private structure */ + spin_lock_init( &serial_priv->ds_serial_lock ); + serial_priv->ds_oob_port_num = serial->type->num_ports; + serial_priv->ds_oob_port = &serial->port[serial_priv->ds_oob_port_num]; + serial_priv->ds_device_started = 0; return( 0 ); @@ -1544,22 +1722,20 @@ static void digi_shutdown( struct usb_serial *serial ) { int i; - digi_private_t *priv; + digi_port_t *priv; unsigned long flags; dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() ); /* stop reads and writes on all ports */ - for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) { + for( i=0; i<serial->type->num_ports+1; i++ ) { usb_unlink_urb( serial->port[i].read_urb ); usb_unlink_urb( serial->port[i].write_urb ); } - device_startup = 0; - /* dec module use count */ - for( i=0; i<digi_acceleport_device.num_ports; i++ ) { + for( i=0; i<serial->type->num_ports; i++ ) { priv = serial->port[i].private; spin_lock_irqsave( &priv->dp_port_lock, flags ); while( priv->dp_open_count > 0 ) { @@ -1571,8 +1747,9 @@ dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() ); /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ - for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) + for( i=0; i<serial->type->num_ports+1; i++ ) kfree( serial->port[i].private ); + kfree( serial->private ); } @@ -1581,18 +1758,24 @@ static void digi_read_bulk_callback( struct urb *urb ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - digi_private_t *priv; + digi_port_t *priv; int ret; dbg( "digi_read_bulk_callback: TOP" ); /* port sanity check, do not resubmit if port is not valid */ - if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) { + if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) { err( __FUNCTION__ ": port or port->private is NULL, status=%d", urb->status ); return; } + if( port->serial == NULL + || serial_paranoia_check( port->serial, __FUNCTION__ ) + || port->serial->private == NULL ) { + err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status ); + return; + } /* do not resubmit urb if it has any status error */ if( urb->status ) { @@ -1601,7 +1784,8 @@ dbg( "digi_read_bulk_callback: TOP" ); } /* handle oob or inb callback, do not resubmit if error */ - if( priv->dp_port_num == oob_port_num ) { + if( priv->dp_port_num + == ((digi_serial_t *)(port->serial->private))->ds_oob_port_num ) { if( digi_read_oob_callback( urb ) != 0 ) return; } else { @@ -1623,45 +1807,110 @@ dbg( "digi_read_bulk_callback: TOP" ); * * Digi Read INB Callback handles reads on the in band ports, sending * the data on to the tty subsystem. When called we know port and -* port->private are not NULL. It returns 0 if successful, and -1 if -* the sanity checks failed. +* port->private are not NULL and port->serial has been validated. +* It returns 0 if successful, 1 if successful but the port is +* throttled, and -1 if the sanity checks failed. */ static int digi_read_inb_callback( struct urb *urb ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = port->serial; struct tty_struct *tty = port->tty; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; int status = ((unsigned char *)urb->transfer_buffer)[2]; unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3; - int i; + int flag,throttled; - /* sanity checks */ - if( port_paranoia_check( port, __FUNCTION__ ) - || serial_paranoia_check( serial, __FUNCTION__ ) ) + /* sanity check */ + if( port_paranoia_check( port, __FUNCTION__ ) ) return( -1 ); - /* short packet check */ + /* do not process callbacks on closed ports */ + /* but do continue the read chain */ + if( priv->dp_open_count == 0 ) + return( 0 ); + + /* short/multiple packet check */ if( urb->actual_length != len + 2 ) { - err( __FUNCTION__ ": INCOMPLETE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status ); + err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status ); return( -1 ); } + spin_lock( &priv->dp_port_lock ); + + /* check for throttle; if set, do not resubmit read urb */ + /* indicate the read chain needs to be restarted on unthrottle */ + throttled = priv->dp_throttled; + if( throttled ) + priv->dp_throttle_restart = 1; + /* receive data */ - if( opcode == DIGI_CMD_RECEIVE_DATA && urb->actual_length > 3 ) { - len = MIN( len, urb->actual_length-3 ); - for( i=0; i<len; ++i ) { - tty_insert_flip_char(tty, data[i], 0); - } - tty_flip_buffer_push(tty); + if( opcode == DIGI_CMD_RECEIVE_DATA ) { + + /* get flag from status */ + flag = 0; + + /* overrun is special, not associated with a char */ + if( status & DIGI_OVERRUN_ERROR ) { + tty_insert_flip_char( tty, 0, TTY_OVERRUN ); + } + + /* break takes precedence over parity, */ + /* which takes precedence over framing errors */ + if( status & DIGI_BREAK_ERROR ) { + flag = TTY_BREAK; + } else if( status & DIGI_PARITY_ERROR ) { + flag = TTY_PARITY; + } else if( status & DIGI_FRAMING_ERROR ) { + flag = TTY_FRAME; + } + + /* data length is len-1 (one byte of len is status) */ + --len; + + if( throttled ) { + + len = MIN( len, + DIGI_IN_BUF_SIZE - priv->dp_in_buf_len ); + + if( len > 0 ) { + memcpy( priv->dp_in_buf + priv->dp_in_buf_len, + data, len ); + memset( priv->dp_in_flag_buf + + priv->dp_in_buf_len, flag, len ); + priv->dp_in_buf_len += len; + } + + } else { + + len = MIN( len, TTY_FLIPBUF_SIZE - tty->flip.count ); + + if( len > 0 ) { + memcpy( tty->flip.char_buf_ptr, data, len ); + memset( tty->flip.flag_buf_ptr, flag, len ); + tty->flip.char_buf_ptr += len; + tty->flip.flag_buf_ptr += len; + tty->flip.count += len; + tty_flip_buffer_push( tty ); + } + + } + } - return( 0 ); + spin_unlock( &priv->dp_port_lock ); + + if( opcode == DIGI_CMD_RECEIVE_DISABLE ) { + dbg( __FUNCTION__ ": got RECEIVE_DISABLE" ); + } else if( opcode != DIGI_CMD_RECEIVE_DATA ) { + dbg( __FUNCTION__ ": unknown opcode: %d", opcode ); + } + + return( throttled ? 1 : 0 ); } @@ -1670,8 +1919,9 @@ static int digi_read_inb_callback( struct urb *urb ) * Digi Read OOB Callback * * Digi Read OOB Callback handles reads on the out of band port. -* When called we know port and port->private are not NULL. It -* returns 0 if successful, and -1 if the sanity checks failed. +* When called we know port and port->private are not NULL and +* the port->serial is valid. It returns 0 if successful, and +* -1 if the sanity checks failed. */ static int digi_read_oob_callback( struct urb *urb ) @@ -1679,19 +1929,13 @@ static int digi_read_oob_callback( struct urb *urb ) struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); int opcode, line, status, val; int i; -dbg( "digi_read_oob_callback: len=%d", urb->actual_length ); - - /* sanity check */ - if( serial == NULL ) { - err( __FUNCTION__ ": port->serial is NULL, status=%d, port=%d", - urb->status, priv->dp_port_num ); - return( -1 ); - } +dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num, +urb->actual_length ); /* handle each oob command */ for( i=0; i<urb->actual_length-3; ) { @@ -1701,25 +1945,39 @@ dbg( "digi_read_oob_callback: len=%d", urb->actual_length ); status = ((unsigned char *)urb->transfer_buffer)[i++]; val = ((unsigned char *)urb->transfer_buffer)[i++]; -dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, line, status, val ); +dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", +opcode, line, status, val ); - if( status != 0 ) + if( status != 0 || line >= serial->type->num_ports ) continue; - if( (priv=serial->port[line].private) == NULL ) { - dbg( __FUNCTION__ ": port[%d].private is NULL!", line ); - continue; - } + port = &serial->port[line]; + + if( port_paranoia_check( port, __FUNCTION__ ) + || (priv=port->private) == NULL ) + return( -1 ); if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) { spin_lock( &priv->dp_port_lock ); /* convert from digi flags to termiox flags */ - if( val & DIGI_READ_INPUT_SIGNALS_CTS ) + if( val & DIGI_READ_INPUT_SIGNALS_CTS ) { priv->dp_modem_signals |= TIOCM_CTS; - else + /* port must be open to use tty struct */ + if( priv->dp_open_count + && port->tty->termios->c_cflag & CRTSCTS ) { + port->tty->hw_stopped = 0; + digi_wakeup_write( port ); + } + } else { priv->dp_modem_signals &= ~TIOCM_CTS; + /* port must be open to use tty struct */ + if( priv->dp_open_count + && port->tty->termios->c_cflag & CRTSCTS ) { + port->tty->hw_stopped = 1; + } + } if( val & DIGI_READ_INPUT_SIGNALS_DSR ) priv->dp_modem_signals |= TIOCM_DSR; else @@ -1733,16 +1991,20 @@ dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, li else priv->dp_modem_signals &= ~TIOCM_CD; - wake_up_interruptible( &modem_change_wait ); + wake_up_interruptible( &priv->dp_modem_change_wait ); spin_unlock( &priv->dp_port_lock ); } else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) { spin_lock( &priv->dp_port_lock ); priv->dp_transmit_idle = 1; - wake_up_interruptible( &transmit_idle_wait ); + wake_up_interruptible( &priv->dp_transmit_idle_wait ); spin_unlock( &priv->dp_port_lock ); + } else if( opcode == DIGI_CMD_IFLUSH_FIFO ) { + + wake_up_interruptible( &priv->dp_flush_wait ); + } } @@ -1754,20 +2016,23 @@ dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, li int digi_init (void) { - usb_serial_register (&digi_acceleport_device); + usb_serial_register (&digi_acceleport_2_device); + usb_serial_register (&digi_acceleport_4_device); return 0; } void digi_exit (void) { - usb_serial_deregister (&digi_acceleport_device); + usb_serial_deregister (&digi_acceleport_2_device); + usb_serial_deregister (&digi_acceleport_4_device); } module_init(digi_init); module_exit(digi_exit); + MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>"); MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver"); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 675764ad4..e118e29b8 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -1,8 +1,9 @@ /* * USB Keyspan PDA Converter driver * - * Copyright (C) 1999, 2000 - * Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 1999, 2000 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (c) 1999, 2000 Brian Warner <warner@lothar.com> + * Copyright (c) 2000 Al Borchers <borchers@steinerpoint.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 @@ -11,6 +12,24 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (07/20/2000) borchers + * - keyspan_pda_write no longer sleeps if it is called on interrupt time; + * PPP and the line discipline with stty echo on can call write on + * interrupt time and this would cause an oops if write slept + * - if keyspan_pda_write is in an interrupt, it will not call + * usb_control_msg (which sleeps) to query the room in the device + * buffer, it simply uses the current room value it has + * - if the urb is busy or if it is throttled keyspan_pda_write just + * returns 0, rather than sleeping to wait for this to change; the + * write_chan code in n_tty.c will sleep if needed before calling + * keyspan_pda_write again + * - if the device needs to be unthrottled, write now queues up the + * call to usb_control_msg (which sleeps) to unthrottle the device + * - the wakeups from keyspan_pda_write_bulk_callback are queued rather + * than done directly from the callback to avoid the race in write_chan + * - keyspan_pda_chars_in_buffer also indicates its buffer is full if the + * urb status is -EINPROGRESS, meaning it cannot write at the moment + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -35,6 +54,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/tqueue.h> #ifdef CONFIG_USB_SERIAL_DEBUG #define DEBUG @@ -56,6 +76,8 @@ struct ezusb_hex_record { struct keyspan_pda_private { int tx_room; int tx_throttled; + struct tq_struct wakeup_task; + struct tq_struct unthrottle_task; }; #define KEYSPAN_VENDOR_ID 0x06cd @@ -69,6 +91,45 @@ static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID; +static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) +{ + + struct tty_struct *tty = port->tty; + + /* wake up port processes */ + wake_up_interruptible( &port->write_wait ); + + /* wake up line discipline */ + if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) + && tty->ldisc.write_wakeup ) + (tty->ldisc.write_wakeup)(tty); + + /* wake up other tty processes */ + wake_up_interruptible( &tty->write_wait ); + /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ + +} + +static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) +{ + + dbg(" request_unthrottle"); + /* ask the device to tell us when the tx buffer becomes + sufficiently empty */ + usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + 7, /* request_unthrottle */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_OUT, + 16, /* value: threshold */ + 0, /* index */ + NULL, + 0, + 2*HZ); + +} + + static void keyspan_pda_rx_interrupt (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -113,8 +174,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb) case 2: /* tx unthrottle interrupt */ tty = serial->port[0].tty; priv->tx_throttled = 0; - wake_up(&port->write_wait); /* wake up writer */ - wake_up(&tty->write_wait); /* them too */ + /* queue up a wakeup at scheduler time */ + queue_task( &priv->wakeup_task, &tq_scheduler ); break; default: break; @@ -355,7 +416,6 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, int request_unthrottle = 0; int rc = 0; struct keyspan_pda_private *priv; - DECLARE_WAITQUEUE(wait, current); priv = (struct keyspan_pda_private *)(port->private); /* guess how much room is left in the device's ring buffer, and if we @@ -376,53 +436,22 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, the TX urb is in-flight (wait until it completes) the device is full (wait until it says there is room) */ - while (port->write_urb->status == -EINPROGRESS) { - if (0 /* file->f_flags & O_NONBLOCK */) { - rc = -EAGAIN; - goto err; - } - interruptible_sleep_on(&port->write_wait); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - goto err; - } + if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) { + return( 0 ); } - /* at this point the URB is in our control, nobody else can submit it + /* At this point the URB is in our control, nobody else can submit it again (the only sudden transition was the one from EINPROGRESS to - finished) */ - - /* the next potential block is that our TX process might be throttled. - The transition from throttled->not happens because of an Rx - interrupt, and the wake_up occurs during the same interrupt, so we - have to be careful to avoid a race that would cause us to sleep - forever. */ - - add_wait_queue(&port->write_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - while (priv->tx_throttled) { - /* device can't accomodate any more characters. Sleep until it - can. Woken up by an Rx interrupt message, which clears - tx_throttled first. */ - dbg(" tx_throttled, going to sleep"); - if (signal_pending(current)) { - current->state = TASK_RUNNING; - remove_wait_queue(&port->write_wait, &wait); - dbg(" woke up because of signal"); - rc = -ERESTARTSYS; - goto err; - } - schedule(); - dbg(" woke up"); - } - remove_wait_queue(&port->write_wait, &wait); - set_current_state(TASK_RUNNING); + finished). Also, the tx process is not throttled. So we are + ready to write. */ count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - if (count > priv->tx_room) { + + /* Check if we might overrun the Tx buffer. If so, ask the + device how much room it really has. This is done only on + scheduler time, since usb_control_msg() sleeps. */ + if (count > priv->tx_room && !in_interrupt()) { unsigned char room; - /* Looks like we might overrun the Tx buffer. Ask the device - how much room it really has */ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 6, /* write_room */ @@ -443,19 +472,20 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, } dbg(" roomquery says %d", room); priv->tx_room = room; - if (count > priv->tx_room) { - /* we're about to completely fill the Tx buffer, so - we'll be throttled afterwards. */ - count = priv->tx_room; - request_unthrottle = 1; - } } - priv->tx_room -= count; + if (count > priv->tx_room) { + /* we're about to completely fill the Tx buffer, so + we'll be throttled afterwards. */ + count = priv->tx_room; + request_unthrottle = 1; + } if (count) { /* now transfer data */ if (from_user) { - copy_from_user(port->write_urb->transfer_buffer, buf, count); + if( copy_from_user(port->write_urb->transfer_buffer, + buf, count) ) + return( -EFAULT ); } else { memcpy (port->write_urb->transfer_buffer, buf, count); @@ -463,6 +493,8 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; + priv->tx_room -= count; + if (usb_submit_urb(port->write_urb)) dbg(" usb_submit_urb(write bulk) failed"); } @@ -473,25 +505,11 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, } if (request_unthrottle) { - dbg(" request_unthrottle"); - /* ask the device to tell us when the tx buffer becomes - sufficiently empty */ priv->tx_throttled = 1; /* block writers */ - rc = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - 7, /* request_unthrottle */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_OUT, - 16, /* value: threshold */ - 0, /* index */ - NULL, - 0, - 2*HZ); + queue_task( &priv->unthrottle_task, &tq_scheduler ); } return (count); - err: - return (rc); } @@ -499,7 +517,9 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial; - struct tty_struct *tty; + struct keyspan_pda_private *priv; + + priv = (struct keyspan_pda_private *)(port->private); if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) { return; @@ -510,14 +530,9 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb) return; } - wake_up_interruptible(&port->write_wait); + /* queue up a wakeup at scheduler time */ + queue_task( &priv->wakeup_task, &tq_scheduler ); - tty = port->tty; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); } @@ -541,7 +556,7 @@ static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port) /* when throttled, return at least WAKEUP_CHARS to tell select() (via n_tty.c:normal_poll() ) that we're not writeable. */ - if (priv->tx_throttled) + if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) return 256; return 0; } @@ -644,14 +659,25 @@ static int keyspan_pda_fake_startup (struct usb_serial *serial) static int keyspan_pda_startup (struct usb_serial *serial) { + + struct keyspan_pda_private *priv; + /* allocate the private data structures for all ports. Well, for all one ports. */ - serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private), - GFP_KERNEL); - if (!serial->port[0].private) + priv = serial->port[0].private + = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL); + if (!priv) return (1); /* error */ init_waitqueue_head(&serial->port[0].write_wait); + priv->wakeup_task.next = NULL; + priv->wakeup_task.sync = 0; + priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write; + priv->wakeup_task.data = (void *)(&serial->port[0]); + priv->unthrottle_task.next = NULL; + priv->unthrottle_task.sync = 0; + priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle; + priv->unthrottle_task.data = (void *)(serial); return (0); } diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index fe63007b8..10d57076c 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/08/2000) gkh + * Added open_count to port structure. + * * (07/23/2000) gkh * Added bulk_out_endpointAddress to port structure. * @@ -59,6 +62,7 @@ struct usb_serial_port { wait_queue_head_t write_wait; struct tq_struct tqueue; /* task queue for line discipline waking up */ + int open_count; /* number of times this port has been opened */ void * private; /* data private to the specific port */ }; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 568f2b5cd..bc0ea807a 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -11,6 +11,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/08/2000) gkh + * Fixed endian problem in visor_startup. + * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + * than once. + * * (07/23/2000) gkh * Added pool of write urbs to speed up transfers to the visor. * @@ -71,6 +76,7 @@ static int visor_write (struct usb_serial_port *port, int from_user, const uns static void visor_throttle (struct usb_serial_port *port); static void visor_unthrottle (struct usb_serial_port *port); static int visor_startup (struct usb_serial *serial); +static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); static void visor_write_bulk_callback (struct urb *urb); @@ -94,6 +100,7 @@ struct usb_serial_device_type handspring_device = { throttle: visor_throttle, unthrottle: visor_unthrottle, startup: visor_startup, + shutdown: visor_shutdown, ioctl: visor_ioctl, set_termios: visor_set_termios, write: visor_write, @@ -117,13 +124,18 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) return -EINVAL; } - port->active = 1; - - /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; - return (0); + /*Start reading from the device*/ + if (usb_submit_urb(port->read_urb)) + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + } + + return 0; } @@ -134,19 +146,24 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) dbg(__FUNCTION__ " - port %d", port->number); - if (!transfer_buffer) { - err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); - } else { - /* send a shutdown message to the device */ - usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, - 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); - kfree (transfer_buffer); - } + --port->open_count; + MOD_DEC_USE_COUNT; + + if (port->open_count <= 0) { + if (!transfer_buffer) { + err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); + } else { + /* send a shutdown message to the device */ + usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, + 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); + kfree (transfer_buffer); + } - /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - port->active = 0; + /* shutdown our bulk read */ + usb_unlink_urb (port->read_urb); + port->active = 0; + port->open_count = 0; + } } @@ -282,6 +299,8 @@ static int visor_startup (struct usb_serial *serial) } else { struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer; char *string; + + le16_to_cpus(&connection_info->num_ports); info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports); for (i = 0; i < connection_info->num_ports; ++i) { switch (connection_info->connections[i].port_function_id) { @@ -322,6 +341,21 @@ static int visor_startup (struct usb_serial *serial) } +static void visor_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + visor_close (&serial->port[i], NULL); + } + } +} + + static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) { dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd); diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index 7da59f78e..e7761863e 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile @@ -5,6 +5,7 @@ O_TARGET := usb-storage.o M_OBJS := usb-storage.o O_OBJS := scsiglue.o protocol.o transport.o usb.o +MOD_LIST_NAME := USB_STORAGE_MODULES CFLAGS_scsiglue.o:= -I../../scsi/ CFLAGS_protocol.o:= -I../../scsi/ @@ -13,6 +14,7 @@ CFLAGS_debug.o:= -I../../scsi/ CFLAGS_usb.o:= -I../../scsi/ CFLAGS_shuttle_usbat.o:= -I../../scsi/ CFLAGS_sddr09.o:= -I../../scsi/ +CFLAGS_dpcm.o:= -I../../scsi/ ifeq ($(CONFIG_USB_STORAGE_DEBUG),y) O_OBJS += debug.o @@ -37,5 +39,9 @@ endif ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y) O_OBJS += shuttle_cf.o endif + +ifeq ($(CONFIG_USB_STORAGE_DPCM),y) + O_OBJS += dpcm.o +endif include $(TOPDIR)/Rules.make diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c new file mode 100644 index 000000000..8b7195bfc --- /dev/null +++ b/drivers/usb/storage/dpcm.c @@ -0,0 +1,83 @@ +/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader + * + * $Id: dpcm.c,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * + * DPCM driver v0.1: + * + * First release + * + * Current development and maintainance by: + * (c) 2000 Brian Webb (webbb@earthlink.net) + * + * This device contains both a CompactFlash card reader, which + * usest the Control/Bulk w/o Interrupt protocol and + * a SmartMedia card reader that uses the same protocol + * as the SDDR09. + * + * 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; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> +#include "transport.h" +#include "protocol.h" +#include "usb.h" +#include "debug.h" +#include "dpcm.h" +#include "sddr09.h" + + +/* + * Transport for the Microtech DPCM-USB + * + */ +int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us) +{ + int ret; + + if(srb == NULL) + return USB_STOR_TRANSPORT_ERROR; + + US_DEBUGP("dpcm_transport: LUN=%d\n", srb->lun); + + switch(srb->lun) { + case 0: + + /* + * LUN 0 corresponds to the CompactFlash card reader. + */ + return usb_stor_CB_transport(srb, us); + +#ifdef CONFIG_USB_STORAGE_SDDR09 + case 1: + + /* + * LUN 1 corresponds to the SmartMedia card reader. + */ + + /* + * Set the LUN to 0 (just in case). + */ + srb->lun = 0; us->srb->lun = 0; + ret = sddr09_transport(srb, us); + srb->lun = 1; us->srb->lun = 1; + + return ret; +#endif + + default: + US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->lun); + return USB_STOR_TRANSPORT_ERROR; + } +} diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h new file mode 100644 index 000000000..d6e5f86ad --- /dev/null +++ b/drivers/usb/storage/dpcm.h @@ -0,0 +1,34 @@ +/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader + * + * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * + * DPCM driver v0.1: + * + * First release + * + * Current development and maintainance by: + * (c) 2000 Brian Webb (webbb@earthlink.net) + * + * See dpcm.c for more explanation + * + * 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; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MICROTECH_DPCM_USB_H +#define _MICROTECH_DPCM_USB_H + +extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); + +#endif diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 7517d63bc..c823aaed1 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $ + * $Id: scsiglue.c,v 1.8 2000/08/11 23:15:05 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -189,6 +189,12 @@ static int command_abort( Scsi_Cmnd *srb ) return SUCCESS; } + /* This is a sanity check that we should never hit */ + if (in_interrupt()) { + printk(KERN_ERR "usb-storage: command_abort() called from an interrupt!!! BAD!!! BAD!! BAD!!\n"); + return FAILED; + } + /* if we have an urb pending, let's wake the control thread up */ if (us->current_urb->status == -EINPROGRESS) { /* cancel the URB */ diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index f68595c47..492bc7259 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -1,5 +1,7 @@ /* Driver for SCM Microsystems USB-ATAPI cable * + * $Id: shuttle_usbat.c,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * * SCM driver v0.2: * * Removed any reference to maxlen for bulk transfers. diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h index eede2651f..ff5c07541 100644 --- a/drivers/usb/storage/shuttle_usbat.h +++ b/drivers/usb/storage/shuttle_usbat.h @@ -1,6 +1,8 @@ /* Driver for SCM Microsystems USB-ATAPI cable * Header File * + * $Id: shuttle_usbat.h,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * * Current development and maintainance by: * (c) 2000 Robert Baruch (autophile@dol.net) * diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index a0fb2407c..dd3c489f1 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1,12 +1,13 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.5 2000/07/28 22:40:20 mdharm Exp $ + * $Id: transport.c,v 1.12 2000/08/08 15:22:38 gowdy Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -52,6 +53,353 @@ #include <linux/malloc.h> /*********************************************************************** + * Helper routines + ***********************************************************************/ + +/* Calculate the length of the data transfer (not the command) for any + * given SCSI command + */ +static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us) +{ + int i; + unsigned int total = 0; + struct scatterlist *sg; + + /* support those devices which need the length calculated + * differently + */ + if (srb->cmnd[0] == INQUIRY) { + srb->cmnd[4] = 36; + } + + if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) + return srb->cmnd[4]; + + if (srb->cmnd[0] == TEST_UNIT_READY) + return 0; + + /* Are we going to scatter gather? */ + if (srb->use_sg) { + /* Add up the sizes of all the scatter-gather segments */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + total += sg[i].length; + + return total; + } + else + /* Just return the length of the buffer */ + return srb->request_bufflen; +} + +/* Calculate the length of the data transfer (not the command) for any + * given SCSI command + */ +static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us) +{ + int i; + int doDefault = 0; + unsigned int len = 0; + unsigned int total = 0; + struct scatterlist *sg; + + /* This table tells us: + X = command not supported + L = return length in cmnd[4] (8 bits). + M = return length in cmnd[8] (8 bits). + G = return length in cmnd[3] and cmnd[4] (16 bits) + H = return length in cmnd[7] and cmnd[8] (16 bits) + I = return length in cmnd[8] and cmnd[9] (16 bits) + C = return length in cmnd[2] to cmnd[5] (32 bits) + D = return length in cmnd[6] to cmnd[9] (32 bits) + B = return length in blocksize so we use buff_len + R = return length in cmnd[2] to cmnd[4] (24 bits) + S = return length in cmnd[3] to cmnd[5] (24 bits) + T = return length in cmnd[6] to cmnd[8] (24 bits) + U = return length in cmnd[7] to cmnd[9] (24 bits) + 0-9 = fixed return length + V = 20 bytes + W = 24 bytes + Z = return length is mode dependant or not in command, use buff_len + */ + + static char *lengths = + + /* 0123456789ABCDEF 0123456789ABCDEF */ + + "00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X" /* 00-1F */ + "XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH" /* 20-3F */ + "M0HHB0X000H0HH0X" "XHH00HXX0TH0H0XX" /* 40-5F */ + "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */ + "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */ + "X0XXX00XB0BXBXBB" "ZZZ0XUIDU000XHBX" /* A0-BF */ + "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */ + "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */ + + /* Commands checked in table: + + CHANGE_DEFINITION 40 + COMPARE 39 + COPY 18 + COPY_AND_VERIFY 3a + ERASE 19 + ERASE_10 2c + ERASE_12 ac + EXCHANGE_MEDIUM a6 + FORMAT_UNIT 04 + GET_DATA_BUFFER_STATUS 34 + GET_MESSAGE_10 28 + GET_MESSAGE_12 a8 + GET_WINDOW 25 !!! Has more data than READ_CAPACITY, need to fix table + INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len + INQUIRY 12 + LOAD_UNLOAD 1b + LOCATE 2b + LOCK_UNLOCK_CACHE 36 + LOG_SELECT 4c + LOG_SENSE 4d + MEDIUM_SCAN 38 !!! This was M + MODE_SELECT6 15 + MODE_SELECT_10 55 + MODE_SENSE_6 1a + MODE_SENSE_10 5a + MOVE_MEDIUM a5 + OBJECT_POSITION 31 !!! Same as SEARCH_DATA_EQUAL + PAUSE_RESUME 4b + PLAY_AUDIO_10 45 + PLAY_AUDIO_12 a5 + PLAY_AUDIO_MSF 47 + PLAY_AUDIO_TRACK_INDEX 48 + PLAY_AUDIO_TRACK_RELATIVE_10 49 + PLAY_AUDIO_TRACK_RELATIVE_12 a9 + POSITION_TO_ELEMENT 2b + PRE-FETCH 34 + PREVENT_ALLOW_MEDIUM_REMOVAL 1e + PRINT 0a !!! Same as WRITE_6 but is always in bytes + READ_6 08 + READ_10 28 + READ_12 a8 + READ_BLOCK_LIMITS 05 + READ_BUFFER 3c + READ_CAPACITY 25 + READ_CDROM_CAPACITY 25 + READ_DEFECT_DATA 37 + READ_DEFECT_DATA_12 b7 + READ_ELEMENT_STATUS b8 !!! Think this is in bytes + READ_GENERATION 29 !!! Could also be M? + READ_HEADER 44 !!! This was L + READ_LONG 3e + READ_POSITION 34 !!! This should be V but conflicts with PRE-FETCH + READ_REVERSE 0f + READ_SUB-CHANNEL 42 !!! Is this in bytes? + READ_TOC 43 !!! Is this in bytes? + READ_UPDATED_BLOCK 2d + REASSIGN_BLOCKS 07 + RECEIVE 08 !!! Same as READ_6 probably in bytes though + RECEIVE_DIAGNOSTIC_RESULTS 1c + RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes + RELEASE_UNIT 17 + REQUEST_SENSE 03 + REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes + RESERVE_UNIT 16 + REWIND 01 + REZERO_UNIT 01 + SCAN 1b !!! Conflicts with various commands, should be L + SEARCH_DATA_EQUAL 31 + SEARCH_DATA_EQUAL_12 b1 + SEARCH_DATA_LOW 30 + SEARCH_DATA_LOW_12 b0 + SEARCH_DATA_HIGH 32 + SEARCH_DATA_HIGH_12 b2 + SEEK_6 0b !!! Conflicts with SLEW_AND_PRINT + SEEK_10 2b + SEND 0a !!! Same as WRITE_6, probably in bytes though + SEND 2a !!! Similar to WRITE_10 but for scanners + SEND_DIAGNOSTIC 1d + SEND_MESSAGE_6 0a !!! Same as WRITE_6 - is in bytes + SEND_MESSAGE_10 2a !!! Same as WRITE_10 - is in bytes + SEND_MESSAGE_12 aa !!! Same as WRITE_12 - is in bytes + SEND_VOLUME_TAG b6 !!! Think this is in bytes + SET_LIMITS 33 + SET_LIMITS_12 b3 + SET_WINDOW 24 + SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6 + SPACE 11 + START_STOP_UNIT 1b + STOP_PRINT 1b + SYNCHRONIZE_BUFFER 10 + SYNCHRONIZE_CACHE 35 + TEST_UNIT_READY 00 + UPDATE_BLOCK 3d + VERIFY 13 + VERIFY 2f + VERIFY_12 af + WRITE_6 0a + WRITE_10 2a + WRITE_12 aa + WRITE_AND_VERIFY 2e + WRITE_AND_VERIFY_12 ae + WRITE_BUFFER 3b + WRITE_FILEMARKS 10 + WRITE_LONG 3f + WRITE_SAME 41 + */ + + /* Not sure this is right as an INQUIRY can contain nonstandard info */ + if (srb->cmnd[0] == INQUIRY) + srb->cmnd[4] = 36; + + if (srb->sc_data_direction == SCSI_DATA_WRITE) { + doDefault = 1; + } + else + switch (lengths[srb->cmnd[0]]) { + case 'L': + len = srb->cmnd[4]; + break; + + case 'M': + len = srb->cmnd[8]; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + len = lengths[srb->cmnd[0]]-'0'; + break; + + case 'G': + len = (((unsigned int)srb->cmnd[3])<<8) | + srb->cmnd[4]; + break; + + case 'H': + len = (((unsigned int)srb->cmnd[7])<<8) | + srb->cmnd[8]; + break; + + case 'I': + len = (((unsigned int)srb->cmnd[8])<<8) | + srb->cmnd[9]; + break; + + case 'R': + len = (((unsigned int)srb->cmnd[2])<<16) | + (((unsigned int)srb->cmnd[3])<<8) | + srb->cmnd[4]; + break; + + case 'S': + len = (((unsigned int)srb->cmnd[3])<<16) | + (((unsigned int)srb->cmnd[4])<<8) | + srb->cmnd[5]; + break; + + case 'T': + len = (((unsigned int)srb->cmnd[6])<<16) | + (((unsigned int)srb->cmnd[7])<<8) | + srb->cmnd[8]; + break; + + case 'U': + len = (((unsigned int)srb->cmnd[7])<<16) | + (((unsigned int)srb->cmnd[8])<<8) | + srb->cmnd[9]; + break; + + case 'C': + len = (((unsigned int)srb->cmnd[2])<<24) | + (((unsigned int)srb->cmnd[3])<<16) | + (((unsigned int)srb->cmnd[4])<<8) | + srb->cmnd[5]; + break; + + case 'D': + len = (((unsigned int)srb->cmnd[6])<<24) | + (((unsigned int)srb->cmnd[7])<<16) | + (((unsigned int)srb->cmnd[8])<<8) | + srb->cmnd[9]; + break; + + case 'V': + len = 20; + break; + + case 'W': + len = 24; + break; + + case 'B': + /* Use buffer size due to different block sizes */ + doDefault = 1; + break; + + case 'X': + US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n", + srb->cmnd[0]); + doDefault = 1; + break; + + case 'Z': + /* Use buffer size due to mode dependence */ + doDefault = 1; + break; + + default: + US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n", + srb->cmnd[0], lengths[srb->cmnd[0]] ); + doDefault = 1; + } + + if ( doDefault == 1 ) { + /* Are we going to scatter gather? */ + if (srb->use_sg) { + /* Add up the sizes of all the sg segments */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + total += sg[i].length; + len = total; + } + else + /* Just return the length of the buffer */ + len = srb->request_bufflen; + } + + return len; +} + +/* This is a version of usb_clear_halt() that doesn't read the status from + * the device -- this is because some devices crash their internal firmware + * when the status is requested after a halt + */ +static int clear_halt(struct usb_device *dev, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); + + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, + endp, NULL, 0, HZ * 3); + + /* this is a failure case */ + if (result < 0) + return result; + + /* reset the toggles and endpoint flags */ + usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); + + return 0; +} + +/*********************************************************************** * Data transfer routines ***********************************************************************/ @@ -217,7 +565,7 @@ static int us_transfer_partial(struct us_data *us, char *buf, int length) /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } /* did we send all the data? */ @@ -287,44 +635,6 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us) srb->result = result; } -/* Calculate the length of the data transfer (not the command) for any - * given SCSI command - */ -static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us) -{ - int i; - unsigned int total = 0; - struct scatterlist *sg; - - /* support those devices which need the length calculated - * differently - */ - if (us->flags & US_FL_ALT_LENGTH) { - if (srb->cmnd[0] == INQUIRY) { - srb->cmnd[4] = 36; - } - - if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) - return srb->cmnd[4]; - - if (srb->cmnd[0] == TEST_UNIT_READY) - return 0; - } - - /* Are we going to scatter gather? */ - if (srb->use_sg) { - /* Add up the sizes of all the scatter-gather segments */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - total += sg[i].length; - - return total; - } - else - /* Just return the length of the buffer */ - return srb->request_bufflen; -} - /*********************************************************************** * Transport routines ***********************************************************************/ @@ -363,7 +673,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * of determining status on it's own, we need to auto-sense almost * every time. */ - if (us->protocol == US_PR_CB) { + if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; @@ -490,7 +800,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * This is necessary because the auto-sense for some devices always * sets byte 0 == 0x70, even if there is no error */ - if ((us->protocol == US_PR_CB) && + if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && (result == USB_STOR_TRANSPORT_GOOD) && ((srb->sense_buffer[2] & 0xf) == 0x0)) srb->sense_buffer[0] = 0x0; @@ -548,10 +858,10 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = clear_halt(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, + 0)); + US_DEBUGP("-- clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -652,10 +962,10 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = clear_halt(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, + 0)); + US_DEBUGP("-- clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -710,7 +1020,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ @@ -757,7 +1067,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; @@ -796,7 +1106,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); @@ -810,7 +1120,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); return USB_STOR_TRANSPORT_ERROR; } } @@ -877,10 +1187,10 @@ int usb_stor_CB_reset(struct us_data *us) schedule_timeout(HZ*6); US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); return 0; @@ -904,14 +1214,13 @@ int usb_stor_Bulk_reset(struct us_data *us) if (result < 0) US_DEBUGP("Bulk hard reset failed %d\n", result); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + clear_halt(us->pusb_dev, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* long wait for reset */ schedule_timeout(HZ*6); return result; } - diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 9d0993c1e..4615569f3 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.6 2000/07/27 14:42:43 groovyjava Exp $ + * $Id: transport.h,v 1.8 2000/08/08 01:23:55 webbb Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -58,6 +58,7 @@ #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ #endif +#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ /* * Bulk only data structures @@ -133,4 +134,6 @@ extern int usb_stor_Bulk_reset(struct us_data*); void usb_stor_invoke_transport(Scsi_Cmnd *, struct us_data *); +extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); + #endif diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index fc70bc72a..50ebddd6f 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.16 2000/08/01 22:01:19 mdharm Exp $ + * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -44,7 +44,6 @@ */ #include <linux/config.h> - #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -56,6 +55,9 @@ #ifdef CONFIG_USB_STORAGE_SDDR09 #include "sddr09.h" #endif +#ifdef CONFIG_USB_STORAGE_DPCM +#include "dpcm.h" +#endif #include <linux/module.h> #include <linux/sched.h> @@ -63,6 +65,10 @@ #include <linux/init.h> #include <linux/malloc.h> +/* Some informational data */ +MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); +MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); + /* * Per device data */ @@ -91,6 +97,58 @@ static struct usb_driver storage_driver = { disconnect: storage_disconnect, }; +/* + * fill_inquiry_response takes an unsigned char array (which must + * be at least 36 characters) and populates the vendor name, + * product name, and revision fields. Then the array is copied + * into the SCSI command's response buffer (oddly enough + * called request_buffer). data_len contains the length of the + * data array, which again must be at least 36. + */ + +void fill_inquiry_response(struct us_data *us, unsigned char *data, + unsigned int data_len) { + + int i; + struct scatterlist *sg; + int len = + us->srb->request_bufflen > data_len ? data_len : + us->srb->request_bufflen; + int transferred; + int amt; + + if (data_len<36) // You lose. + return; + + memcpy(data+8, us->unusual_dev->vendorName, + strlen(us->unusual_dev->vendorName) > 8 ? 8 : + strlen(us->unusual_dev->vendorName)); + memcpy(data+16, us->unusual_dev->productName, + strlen(us->unusual_dev->productName) > 16 ? 16 : + strlen(us->unusual_dev->productName)); + data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F); + data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F); + data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F); + data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F); + + if (us->srb->use_sg) { + sg = (struct scatterlist *)us->srb->request_buffer; + for (i=0; i<us->srb->use_sg; i++) + memset(sg[i].address, 0, sg[i].length); + for (i=0, transferred=0; + i<us->srb->use_sg && transferred < len; + i++) { + amt = sg[i].length > len-transferred ? + len-transferred : sg[i].length; + memcpy(sg[i].address, data+transferred, amt); + transferred -= amt; + } + } else { + memset(us->srb->request_buffer, 0, us->srb->request_bufflen); + memcpy(us->srb->request_buffer, data, len); + } +} + static int usb_stor_control_thread(void * __us) { wait_queue_t wait; @@ -176,7 +234,7 @@ static int usb_stor_control_thread(void * __us) us->srb = NULL; break; } - + /* lock the device pointers */ down(&(us->dev_semaphore)); @@ -246,50 +304,140 @@ static int usb_stor_control_thread(void * __us) } /* This is the list of devices we recognize, along with their flag data */ + +/* The vendor name should be kept at eight characters or less, and + * the product name should be kept at 16 characters or less. If a device + * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names + * normally generated by a device thorugh the INQUIRY response will be + * taken from this list, and this is the reason for the above size + * restriction. However, if the flag is not present, then you + * are free to use as many characters as you like. + */ + static struct us_unusual_dev us_unusual_dev_list[] = { - { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus", - US_SC_8070, US_PR_CB, 0}, + + { 0x03f0, 0x0107, 0x0200, 0x0200, + "HP", + "CD-Writer+", + US_SC_8070, US_PR_CB, NULL, + 0}, + #ifdef CONFIG_USB_STORAGE_HP8200e - { 0x03f0, 0x0207, 0x0001, 0x0001, "HP USB CD-Writer Plus 8200e", - US_SC_8070, US_PR_SCM_ATAPI, - US_FL_ALT_LENGTH | US_FL_NEED_INIT | US_FL_SINGLE_LUN}, + { 0x03f0, 0x0207, 0x0001, 0x0001, + "HP", + "CD-Writer+ 8200e", + US_SC_8070, US_PR_SCM_ATAPI, init_8200e, + US_FL_SINGLE_LUN}, #endif - { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120", - US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30/S70", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | - US_FL_MODE_XLATE | US_FL_ALT_LENGTH | US_FL_ALT_LENGTH}, - { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | - US_FL_MODE_XLATE | US_FL_ALT_LENGTH}, - { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U", - US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U", - US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN}, - { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-05a)", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP}, -#ifdef CONFIG_USB_STORAGE_SDDR09 - { 0x0781, 0x0200, 0x0100, 0x0100, "Sandisk ImageMate (SDDR-09)", - US_SC_SCSI, US_PR_EUSB_SDDR09, + + { 0x04e6, 0x0001, 0x0200, 0x0200, + "Matshita", + "LS-120", + US_SC_8020, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x04e6, 0x0002, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x04e6, 0x0006, 0x0100, 0x0100, + "Shuttle", + "eUSB MMC Adapter", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x054c, 0x0010, 0x0210, 0x0210, + "Sony", + "DSC-S30/S70", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, + + { 0x054c, 0x002d, 0x0100, 0x0100, + "Sony", + "Memorystick MSAC-US1", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, + + { 0x057b, 0x0000, 0x0000, 0x0299, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x057b, 0x0000, 0x0300, 0x9999, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CBI, NULL, + US_FL_SINGLE_LUN}, + + { 0x0693, 0x0002, 0x0100, 0x0100, + "Hagiwara", + "FlashGate SmartMedia", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x0781, 0x0001, 0x0200, 0x0200, + "Sandisk", + "ImageMate SDDR05a", + US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP}, + +#ifdef CONFIG_USB_STORAGE_SDDR09 + { 0x0781, 0x0200, 0x0100, 0x0100, + "Sandisk", + "ImageMate SDDR09", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP }, +#endif + + { 0x0781, 0x0002, 0x0009, 0x0009, + "Sandisk", + "ImageMate SDDR31", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_IGNORE_SER}, + + { 0x07af, 0x0004, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-DB25", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x059f, 0xa601, 0x0200, 0x0200, + "LaCie", + "USB Hard Disk", + US_SC_RBC, US_PR_CB, NULL, + 0 }, + +#ifdef CONFIG_USB_STORAGE_DPCM + { 0x07af, 0x0006, 0x0100, 0x0100, + "Microtech", + "CameraMate (DPCM_USB)", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP }, #endif - { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)", - US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER}, - { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech USB-SCSI-DB25", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge", - US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0 }}; + + { 0x07af, 0x0005, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-HD50", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x05ab, 0x0031, 0x0100, 0x0100, + "In-System", + "USB/IDE Bridge", + US_SC_8070, US_PR_BULK, NULL, + 0 }, + + { 0x0693, 0x0005, 0x0100, 0x0100, + "Hagiwara", + "Flashgate", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0 } +}; /* Search our ususual device list, based on vendor/product combinations * to see if we can support this device. Returns a pointer to a structure @@ -319,7 +467,8 @@ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct, } /* otherwise, we found one! */ - US_DEBUGP("-- found matching device: %s\n", ptr->name); + US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName, + ptr->productName); return ptr; } @@ -546,15 +695,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) USB_ENDPOINT_NUMBER_MASK; ss->ep_int = ep_int; - /* Reset the device's NEED_INIT flag if it needs to be - initialized with a magic sequence */ - - if (flags & US_FL_NEED_INIT) - ss->flags |= US_FL_NEED_INIT; - /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) return NULL; + + /* Re-Initialize the device if it needs it */ + + if (unusual_dev && unusual_dev->initFunction) + (*unusual_dev->initFunction)(ss); + } else { /* New device -- allocate memory and initialize */ US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); @@ -586,6 +735,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) ss->subclass = subclass; ss->protocol = protocol; ss->flags = flags; + ss->unusual_dev = unusual_dev; /* copy over the endpoint data */ if (ep_in) @@ -604,10 +754,22 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) strncpy(ss->vendor, mf, USB_STOR_STRING_LEN); strncpy(ss->product, prod, USB_STOR_STRING_LEN); strncpy(ss->serial, serial, USB_STOR_STRING_LEN); - if (strlen(ss->vendor) == 0) - strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN); - if (strlen(ss->product) == 0) - strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN); + if (strlen(ss->vendor) == 0) { + if (unusual_dev) + strncpy(ss->vendor, unusual_dev->vendorName, + USB_STOR_STRING_LEN); + else + strncpy(ss->vendor, "Unknown", + USB_STOR_STRING_LEN); + } + if (strlen(ss->product) == 0) { + if (unusual_dev) + strncpy(ss->product, unusual_dev->productName, + USB_STOR_STRING_LEN); + else + strncpy(ss->product, "Unknown", + USB_STOR_STRING_LEN); + } if (strlen(ss->serial) == 0) strncpy(ss->serial, "None", USB_STOR_STRING_LEN); @@ -657,6 +819,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) ss->max_lun = 1; break; #endif + +#ifdef CONFIG_USB_STORAGE_DPCM + case US_PR_DPCM_USB: + ss->transport_name = "Control/Bulk-EUSB/SDDR09"; + ss->transport = dpcm_transport; + ss->transport_reset = usb_stor_CB_reset; + ss->max_lun = 1; + break; +#endif default: ss->transport_name = "Unknown"; @@ -734,6 +905,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) * we to do it? */ (struct us_data *)ss->htmplt.proc_dir = ss; + + /* Just before we start our control thread, initialize + * the device if it needs initialization */ + if (unusual_dev && unusual_dev->initFunction) + (*unusual_dev->initFunction)(ss); /* start up our control thread */ ss->pid = kernel_thread(usb_stor_control_thread, ss, @@ -878,6 +1054,3 @@ void __exit usb_stor_exit(void) module_init(usb_stor_init) ; module_exit(usb_stor_exit) ; - -MODULE_AUTHOR("Michael Gee <michael@linuxspecific.com>, David L. Brown, Jr. <usb-storage@davidb.org>, Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); -MODULE_DESCRIPTION("USB Mass Storage driver"); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index b376d39ee..435ad9777 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Main Header File * - * $Id: usb.h,v 1.4 2000/07/28 20:14:49 groovyjava Exp $ + * $Id: usb.h,v 1.7 2000/08/15 00:06:38 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -77,6 +77,8 @@ static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *seri } } +struct us_data; + /* * Unusual device list definitions */ @@ -89,9 +91,11 @@ struct us_unusual_dev { __u16 bcdDeviceMax; /* the list specifies these parameters */ - const char* name; + const char* vendorName; + const char* productName; __u8 useProtocol; __u8 useTransport; + int (*initFunction)(struct us_data *); unsigned int flags; }; @@ -100,15 +104,11 @@ struct us_unusual_dev { #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for Win/MacOS compatibility */ #define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ -#define US_FL_ALT_LENGTH 0x00000008 /* use the alternate algorithm for - us_transfer_length() */ #define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ -#define US_FL_NEED_INIT 0x00000020 /* Device needs initialization */ +#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define USB_STOR_STRING_LEN 32 -struct us_data; - typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); typedef int (*trans_reset)(struct us_data*); typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); @@ -176,6 +176,7 @@ struct us_data { /* mutual exclusion structures */ struct semaphore notify; /* thread begin/end */ struct semaphore queue_exclusion; /* to protect data structs */ + struct us_unusual_dev *unusual_dev; /* If unusual device */ void *extra; /* Any extra data */ void (*extra_destructor)(void *); /* extra data destructor */ }; @@ -184,4 +185,9 @@ struct us_data { extern struct us_data *us_list; extern struct semaphore us_list_semaphore; +/* Function to fill an inquiry response. See usb.c for details */ + +extern void fill_inquiry_response(struct us_data *us, + unsigned char *data, unsigned int data_len); + #endif diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index 25d1d24cf..017a99dce 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -13,6 +13,7 @@ #include <linux/version.h> #include <linux/kernel.h> #include <linux/config.h> +#include <linux/init.h> #include <linux/usb.h> /* @@ -42,13 +43,11 @@ int dsbr100_init(void); int uhci_init(void); int ohci_hcd_init(void); -#ifdef MODULE - /* * Cleanup */ -void cleanup_module(void) +static void __exit usb_exit(void) { usb_major_cleanup(); usbdevfs_cleanup(); @@ -59,10 +58,7 @@ void cleanup_module(void) * Init */ -int init_module(void) -#else -int usb_init(void) -#endif +static int __init usb_init(void) { usb_major_init(); usbdevfs_init(); @@ -99,3 +95,6 @@ int usb_init(void) #endif return 0; } + +module_init(usb_init); +module_exit(usb_exit); diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 367f0d3f6..316394a84 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -76,7 +76,6 @@ (OHCI_CTRL_CBSR & 0x3) \ | OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE -static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); static LIST_HEAD (ohci_hcd_list); static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; @@ -534,7 +533,6 @@ static int sohci_unlink_urb (urb_t * urb) { unsigned long flags; ohci_t * ohci; - DECLARE_WAITQUEUE (wait, current); if (!urb) /* just to be sure */ return -EINVAL; @@ -580,14 +578,18 @@ static int sohci_unlink_urb (urb_t * urb) spin_unlock_irqrestore (&usb_ed_lock, flags); if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { + DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAITQUEUE (wait, current); + usb_dec_dev_use (urb->dev); - add_wait_queue (&op_wakeup, &wait); - current->state = TASK_UNINTERRUPTIBLE; /* wait until all TDs are deleted */ - if (!schedule_timeout (HZ / 10)) - err("unlink URB timeout!"); - remove_wait_queue (&op_wakeup, &wait); + add_wait_queue (&unlink_wakeup, &wait); + urb_priv->wait = &unlink_wakeup; + current->state = TASK_UNINTERRUPTIBLE; + schedule (); + remove_wait_queue (&unlink_wakeup, &wait); urb->status = -ENOENT; + urb_priv->wait = 0; } else { /* usb_dec_dev_use done in dl_del_list() */ urb->status = -EINPROGRESS; @@ -634,7 +636,6 @@ static int sohci_free_dev (struct usb_device * usb_dev) unsigned long flags; int i, cnt = 0; ed_t * ed; - DECLARE_WAITQUEUE (wait, current); struct ohci_device * dev = usb_to_ohci (usb_dev); ohci_t * ohci = usb_dev->bus->hcpriv; @@ -643,13 +644,20 @@ static int sohci_free_dev (struct usb_device * usb_dev) if (usb_dev->devnum >= 0) { - /* delete all TDs of all EDs */ + /* driver disconnects should have unlinked all urbs + * (freeing all the TDs, unlinking EDs) but we need + * to defend against bugs that prevent that. + */ spin_lock_irqsave (&usb_ed_lock, flags); for(i = 0; i < NUM_EDS; i++) { ed = &(dev->ed[i]); if (ed->state != ED_NEW) { - if (ed->state == ED_OPER) + if (ed->state == ED_OPER) { + /* driver on that interface didn't unlink an urb */ + dbg ("driver usb-%s dev %d ed 0x%x unfreed URB", + ohci->ohci_dev->slot_name, usb_dev->devnum, i); ep_unlink (ohci, ed); + } ep_rm_ed (usb_dev, ed); ed->state = ED_DEL; cnt++; @@ -657,6 +665,9 @@ static int sohci_free_dev (struct usb_device * usb_dev) } spin_unlock_irqrestore (&usb_ed_lock, flags); + /* if the controller is running, tds for those unlinked + * urbs get freed by dl_del_list at the next SF interrupt + */ if (cnt > 0) { if (ohci->disabled) { @@ -670,15 +681,21 @@ static int sohci_free_dev (struct usb_device * usb_dev) warn ("TD leak, %d", cnt); } else if (!in_interrupt ()) { + DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup); + DECLARE_WAITQUEUE (wait, current); + /* SF interrupt handler calls dl_del_list */ - add_wait_queue (&op_wakeup, &wait); + add_wait_queue (&freedev_wakeup, &wait); + dev->wait = &freedev_wakeup; current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout (HZ / 10); - remove_wait_queue (&op_wakeup, &wait); + schedule (); + remove_wait_queue (&freedev_wakeup, &wait); } else { - /* drivers mustn't expect this to work */ - err ("can't free tds, interrupt context"); + /* likely some interface's driver has a refcount bug */ + err ("bus %s devnum %d deletion in interrupt", + ohci->ohci_dev->slot_name, usb_dev->devnum); + BUG (); } } } @@ -907,35 +924,34 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed) #endif break; - case ISO: - if (ohci->ed_isotail == ed) - ohci->ed_isotail = ed->ed_prev; + case ISO: + if (ohci->ed_isotail == ed) + ohci->ed_isotail = ed->ed_prev; if (ed->hwNextED != 0) - ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev; - + ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev; + if (ed->ed_prev != NULL) { ed->ed_prev->hwNextED = ed->hwNextED; } else { - for (i = 0; i < 32; i += inter) { - inter = 1; + for (i = 0; i < 32; i++) { for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); - *ed_p != 0; - ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) { - inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); - if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) { - *ed_p = ed->hwNextED; - break; - } - } + *ed_p != 0; + ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) { + // inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); + if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) { + *ed_p = ed->hwNextED; + break; + } + } } } #ifdef DEBUG ep_print_int_eds (ohci, "UNLINK_ISO"); #endif break; - } - ed->state = ED_UNLINK; - return 0; + } + ed->state = ED_UNLINK; + return 0; } @@ -1276,28 +1292,33 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) tdINFO = le32_to_cpup (&td->hwINFO); if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td); *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3)); - if(++ (urb_priv->td_cnt) == urb_priv->length) + /* URB is done; clean up */ + if (++(urb_priv->td_cnt) == urb_priv->length) { + void *condition = urb_priv->wait; + urb_rm_priv (urb); if (urb->transfer_flags & USB_ASYNC_UNLINK) { usb_dec_dev_use (urb->dev); urb->status = -ECONNRESET; urb->complete (urb); - } else { - wake_up (&op_wakeup); + } else if (condition) { + /* unblock sohci_unlink_urb */ + wake_up (condition); } + } } else { td_p = &td->hwNextTD; } - } + if (ed->state & ED_DEL) { /* set by sohci_free_dev */ struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]); - OHCI_FREE (tdTailP); /* free dummy td */ + OHCI_FREE (tdTailP); /* free dummy td */ ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); ed->state = ED_NEW; /* if all eds are removed wake up sohci_free_dev */ - if (!--dev->ed_cnt) - wake_up (&op_wakeup); + if (!--dev->ed_cnt && dev->wait) + wake_up (dev->wait); } else { ed->state &= ~ED_URB_DEL; @@ -1839,6 +1860,7 @@ static int hc_start (ohci_t * ohci) /* start controller operations */ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + ohci->disabled = 0; writel (ohci->hc_control, &ohci->regs->control); /* Choose the interrupts we care about now, others later on demand */ @@ -1850,25 +1872,28 @@ static int hc_start (ohci_t * ohci) writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM, &ohci->regs->roothub.a); writel (RH_HS_LPSC, &ohci->regs->roothub.status); +#endif /* OHCI_USE_NPS */ + // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe); -#endif /* OHCI_USE_NPS */ /* connect the virtual root hub */ ohci->rh.devnum = 0; usb_dev = usb_alloc_dev (NULL, ohci->bus); - if (!usb_dev) + if (!usb_dev) { + ohci->disabled = 1; return -ENOMEM; + } dev = usb_to_ohci (usb_dev); ohci->bus->root_hub = usb_dev; usb_connect (usb_dev); if (usb_new_device (usb_dev) != 0) { usb_free_dev (usb_dev); + ohci->disabled = 1; return -ENODEV; } - ohci->disabled = 0; return 0; } @@ -1936,7 +1961,7 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r) /* allocate OHCI */ -static ohci_t * __devinit hc_alloc_ohci (void * mem_base) +static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base) { ohci_t * ohci; struct usb_bus * bus; @@ -1947,9 +1972,16 @@ static ohci_t * __devinit hc_alloc_ohci (void * mem_base) memset (ohci, 0, sizeof (ohci_t)); + ohci->disabled = 1; ohci->irq = -1; ohci->regs = mem_base; + ohci->ohci_dev = dev; + dev->driver_data = ohci; + + INIT_LIST_HEAD (&ohci->ohci_hcd_list); + list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); + bus = usb_alloc_bus (&sohci_device_operations); if (!bus) { kfree (ohci); @@ -1958,8 +1990,7 @@ static ohci_t * __devinit hc_alloc_ohci (void * mem_base) ohci->bus = bus; bus->hcpriv = (void *) ohci; - ohci->disabled = 1; - + return ohci; } @@ -2008,6 +2039,7 @@ static int __devinit hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) { ohci_t * ohci; + u8 latency, limit; char buf[8], *bufp = buf; #ifndef __sparc__ @@ -2019,15 +2051,24 @@ hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) (unsigned long) mem_base, bufp); printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name); - ohci = hc_alloc_ohci (mem_base); + ohci = hc_alloc_ohci (dev, mem_base); if (!ohci) { return -ENOMEM; } - ohci->ohci_dev = dev; - dev->driver_data = ohci; - INIT_LIST_HEAD (&ohci->ohci_hcd_list); - list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); + /* bad pci latencies can contribute to overruns */ + pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte (dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) { + dbg ("PCI latency reduced to max %d", limit); + pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); + ohci->pci_latency = limit; + } else { + /* it might already have been reduced */ + ohci->pci_latency = latency; + } + } if (hc_reset (ohci) < 0) { hc_release_ohci (ohci); @@ -2042,7 +2083,7 @@ hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) if (request_irq (irq, hc_interrupt, SA_SHIRQ, ohci_pci_driver.name, ohci) != 0) { - err ("request interrupt %d failed", irq); + err ("request interrupt %s failed", bufp); hc_release_ohci (ohci); return -EBUSY; } @@ -2072,6 +2113,9 @@ static void hc_restart (ohci_t *ohci) int temp; int i; + if (ohci->pci_latency) + pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency); + ohci->disabled = 1; if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub); @@ -2106,7 +2150,6 @@ static int __devinit ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) { unsigned long mem_resource, mem_len; - u8 latency, limit; void *mem_base; if (pci_enable_device(dev) < 0) @@ -2128,14 +2171,6 @@ ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) /* controller writes into our memory */ pci_set_master (dev); - pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); - if (latency) { - pci_read_config_byte (dev, PCI_MAX_LAT, &limit); - if (limit && limit < latency) { - dbg ("PCI latency reduced to max %d", limit); - pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); - } - } return hc_found_ohci (dev, dev->irq, mem_base); } @@ -2157,6 +2192,9 @@ ohci_pci_remove (struct pci_dev *dev) ohci->disabled ? " (disabled)" : "", in_interrupt () ? " in interrupt" : "" ); +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif /* don't wake up sleeping controllers, or block in interrupt context */ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) { @@ -2209,6 +2247,14 @@ ohci_pci_resume (struct pci_dev *dev) ohci_t *ohci = (ohci_t *) dev->driver_data; int temp; + /* guard against multiple resumes */ + atomic_inc (&ohci->resume_count); + if (atomic_read (&ohci->resume_count) != 1) { + err ("concurrent PCI resumes for usb-%s", dev->slot_name); + atomic_dec (&ohci->resume_count); + return; + } + /* did we suspend, or were we powered off? */ ohci->hc_control = readl (&ohci->regs->control); temp = ohci->hc_control & OHCI_CTRL_HCFS; @@ -2253,6 +2299,9 @@ ohci_pci_resume (struct pci_dev *dev) default: warn ("odd PCI resume for usb-%s", dev->slot_name); } + + /* controller is operational, extra resumes are harmless */ + atomic_dec (&ohci->resume_count); } #endif /* CONFIG_PM */ diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h index e326f5ee6..d286265e3 100644 --- a/drivers/usb/usb-ohci.h +++ b/drivers/usb/usb-ohci.h @@ -366,6 +366,7 @@ typedef struct ohci { int irq; int disabled; /* e.g. got a UE, we're hung */ + atomic_t resume_count; /* defending against multiple resumes */ struct ohci_regs * regs; /* OHCI controller's memory */ struct list_head ohci_hcd_list; /* list of all ohci_hcd */ @@ -384,7 +385,10 @@ typedef struct ohci { struct usb_bus * bus; struct usb_device * dev[128]; struct virt_root_hub rh; - struct pci_dev *ohci_dev; + + /* PCI device handle and settings */ + struct pci_dev *ohci_dev; + u8 pci_latency; } ohci_t; diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c index bd721cba2..14c6e649e 100644 --- a/drivers/usb/usb-uhci.c +++ b/drivers/usb/usb-uhci.c @@ -12,7 +12,7 @@ * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * - * $Id: usb-uhci.c,v 1.236 2000/08/02 20:28:28 acher Exp $ + * $Id: usb-uhci.c,v 1.237 2000/08/08 14:58:17 acher Exp $ */ #include <linux/config.h> @@ -48,7 +48,7 @@ /* This enables an extra UHCI slab for memory debugging */ #define DEBUG_SLAB -#define VERSTR "$Revision: 1.236 $ time " __TIME__ " " __DATE__ +#define VERSTR "$Revision: 1.237 $ time " __TIME__ " " __DATE__ #include <linux/usb.h> #include "usb-uhci.h" @@ -888,7 +888,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb) data += pktsze; len -= pktsze; - last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || (urb->transfer_flags & USB_DISABLE_SPD))); + last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_DISABLE_SPD))); if (last) td->hw.td.status |= TD_CTRL_IOC; // last one generates INT diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 777e2d650..93fe7826c 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -1222,9 +1222,7 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface *int int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer) { - int i; - int retval; - int size; + int i, retval, size; struct usb_descriptor_header *header; memcpy(config, buffer, USB_DT_CONFIG_SIZE); @@ -1252,19 +1250,54 @@ int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor size -= config->bLength; for (i = 0; i < config->bNumInterfaces; i++) { - header = (struct usb_descriptor_header *)buffer; - if ((header->bLength > size) || (header->bLength <= 2)) { - err("ran out of descriptors parsing"); - return -1; - } - - if (header->bDescriptorType != USB_DT_INTERFACE) { - warn("unexpected descriptor 0x%X", - header->bDescriptorType); + int numskipped, len; + char *begin; + + /* Skip over the rest of the Class Specific or Vendor */ + /* Specific descriptors */ + begin = buffer; + numskipped = 0; + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if ((header->bLength > size) || (header->bLength < 2)) { + err("invalid descriptor length of %d", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below */ + /* us in the descriptor heirarchy then we're done */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + break; + + dbg("skipping descriptor 0x%X", header->bDescriptorType); + numskipped++; buffer += header->bLength; size -= header->bLength; - continue; + } + if (numskipped) + dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (!len) { + config->extra = NULL; + config->extralen = 0; + } else { + config->extra = kmalloc(len, GFP_KERNEL); + if (!config->extra) { + err("couldn't allocate memory for config extra descriptors"); + config->extralen = 0; + return -1; + } + + memcpy(config->extra, begin, len); + config->extralen = len; } retval = usb_parse_interface(dev, config->interface + i, buffer, size); diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c index 89cc76537..bbf4b59ac 100644 --- a/drivers/usb/usbkbd.c +++ b/drivers/usb/usbkbd.c @@ -1,5 +1,5 @@ /* - * $Id: usbkbd.c,v 1.11 2000/05/29 09:01:52 vojtech Exp $ + * $Id: usbkbd.c,v 1.16 2000/08/14 21:05:26 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -47,8 +47,8 @@ static unsigned char usb_kbd_keycode[256] = { 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -63,7 +63,7 @@ struct usb_kbd { unsigned char old[8]; struct urb irq, led; devrequest dr; - unsigned char leds; + unsigned char leds, newleds; char name[128]; int open; }; @@ -104,28 +104,37 @@ int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, i if (type != EV_LED) return -1; - if (kbd->led.status == -EINPROGRESS) { - warn("had to kill led urb"); - usb_unlink_urb(&kbd->led); - } - kbd->leds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | - (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | - (!!test_bit(LED_NUML, dev->led)); + kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | + (!!test_bit(LED_NUML, dev->led)); + + if (kbd->led.status == -EINPROGRESS) + return 0; + if (kbd->leds == kbd->newleds) + return 0; - if (usb_submit_urb(&kbd->led)) { + kbd->leds = kbd->newleds; + if (usb_submit_urb(&kbd->led)) err("usb_submit_urb(leds) failed"); - return -1; - } return 0; } static void usb_kbd_led(struct urb *urb) { + struct usb_kbd *kbd = urb->context; + if (urb->status) warn("led urb status %d received", urb->status); + + if (kbd->leds == kbd->newleds) + return; + + kbd->leds = kbd->newleds; + if (usb_submit_urb(&kbd->led)) + err("usb_submit_urb(leds) failed"); } static int usb_kbd_open(struct input_dev *dev) diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 5eb9970a2..4ac946a3a 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -22,7 +22,6 @@ #include <linux/malloc.h> #include <linux/init.h> #include <linux/fb.h> -#include <linux/wrapper.h> #include <asm/hardware.h> #include <asm/io.h> @@ -1528,13 +1527,16 @@ free_unused_pages(unsigned int virtual_start, unsigned int virtual_end) virtual_end = PAGE_ALIGN(virtual_end); while (virtual_start < virtual_end) { + struct page *page; + /* * Clear page reserved bit, * set count to 1, and free * the page. */ - mem_map_unreserve(virt_to_page(virtual_start)); - atomic_set(&virt_to_page(virtual_start)->count, 1); + page = virt_to_page(virtual_start); + ClearPageReserved(page); + atomic_set(&page->count, 1); free_page(virtual_start); virtual_start += PAGE_SIZE; @@ -1629,7 +1631,7 @@ acornfb_init(void) for (page = current_par.screen_base; page < PAGE_ALIGN(current_par.screen_base + size); page += PAGE_SIZE) - mem_map_reserve(virt_to_page(page)); + SetPageReserved(virt_to_page(page)); /* Hand back any excess pages that we allocated. */ for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE) free_page(page); diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index d2b09416b..8b389f846 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -7,6 +7,8 @@ * * History: * + * - Revision 0.1.6 (17 Aug 2000): new style structs + * documentation * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc * minor fixes * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for @@ -107,19 +109,23 @@ spinlock_t hga_reg_lock = SPIN_LOCK_UNLOCKED; /* Framebuffer driver structures */ static struct fb_var_screeninfo hga_default_var = { - 720, 348, /* xres, yres */ - 720, 348, /* xres_virtual, yres_virtual */ - 0, 0, /* xoffset, yoffset */ - 1, /* bits_per_pixel */ - 0, /* grayscale */ - {0, 1, 0}, /* red */ - {0, 1, 0}, /* green */ - {0, 1, 0}, /* blue */ - {0, 0, 0}, /* transp */ - 0, /* nonstd (FB_NONSTD_HGA ?) */ - 0, /* activate */ - -1, -1, /* height, width */ - 0, /* accel_flags */ + xres: 720, + yres: 348, + xres_virtual: 720, + yres_virtual: 348, + xoffset: 0, + yoffset: 0, + bits_per_pixel: 1, + grayscale: 0, + red: {0, 1, 0}, + green: {0, 1, 0}, + blue: {0, 1, 0}, + transp: {0, 0, 0}, + nonstd: 0, /* (FB_NONSTD_HGA ?) */ + activate: 0, + height: -1, + width: -1, + accel_flags: 0, /* pixclock */ /* left_margin, right_margin */ /* upper_margin, lower_margin */ @@ -129,19 +135,19 @@ static struct fb_var_screeninfo hga_default_var = { }; static struct fb_fix_screeninfo hga_fix = { - "HGA", /* id */ - (unsigned long) NULL, /* smem_start */ - 0, /* smem_len */ - FB_TYPE_PACKED_PIXELS, /* type (not sure) */ - 0, /* type_aux (not sure) */ - FB_VISUAL_MONO10, /* visual */ - 8, /* xpanstep */ - 8, /* ypanstep */ - 0, /* ywrapstep */ - 90, /* line_length */ - 0, /* mmio_start */ - 0, /* mmio_len */ - FB_ACCEL_NONE /* accel */ + id: "HGA", + smem_start: (unsigned long) NULL, + smem_len: 0, + type: FB_TYPE_PACKED_PIXELS, /* (not sure) */ + type_aux: 0, /* (not sure) */ + visual: FB_VISUAL_MONO10, + xpanstep: 8, + ypanstep: 8, + ywrapstep: 0, + line_length: 90, + mmio_start: 0, + mmio_len: 0, + accel: FB_ACCEL_NONE }; static struct fb_info fb_info; @@ -377,9 +383,15 @@ static int __init hga_card_detect(void) * * ------------------------------------------------------------------------- */ - /* - * Get the Fixed Part of the Display - */ +/** + * hga_get_fix - get the fixed part of the display + * @fix:struct fb_fix_screeninfo to fill in + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function copies @info->fix to @fix. + * A zero is returned on success and %-EINVAL for failure. + */ int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { @@ -390,10 +402,15 @@ int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) return 0; } - - /* - * Get the User Defined Part of the Display - */ +/** + * hga_get_var - get the user defined part of the display + * @var:struct fb_var_screeninfo to fill in + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function copies @info->var to @var. + * A zero is returned on success and %-EINVAL for failure. + */ int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -404,13 +421,23 @@ int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) return 0; } - /* - * Set the User Defined Part of the Display - * This is the most mystical function (at least for me). - * What is the exact specification of xxx_set_var? - * Should it handle xoffset, yoffset? Should it do pannig? - * What does vmode mean? - */ +/** + * hga_set_var - set the user defined part of the display + * @var:new video mode + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This function is called for changing video modes. Since HGA cards have + * only one fixed mode we have not much to do. After checking input + * parameters @var is copied to @info->var and @info->changevar is called. + * A zero is returned on success and %-EINVAL for failure. + * + * FIXME: + * This is the most mystical function (at least for me). + * What is the exact specification of xxx_set_var()? + * Should it handle xoffset, yoffset? Should it do panning? + * What does vmode mean? + */ int hga_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -431,10 +458,20 @@ int hga_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) return 0; } - - /* - * Get the Colormap - */ +/** + * hga_getcolreg - read color registers + * @regno:register index to read out + * @red:red value + * @green:green value + * @blue:blue value + * @transp:transparency value + * @info:unused + * + * This callback function is used to read the color registers of a HGA + * board. Since we have only two fixed colors, RGB values are 0x0000 + * for register0 and 0xaaaa for register1. + * A zero is returned on success and 1 for failure. + */ static int hga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info) @@ -450,6 +487,17 @@ static int hga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, return 0; } +/** + * hga_get_cmap - get the colormap + * @cmap:struct fb_cmap to fill in + * @kspc:called from kernel space? + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function passes it's input parameters to fb_get_cmap(). + * Callback function hga_getcolreg() is used to read the color registers. + */ + int hga_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { @@ -458,9 +506,19 @@ int hga_get_cmap(struct fb_cmap *cmap, int kspc, int con, return fb_get_cmap(cmap, kspc, hga_getcolreg, info); } - /* - * Set the Colormap - */ +/** + * hga_setcolreg - set color registers + * @regno:register index to set + * @red:red value, unused + * @green:green value, unused + * @blue:blue value, unused + * @transp:transparency value, unused + * @info:unused + * + * This callback function is used to set the color registers of a HGA + * board. Since we have only two fixed colors only @regno is checked. + * A zero is returned on success and 1 for failure. + */ static int hga_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) @@ -470,6 +528,17 @@ static int hga_setcolreg(u_int regno, u_int red, u_int green, u_int blue, return 0; } +/** + * hga_set_cmap - set the colormap + * @cmap:struct fb_cmap to set + * @kspc:called from kernel space? + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function passes it's input parameters to fb_set_cmap(). + * Callback function hga_setcolreg() is used to set the color registers. + */ + int hga_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { @@ -478,11 +547,17 @@ int hga_set_cmap(struct fb_cmap *cmap, int kspc, int con, return fb_set_cmap(cmap, kspc, hga_setcolreg, info); } - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ +/** + * hga_pan_display - pan or wrap the display + * @var:contains new xoffset, yoffset and vmode values + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP + * flag in @var. If input parameters are correct it calls hga_pan() to + * program the hardware. @info->var is updated to the new values. + * A zero is returned on success and %-EINVAL for failure. + */ int hga_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) @@ -531,6 +606,18 @@ static struct fb_ops hgafb_ops = { * * ------------------------------------------------------------------------- */ +/** + * hgafbcon_switch - switch console + * @con:new console to switch to + * @info:pointer to fb_info object containing info for current hga board + * + * This function should install a new colormap and change the video mode. + * Since we have fixed colors and only one video mode we have nothing to + * do. + * Only console administration is done but it should go to fbcon.c IMHO. + * A zero is returned on success and %-EINVAL for failure. + */ + static int hgafbcon_switch(int con, struct fb_info *info) { CHKINFO(-EINVAL); @@ -564,6 +651,17 @@ static int hgafbcon_switch(int con, struct fb_info *info) return 0; } +/** + * hgafbcon_updatevar - update the user defined part of the display + * @con:console to update or -1 when no consoles defined on this fb + * @info:pointer to fb_info object containing info for current hga board + * + * This function is called when @var is changed by fbcon.c without calling + * hga_set_var(). It usually means scrolling. hga_pan_display() is called + * to update the hardware and @info->var. + * A zero is returned on success and %-EINVAL for failure. + */ + static int hgafbcon_updatevar(int con, struct fb_info *info) { CHKINFO(-EINVAL); @@ -571,17 +669,21 @@ static int hgafbcon_updatevar(int con, struct fb_info *info) return (con < 0) ? -EINVAL : hga_pan_display(&fb_display[con].var, con, info); } +/** + * hgafbcon_blank - (un)blank the screen + * @blank_mode:blanking method to use + * @info:unused + * + * Blank the screen if blank_mode != 0, else unblank. + * Implements VESA suspend and powerdown modes on hardware that supports + * disabling hsync/vsync: + * @blank_mode == 2 means suspend vsync, + * @blank_mode == 3 means suspend hsync, + * @blank_mode == 4 means powerdown. + */ + static void hgafbcon_blank(int blank_mode, struct fb_info *info) { - /* - * Blank the screen if blank_mode != 0, else unblank. - * Implements VESA suspend and powerdown modes on hardware - * that supports disabling hsync/vsync: - * blank_mode == 2: suspend vsync - * blank_mode == 3: suspend hsync - * blank_mode == 4: powerdown - */ - CHKINFO( ); DPRINTK("hga_blank: blank_mode:%d, info:%x, fb_info:%x\n", blank_mode, (unsigned)info, (unsigned)&fb_info); diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index e8a3738f8..1c611ebee 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * - * Version: 1.21 1999/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * * Contributors: "menion?" <menion@mindless.com> * Betatesting, fixes, ideas * - * "Kurt Garloff" <garloff@kg1.ping.de> + * "Kurt Garloff" <garloff@suse.de> * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" <trini@kernel.crashing.org> @@ -63,6 +63,9 @@ * "Mark Vojkovich" <mvojkovi@ucsd.edu> * G400 support * + * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com> + * memtype extension (needed for GXT130P RS/6000 adapter) + * * (following author is not in any relation with this code, but his code * is included in this driver) * @@ -755,7 +758,7 @@ static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){ if (ACCESS_FBINFO(devflags.noinit)) return 0; hw->MXoptionReg &= 0xC0000100; - hw->MXoptionReg |= 0x00078020; + hw->MXoptionReg |= 0x00000020; if (ACCESS_FBINFO(devflags.novga)) hw->MXoptionReg &= ~0x00000100; if (ACCESS_FBINFO(devflags.nobios)) @@ -763,13 +766,13 @@ static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){ if (ACCESS_FBINFO(devflags.nopciretry)) hw->MXoptionReg |= 0x20000000; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); - reg50 &= ~0x3000; - pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); - DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333); if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) { + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + reg50 &= ~0x3000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + hw->MXoptionReg |= 0x1080; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); mga_outl(M_CTLWTST, 0x00000300); @@ -797,20 +800,45 @@ static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){ hw->MXoptionReg &= ~0x1000; } #endif + hw->MXoptionReg |= 0x00078020; + } else if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG200) { + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + reg50 &= ~0x3000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + + if (ACCESS_FBINFO(devflags.memtype) == -1) + ACCESS_FBINFO(devflags.memtype) = 3; + hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; + if (ACCESS_FBINFO(devflags.sgram)) + hw->MXoptionReg |= 0x4000; + mga_outl(M_CTLWTST, 0x042450A1); + mga_outl(M_MEMRDBK, 0x00000108); + udelay(200); + mga_outl(M_MACCESS, 0x00000000); + mga_outl(M_MACCESS, 0x00008000); + udelay(100); + mga_outw(M_MEMRDBK, 0x00000108); + hw->MXoptionReg |= 0x00078020; } else { - hw->MXoptionReg |= 0x00000C00; + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + reg50 &= ~0x00000100; + reg50 |= 0x00000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + + if (ACCESS_FBINFO(devflags.memtype) == -1) + ACCESS_FBINFO(devflags.memtype) = 0; + hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; if (ACCESS_FBINFO(devflags.sgram)) hw->MXoptionReg |= 0x4000; mga_outl(M_CTLWTST, 0x042450A1); - mga_outb(0x1E47, 0x00); - mga_outb(0x1E46, 0x00); - udelay(10); - mga_outb(0x1C05, 0x00); - mga_outb(0x1C05, 0x80); + mga_outl(M_MEMRDBK, 0x00000108); + udelay(200); + mga_outl(M_MACCESS, 0x00000000); + mga_outl(M_MACCESS, 0x00008000); udelay(100); - mga_outw(0x1E44, 0x0108); + mga_outl(M_MEMRDBK, 0x00000108); + hw->MXoptionReg |= 0x00040020; } - hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); return 0; } diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c index 67dc556b0..7c65eaa0f 100644 --- a/drivers/video/matrox/matroxfb_Ti3026.c +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * - * Version: 1.21 2000/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * * Contributors: "menion?" <menion@mindless.com> * Betatesting, fixes, ideas * - * "Kurt Garloff" <garloff@kg1.ping.de> + * "Kurt Garloff" <garloff@suse.de> * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" <trini@kernel.crashing.org> diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index a28388e1e..d79e5e3e4 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * - * Version: 1.21 2000/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * * Contributors: "menion?" <menion@mindless.com> * Betatesting, fixes, ideas * - * "Kurt Garloff" <garloff@kg1.ping.de> + * "Kurt Garloff" <garloff@suse.de> * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" <trini@kernel.crashing.org> diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 9ddb30140..9a21d5dc7 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * - * Version: 1.21 1999/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * * Contributors: "menion?" <menion@mindless.com> * Betatesting, fixes, ideas * - * "Kurt Garloff" <garloff@kg1.ping.de> + * "Kurt Garloff" <garloff@suse.de> * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" <trini@kernel.crashing.org> @@ -69,6 +69,9 @@ * "Anton Altaparmakov" <AntonA@bigfoot.com> * G400 MAX/non-MAX distinction * + * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com> + * memtype extension (needed for GXT130P RS/6000 adapter) + * * (following author is not in any relation with this code, but his code * is included in this driver) * @@ -1312,6 +1315,7 @@ static unsigned int fv = 0; /* "matrox:fv:xxxxx" */ static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ static int dfp = 0; /* "matrox:dfp */ +static int memtype = -1; /* "matrox:memtype:xxx" */ static char fontname[64]; /* "matrox:font:xxxxx" */ #ifndef MODULE @@ -2037,6 +2041,9 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); /* DEVFLAGS */ ACCESS_FBINFO(devflags.inverse) = inverse; + ACCESS_FBINFO(devflags.memtype) = memtype; + if (memtype != -1) + noinit = 0; if (cmd & PCI_COMMAND_MEMORY) { ACCESS_FBINFO(devflags.novga) = novga; ACCESS_FBINFO(devflags.nobios) = nobios; @@ -2050,6 +2057,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm ACCESS_FBINFO(devflags.nobios) = 1; ACCESS_FBINFO(devflags.noinit) = 0; } + ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry; ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24; ACCESS_FBINFO(devflags.precise_width) = option_precise_width; @@ -2094,10 +2102,42 @@ static void pci_remove_matrox(struct pci_dev* pdev) { matroxfb_remove(PMINFO 1); } +static struct pci_device_id matroxfb_devices[] __devinitdata = { +#ifdef CONFIG_FB_MATROX_MILLENIUM + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif +#ifdef CONFIG_FB_MATROX_MYSTIQUE + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif +#ifdef CONFIG_FB_MATROX_G100 + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif + {0, 0, + 0, 0, 0, 0, 0} +}; + +MODULE_DEVICE_TABLE(pci, matroxfb_devices); + static struct pci_driver matroxfb_driver = { - name: "matroxfb", - probe: matroxfb_probe, - remove: pci_remove_matrox, + name: "matroxfb", + id_table: matroxfb_devices, + probe: matroxfb_probe, + remove: pci_remove_matrox, }; /* **************************** init-time only **************************** */ @@ -2378,6 +2418,8 @@ int __init matroxfb_setup(char *options) { sgram = 1; else if (!strcmp(this_opt, "sdram")) sgram = 0; + else if (!strncmp(this_opt, "memtype:", 8)) + memtype = simple_strtoul(this_opt+8, NULL, 0); else { int value = 1; @@ -2461,6 +2503,8 @@ MODULE_PARM(nobios, "i"); MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); MODULE_PARM(noinit, "i"); MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)"); +MODULE_PARM(memtype, "i"); +MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.txt for explanation) (default=3 for G200, 0 for G400)"); MODULE_PARM(mtrr, "i"); MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)"); MODULE_PARM(sgram, "i"); diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index c8a47fe9e..125f8be4f 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -2,7 +2,7 @@ * * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * - * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz> + * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * */ #ifndef __MATROXFB_H__ @@ -530,6 +530,7 @@ struct matrox_fb_info { unsigned int textvram; /* character cells */ unsigned int ydstorg; /* offset in bytes from video start to usable memory */ /* 0 except for 6MB Millenium */ + int memtype; } devflags; struct display_switch dispsw; struct { @@ -695,6 +696,7 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv); #define M_VCOUNT 0x1E20 #define M_RESET 0x1E40 +#define M_MEMRDBK 0x1E44 #define M_AGP2PLL 0x1E4C diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index 126ab9b66..ff9d6fb75 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> * - * Version: 1.21 2000/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * * Contributors: "menion?" <menion@mindless.com> * Betatesting, fixes, ideas * - * "Kurt Garloff" <garloff@kg1.ping.de> + * "Kurt Garloff" <garloff@suse.de> * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" <trini@kernel.crashing.org> diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index df86a674e..aa955b41c 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -12,17 +12,40 @@ /* * Code Status: - * 4/1/99 - Driver appears to be working for Brutus 320x200x8bpp mode. Other - * resolutions are working, but only the 8bpp mode is supported. - * Changes need to be made to the palette encode and decode routines - * to support 4 and 16 bpp modes. - * Driver is not designed to be a module. The FrameBuffer is statically - * allocated since dynamic allocation of a 300k buffer cannot be guaranteed. - * - * 6/17/99 - FrameBuffer memory is now allocated at run-time when the - * driver is initialized. + * 1999/04/01: + * Driver appears to be working for Brutus 320x200x8bpp mode. Other + * resolutions are working, but only the 8bpp mode is supported. + * Changes need to be made to the palette encode and decode routines + * to support 4 and 16 bpp modes. + * Driver is not designed to be a module. The FrameBuffer is statically + * allocated since dynamic allocation of a 300k buffer cannot be + * guaranteed. + * + * 1999/06/17: + * FrameBuffer memory is now allocated at run-time when the + * driver is initialized. * + * 2000/04/10: + * Big cleanup for dynamic selection of machine type at run time. + * Nicolas Pitre <nico@cam.org> + * + * 2000/07/19: + * Support for Bitsy aka Compaq iPAQ H3600 added. + * Jamey Hicks <jamey@crl.dec.com> + * + * 2000/08/07: + * Resolved an issue caused by a change made to the Assabet's PLD + * earlier this year which broke the framebuffer driver for newer + * Phase 4 Assabets. Some other parameters were changed to optimize for + * the Sharp display. + * Tak-Shing Chan <tchan.rd@idthk.com> + * Jeff Sutherland <jsutherland@accelent.com> + * + * 2000/08/09: + * XP860 support added + * Kunihiko IMAI <???> */ + #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -41,6 +64,7 @@ #include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> +#include <asm/mach-types.h> #include <asm/uaccess.h> #include <asm/proc/pgtable.h> @@ -324,7 +348,7 @@ static int sa1100fb_encode_var(struct fb_var_screeninfo *var, struct sa1100fb_par *par) { - // Don't know if really want to var on entry. + // Don't know if really want to zero var on entry. // Look at set_var to see. If so, may need to add extra params to par // memset(var, 0, sizeof(struct fb_var_screeninfo)); @@ -347,15 +371,26 @@ sa1100fb_encode_var(struct fb_var_screeninfo *var, break; case 12: // This case should differ for Active/Passive mode case 16: - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - var->transp.length = 0; - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->transp.offset = 0; - break; + if (machine_is_bitsy()) { + var->red.length = 4; + var->blue.length = 4; + var->green.length = 4; + var->transp.length = 0; + var->red.offset = 12; + var->green.offset = 7; + var->blue.offset = 1; + var->transp.offset = 0; + } else { + var->red.length = 5; + var->blue.length = 5; + var->green.length = 6; + var->transp.length = 0; + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->transp.offset = 0; + } + break; } return 0; } @@ -425,10 +460,13 @@ sa1100fb_decode_var(struct fb_var_screeninfo *var, DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base); DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base); + DPRINTK("palette_size = 0x%08lx\n",(u_long)par->palette_size); + DPRINTK("palette_mem_size = 0x%08lx\n",(u_long)palette_mem_size); DPRINTK("p_screen_base = 0x%08lx\n",(u_long)par->p_screen_base); DPRINTK("v_screen_base = 0x%08lx\n",(u_long)par->v_screen_base); DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion); DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys); + return 0; } @@ -463,8 +501,6 @@ sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) else display = &global_disp; /* Default display settings */ - - DPRINTK("xres = %d, yres = %d\n",var->xres, var->yres); /* Decode var contents into a par structure, adjusting any */ /* out of range values. */ if ((err = sa1100fb_decode_var(var, &par))) @@ -490,7 +526,6 @@ sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))) chgvar = 1; } - DPRINTK("chgvar=%d\n", chgvar); display->var = *var; display->screen_base = par.v_screen_base; @@ -505,8 +540,6 @@ sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) display->can_soft_blank = 1; display->inverse = 0; - DPRINTK("display->var.bits_per_pixel=%d xres=%d yres=%d display->dispsw=%p\n", - display->var.bits_per_pixel, var->xres, var->yres, display->dispsw); switch (display->var.bits_per_pixel) { #ifdef FBCON_HAS_CFB4 case 4: @@ -545,7 +578,6 @@ sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) cmap = &display->cmap; else cmap = fb_default_cmap(current_par.palette_size); - DPRINTK("visual=%d palette_size=%d cmap=%p\n", current_par.visual, current_par.palette_size, cmap); fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info); } @@ -634,14 +666,18 @@ __init sa1100fb_init_fbinfo(void) init_var.blue.length = 5; init_var.grayscale = 0; init_var.sync = 0; + init_var.pixclock = 171521; } else if (machine_is_bitsy()) { current_par.max_xres = 320; current_par.max_yres = 240; current_par.max_bpp = 16; - init_var.red.length = 5; - init_var.green.length = 6; - init_var.blue.length = 5; - init_var.grayscale = 0; + init_var.red.length = 4; + init_var.green.length = 4; + init_var.blue.length = 4; + init_var.red.offset = 12; + init_var.green.offset = 7; + init_var.blue.offset = 1; + init_var.grayscale = 0; } else if (machine_is_brutus()) { current_par.max_xres = 320; current_par.max_yres = 240; @@ -694,6 +730,23 @@ __init sa1100fb_init_fbinfo(void) init_var.vsync_len = 1; init_var.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT; init_var.vmode = 0; + } else if (machine_is_xp860()) { + current_par.max_xres = 1024; + current_par.max_yres = 768; + + current_par.max_bpp = 8; + init_var.red.length = 4; + init_var.green = init_var.red; + init_var.blue = init_var.red; + + init_var.hsync_len = 4; + init_var.left_margin = 3; + init_var.right_margin = 2; + + init_var.vsync_len = 3; + init_var.upper_margin = 2; + init_var.lower_margin = 1; + } current_par.p_palette_base = NULL; @@ -769,7 +822,6 @@ __init sa1100fb_map_video_memory(void) L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE); - memset(VideoMemRegion, 0xAA, ALLOCATED_FB_MEM_SIZE); return (VideoMemRegion == NULL ? -EINVAL : 0); } @@ -804,6 +856,12 @@ static inline int get_pcd(unsigned int pixclock) /* the last multiplication by 1.2 is to handle */ /* sync problems */ } + if (machine_is_assabet()) { + pcd = frequency[PPCR & 0xf] / 1000; + pcd *= pixclock / 1000; + pcd = pcd / 1000000; + pcd++; /* make up for integer math truncations */ + } return pcd; } @@ -844,12 +902,12 @@ sa1100fb_activate_var(struct fb_var_screeninfo *var) LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) + LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9); lcd_shadow.lccr2 = - LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(2) + + LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0); lcd_shadow.lccr3 = LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + LCCR3_HorSnchH + LCCR3_ACBsCntOff + - LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38); + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd); /* Set board control register to handle new color depth */ sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16); @@ -860,29 +918,33 @@ sa1100fb_activate_var(struct fb_var_screeninfo *var) LCCR0_DMADel(0); lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) + LCCR1_HorSnchWdth( 4 ) + - LCCR1_BegLnDel( 0x1f ) + - LCCR1_EndLnDel( 0x1f ); - lcd_shadow.lccr2 = LCCR2_DisHght( var->yres ) + - LCCR2_VrtSnchWdth( 1 )+ - LCCR2_BegFrmDel( 0 ) + - LCCR2_EndFrmDel( 0 ); - lcd_shadow.lccr3 = 15; + LCCR1_BegLnDel( 0xC ) + + LCCR1_EndLnDel( 0x11 ); + lcd_shadow.lccr2 = LCCR2_DisHght( var->yres + 1 ) + + LCCR2_VrtSnchWdth( 3 )+ + LCCR2_BegFrmDel( 10 ) + + LCCR2_EndFrmDel( 1 ); + lcd_shadow.lccr3 = (/* PCD */ 0x10 + | /* ACB */ 0 + | /* API */ 0 + | LCCR3_VrtSnchL + | LCCR3_HorSnchL); } else if (machine_is_brutus()) { - DPRINTK("Configuring Brutus LCD\n"); - lcd_shadow.lccr0 = - LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + - LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + - LCCR0_DMADel(0); - lcd_shadow.lccr1 = - LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) + - LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101); - lcd_shadow.lccr2 = - LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + - LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0); - lcd_shadow.lccr3 = - LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + - LCCR3_HorSnchH + LCCR3_ACBsCntOff + - LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44); + DPRINTK("Configuring Brutus LCD\n"); + lcd_shadow.lccr0 = + LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + + LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + + LCCR0_DMADel(0); + lcd_shadow.lccr1 = + LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) + + LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101); + lcd_shadow.lccr2 = + LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + + LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0); + lcd_shadow.lccr3 = + LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + + LCCR3_HorSnchH + LCCR3_ACBsCntOff + + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44); } else if (machine_is_lart()) { DPRINTK("Configuring LART LCD\n"); lcd_shadow.lccr0 = @@ -950,6 +1012,25 @@ sa1100fb_activate_var(struct fb_var_screeninfo *var) ((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) + ((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); */ + } else if (machine_is_xp860()) { + DPRINTK("Configuring XP860 LCD\n"); + lcd_shadow.lccr0 = + LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + + LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM + + LCCR0_DMADel(0); + lcd_shadow.lccr1 = + LCCR1_DisWdth(var->xres) + + LCCR1_HorSnchWdth(var->hsync_len) + + LCCR1_BegLnDel(var->left_margin) + + LCCR1_EndLnDel(var->right_margin); + lcd_shadow.lccr2 = + LCCR2_DisHght(var->yres) + + LCCR2_VrtSnchWdth(var->vsync_len) + + LCCR2_BegFrmDel(var->upper_margin) + + LCCR2_EndFrmDel(var->lower_margin); + lcd_shadow.lccr3 = + LCCR3_PixClkDiv(6) + + LCCR3_HorSnchL + LCCR3_VrtSnchL; } /* Restore interrupt status */ @@ -976,10 +1057,12 @@ sa1100fb_activate_var(struct fb_var_screeninfo *var) static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs) { if (LCSR & LCSR_LDD) { + int controller_state = current_par.controller_state; /* Disable Done Flag is set */ LCCR0 |= LCCR0_LDM; /* Mask LCD Disable Done Interrupt */ current_par.controller_state = LCD_MODE_DISABLED; - if (current_par.controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) { + if (controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) { + DPRINTK("sa1100fb_inter_handler: re-enabling LCD controller\n"); sa1100fb_enable_lcd_controller(); } } @@ -1010,7 +1093,8 @@ static void sa1100fb_disable_lcd_controller(void) #endif } else if (machine_is_bitsy()) { #ifdef CONFIG_SA1100_BITSY - clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); + if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE) + clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); #endif } else if (machine_is_penny()) { #ifdef CONFIG_SA1100_PENNY @@ -1066,7 +1150,7 @@ static void sa1100fb_enable_lcd_controller(void) #endif } else if (machine_is_bitsy()) { #ifdef CONFIG_SA1100_BITSY - set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON) + set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); DPRINTK("DBAR1=%p\n", DBAR1); DPRINTK("LCCR0=%x\n", LCCR0); DPRINTK("LCCR1=%x\n", LCCR1); @@ -1115,6 +1199,7 @@ sa1100fb_blank(int blank, struct fb_info *info) current_par.currcon, info); sa1100fb_enable_lcd_controller(); } + /* TODO: Bitsy support for blanking display */ } @@ -1164,7 +1249,7 @@ int __init sa1100fb_init(void) current_par.montype = 1; if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL) != 0) { - printk("sa1100fb: failed in request_irq\n"); + printk(KERN_ERR "sa1100fb: failed in request_irq\n"); return -EBUSY; } DPRINTK("sa1100fb: request_irq succeeded\n"); @@ -1185,6 +1270,9 @@ int __init sa1100fb_init(void) #endif } else if (machine_is_tifon()) { GPDR |= GPIO_GPIO(24); /* set GPIO24 to output */ + } else if (machine_is_xp860()) { + GPDR |= 0x3fc; + GAFR |= 0x3fc; } if (sa1100fb_set_var(&init_var, -1, &fb_info)) |