diff options
Diffstat (limited to 'drivers')
254 files changed, 11450 insertions, 5361 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 7bdae47d6b9..4fb134d50da 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -84,6 +84,8 @@ source "drivers/rtc/Kconfig" source "drivers/dma/Kconfig" +source "drivers/dca/Kconfig" + source "drivers/auxdisplay/Kconfig" source "drivers/kvm/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index a168eacdcd9..174c27eb443 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -85,6 +85,7 @@ obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SUPERH) += sh/ obj-$(CONFIG_GENERIC_TIME) += clocksource/ obj-$(CONFIG_DMA_ENGINE) += dma/ +obj-$(CONFIG_DCA) += dca/ obj-$(CONFIG_HID) += hid/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 68699b3e799..bbaa545ea99 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1410,7 +1410,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) */ unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, struct scatterlist *sg, + int dma_dir, struct scatterlist *sgl, unsigned int n_elem, unsigned long timeout) { struct ata_link *link = dev->link; @@ -1472,11 +1472,12 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, qc->dma_dir = dma_dir; if (dma_dir != DMA_NONE) { unsigned int i, buflen = 0; + struct scatterlist *sg; - for (i = 0; i < n_elem; i++) - buflen += sg[i].length; + for_each_sg(sgl, sg, n_elem, i) + buflen += sg->length; - ata_sg_init(qc, sg, n_elem); + ata_sg_init(qc, sgl, n_elem); qc->nbytes = buflen; } @@ -4292,7 +4293,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc) if (qc->n_elem) dma_unmap_sg(ap->dev, sg, qc->n_elem, dir); /* restore last sg */ - sg[qc->orig_n_elem - 1].length += qc->pad_len; + sg_last(sg, qc->orig_n_elem)->length += qc->pad_len; if (pad_buf) { struct scatterlist *psg = &qc->pad_sgent; void *addr = kmap_atomic(psg->page, KM_IRQ0); @@ -4547,6 +4548,7 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) qc->orig_n_elem = 1; qc->buf_virt = buf; qc->nbytes = buflen; + qc->cursg = qc->__sg; sg_init_one(&qc->sgent, buf, buflen); } @@ -4572,6 +4574,7 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, qc->__sg = sg; qc->n_elem = n_elem; qc->orig_n_elem = n_elem; + qc->cursg = qc->__sg; } /** @@ -4661,7 +4664,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg = qc->__sg; - struct scatterlist *lsg = &sg[qc->n_elem - 1]; + struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem); int n_elem, pre_n_elem, dir, trim_sg = 0; VPRINTK("ENTER, ata%u\n", ap->print_id); @@ -4825,7 +4828,6 @@ void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, static void ata_pio_sector(struct ata_queued_cmd *qc) { int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - struct scatterlist *sg = qc->__sg; struct ata_port *ap = qc->ap; struct page *page; unsigned int offset; @@ -4834,8 +4836,8 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) if (qc->curbytes == qc->nbytes - qc->sect_size) ap->hsm_task_state = HSM_ST_LAST; - page = sg[qc->cursg].page; - offset = sg[qc->cursg].offset + qc->cursg_ofs; + page = qc->cursg->page; + offset = qc->cursg->offset + qc->cursg_ofs; /* get the current page and offset */ page = nth_page(page, (offset >> PAGE_SHIFT)); @@ -4863,8 +4865,8 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) qc->curbytes += qc->sect_size; qc->cursg_ofs += qc->sect_size; - if (qc->cursg_ofs == (&sg[qc->cursg])->length) { - qc->cursg++; + if (qc->cursg_ofs == qc->cursg->length) { + qc->cursg = sg_next(qc->cursg); qc->cursg_ofs = 0; } } @@ -4950,16 +4952,18 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) { int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); struct scatterlist *sg = qc->__sg; + struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem); struct ata_port *ap = qc->ap; struct page *page; unsigned char *buf; unsigned int offset, count; + int no_more_sg = 0; if (qc->curbytes + bytes >= qc->nbytes) ap->hsm_task_state = HSM_ST_LAST; next_sg: - if (unlikely(qc->cursg >= qc->n_elem)) { + if (unlikely(no_more_sg)) { /* * The end of qc->sg is reached and the device expects * more data to transfer. In order not to overrun qc->sg @@ -4982,7 +4986,7 @@ next_sg: return; } - sg = &qc->__sg[qc->cursg]; + sg = qc->cursg; page = sg->page; offset = sg->offset + qc->cursg_ofs; @@ -5021,7 +5025,10 @@ next_sg: qc->cursg_ofs += count; if (qc->cursg_ofs == sg->length) { - qc->cursg++; + if (qc->cursg == lsg) + no_more_sg = 1; + + qc->cursg = sg_next(qc->cursg); qc->cursg_ofs = 0; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d63c81ed084..9fbb39cd0f5 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -801,8 +801,6 @@ int ata_scsi_slave_config(struct scsi_device *sdev) ata_scsi_sdev_config(sdev); - blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD); - sdev->manage_start_stop = 1; if (dev) @@ -3240,7 +3238,7 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) /** * ata_scsi_media_change_notify - send media change event - * @atadev: Pointer to the disk device with media change event + * @dev: Pointer to the disk device with media change event * * Tell the block layer to send a media change notification * event. diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 7a1390cd6aa..c41d0728efe 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -238,7 +238,7 @@ store_mem_state(struct sys_device *dev, const char *buf, size_t count) mem = container_of(dev, struct memory_block, sysdev); phys_section_nr = mem->phys_index; - if (!valid_section_nr(phys_section_nr)) + if (!present_section_nr(phys_section_nr)) goto out; if (!strncmp(buf, "online", min((int)count, 6))) @@ -418,7 +418,7 @@ int register_new_memory(struct mem_section *section) int unregister_memory_section(struct mem_section *section) { - if (!valid_section(section)) + if (!present_section(section)) return -EINVAL; return remove_memory_block(0, section, 0); @@ -443,7 +443,7 @@ int __init memory_dev_init(void) * during boot and have been initialized */ for (i = 0; i < NR_MEM_SECTIONS; i++) { - if (!valid_section_nr(i)) + if (!present_section_nr(i)) continue; err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); if (!ret) diff --git a/drivers/base/node.c b/drivers/base/node.c index cae346ef1b2..88eeed72b5d 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -12,6 +12,7 @@ #include <linux/topology.h> #include <linux/nodemask.h> #include <linux/cpu.h> +#include <linux/device.h> static struct sysdev_class node_class = { set_kset_name("node"), @@ -232,8 +233,96 @@ void unregister_one_node(int nid) unregister_node(&node_devices[nid]); } +/* + * node states attributes + */ + +static ssize_t print_nodes_state(enum node_states state, char *buf) +{ + int n; + + n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]); + if (n > 0 && PAGE_SIZE > n + 1) { + *(buf + n++) = '\n'; + *(buf + n++) = '\0'; + } + return n; +} + +static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf) +{ + return print_nodes_state(N_POSSIBLE, buf); +} + +static ssize_t print_nodes_online(struct sysdev_class *class, char *buf) +{ + return print_nodes_state(N_ONLINE, buf); +} + +static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class, + char *buf) +{ + return print_nodes_state(N_NORMAL_MEMORY, buf); +} + +static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf) +{ + return print_nodes_state(N_CPU, buf); +} + +static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL); +static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL); +static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory, + NULL); +static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL); + +#ifdef CONFIG_HIGHMEM +static ssize_t print_nodes_has_high_memory(struct sysdev_class *class, + char *buf) +{ + return print_nodes_state(N_HIGH_MEMORY, buf); +} + +static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory, + NULL); +#endif + +struct sysdev_class_attribute *node_state_attr[] = { + &attr_possible, + &attr_online, + &attr_has_normal_memory, +#ifdef CONFIG_HIGHMEM + &attr_has_high_memory, +#endif + &attr_has_cpu, +}; + +static int node_states_init(void) +{ + int i; + int err = 0; + + for (i = 0; i < NR_NODE_STATES; i++) { + int ret; + ret = sysdev_class_create_file(&node_class, node_state_attr[i]); + if (!err) + err = ret; + } + return err; +} + static int __init register_node_type(void) { - return sysdev_class_register(&node_class); + int ret; + + ret = sysdev_class_register(&node_class); + if (!ret) + ret = node_states_init(); + + /* + * Note: we're not going to unregister the node class if we fail + * to register the node state class attribute files. + */ + return ret; } postcore_initcall(register_node_type); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 55c3237fb1b..3fb7e8bc436 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1191,7 +1191,6 @@ static inline void complete_buffers(struct bio *bio, int status) { while (bio) { struct bio *xbh = bio->bi_next; - int nr_sectors = bio_sectors(bio); bio->bi_next = NULL; bio_endio(bio, status ? 0 : -EIO); @@ -2570,6 +2569,7 @@ static void do_cciss_request(struct request_queue *q) (int)creq->nr_sectors); #endif /* CCISS_DEBUG */ + memset(tmp_sg, 0, sizeof(tmp_sg)); seg = blk_rq_map_sg(q, creq, tmp_sg); /* get the DMA records for the setup */ diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 3853c9a38d6..568603d3043 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -981,9 +981,8 @@ static void start_io(ctlr_info_t *h) static inline void complete_buffers(struct bio *bio, int ok) { struct bio *xbh; - while(bio) { - int nr_sectors = bio_sectors(bio); + while (bio) { xbh = bio->bi_next; bio->bi_next = NULL; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b9233a06934..e5a051577a5 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -204,14 +204,13 @@ lo_do_transfer(struct loop_device *lo, int cmd, * do_lo_send_aops - helper for writing data to a loop device * * This is the fast version for backing filesystems which implement the address - * space operations prepare_write and commit_write. + * space operations write_begin and write_end. */ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec, - int bsize, loff_t pos, struct page *page) + int bsize, loff_t pos, struct page *unused) { struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ struct address_space *mapping = file->f_mapping; - const struct address_space_operations *aops = mapping->a_ops; pgoff_t index; unsigned offset, bv_offs; int len, ret; @@ -223,63 +222,45 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec, len = bvec->bv_len; while (len > 0) { sector_t IV; - unsigned size; + unsigned size, copied; int transfer_result; + struct page *page; + void *fsdata; IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9); size = PAGE_CACHE_SIZE - offset; if (size > len) size = len; - page = grab_cache_page(mapping, index); - if (unlikely(!page)) + + ret = pagecache_write_begin(file, mapping, pos, size, 0, + &page, &fsdata); + if (ret) goto fail; - ret = aops->prepare_write(file, page, offset, - offset + size); - if (unlikely(ret)) { - if (ret == AOP_TRUNCATED_PAGE) { - page_cache_release(page); - continue; - } - goto unlock; - } + transfer_result = lo_do_transfer(lo, WRITE, page, offset, bvec->bv_page, bv_offs, size, IV); - if (unlikely(transfer_result)) { - /* - * The transfer failed, but we still write the data to - * keep prepare/commit calls balanced. - */ - printk(KERN_ERR "loop: transfer error block %llu\n", - (unsigned long long)index); - zero_user_page(page, offset, size, KM_USER0); - } - flush_dcache_page(page); - ret = aops->commit_write(file, page, offset, - offset + size); - if (unlikely(ret)) { - if (ret == AOP_TRUNCATED_PAGE) { - page_cache_release(page); - continue; - } - goto unlock; - } + copied = size; if (unlikely(transfer_result)) - goto unlock; - bv_offs += size; - len -= size; + copied = 0; + + ret = pagecache_write_end(file, mapping, pos, size, copied, + page, fsdata); + if (ret < 0 || ret != copied) + goto fail; + + if (unlikely(transfer_result)) + goto fail; + + bv_offs += copied; + len -= copied; offset = 0; index++; - pos += size; - unlock_page(page); - page_cache_release(page); + pos += copied; } ret = 0; out: mutex_unlock(&mapping->host->i_mutex); return ret; -unlock: - unlock_page(page); - page_cache_release(page); fail: ret = -1; goto out; @@ -313,7 +294,7 @@ static int __do_lo_send_write(struct file *file, * do_lo_send_direct_write - helper for writing data to a loop device * * This is the fast, non-transforming version for backing filesystems which do - * not implement the address space operations prepare_write and commit_write. + * not implement the address space operations write_begin and write_end. * It uses the write file operation which should be present on all writeable * filesystems. */ @@ -332,7 +313,7 @@ static int do_lo_send_direct_write(struct loop_device *lo, * do_lo_send_write - helper for writing data to a loop device * * This is the slow, transforming version for filesystems which do not - * implement the address space operations prepare_write and commit_write. It + * implement the address space operations write_begin and write_end. It * uses the write file operation which should be present on all writeable * filesystems. * @@ -780,7 +761,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, */ if (!file->f_op->splice_read) goto out_putf; - if (aops->prepare_write && aops->commit_write) + if (aops->prepare_write || aops->write_begin) lo_flags |= LO_FLAGS_USE_AOPS; if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) lo_flags |= LO_FLAGS_READ_ONLY; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 540bf367698..a8130a4ad6d 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1133,16 +1133,21 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) * Schedule reads for missing parts of the packet. */ for (f = 0; f < pkt->frames; f++) { + struct bio_vec *vec; + int p, offset; if (written[f]) continue; bio = pkt->r_bios[f]; + vec = bio->bi_io_vec; bio_init(bio); bio->bi_max_vecs = 1; bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); bio->bi_bdev = pd->bdev; bio->bi_end_io = pkt_end_io_read; bio->bi_private = pkt; + bio->bi_io_vec = vec; + bio->bi_destructor = pkt_bio_destructor; p = (f * CD_FRAMESIZE) / PAGE_SIZE; offset = (f * CD_FRAMESIZE) % PAGE_SIZE; @@ -1439,6 +1444,8 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) pkt->w_bio->bi_bdev = pd->bdev; pkt->w_bio->bi_end_io = pkt_end_io_packet_write; pkt->w_bio->bi_private = pkt; + pkt->w_bio->bi_io_vec = bvec; + pkt->w_bio->bi_destructor = pkt_bio_destructor; for (f = 0; f < pkt->frames; f++) if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset)) BUG(); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 06d0552cf49..e354bfc070e 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -414,26 +414,6 @@ static void ps3disk_prepare_flush(struct request_queue *q, struct request *req) req->cmd_type = REQ_TYPE_FLUSH; } -static int ps3disk_issue_flush(struct request_queue *q, struct gendisk *gendisk, - sector_t *sector) -{ - struct ps3_storage_device *dev = q->queuedata; - struct request *req; - int res; - - dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); - - req = blk_get_request(q, WRITE, __GFP_WAIT); - ps3disk_prepare_flush(q, req); - res = blk_execute_rq(q, gendisk, req, 0); - if (res) - dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n", - __func__, __LINE__, res); - blk_put_request(req); - return res; -} - - static unsigned long ps3disk_mask; static DEFINE_MUTEX(ps3disk_mask_mutex); @@ -506,7 +486,6 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) blk_queue_dma_alignment(queue, dev->blk_size-1); blk_queue_hardsect_size(queue, dev->blk_size); - blk_queue_issue_flush_fn(queue, ps3disk_issue_flush); blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH, ps3disk_prepare_flush); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index b391776e5bf..f6f8c03047f 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -896,10 +896,6 @@ config GPIO_TB0219 depends on TANBAC_TB022X select GPIO_VR41XX -source "drivers/char/agp/Kconfig" - -source "drivers/char/drm/Kconfig" - source "drivers/char/pcmcia/Kconfig" config MWAVE diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 713533d8a86..f22c253bc09 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -1,4 +1,4 @@ -config AGP +menuconfig AGP tristate "/dev/agpgart (AGP Support)" depends on ALPHA || IA64 || PARISC || PPC || X86 depends on PCI diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index 0b7ffa5191c..ba3058dd39a 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig @@ -4,7 +4,7 @@ # This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. # -config DRM +menuconfig DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG help diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index f89e57665b6..2b2407ee490 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c @@ -144,8 +144,8 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) return ret; } -int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence, - int crtc) +static int radeon_driver_vblank_do_wait(struct drm_device * dev, + unsigned int *sequence, int crtc) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index bbee97ff355..64551ab6be0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -625,65 +625,10 @@ static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out, return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); } -#ifdef CONFIG_MMU -/* - * For fun, we are using the MMU for this. - */ -static inline size_t read_zero_pagealigned(char __user * buf, size_t size) -{ - struct mm_struct *mm; - struct vm_area_struct * vma; - unsigned long addr=(unsigned long)buf; - - mm = current->mm; - /* Oops, this was forgotten before. -ben */ - down_read(&mm->mmap_sem); - - /* For private mappings, just map in zero pages. */ - for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { - unsigned long count; - - if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0) - goto out_up; - if (vma->vm_flags & (VM_SHARED | VM_HUGETLB)) - break; - count = vma->vm_end - addr; - if (count > size) - count = size; - - zap_page_range(vma, addr, count, NULL); - if (zeromap_page_range(vma, addr, count, PAGE_COPY)) - break; - - size -= count; - buf += count; - addr += count; - if (size == 0) - goto out_up; - } - - up_read(&mm->mmap_sem); - - /* The shared case is hard. Let's do the conventional zeroing. */ - do { - unsigned long unwritten = clear_user(buf, PAGE_SIZE); - if (unwritten) - return size + unwritten - PAGE_SIZE; - cond_resched(); - buf += PAGE_SIZE; - size -= PAGE_SIZE; - } while (size); - - return size; -out_up: - up_read(&mm->mmap_sem); - return size; -} - static ssize_t read_zero(struct file * file, char __user * buf, size_t count, loff_t *ppos) { - unsigned long left, unwritten, written = 0; + size_t written; if (!count) return 0; @@ -691,69 +636,33 @@ static ssize_t read_zero(struct file * file, char __user * buf, if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; - left = count; - - /* do we want to be clever? Arbitrary cut-off */ - if (count >= PAGE_SIZE*4) { - unsigned long partial; + written = 0; + while (count) { + unsigned long unwritten; + size_t chunk = count; - /* How much left of the page? */ - partial = (PAGE_SIZE-1) & -(unsigned long) buf; - unwritten = clear_user(buf, partial); - written = partial - unwritten; - if (unwritten) - goto out; - left -= partial; - buf += partial; - unwritten = read_zero_pagealigned(buf, left & PAGE_MASK); - written += (left & PAGE_MASK) - unwritten; + if (chunk > PAGE_SIZE) + chunk = PAGE_SIZE; /* Just for latency reasons */ + unwritten = clear_user(buf, chunk); + written += chunk - unwritten; if (unwritten) - goto out; - buf += left & PAGE_MASK; - left &= ~PAGE_MASK; - } - unwritten = clear_user(buf, left); - written += left - unwritten; -out: - return written ? written : -EFAULT; -} - -static int mmap_zero(struct file * file, struct vm_area_struct * vma) -{ - int err; - - if (vma->vm_flags & VM_SHARED) - return shmem_zero_setup(vma); - err = zeromap_page_range(vma, vma->vm_start, - vma->vm_end - vma->vm_start, vma->vm_page_prot); - BUG_ON(err == -EEXIST); - return err; -} -#else /* CONFIG_MMU */ -static ssize_t read_zero(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - size_t todo = count; - - while (todo) { - size_t chunk = todo; - - if (chunk > 4096) - chunk = 4096; /* Just for latency reasons */ - if (clear_user(buf, chunk)) - return -EFAULT; + break; buf += chunk; - todo -= chunk; + count -= chunk; cond_resched(); } - return count; + return written ? written : -EFAULT; } static int mmap_zero(struct file * file, struct vm_area_struct * vma) { +#ifndef CONFIG_MMU return -ENOSYS; +#endif + if (vma->vm_flags & VM_SHARED) + return shmem_zero_setup(vma); + return 0; } -#endif /* CONFIG_MMU */ static ssize_t write_full(struct file * file, const char __user * buf, size_t count, loff_t *ppos) diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 04ac155d3a0..82f2e27dca7 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -362,7 +362,7 @@ mspec_init(void) is_sn2 = 1; if (is_shub2()) { ret = -ENOMEM; - for_each_online_node(nid) { + for_each_node_state(nid, N_ONLINE) { int actual_nid; int nasid; unsigned long phys; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index edb7002a321..0d56f8fc105 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -750,13 +750,15 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ return 0; } -static inline int resize_screen(struct vc_data *vc, int width, int height) +static inline int resize_screen(struct vc_data *vc, int width, int height, + int user) { /* Resizes the resolution of the display adapater */ int err = 0; if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) - err = vc->vc_sw->con_resize(vc, width, height); + err = vc->vc_sw->con_resize(vc, width, height, user); + return err; } @@ -772,7 +774,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned int old_cols, old_rows, old_row_size, old_screen_size; unsigned int new_cols, new_rows, new_row_size, new_screen_size; - unsigned int end; + unsigned int end, user; unsigned short *newscreen; WARN_CONSOLE_UNLOCKED(); @@ -780,6 +782,9 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) if (!vc) return -ENXIO; + user = vc->vc_resize_user; + vc->vc_resize_user = 0; + if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) return -EINVAL; @@ -800,7 +805,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) old_row_size = vc->vc_size_row; old_screen_size = vc->vc_screenbuf_size; - err = resize_screen(vc, new_cols, new_rows); + err = resize_screen(vc, new_cols, new_rows, user); if (err) { kfree(newscreen); return err; diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 7a61a2a9aaf..f69a8258095 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -847,14 +847,24 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case VT_RESIZE: { struct vt_sizes __user *vtsizes = up; + struct vc_data *vc; + ushort ll,cc; if (!perm) return -EPERM; if (get_user(ll, &vtsizes->v_rows) || get_user(cc, &vtsizes->v_cols)) return -EFAULT; - for (i = 0; i < MAX_NR_CONSOLES; i++) - vc_lock_resize(vc_cons[i].d, cc, ll); + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vc_cons[i].d; + + if (vc) { + vc->vc_resize_user = 1; + vc_lock_resize(vc_cons[i].d, cc, ll); + } + } + return 0; } @@ -900,6 +910,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vc_cons[i].d->vc_scan_lines = vlin; if (clin) vc_cons[i].d->vc_font.height = clin; + vc_cons[i].d->vc_resize_user = 1; vc_resize(vc_cons[i].d, cc, ll); release_console_sem(); } diff --git a/drivers/dca/Kconfig b/drivers/dca/Kconfig new file mode 100644 index 00000000000..94f0364a0ef --- /dev/null +++ b/drivers/dca/Kconfig @@ -0,0 +1,7 @@ +# +# DCA server configuration +# + +config DCA + tristate + diff --git a/drivers/dca/Makefile b/drivers/dca/Makefile new file mode 100644 index 00000000000..b2db56bb9dd --- /dev/null +++ b/drivers/dca/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_DCA) += dca.o +dca-objs := dca-core.o dca-sysfs.o diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c new file mode 100644 index 00000000000..bf5b92f86df --- /dev/null +++ b/drivers/dca/dca-core.c @@ -0,0 +1,200 @@ +/* + * Copyright(c) 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ + +/* + * This driver supports an interface for DCA clients and providers to meet. + */ + +#include <linux/kernel.h> +#include <linux/notifier.h> +#include <linux/device.h> +#include <linux/dca.h> + +MODULE_LICENSE("GPL"); + +/* For now we're assuming a single, global, DCA provider for the system. */ + +static DEFINE_SPINLOCK(dca_lock); + +static struct dca_provider *global_dca = NULL; + +/** + * dca_add_requester - add a dca client to the list + * @dev - the device that wants dca service + */ +int dca_add_requester(struct device *dev) +{ + int err, slot; + + if (!global_dca) + return -ENODEV; + + spin_lock(&dca_lock); + slot = global_dca->ops->add_requester(global_dca, dev); + spin_unlock(&dca_lock); + if (slot < 0) + return slot; + + err = dca_sysfs_add_req(global_dca, dev, slot); + if (err) { + spin_lock(&dca_lock); + global_dca->ops->remove_requester(global_dca, dev); + spin_unlock(&dca_lock); + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(dca_add_requester); + +/** + * dca_remove_requester - remove a dca client from the list + * @dev - the device that wants dca service + */ +int dca_remove_requester(struct device *dev) +{ + int slot; + if (!global_dca) + return -ENODEV; + + spin_lock(&dca_lock); + slot = global_dca->ops->remove_requester(global_dca, dev); + spin_unlock(&dca_lock); + if (slot < 0) + return slot; + + dca_sysfs_remove_req(global_dca, slot); + return 0; +} +EXPORT_SYMBOL_GPL(dca_remove_requester); + +/** + * dca_get_tag - return the dca tag for the given cpu + * @cpu - the cpuid as returned by get_cpu() + */ +u8 dca_get_tag(int cpu) +{ + if (!global_dca) + return -ENODEV; + return global_dca->ops->get_tag(global_dca, cpu); +} +EXPORT_SYMBOL_GPL(dca_get_tag); + +/** + * alloc_dca_provider - get data struct for describing a dca provider + * @ops - pointer to struct of dca operation function pointers + * @priv_size - size of extra mem to be added for provider's needs + */ +struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size) +{ + struct dca_provider *dca; + int alloc_size; + + alloc_size = (sizeof(*dca) + priv_size); + dca = kzalloc(alloc_size, GFP_KERNEL); + if (!dca) + return NULL; + dca->ops = ops; + + return dca; +} +EXPORT_SYMBOL_GPL(alloc_dca_provider); + +/** + * free_dca_provider - release the dca provider data struct + * @ops - pointer to struct of dca operation function pointers + * @priv_size - size of extra mem to be added for provider's needs + */ +void free_dca_provider(struct dca_provider *dca) +{ + kfree(dca); +} +EXPORT_SYMBOL_GPL(free_dca_provider); + +static BLOCKING_NOTIFIER_HEAD(dca_provider_chain); + +/** + * register_dca_provider - register a dca provider + * @dca - struct created by alloc_dca_provider() + * @dev - device providing dca services + */ +int register_dca_provider(struct dca_provider *dca, struct device *dev) +{ + int err; + + if (global_dca) + return -EEXIST; + err = dca_sysfs_add_provider(dca, dev); + if (err) + return err; + global_dca = dca; + blocking_notifier_call_chain(&dca_provider_chain, + DCA_PROVIDER_ADD, NULL); + return 0; +} +EXPORT_SYMBOL_GPL(register_dca_provider); + +/** + * unregister_dca_provider - remove a dca provider + * @dca - struct created by alloc_dca_provider() + */ +void unregister_dca_provider(struct dca_provider *dca) +{ + if (!global_dca) + return; + blocking_notifier_call_chain(&dca_provider_chain, + DCA_PROVIDER_REMOVE, NULL); + global_dca = NULL; + dca_sysfs_remove_provider(dca); +} +EXPORT_SYMBOL_GPL(unregister_dca_provider); + +/** + * dca_register_notify - register a client's notifier callback + */ +void dca_register_notify(struct notifier_block *nb) +{ + blocking_notifier_chain_register(&dca_provider_chain, nb); +} +EXPORT_SYMBOL_GPL(dca_register_notify); + +/** + * dca_unregister_notify - remove a client's notifier callback + */ +void dca_unregister_notify(struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&dca_provider_chain, nb); +} +EXPORT_SYMBOL_GPL(dca_unregister_notify); + +static int __init dca_init(void) +{ + return dca_sysfs_init(); +} + +static void __exit dca_exit(void) +{ + dca_sysfs_exit(); +} + +module_init(dca_init); +module_exit(dca_exit); + diff --git a/drivers/dca/dca-sysfs.c b/drivers/dca/dca-sysfs.c new file mode 100644 index 00000000000..24a263b6844 --- /dev/null +++ b/drivers/dca/dca-sysfs.c @@ -0,0 +1,88 @@ +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/device.h> +#include <linux/idr.h> +#include <linux/kdev_t.h> +#include <linux/err.h> +#include <linux/dca.h> + +static struct class *dca_class; +static struct idr dca_idr; +static spinlock_t dca_idr_lock; + +int dca_sysfs_add_req(struct dca_provider *dca, struct device *dev, int slot) +{ + struct class_device *cd; + + cd = class_device_create(dca_class, dca->cd, MKDEV(0, slot + 1), + dev, "requester%d", slot); + if (IS_ERR(cd)) + return PTR_ERR(cd); + return 0; +} + +void dca_sysfs_remove_req(struct dca_provider *dca, int slot) +{ + class_device_destroy(dca_class, MKDEV(0, slot + 1)); +} + +int dca_sysfs_add_provider(struct dca_provider *dca, struct device *dev) +{ + struct class_device *cd; + int err = 0; + +idr_try_again: + if (!idr_pre_get(&dca_idr, GFP_KERNEL)) + return -ENOMEM; + spin_lock(&dca_idr_lock); + err = idr_get_new(&dca_idr, dca, &dca->id); + spin_unlock(&dca_idr_lock); + switch (err) { + case 0: + break; + case -EAGAIN: + goto idr_try_again; + default: + return err; + } + + cd = class_device_create(dca_class, NULL, MKDEV(0, 0), + dev, "dca%d", dca->id); + if (IS_ERR(cd)) { + spin_lock(&dca_idr_lock); + idr_remove(&dca_idr, dca->id); + spin_unlock(&dca_idr_lock); + return PTR_ERR(cd); + } + dca->cd = cd; + return 0; +} + +void dca_sysfs_remove_provider(struct dca_provider *dca) +{ + class_device_unregister(dca->cd); + dca->cd = NULL; + spin_lock(&dca_idr_lock); + idr_remove(&dca_idr, dca->id); + spin_unlock(&dca_idr_lock); +} + +int __init dca_sysfs_init(void) +{ + idr_init(&dca_idr); + spin_lock_init(&dca_idr_lock); + + dca_class = class_create(THIS_MODULE, "dca"); + if (IS_ERR(dca_class)) { + idr_destroy(&dca_idr); + return PTR_ERR(dca_class); + } + return 0; +} + +void __exit dca_sysfs_exit(void) +{ + class_destroy(dca_class); + idr_destroy(&dca_idr); +} + diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 8f670dae53b..9c91b0fd134 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -2,42 +2,52 @@ # DMA engine configuration # -menu "DMA Engine support" - depends on HAS_DMA +menuconfig DMADEVICES + bool "DMA Offload Engine support" + depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX + help + Intel(R) offload engines enable offloading memory copies in the + network stack and RAID operations in the MD driver. + +if DMADEVICES + +comment "DMA Devices" + +config INTEL_IOATDMA + tristate "Intel I/OAT DMA support" + depends on PCI && X86 + select DMA_ENGINE + select DCA + help + Enable support for the Intel(R) I/OAT DMA engine present + in recent Intel Xeon chipsets. + + Say Y here if you have such a chipset. + + If unsure, say N. + +config INTEL_IOP_ADMA + tristate "Intel IOP ADMA support" + depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX + select ASYNC_CORE + select DMA_ENGINE + help + Enable support for the Intel(R) IOP Series RAID engines. config DMA_ENGINE - bool "Support for DMA engines" - ---help--- - DMA engines offload bulk memory operations from the CPU to dedicated - hardware, allowing the operations to happen asynchronously. + bool comment "DMA Clients" + depends on DMA_ENGINE config NET_DMA bool "Network: TCP receive copy offload" depends on DMA_ENGINE && NET default y - ---help--- + help This enables the use of DMA engines in the network stack to offload receive copy-to-user operations, freeing CPU cycles. Since this is the main user of the DMA engine, it should be enabled; say Y here. -comment "DMA Devices" - -config INTEL_IOATDMA - tristate "Intel I/OAT DMA support" - depends on DMA_ENGINE && PCI - default m - ---help--- - Enable support for the Intel(R) I/OAT DMA engine. - -config INTEL_IOP_ADMA - tristate "Intel IOP ADMA support" - depends on DMA_ENGINE && (ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX) - select ASYNC_CORE - default m - ---help--- - Enable support for the Intel(R) IOP Series RAID engines. - -endmenu +endif diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index b3839b687ae..b152cd84e12 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_DMA_ENGINE) += dmaengine.o obj-$(CONFIG_NET_DMA) += iovlock.o obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o +ioatdma-objs := ioat.o ioat_dma.o ioat_dca.o obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c new file mode 100644 index 00000000000..f7276bf2fe7 --- /dev/null +++ b/drivers/dma/ioat.c @@ -0,0 +1,211 @@ +/* + * Intel I/OAT DMA Linux driver + * Copyright(c) 2007 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +/* + * This driver supports an Intel I/OAT DMA engine, which does asynchronous + * copy operations. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/dca.h> +#include "ioatdma.h" +#include "ioatdma_registers.h" +#include "ioatdma_hw.h" + +MODULE_VERSION("1.24"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Intel Corporation"); + +static struct pci_device_id ioat_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) }, + { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) }, + { 0, } +}; + +struct ioat_device { + struct pci_dev *pdev; + void __iomem *iobase; + struct ioatdma_device *dma; + struct dca_provider *dca; +}; + +static int __devinit ioat_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +#ifdef IOAT_DMA_REMOVE +static void __devexit ioat_remove(struct pci_dev *pdev); +#endif + +static int ioat_dca_enabled = 1; +module_param(ioat_dca_enabled, int, 0644); +MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)"); + +static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase) +{ + struct ioat_device *device = pci_get_drvdata(pdev); + u8 version; + int err = 0; + + version = readb(iobase + IOAT_VER_OFFSET); + switch (version) { + case IOAT_VER_1_2: + device->dma = ioat_dma_probe(pdev, iobase); + if (ioat_dca_enabled) + device->dca = ioat_dca_init(pdev, iobase); + break; + default: + err = -ENODEV; + break; + } + return err; +} + +static void ioat_shutdown_functionality(struct pci_dev *pdev) +{ + struct ioat_device *device = pci_get_drvdata(pdev); + + if (device->dma) { + ioat_dma_remove(device->dma); + device->dma = NULL; + } + + if (device->dca) { + unregister_dca_provider(device->dca); + free_dca_provider(device->dca); + device->dca = NULL; + } + +} + +static struct pci_driver ioat_pci_drv = { + .name = "ioatdma", + .id_table = ioat_pci_tbl, + .probe = ioat_probe, + .shutdown = ioat_shutdown_functionality, +#ifdef IOAT_DMA_REMOVE + .remove = __devexit_p(ioat_remove), +#endif +}; + +static int __devinit ioat_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *iobase; + struct ioat_device *device; + unsigned long mmio_start, mmio_len; + int err; + + err = pci_enable_device(pdev); + if (err) + goto err_enable_device; + + err = pci_request_regions(pdev, ioat_pci_drv.name); + if (err) + goto err_request_regions; + + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (err) + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) + goto err_set_dma_mask; + + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) + goto err_set_dma_mask; + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + iobase = ioremap(mmio_start, mmio_len); + if (!iobase) { + err = -ENOMEM; + goto err_ioremap; + } + + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) { + err = -ENOMEM; + goto err_kzalloc; + } + device->pdev = pdev; + pci_set_drvdata(pdev, device); + device->iobase = iobase; + + pci_set_master(pdev); + + err = ioat_setup_functionality(pdev, iobase); + if (err) + goto err_version; + + return 0; + +err_version: + kfree(device); +err_kzalloc: + iounmap(iobase); +err_ioremap: +err_set_dma_mask: + pci_release_regions(pdev); + pci_disable_device(pdev); +err_request_regions: +err_enable_device: + return err; +} + +#ifdef IOAT_DMA_REMOVE +/* + * It is unsafe to remove this module: if removed while a requested + * dma is outstanding, esp. from tcp, it is possible to hang while + * waiting for something that will never finish, thus hanging at + * least one cpu. However, if you're feeling lucky and need to do + * some testing, this usually works just fine. + */ +static void __devexit ioat_remove(struct pci_dev *pdev) +{ + struct ioat_device *device = pci_get_drvdata(pdev); + + ioat_shutdown_functionality(pdev); + + kfree(device); + + iounmap(device->iobase); + pci_release_regions(pdev); + pci_disable_device(pdev); +} +#endif + +static int __init ioat_init_module(void) +{ + return pci_register_driver(&ioat_pci_drv); +} +module_init(ioat_init_module); + +static void __exit ioat_exit_module(void) +{ + pci_unregister_driver(&ioat_pci_drv); +} +module_exit(ioat_exit_module); diff --git a/drivers/dma/ioat_dca.c b/drivers/dma/ioat_dca.c new file mode 100644 index 00000000000..2ae04c30ede --- /dev/null +++ b/drivers/dma/ioat_dca.c @@ -0,0 +1,263 @@ +/* + * Intel I/OAT DMA Linux driver + * Copyright(c) 2007 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/smp.h> +#include <linux/interrupt.h> +#include <linux/dca.h> + +/* either a kernel change is needed, or we need something like this in kernel */ +#ifndef CONFIG_SMP +#include <asm/smp.h> +#undef cpu_physical_id +#define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24) +#endif + +#include "ioatdma.h" +#include "ioatdma_registers.h" + +/* + * Bit 16 of a tag map entry is the "valid" bit, if it is set then bits 0:15 + * contain the bit number of the APIC ID to map into the DCA tag. If the valid + * bit is not set, then the value must be 0 or 1 and defines the bit in the tag. + */ +#define DCA_TAG_MAP_VALID 0x80 + +/* + * "Legacy" DCA systems do not implement the DCA register set in the + * I/OAT device. Software needs direct support for their tag mappings. + */ + +#define APICID_BIT(x) (DCA_TAG_MAP_VALID | (x)) +#define IOAT_TAG_MAP_LEN 8 + +static u8 ioat_tag_map_BNB[IOAT_TAG_MAP_LEN] = { + 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), }; +static u8 ioat_tag_map_SCNB[IOAT_TAG_MAP_LEN] = { + 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), }; +static u8 ioat_tag_map_CNB[IOAT_TAG_MAP_LEN] = { + 1, APICID_BIT(1), APICID_BIT(3), APICID_BIT(4), APICID_BIT(2), }; +static u8 ioat_tag_map_UNISYS[IOAT_TAG_MAP_LEN] = { 0 }; + +/* pack PCI B/D/F into a u16 */ +static inline u16 dcaid_from_pcidev(struct pci_dev *pci) +{ + return (pci->bus->number << 8) | pci->devfn; +} + +static int dca_enabled_in_bios(void) +{ + /* CPUID level 9 returns DCA configuration */ + /* Bit 0 indicates DCA enabled by the BIOS */ + unsigned long cpuid_level_9; + int res; + + cpuid_level_9 = cpuid_eax(9); + res = test_bit(0, &cpuid_level_9); + if (!res) + printk(KERN_ERR "ioat dma: DCA is disabled in BIOS\n"); + + return res; +} + +static int system_has_dca_enabled(void) +{ + if (boot_cpu_has(X86_FEATURE_DCA)) + return dca_enabled_in_bios(); + + printk(KERN_ERR "ioat dma: boot cpu doesn't have X86_FEATURE_DCA\n"); + return 0; +} + +struct ioat_dca_slot { + struct pci_dev *pdev; /* requester device */ + u16 rid; /* requester id, as used by IOAT */ +}; + +#define IOAT_DCA_MAX_REQ 6 + +struct ioat_dca_priv { + void __iomem *iobase; + void *dca_base; + int max_requesters; + int requester_count; + u8 tag_map[IOAT_TAG_MAP_LEN]; + struct ioat_dca_slot req_slots[0]; +}; + +/* 5000 series chipset DCA Port Requester ID Table Entry Format + * [15:8] PCI-Express Bus Number + * [7:3] PCI-Express Device Number + * [2:0] PCI-Express Function Number + * + * 5000 series chipset DCA control register format + * [7:1] Reserved (0) + * [0] Ignore Function Number + */ + +static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev) +{ + struct ioat_dca_priv *ioatdca = dca_priv(dca); + struct pci_dev *pdev; + int i; + u16 id; + + /* This implementation only supports PCI-Express */ + if (dev->bus != &pci_bus_type) + return -ENODEV; + pdev = to_pci_dev(dev); + id = dcaid_from_pcidev(pdev); + + if (ioatdca->requester_count == ioatdca->max_requesters) + return -ENODEV; + + for (i = 0; i < ioatdca->max_requesters; i++) { + if (ioatdca->req_slots[i].pdev == NULL) { + /* found an empty slot */ + ioatdca->requester_count++; + ioatdca->req_slots[i].pdev = pdev; + ioatdca->req_slots[i].rid = id; + writew(id, ioatdca->dca_base + (i * 4)); + /* make sure the ignore function bit is off */ + writeb(0, ioatdca->dca_base + (i * 4) + 2); + return i; + } + } + /* Error, ioatdma->requester_count is out of whack */ + return -EFAULT; +} + +static int ioat_dca_remove_requester(struct dca_provider *dca, + struct device *dev) +{ + struct ioat_dca_priv *ioatdca = dca_priv(dca); + struct pci_dev *pdev; + int i; + + /* This implementation only supports PCI-Express */ + if (dev->bus != &pci_bus_type) + return -ENODEV; + pdev = to_pci_dev(dev); + + for (i = 0; i < ioatdca->max_requesters; i++) { + if (ioatdca->req_slots[i].pdev == pdev) { + writew(0, ioatdca->dca_base + (i * 4)); + ioatdca->req_slots[i].pdev = NULL; + ioatdca->req_slots[i].rid = 0; + ioatdca->requester_count--; + return i; + } + } + return -ENODEV; +} + +static u8 ioat_dca_get_tag(struct dca_provider *dca, int cpu) +{ + struct ioat_dca_priv *ioatdca = dca_priv(dca); + int i, apic_id, bit, value; + u8 entry, tag; + + tag = 0; + apic_id = cpu_physical_id(cpu); + + for (i = 0; i < IOAT_TAG_MAP_LEN; i++) { + entry = ioatdca->tag_map[i]; + if (entry & DCA_TAG_MAP_VALID) { + bit = entry & ~DCA_TAG_MAP_VALID; + value = (apic_id & (1 << bit)) ? 1 : 0; + } else { + value = entry ? 1 : 0; + } + tag |= (value << i); + } + return tag; +} + +static struct dca_ops ioat_dca_ops = { + .add_requester = ioat_dca_add_requester, + .remove_requester = ioat_dca_remove_requester, + .get_tag = ioat_dca_get_tag, +}; + + +struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase) +{ + struct dca_provider *dca; + struct ioat_dca_priv *ioatdca; + u8 *tag_map = NULL; + int i; + int err; + + if (!system_has_dca_enabled()) + return NULL; + + /* I/OAT v1 systems must have a known tag_map to support DCA */ + switch (pdev->vendor) { + case PCI_VENDOR_ID_INTEL: + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_IOAT: + tag_map = ioat_tag_map_BNB; + break; + case PCI_DEVICE_ID_INTEL_IOAT_CNB: + tag_map = ioat_tag_map_CNB; + break; + case PCI_DEVICE_ID_INTEL_IOAT_SCNB: + tag_map = ioat_tag_map_SCNB; + break; + } + break; + case PCI_VENDOR_ID_UNISYS: + switch (pdev->device) { + case PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR: + tag_map = ioat_tag_map_UNISYS; + break; + } + break; + } + if (tag_map == NULL) + return NULL; + + dca = alloc_dca_provider(&ioat_dca_ops, + sizeof(*ioatdca) + + (sizeof(struct ioat_dca_slot) * IOAT_DCA_MAX_REQ)); + if (!dca) + return NULL; + + ioatdca = dca_priv(dca); + ioatdca->max_requesters = IOAT_DCA_MAX_REQ; + + ioatdca->dca_base = iobase + 0x54; + + /* copy over the APIC ID to DCA tag mapping */ + for (i = 0; i < IOAT_TAG_MAP_LEN; i++) + ioatdca->tag_map[i] = tag_map[i]; + + err = register_dca_provider(dca, &pdev->dev); + if (err) { + free_dca_provider(dca); + return NULL; + } + + return dca; +} + diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioat_dma.c index 41b18c5a314..66c5bb53211 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioat_dma.c @@ -1,10 +1,10 @@ /* - * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * Intel I/OAT DMA Linux driver + * Copyright(c) 2004 - 2007 Intel Corporation. * * 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. + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -12,11 +12,12 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. */ /* @@ -35,17 +36,77 @@ #include "ioatdma_registers.h" #include "ioatdma_hw.h" +#define INITIAL_IOAT_DESC_COUNT 128 + #define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common) -#define to_ioat_device(dev) container_of(dev, struct ioat_device, common) +#define to_ioatdma_device(dev) container_of(dev, struct ioatdma_device, common) #define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node) #define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx) /* internal functions */ -static int __devinit ioat_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -static void ioat_shutdown(struct pci_dev *pdev); -static void __devexit ioat_remove(struct pci_dev *pdev); +static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan); +static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan); -static int enumerate_dma_channels(struct ioat_device *device) +static struct ioat_dma_chan *ioat_lookup_chan_by_index(struct ioatdma_device *device, + int index) +{ + return device->idx[index]; +} + +/** + * ioat_dma_do_interrupt - handler used for single vector interrupt mode + * @irq: interrupt id + * @data: interrupt data + */ +static irqreturn_t ioat_dma_do_interrupt(int irq, void *data) +{ + struct ioatdma_device *instance = data; + struct ioat_dma_chan *ioat_chan; + unsigned long attnstatus; + int bit; + u8 intrctrl; + + intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET); + + if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN)) + return IRQ_NONE; + + if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) { + writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); + return IRQ_NONE; + } + + attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); + for_each_bit(bit, &attnstatus, BITS_PER_LONG) { + ioat_chan = ioat_lookup_chan_by_index(instance, bit); + tasklet_schedule(&ioat_chan->cleanup_task); + } + + writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); + return IRQ_HANDLED; +} + +/** + * ioat_dma_do_interrupt_msix - handler used for vector-per-channel interrupt mode + * @irq: interrupt id + * @data: interrupt data + */ +static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data) +{ + struct ioat_dma_chan *ioat_chan = data; + + tasklet_schedule(&ioat_chan->cleanup_task); + + return IRQ_HANDLED; +} + +static void ioat_dma_cleanup_tasklet(unsigned long data); + +/** + * ioat_dma_enumerate_channels - find and initialize the device's channels + * @device: the device to be enumerated + */ +static int ioat_dma_enumerate_channels(struct ioatdma_device *device) { u8 xfercap_scale; u32 xfercap; @@ -73,13 +134,19 @@ static int enumerate_dma_channels(struct ioat_device *device) /* This should be made common somewhere in dmaengine.c */ ioat_chan->common.device = &device->common; list_add_tail(&ioat_chan->common.device_node, - &device->common.channels); + &device->common.channels); + device->idx[i] = ioat_chan; + tasklet_init(&ioat_chan->cleanup_task, + ioat_dma_cleanup_tasklet, + (unsigned long) ioat_chan); + tasklet_disable(&ioat_chan->cleanup_task); } return device->common.chancnt; } -static void -ioat_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) +static void ioat_set_src(dma_addr_t addr, + struct dma_async_tx_descriptor *tx, + int index) { struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx); struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); @@ -93,8 +160,9 @@ ioat_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) } -static void -ioat_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) +static void ioat_set_dest(dma_addr_t addr, + struct dma_async_tx_descriptor *tx, + int index) { struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx); struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); @@ -107,8 +175,7 @@ ioat_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index) } } -static dma_cookie_t -ioat_tx_submit(struct dma_async_tx_descriptor *tx) +static dma_cookie_t ioat_tx_submit(struct dma_async_tx_descriptor *tx) { struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); struct ioat_desc_sw *desc = tx_to_ioat_desc(tx); @@ -141,27 +208,27 @@ ioat_tx_submit(struct dma_async_tx_descriptor *tx) if (append) writeb(IOAT_CHANCMD_APPEND, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET); - + return cookie; } static struct ioat_desc_sw *ioat_dma_alloc_descriptor( - struct ioat_dma_chan *ioat_chan, - gfp_t flags) + struct ioat_dma_chan *ioat_chan, + gfp_t flags) { struct ioat_dma_descriptor *desc; struct ioat_desc_sw *desc_sw; - struct ioat_device *ioat_device; + struct ioatdma_device *ioatdma_device; dma_addr_t phys; - ioat_device = to_ioat_device(ioat_chan->common.device); - desc = pci_pool_alloc(ioat_device->dma_pool, flags, &phys); + ioatdma_device = to_ioatdma_device(ioat_chan->common.device); + desc = pci_pool_alloc(ioatdma_device->dma_pool, flags, &phys); if (unlikely(!desc)) return NULL; desc_sw = kzalloc(sizeof(*desc_sw), flags); if (unlikely(!desc_sw)) { - pci_pool_free(ioat_device->dma_pool, desc, phys); + pci_pool_free(ioatdma_device->dma_pool, desc, phys); return NULL; } @@ -177,10 +244,6 @@ static struct ioat_desc_sw *ioat_dma_alloc_descriptor( return desc_sw; } -#define INITIAL_IOAT_DESC_COUNT 128 - -static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan); - /* returns the actual number of allocated descriptors */ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) { @@ -195,15 +258,16 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) if (!list_empty(&ioat_chan->free_desc)) return INITIAL_IOAT_DESC_COUNT; - /* Setup register to interrupt and write completion status on error */ + /* Setup register to interrupt and write completion status on error */ chanctrl = IOAT_CHANCTRL_ERR_INT_EN | IOAT_CHANCTRL_ANY_ERR_ABORT_EN | IOAT_CHANCTRL_ERR_COMPLETION_EN; - writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET); + writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET); chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET); if (chanerr) { - printk("IOAT: CHANERR = %x, clearing\n", chanerr); + dev_err(&ioat_chan->device->pdev->dev, + "ioatdma: CHANERR = %x, clearing\n", chanerr); writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET); } @@ -211,7 +275,8 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) for (i = 0; i < INITIAL_IOAT_DESC_COUNT; i++) { desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL); if (!desc) { - printk(KERN_ERR "IOAT: Only %d initial descriptors\n", i); + dev_err(&ioat_chan->device->pdev->dev, + "ioatdma: Only %d initial descriptors\n", i); break; } list_add_tail(&desc->node, &tmp_list); @@ -224,8 +289,8 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) /* doing 2 32bit writes to mmio since 1 64b write doesn't work */ ioat_chan->completion_virt = pci_pool_alloc(ioat_chan->device->completion_pool, - GFP_KERNEL, - &ioat_chan->completion_addr); + GFP_KERNEL, + &ioat_chan->completion_addr); memset(ioat_chan->completion_virt, 0, sizeof(*ioat_chan->completion_virt)); writel(((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF, @@ -233,54 +298,88 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) writel(((u64) ioat_chan->completion_addr) >> 32, ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); - ioat_start_null_desc(ioat_chan); + tasklet_enable(&ioat_chan->cleanup_task); + ioat_dma_start_null_desc(ioat_chan); return i; } -static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan); - static void ioat_dma_free_chan_resources(struct dma_chan *chan) { struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); - struct ioat_device *ioat_device = to_ioat_device(chan->device); + struct ioatdma_device *ioatdma_device = to_ioatdma_device(chan->device); struct ioat_desc_sw *desc, *_desc; - u16 chanctrl; int in_use_descs = 0; + tasklet_disable(&ioat_chan->cleanup_task); ioat_dma_memcpy_cleanup(ioat_chan); + /* Delay 100ms after reset to allow internal DMA logic to quiesce + * before removing DMA descriptor resources. + */ writeb(IOAT_CHANCMD_RESET, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET); + mdelay(100); spin_lock_bh(&ioat_chan->desc_lock); list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) { in_use_descs++; list_del(&desc->node); - pci_pool_free(ioat_device->dma_pool, desc->hw, + pci_pool_free(ioatdma_device->dma_pool, desc->hw, desc->async_tx.phys); kfree(desc); } list_for_each_entry_safe(desc, _desc, &ioat_chan->free_desc, node) { list_del(&desc->node); - pci_pool_free(ioat_device->dma_pool, desc->hw, + pci_pool_free(ioatdma_device->dma_pool, desc->hw, desc->async_tx.phys); kfree(desc); } spin_unlock_bh(&ioat_chan->desc_lock); - pci_pool_free(ioat_device->completion_pool, - ioat_chan->completion_virt, - ioat_chan->completion_addr); + pci_pool_free(ioatdma_device->completion_pool, + ioat_chan->completion_virt, + ioat_chan->completion_addr); /* one is ok since we left it on there on purpose */ if (in_use_descs > 1) - printk(KERN_ERR "IOAT: Freeing %d in use descriptors!\n", + dev_err(&ioat_chan->device->pdev->dev, + "ioatdma: Freeing %d in use descriptors!\n", in_use_descs - 1); ioat_chan->last_completion = ioat_chan->completion_addr = 0; + ioat_chan->pending = 0; +} +/** + * ioat_dma_get_next_descriptor - return the next available descriptor + * @ioat_chan: IOAT DMA channel handle + * + * Gets the next descriptor from the chain, and must be called with the + * channel's desc_lock held. Allocates more descriptors if the channel + * has run out. + */ +static struct ioat_desc_sw *ioat_dma_get_next_descriptor( + struct ioat_dma_chan *ioat_chan) +{ + struct ioat_desc_sw *new = NULL; + + if (!list_empty(&ioat_chan->free_desc)) { + new = to_ioat_desc(ioat_chan->free_desc.next); + list_del(&new->node); + } else { + /* try to get another desc */ + new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC); + /* will this ever happen? */ + /* TODO add upper limit on these */ + BUG_ON(!new); + } + + prefetch(new->hw); + return new; } -static struct dma_async_tx_descriptor * -ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en) +static struct dma_async_tx_descriptor *ioat_dma_prep_memcpy( + struct dma_chan *chan, + size_t len, + int int_en) { struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); struct ioat_desc_sw *first, *prev, *new; @@ -299,17 +398,7 @@ ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en) spin_lock_bh(&ioat_chan->desc_lock); while (len) { - if (!list_empty(&ioat_chan->free_desc)) { - new = to_ioat_desc(ioat_chan->free_desc.next); - list_del(&new->node); - } else { - /* try to get another desc */ - new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC); - /* will this ever happen? */ - /* TODO add upper limit on these */ - BUG_ON(!new); - } - + new = ioat_dma_get_next_descriptor(ioat_chan); copy = min((u32) len, ioat_chan->xfercap); new->hw->size = copy; @@ -343,12 +432,11 @@ ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en) return new ? &new->async_tx : NULL; } - /** - * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended descriptors to hw + * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended + * descriptors to hw * @chan: DMA channel handle */ - static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan) { struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); @@ -360,15 +448,23 @@ static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan) } } -static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) +static void ioat_dma_cleanup_tasklet(unsigned long data) +{ + struct ioat_dma_chan *chan = (void *)data; + ioat_dma_memcpy_cleanup(chan); + writew(IOAT_CHANCTRL_INT_DISABLE, + chan->reg_base + IOAT_CHANCTRL_OFFSET); +} + +static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) { unsigned long phys_complete; struct ioat_desc_sw *desc, *_desc; dma_cookie_t cookie = 0; - prefetch(chan->completion_virt); + prefetch(ioat_chan->completion_virt); - if (!spin_trylock(&chan->cleanup_lock)) + if (!spin_trylock(&ioat_chan->cleanup_lock)) return; /* The completion writeback can happen at any time, @@ -378,26 +474,28 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) #if (BITS_PER_LONG == 64) phys_complete = - chan->completion_virt->full & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR; + ioat_chan->completion_virt->full & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR; #else - phys_complete = chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK; + phys_complete = ioat_chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK; #endif - if ((chan->completion_virt->full & IOAT_CHANSTS_DMA_TRANSFER_STATUS) == - IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) { - printk("IOAT: Channel halted, chanerr = %x\n", - readl(chan->reg_base + IOAT_CHANERR_OFFSET)); + if ((ioat_chan->completion_virt->full & IOAT_CHANSTS_DMA_TRANSFER_STATUS) == + IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) { + dev_err(&ioat_chan->device->pdev->dev, + "ioatdma: Channel halted, chanerr = %x\n", + readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET)); /* TODO do something to salvage the situation */ } - if (phys_complete == chan->last_completion) { - spin_unlock(&chan->cleanup_lock); + if (phys_complete == ioat_chan->last_completion) { + spin_unlock(&ioat_chan->cleanup_lock); return; } - spin_lock_bh(&chan->desc_lock); - list_for_each_entry_safe(desc, _desc, &chan->used_desc, node) { + cookie = 0; + spin_lock_bh(&ioat_chan->desc_lock); + list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) { /* * Incoming DMA requests may use multiple descriptors, due to @@ -407,31 +505,36 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) if (desc->async_tx.cookie) { cookie = desc->async_tx.cookie; - /* yes we are unmapping both _page and _single alloc'd - regions with unmap_page. Is this *really* that bad? - */ - pci_unmap_page(chan->device->pdev, + /* + * yes we are unmapping both _page and _single alloc'd + * regions with unmap_page. Is this *really* that bad? + */ + pci_unmap_page(ioat_chan->device->pdev, pci_unmap_addr(desc, dst), pci_unmap_len(desc, len), PCI_DMA_FROMDEVICE); - pci_unmap_page(chan->device->pdev, + pci_unmap_page(ioat_chan->device->pdev, pci_unmap_addr(desc, src), pci_unmap_len(desc, len), PCI_DMA_TODEVICE); } if (desc->async_tx.phys != phys_complete) { - /* a completed entry, but not the last, so cleanup + /* + * a completed entry, but not the last, so cleanup * if the client is done with the descriptor */ if (desc->async_tx.ack) { list_del(&desc->node); - list_add_tail(&desc->node, &chan->free_desc); + list_add_tail(&desc->node, + &ioat_chan->free_desc); } else desc->async_tx.cookie = 0; } else { - /* last used desc. Do not remove, so we can append from - it, but don't look at it next time, either */ + /* + * last used desc. Do not remove, so we can append from + * it, but don't look at it next time, either + */ desc->async_tx.cookie = 0; /* TODO check status bits? */ @@ -439,13 +542,13 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan) } } - spin_unlock_bh(&chan->desc_lock); + spin_unlock_bh(&ioat_chan->desc_lock); - chan->last_completion = phys_complete; + ioat_chan->last_completion = phys_complete; if (cookie != 0) - chan->completed_cookie = cookie; + ioat_chan->completed_cookie = cookie; - spin_unlock(&chan->cleanup_lock); + spin_unlock(&ioat_chan->cleanup_lock); } static void ioat_dma_dependency_added(struct dma_chan *chan) @@ -466,11 +569,10 @@ static void ioat_dma_dependency_added(struct dma_chan *chan) * @done: if not %NULL, updated with last completed transaction * @used: if not %NULL, updated with last used transaction */ - static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, - dma_cookie_t cookie, - dma_cookie_t *done, - dma_cookie_t *used) + dma_cookie_t cookie, + dma_cookie_t *done, + dma_cookie_t *used) { struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); dma_cookie_t last_used; @@ -481,7 +583,7 @@ static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, last_complete = ioat_chan->completed_cookie; if (done) - *done= last_complete; + *done = last_complete; if (used) *used = last_used; @@ -495,7 +597,7 @@ static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, last_complete = ioat_chan->completed_cookie; if (done) - *done= last_complete; + *done = last_complete; if (used) *used = last_used; @@ -504,63 +606,13 @@ static enum dma_status ioat_dma_is_complete(struct dma_chan *chan, /* PCI API */ -static struct pci_device_id ioat_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) }, - { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, - PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) }, - { 0, } -}; - -static struct pci_driver ioat_pci_driver = { - .name = "ioatdma", - .id_table = ioat_pci_tbl, - .probe = ioat_probe, - .shutdown = ioat_shutdown, - .remove = __devexit_p(ioat_remove), -}; - -static irqreturn_t ioat_do_interrupt(int irq, void *data) -{ - struct ioat_device *instance = data; - unsigned long attnstatus; - u8 intrctrl; - - intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET); - - if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN)) - return IRQ_NONE; - - if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) { - writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); - return IRQ_NONE; - } - - attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); - - printk(KERN_ERR "ioatdma error: interrupt! status %lx\n", attnstatus); - - writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); - return IRQ_HANDLED; -} - -static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan) +static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) { struct ioat_desc_sw *desc; spin_lock_bh(&ioat_chan->desc_lock); - if (!list_empty(&ioat_chan->free_desc)) { - desc = to_ioat_desc(ioat_chan->free_desc.next); - list_del(&desc->node); - } else { - /* try to get another desc */ - spin_unlock_bh(&ioat_chan->desc_lock); - desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL); - spin_lock_bh(&ioat_chan->desc_lock); - /* will this ever happen? */ - BUG_ON(!desc); - } - + desc = ioat_dma_get_next_descriptor(ioat_chan); desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL; desc->hw->next = 0; desc->async_tx.ack = 1; @@ -581,7 +633,11 @@ static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan) */ #define IOAT_TEST_SIZE 2000 -static int ioat_self_test(struct ioat_device *device) +/** + * ioat_dma_self_test - Perform a IOAT transaction to verify the HW works. + * @device: device to be tested + */ +static int ioat_dma_self_test(struct ioatdma_device *device) { int i; u8 *src; @@ -607,9 +663,11 @@ static int ioat_self_test(struct ioat_device *device) /* Start copy, using first DMA channel */ dma_chan = container_of(device->common.channels.next, - struct dma_chan, - device_node); + struct dma_chan, + device_node); if (ioat_dma_alloc_chan_resources(dma_chan) < 1) { + dev_err(&device->pdev->dev, + "selftest cannot allocate chan resource\n"); err = -ENODEV; goto out; } @@ -627,12 +685,14 @@ static int ioat_self_test(struct ioat_device *device) msleep(1); if (ioat_dma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { - printk(KERN_ERR "ioatdma: Self-test copy timed out, disabling\n"); + dev_err(&device->pdev->dev, + "ioatdma: Self-test copy timed out, disabling\n"); err = -ENODEV; goto free_resources; } if (memcmp(src, dest, IOAT_TEST_SIZE)) { - printk(KERN_ERR "ioatdma: Self-test copy failed compare, disabling\n"); + dev_err(&device->pdev->dev, + "ioatdma: Self-test copy failed compare, disabling\n"); err = -ENODEV; goto free_resources; } @@ -645,147 +705,252 @@ out: return err; } -static int __devinit ioat_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static char ioat_interrupt_style[32] = "msix"; +module_param_string(ioat_interrupt_style, ioat_interrupt_style, + sizeof(ioat_interrupt_style), 0644); +MODULE_PARM_DESC(ioat_interrupt_style, + "set ioat interrupt style: msix (default), " + "msix-single-vector, msi, intx)"); + +/** + * ioat_dma_setup_interrupts - setup interrupt handler + * @device: ioat device + */ +static int ioat_dma_setup_interrupts(struct ioatdma_device *device) { - int err; - unsigned long mmio_start, mmio_len; - void __iomem *reg_base; - struct ioat_device *device; + struct ioat_dma_chan *ioat_chan; + int err, i, j, msixcnt; + u8 intrctrl = 0; + + if (!strcmp(ioat_interrupt_style, "msix")) + goto msix; + if (!strcmp(ioat_interrupt_style, "msix-single-vector")) + goto msix_single_vector; + if (!strcmp(ioat_interrupt_style, "msi")) + goto msi; + if (!strcmp(ioat_interrupt_style, "intx")) + goto intx; + +msix: + /* The number of MSI-X vectors should equal the number of channels */ + msixcnt = device->common.chancnt; + for (i = 0; i < msixcnt; i++) + device->msix_entries[i].entry = i; + + err = pci_enable_msix(device->pdev, device->msix_entries, msixcnt); + if (err < 0) + goto msi; + if (err > 0) + goto msix_single_vector; + + for (i = 0; i < msixcnt; i++) { + ioat_chan = ioat_lookup_chan_by_index(device, i); + err = request_irq(device->msix_entries[i].vector, + ioat_dma_do_interrupt_msix, + 0, "ioat-msix", ioat_chan); + if (err) { + for (j = 0; j < i; j++) { + ioat_chan = + ioat_lookup_chan_by_index(device, j); + free_irq(device->msix_entries[j].vector, + ioat_chan); + } + goto msix_single_vector; + } + } + intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL; + device->irq_mode = msix_multi_vector; + goto done; - err = pci_enable_device(pdev); +msix_single_vector: + device->msix_entries[0].entry = 0; + err = pci_enable_msix(device->pdev, device->msix_entries, 1); if (err) - goto err_enable_device; + goto msi; - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); - if (err) - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = request_irq(device->msix_entries[0].vector, ioat_dma_do_interrupt, + 0, "ioat-msix", device); + if (err) { + pci_disable_msix(device->pdev); + goto msi; + } + device->irq_mode = msix_single_vector; + goto done; + +msi: + err = pci_enable_msi(device->pdev); if (err) - goto err_set_dma_mask; + goto intx; - err = pci_request_regions(pdev, ioat_pci_driver.name); + err = request_irq(device->pdev->irq, ioat_dma_do_interrupt, + 0, "ioat-msi", device); + if (err) { + pci_disable_msi(device->pdev); + goto intx; + } + /* + * CB 1.2 devices need a bit set in configuration space to enable MSI + */ + if (device->version == IOAT_VER_1_2) { + u32 dmactrl; + pci_read_config_dword(device->pdev, + IOAT_PCI_DMACTRL_OFFSET, &dmactrl); + dmactrl |= IOAT_PCI_DMACTRL_MSI_EN; + pci_write_config_dword(device->pdev, + IOAT_PCI_DMACTRL_OFFSET, dmactrl); + } + device->irq_mode = msi; + goto done; + +intx: + err = request_irq(device->pdev->irq, ioat_dma_do_interrupt, + IRQF_SHARED, "ioat-intx", device); if (err) - goto err_request_regions; + goto err_no_irq; + device->irq_mode = intx; - mmio_start = pci_resource_start(pdev, 0); - mmio_len = pci_resource_len(pdev, 0); +done: + intrctrl |= IOAT_INTRCTRL_MASTER_INT_EN; + writeb(intrctrl, device->reg_base + IOAT_INTRCTRL_OFFSET); + return 0; - reg_base = ioremap(mmio_start, mmio_len); - if (!reg_base) { - err = -ENOMEM; - goto err_ioremap; +err_no_irq: + /* Disable all interrupt generation */ + writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET); + dev_err(&device->pdev->dev, "no usable interrupts\n"); + device->irq_mode = none; + return -1; +} + +/** + * ioat_dma_remove_interrupts - remove whatever interrupts were set + * @device: ioat device + */ +static void ioat_dma_remove_interrupts(struct ioatdma_device *device) +{ + struct ioat_dma_chan *ioat_chan; + int i; + + /* Disable all interrupt generation */ + writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET); + + switch (device->irq_mode) { + case msix_multi_vector: + for (i = 0; i < device->common.chancnt; i++) { + ioat_chan = ioat_lookup_chan_by_index(device, i); + free_irq(device->msix_entries[i].vector, ioat_chan); + } + pci_disable_msix(device->pdev); + break; + case msix_single_vector: + free_irq(device->msix_entries[0].vector, device); + pci_disable_msix(device->pdev); + break; + case msi: + free_irq(device->pdev->irq, device); + pci_disable_msi(device->pdev); + break; + case intx: + free_irq(device->pdev->irq, device); + break; + case none: + dev_warn(&device->pdev->dev, + "call to %s without interrupts setup\n", __func__); } + device->irq_mode = none; +} + +struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, + void __iomem *iobase) +{ + int err; + struct ioatdma_device *device; device = kzalloc(sizeof(*device), GFP_KERNEL); if (!device) { err = -ENOMEM; goto err_kzalloc; } + device->pdev = pdev; + device->reg_base = iobase; + device->version = readb(device->reg_base + IOAT_VER_OFFSET); /* DMA coherent memory pool for DMA descriptor allocations */ device->dma_pool = pci_pool_create("dma_desc_pool", pdev, - sizeof(struct ioat_dma_descriptor), 64, 0); + sizeof(struct ioat_dma_descriptor), + 64, 0); if (!device->dma_pool) { err = -ENOMEM; goto err_dma_pool; } - device->completion_pool = pci_pool_create("completion_pool", pdev, sizeof(u64), SMP_CACHE_BYTES, SMP_CACHE_BYTES); + device->completion_pool = pci_pool_create("completion_pool", pdev, + sizeof(u64), SMP_CACHE_BYTES, + SMP_CACHE_BYTES); if (!device->completion_pool) { err = -ENOMEM; goto err_completion_pool; } - device->pdev = pdev; - pci_set_drvdata(pdev, device); -#ifdef CONFIG_PCI_MSI - if (pci_enable_msi(pdev) == 0) { - device->msi = 1; - } else { - device->msi = 0; - } -#endif - err = request_irq(pdev->irq, &ioat_do_interrupt, IRQF_SHARED, "ioat", - device); - if (err) - goto err_irq; - - device->reg_base = reg_base; - - writeb(IOAT_INTRCTRL_MASTER_INT_EN, device->reg_base + IOAT_INTRCTRL_OFFSET); - pci_set_master(pdev); - INIT_LIST_HEAD(&device->common.channels); - enumerate_dma_channels(device); + ioat_dma_enumerate_channels(device); dma_cap_set(DMA_MEMCPY, device->common.cap_mask); - device->common.device_alloc_chan_resources = ioat_dma_alloc_chan_resources; - device->common.device_free_chan_resources = ioat_dma_free_chan_resources; + device->common.device_alloc_chan_resources = + ioat_dma_alloc_chan_resources; + device->common.device_free_chan_resources = + ioat_dma_free_chan_resources; device->common.device_prep_dma_memcpy = ioat_dma_prep_memcpy; device->common.device_is_tx_complete = ioat_dma_is_complete; device->common.device_issue_pending = ioat_dma_memcpy_issue_pending; device->common.device_dependency_added = ioat_dma_dependency_added; device->common.dev = &pdev->dev; - printk(KERN_INFO "Intel(R) I/OAT DMA Engine found, %d channels\n", - device->common.chancnt); + dev_err(&device->pdev->dev, + "ioatdma: Intel(R) I/OAT DMA Engine found," + " %d channels, device version 0x%02x\n", + device->common.chancnt, device->version); - err = ioat_self_test(device); + err = ioat_dma_setup_interrupts(device); + if (err) + goto err_setup_interrupts; + + err = ioat_dma_self_test(device); if (err) goto err_self_test; dma_async_device_register(&device->common); - return 0; + return device; err_self_test: -err_irq: + ioat_dma_remove_interrupts(device); +err_setup_interrupts: pci_pool_destroy(device->completion_pool); err_completion_pool: pci_pool_destroy(device->dma_pool); err_dma_pool: kfree(device); err_kzalloc: - iounmap(reg_base); -err_ioremap: - pci_release_regions(pdev); -err_request_regions: -err_set_dma_mask: - pci_disable_device(pdev); -err_enable_device: - - printk(KERN_ERR "Intel(R) I/OAT DMA Engine initialization failed\n"); - - return err; + iounmap(iobase); + dev_err(&device->pdev->dev, + "ioatdma: Intel(R) I/OAT DMA Engine initialization failed\n"); + return NULL; } -static void ioat_shutdown(struct pci_dev *pdev) +void ioat_dma_remove(struct ioatdma_device *device) { - struct ioat_device *device; - device = pci_get_drvdata(pdev); - - dma_async_device_unregister(&device->common); -} - -static void __devexit ioat_remove(struct pci_dev *pdev) -{ - struct ioat_device *device; struct dma_chan *chan, *_chan; struct ioat_dma_chan *ioat_chan; - device = pci_get_drvdata(pdev); dma_async_device_unregister(&device->common); - free_irq(device->pdev->irq, device); -#ifdef CONFIG_PCI_MSI - if (device->msi) - pci_disable_msi(device->pdev); -#endif + ioat_dma_remove_interrupts(device); + pci_pool_destroy(device->dma_pool); pci_pool_destroy(device->completion_pool); - iounmap(device->reg_base); - pci_release_regions(pdev); - pci_disable_device(pdev); - list_for_each_entry_safe(chan, _chan, &device->common.channels, device_node) { + + list_for_each_entry_safe(chan, _chan, + &device->common.channels, device_node) { ioat_chan = to_ioat_chan(chan); list_del(&chan->device_node); kfree(ioat_chan); @@ -793,25 +958,3 @@ static void __devexit ioat_remove(struct pci_dev *pdev) kfree(device); } -/* MODULE API */ -MODULE_VERSION("1.9"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Intel Corporation"); - -static int __init ioat_init_module(void) -{ - /* it's currently unsafe to unload this module */ - /* if forced, worst case is that rmmod hangs */ - __unsafe(THIS_MODULE); - - return pci_register_driver(&ioat_pci_driver); -} - -module_init(ioat_init_module); - -static void __exit ioat_exit_module(void) -{ - pci_unregister_driver(&ioat_pci_driver); -} - -module_exit(ioat_exit_module); diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h index bf4dad70e0f..2a319e124ec 100644 --- a/drivers/dma/ioatdma.h +++ b/drivers/dma/ioatdma.h @@ -28,25 +28,35 @@ #include <linux/cache.h> #include <linux/pci_ids.h> +enum ioat_interrupt { + none = 0, + msix_multi_vector = 1, + msix_single_vector = 2, + msi = 3, + intx = 4, +}; + #define IOAT_LOW_COMPLETION_MASK 0xffffffc0 /** - * struct ioat_device - internal representation of a IOAT device + * struct ioatdma_device - internal representation of a IOAT device * @pdev: PCI-Express device * @reg_base: MMIO register space base address * @dma_pool: for allocating DMA descriptors * @common: embedded struct dma_device - * @msi: Message Signaled Interrupt number + * @version: version of ioatdma device */ -struct ioat_device { +struct ioatdma_device { struct pci_dev *pdev; void __iomem *reg_base; struct pci_pool *dma_pool; struct pci_pool *completion_pool; - struct dma_device common; - u8 msi; + u8 version; + enum ioat_interrupt irq_mode; + struct msix_entry msix_entries[4]; + struct ioat_dma_chan *idx[4]; }; /** @@ -84,7 +94,7 @@ struct ioat_dma_chan { int pending; - struct ioat_device *device; + struct ioatdma_device *device; struct dma_chan common; dma_addr_t completion_addr; @@ -95,6 +105,7 @@ struct ioat_dma_chan { u32 high; }; } *completion_virt; + struct tasklet_struct cleanup_task; }; /* wrapper around hardware descriptor format + additional software fields */ @@ -117,4 +128,16 @@ struct ioat_desc_sw { struct dma_async_tx_descriptor async_tx; }; +#if defined(CONFIG_INTEL_IOATDMA) || defined(CONFIG_INTEL_IOATDMA_MODULE) +struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, + void __iomem *iobase); +void ioat_dma_remove(struct ioatdma_device *device); +struct dca_provider *ioat_dca_init(struct pci_dev *pdev, + void __iomem *iobase); +#else +#define ioat_dma_probe(pdev, iobase) NULL +#define ioat_dma_remove(device) do { } while (0) +#define ioat_dca_init(pdev, iobase) NULL +#endif + #endif /* IOATDMA_H */ diff --git a/drivers/dma/ioatdma_hw.h b/drivers/dma/ioatdma_hw.h index 4d7a12880be..9e7434e1551 100644 --- a/drivers/dma/ioatdma_hw.h +++ b/drivers/dma/ioatdma_hw.h @@ -27,7 +27,7 @@ #define IOAT_PCI_RID 0x00 #define IOAT_PCI_SVID 0x8086 #define IOAT_PCI_SID 0x8086 -#define IOAT_VER 0x12 /* Version 1.2 */ +#define IOAT_VER_1_2 0x12 /* Version 1.2 */ struct ioat_dma_descriptor { uint32_t size; diff --git a/drivers/dma/ioatdma_registers.h b/drivers/dma/ioatdma_registers.h index a30c7349075..baaab5ea146 100644 --- a/drivers/dma/ioatdma_registers.h +++ b/drivers/dma/ioatdma_registers.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -21,6 +21,9 @@ #ifndef _IOAT_REGISTERS_H_ #define _IOAT_REGISTERS_H_ +#define IOAT_PCI_DMACTRL_OFFSET 0x48 +#define IOAT_PCI_DMACTRL_DMA_EN 0x00000001 +#define IOAT_PCI_DMACTRL_MSI_EN 0x00000002 /* MMIO Device Registers */ #define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */ @@ -39,6 +42,7 @@ #define IOAT_INTRCTRL_MASTER_INT_EN 0x01 /* Master Interrupt Enable */ #define IOAT_INTRCTRL_INT_STATUS 0x02 /* ATTNSTATUS -or- Channel Int */ #define IOAT_INTRCTRL_INT 0x04 /* INT_STATUS -and- MASTER_INT_EN */ +#define IOAT_INTRCTRL_MSIX_VECTOR_CONTROL 0x08 /* Enable all MSI-X vectors */ #define IOAT_ATTNSTATUS_OFFSET 0x04 /* Each bit is a channel */ diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 2b4d2a0ae5c..c306c9f534a 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -939,7 +939,8 @@ static int cris_ide_build_dmatable (ide_drive_t *drive) /* group sequential buffers into one large buffer */ addr = page_to_phys(sg->page) + sg->offset; size = sg_dma_len(sg); - while (sg++, --i) { + while (--i) { + sg = sg_next(sg); if ((addr + size) != page_to_phys(sg->page) + sg->offset) break; size += sg_dma_len(sg); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 4754769eda9..92177ca48b4 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -716,32 +716,6 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) rq->buffer = rq->cmd; } -static int idedisk_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - ide_drive_t *drive = q->queuedata; - struct request *rq; - int ret; - - if (!drive->wcache) - return 0; - - rq = blk_get_request(q, WRITE, __GFP_WAIT); - - idedisk_prepare_flush(q, rq); - - ret = blk_execute_rq(q, disk, rq, 0); - - /* - * if we failed and caller wants error offset, get it - */ - if (ret && error_sector) - *error_sector = ide_get_error_location(drive, rq->cmd); - - blk_put_request(rq); - return ret; -} - /* * This is tightly woven into the driver->do_special can not touch. * DON'T do it again until a total personality rewrite is committed. @@ -781,7 +755,6 @@ static void update_ordered(ide_drive_t *drive) struct hd_driveid *id = drive->id; unsigned ordered = QUEUE_ORDERED_NONE; prepare_flush_fn *prep_fn = NULL; - issue_flush_fn *issue_fn = NULL; if (drive->wcache) { unsigned long long capacity; @@ -805,13 +778,11 @@ static void update_ordered(ide_drive_t *drive) if (barrier) { ordered = QUEUE_ORDERED_DRAIN_FLUSH; prep_fn = idedisk_prepare_flush; - issue_fn = idedisk_issue_flush; } } else ordered = QUEUE_ORDERED_DRAIN; blk_queue_ordered(drive->queue, ordered, prep_fn); - blk_queue_issue_flush_fn(drive->queue, issue_fn); } static int write_cache(ide_drive_t *drive, int arg) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index b453211ee0f..a4cbbbaccde 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -280,7 +280,7 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq) } } - sg++; + sg = sg_next(sg); i--; } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 4cece930114..04273d3c147 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -322,41 +322,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) spin_unlock_irqrestore(&ide_lock, flags); } -/* - * FIXME: probably move this somewhere else, name is bad too :) - */ -u64 ide_get_error_location(ide_drive_t *drive, char *args) -{ - u32 high, low; - u8 hcyl, lcyl, sect; - u64 sector; - - high = 0; - hcyl = args[5]; - lcyl = args[4]; - sect = args[3]; - - if (ide_id_has_flush_cache_ext(drive->id)) { - low = (hcyl << 16) | (lcyl << 8) | sect; - HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); - high = ide_read_24(drive); - } else { - u8 cur = HWIF(drive)->INB(IDE_SELECT_REG); - if (cur & 0x40) { - high = cur & 0xf; - low = (hcyl << 16) | (lcyl << 8) | sect; - } else { - low = hcyl * drive->head * drive->sect; - low += lcyl * drive->sect; - low += sect - 1; - } - } - - sector = ((u64) high << 24) | low; - return sector; -} -EXPORT_SYMBOL(ide_get_error_location); - /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -881,7 +846,8 @@ void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq) ide_hwif_t *hwif = drive->hwif; hwif->nsect = hwif->nleft = rq->nr_sectors; - hwif->cursg = hwif->cursg_ofs = 0; + hwif->cursg_ofs = 0; + hwif->cursg = NULL; } EXPORT_SYMBOL_GPL(ide_init_sg_cmd); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index d1011712601..34b1fb65bc7 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1349,7 +1349,7 @@ static int hwif_init(ide_hwif_t *hwif) if (!hwif->sg_max_nents) hwif->sg_max_nents = PRD_ENTRIES; - hwif->sg_table = kmalloc(sizeof(struct scatterlist)*hwif->sg_max_nents, + hwif->sg_table = kzalloc(sizeof(struct scatterlist)*hwif->sg_max_nents, GFP_KERNEL); if (!hwif->sg_table) { printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index aa06dafb74a..2a3c8d49834 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -45,6 +45,7 @@ #include <linux/hdreg.h> #include <linux/ide.h> #include <linux/bitops.h> +#include <linux/scatterlist.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -263,6 +264,7 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; + struct scatterlist *cursg = hwif->cursg; struct page *page; #ifdef CONFIG_HIGHMEM unsigned long flags; @@ -270,8 +272,14 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) unsigned int offset; u8 *buf; - page = sg[hwif->cursg].page; - offset = sg[hwif->cursg].offset + hwif->cursg_ofs * SECTOR_SIZE; + cursg = hwif->cursg; + if (!cursg) { + cursg = sg; + hwif->cursg = sg; + } + + page = cursg->page; + offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE; /* get the current page and offset */ page = nth_page(page, (offset >> PAGE_SHIFT)); @@ -285,8 +293,8 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) hwif->nleft--; hwif->cursg_ofs++; - if ((hwif->cursg_ofs * SECTOR_SIZE) == sg[hwif->cursg].length) { - hwif->cursg++; + if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) { + hwif->cursg = sg_next(hwif->cursg); hwif->cursg_ofs = 0; } @@ -367,6 +375,8 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) { + HWIF(drive)->cursg = NULL; + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *task = rq->special; diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index aebde49365d..892d08f61dc 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -296,7 +296,7 @@ static int auide_build_dmatable(ide_drive_t *drive) cur_addr += tc; cur_len -= tc; } - sg++; + sg = sg_next(sg); i--; } diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 85ffaaa39b1..c74fef6bbc9 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -29,6 +29,7 @@ #include <linux/mm.h> #include <linux/ioport.h> #include <linux/blkdev.h> +#include <linux/scatterlist.h> #include <linux/ioc4.h> #include <asm/io.h> @@ -537,7 +538,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir) } } - sg++; + sg = sg_next(sg); i--; } diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 7d8873839e2..9e86406bf44 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1539,7 +1539,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) cur_len -= tc; ++table; } - sg++; + sg = sg_next(sg); i--; } diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/infiniband/hw/ipath/ipath_dma.c index f87f003e3ef..22709a4f8fc 100644 --- a/drivers/infiniband/hw/ipath/ipath_dma.c +++ b/drivers/infiniband/hw/ipath/ipath_dma.c @@ -30,6 +30,7 @@ * SOFTWARE. */ +#include <linux/scatterlist.h> #include <rdma/ib_verbs.h> #include "ipath_verbs.h" @@ -96,17 +97,18 @@ static void ipath_dma_unmap_page(struct ib_device *dev, BUG_ON(!valid_dma_direction(direction)); } -static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) +static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction direction) { + struct scatterlist *sg; u64 addr; int i; int ret = nents; BUG_ON(!valid_dma_direction(direction)); - for (i = 0; i < nents; i++) { - addr = (u64) page_address(sg[i].page); + for_each_sg(sgl, sg, nents, i) { + addr = (u64) page_address(sg->page); /* TODO: handle highmem pages */ if (!addr) { ret = 0; diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index e05690e3592..f3529b6f0a3 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -124,17 +124,19 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, if (cmd_dir == ISER_DIR_OUT) { /* copy the unaligned sg the buffer which is used for RDMA */ - struct scatterlist *sg = (struct scatterlist *)data->buf; + struct scatterlist *sgl = (struct scatterlist *)data->buf; + struct scatterlist *sg; int i; char *p, *from; - for (p = mem, i = 0; i < data->size; i++) { - from = kmap_atomic(sg[i].page, KM_USER0); + p = mem; + for_each_sg(sgl, sg, data->size, i) { + from = kmap_atomic(sg->page, KM_USER0); memcpy(p, - from + sg[i].offset, - sg[i].length); + from + sg->offset, + sg->length); kunmap_atomic(from, KM_USER0); - p += sg[i].length; + p += sg->length; } } @@ -176,7 +178,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, if (cmd_dir == ISER_DIR_IN) { char *mem; - struct scatterlist *sg; + struct scatterlist *sgl, *sg; unsigned char *p, *to; unsigned int sg_size; int i; @@ -184,16 +186,17 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, /* copy back read RDMA to unaligned sg */ mem = mem_copy->copy_buf; - sg = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf; + sgl = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf; sg_size = iser_ctask->data[ISER_DIR_IN].size; - for (p = mem, i = 0; i < sg_size; i++){ - to = kmap_atomic(sg[i].page, KM_SOFTIRQ0); - memcpy(to + sg[i].offset, + p = mem; + for_each_sg(sgl, sg, sg_size, i) { + to = kmap_atomic(sg->page, KM_SOFTIRQ0); + memcpy(to + sg->offset, p, - sg[i].length); + sg->length); kunmap_atomic(to, KM_SOFTIRQ0); - p += sg[i].length; + p += sg->length; } } @@ -224,7 +227,8 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data, struct iser_page_vec *page_vec, struct ib_device *ibdev) { - struct scatterlist *sg = (struct scatterlist *)data->buf; + struct scatterlist *sgl = (struct scatterlist *)data->buf; + struct scatterlist *sg; u64 first_addr, last_addr, page; int end_aligned; unsigned int cur_page = 0; @@ -232,24 +236,25 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data, int i; /* compute the offset of first element */ - page_vec->offset = (u64) sg[0].offset & ~MASK_4K; + page_vec->offset = (u64) sgl[0].offset & ~MASK_4K; - for (i = 0; i < data->dma_nents; i++) { - unsigned int dma_len = ib_sg_dma_len(ibdev, &sg[i]); + for_each_sg(sgl, sg, data->dma_nents, i) { + unsigned int dma_len = ib_sg_dma_len(ibdev, sg); total_sz += dma_len; - first_addr = ib_sg_dma_address(ibdev, &sg[i]); + first_addr = ib_sg_dma_address(ibdev, sg); last_addr = first_addr + dma_len; end_aligned = !(last_addr & ~MASK_4K); /* continue to collect page fragments till aligned or SG ends */ while (!end_aligned && (i + 1 < data->dma_nents)) { + sg = sg_next(sg); i++; - dma_len = ib_sg_dma_len(ibdev, &sg[i]); + dma_len = ib_sg_dma_len(ibdev, sg); total_sz += dma_len; - last_addr = ib_sg_dma_address(ibdev, &sg[i]) + dma_len; + last_addr = ib_sg_dma_address(ibdev, sg) + dma_len; end_aligned = !(last_addr & ~MASK_4K); } @@ -284,25 +289,26 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data, static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data, struct ib_device *ibdev) { - struct scatterlist *sg; + struct scatterlist *sgl, *sg; u64 end_addr, next_addr; int i, cnt; unsigned int ret_len = 0; - sg = (struct scatterlist *)data->buf; + sgl = (struct scatterlist *)data->buf; - for (cnt = 0, i = 0; i < data->dma_nents; i++, cnt++) { + cnt = 0; + for_each_sg(sgl, sg, data->dma_nents, i) { /* iser_dbg("Checking sg iobuf [%d]: phys=0x%08lX " "offset: %ld sz: %ld\n", i, - (unsigned long)page_to_phys(sg[i].page), - (unsigned long)sg[i].offset, - (unsigned long)sg[i].length); */ - end_addr = ib_sg_dma_address(ibdev, &sg[i]) + - ib_sg_dma_len(ibdev, &sg[i]); + (unsigned long)page_to_phys(sg->page), + (unsigned long)sg->offset, + (unsigned long)sg->length); */ + end_addr = ib_sg_dma_address(ibdev, sg) + + ib_sg_dma_len(ibdev, sg); /* iser_dbg("Checking sg iobuf end address " "0x%08lX\n", end_addr); */ if (i + 1 < data->dma_nents) { - next_addr = ib_sg_dma_address(ibdev, &sg[i+1]); + next_addr = ib_sg_dma_address(ibdev, sg_next(sg)); /* are i, i+1 fragments of the same page? */ if (end_addr == next_addr) continue; @@ -322,15 +328,16 @@ static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data, static void iser_data_buf_dump(struct iser_data_buf *data, struct ib_device *ibdev) { - struct scatterlist *sg = (struct scatterlist *)data->buf; + struct scatterlist *sgl = (struct scatterlist *)data->buf; + struct scatterlist *sg; int i; - for (i = 0; i < data->dma_nents; i++) + for_each_sg(sgl, sg, data->dma_nents, i) iser_err("sg[%d] dma_addr:0x%lX page:0x%p " "off:0x%x sz:0x%x dma_len:0x%x\n", - i, (unsigned long)ib_sg_dma_address(ibdev, &sg[i]), - sg[i].page, sg[i].offset, - sg[i].length, ib_sg_dma_len(ibdev, &sg[i])); + i, (unsigned long)ib_sg_dma_address(ibdev, sg), + sg->page, sg->offset, + sg->length, ib_sg_dma_len(ibdev, sg)); } static void iser_dump_page_vec(struct iser_page_vec *page_vec) diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 23b6f7bc16b..476012b6dfa 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -506,9 +506,14 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg) { struct sk_buff *skb; size_t len; + capi_cmsg2message(cmsg, cmsg->buf); len = CAPIMSG_LEN(cmsg->buf); skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "capidrv::send_message: can't allocate mem\n"); + return; + } memcpy(skb_put(skb, len), cmsg->buf, len); if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) kfree_skb(skb); diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 9f73bc2727c..f5553186931 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -821,6 +821,8 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) return -EFAULT; } card = get_capi_ctr_by_nr(ldef.contr); + if (!card) + return -EINVAL; card = capi_ctr_get(card); if (!card) return -ESRCH; diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 00e31609a23..af7648274b3 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -1936,14 +1936,7 @@ static int gigaset_write_room(struct cardstate *cs) */ static int gigaset_chars_in_buffer(struct cardstate *cs) { - unsigned long flags; - unsigned bytes; - - spin_lock_irqsave(&cs->cmdlock, flags); - bytes = cs->cmdbytes; - spin_unlock_irqrestore(&cs->cmdlock, flags); - - return bytes; + return cs->cmdbytes; } /* gigaset_brkchars diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 1654fa41357..9e089f06a94 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -109,13 +109,9 @@ EXPORT_SYMBOL_GPL(gigaset_skb_sent); static int command_from_LL(isdn_ctrl *cntrl) { struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver); - //isdn_ctrl response; - //unsigned long flags; struct bc_state *bcs; int retval = 0; struct setup_parm *sp; - unsigned param; - unsigned long flags; gigaset_debugdrivers(); @@ -162,12 +158,8 @@ static int command_from_LL(isdn_ctrl *cntrl) } *sp = cntrl->parm.setup; - spin_lock_irqsave(&cs->lock, flags); - param = bcs->at_state.seq_index; - spin_unlock_irqrestore(&cs->lock, flags); - - if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, param, - NULL)) { + if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, + bcs->at_state.seq_index, NULL)) { //FIXME what should we do? kfree(sp); gigaset_free_channel(bcs); diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index e767afa55ab..da6f3acf9fd 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c @@ -19,15 +19,9 @@ static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, char *buf) { - int ret; - unsigned long flags; struct cardstate *cs = dev_get_drvdata(dev); - spin_lock_irqsave(&cs->lock, flags); - ret = sprintf(buf, "%u\n", cs->cidmode); - spin_unlock_irqrestore(&cs->lock, flags); - - return ret; + return sprintf(buf, "%u\n", cs->cidmode); } static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index a1263019df5..ca4bee173cf 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -310,7 +310,6 @@ static void gigaset_modem_fill(unsigned long data) struct cardstate *cs = (struct cardstate *) data; struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ struct cmdbuf_t *cb; - unsigned long flags; int again; gig_dbg(DEBUG_OUTPUT, "modem_fill"); @@ -323,9 +322,7 @@ static void gigaset_modem_fill(unsigned long data) do { again = 0; if (!bcs->tx_skb) { /* no skb is being sent */ - spin_lock_irqsave(&cs->cmdlock, flags); cb = cs->cmdbuf; - spin_unlock_irqrestore(&cs->cmdlock, flags); if (cb) { /* commands to send? */ gig_dbg(DEBUG_OUTPUT, "modem_fill: cb"); if (send_cb(cs, cb) < 0) { @@ -546,13 +543,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, static int gigaset_write_room(struct cardstate *cs) { - unsigned long flags; unsigned bytes; - spin_lock_irqsave(&cs->cmdlock, flags); bytes = cs->cmdbytes; - spin_unlock_irqrestore(&cs->cmdlock, flags); - return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0; } diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 4910bca5264..c6df2925ebd 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1365,7 +1365,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) } else { s = NULL; } - ret = down_interruptible(&dev->sem); + ret = mutex_lock_interruptible(&dev->mtx); if( ret ) return ret; if ((s = isdn_net_new(s, NULL))) { if (copy_to_user(argp, s, strlen(s) + 1)){ @@ -1375,7 +1375,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) } } else ret = -ENODEV; - up(&dev->sem); + mutex_unlock(&dev->mtx); return ret; case IIOCNETASL: /* Add a slave to a network-interface */ @@ -1384,7 +1384,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) return -EFAULT; } else return -EINVAL; - ret = down_interruptible(&dev->sem); + ret = mutex_lock_interruptible(&dev->mtx); if( ret ) return ret; if ((s = isdn_net_newslave(bname))) { if (copy_to_user(argp, s, strlen(s) + 1)){ @@ -1394,17 +1394,17 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) } } else ret = -ENODEV; - up(&dev->sem); + mutex_unlock(&dev->mtx); return ret; case IIOCNETDIF: /* Delete a network-interface */ if (arg) { if (copy_from_user(name, argp, sizeof(name))) return -EFAULT; - ret = down_interruptible(&dev->sem); + ret = mutex_lock_interruptible(&dev->mtx); if( ret ) return ret; ret = isdn_net_rm(name); - up(&dev->sem); + mutex_unlock(&dev->mtx); return ret; } else return -EINVAL; @@ -1433,10 +1433,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (arg) { if (copy_from_user(&phone, argp, sizeof(phone))) return -EFAULT; - ret = down_interruptible(&dev->sem); + ret = mutex_lock_interruptible(&dev->mtx); if( ret ) return ret; ret = isdn_net_addphone(&phone); - up(&dev->sem); + mutex_unlock(&dev->mtx); return ret; } else return -EINVAL; @@ -1445,10 +1445,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (arg) { if (copy_from_user(&phone, argp, sizeof(phone))) return -EFAULT; - ret = down_interruptible(&dev->sem); + ret = mutex_lock_interruptible(&dev->mtx); if( ret ) return ret; ret = isdn_net_getphones(&phone, argp); - up(&dev->sem); + mutex_unlock(&dev->mtx); return ret; } else return -EINVAL; @@ -1457,10 +1457,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (arg) { if (copy_from_user(&phone, argp, sizeof(phone))) return -EFAULT; - ret = down_interruptible(&dev->sem); + ret = mutex_lock_interruptible(&dev->mtx); if( ret ) return ret; ret = isdn_net_delphone(&phone); - up(&dev->sem); + mutex_unlock(&dev->mtx); return ret; } else return -EINVAL; @@ -2304,7 +2304,7 @@ static int __init isdn_init(void) #ifdef MODULE dev->owner = THIS_MODULE; #endif - init_MUTEX(&dev->sem); + mutex_init(&dev->mtx); init_waitqueue_head(&dev->info_waitq); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 8216a6f75be..64fee90bb68 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -441,33 +441,12 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size) return clone; } -static void crypt_free_buffer_pages(struct crypt_config *cc, - struct bio *clone, unsigned int bytes) +static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone) { - unsigned int i, start, end; + unsigned int i; struct bio_vec *bv; - /* - * This is ugly, but Jens Axboe thinks that using bi_idx in the - * endio function is too dangerous at the moment, so I calculate the - * correct position using bi_vcnt and bi_size. - * The bv_offset and bv_len fields might already be modified but we - * know that we always allocated whole pages. - * A fix to the bi_idx issue in the kernel is in the works, so - * we will hopefully be able to revert to the cleaner solution soon. - */ - i = clone->bi_vcnt - 1; - bv = bio_iovec_idx(clone, i); - end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - clone->bi_size; - start = end - bytes; - - start >>= PAGE_SHIFT; - if (!clone->bi_size) - end = clone->bi_vcnt; - else - end >>= PAGE_SHIFT; - - for (i = start; i < end; i++) { + for (i = 0; i < clone->bi_vcnt; i++) { bv = bio_iovec_idx(clone, i); BUG_ON(!bv->bv_page); mempool_free(bv->bv_page, cc->page_pool); @@ -519,7 +498,7 @@ static void crypt_endio(struct bio *clone, int error) * free the processed pages */ if (!read_io) { - crypt_free_buffer_pages(cc, clone, clone->bi_size); + crypt_free_buffer_pages(cc, clone); goto out; } @@ -608,7 +587,7 @@ static void process_write(struct dm_crypt_io *io) ctx.idx_out = 0; if (unlikely(crypt_convert(cc, &ctx) < 0)) { - crypt_free_buffer_pages(cc, clone, clone->bi_size); + crypt_free_buffer_pages(cc, clone); bio_put(clone); dec_pending(io, -EIO); return; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 2bcde5798b5..fbe477bb2c6 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -999,33 +999,6 @@ void dm_table_unplug_all(struct dm_table *t) } } -int dm_table_flush_all(struct dm_table *t) -{ - struct list_head *d, *devices = dm_table_get_devices(t); - int ret = 0; - unsigned i; - - for (i = 0; i < t->num_targets; i++) - if (t->targets[i].type->flush) - t->targets[i].type->flush(&t->targets[i]); - - for (d = devices->next; d != devices; d = d->next) { - struct dm_dev *dd = list_entry(d, struct dm_dev, list); - struct request_queue *q = bdev_get_queue(dd->bdev); - int err; - - if (!q->issue_flush_fn) - err = -EOPNOTSUPP; - else - err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL); - - if (!ret) - ret = err; - } - - return ret; -} - struct mapped_device *dm_table_get_md(struct dm_table *t) { dm_get(t->md); @@ -1043,4 +1016,3 @@ EXPORT_SYMBOL(dm_table_get_md); EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); EXPORT_SYMBOL(dm_table_unplug_all); -EXPORT_SYMBOL(dm_table_flush_all); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 167765c4774..d837d37f620 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -840,21 +840,6 @@ static int dm_request(struct request_queue *q, struct bio *bio) return 0; } -static int dm_flush_all(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - struct mapped_device *md = q->queuedata; - struct dm_table *map = dm_get_table(md); - int ret = -ENXIO; - - if (map) { - ret = dm_table_flush_all(map); - dm_table_put(map); - } - - return ret; -} - static void dm_unplug_all(struct request_queue *q) { struct mapped_device *md = q->queuedata; @@ -1003,7 +988,6 @@ static struct mapped_device *alloc_dev(int minor) blk_queue_make_request(md->queue, dm_request); blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); md->queue->unplug_fn = dm_unplug_all; - md->queue->issue_flush_fn = dm_flush_all; md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache); if (!md->io_pool) diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 462ee652a89..4b3faa45277 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -111,7 +111,6 @@ void dm_table_postsuspend_targets(struct dm_table *t); int dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); void dm_table_unplug_all(struct dm_table *t); -int dm_table_flush_all(struct dm_table *t); /*----------------------------------------------------------------- * A registry of target types. diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 550148770bb..56a11f6c127 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -92,25 +92,6 @@ static void linear_unplug(struct request_queue *q) } } -static int linear_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - mddev_t *mddev = q->queuedata; - linear_conf_t *conf = mddev_to_conf(mddev); - int i, ret = 0; - - for (i=0; i < mddev->raid_disks && ret == 0; i++) { - struct block_device *bdev = conf->disks[i].rdev->bdev; - struct request_queue *r_queue = bdev_get_queue(bdev); - - if (!r_queue->issue_flush_fn) - ret = -EOPNOTSUPP; - else - ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); - } - return ret; -} - static int linear_congested(void *data, int bits) { mddev_t *mddev = data; @@ -279,7 +260,6 @@ static int linear_run (mddev_t *mddev) blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->unplug_fn = linear_unplug; - mddev->queue->issue_flush_fn = linear_issue_flush; mddev->queue->backing_dev_info.congested_fn = linear_congested; mddev->queue->backing_dev_info.congested_data = mddev; return 0; diff --git a/drivers/md/md.c b/drivers/md/md.c index acf1b81b47c..0dc563d76b3 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3463,7 +3463,6 @@ static int do_md_stop(mddev_t * mddev, int mode) mddev->pers->stop(mddev); mddev->queue->merge_bvec_fn = NULL; mddev->queue->unplug_fn = NULL; - mddev->queue->issue_flush_fn = NULL; mddev->queue->backing_dev_info.congested_fn = NULL; if (mddev->pers->sync_request) sysfs_remove_group(&mddev->kobj, &md_redundancy_group); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index f2a63f394ad..b35731cceac 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -194,35 +194,6 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev) seq_printf (seq, "]"); } -static int multipath_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - mddev_t *mddev = q->queuedata; - multipath_conf_t *conf = mddev_to_conf(mddev); - int i, ret = 0; - - rcu_read_lock(); - for (i=0; i<mddev->raid_disks && ret == 0; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags)) { - struct block_device *bdev = rdev->bdev; - struct request_queue *r_queue = bdev_get_queue(bdev); - - if (!r_queue->issue_flush_fn) - ret = -EOPNOTSUPP; - else { - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, - error_sector); - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - } - rcu_read_unlock(); - return ret; -} static int multipath_congested(void *data, int bits) { mddev_t *mddev = data; @@ -527,7 +498,6 @@ static int multipath_run (mddev_t *mddev) mddev->array_size = mddev->size; mddev->queue->unplug_fn = multipath_unplug; - mddev->queue->issue_flush_fn = multipath_issue_flush; mddev->queue->backing_dev_info.congested_fn = multipath_congested; mddev->queue->backing_dev_info.congested_data = mddev; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index ef0da2d8495..e79e1a538d4 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -40,26 +40,6 @@ static void raid0_unplug(struct request_queue *q) } } -static int raid0_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - mddev_t *mddev = q->queuedata; - raid0_conf_t *conf = mddev_to_conf(mddev); - mdk_rdev_t **devlist = conf->strip_zone[0].dev; - int i, ret = 0; - - for (i=0; i<mddev->raid_disks && ret == 0; i++) { - struct block_device *bdev = devlist[i]->bdev; - struct request_queue *r_queue = bdev_get_queue(bdev); - - if (!r_queue->issue_flush_fn) - ret = -EOPNOTSUPP; - else - ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); - } - return ret; -} - static int raid0_congested(void *data, int bits) { mddev_t *mddev = data; @@ -250,7 +230,6 @@ static int create_strip_zones (mddev_t *mddev) mddev->queue->unplug_fn = raid0_unplug; - mddev->queue->issue_flush_fn = raid0_issue_flush; mddev->queue->backing_dev_info.congested_fn = raid0_congested; mddev->queue->backing_dev_info.congested_data = mddev; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 6d03bea6fa5..0bcefad8241 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -567,36 +567,6 @@ static void raid1_unplug(struct request_queue *q) md_wakeup_thread(mddev->thread); } -static int raid1_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - mddev_t *mddev = q->queuedata; - conf_t *conf = mddev_to_conf(mddev); - int i, ret = 0; - - rcu_read_lock(); - for (i=0; i<mddev->raid_disks && ret == 0; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags)) { - struct block_device *bdev = rdev->bdev; - struct request_queue *r_queue = bdev_get_queue(bdev); - - if (!r_queue->issue_flush_fn) - ret = -EOPNOTSUPP; - else { - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, - error_sector); - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - } - rcu_read_unlock(); - return ret; -} - static int raid1_congested(void *data, int bits) { mddev_t *mddev = data; @@ -1997,7 +1967,6 @@ static int run(mddev_t *mddev) mddev->array_size = mddev->size; mddev->queue->unplug_fn = raid1_unplug; - mddev->queue->issue_flush_fn = raid1_issue_flush; mddev->queue->backing_dev_info.congested_fn = raid1_congested; mddev->queue->backing_dev_info.congested_data = mddev; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 25a96c42bdb..fc6607acb6e 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -611,36 +611,6 @@ static void raid10_unplug(struct request_queue *q) md_wakeup_thread(mddev->thread); } -static int raid10_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - mddev_t *mddev = q->queuedata; - conf_t *conf = mddev_to_conf(mddev); - int i, ret = 0; - - rcu_read_lock(); - for (i=0; i<mddev->raid_disks && ret == 0; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags)) { - struct block_device *bdev = rdev->bdev; - struct request_queue *r_queue = bdev_get_queue(bdev); - - if (!r_queue->issue_flush_fn) - ret = -EOPNOTSUPP; - else { - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, - error_sector); - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - } - rcu_read_unlock(); - return ret; -} - static int raid10_congested(void *data, int bits) { mddev_t *mddev = data; @@ -2118,7 +2088,6 @@ static int run(mddev_t *mddev) mddev->resync_max_sectors = size << conf->chunk_shift; mddev->queue->unplug_fn = raid10_unplug; - mddev->queue->issue_flush_fn = raid10_issue_flush; mddev->queue->backing_dev_info.congested_fn = raid10_congested; mddev->queue->backing_dev_info.congested_data = mddev; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index caaca9e178b..8ee181a01f5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3204,36 +3204,6 @@ static void raid5_unplug_device(struct request_queue *q) unplug_slaves(mddev); } -static int raid5_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - mddev_t *mddev = q->queuedata; - raid5_conf_t *conf = mddev_to_conf(mddev); - int i, ret = 0; - - rcu_read_lock(); - for (i=0; i<mddev->raid_disks && ret == 0; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags)) { - struct block_device *bdev = rdev->bdev; - struct request_queue *r_queue = bdev_get_queue(bdev); - - if (!r_queue->issue_flush_fn) - ret = -EOPNOTSUPP; - else { - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, - error_sector); - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - } - rcu_read_unlock(); - return ret; -} - static int raid5_congested(void *data, int bits) { mddev_t *mddev = data; @@ -4263,7 +4233,6 @@ static int run(mddev_t *mddev) mdname(mddev)); mddev->queue->unplug_fn = raid5_unplug_device; - mddev->queue->issue_flush_fn = raid5_issue_flush; mddev->queue->backing_dev_info.congested_data = mddev; mddev->queue->backing_dev_info.congested_fn = raid5_congested; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index bdff950a54a..626bb3c9af2 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -293,7 +293,7 @@ nextSGEset: for (ii=0; ii < (numSgeThisFrame-1); ii++) { thisxfer = sg_dma_len(sg); if (thisxfer == 0) { - sg ++; /* Get next SG element from the OS */ + sg = sg_next(sg); /* Get next SG element from the OS */ sg_done++; continue; } @@ -301,7 +301,7 @@ nextSGEset: v2 = sg_dma_address(sg); mptscsih_add_sge(psge, sgflags | thisxfer, v2); - sg++; /* Get next SG element from the OS */ + sg = sg_next(sg); /* Get next SG element from the OS */ psge += (sizeof(u32) + sizeof(dma_addr_t)); sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); sg_done++; @@ -322,7 +322,7 @@ nextSGEset: v2 = sg_dma_address(sg); mptscsih_add_sge(psge, sgflags | thisxfer, v2); /* - sg++; + sg = sg_next(sg); psge += (sizeof(u32) + sizeof(dma_addr_t)); */ sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); @@ -2605,14 +2605,10 @@ mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd) } /** - * SCPNT_TO_LOOKUP_IDX - * - * search's for a given scmd in the ScsiLookup[] array list - * + * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list * @ioc: Pointer to MPT_ADAPTER structure - * @scmd: scsi_cmnd pointer - * - **/ + * @sc: scsi_cmnd pointer + */ static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc) { diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 50b2c733441..d602ba6d541 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -149,29 +149,6 @@ static int i2o_block_device_flush(struct i2o_device *dev) }; /** - * i2o_block_issue_flush - device-flush interface for block-layer - * @queue: the request queue of the device which should be flushed - * @disk: gendisk - * @error_sector: error offset - * - * Helper function to provide flush functionality to block-layer. - * - * Returns 0 on success or negative error code on failure. - */ - -static int i2o_block_issue_flush(struct request_queue * queue, struct gendisk *disk, - sector_t * error_sector) -{ - struct i2o_block_device *i2o_blk_dev = queue->queuedata; - int rc = -ENODEV; - - if (likely(i2o_blk_dev)) - rc = i2o_block_device_flush(i2o_blk_dev->i2o_dev); - - return rc; -} - -/** * i2o_block_device_mount - Mount (load) the media of device dev * @dev: I2O device which should receive the mount request * @media_id: Media Identifier @@ -1009,7 +986,6 @@ static struct i2o_block_device *i2o_block_device_alloc(void) } blk_queue_prep_rq(queue, i2o_block_prep_req_fn); - blk_queue_issue_flush_fn(queue, i2o_block_issue_flush); gd->major = I2O_MAJOR; gd->queue = queue; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index b0abc7d9280..a5d0354bbbd 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -153,14 +153,14 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock blk_queue_max_hw_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); - mq->sg = kmalloc(sizeof(struct scatterlist), + mq->sg = kzalloc(sizeof(struct scatterlist), GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } - mq->bounce_sg = kmalloc(sizeof(struct scatterlist) * + mq->bounce_sg = kzalloc(sizeof(struct scatterlist) * bouncesz / 512, GFP_KERNEL); if (!mq->bounce_sg) { ret = -ENOMEM; @@ -177,7 +177,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); - mq->sg = kmalloc(sizeof(struct scatterlist) * + mq->sg = kzalloc(sizeof(struct scatterlist) * host->max_phys_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 254b194e762..71b986b38c5 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1280,8 +1280,8 @@ static int mmc_spi_probe(struct spi_device *spi) if (!host->data) goto fail_nobuf1; - if (spi->master->cdev.dev->dma_mask) { - struct device *dev = spi->master->cdev.dev; + if (spi->master->dev.parent->dma_mask) { + struct device *dev = spi->master->dev.parent; host->dma_dev = dev; host->ones_dma = dma_map_single(dev, ones, diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index c0c77f82d05..f201bd67313 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -2,9 +2,7 @@ # PCCARD (PCMCIA/CardBus) bus subsystem configuration # -menu "PCCARD (PCMCIA/CardBus) support" - -config PCCARD +menuconfig PCCARD tristate "PCCard (PCMCIA/CardBus) support" depends on HOTPLUG ---help--- @@ -278,5 +276,3 @@ config PCCARD_IODYN bool endif # PCCARD - -endmenu diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c index 01874b0bb03..ce9d5c44a7b 100644 --- a/drivers/pcmcia/au1000_xxs1500.c +++ b/drivers/pcmcia/au1000_xxs1500.c @@ -50,7 +50,10 @@ #include <asm/au1000.h> #include <asm/au1000_pcmcia.h> -#include <asm/xxs1500.h> + +#define PCMCIA_MAX_SOCK 0 +#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1) +#define PCMCIA_IRQ AU1000_GPIO_4 #if 0 #define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index d154dee76e7..06a85d7d5aa 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -25,6 +25,7 @@ #include <linux/ioport.h> #include <asm/io.h> #include <asm/byteorder.h> +#include <asm/unaligned.h> #include <pcmcia/cs_types.h> #include <pcmcia/ss.h> @@ -401,6 +402,15 @@ EXPORT_SYMBOL(pcmcia_replace_cis); ======================================================================*/ +static inline u16 cis_get_u16(void *ptr) +{ + return le16_to_cpu(get_unaligned((__le16 *) ptr)); +} +static inline u32 cis_get_u32(void *ptr) +{ + return le32_to_cpu(get_unaligned((__le32 *) ptr)); +} + typedef struct tuple_flags { u_int link_space:4; u_int has_link:1; @@ -461,7 +471,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) /* Get indirect link from the MFC tuple */ read_cis_cache(s, LINK_SPACE(tuple->Flags), tuple->LinkOffset, 5, link); - ofs = le32_to_cpu(*(__le32 *)(link+1)); + ofs = cis_get_u32(link + 1); SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); /* Move to the next indirect link */ tuple->LinkOffset += 5; @@ -668,10 +678,10 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) u_char *p; if (tuple->TupleDataLen < 5) return CS_BAD_TUPLE; - p = (u_char *)tuple->TupleData; - csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(__le16 *)p)-2; - csum->len = le16_to_cpu(*(__le16 *)(p + 2)); - csum->sum = *(p+4); + p = (u_char *) tuple->TupleData; + csum->addr = tuple->CISOffset + cis_get_u16(p) - 2; + csum->len = cis_get_u16(p + 2); + csum->sum = *(p + 4); return CS_SUCCESS; } @@ -681,7 +691,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) { if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - link->addr = le32_to_cpu(*(__le32 *)tuple->TupleData); + link->addr = cis_get_u32(tuple->TupleData); return CS_SUCCESS; } @@ -700,7 +710,8 @@ static int parse_longlink_mfc(tuple_t *tuple, return CS_BAD_TUPLE; for (i = 0; i < link->nfn; i++) { link->fn[i].space = *p; p++; - link->fn[i].addr = le32_to_cpu(*(__le32 *)p); p += 4; + link->fn[i].addr = cis_get_u32(p); + p += 4; } return CS_SUCCESS; } @@ -787,12 +798,10 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) { - __le16 *p; if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - p = (__le16 *)tuple->TupleData; - m->manf = le16_to_cpu(p[0]); - m->card = le16_to_cpu(p[1]); + m->manf = cis_get_u16(tuple->TupleData); + m->card = cis_get_u16(tuple->TupleData + 2); return CS_SUCCESS; } @@ -1091,7 +1100,7 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x20: entry->mem.nwin = 1; - entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8; + entry->mem.win[0].len = cis_get_u16(p) << 8; entry->mem.win[0].card_addr = 0; entry->mem.win[0].host_addr = 0; p += 2; @@ -1099,9 +1108,8 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x40: entry->mem.nwin = 1; - entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8; - entry->mem.win[0].card_addr = - le16_to_cpu(*(__le16 *)(p+2)) << 8; + entry->mem.win[0].len = cis_get_u16(p) << 8; + entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8; entry->mem.win[0].host_addr = 0; p += 4; if (p > q) return CS_BAD_TUPLE; @@ -1138,7 +1146,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) p = (u_char *)tuple->TupleData; bar->attr = *p; p += 2; - bar->size = le32_to_cpu(*(__le32 *)p); + bar->size = cis_get_u32(p); return CS_SUCCESS; } @@ -1151,7 +1159,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) return CS_BAD_TUPLE; config->last_idx = *(++p); p++; - config->base = le32_to_cpu(*(__le32 *)p); + config->base = cis_get_u32(p); config->subtuples = tuple->TupleDataLen - 6; return CS_SUCCESS; } @@ -1267,7 +1275,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) v2->vers = p[0]; v2->comply = p[1]; - v2->dindex = le16_to_cpu(*(__le16 *)(p+2)); + v2->dindex = cis_get_u16(p +2 ); v2->vspec8 = p[6]; v2->vspec9 = p[7]; v2->nhdr = p[8]; @@ -1308,8 +1316,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) fmt->type = p[0]; fmt->edc = p[1]; - fmt->offset = le32_to_cpu(*(__le32 *)(p+2)); - fmt->length = le32_to_cpu(*(__le32 *)(p+6)); + fmt->offset = cis_get_u32(p + 2); + fmt->length = cis_get_u32(p + 6); return CS_SUCCESS; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 55baa1f0fcb..7bf78c12789 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -23,6 +23,7 @@ #include <linux/crc32.h> #include <linux/firmware.h> #include <linux/kref.h> +#include <linux/dma-mapping.h> #define IN_CARD_SERVICES #include <pcmcia/cs_types.h> @@ -670,6 +671,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.parent = s->dev.parent; p_dev->dev.release = pcmcia_release_dev; + /* by default don't allow DMA */ + p_dev->dma_mask = DMA_MASK_NONE; + p_dev->dev.dma_mask = &p_dev->dma_mask; bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL); diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index dca9f8549b3..874923fcb2f 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -58,7 +58,7 @@ static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns, u_int mem_clk_10khz) { u_int code = pcmcia_cycle_ns * mem_clk_10khz; - return (code / 300000) + ((code % 300000) ? 1 : 0) - 1; + return (code / 300000) + ((code % 300000) ? 1 : 0) + 1; } static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns, diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 85e21614f86..397f4ce849d 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/notifier.h> #include <linux/ioctl.h> +#include <linux/fb.h> #include <asm/firmware.h> #include <asm/ps3av.h> @@ -33,6 +34,8 @@ #define BUFSIZE 4096 /* vuart buf size */ #define PS3AV_BUF_SIZE 512 /* max packet size */ +static int safe_mode; + static int timeout = 5000; /* in msec ( 5 sec ) */ module_param(timeout, int, 0644); @@ -491,10 +494,10 @@ static int ps3av_set_videomode(void) return 0; } -static void ps3av_set_videomode_cont(u32 id, u32 old_id) +static void ps3av_set_videomode_packet(u32 id) { struct ps3av_pkt_avb_param avb_param; - int i; + unsigned int i; u32 len = 0, av_video_cs; const struct avset_video_mode *video_mode; int res; @@ -507,24 +510,6 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) ps3av->av_hw_conf.num_of_avmulti; avb_param.num_of_av_audio_pkt = 0; - /* video signal off */ - ps3av_set_video_disable_sig(); - - /* Retail PS3 product doesn't support this */ - if (id & PS3AV_MODE_HDCP_OFF) { - res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); - if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) - dev_dbg(&ps3av->dev->core, "Not supported\n"); - else if (res) - dev_dbg(&ps3av->dev->core, - "ps3av_cmd_av_hdmi_mode failed\n"); - } else if (old_id & PS3AV_MODE_HDCP_OFF) { - res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); - if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) - dev_dbg(&ps3av->dev->core, - "ps3av_cmd_av_hdmi_mode failed\n"); - } - /* video_pkt */ for (i = 0; i < avb_param.num_of_video_pkt; i++) len += ps3av_cmd_set_video_mode(&avb_param.buf[len], @@ -555,6 +540,42 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) __func__); else if (res) dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); +} + +static void ps3av_set_videomode_cont(u32 id, u32 old_id) +{ + static int vesa = 0; + int res; + + /* video signal off */ + ps3av_set_video_disable_sig(); + + /* + * AV backend needs non-VESA mode setting at least one time + * when VESA mode is used. + */ + if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) { + /* vesa mode */ + ps3av_set_videomode_packet(2); /* 480P */ + } + vesa = 1; + + /* Retail PS3 product doesn't support this */ + if (id & PS3AV_MODE_HDCP_OFF) { + res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); + if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) + dev_dbg(&ps3av->dev->core, "Not supported\n"); + else if (res) + dev_dbg(&ps3av->dev->core, + "ps3av_cmd_av_hdmi_mode failed\n"); + } else if (old_id & PS3AV_MODE_HDCP_OFF) { + res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); + if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) + dev_dbg(&ps3av->dev->core, + "ps3av_cmd_av_hdmi_mode failed\n"); + } + + ps3av_set_videomode_packet(id); msleep(1500); /* av video mute */ @@ -567,165 +588,251 @@ static void ps3avd(struct work_struct *work) complete(&ps3av->done); } -static int ps3av_vid2table_id(int vid) -{ - int i; - - for (i = 1; i < ARRAY_SIZE(video_mode_table); i++) - if (video_mode_table[i].vid == vid) - return i; - return -1; -} +#define SHIFT_50 0 +#define SHIFT_60 4 +#define SHIFT_VESA 8 + +static const struct { + unsigned mask : 19; + unsigned id : 4; +} ps3av_preferred_modes[] = { + { .mask = PS3AV_RESBIT_WUXGA << SHIFT_VESA, .id = 13 }, + { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_60, .id = 5 }, + { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_50, .id = 10 }, + { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_60, .id = 4 }, + { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_50, .id = 9 }, + { .mask = PS3AV_RESBIT_SXGA << SHIFT_VESA, .id = 12 }, + { .mask = PS3AV_RESBIT_WXGA << SHIFT_VESA, .id = 11 }, + { .mask = PS3AV_RESBIT_1280x720P << SHIFT_60, .id = 3 }, + { .mask = PS3AV_RESBIT_1280x720P << SHIFT_50, .id = 8 }, + { .mask = PS3AV_RESBIT_720x480P << SHIFT_60, .id = 2 }, + { .mask = PS3AV_RESBIT_720x576P << SHIFT_50, .id = 7 }, +}; -static int ps3av_resbit2vid(u32 res_50, u32 res_60) +static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa) { - int vid = -1; + unsigned int i; + u32 res_all; + + /* + * We mask off the resolution bits we care about and combine the + * results in one bitfield, so make sure there's no overlap + */ + BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & + PS3AV_RES_MASK_60 << SHIFT_60); + BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 & + PS3AV_RES_MASK_VESA << SHIFT_VESA); + BUILD_BUG_ON(PS3AV_RES_MASK_60 << SHIFT_60 & + PS3AV_RES_MASK_VESA << SHIFT_VESA); + res_all = (res_50 & PS3AV_RES_MASK_50) << SHIFT_50 | + (res_60 & PS3AV_RES_MASK_60) << SHIFT_60 | + (res_vesa & PS3AV_RES_MASK_VESA) << SHIFT_VESA; + + if (!res_all) + return 0; + + for (i = 0; i < ARRAY_SIZE(ps3av_preferred_modes); i++) + if (res_all & ps3av_preferred_modes[i].mask) + return ps3av_preferred_modes[i].id; - if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */ - if (res_50 & PS3AV_RESBIT_1920x1080P) - vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ; - else if (res_50 & PS3AV_RESBIT_1920x1080I) - vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ; - else if (res_50 & PS3AV_RESBIT_1280x720P) - vid = PS3AV_CMD_VIDEO_VID_720P_50HZ; - else if (res_50 & PS3AV_RESBIT_720x576P) - vid = PS3AV_CMD_VIDEO_VID_576P; - else - vid = -1; - } else { - if (res_60 & PS3AV_RESBIT_1920x1080P) - vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ; - else if (res_60 & PS3AV_RESBIT_1920x1080I) - vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ; - else if (res_60 & PS3AV_RESBIT_1280x720P) - vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; - else if (res_60 & PS3AV_RESBIT_720x480P) - vid = PS3AV_CMD_VIDEO_VID_480P; - else - vid = -1; - } - return vid; + return 0; } -static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info) +static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info) { - u32 res_50, res_60; - int vid = -1; + int id; - if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI) - return -1; + if (safe_mode) + return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; /* check native resolution */ - res_50 = info->res_50.native & PS3AV_RES_MASK_50; - res_60 = info->res_60.native & PS3AV_RES_MASK_60; - if (res_50 || res_60) { - vid = ps3av_resbit2vid(res_50, res_60); - return vid; + id = ps3av_resbit2id(info->res_50.native, info->res_60.native, + info->res_vesa.native); + if (id) { + pr_debug("%s: Using native mode %d\n", __func__, id); + return id; } - /* check resolution */ - res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50; - res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60; - if (res_50 || res_60) { - vid = ps3av_resbit2vid(res_50, res_60); - return vid; + /* check supported resolutions */ + id = ps3av_resbit2id(info->res_50.res_bits, info->res_60.res_bits, + info->res_vesa.res_bits); + if (id) { + pr_debug("%s: Using supported mode %d\n", __func__, id); + return id; } if (ps3av->region & PS3AV_REGION_60) - vid = PS3AV_DEFAULT_HDMI_VID_REG_60; + id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; else - vid = PS3AV_DEFAULT_HDMI_VID_REG_50; - return vid; + id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_50; + pr_debug("%s: Using default mode %d\n", __func__, id); + return id; } -static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf, - int boot) +static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info) { - int i, res, vid = -1, dvi = 0, rgb = 0; + const struct ps3av_info_monitor *info = &monitor_info->info; + const struct ps3av_info_audio *audio = info->audio; + char id[sizeof(info->monitor_id)*3+1]; + int i; + + pr_debug("Monitor Info: size %u\n", monitor_info->send_hdr.size); + + pr_debug("avport: %02x\n", info->avport); + for (i = 0; i < sizeof(info->monitor_id); i++) + sprintf(&id[i*3], " %02x", info->monitor_id[i]); + pr_debug("monitor_id: %s\n", id); + pr_debug("monitor_type: %02x\n", info->monitor_type); + pr_debug("monitor_name: %.*s\n", (int)sizeof(info->monitor_name), + info->monitor_name); + + /* resolution */ + pr_debug("resolution_60: bits: %08x native: %08x\n", + info->res_60.res_bits, info->res_60.native); + pr_debug("resolution_50: bits: %08x native: %08x\n", + info->res_50.res_bits, info->res_50.native); + pr_debug("resolution_other: bits: %08x native: %08x\n", + info->res_other.res_bits, info->res_other.native); + pr_debug("resolution_vesa: bits: %08x native: %08x\n", + info->res_vesa.res_bits, info->res_vesa.native); + + /* color space */ + pr_debug("color space rgb: %02x\n", info->cs.rgb); + pr_debug("color space yuv444: %02x\n", info->cs.yuv444); + pr_debug("color space yuv422: %02x\n", info->cs.yuv422); + + /* color info */ + pr_debug("color info red: X %04x Y %04x\n", info->color.red_x, + info->color.red_y); + pr_debug("color info green: X %04x Y %04x\n", info->color.green_x, + info->color.green_y); + pr_debug("color info blue: X %04x Y %04x\n", info->color.blue_x, + info->color.blue_y); + pr_debug("color info white: X %04x Y %04x\n", info->color.white_x, + info->color.white_y); + pr_debug("color info gamma: %08x\n", info->color.gamma); + + /* other info */ + pr_debug("supported_AI: %02x\n", info->supported_ai); + pr_debug("speaker_info: %02x\n", info->speaker_info); + pr_debug("num of audio: %02x\n", info->num_of_audio_block); + + /* audio block */ + for (i = 0; i < info->num_of_audio_block; i++) { + pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: " + "%02x\n", + i, audio->type, audio->max_num_of_ch, audio->fs, + audio->sbit); + audio++; + } +} + +static const struct ps3av_monitor_quirk { + const char *monitor_name; + u32 clear_60, clear_50, clear_vesa; +} ps3av_monitor_quirks[] = { + { + .monitor_name = "DELL 2007WFP", + .clear_60 = PS3AV_RESBIT_1920x1080I + }, { + .monitor_name = "L226WTQ", + .clear_60 = PS3AV_RESBIT_1920x1080I | + PS3AV_RESBIT_1920x1080P + }, { + .monitor_name = "SyncMaster", + .clear_60 = PS3AV_RESBIT_1920x1080I + } +}; + +static void ps3av_fixup_monitor_info(struct ps3av_info_monitor *info) +{ + unsigned int i; + const struct ps3av_monitor_quirk *quirk; + + for (i = 0; i < ARRAY_SIZE(ps3av_monitor_quirks); i++) { + quirk = &ps3av_monitor_quirks[i]; + if (!strncmp(info->monitor_name, quirk->monitor_name, + sizeof(info->monitor_name))) { + pr_info("%s: Applying quirk for %s\n", __func__, + quirk->monitor_name); + info->res_60.res_bits &= ~quirk->clear_60; + info->res_60.native &= ~quirk->clear_60; + info->res_50.res_bits &= ~quirk->clear_50; + info->res_50.native &= ~quirk->clear_50; + info->res_vesa.res_bits &= ~quirk->clear_vesa; + info->res_vesa.native &= ~quirk->clear_vesa; + break; + } + } +} + +static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf) +{ + int i, res, id = 0, dvi = 0, rgb = 0; struct ps3av_pkt_av_get_monitor_info monitor_info; struct ps3av_info_monitor *info; - /* get vid for hdmi */ - for (i = 0; i < av_hw_conf->num_of_hdmi; i++) { + /* get mode id for hdmi */ + for (i = 0; i < av_hw_conf->num_of_hdmi && !id; i++) { res = ps3av_cmd_video_get_monitor_info(&monitor_info, PS3AV_CMD_AVPORT_HDMI_0 + i); if (res < 0) return -1; - ps3av_cmd_av_monitor_info_dump(&monitor_info); + ps3av_monitor_info_dump(&monitor_info); + info = &monitor_info.info; - /* check DVI */ - if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) { + ps3av_fixup_monitor_info(info); + + switch (info->monitor_type) { + case PS3AV_MONITOR_TYPE_DVI: dvi = PS3AV_MODE_DVI; - break; - } - /* check HDMI */ - vid = ps3av_hdmi_get_vid(info); - if (vid != -1) { - /* got valid vid */ + /* fall through */ + case PS3AV_MONITOR_TYPE_HDMI: + id = ps3av_hdmi_get_id(info); break; } } - if (dvi) { - /* DVI mode */ - vid = PS3AV_DEFAULT_DVI_VID; - } else if (vid == -1) { + if (!id) { /* no HDMI interface or HDMI is off */ if (ps3av->region & PS3AV_REGION_60) - vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; + id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60; else - vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; + id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50; if (ps3av->region & PS3AV_REGION_RGB) rgb = PS3AV_MODE_RGB; - } else if (boot) { - /* HDMI: using DEFAULT HDMI_VID while booting up */ - info = &monitor_info.info; - if (ps3av->region & PS3AV_REGION_60) { - if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) - vid = PS3AV_DEFAULT_HDMI_VID_REG_60; - else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) - vid = PS3AV_DEFAULT_HDMI_VID_REG_50; - else { - /* default */ - vid = PS3AV_DEFAULT_HDMI_VID_REG_60; - } - } else { - if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) - vid = PS3AV_DEFAULT_HDMI_VID_REG_50; - else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) - vid = PS3AV_DEFAULT_HDMI_VID_REG_60; - else { - /* default */ - vid = PS3AV_DEFAULT_HDMI_VID_REG_50; - } - } + pr_debug("%s: Using avmulti mode %d\n", __func__, id); } - return (ps3av_vid2table_id(vid) | dvi | rgb); + return id | dvi | rgb; } static int ps3av_get_hw_conf(struct ps3av *ps3av) { int i, j, k, res; + const struct ps3av_pkt_av_get_hw_conf *hw_conf; /* get av_hw_conf */ res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); if (res < 0) return -1; - ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf); + hw_conf = &ps3av->av_hw_conf; + pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi); + pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti); + pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif); for (i = 0; i < PS3AV_HEAD_MAX; i++) ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; - for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++) + for (i = 0; i < hw_conf->num_of_hdmi; i++) ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; - for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++) + for (j = 0; j < hw_conf->num_of_avmulti; j++) ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; - for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++) + for (k = 0; k < hw_conf->num_of_spdif; k++) ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; /* set all audio port */ @@ -738,7 +845,7 @@ static int ps3av_get_hw_conf(struct ps3av *ps3av) } /* set mode using id */ -int ps3av_set_video_mode(u32 id, int boot) +int ps3av_set_video_mode(u32 id) { int size; u32 option; @@ -752,7 +859,7 @@ int ps3av_set_video_mode(u32 id, int boot) /* auto mode */ option = id & ~PS3AV_MODE_MASK; if ((id & PS3AV_MODE_MASK) == 0) { - id = ps3av_auto_videomode(&ps3av->av_hw_conf, boot); + id = ps3av_auto_videomode(&ps3av->av_hw_conf); if (id < 1) { printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); return -EINVAL; @@ -772,34 +879,13 @@ int ps3av_set_video_mode(u32 id, int boot) EXPORT_SYMBOL_GPL(ps3av_set_video_mode); -int ps3av_get_auto_mode(int boot) +int ps3av_get_auto_mode(void) { - return ps3av_auto_videomode(&ps3av->av_hw_conf, boot); + return ps3av_auto_videomode(&ps3av->av_hw_conf); } EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); -int ps3av_set_mode(u32 id, int boot) -{ - int res; - - res = ps3av_set_video_mode(id, boot); - if (res) - return res; - - res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2, - PS3AV_CMD_AUDIO_FS_48K, - PS3AV_CMD_AUDIO_WORD_BITS_16, - PS3AV_CMD_AUDIO_FORMAT_PCM, - PS3AV_CMD_AUDIO_SOURCE_SERIAL); - if (res) - return res; - - return 0; -} - -EXPORT_SYMBOL_GPL(ps3av_set_mode); - int ps3av_get_mode(void) { return ps3av ? ps3av->ps3av_mode : 0; @@ -941,7 +1027,14 @@ static int ps3av_probe(struct ps3_system_bus_device *dev) res); ps3av_get_hw_conf(ps3av); - id = ps3av_auto_videomode(&ps3av->av_hw_conf, 1); + +#ifdef CONFIG_FB + if (fb_mode_option && !strcmp(fb_mode_option, "safe")) + safe_mode = 1; +#endif /* CONFIG_FB */ + id = ps3av_auto_videomode(&ps3av->av_hw_conf); + safe_mode = 0; + mutex_lock(&ps3av->mutex); ps3av->ps3av_mode = id; mutex_unlock(&ps3av->mutex); diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index f72f5ddf18e..7f880c26122 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c @@ -512,7 +512,6 @@ static const u32 ps3av_ns_table[][5] = { static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) { u32 av_vid, ns_val; - u8 *p = ns; int d; d = ns_val = 0; @@ -551,24 +550,22 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) else ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d]; - *p++ = ns_val & 0x000000FF; - *p++ = (ns_val & 0x0000FF00) >> 8; - *p = (ns_val & 0x00FF0000) >> 16; + *ns++ = ns_val & 0x000000FF; + *ns++ = (ns_val & 0x0000FF00) >> 8; + *ns = (ns_val & 0x00FF0000) >> 16; } #undef BASE static u8 ps3av_cnv_enable(u32 source, const u8 *enable) { - const u8 *p; u8 ret = 0; if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) { ret = 0x03; } else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) { - p = enable; - ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) | - 0x01; + ret = ((enable[0] << 4) + (enable[1] << 5) + (enable[2] << 6) + + (enable[3] << 7)) | 0x01; } else printk(KERN_ERR "%s failed, source:%x\n", __func__, source); return ret; @@ -576,11 +573,9 @@ static u8 ps3av_cnv_enable(u32 source, const u8 *enable) static u8 ps3av_cnv_fifomap(const u8 *map) { - const u8 *p; u8 ret = 0; - p = map; - ret = p[0] + (p[1] << 2) + (p[2] << 4) + (p[3] << 6); + ret = map[0] + (map[1] << 2) + (map[2] << 4) + (map[3] << 6); return ret; } @@ -927,72 +922,6 @@ int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *info, return res; } -#ifdef PS3AV_DEBUG -void ps3av_cmd_av_hw_conf_dump(const struct ps3av_pkt_av_get_hw_conf *hw_conf) -{ - printk("av_h_conf:num of hdmi:%d\n", hw_conf->num_of_hdmi); - printk("av_h_conf:num of avmulti:%d\n", hw_conf->num_of_avmulti); - printk("av_h_conf:num of spdif:%d\n", hw_conf->num_of_spdif); -} - -void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info) -{ - const struct ps3av_info_monitor *info = &monitor_info->info; - const struct ps3av_info_audio *audio = info->audio; - int i; - - printk("Monitor Info: size%d\n", monitor_info->send_hdr.size); - - printk("avport:%02x\n", info->avport); - printk("monitor_id:"); - for (i = 0; i < 10; i++) - printk("%02x ", info->monitor_id[i]); - printk("\nmonitor_type:%02x\n", info->monitor_type); - printk("monitor_name:"); - for (i = 0; i < 16; i++) - printk("%c", info->monitor_name[i]); - - /* resolution */ - printk("\nresolution_60: bits:%08x native:%08x\n", - info->res_60.res_bits, info->res_60.native); - printk("resolution_50: bits:%08x native:%08x\n", - info->res_50.res_bits, info->res_50.native); - printk("resolution_other: bits:%08x native:%08x\n", - info->res_other.res_bits, info->res_other.native); - printk("resolution_vesa: bits:%08x native:%08x\n", - info->res_vesa.res_bits, info->res_vesa.native); - - /* color space */ - printk("color space rgb:%02x\n", info->cs.rgb); - printk("color space yuv444:%02x\n", info->cs.yuv444); - printk("color space yuv422:%02x\n", info->cs.yuv422); - - /* color info */ - printk("color info red:X %04x Y %04x\n", - info->color.red_x, info->color.red_y); - printk("color info green:X %04x Y %04x\n", - info->color.green_x, info->color.green_y); - printk("color info blue:X %04x Y %04x\n", - info->color.blue_x, info->color.blue_y); - printk("color info white:X %04x Y %04x\n", - info->color.white_x, info->color.white_y); - printk("color info gamma: %08x\n", info->color.gamma); - - /* other info */ - printk("supported_AI:%02x\n", info->supported_ai); - printk("speaker_info:%02x\n", info->speaker_info); - printk("num of audio:%02x\n", info->num_of_audio_block); - - /* audio block */ - for (i = 0; i < info->num_of_audio_block; i++) { - printk("audio[%d] type:%02x max_ch:%02x fs:%02x sbit:%02x\n", - i, audio->type, audio->max_num_of_ch, audio->fs, - audio->sbit); - audio++; - } -} -#endif /* PS3AV_DEBUG */ - #define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \ | PS3AV_CMD_AV_LAYOUT_44 \ | PS3AV_CMD_AV_LAYOUT_48) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index ff9e35cb308..6420a90a4a9 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -139,6 +139,17 @@ config RTC_DRV_DS1307 This driver can also be built as a module. If so, the module will be called rtc-ds1307. +config RTC_DRV_DS1374 + tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" + depends on RTC_CLASS && I2C + help + If you say yes here you get support for Dallas Semiconductor + DS1374 real-time clock chips. If an interrupt is associated + with the device, the alarm functionality is supported. + + This driver can also be built as a module. If so, the module + will be called rtc-ds1374. + config RTC_DRV_DS1672 tristate "Dallas/Maxim DS1672" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3a33aa2696..465db4dd50b 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o +obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 10ab3b71ffc..4dfdf019fcc 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -153,6 +153,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, mutex_init(&rtc->ops_lock); spin_lock_init(&rtc->irq_lock); spin_lock_init(&rtc->irq_task_lock); + init_waitqueue_head(&rtc->irq_queue); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index ad66c6ecf36..de0da545c7a 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -12,6 +12,7 @@ */ #include <linux/rtc.h> +#include <linux/log2.h> int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) { @@ -99,7 +100,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) } EXPORT_SYMBOL_GPL(rtc_set_mmss); -int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; @@ -119,6 +120,87 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) mutex_unlock(&rtc->ops_lock); return err; } + +int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +{ + int err; + struct rtc_time before, now; + int first_time = 1; + + /* The lower level RTC driver may not be capable of filling + * in all fields of the rtc_time struct (eg. rtc-cmos), + * and so might instead return -1 in some fields. + * We deal with that here by grabbing a current RTC timestamp + * and using values from that for any missing (-1) values. + * + * But this can be racey, because some fields of the RTC timestamp + * may have wrapped in the interval since we read the RTC alarm, + * which would lead to us inserting inconsistent values in place + * of the -1 fields. + * + * Reading the alarm and timestamp in the reverse sequence + * would have the same race condition, and not solve the issue. + * + * So, we must first read the RTC timestamp, + * then read the RTC alarm value, + * and then read a second RTC timestamp. + * + * If any fields of the second timestamp have changed + * when compared with the first timestamp, then we know + * our timestamp may be inconsistent with that used by + * the low-level rtc_read_alarm_internal() function. + * + * So, when the two timestamps disagree, we just loop and do + * the process again to get a fully consistent set of values. + * + * This could all instead be done in the lower level driver, + * but since more than one lower level RTC implementation needs it, + * then it's probably best best to do it here instead of there.. + */ + + /* Get the "before" timestamp */ + err = rtc_read_time(rtc, &before); + if (err < 0) + return err; + do { + if (!first_time) + memcpy(&before, &now, sizeof(struct rtc_time)); + first_time = 0; + + /* get the RTC alarm values, which may be incomplete */ + err = rtc_read_alarm_internal(rtc, alarm); + if (err) + return err; + if (!alarm->enabled) + return 0; + + /* get the "after" timestamp, to detect wrapped fields */ + err = rtc_read_time(rtc, &now); + if (err < 0) + return err; + + /* note that tm_sec is a "don't care" value here: */ + } while ( before.tm_min != now.tm_min + || before.tm_hour != now.tm_hour + || before.tm_mon != now.tm_mon + || before.tm_year != now.tm_year + || before.tm_isdst != now.tm_isdst); + + /* Fill in any missing alarm fields using the timestamp */ + if (alarm->time.tm_sec == -1) + alarm->time.tm_sec = now.tm_sec; + if (alarm->time.tm_min == -1) + alarm->time.tm_min = now.tm_min; + if (alarm->time.tm_hour == -1) + alarm->time.tm_hour = now.tm_hour; + if (alarm->time.tm_mday == -1) + alarm->time.tm_mday = now.tm_mday; + if (alarm->time.tm_mon == -1) + alarm->time.tm_mon = now.tm_mon; + if (alarm->time.tm_year == -1) + alarm->time.tm_year = now.tm_year; + return 0; +} EXPORT_SYMBOL_GPL(rtc_read_alarm); int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) @@ -210,6 +292,10 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) if (task == NULL || task->func == NULL) return -EINVAL; + /* Cannot register while the char dev is in use */ + if (!(mutex_trylock(&rtc->char_lock))) + return -EBUSY; + spin_lock_irq(&rtc->irq_task_lock); if (rtc->irq_task == NULL) { rtc->irq_task = task; @@ -217,13 +303,14 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) } spin_unlock_irq(&rtc->irq_task_lock); + mutex_unlock(&rtc->char_lock); + return retval; } EXPORT_SYMBOL_GPL(rtc_irq_register); void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) { - spin_lock_irq(&rtc->irq_task_lock); if (rtc->irq_task == task) rtc->irq_task = NULL; @@ -231,6 +318,16 @@ void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) } EXPORT_SYMBOL_GPL(rtc_irq_unregister); +/** + * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs + * @rtc: the rtc device + * @task: currently registered with rtc_irq_register() + * @enabled: true to enable periodic IRQs + * Context: any + * + * Note that rtc_irq_set_freq() should previously have been used to + * specify the desired frequency of periodic IRQ task->func() callbacks. + */ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) { int err = 0; @@ -240,8 +337,10 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled return -ENXIO; spin_lock_irqsave(&rtc->irq_task_lock, flags); + if (rtc->irq_task != NULL && task == NULL) + err = -EBUSY; if (rtc->irq_task != task) - err = -ENXIO; + err = -EACCES; spin_unlock_irqrestore(&rtc->irq_task_lock, flags); if (err == 0) @@ -251,6 +350,16 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled } EXPORT_SYMBOL_GPL(rtc_irq_set_state); +/** + * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ + * @rtc: the rtc device + * @task: currently registered with rtc_irq_register() + * @freq: positive frequency with which task->func() will be called + * Context: any + * + * Note that rtc_irq_set_state() is used to enable or disable the + * periodic IRQs. + */ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) { int err = 0; @@ -259,9 +368,14 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) if (rtc->ops->irq_set_freq == NULL) return -ENXIO; + if (!is_power_of_2(freq)) + return -EINVAL; + spin_lock_irqsave(&rtc->irq_task_lock, flags); + if (rtc->irq_task != NULL && task == NULL) + err = -EBUSY; if (rtc->irq_task != task) - err = -ENXIO; + err = -EACCES; spin_unlock_irqrestore(&rtc->irq_task_lock, flags); if (err == 0) { diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 5d760bb6c2c..e3fe83a23cf 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -246,11 +246,9 @@ static int cmos_irq_set_freq(struct device *dev, int freq) /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */ f = ffs(freq); - if (f != 0) { - if (f-- > 16 || freq != (1 << f)) - return -EINVAL; - f = 16 - f; - } + if (f-- > 16) + return -EINVAL; + f = 16 - f; spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); @@ -435,6 +433,19 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) if (!ports) return -ENODEV; + /* Claim I/O ports ASAP, minimizing conflict with legacy driver. + * + * REVISIT non-x86 systems may instead use memory space resources + * (needing ioremap etc), not i/o space resources like this ... + */ + ports = request_region(ports->start, + ports->end + 1 - ports->start, + driver_name); + if (!ports) { + dev_dbg(dev, "i/o registers already in use\n"); + return -EBUSY; + } + cmos_rtc.irq = rtc_irq; cmos_rtc.iomem = ports; @@ -456,24 +467,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) cmos_rtc.rtc = rtc_device_register(driver_name, dev, &cmos_rtc_ops, THIS_MODULE); - if (IS_ERR(cmos_rtc.rtc)) - return PTR_ERR(cmos_rtc.rtc); + if (IS_ERR(cmos_rtc.rtc)) { + retval = PTR_ERR(cmos_rtc.rtc); + goto cleanup0; + } cmos_rtc.dev = dev; dev_set_drvdata(dev, &cmos_rtc); - - /* platform and pnp busses handle resources incompatibly. - * - * REVISIT for non-x86 systems we may need to handle io memory - * resources: ioremap them, and request_mem_region(). - */ - if (is_pnp()) { - retval = request_resource(&ioport_resource, ports); - if (retval < 0) { - dev_dbg(dev, "i/o registers already in use\n"); - goto cleanup0; - } - } rename_region(ports, cmos_rtc.rtc->dev.bus_id); spin_lock_irq(&rtc_lock); @@ -536,9 +536,10 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) return 0; cleanup1: - rename_region(ports, NULL); -cleanup0: + cmos_rtc.dev = NULL; rtc_device_unregister(cmos_rtc.rtc); +cleanup0: + release_region(ports->start, ports->end + 1 - ports->start); return retval; } @@ -557,19 +558,21 @@ static void cmos_do_shutdown(void) static void __exit cmos_do_remove(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); + struct resource *ports; cmos_do_shutdown(); - if (is_pnp()) - release_resource(cmos->iomem); - rename_region(cmos->iomem, NULL); - if (is_valid_irq(cmos->irq)) - free_irq(cmos->irq, cmos_rtc.rtc); + free_irq(cmos->irq, cmos->rtc); - rtc_device_unregister(cmos_rtc.rtc); + rtc_device_unregister(cmos->rtc); + cmos->rtc = NULL; - cmos_rtc.dev = NULL; + ports = cmos->iomem; + release_region(ports->start, ports->end + 1 - ports->start); + cmos->iomem = NULL; + + cmos->dev = NULL; dev_set_drvdata(dev, NULL); } @@ -656,7 +659,8 @@ static int cmos_resume(struct device *dev) /*----------------------------------------------------------------*/ /* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems, - * the device node will always be created as a PNPACPI device. + * the device node will always be created as a PNPACPI device. Plus + * pre-ACPI PCs probably list it in the PNPBIOS tables. */ #ifdef CONFIG_PNP diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 005fff3a350..814583bd2fe 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -142,7 +142,7 @@ static int set_uie(struct rtc_device *rtc) static ssize_t rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct rtc_device *rtc = to_rtc_device(file->private_data); + struct rtc_device *rtc = file->private_data; DECLARE_WAITQUEUE(wait, current); unsigned long data; @@ -196,7 +196,7 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) static unsigned int rtc_dev_poll(struct file *file, poll_table *wait) { - struct rtc_device *rtc = to_rtc_device(file->private_data); + struct rtc_device *rtc = file->private_data; unsigned long data; poll_wait(file, &rtc->irq_queue, wait); @@ -233,22 +233,12 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, break; case RTC_PIE_ON: - if (!capable(CAP_SYS_RESOURCE)) + if (rtc->irq_freq > rtc->max_user_freq && + !capable(CAP_SYS_RESOURCE)) return -EACCES; break; } - /* avoid conflicting IRQ users */ - if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) { - spin_lock_irq(&rtc->irq_task_lock); - if (rtc->irq_task) - err = -EBUSY; - spin_unlock_irq(&rtc->irq_task_lock); - - if (err < 0) - return err; - } - /* try the driver's ioctl interface */ if (ops->ioctl) { err = ops->ioctl(rtc->dev.parent, cmd, arg); @@ -338,18 +328,20 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, err = rtc_set_time(rtc, &tm); break; - case RTC_IRQP_READ: - if (ops->irq_set_freq) - err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); - else - err = -ENOTTY; + case RTC_PIE_ON: + err = rtc_irq_set_state(rtc, NULL, 1); + break; + + case RTC_PIE_OFF: + err = rtc_irq_set_state(rtc, NULL, 0); break; case RTC_IRQP_SET: - if (ops->irq_set_freq) - err = rtc_irq_set_freq(rtc, rtc->irq_task, arg); - else - err = -ENOTTY; + err = rtc_irq_set_freq(rtc, NULL, arg); + break; + + case RTC_IRQP_READ: + err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); break; #if 0 @@ -405,7 +397,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, static int rtc_dev_release(struct inode *inode, struct file *file) { - struct rtc_device *rtc = to_rtc_device(file->private_data); + struct rtc_device *rtc = file->private_data; #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL clear_uie(rtc); @@ -419,7 +411,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file) static int rtc_dev_fasync(int fd, struct file *file, int on) { - struct rtc_device *rtc = to_rtc_device(file->private_data); + struct rtc_device *rtc = file->private_data; return fasync_helper(fd, file, on, &rtc->async_queue); } @@ -449,8 +441,6 @@ void rtc_dev_prepare(struct rtc_device *rtc) rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); mutex_init(&rtc->char_lock); - spin_lock_init(&rtc->irq_lock); - init_waitqueue_head(&rtc->irq_queue); #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL INIT_WORK(&rtc->uie_task, rtc_uie_task); setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c new file mode 100644 index 00000000000..45bda186bef --- /dev/null +++ b/drivers/rtc/rtc-ds1374.c @@ -0,0 +1,449 @@ +/* + * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C + * + * Based on code by Randy Vinson <rvinson@mvista.com>, + * which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>. + * + * Copyright (C) 2006-2007 Freescale Semiconductor + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +/* + * It would be more efficient to use i2c msgs/i2c_transfer directly but, as + * recommened in .../Documentation/i2c/writing-clients section + * "Sending and receiving", using SMBus level communication is preferred. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/workqueue.h> + +#define DS1374_REG_TOD0 0x00 /* Time of Day */ +#define DS1374_REG_TOD1 0x01 +#define DS1374_REG_TOD2 0x02 +#define DS1374_REG_TOD3 0x03 +#define DS1374_REG_WDALM0 0x04 /* Watchdog/Alarm */ +#define DS1374_REG_WDALM1 0x05 +#define DS1374_REG_WDALM2 0x06 +#define DS1374_REG_CR 0x07 /* Control */ +#define DS1374_REG_CR_AIE 0x01 /* Alarm Int. Enable */ +#define DS1374_REG_CR_WDALM 0x20 /* 1=Watchdog, 0=Alarm */ +#define DS1374_REG_CR_WACE 0x40 /* WD/Alarm counter enable */ +#define DS1374_REG_SR 0x08 /* Status */ +#define DS1374_REG_SR_OSF 0x80 /* Oscillator Stop Flag */ +#define DS1374_REG_SR_AF 0x01 /* Alarm Flag */ +#define DS1374_REG_TCR 0x09 /* Trickle Charge */ + +struct ds1374 { + struct i2c_client *client; + struct rtc_device *rtc; + struct work_struct work; + + /* The mutex protects alarm operations, and prevents a race + * between the enable_irq() in the workqueue and the free_irq() + * in the remove function. + */ + struct mutex mutex; + int exiting; +}; + +static struct i2c_driver ds1374_driver; + +static int ds1374_read_rtc(struct i2c_client *client, u32 *time, + int reg, int nbytes) +{ + u8 buf[4]; + int ret; + int i; + + if (nbytes > 4) { + WARN_ON(1); + return -EINVAL; + } + + ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf); + + if (ret < 0) + return ret; + if (ret < nbytes) + return -EIO; + + for (i = nbytes - 1, *time = 0; i >= 0; i--) + *time = (*time << 8) | buf[i]; + + return 0; +} + +static int ds1374_write_rtc(struct i2c_client *client, u32 time, + int reg, int nbytes) +{ + u8 buf[4]; + int i; + + if (nbytes > 4) { + WARN_ON(1); + return -EINVAL; + } + + for (i = 0; i < nbytes; i++) { + buf[i] = time & 0xff; + time >>= 8; + } + + return i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf); +} + +static int ds1374_check_rtc_status(struct i2c_client *client) +{ + int ret = 0; + int control, stat; + + stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); + if (stat < 0) + return stat; + + if (stat & DS1374_REG_SR_OSF) + dev_warn(&client->dev, + "oscillator discontinuity flagged, " + "time unreliable\n"); + + stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF); + + ret = i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); + if (ret < 0) + return ret; + + /* If the alarm is pending, clear it before requesting + * the interrupt, so an interrupt event isn't reported + * before everything is initialized. + */ + + control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (control < 0) + return control; + + control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); + return i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); +} + +static int ds1374_read_time(struct device *dev, struct rtc_time *time) +{ + struct i2c_client *client = to_i2c_client(dev); + u32 itime; + int ret; + + ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4); + if (!ret) + rtc_time_to_tm(itime, time); + + return ret; +} + +static int ds1374_set_time(struct device *dev, struct rtc_time *time) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long itime; + + rtc_tm_to_time(time, &itime); + return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4); +} + +/* The ds1374 has a decrementer for an alarm, rather than a comparator. + * If the time of day is changed, then the alarm will need to be + * reset. + */ +static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1374 *ds1374 = i2c_get_clientdata(client); + u32 now, cur_alarm; + int cr, sr; + int ret = 0; + + if (client->irq < 0) + return -EINVAL; + + mutex_lock(&ds1374->mutex); + + cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (ret < 0) + goto out; + + sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR); + if (ret < 0) + goto out; + + ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4); + if (ret) + goto out; + + ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3); + if (ret) + goto out; + + rtc_time_to_tm(now + cur_alarm, &alarm->time); + alarm->enabled = !!(cr & DS1374_REG_CR_WACE); + alarm->pending = !!(sr & DS1374_REG_SR_AF); + +out: + mutex_unlock(&ds1374->mutex); + return ret; +} + +static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1374 *ds1374 = i2c_get_clientdata(client); + struct rtc_time now; + unsigned long new_alarm, itime; + int cr; + int ret = 0; + + if (client->irq < 0) + return -EINVAL; + + ret = ds1374_read_time(dev, &now); + if (ret < 0) + return ret; + + rtc_tm_to_time(&alarm->time, &new_alarm); + rtc_tm_to_time(&now, &itime); + + new_alarm -= itime; + + /* This can happen due to races, in addition to dates that are + * truly in the past. To avoid requiring the caller to check for + * races, dates in the past are assumed to be in the recent past + * (i.e. not something that we'd rather the caller know about via + * an error), and the alarm is set to go off as soon as possible. + */ + if (new_alarm <= 0) + new_alarm = 1; + + mutex_lock(&ds1374->mutex); + + ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (ret < 0) + goto out; + + /* Disable any existing alarm before setting the new one + * (or lack thereof). */ + cr &= ~DS1374_REG_CR_WACE; + + ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); + if (ret < 0) + goto out; + + ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3); + if (ret) + goto out; + + if (alarm->enabled) { + cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; + cr &= ~DS1374_REG_CR_WDALM; + + ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); + } + +out: + mutex_unlock(&ds1374->mutex); + return ret; +} + +static irqreturn_t ds1374_irq(int irq, void *dev_id) +{ + struct i2c_client *client = dev_id; + struct ds1374 *ds1374 = i2c_get_clientdata(client); + + disable_irq_nosync(irq); + schedule_work(&ds1374->work); + return IRQ_HANDLED; +} + +static void ds1374_work(struct work_struct *work) +{ + struct ds1374 *ds1374 = container_of(work, struct ds1374, work); + struct i2c_client *client = ds1374->client; + int stat, control; + + mutex_lock(&ds1374->mutex); + + stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); + if (stat < 0) + return; + + if (stat & DS1374_REG_SR_AF) { + stat &= ~DS1374_REG_SR_AF; + i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); + + control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (control < 0) + goto out; + + control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); + i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); + + /* rtc_update_irq() assumes that it is called + * from IRQ-disabled context. + */ + local_irq_disable(); + rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF); + local_irq_enable(); + } + +out: + if (!ds1374->exiting) + enable_irq(client->irq); + + mutex_unlock(&ds1374->mutex); +} + +static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1374 *ds1374 = i2c_get_clientdata(client); + int ret = -ENOIOCTLCMD; + + mutex_lock(&ds1374->mutex); + + switch (cmd) { + case RTC_AIE_OFF: + ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (ret < 0) + goto out; + + ret &= ~DS1374_REG_CR_WACE; + + ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); + if (ret < 0) + goto out; + + break; + + case RTC_AIE_ON: + ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (ret < 0) + goto out; + + ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; + ret &= ~DS1374_REG_CR_WDALM; + + ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); + if (ret < 0) + goto out; + + break; + } + +out: + mutex_unlock(&ds1374->mutex); + return ret; +} + +static const struct rtc_class_ops ds1374_rtc_ops = { + .read_time = ds1374_read_time, + .set_time = ds1374_set_time, + .read_alarm = ds1374_read_alarm, + .set_alarm = ds1374_set_alarm, + .ioctl = ds1374_ioctl, +}; + +static int ds1374_probe(struct i2c_client *client) +{ + struct ds1374 *ds1374; + int ret; + + ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL); + if (!ds1374) + return -ENOMEM; + + ds1374->client = client; + i2c_set_clientdata(client, ds1374); + + INIT_WORK(&ds1374->work, ds1374_work); + mutex_init(&ds1374->mutex); + + ret = ds1374_check_rtc_status(client); + if (ret) + goto out_free; + + if (client->irq >= 0) { + ret = request_irq(client->irq, ds1374_irq, 0, + "ds1374", client); + if (ret) { + dev_err(&client->dev, "unable to request IRQ\n"); + goto out_free; + } + } + + ds1374->rtc = rtc_device_register(client->name, &client->dev, + &ds1374_rtc_ops, THIS_MODULE); + if (IS_ERR(ds1374->rtc)) { + ret = PTR_ERR(ds1374->rtc); + dev_err(&client->dev, "unable to register the class device\n"); + goto out_irq; + } + + return 0; + +out_irq: + if (client->irq >= 0) + free_irq(client->irq, client); + +out_free: + i2c_set_clientdata(client, NULL); + kfree(ds1374); + return ret; +} + +static int __devexit ds1374_remove(struct i2c_client *client) +{ + struct ds1374 *ds1374 = i2c_get_clientdata(client); + + if (client->irq >= 0) { + mutex_lock(&ds1374->mutex); + ds1374->exiting = 1; + mutex_unlock(&ds1374->mutex); + + free_irq(client->irq, client); + flush_scheduled_work(); + } + + rtc_device_unregister(ds1374->rtc); + i2c_set_clientdata(client, NULL); + kfree(ds1374); + return 0; +} + +static struct i2c_driver ds1374_driver = { + .driver = { + .name = "rtc-ds1374", + .owner = THIS_MODULE, + }, + .probe = ds1374_probe, + .remove = __devexit_p(ds1374_remove), +}; + +static int __init ds1374_init(void) +{ + return i2c_add_driver(&ds1374_driver); +} + +static void __exit ds1374_exit(void) +{ + i2c_del_driver(&ds1374_driver); +} + +module_init(ds1374_init); +module_exit(ds1374_exit); + +MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>"); +MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 5ab3492817d..bb53c09bad1 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -395,7 +395,7 @@ static struct platform_driver ds1553_rtc_driver = { .probe = ds1553_rtc_probe, .remove = __devexit_p(ds1553_rtc_remove), .driver = { - .name = "ds1553", + .name = "rtc-ds1553", .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 67291b0f828..c535b78698e 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -251,7 +251,7 @@ static struct platform_driver ds1742_rtc_driver = { .probe = ds1742_rtc_probe, .remove = __devexit_p(ds1742_rtc_remove), .driver = { - .name = "ds1742", + .name = "rtc-ds1742", .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index d48b0337458..556d0e7da35 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -332,6 +332,9 @@ static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind) } }; + if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) + return 0; + pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); if (!pcf) return -ENOMEM; diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 69df94b4484..6cad0841f3c 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -73,11 +73,35 @@ rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr, return retval; } +static ssize_t +rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); +} + +static ssize_t +rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct rtc_device *rtc = to_rtc_device(dev); + unsigned long val = simple_strtoul(buf, NULL, 0); + + if (val >= 4096 || val == 0) + return -EINVAL; + + rtc->max_user_freq = (int)val; + + return n; +} + static struct device_attribute rtc_attrs[] = { __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL), __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), + __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, + rtc_sysfs_set_max_user_freq), { }, }; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 16e5563e0c6..57cac7008e0 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/mempool.h> #include <linux/syscalls.h> +#include <linux/scatterlist.h> #include <linux/ioctl.h> #include <scsi/scsi.h> #include <scsi/scsi_tcq.h> diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 3f105fdcf23..51d92b196ee 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -590,7 +590,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, */ int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, - struct scatterlist *sg, int sg_count, int max_sbals) + struct scatterlist *sgl, int sg_count, int max_sbals) { int sg_index; struct scatterlist *sg_segment; @@ -606,9 +606,7 @@ zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, sbale->flags |= sbtype; /* process all segements of scatter-gather list */ - for (sg_index = 0, sg_segment = sg, bytes = 0; - sg_index < sg_count; - sg_index++, sg_segment++) { + for_each_sg(sgl, sg_segment, sg_count, sg_index) { retval = zfcp_qdio_sbals_from_segment( fsf_req, sbtype, diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index efd9d8d3a89..fb14014ee16 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1990,6 +1990,7 @@ static struct scsi_host_template driver_template = { .max_sectors = TW_MAX_SECTORS, .cmd_per_lun = TW_MAX_CMDS_PER_LUN, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = twa_host_attrs, .emulated = 1 }; diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index c7995fc216e..a64153b9603 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2261,6 +2261,7 @@ static struct scsi_host_template driver_template = { .max_sectors = TW_MAX_SECTORS, .cmd_per_lun = TW_MAX_CMDS_PER_LUN, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = tw_host_attrs, .emulated = 1 }; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 9b206176f71..49e1ffa4b2f 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3575,6 +3575,7 @@ static struct scsi_host_template Bus_Logic_template = { .unchecked_isa_dma = 1, .max_sectors = 128, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; /* diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index eda8c48f6be..3168a179484 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -1066,7 +1066,8 @@ static struct scsi_host_template driver_template = .sg_tablesize = 32 /*SG_ALL*/ /*SG_NONE*/, .cmd_per_lun = 1 /* commands per lun */, .unchecked_isa_dma = 1 /* unchecked_isa_dma */, - .use_clustering = ENABLE_CLUSTERING + .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index f608d4a1d6d..d3a6d15fb77 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -1071,6 +1071,7 @@ static struct scsi_host_template inia100_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static int __devinit inia100_probe_one(struct pci_dev *pdev, diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index a7f42a17b5c..038980be763 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -944,6 +944,7 @@ static struct scsi_host_template aac_driver_template = { .cmd_per_lun = AAC_NUM_IO_FIB, #endif .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .emulated = 1, }; diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index cbbfbc9f3e0..961a1882cb7 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -61,15 +61,15 @@ static void BAD_DMA(void *address, unsigned int length) } static void BAD_SG_DMA(Scsi_Cmnd * SCpnt, - struct scatterlist *sgpnt, + struct scatterlist *sgp, int nseg, int badseg) { printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%llx length %u\n", badseg, nseg, - page_address(sgpnt[badseg].page) + sgpnt[badseg].offset, - (unsigned long long)SCSI_SG_PA(&sgpnt[badseg]), - sgpnt[badseg].length); + page_address(sgp->page) + sgp->offset, + (unsigned long long)SCSI_SG_PA(sgp), + sgp->length); /* * Not safe to continue. @@ -691,7 +691,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); if (SCpnt->use_sg) { - struct scatterlist *sgpnt; + struct scatterlist *sg; struct chain *cptr; #ifdef DEBUG unsigned char *ptr; @@ -699,23 +699,21 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) int i; ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA); - sgpnt = (struct scatterlist *) SCpnt->request_buffer; cptr = (struct chain *) SCpnt->host_scribble; if (cptr == NULL) { /* free the claimed mailbox slot */ HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL; return SCSI_MLQUEUE_HOST_BUSY; } - for (i = 0; i < SCpnt->use_sg; i++) { - if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 || - (((int) sgpnt[i].offset) & 1) || (sgpnt[i].length & 1)) { + scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) { + if (sg->length == 0 || SCpnt->use_sg > 16 || + (((int) sg->offset) & 1) || (sg->length & 1)) { unsigned char *ptr; printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i); - for (i = 0; i < SCpnt->use_sg; i++) { + scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) { printk(KERN_CRIT "%d: %p %d\n", i, - (page_address(sgpnt[i].page) + - sgpnt[i].offset), - sgpnt[i].length); + (page_address(sg->page) + + sg->offset), sg->length); }; printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr); ptr = (unsigned char *) &cptr[i]; @@ -723,10 +721,10 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) printk("%02x ", ptr[i]); panic("Foooooooood fight!"); }; - any2scsi(cptr[i].dataptr, SCSI_SG_PA(&sgpnt[i])); - if (SCSI_SG_PA(&sgpnt[i]) + sgpnt[i].length - 1 > ISA_DMA_THRESHOLD) - BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i); - any2scsi(cptr[i].datalen, sgpnt[i].length); + any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg)); + if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD) + BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i); + any2scsi(cptr[i].datalen, sg->length); }; any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain)); any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr)); diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index e4a4f3a965d..f6722fd4600 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -563,6 +563,7 @@ static struct scsi_host_template aha1740_template = { .sg_tablesize = AHA1740_SCATTER, .cmd_per_lun = AHA1740_CMDLUN, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .eh_abort_handler = aha1740_eh_abort_handler, }; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index a055a96e3ad..42c0f14a262 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -766,6 +766,7 @@ struct scsi_host_template aic79xx_driver_template = { .max_sectors = 8192, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, .target_alloc = ahd_linux_target_alloc, diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 2e9c38f2e8a..7770befbf50 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -747,6 +747,7 @@ struct scsi_host_template aic7xxx_driver_template = { .max_sectors = 8192, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .slave_alloc = ahc_linux_slave_alloc, .slave_configure = ahc_linux_slave_configure, .target_alloc = ahc_linux_target_alloc, diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 1a71b0236c9..4025608d696 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -11142,6 +11142,7 @@ static struct scsi_host_template driver_template = { .max_sectors = 2048, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index f2b23e01401..ee0a98bffcd 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -94,7 +94,7 @@ static inline int asd_map_scatterlist(struct sas_task *task, res = -ENOMEM; goto err_unmap; } - for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) { + for_each_sg(task->scatter, sc, num_sg, i) { struct sg_el *sg = &((struct sg_el *)ascb->sg_arr->vaddr)[i]; sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc)); @@ -103,7 +103,7 @@ static inline int asd_map_scatterlist(struct sas_task *task, sg->flags |= ASD_SG_EL_LIST_EOL; } - for (sc = task->scatter, i = 0; i < 2; i++, sc++) { + for_each_sg(task->scatter, sc, 2, i) { sg_arr[i].bus_addr = cpu_to_le64((u64)sg_dma_address(sc)); sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); @@ -115,7 +115,7 @@ static inline int asd_map_scatterlist(struct sas_task *task, sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle); } else { int i; - for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) { + for_each_sg(task->scatter, sc, num_sg, i) { sg_arr[i].bus_addr = cpu_to_le64((u64)sg_dma_address(sc)); sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index cfcf40159ea..f81777586b8 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -122,6 +122,7 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .max_sectors = ARCMSR_MAX_XFER_SECTORS, .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = arcmsr_host_attrs, }; #ifdef CONFIG_SCSI_ARCMSR_AER diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 1591824cf4b..fd42d478920 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -4765,6 +4765,7 @@ static struct scsi_host_template dc395x_driver_template = { .eh_bus_reset_handler = dc395x_eh_bus_reset, .unchecked_isa_dma = 0, .use_clustering = DISABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index bea9d659af1..8258506ba7d 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -3295,6 +3295,7 @@ static struct scsi_host_template adpt_template = { .this_id = 7, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static s32 adpt_scsi_register(adpt_hba* pHba) diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index ec2233114bc..7ead5210de9 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -523,7 +523,8 @@ static struct scsi_host_template driver_template = { .slave_configure = eata2x_slave_configure, .this_id = 7, .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING + .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index adc9559cb6f..112ab6abe62 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -343,6 +343,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->use_clustering = sht->use_clustering; shost->ordered_tag = sht->ordered_tag; shost->active_mode = sht->supported_mode; + shost->use_sg_chaining = sht->use_sg_chaining; if (sht->max_host_blocked) shost->max_host_blocked = sht->max_host_blocked; diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 8b384fa7f04..8515054cdf7 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -655,6 +655,7 @@ static struct scsi_host_template driver_template = { .unchecked_isa_dma = 0, .emulated = 0, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .proc_name = driver_name, .shost_attrs = hptiop_attrs, .this_id = -1, diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 1a924e9b027..714e6273a70 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -1501,6 +1501,7 @@ static struct scsi_host_template ibmmca_driver_template = { .sg_tablesize = 16, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static int ibmmca_probe(struct device *dev) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index cda0cc3d182..22d91ee173c 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1548,6 +1548,7 @@ static struct scsi_host_template driver_template = { .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = ibmvscsi_attrs, }; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index d81bb076a15..d297f64cd43 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -70,6 +70,7 @@ typedef struct idescsi_pc_s { u8 *buffer; /* Data buffer */ u8 *current_position; /* Pointer into the above buffer */ struct scatterlist *sg; /* Scatter gather table */ + struct scatterlist *last_sg; /* Last sg element */ int b_count; /* Bytes transferred from current entry */ struct scsi_cmnd *scsi_cmd; /* SCSI command */ void (*done)(struct scsi_cmnd *); /* Scsi completion routine */ @@ -173,12 +174,6 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne char *buf; while (bcount) { - if (pc->sg - scsi_sglist(pc->scsi_cmd) > - scsi_sg_count(pc->scsi_cmd)) { - printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); - idescsi_discard_data (drive, bcount); - return; - } count = min(pc->sg->length - pc->b_count, bcount); if (PageHighMem(pc->sg->page)) { unsigned long flags; @@ -197,10 +192,17 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { - pc->sg++; + if (pc->sg == pc->last_sg) + break; + pc->sg = sg_next(pc->sg); pc->b_count = 0; } } + + if (bcount) { + printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); + idescsi_discard_data (drive, bcount); + } } static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount) @@ -209,12 +211,6 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign char *buf; while (bcount) { - if (pc->sg - scsi_sglist(pc->scsi_cmd) > - scsi_sg_count(pc->scsi_cmd)) { - printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); - idescsi_output_zeros (drive, bcount); - return; - } count = min(pc->sg->length - pc->b_count, bcount); if (PageHighMem(pc->sg->page)) { unsigned long flags; @@ -233,10 +229,17 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { - pc->sg++; + if (pc->sg == pc->last_sg) + break; + pc->sg = sg_next(pc->sg); pc->b_count = 0; } } + + if (bcount) { + printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); + idescsi_output_zeros (drive, bcount); + } } static void hexdump(u8 *x, int len) @@ -804,6 +807,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd, memcpy (pc->c, cmd->cmnd, cmd->cmd_len); pc->buffer = NULL; pc->sg = scsi_sglist(cmd); + pc->last_sg = sg_last(pc->sg, cmd->use_sg); pc->b_count = 0; pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd); pc->scsi_cmd = cmd; diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index d9dfb69ae03..22d40fd5845 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2831,6 +2831,7 @@ static struct scsi_host_template initio_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static int initio_probe_one(struct pci_dev *pdev, diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 2ed099e2c20..edaac2714c5 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -3252,7 +3252,7 @@ ips_done(ips_ha_t * ha, ips_scb_t * scb) */ if ((scb->breakup) || (scb->sg_break)) { struct scatterlist *sg; - int sg_dma_index, ips_sg_index = 0; + int i, sg_dma_index, ips_sg_index = 0; /* we had a data breakup */ scb->data_len = 0; @@ -3261,20 +3261,22 @@ ips_done(ips_ha_t * ha, ips_scb_t * scb) /* Spin forward to last dma chunk */ sg_dma_index = scb->breakup; + for (i = 0; i < scb->breakup; i++) + sg = sg_next(sg); /* Take care of possible partial on last chunk */ ips_fill_scb_sg_single(ha, - sg_dma_address(&sg[sg_dma_index]), + sg_dma_address(sg), scb, ips_sg_index++, - sg_dma_len(&sg[sg_dma_index])); + sg_dma_len(sg)); for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd); - sg_dma_index++) { + sg_dma_index++, sg = sg_next(sg)) { if (ips_fill_scb_sg_single (ha, - sg_dma_address(&sg[sg_dma_index]), + sg_dma_address(sg), scb, ips_sg_index++, - sg_dma_len(&sg[sg_dma_index])) < 0) + sg_dma_len(sg)) < 0) break; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index cd674938ccd..c0755565fae 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1438,6 +1438,7 @@ struct scsi_host_template lpfc_template = { .scan_finished = lpfc_scan_finished, .this_id = -1, .sg_tablesize = LPFC_SG_SEG_CNT, + .use_sg_chaining = ENABLE_SG_CHAINING, .cmd_per_lun = LPFC_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_hba_attrs, @@ -1460,6 +1461,7 @@ struct scsi_host_template lpfc_vport_template = { .sg_tablesize = LPFC_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = lpfc_vport_attrs, .max_sectors = 0xFFFF, }; diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index b12ad7c7c67..a035001f443 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -402,6 +402,7 @@ static struct scsi_host_template mac53c94_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match) diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index cdbcaa5ad6c..abe2bda6ac3 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -53,6 +53,11 @@ #include "scsi.h" #include <scsi/scsi_host.h> #include "mac_scsi.h" + +/* These control the behaviour of the generic 5380 core */ +#define AUTOSENSE +#define PSEUDO_DMA + #include "NCR5380.h" #if 0 @@ -571,10 +576,6 @@ static int macscsi_pwrite (struct Scsi_Host *instance, } -/* These control the behaviour of the generic 5380 core */ -#define AUTOSENSE -#define PSEUDO_DMA - #include "NCR5380.c" static struct scsi_host_template driver_template = { diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index e7e11f282c8..10d1aff9938 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4492,6 +4492,7 @@ static struct scsi_host_template megaraid_template = { .sg_tablesize = MAX_SGLIST, .cmd_per_lun = DEF_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .eh_abort_handler = megaraid_abort, .eh_device_reset_handler = megaraid_reset, .eh_bus_reset_handler = megaraid_reset, diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c6a53dccc16..e4e4c6a39ed 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -361,6 +361,7 @@ static struct scsi_host_template megaraid_template_g = { .eh_host_reset_handler = megaraid_reset_handler, .change_queue_depth = megaraid_change_queue_depth, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .sdev_attrs = megaraid_sdev_attrs, .shost_attrs = megaraid_shost_attrs, }; diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index ebb948c016b..e3c5c528220 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -1110,6 +1110,7 @@ static struct scsi_host_template megasas_template = { .eh_timed_out = megasas_reset_timer, .bios_param = megasas_bios_param, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; /** diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 651d09b08f2..7470ff39ab2 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1843,6 +1843,7 @@ static struct scsi_host_template mesh_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 2, .use_clustering = DISABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 7fed3537215..28161dc95e0 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -281,6 +281,7 @@ static struct scsi_host_template nsp32_template = { .cmd_per_lun = 1, .this_id = NSP32_HOST_SCSIID, .use_clustering = DISABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .eh_abort_handler = nsp32_eh_abort, .eh_bus_reset_handler = nsp32_eh_bus_reset, .eh_host_reset_handler = nsp32_eh_host_reset, diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 961839ecfe8..190e2a7d706 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -694,6 +694,7 @@ static struct scsi_host_template sym53c500_driver_template = { .sg_tablesize = 32, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = SYM53C500_shost_attrs }; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index fba8aa8a81b..76089cf55f4 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -2775,7 +2775,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) struct device_reg __iomem *reg = ha->iobase; struct scsi_cmnd *cmd = sp->cmd; cmd_a64_entry_t *pkt; - struct scatterlist *sg = NULL; + struct scatterlist *sg = NULL, *s; __le32 *dword_ptr; dma_addr_t dma_handle; int status = 0; @@ -2889,13 +2889,16 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) * Load data segments. */ if (seg_cnt) { /* If data transfer. */ + int remseg = seg_cnt; /* Setup packet address segment pointer. */ dword_ptr = (u32 *)&pkt->dseg_0_address; if (cmd->use_sg) { /* If scatter gather */ /* Load command entry data segments. */ - for (cnt = 0; cnt < 2 && seg_cnt; cnt++, seg_cnt--) { - dma_handle = sg_dma_address(sg); + for_each_sg(sg, s, seg_cnt, cnt) { + if (cnt == 2) + break; + dma_handle = sg_dma_address(s); #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) if (ha->flags.use_pci_vchannel) sn_pci_set_vchan(ha->pdev, @@ -2906,12 +2909,12 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) cpu_to_le32(pci_dma_lo32(dma_handle)); *dword_ptr++ = cpu_to_le32(pci_dma_hi32(dma_handle)); - *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); - sg++; + *dword_ptr++ = cpu_to_le32(sg_dma_len(s)); dprintk(3, "S/G Segment phys_addr=%x %x, len=0x%x\n", cpu_to_le32(pci_dma_hi32(dma_handle)), cpu_to_le32(pci_dma_lo32(dma_handle)), - cpu_to_le32(sg_dma_len(sg))); + cpu_to_le32(sg_dma_len(sg_next(s)))); + remseg--; } dprintk(5, "qla1280_64bit_start_scsi: Scatter/gather " "command packet data - b %i, t %i, l %i \n", @@ -2926,7 +2929,9 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) dprintk(3, "S/G Building Continuation...seg_cnt=0x%x " "remains\n", seg_cnt); - while (seg_cnt > 0) { + while (remseg > 0) { + /* Update sg start */ + sg = s; /* Adjust ring index. */ ha->req_ring_index++; if (ha->req_ring_index == REQUEST_ENTRY_CNT) { @@ -2952,9 +2957,10 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) (u32 *)&((struct cont_a64_entry *) pkt)->dseg_0_address; /* Load continuation entry data segments. */ - for (cnt = 0; cnt < 5 && seg_cnt; - cnt++, seg_cnt--) { - dma_handle = sg_dma_address(sg); + for_each_sg(sg, s, remseg, cnt) { + if (cnt == 5) + break; + dma_handle = sg_dma_address(s); #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) if (ha->flags.use_pci_vchannel) sn_pci_set_vchan(ha->pdev, @@ -2966,13 +2972,13 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) *dword_ptr++ = cpu_to_le32(pci_dma_hi32(dma_handle)); *dword_ptr++ = - cpu_to_le32(sg_dma_len(sg)); + cpu_to_le32(sg_dma_len(s)); dprintk(3, "S/G Segment Cont. phys_addr=%x %x, len=0x%x\n", cpu_to_le32(pci_dma_hi32(dma_handle)), cpu_to_le32(pci_dma_lo32(dma_handle)), - cpu_to_le32(sg_dma_len(sg))); - sg++; + cpu_to_le32(sg_dma_len(s))); } + remseg -= cnt; dprintk(5, "qla1280_64bit_start_scsi: " "continuation packet data - b %i, t " "%i, l %i \n", SCSI_BUS_32(cmd), @@ -3062,7 +3068,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) struct device_reg __iomem *reg = ha->iobase; struct scsi_cmnd *cmd = sp->cmd; struct cmd_entry *pkt; - struct scatterlist *sg = NULL; + struct scatterlist *sg = NULL, *s; __le32 *dword_ptr; int status = 0; int cnt; @@ -3188,6 +3194,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) * Load data segments. */ if (seg_cnt) { + int remseg = seg_cnt; /* Setup packet address segment pointer. */ dword_ptr = &pkt->dseg_0_address; @@ -3196,22 +3203,25 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) qla1280_dump_buffer(1, (char *)sg, 4 * 16); /* Load command entry data segments. */ - for (cnt = 0; cnt < 4 && seg_cnt; cnt++, seg_cnt--) { + for_each_sg(sg, s, seg_cnt, cnt) { + if (cnt == 4) + break; *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); - *dword_ptr++ = - cpu_to_le32(sg_dma_len(sg)); + cpu_to_le32(pci_dma_lo32(sg_dma_address(s))); + *dword_ptr++ = cpu_to_le32(sg_dma_len(s)); dprintk(3, "S/G Segment phys_addr=0x%lx, len=0x%x\n", - (pci_dma_lo32(sg_dma_address(sg))), - (sg_dma_len(sg))); - sg++; + (pci_dma_lo32(sg_dma_address(s))), + (sg_dma_len(s))); + remseg--; } /* * Build continuation packets. */ dprintk(3, "S/G Building Continuation" "...seg_cnt=0x%x remains\n", seg_cnt); - while (seg_cnt > 0) { + while (remseg > 0) { + /* Continue from end point */ + sg = s; /* Adjust ring index. */ ha->req_ring_index++; if (ha->req_ring_index == REQUEST_ENTRY_CNT) { @@ -3239,19 +3249,20 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) &((struct cont_entry *) pkt)->dseg_0_address; /* Load continuation entry data segments. */ - for (cnt = 0; cnt < 7 && seg_cnt; - cnt++, seg_cnt--) { + for_each_sg(sg, s, remseg, cnt) { + if (cnt == 7) + break; *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); + cpu_to_le32(pci_dma_lo32(sg_dma_address(s))); *dword_ptr++ = - cpu_to_le32(sg_dma_len(sg)); + cpu_to_le32(sg_dma_len(s)); dprintk(1, "S/G Segment Cont. phys_addr=0x%x, " "len=0x%x\n", - cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), - cpu_to_le32(sg_dma_len(sg))); - sg++; + cpu_to_le32(pci_dma_lo32(sg_dma_address(s))), + cpu_to_le32(sg_dma_len(s))); } + remseg -= cnt; dprintk(5, "qla1280_32bit_start_scsi: " "continuation packet data - " "scsi(%i:%i:%i)\n", SCSI_BUS_32(cmd), @@ -4248,6 +4259,7 @@ static struct scsi_host_template qla1280_driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index a6bb8d0ecf1..0351d380c2d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -132,6 +132,7 @@ struct scsi_host_template qla2x00_driver_template = { .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .sg_tablesize = SG_ALL, /* @@ -163,6 +164,7 @@ struct scsi_host_template qla24xx_driver_template = { .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index b1d565c12c5..03b68d4f3bd 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -94,6 +94,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index 1e874f1fb5c..1769f965eed 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -197,6 +197,7 @@ static struct scsi_host_template qlogicfas_driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static __init int qlogicfas_init(void) diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index e93f80316a1..7a2e7986b03 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -868,7 +868,7 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, struct qlogicpti *qpti, u_int in_ptr, u_int out_ptr) { struct dataseg *ds; - struct scatterlist *sg; + struct scatterlist *sg, *s; int i, n; if (Cmnd->use_sg) { @@ -884,11 +884,12 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, n = sg_count; if (n > 4) n = 4; - for (i = 0; i < n; i++, sg++) { - ds[i].d_base = sg_dma_address(sg); - ds[i].d_count = sg_dma_len(sg); + for_each_sg(sg, s, n, i) { + ds[i].d_base = sg_dma_address(s); + ds[i].d_count = sg_dma_len(s); } sg_count -= 4; + sg = s; while (sg_count > 0) { struct Continuation_Entry *cont; @@ -907,9 +908,9 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, n = sg_count; if (n > 7) n = 7; - for (i = 0; i < n; i++, sg++) { - ds[i].d_base = sg_dma_address(sg); - ds[i].d_count = sg_dma_len(sg); + for_each_sg(sg, s, n, i) { + ds[i].d_base = sg_dma_address(s); + ds[i].d_count = sg_dma_len(s); } sg_count -= n; } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 4947dfe625a..72ee4c9cfb1 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -38,6 +38,7 @@ #include <linux/proc_fs.h> #include <linux/vmalloc.h> #include <linux/moduleparam.h> +#include <linux/scatterlist.h> #include <linux/blkdev.h> #include "scsi.h" @@ -600,7 +601,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, int k, req_len, act_len, len, active; void * kaddr; void * kaddr_off; - struct scatterlist * sgpnt; + struct scatterlist * sg; if (0 == scp->request_bufflen) return 0; @@ -619,16 +620,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, scp->resid = req_len - act_len; return 0; } - sgpnt = (struct scatterlist *)scp->request_buffer; active = 1; - for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) { + req_len = act_len = 0; + scsi_for_each_sg(scp, sg, scp->use_sg, k) { if (active) { kaddr = (unsigned char *) - kmap_atomic(sgpnt->page, KM_USER0); + kmap_atomic(sg->page, KM_USER0); if (NULL == kaddr) return (DID_ERROR << 16); - kaddr_off = (unsigned char *)kaddr + sgpnt->offset; - len = sgpnt->length; + kaddr_off = (unsigned char *)kaddr + sg->offset; + len = sg->length; if ((req_len + len) > arr_len) { active = 0; len = arr_len - req_len; @@ -637,7 +638,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, kunmap_atomic(kaddr, KM_USER0); act_len += len; } - req_len += sgpnt->length; + req_len += sg->length; } if (scp->resid) scp->resid -= act_len; @@ -653,7 +654,7 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, int k, req_len, len, fin; void * kaddr; void * kaddr_off; - struct scatterlist * sgpnt; + struct scatterlist * sg; if (0 == scp->request_bufflen) return 0; @@ -668,13 +669,14 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, memcpy(arr, scp->request_buffer, len); return len; } - sgpnt = (struct scatterlist *)scp->request_buffer; - for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) { - kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0); + sg = scsi_sglist(scp); + req_len = fin = 0; + for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) { + kaddr = (unsigned char *)kmap_atomic(sg->page, KM_USER0); if (NULL == kaddr) return -1; - kaddr_off = (unsigned char *)kaddr + sgpnt->offset; - len = sgpnt->length; + kaddr_off = (unsigned char *)kaddr + sg->offset; + len = sg->length; if ((req_len + len) > max_arr_len) { len = max_arr_len - req_len; fin = 1; @@ -683,7 +685,7 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, kunmap_atomic(kaddr, KM_USER0); if (fin) return req_len + len; - req_len += sgpnt->length; + req_len += sg->length; } return req_len; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 207f1aa0886..aac8a02cbe8 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -17,6 +17,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/hardirq.h> +#include <linux/scatterlist.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -33,35 +34,34 @@ #define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools) #define SG_MEMPOOL_SIZE 2 +/* + * The maximum number of SG segments that we will put inside a scatterlist + * (unless chaining is used). Should ideally fit inside a single page, to + * avoid a higher order allocation. + */ +#define SCSI_MAX_SG_SEGMENTS 128 + struct scsi_host_sg_pool { size_t size; - char *name; + char *name; struct kmem_cache *slab; mempool_t *pool; }; -#if (SCSI_MAX_PHYS_SEGMENTS < 32) -#error SCSI_MAX_PHYS_SEGMENTS is too small -#endif - -#define SP(x) { x, "sgpool-" #x } +#define SP(x) { x, "sgpool-" #x } static struct scsi_host_sg_pool scsi_sg_pools[] = { SP(8), SP(16), +#if (SCSI_MAX_SG_SEGMENTS > 16) SP(32), -#if (SCSI_MAX_PHYS_SEGMENTS > 32) +#if (SCSI_MAX_SG_SEGMENTS > 32) SP(64), -#if (SCSI_MAX_PHYS_SEGMENTS > 64) +#if (SCSI_MAX_SG_SEGMENTS > 64) SP(128), -#if (SCSI_MAX_PHYS_SEGMENTS > 128) - SP(256), -#if (SCSI_MAX_PHYS_SEGMENTS > 256) -#error SCSI_MAX_PHYS_SEGMENTS is too large -#endif #endif #endif #endif -}; +}; #undef SP static void scsi_run_queue(struct request_queue *q); @@ -289,14 +289,16 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, struct request_queue *q = rq->q; int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned int data_len = bufflen, len, bytes, off; + struct scatterlist *sg; struct page *page; struct bio *bio = NULL; int i, err, nr_vecs = 0; - for (i = 0; i < nsegs; i++) { - page = sgl[i].page; - off = sgl[i].offset; - len = sgl[i].length; + for_each_sg(sgl, sg, nsegs, i) { + page = sg->page; + off = sg->offset; + len = sg->length; + data_len += len; while (len > 0 && data_len > 0) { /* @@ -695,56 +697,170 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, return NULL; } -struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) -{ - struct scsi_host_sg_pool *sgp; - struct scatterlist *sgl; +/* + * Like SCSI_MAX_SG_SEGMENTS, but for archs that have sg chaining. This limit + * is totally arbitrary, a setting of 2048 will get you at least 8mb ios. + */ +#define SCSI_MAX_SG_CHAIN_SEGMENTS 2048 - BUG_ON(!cmd->use_sg); +static inline unsigned int scsi_sgtable_index(unsigned short nents) +{ + unsigned int index; - switch (cmd->use_sg) { + switch (nents) { case 1 ... 8: - cmd->sglist_len = 0; + index = 0; break; case 9 ... 16: - cmd->sglist_len = 1; + index = 1; break; +#if (SCSI_MAX_SG_SEGMENTS > 16) case 17 ... 32: - cmd->sglist_len = 2; + index = 2; break; -#if (SCSI_MAX_PHYS_SEGMENTS > 32) +#if (SCSI_MAX_SG_SEGMENTS > 32) case 33 ... 64: - cmd->sglist_len = 3; + index = 3; break; -#if (SCSI_MAX_PHYS_SEGMENTS > 64) +#if (SCSI_MAX_SG_SEGMENTS > 64) case 65 ... 128: - cmd->sglist_len = 4; - break; -#if (SCSI_MAX_PHYS_SEGMENTS > 128) - case 129 ... 256: - cmd->sglist_len = 5; + index = 4; break; #endif #endif #endif default: - return NULL; + printk(KERN_ERR "scsi: bad segment count=%d\n", nents); + BUG(); } - sgp = scsi_sg_pools + cmd->sglist_len; - sgl = mempool_alloc(sgp->pool, gfp_mask); - return sgl; + return index; +} + +struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) +{ + struct scsi_host_sg_pool *sgp; + struct scatterlist *sgl, *prev, *ret; + unsigned int index; + int this, left; + + BUG_ON(!cmd->use_sg); + + left = cmd->use_sg; + ret = prev = NULL; + do { + this = left; + if (this > SCSI_MAX_SG_SEGMENTS) { + this = SCSI_MAX_SG_SEGMENTS - 1; + index = SG_MEMPOOL_NR - 1; + } else + index = scsi_sgtable_index(this); + + left -= this; + + sgp = scsi_sg_pools + index; + + sgl = mempool_alloc(sgp->pool, gfp_mask); + if (unlikely(!sgl)) + goto enomem; + + memset(sgl, 0, sizeof(*sgl) * sgp->size); + + /* + * first loop through, set initial index and return value + */ + if (!ret) + ret = sgl; + + /* + * chain previous sglist, if any. we know the previous + * sglist must be the biggest one, or we would not have + * ended up doing another loop. + */ + if (prev) + sg_chain(prev, SCSI_MAX_SG_SEGMENTS, sgl); + + /* + * don't allow subsequent mempool allocs to sleep, it would + * violate the mempool principle. + */ + gfp_mask &= ~__GFP_WAIT; + gfp_mask |= __GFP_HIGH; + prev = sgl; + } while (left); + + /* + * ->use_sg may get modified after dma mapping has potentially + * shrunk the number of segments, so keep a copy of it for free. + */ + cmd->__use_sg = cmd->use_sg; + return ret; +enomem: + if (ret) { + /* + * Free entries chained off ret. Since we were trying to + * allocate another sglist, we know that all entries are of + * the max size. + */ + sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1; + prev = ret; + ret = &ret[SCSI_MAX_SG_SEGMENTS - 1]; + + while ((sgl = sg_chain_ptr(ret)) != NULL) { + ret = &sgl[SCSI_MAX_SG_SEGMENTS - 1]; + mempool_free(sgl, sgp->pool); + } + + mempool_free(prev, sgp->pool); + } + return NULL; } EXPORT_SYMBOL(scsi_alloc_sgtable); -void scsi_free_sgtable(struct scatterlist *sgl, int index) +void scsi_free_sgtable(struct scsi_cmnd *cmd) { + struct scatterlist *sgl = cmd->request_buffer; struct scsi_host_sg_pool *sgp; - BUG_ON(index >= SG_MEMPOOL_NR); + /* + * if this is the biggest size sglist, check if we have + * chained parts we need to free + */ + if (cmd->__use_sg > SCSI_MAX_SG_SEGMENTS) { + unsigned short this, left; + struct scatterlist *next; + unsigned int index; + + left = cmd->__use_sg - (SCSI_MAX_SG_SEGMENTS - 1); + next = sg_chain_ptr(&sgl[SCSI_MAX_SG_SEGMENTS - 1]); + while (left && next) { + sgl = next; + this = left; + if (this > SCSI_MAX_SG_SEGMENTS) { + this = SCSI_MAX_SG_SEGMENTS - 1; + index = SG_MEMPOOL_NR - 1; + } else + index = scsi_sgtable_index(this); + + left -= this; + + sgp = scsi_sg_pools + index; + + if (left) + next = sg_chain_ptr(&sgl[sgp->size - 1]); + + mempool_free(sgl, sgp->pool); + } + + /* + * Restore original, will be freed below + */ + sgl = cmd->request_buffer; + sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1; + } else + sgp = scsi_sg_pools + scsi_sgtable_index(cmd->__use_sg); - sgp = scsi_sg_pools + index; mempool_free(sgl, sgp->pool); } @@ -770,7 +886,7 @@ EXPORT_SYMBOL(scsi_free_sgtable); static void scsi_release_buffers(struct scsi_cmnd *cmd) { if (cmd->use_sg) - scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + scsi_free_sgtable(cmd); /* * Zero these out. They now point to freed memory, and it is @@ -984,7 +1100,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) static int scsi_init_io(struct scsi_cmnd *cmd) { struct request *req = cmd->request; - struct scatterlist *sgpnt; int count; /* @@ -997,14 +1112,13 @@ static int scsi_init_io(struct scsi_cmnd *cmd) /* * If sg table allocation fails, requeue request later. */ - sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC); - if (unlikely(!sgpnt)) { + cmd->request_buffer = scsi_alloc_sgtable(cmd, GFP_ATOMIC); + if (unlikely(!cmd->request_buffer)) { scsi_unprep_request(req); return BLKPREP_DEFER; } req->buffer = NULL; - cmd->request_buffer = (char *) sgpnt; if (blk_pc_request(req)) cmd->request_bufflen = req->data_len; else @@ -1529,8 +1643,25 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, if (!q) return NULL; + /* + * this limit is imposed by hardware restrictions + */ blk_queue_max_hw_segments(q, shost->sg_tablesize); - blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS); + + /* + * In the future, sg chaining support will be mandatory and this + * ifdef can then go away. Right now we don't have all archs + * converted, so better keep it safe. + */ +#ifdef ARCH_HAS_SG_CHAIN + if (shost->use_sg_chaining) + blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS); + else + blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS); +#else + blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS); +#endif + blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); @@ -2193,18 +2324,19 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock); * * Returns virtual address of the start of the mapped page */ -void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, +void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, size_t *offset, size_t *len) { int i; size_t sg_len = 0, len_complete = 0; + struct scatterlist *sg; struct page *page; WARN_ON(!irqs_disabled()); - for (i = 0; i < sg_count; i++) { + for_each_sg(sgl, sg, sg_count, i) { len_complete = sg_len; /* Complete sg-entries */ - sg_len += sg[i].length; + sg_len += sg->length; if (sg_len > *offset) break; } @@ -2218,10 +2350,10 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, } /* Offset starting from the beginning of first page in this sg-entry */ - *offset = *offset - len_complete + sg[i].offset; + *offset = *offset - len_complete + sg->offset; /* Assumption: contiguous pages can be accessed as "page + i" */ - page = nth_page(sg[i].page, (*offset >> PAGE_SHIFT)); + page = nth_page(sg->page, (*offset >> PAGE_SHIFT)); *offset &= ~PAGE_MASK; /* Bytes in this sg-entry from *offset to the end of the page */ diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 66c692ffa30..a91761c3645 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -332,7 +332,7 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag); if (cmd->request_buffer) - scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + scsi_free_sgtable(cmd); queue_work(scsi_tgtd, &tcmd->work); } @@ -373,7 +373,7 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) } eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg); - scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + scsi_free_sgtable(cmd); return -EINVAL; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0a3a528212c..69f542c4923 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -826,27 +826,6 @@ static int sd_sync_cache(struct scsi_disk *sdkp) return 0; } -static int sd_issue_flush(struct request_queue *q, struct gendisk *disk, - sector_t *error_sector) -{ - int ret = 0; - struct scsi_device *sdp = q->queuedata; - struct scsi_disk *sdkp; - - if (sdp->sdev_state != SDEV_RUNNING) - return -ENXIO; - - sdkp = scsi_disk_get_from_dev(&sdp->sdev_gendev); - - if (!sdkp) - return -ENODEV; - - if (sdkp->WCE) - ret = sd_sync_cache(sdkp); - scsi_disk_put(sdkp); - return ret; -} - static void sd_prepare_flush(struct request_queue *q, struct request *rq) { memset(rq->cmd, 0, sizeof(rq->cmd)); @@ -1697,7 +1676,6 @@ static int sd_probe(struct device *dev) sd_revalidate_disk(gd); blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); - blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush); gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_DRIVERFS; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index f6f5fc7d0ce..7238b2dfc49 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1165,7 +1165,7 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) sg = rsv_schp->buffer; sa = vma->vm_start; for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); - ++k, ++sg) { + ++k, sg = sg_next(sg)) { len = vma->vm_end - sa; len = (len < sg->length) ? len : sg->length; if (offset < len) { @@ -1209,7 +1209,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma) sa = vma->vm_start; sg = rsv_schp->buffer; for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); - ++k, ++sg) { + ++k, sg = sg_next(sg)) { len = vma->vm_end - sa; len = (len < sg->length) ? len : sg->length; sa += len; @@ -1840,7 +1840,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) } for (k = 0, sg = schp->buffer, rem_sz = blk_size; (rem_sz > 0) && (k < mx_sc_elems); - ++k, rem_sz -= ret_sz, ++sg) { + ++k, rem_sz -= ret_sz, sg = sg_next(sg)) { num = (rem_sz > scatter_elem_sz_prev) ? scatter_elem_sz_prev : rem_sz; @@ -1913,7 +1913,7 @@ sg_write_xfer(Sg_request * srp) if (res) return res; - for (; p; ++sg, ksglen = sg->length, + for (; p; sg = sg_next(sg), ksglen = sg->length, p = page_address(sg->page)) { if (usglen <= 0) break; @@ -1992,7 +1992,7 @@ sg_remove_scat(Sg_scatter_hold * schp) int k; for (k = 0; (k < schp->k_use_sg) && sg->page; - ++k, ++sg) { + ++k, sg = sg_next(sg)) { SCSI_LOG_TIMEOUT(5, printk( "sg_remove_scat: k=%d, pg=0x%p, len=%d\n", k, sg->page, sg->length)); @@ -2045,7 +2045,7 @@ sg_read_xfer(Sg_request * srp) if (res) return res; - for (; p; ++sg, ksglen = sg->length, + for (; p; sg = sg_next(sg), ksglen = sg->length, p = page_address(sg->page)) { if (usglen <= 0) break; @@ -2092,7 +2092,7 @@ sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer) if ((!outp) || (num_read_xfer <= 0)) return 0; - for (k = 0; (k < schp->k_use_sg) && sg->page; ++k, ++sg) { + for (k = 0; (k < schp->k_use_sg) && sg->page; ++k, sg = sg_next(sg)) { num = sg->length; if (num > num_read_xfer) { if (__copy_to_user(outp, page_address(sg->page), @@ -2142,7 +2142,7 @@ sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size) SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); rem = size; - for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sg) { + for (k = 0; k < rsv_schp->k_use_sg; ++k, sg = sg_next(sg)) { num = sg->length; if (rem <= num) { sfp->save_scat_len = num; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 72f6d801535..e3fab3a6aed 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -1123,6 +1123,7 @@ static struct scsi_host_template driver_template = { .this_id = -1, .sg_tablesize = ST_MAX_SG, .cmd_per_lun = ST_CMD_PER_LUN, + .use_sg_chaining = ENABLE_SG_CHAINING, }; static int stex_set_dma_mask(struct pci_dev * pdev) diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 92bfaeafe30..8befab7e983 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -854,5 +854,6 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 1, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 3db22325ea2..db03c4c8ec1 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -1808,6 +1808,7 @@ static struct scsi_host_template sym2_template = { .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, .this_id = 7, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .max_sectors = 0xFFFF, #ifdef SYM_LINUX_PROC_INFO_SUPPORT .proc_info = sym53c8xx_proc_info, diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index fc9f51818e8..7edd6ceb13b 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -450,7 +450,8 @@ static struct scsi_host_template driver_template = { .slave_configure = u14_34f_slave_configure, .this_id = 7, .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING + .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index c08235d5afc..ea72bbeb8f9 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -1197,5 +1197,6 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = ULTRASTOR_MAX_CMDS_PER_LUN, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index d6fd4259c56..255c611e78b 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1671,6 +1671,7 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 1, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 1ea1ed82c35..0e357562ce9 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -1036,6 +1036,7 @@ enum pci_board_num_t { pbn_b0_2_115200, pbn_b0_4_115200, pbn_b0_5_115200, + pbn_b0_8_115200, pbn_b0_1_921600, pbn_b0_2_921600, @@ -1172,6 +1173,12 @@ static struct pciserial_board pci_boards[] __devinitdata = { .base_baud = 115200, .uart_offset = 8, }, + [pbn_b0_8_115200] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + }, [pbn_b0_1_921600] = { .flags = FL_BASE0, @@ -2566,6 +2573,119 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8, 0, 0, pbn_b2_8_921600 }, + + /* + * Mainpine series cards: Fairly standard layout but fools + * parts of the autodetect in some cases and uses otherwise + * unmatched communications subclasses in the PCI Express case + */ + + { /* RockForceDUO */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0200, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceQUATRO */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0300, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceDUO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0400, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceQUATRO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0500, + 0, 0, pbn_b0_4_115200 }, + { /* RockForce+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0600, + 0, 0, pbn_b0_2_115200 }, + { /* RockForce+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0700, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceOCTO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0800, + 0, 0, pbn_b0_8_115200 }, + { /* RockForceDUO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0C00, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceQUARTRO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0D00, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceOCTO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x1D00, + 0, 0, pbn_b0_8_115200 }, + { /* RockForceD1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2000, + 0, 0, pbn_b0_1_115200 }, + { /* RockForceF1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2100, + 0, 0, pbn_b0_1_115200 }, + { /* RockForceD2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2200, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceF2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2300, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceD4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2400, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceF4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2500, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceD8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2600, + 0, 0, pbn_b0_8_115200 }, + { /* RockForceF8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2700, + 0, 0, pbn_b0_8_115200 }, + { /* IQ Express D1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3000, + 0, 0, pbn_b0_1_115200 }, + { /* IQ Express F1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3100, + 0, 0, pbn_b0_1_115200 }, + { /* IQ Express D2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3200, + 0, 0, pbn_b0_2_115200 }, + { /* IQ Express F2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3300, + 0, 0, pbn_b0_2_115200 }, + { /* IQ Express D4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3400, + 0, 0, pbn_b0_4_115200 }, + { /* IQ Express F4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3500, + 0, 0, pbn_b0_4_115200 }, + { /* IQ Express D8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3C00, + 0, 0, pbn_b0_8_115200 }, + { /* IQ Express F8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3D00, + 0, 0, pbn_b0_8_115200 }, + + /* * PA Semi PA6T-1682M on-chip UART */ diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index 301c8c0be9d..926f58a674a 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -327,6 +327,8 @@ static const struct pnp_device_id pnp_dev_table[] = { { "WACF004", 0 }, { "WACF005", 0 }, { "WACF006", 0 }, + { "WACF007", 0 }, + { "WACF008", 0 }, /* Compaq touchscreen */ { "FPI2002", 0 }, /* Fujitsu Stylistic touchscreens */ diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 312bef6bd58..7e8724d3571 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -514,6 +514,8 @@ struct tty_driver *serial_driver; * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128 * BUF_SIZE can't be > 128 */ +#define CRIS_BUF_SIZE 512 + /* Currently 16 descriptors x 128 bytes = 2048 bytes */ #define SERIAL_DESCR_BUF_SIZE 256 @@ -2497,55 +2499,18 @@ static void flush_to_flip_buffer(struct e100_serial *info) return; } - length = tty->flip.count; - /* Don't flip more than the ldisc has room for. - * The return value from ldisc.receive_room(tty) - might not be up to - * date, the previous flip of up to TTY_FLIPBUF_SIZE might be on the - * processed and not accounted for yet. - * Since we use DMA, 1 SERIAL_DESCR_BUF_SIZE could be on the way. - * Lets buffer data here and let flow control take care of it. - * Since we normally flip large chunks, the ldisc don't react - * with throttle until too late if we flip to much. - */ - max_flip_size = tty->ldisc.receive_room(tty); - if (max_flip_size < 0) - max_flip_size = 0; - if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */ - length + info->recv_cnt + /* We have this queued */ - 2*SERIAL_DESCR_BUF_SIZE + /* This could be on the way */ - TTY_THRESHOLD_THROTTLE)) { /* Some slack */ - /* check TTY_THROTTLED first so it indicates our state */ - if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) { - DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles room %lu\n", max_flip_size)); - rs_throttle(tty); - } -#if 0 - else if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */ - length + info->recv_cnt + /* We have this queued */ - SERIAL_DESCR_BUF_SIZE + /* This could be on the way */ - TTY_THRESHOLD_THROTTLE)) { /* Some slack */ - DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles again! %lu\n", max_flip_size)); - rs_throttle(tty); - } -#endif - } - - if (max_flip_size > TTY_FLIPBUF_SIZE) - max_flip_size = TTY_FLIPBUF_SIZE; - - while ((buffer = info->first_recv_buffer) && length < max_flip_size) { + while ((buffer = info->first_recv_buffer) != NULL) { unsigned int count = buffer->length; - if (length + count > max_flip_size) - count = max_flip_size - length; + count = tty_buffer_request_room(tty, count); + if (count == 0) /* Throttle ?? */ + break; - memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count); - memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count); - tty->flip.flag_buf_ptr[length] = buffer->error; + if (count > 1) + tty_insert_flip_strings(tty, buffer->buffer, count - 1); + tty_insert_flip_char(tty, buffer->buffer[count-1], buffer->error); - length += count; info->recv_cnt -= count; - DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length)); if (count == buffer->length) { info->first_recv_buffer = buffer->next; @@ -2560,14 +2525,6 @@ static void flush_to_flip_buffer(struct e100_serial *info) if (!info->first_recv_buffer) info->last_recv_buffer = NULL; - tty->flip.count = length; - DFLIP(if (tty->ldisc.chars_in_buffer(tty) > 3500) { - DEBUG_LOG(info->line, "ldisc %lu\n", - tty->ldisc.chars_in_buffer(tty)); - DEBUG_LOG(info->line, "flip.count %lu\n", - tty->flip.count); - } - ); restore_flags(flags); DFLIP( @@ -2722,17 +2679,17 @@ struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) printk("!NO TTY!\n"); return info; } - if (tty->flip.count >= TTY_FLIPBUF_SIZE - TTY_THRESHOLD_THROTTLE) { + if (tty->flip.count >= CRIS_BUF_SIZE - TTY_THRESHOLD_THROTTLE) { /* check TTY_THROTTLED first so it indicates our state */ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) { DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count)); rs_throttle(tty); } } - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + if (tty->flip.count >= CRIS_BUF_SIZE) { DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count); tty->flip.work.func((void *) tty); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + if (tty->flip.count >= CRIS_BUF_SIZE) { DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count); return info; /* if TTY_DONT_FLIP is set */ } diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index 6e09c8b395e..348ee2c19b5 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -539,7 +539,7 @@ static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up) static int serial_link_irq_chain(struct uart_sio_port *up) { struct irq_info *i = irq_lists + up->port.irq; - int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; + int ret, irq_flags = 0; spin_lock_irq(&i->lock); diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h index 849f1b2c253..e9b7e11793b 100644 --- a/drivers/serial/m32r_sio.h +++ b/drivers/serial/m32r_sio.h @@ -46,9 +46,3 @@ struct old_serial_port { #define PROBE_ANY (~0) #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) - -#ifdef CONFIG_SERIAL_SIO_SHARE_IRQ -#define M32R_SIO_SHARE_IRQS 1 -#else -#define M32R_SIO_SHARE_IRQS 0 -#endif diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index a3bd3a3f41f..68aa4da0186 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1938,9 +1938,24 @@ static void uart_change_pm(struct uart_state *state, int pm_state) } } +struct uart_match { + struct uart_port *port; + struct uart_driver *driver; +}; + +static int serial_match_port(struct device *dev, void *data) +{ + struct uart_match *match = data; + dev_t devt = MKDEV(match->driver->major, match->driver->minor) + match->port->line; + + return dev->devt == devt; /* Actually, only one tty per port */ +} + int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state = drv->state + port->line; + struct device *tty_dev; + struct uart_match match = {port, drv}; mutex_lock(&state->mutex); @@ -1951,6 +1966,15 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) } #endif + tty_dev = device_find_child(port->dev, &match, serial_match_port); + if (device_may_wakeup(tty_dev)) { + enable_irq_wake(port->irq); + put_device(tty_dev); + mutex_unlock(&state->mutex); + return 0; + } + port->suspended = 1; + if (state->info && state->info->flags & UIF_INITIALIZED) { const struct uart_ops *ops = port->ops; @@ -1999,6 +2023,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) } #endif + if (!port->suspended) { + disable_irq_wake(port->irq); + mutex_unlock(&state->mutex); + return 0; + } + port->suspended = 0; + uart_change_pm(state, 0); /* @@ -2278,6 +2309,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state; int ret = 0; + struct device *tty_dev; BUG_ON(in_interrupt()); @@ -2314,7 +2346,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_register_device(drv->tty_driver, port->line, port->dev); + tty_dev = tty_register_device(drv->tty_driver, port->line, port->dev); + if (likely(!IS_ERR(tty_dev))) { + device_can_wakeup(tty_dev) = 1; + device_set_wakeup_enable(tty_dev, 0); + } else + printk(KERN_ERR "Cannot register tty device on line %d\n", + port->line); /* * Ensure UPF_DEAD is not set. diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 7c8d78fbbbf..5afcb2fa7cd 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -911,6 +911,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"), + PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 0930e2a8551..6846a6c38b6 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -25,19 +25,15 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/console.h> -#include <linux/sysrq.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/pci.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> #include <linux/serial_core.h> #include <linux/serial.h> -#include <linux/mutex.h> #include <asm/io.h> -static char *serial_version = "1.10"; +static char *serial_version = "1.11"; static char *serial_name = "TX39/49 Serial driver"; #define PASS_LIMIT 256 @@ -68,8 +64,6 @@ static char *serial_name = "TX39/49 Serial driver"; */ #define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) - struct uart_txx9_port { struct uart_port port; /* No additional info for now */ @@ -756,21 +750,6 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags) serial_txx9_initialize(port); } -static int -serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - unsigned long new_port = ser->port; - if (HIGH_BITS_OFFSET) - new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET; - if (ser->type != port->type || - ser->irq != port->irq || - ser->io_type != port->iotype || - new_port != port->iobase || - (unsigned long)ser->iomem_base != port->mapbase) - return -EINVAL; - return 0; -} - static const char * serial_txx9_type(struct uart_port *port) { @@ -794,7 +773,6 @@ static struct uart_ops serial_txx9_pops = { .release_port = serial_txx9_release_port, .request_port = serial_txx9_request_port, .config_port = serial_txx9_config_port, - .verify_port = serial_txx9_verify_port, }; static struct uart_txx9_port serial_txx9_ports[UART_NR]; @@ -950,7 +928,8 @@ int __init early_serial_txx9_setup(struct uart_port *port) serial_txx9_ports[port->line].port = *port; serial_txx9_ports[port->line].port.ops = &serial_txx9_pops; - serial_txx9_ports[port->line].port.flags |= UPF_BOOT_AUTOCONF; + serial_txx9_ports[port->line].port.flags |= + UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; return 0; } @@ -995,7 +974,8 @@ static int __devinit serial_txx9_register_port(struct uart_port *port) uart->port.irq = port->irq; uart->port.uartclk = port->uartclk; uart->port.iotype = port->iotype; - uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; + uart->port.flags = port->flags + | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; uart->port.mapbase = port->mapbase; if (port->dev) uart->port.dev = port->dev; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b91571122da..a77ede598d3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -124,16 +124,17 @@ config SPI_MPC52xx_PSC Controller in master SPI mode. config SPI_MPC83xx - tristate "Freescale MPC83xx SPI controller" - depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL + tristate "Freescale MPC83xx/QUICC Engine SPI controller" + depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL select SPI_BITBANG help - This enables using the Freescale MPC83xx SPI controller in master - mode. + This enables using the Freescale MPC83xx and QUICC Engine SPI + controllers in master mode. Note, this driver uniquely supports the SPI controller on the MPC83xx - family of PowerPC processors. The MPC83xx uses a simple set of shift - registers for data (opposed to the CPM based descriptor model). + family of PowerPC processors, plus processors with QUICC Engine + technology. This driver uses a simple set of shift registers for data + (opposed to the CPM based descriptor model). config SPI_OMAP_UWIRE tristate "OMAP1 MicroWire" diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index b0469749310..0d342dcdd30 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -211,7 +211,7 @@ static void atmel_spi_next_message(struct spi_master *master) msg = list_entry(as->queue.next, struct spi_message, queue); spi = msg->spi; - dev_dbg(master->cdev.dev, "start message %p for %s\n", + dev_dbg(master->dev.parent, "start message %p for %s\n", msg, spi->dev.bus_id); /* select chip if it's not still active */ @@ -266,10 +266,10 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master, struct spi_transfer *xfer) { if (xfer->tx_dma != INVALID_DMA_ADDRESS) - dma_unmap_single(master->cdev.dev, xfer->tx_dma, + dma_unmap_single(master->dev.parent, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); if (xfer->rx_dma != INVALID_DMA_ADDRESS) - dma_unmap_single(master->cdev.dev, xfer->rx_dma, + dma_unmap_single(master->dev.parent, xfer->rx_dma, xfer->len, DMA_FROM_DEVICE); } @@ -285,7 +285,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, list_del(&msg->queue); msg->status = status; - dev_dbg(master->cdev.dev, + dev_dbg(master->dev.parent, "xfer complete: %u bytes transferred\n", msg->actual_length); @@ -348,7 +348,7 @@ atmel_spi_interrupt(int irq, void *dev_id) if (xfer->delay_usecs) udelay(xfer->delay_usecs); - dev_warn(master->cdev.dev, "fifo overrun (%u/%u remaining)\n", + dev_warn(master->dev.parent, "fifo overrun (%u/%u remaining)\n", spi_readl(as, TCR), spi_readl(as, RCR)); /* @@ -363,7 +363,7 @@ atmel_spi_interrupt(int irq, void *dev_id) if (spi_readl(as, SR) & SPI_BIT(TXEMPTY)) break; if (!timeout) - dev_warn(master->cdev.dev, + dev_warn(master->dev.parent, "timeout waiting for TXEMPTY"); while (spi_readl(as, SR) & SPI_BIT(RDRF)) spi_readl(as, RDR); @@ -526,7 +526,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) struct atmel_spi *as; struct spi_transfer *xfer; unsigned long flags; - struct device *controller = spi->master->cdev.dev; + struct device *controller = spi->master->dev.parent; as = spi_master_get_devdata(spi->master); diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index d2a4b2bdb07..e9aba932f21 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -503,7 +503,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, INIT_LIST_HEAD(&mps->queue); mps->workqueue = create_singlethread_workqueue( - master->cdev.dev->bus_id); + master->dev.parent->bus_id); if (mps->workqueue == NULL) { ret = -EBUSY; goto free_irq; diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index 6b357cdb9ea..3cdab131c4a 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -645,7 +645,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) clk_enable(mcspi->ick); clk_enable(mcspi->fck); - ret = omap2_mcspi_setup_transfer(spi, NULL); + ret = omap2_mcspi_setup_transfer(spi, NULL); clk_disable(mcspi->fck); clk_disable(mcspi->ick); @@ -693,7 +693,6 @@ static void omap2_mcspi_work(struct work_struct *work) struct spi_device *spi; struct spi_transfer *t = NULL; int cs_active = 0; - struct omap2_mcspi_device_config *conf; struct omap2_mcspi_cs *cs; int par_override = 0; int status = 0; @@ -706,7 +705,6 @@ static void omap2_mcspi_work(struct work_struct *work) spin_unlock_irq(&mcspi->lock); spi = m->spi; - conf = spi->controller_data; cs = spi->controller_state; omap2_mcspi_set_enable(spi, 1); diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c index d275c615a73..8245b5153f3 100644 --- a/drivers/spi/omap_uwire.c +++ b/drivers/spi/omap_uwire.c @@ -481,7 +481,7 @@ static void uwire_off(struct uwire_spi *uwire) spi_master_put(uwire->bitbang.master); } -static int uwire_probe(struct platform_device *pdev) +static int __init uwire_probe(struct platform_device *pdev) { struct spi_master *master; struct uwire_spi *uwire; @@ -525,7 +525,7 @@ static int uwire_probe(struct platform_device *pdev) return status; } -static int uwire_remove(struct platform_device *pdev) +static int __exit uwire_remove(struct platform_device *pdev) { struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev); int status; @@ -543,8 +543,7 @@ static struct platform_driver uwire_driver = { .bus = &platform_bus_type, .owner = THIS_MODULE, }, - .probe = uwire_probe, - .remove = uwire_remove, + .remove = __exit_p(uwire_remove), // suspend ... unuse ck // resume ... use ck }; @@ -566,7 +565,7 @@ static int __init omap_uwire_init(void) omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9); } - return platform_driver_register(&uwire_driver); + return platform_driver_probe(&uwire_driver, uwire_probe); } static void __exit omap_uwire_exit(void) diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index e51311b2da0..5f3d808cbc2 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -26,7 +26,6 @@ #include <linux/dma-mapping.h> #include <linux/spi/spi.h> #include <linux/workqueue.h> -#include <linux/errno.h> #include <linux/delay.h> #include <asm/io.h> @@ -1230,7 +1229,7 @@ static void cleanup(struct spi_device *spi) kfree(chip); } -static int init_queue(struct driver_data *drv_data) +static int __init init_queue(struct driver_data *drv_data) { INIT_LIST_HEAD(&drv_data->queue); spin_lock_init(&drv_data->lock); @@ -1243,7 +1242,7 @@ static int init_queue(struct driver_data *drv_data) INIT_WORK(&drv_data->pump_messages, pump_messages); drv_data->workqueue = create_singlethread_workqueue( - drv_data->master->cdev.dev->bus_id); + drv_data->master->dev.parent->bus_id); if (drv_data->workqueue == NULL) return -EBUSY; @@ -1318,7 +1317,7 @@ static int destroy_queue(struct driver_data *drv_data) return 0; } -static int pxa2xx_spi_probe(struct platform_device *pdev) +static int __init pxa2xx_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct pxa2xx_spi_master *platform_info; @@ -1622,8 +1621,7 @@ static struct platform_driver driver = { .bus = &platform_bus_type, .owner = THIS_MODULE, }, - .probe = pxa2xx_spi_probe, - .remove = __devexit_p(pxa2xx_spi_remove), + .remove = pxa2xx_spi_remove, .shutdown = pxa2xx_spi_shutdown, .suspend = pxa2xx_spi_suspend, .resume = pxa2xx_spi_resume, @@ -1631,9 +1629,7 @@ static struct platform_driver driver = { static int __init pxa2xx_spi_init(void) { - platform_driver_register(&driver); - - return 0; + return platform_driver_probe(&driver, pxa2xx_spi_probe); } module_init(pxa2xx_spi_init); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index bcb8dd5fb0b..89769ce16f8 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -204,7 +204,7 @@ struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip) { struct spi_device *proxy; - struct device *dev = master->cdev.dev; + struct device *dev = master->dev.parent; int status; /* NOTE: caller did any chip->bus_num checks necessary. @@ -239,7 +239,7 @@ struct spi_device *spi_new_device(struct spi_master *master, proxy->modalias = chip->modalias; snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, - "%s.%u", master->cdev.class_id, + "%s.%u", master->dev.bus_id, chip->chip_select); proxy->dev.parent = dev; proxy->dev.bus = &spi_bus_type; @@ -338,18 +338,18 @@ static void scan_boardinfo(struct spi_master *master) /*-------------------------------------------------------------------------*/ -static void spi_master_release(struct class_device *cdev) +static void spi_master_release(struct device *dev) { struct spi_master *master; - master = container_of(cdev, struct spi_master, cdev); + master = container_of(dev, struct spi_master, dev); kfree(master); } static struct class spi_master_class = { .name = "spi_master", .owner = THIS_MODULE, - .release = spi_master_release, + .dev_release = spi_master_release, }; @@ -357,7 +357,7 @@ static struct class spi_master_class = { * spi_alloc_master - allocate SPI master controller * @dev: the controller, possibly using the platform_bus * @size: how much zeroed driver-private data to allocate; the pointer to this - * memory is in the class_data field of the returned class_device, + * memory is in the driver_data field of the returned device, * accessible with spi_master_get_devdata(). * Context: can sleep * @@ -383,9 +383,9 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) if (!master) return NULL; - class_device_initialize(&master->cdev); - master->cdev.class = &spi_master_class; - master->cdev.dev = get_device(dev); + device_initialize(&master->dev); + master->dev.class = &spi_master_class; + master->dev.parent = get_device(dev); spi_master_set_devdata(master, &master[1]); return master; @@ -415,7 +415,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master); int spi_register_master(struct spi_master *master) { static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); - struct device *dev = master->cdev.dev; + struct device *dev = master->dev.parent; int status = -ENODEV; int dynamic = 0; @@ -440,12 +440,12 @@ int spi_register_master(struct spi_master *master) /* register the device, then userspace will see it. * registration fails if the bus ID is in use. */ - snprintf(master->cdev.class_id, sizeof master->cdev.class_id, + snprintf(master->dev.bus_id, sizeof master->dev.bus_id, "spi%u", master->bus_num); - status = class_device_add(&master->cdev); + status = device_add(&master->dev); if (status < 0) goto done; - dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, + dev_dbg(dev, "registered master %s%s\n", master->dev.bus_id, dynamic ? " (dynamic)" : ""); /* populate children from any spi device tables */ @@ -478,8 +478,8 @@ void spi_unregister_master(struct spi_master *master) { int dummy; - dummy = device_for_each_child(master->cdev.dev, NULL, __unregister); - class_device_unregister(&master->cdev); + dummy = device_for_each_child(master->dev.parent, NULL, __unregister); + device_unregister(&master->dev); } EXPORT_SYMBOL_GPL(spi_unregister_master); @@ -495,13 +495,13 @@ EXPORT_SYMBOL_GPL(spi_unregister_master); */ struct spi_master *spi_busnum_to_master(u16 bus_num) { - struct class_device *cdev; + struct device *dev; struct spi_master *master = NULL; struct spi_master *m; down(&spi_master_class.sem); - list_for_each_entry(cdev, &spi_master_class.children, node) { - m = container_of(cdev, struct spi_master, cdev); + list_for_each_entry(dev, &spi_master_class.children, node) { + m = container_of(dev, struct spi_master, dev); if (m->bus_num == bus_num) { master = spi_master_get(m); break; diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index f540ed77a10..6cb71d74738 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -39,7 +39,6 @@ #include <linux/dma-mapping.h> #include <linux/spi/spi.h> #include <linux/workqueue.h> -#include <linux/errno.h> #include <linux/delay.h> #include <asm/io.h> @@ -1107,7 +1106,7 @@ static inline int init_queue(struct driver_data *drv_data) /* init messages workqueue */ INIT_WORK(&drv_data->pump_messages, pump_messages); drv_data->workqueue = - create_singlethread_workqueue(drv_data->master->cdev.dev->bus_id); + create_singlethread_workqueue(drv_data->master->dev.parent->bus_id); if (drv_data->workqueue == NULL) return -EBUSY; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 0c85c984ccb..81639c6be1c 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -472,7 +472,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) /* this task is the only thing to touch the SPI bits */ bitbang->busy = 0; bitbang->workqueue = create_singlethread_workqueue( - bitbang->master->cdev.dev->bus_id); + bitbang->master->dev.parent->bus_id); if (bitbang->workqueue == NULL) { status = -EBUSY; goto err1; diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index bd9177f51de..3b4650ae6f1 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -1361,7 +1361,7 @@ static void cleanup(struct spi_device *spi) kfree(spi_get_ctldata(spi)); } -static int init_queue(struct driver_data *drv_data) +static int __init init_queue(struct driver_data *drv_data) { INIT_LIST_HEAD(&drv_data->queue); spin_lock_init(&drv_data->lock); @@ -1374,7 +1374,7 @@ static int init_queue(struct driver_data *drv_data) INIT_WORK(&drv_data->work, pump_messages); drv_data->workqueue = create_singlethread_workqueue( - drv_data->master->cdev.dev->bus_id); + drv_data->master->dev.parent->bus_id); if (drv_data->workqueue == NULL) return -EBUSY; @@ -1444,7 +1444,7 @@ static int destroy_queue(struct driver_data *drv_data) return 0; } -static int spi_imx_probe(struct platform_device *pdev) +static int __init spi_imx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct spi_imx_master *platform_info; @@ -1622,7 +1622,7 @@ err_no_mem: return status; } -static int __devexit spi_imx_remove(struct platform_device *pdev) +static int __exit spi_imx_remove(struct platform_device *pdev) { struct driver_data *drv_data = platform_get_drvdata(pdev); int irq; @@ -1739,8 +1739,7 @@ static struct platform_driver driver = { .bus = &platform_bus_type, .owner = THIS_MODULE, }, - .probe = spi_imx_probe, - .remove = __devexit_p(spi_imx_remove), + .remove = __exit_p(spi_imx_remove), .shutdown = spi_imx_shutdown, .suspend = spi_imx_suspend, .resume = spi_imx_resume, @@ -1748,7 +1747,7 @@ static struct platform_driver driver = { static int __init spi_imx_init(void) { - return platform_driver_register(&driver); + return platform_driver_probe(&driver, spi_imx_probe); } module_init(spi_imx_init); diff --git a/drivers/spi/spi_lm70llp.c b/drivers/spi/spi_lm70llp.c index 4ea68ac1611..39d8d8ad65c 100644 --- a/drivers/spi/spi_lm70llp.c +++ b/drivers/spi/spi_lm70llp.c @@ -82,7 +82,7 @@ struct spi_lm70llp { struct pardevice *pd; struct spi_device *spidev_lm70; struct spi_board_info info; - struct class_device *cdev; + //struct device *dev; }; /* REVISIT : ugly global ; provides "exclusive open" facility */ diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index 32cda77b31c..4580b9cf625 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc83xx.c @@ -511,7 +511,7 @@ err: return ret; } -static int __devexit mpc83xx_spi_remove(struct platform_device *dev) +static int __exit mpc83xx_spi_remove(struct platform_device *dev) { struct mpc83xx_spi *mpc83xx_spi; struct spi_master *master; @@ -529,8 +529,7 @@ static int __devexit mpc83xx_spi_remove(struct platform_device *dev) MODULE_ALIAS("mpc83xx_spi"); /* for platform bus hotplug */ static struct platform_driver mpc83xx_spi_driver = { - .probe = mpc83xx_spi_probe, - .remove = __devexit_p(mpc83xx_spi_remove), + .remove = __exit_p(mpc83xx_spi_remove), .driver = { .name = "mpc83xx_spi", }, @@ -538,7 +537,7 @@ static struct platform_driver mpc83xx_spi_driver = { static int __init mpc83xx_spi_init(void) { - return platform_driver_register(&mpc83xx_spi_driver); + return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe); } static void __exit mpc83xx_spi_exit(void) diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index e9b683f7d7b..89d6685a5ca 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -233,7 +233,7 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) return IRQ_HANDLED; } -static int s3c24xx_spi_probe(struct platform_device *pdev) +static int __init s3c24xx_spi_probe(struct platform_device *pdev) { struct s3c24xx_spi *hw; struct spi_master *master; @@ -382,7 +382,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) return err; } -static int s3c24xx_spi_remove(struct platform_device *dev) +static int __exit s3c24xx_spi_remove(struct platform_device *dev) { struct s3c24xx_spi *hw = platform_get_drvdata(dev); @@ -429,8 +429,7 @@ static int s3c24xx_spi_resume(struct platform_device *pdev) MODULE_ALIAS("s3c2410_spi"); /* for platform bus hotplug */ static struct platform_driver s3c24xx_spidrv = { - .probe = s3c24xx_spi_probe, - .remove = s3c24xx_spi_remove, + .remove = __exit_p(s3c24xx_spi_remove), .suspend = s3c24xx_spi_suspend, .resume = s3c24xx_spi_resume, .driver = { @@ -441,7 +440,7 @@ static struct platform_driver s3c24xx_spidrv = { static int __init s3c24xx_spi_init(void) { - return platform_driver_register(&s3c24xx_spidrv); + return platform_driver_probe(&s3c24xx_spidrv, s3c24xx_spi_probe); } static void __exit s3c24xx_spi_exit(void) diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c index b7f4bb239ea..cc5094f37dd 100644 --- a/drivers/spi/spi_txx9.c +++ b/drivers/spi/spi_txx9.c @@ -400,7 +400,7 @@ static int __init txx9spi_probe(struct platform_device *dev) goto exit; } - c->workqueue = create_singlethread_workqueue(master->cdev.dev->bus_id); + c->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id); if (!c->workqueue) goto exit; c->last_chipselect = -1; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d20cb545a6e..60a8f55a0cc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1407,7 +1407,11 @@ fail: /** - * Similar to usb_disconnect() + * usb_deauthorize_device - deauthorize a device (usbcore-internal) + * @usb_dev: USB device + * + * Move the USB device to a very basic state where interfaces are disabled + * and the device is in fact unconfigured and unusable. * * We share a lock (that we have) with device_del(), so we need to * defer its call. diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 43722e5a49d..b624320df90 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -1042,7 +1042,8 @@ sisusbcon_set_origin(struct vc_data *c) /* Interface routine */ static int -sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows) +sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows, + unsigned int user) { struct sisusb_usb_data *sisusb; int fh; diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 4d3cbb12b71..8d3711a7ff0 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -798,12 +798,13 @@ static int alauda_read_data(struct us_data *us, unsigned long address, { unsigned char *buffer; u16 lba, max_lba; - unsigned int page, len, index, offset; + unsigned int page, len, offset; unsigned int blockshift = MEDIA_INFO(us).blockshift; unsigned int pageshift = MEDIA_INFO(us).pageshift; unsigned int blocksize = MEDIA_INFO(us).blocksize; unsigned int pagesize = MEDIA_INFO(us).pagesize; unsigned int uzonesize = MEDIA_INFO(us).uzonesize; + struct scatterlist *sg; int result; /* @@ -827,7 +828,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address, max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift); result = USB_STOR_TRANSPORT_GOOD; - index = offset = 0; + offset = 0; + sg = NULL; while (sectors > 0) { unsigned int zone = lba / uzonesize; /* integer division */ @@ -873,7 +875,7 @@ static int alauda_read_data(struct us_data *us, unsigned long address, /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, TO_XFER_BUF); + &sg, &offset, TO_XFER_BUF); page = 0; lba++; @@ -891,11 +893,12 @@ static int alauda_write_data(struct us_data *us, unsigned long address, unsigned int sectors) { unsigned char *buffer, *blockbuffer; - unsigned int page, len, index, offset; + unsigned int page, len, offset; unsigned int blockshift = MEDIA_INFO(us).blockshift; unsigned int pageshift = MEDIA_INFO(us).pageshift; unsigned int blocksize = MEDIA_INFO(us).blocksize; unsigned int pagesize = MEDIA_INFO(us).pagesize; + struct scatterlist *sg; u16 lba, max_lba; int result; @@ -929,7 +932,8 @@ static int alauda_write_data(struct us_data *us, unsigned long address, max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift); result = USB_STOR_TRANSPORT_GOOD; - index = offset = 0; + offset = 0; + sg = NULL; while (sectors > 0) { /* Write as many sectors as possible in this block */ @@ -946,7 +950,7 @@ static int alauda_write_data(struct us_data *us, unsigned long address, /* Get the data from the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, FROM_XFER_BUF); + &sg, &offset, FROM_XFER_BUF); result = alauda_write_lba(us, lba, page, pages, buffer, blockbuffer); diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index c87ad1bae1d..579e9f52053 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -98,7 +98,8 @@ static int datafab_read_data(struct us_data *us, unsigned char thistime; unsigned int totallen, alloclen; int len, result; - unsigned int sg_idx = 0, sg_offset = 0; + unsigned int sg_offset = 0; + struct scatterlist *sg = NULL; // we're working in LBA mode. according to the ATA spec, // we can support up to 28-bit addressing. I don't know if Datafab @@ -155,7 +156,7 @@ static int datafab_read_data(struct us_data *us, // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg_idx, &sg_offset, TO_XFER_BUF); + &sg, &sg_offset, TO_XFER_BUF); sector += thistime; totallen -= len; @@ -181,7 +182,8 @@ static int datafab_write_data(struct us_data *us, unsigned char thistime; unsigned int totallen, alloclen; int len, result; - unsigned int sg_idx = 0, sg_offset = 0; + unsigned int sg_offset = 0; + struct scatterlist *sg = NULL; // we're working in LBA mode. according to the ATA spec, // we can support up to 28-bit addressing. I don't know if Datafab @@ -217,7 +219,7 @@ static int datafab_write_data(struct us_data *us, // Get the data from the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg_idx, &sg_offset, FROM_XFER_BUF); + &sg, &sg_offset, FROM_XFER_BUF); command[0] = 0; command[1] = thistime; diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index 003fcf54588..61097cbb158 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -119,7 +119,8 @@ static int jumpshot_read_data(struct us_data *us, unsigned char thistime; unsigned int totallen, alloclen; int len, result; - unsigned int sg_idx = 0, sg_offset = 0; + unsigned int sg_offset = 0; + struct scatterlist *sg = NULL; // we're working in LBA mode. according to the ATA spec, // we can support up to 28-bit addressing. I don't know if Jumpshot @@ -170,7 +171,7 @@ static int jumpshot_read_data(struct us_data *us, // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg_idx, &sg_offset, TO_XFER_BUF); + &sg, &sg_offset, TO_XFER_BUF); sector += thistime; totallen -= len; @@ -195,7 +196,8 @@ static int jumpshot_write_data(struct us_data *us, unsigned char thistime; unsigned int totallen, alloclen; int len, result, waitcount; - unsigned int sg_idx = 0, sg_offset = 0; + unsigned int sg_offset = 0; + struct scatterlist *sg = NULL; // we're working in LBA mode. according to the ATA spec, // we can support up to 28-bit addressing. I don't know if Jumpshot @@ -225,7 +227,7 @@ static int jumpshot_write_data(struct us_data *us, // Get the data from the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg_idx, &sg_offset, FROM_XFER_BUF); + &sg, &sg_offset, FROM_XFER_BUF); command[0] = 0; command[1] = thistime; diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 9ad30428d2d..cc8f7c52c72 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -157,7 +157,7 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, * pick up from where this one left off. */ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr, unsigned int *offset, enum xfer_buf_dir dir) { unsigned int cnt; @@ -184,16 +184,17 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, * located in high memory -- then kmap() will map it to a temporary * position in the kernel's virtual address space. */ } else { - struct scatterlist *sg = - (struct scatterlist *) srb->request_buffer - + *index; + struct scatterlist *sg = *sgptr; + + if (!sg) + sg = (struct scatterlist *) srb->request_buffer; /* This loop handles a single s-g list entry, which may * include multiple pages. Find the initial page structure * and the starting offset within the page, and update * the *offset and *index values for the next loop. */ cnt = 0; - while (cnt < buflen && *index < srb->use_sg) { + while (cnt < buflen) { struct page *page = sg->page + ((sg->offset + *offset) >> PAGE_SHIFT); unsigned int poff = @@ -209,8 +210,7 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, /* Transfer continues to next s-g entry */ *offset = 0; - ++*index; - ++sg; + sg = sg_next(sg); } /* Transfer the data for all the pages in this @@ -234,6 +234,7 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, sglen -= plen; } } + *sgptr = sg; } /* Return the amount actually transferred */ @@ -245,9 +246,10 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, void usb_stor_set_xfer_buf(unsigned char *buffer, unsigned int buflen, struct scsi_cmnd *srb) { - unsigned int index = 0, offset = 0; + unsigned int offset = 0; + struct scatterlist *sg = NULL; - usb_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset, + usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, TO_XFER_BUF); if (buflen < srb->request_bufflen) srb->resid = srb->request_bufflen - buflen; diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h index 845bed4b803..8737a36891c 100644 --- a/drivers/usb/storage/protocol.h +++ b/drivers/usb/storage/protocol.h @@ -52,7 +52,7 @@ extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*, enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF}; extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **, unsigned int *offset, enum xfer_buf_dir dir); extern void usb_stor_set_xfer_buf(unsigned char *buffer, diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index b2ed2a3e6fc..b12202c5da2 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -705,7 +705,8 @@ sddr09_read_data(struct us_data *us, unsigned char *buffer; unsigned int lba, maxlba, pba; unsigned int page, pages; - unsigned int len, index, offset; + unsigned int len, offset; + struct scatterlist *sg; int result; // Figure out the initial LBA and page @@ -730,7 +731,8 @@ sddr09_read_data(struct us_data *us, // contiguous LBA's. Another exercise left to the student. result = 0; - index = offset = 0; + offset = 0; + sg = NULL; while (sectors > 0) { @@ -777,7 +779,7 @@ sddr09_read_data(struct us_data *us, // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, TO_XFER_BUF); + &sg, &offset, TO_XFER_BUF); page = 0; lba++; @@ -931,7 +933,8 @@ sddr09_write_data(struct us_data *us, unsigned int pagelen, blocklen; unsigned char *blockbuffer; unsigned char *buffer; - unsigned int len, index, offset; + unsigned int len, offset; + struct scatterlist *sg; int result; // Figure out the initial LBA and page @@ -968,7 +971,8 @@ sddr09_write_data(struct us_data *us, } result = 0; - index = offset = 0; + offset = 0; + sg = NULL; while (sectors > 0) { @@ -987,7 +991,7 @@ sddr09_write_data(struct us_data *us, // Get the data from the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, FROM_XFER_BUF); + &sg, &offset, FROM_XFER_BUF); result = sddr09_write_lba(us, lba, page, pages, buffer, blockbuffer); diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index 0b1b5b59ca7..d43a3415e12 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -167,7 +167,8 @@ static int sddr55_read_data(struct us_data *us, unsigned long address; unsigned short pages; - unsigned int len, index, offset; + unsigned int len, offset; + struct scatterlist *sg; // Since we only read in one block at a time, we have to create // a bounce buffer and move the data a piece at a time between the @@ -178,7 +179,8 @@ static int sddr55_read_data(struct us_data *us, buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; /* out of memory */ - index = offset = 0; + offset = 0; + sg = NULL; while (sectors>0) { @@ -255,7 +257,7 @@ static int sddr55_read_data(struct us_data *us, // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, TO_XFER_BUF); + &sg, &offset, TO_XFER_BUF); page = 0; lba++; @@ -287,7 +289,8 @@ static int sddr55_write_data(struct us_data *us, unsigned short pages; int i; - unsigned int len, index, offset; + unsigned int len, offset; + struct scatterlist *sg; /* check if we are allowed to write */ if (info->read_only || info->force_read_only) { @@ -304,7 +307,8 @@ static int sddr55_write_data(struct us_data *us, buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; - index = offset = 0; + offset = 0; + sg = NULL; while (sectors > 0) { @@ -322,7 +326,7 @@ static int sddr55_write_data(struct us_data *us, // Get the data from the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, FROM_XFER_BUF); + &sg, &offset, FROM_XFER_BUF); US_DEBUGP("Write %02X pages, to PBA %04X" " (LBA %04X) page %02X\n", diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 17ca4d73577..cb22a9ad169 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -993,7 +993,8 @@ static int usbat_flash_read_data(struct us_data *us, unsigned char thistime; unsigned int totallen, alloclen; int len, result; - unsigned int sg_idx = 0, sg_offset = 0; + unsigned int sg_offset = 0; + struct scatterlist *sg = NULL; result = usbat_flash_check_media(us, info); if (result != USB_STOR_TRANSPORT_GOOD) @@ -1047,7 +1048,7 @@ static int usbat_flash_read_data(struct us_data *us, /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg_idx, &sg_offset, TO_XFER_BUF); + &sg, &sg_offset, TO_XFER_BUF); sector += thistime; totallen -= len; @@ -1083,7 +1084,8 @@ static int usbat_flash_write_data(struct us_data *us, unsigned char thistime; unsigned int totallen, alloclen; int len, result; - unsigned int sg_idx = 0, sg_offset = 0; + unsigned int sg_offset = 0; + struct scatterlist *sg = NULL; result = usbat_flash_check_media(us, info); if (result != USB_STOR_TRANSPORT_GOOD) @@ -1122,7 +1124,7 @@ static int usbat_flash_write_data(struct us_data *us, /* Get the data from the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg_idx, &sg_offset, FROM_XFER_BUF); + &sg, &sg_offset, FROM_XFER_BUF); /* ATA command 0x30 (WRITE SECTORS) */ usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30); @@ -1162,8 +1164,8 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, unsigned char *buffer; unsigned int len; unsigned int sector; - unsigned int sg_segment = 0; unsigned int sg_offset = 0; + struct scatterlist *sg = NULL; US_DEBUGP("handle_read10: transfersize %d\n", srb->transfersize); @@ -1220,9 +1222,6 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, sector |= short_pack(data[7+5], data[7+4]); transferred = 0; - sg_segment = 0; /* for keeping track of where we are in */ - sg_offset = 0; /* the scatter/gather list */ - while (transferred != srb->request_bufflen) { if (len > srb->request_bufflen - transferred) @@ -1255,7 +1254,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, srb, - &sg_segment, &sg_offset, TO_XFER_BUF); + &sg, &sg_offset, TO_XFER_BUF); /* Update the amount transferred and the sector number */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 5216c11d4de..efe474e2cc3 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -5,8 +5,9 @@ menu "Graphics support" depends on HAS_IOMEM -source "drivers/video/backlight/Kconfig" -source "drivers/video/display/Kconfig" +source "drivers/char/agp/Kconfig" + +source "drivers/char/drm/Kconfig" config VGASTATE tristate @@ -19,7 +20,7 @@ config VIDEO_OUTPUT_CONTROL This framework adds support for low-level control of the video output switch. -config FB +menuconfig FB tristate "Support for frame buffer devices" ---help--- The frame buffer device provides an abstraction for the graphics @@ -103,6 +104,15 @@ config FB_CFB_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version. +config FB_CFB_REV_PIXELS_IN_BYTE + bool + depends on FB + default n + ---help--- + Allow generic frame-buffer functions to work on displays with 1, 2 + and 4 bits per pixel depths which has opposite order of pixels in + byte order to bytes in long order. + config FB_SYS_FILLRECT tristate depends on FB @@ -535,6 +545,15 @@ config FB_VGA16 To compile this driver as a module, choose M here: the module will be called vga16fb. +config FB_BF54X_LQ043 + tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)" + depends on FB && (BF54x) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD + config FB_STI tristate "HP STI frame buffer device support" depends on FB && PARISC @@ -592,6 +611,24 @@ config FB_TGA Say Y if you have one of those. +config FB_UVESA + tristate "Userspace VESA VGA graphics support" + depends on FB && CONNECTOR + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_MODE_HELPERS + help + This is the frame buffer driver for generic VBE 2.0 compliant + graphic cards. It can also take advantage of VBE 3.0 features, + such as refresh rate adjustment. + + This driver generally provides more features than vesafb but + requires a userspace helper application called 'v86d'. See + <file:Documentation/fb/uvesafb.txt> for more information. + + If unsure, say N. + config FB_VESA bool "VESA VGA graphics support" depends on (FB = y) && X86 @@ -1625,7 +1662,7 @@ config FB_PMAG_BA config FB_PMAGB_B tristate "PMAGB-B TURBOchannel framebuffer support" - depends on TC + depends on FB && TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1793,7 +1830,7 @@ config FB_PNX4008_DUM_RGB config FB_IBM_GXT4500 tristate "Framebuffer support for IBM GXT4500P adaptor" - depends on PPC + depends on FB && PPC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1833,10 +1870,6 @@ config FB_XILINX framebuffer. ML300 carries a 640*480 LCD display on the board, ML403 uses a standard DB15 VGA connector. -if ARCH_OMAP - source "drivers/video/omap/Kconfig" -endif - config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB @@ -1860,6 +1893,13 @@ config FB_VIRTUAL If unsure, say N. +if ARCH_OMAP + source "drivers/video/omap/Kconfig" +endif + +source "drivers/video/backlight/Kconfig" +source "drivers/video/display/Kconfig" + if VT source "drivers/video/console/Kconfig" endif @@ -1869,4 +1909,3 @@ if FB || SGI_NEWPORT_CONSOLE endif endmenu - diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 06eec7b182b..59d6c45a910 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -115,10 +115,12 @@ obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_OMAP) += omap/ # Platform or fallback drivers go here +obj-$(CONFIG_FB_UVESA) += uvesafb.o obj-$(CONFIG_FB_VESA) += vesafb.o obj-$(CONFIG_FB_IMAC) += imacfb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o +obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 1a849b870bc..f2e243c353f 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -52,7 +52,7 @@ #include <linux/init.h> #include <linux/ioport.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/system.h> #include <asm/irq.h> #include <asm/amigahw.h> diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index db15baca3f7..c3431691c9f 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -48,7 +48,7 @@ #include <linux/arcfb.h> #include <linux/platform_device.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #define floor8(a) (a&(~0x07)) #define floorXres(a,xres) (a&(~(xres - 1))) diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 0038a0541c7..5d4fbaa53a6 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -58,7 +58,7 @@ #include <linux/interrupt.h> #include <asm/setup.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/pgtable.h> #include <asm/irq.h> #include <asm/io.h> diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h index dca2eb8f2dd..3e9d28bcd9f 100644 --- a/drivers/video/aty/ati_ids.h +++ b/drivers/video/aty/ati_ids.h @@ -188,6 +188,7 @@ #define PCI_CHIP_MACH64VT 0x5654 #define PCI_CHIP_MACH64VU 0x5655 #define PCI_CHIP_MACH64VV 0x5656 +#define PCI_CHIP_RC410_5A62 0x5A62 #define PCI_CHIP_RS300_5834 0x5834 #define PCI_CHIP_RS300_5835 0x5835 #define PCI_CHIP_RS300_5836 0x5836 diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index cfcbe37d2d7..cbd3308b669 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -56,7 +56,7 @@ #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/pci.h> diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h index dc62f8e282b..7691e73823d 100644 --- a/drivers/video/aty/atyfb.h +++ b/drivers/video/aty/atyfb.h @@ -126,6 +126,7 @@ union aty_pll { */ struct atyfb_par { + u32 pseudo_palette[16]; struct { u8 red, green, blue; } palette[256]; const struct aty_dac_ops *dac_ops; const struct aty_pll_ops *pll_ops; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index bc6f0096aa0..abe0c435a66 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -68,7 +68,7 @@ #include <linux/backlight.h> #include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <video/mach64.h> #include "atyfb.h" @@ -541,8 +541,6 @@ static char ram_off[] __devinitdata = "OFF"; #endif /* CONFIG_FB_ATY_CT */ -static u32 pseudo_palette[16]; - #ifdef CONFIG_FB_ATY_GX static char *aty_gx_ram[8] __devinitdata = { ram_dram, ram_vram, ram_vram, ram_dram, @@ -2577,7 +2575,7 @@ static int __devinit aty_init(struct fb_info *info) #endif info->fbops = &atyfb_ops; - info->pseudo_palette = pseudo_palette; + info->pseudo_palette = par->pseudo_palette; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT | diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c index fe2c6ad01a8..faf95da8fcb 100644 --- a/drivers/video/aty/mach64_cursor.c +++ b/drivers/video/aty/mach64_cursor.c @@ -8,7 +8,6 @@ #include <linux/string.h> #include <asm/io.h> -#include <asm/uaccess.h> #ifdef __sparc__ #include <asm/fbio.h> diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 4b747bdaeea..1e32b3d13f2 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -69,7 +69,7 @@ #include <linux/device.h> #include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #ifdef CONFIG_PPC_OF @@ -145,6 +145,8 @@ static struct pci_device_id radeonfb_pci_table[] = { /* 9000/Pro */ CHIP_DEF(PCI_CHIP_RV250_If, RV250, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_RV250_Ig, RV250, CHIP_HAS_CRTC2), + + CHIP_DEF(PCI_CHIP_RC410_5A62, RC410, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), /* Mobility 9100 IGP (U3) */ CHIP_DEF(PCI_CHIP_RS300_5835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), CHIP_DEF(PCI_CHIP_RS350_7835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), @@ -1999,6 +2001,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo) if ((rinfo->family == CHIP_FAMILY_RS100) || (rinfo->family == CHIP_FAMILY_RS200) || (rinfo->family == CHIP_FAMILY_RS300) || + (rinfo->family == CHIP_FAMILY_RC410) || (rinfo->family == CHIP_FAMILY_RS480) ) { u32 tom = INREG(NB_TOM); tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024); diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 7c922c7b460..5eac1ce52e7 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -48,6 +48,7 @@ enum radeon_family { CHIP_FAMILY_RV350, CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ CHIP_FAMILY_R420, /* R420/R423/M18 */ + CHIP_FAMILY_RC410, CHIP_FAMILY_RS480, CHIP_FAMILY_LAST, }; @@ -66,7 +67,8 @@ enum radeon_family { ((rinfo)->family == CHIP_FAMILY_R350) || \ ((rinfo)->family == CHIP_FAMILY_RV380) || \ ((rinfo)->family == CHIP_FAMILY_R420) || \ - ((rinfo)->family == CHIP_FAMILY_RS480) ) + ((rinfo)->family == CHIP_FAMILY_RC410) || \ + ((rinfo)->family == CHIP_FAMILY_RS480)) /* * Chip flags diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 92e201e81fb..26add889860 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -36,7 +36,6 @@ #include <linux/backlight.h> #include <linux/lcd.h> #include <linux/pci.h> -#include <asm/uaccess.h> /* The LVDS- and panel power controls sits on the * GPIO port of the ISA bridge. diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 836ab4df0ef..15fb4d58b5b 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -23,7 +23,6 @@ #include <linux/fb.h> #include <linux/backlight.h> #include <linux/pci.h> -#include <asm/uaccess.h> #define PMU_LPCR 0xB0 #define SB_MPS1 0x61 diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c new file mode 100644 index 00000000000..74d11c31898 --- /dev/null +++ b/drivers/video/bf54x-lq043fb.c @@ -0,0 +1,786 @@ +/* + * File: drivers/video/bf54x-lq043.c + * Based on: + * Author: Michael Hennerich <hennerich@blackfin.uclinux.org> + * + * Created: + * Description: ADSP-BF54x Framebufer driver + * + * + * Modified: + * Copyright 2004-2007 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/lcd.h> +#include <linux/spinlock.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> +#include <asm/dpmc.h> +#include <asm/dma-mapping.h> +#include <asm/dma.h> +#include <asm/gpio.h> +#include <asm/portmux.h> + +#include <asm/mach/bf54x-lq043.h> + +#define NO_BL_SUPPORT + +#define DRIVER_NAME "bf54x-lq043" +static char driver_name[] = DRIVER_NAME; + +#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 + +#define EPPI0_18 {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, \ + P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, \ + P_PPI0_D11, P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, P_PPI0_D16, P_PPI0_D17, 0} + +#define EPPI0_24 {P_PPI0_D18, P_PPI0_D19, P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23, 0} + +struct bfin_bf54xfb_info { + struct fb_info *fb; + struct device *dev; + + struct bfin_bf54xfb_mach_info *mach_info; + + unsigned char *fb_buffer; /* RGB Buffer */ + + dma_addr_t dma_handle; + int lq043_mmap; + int lq043_open_cnt; + int irq; + spinlock_t lock; /* lock */ +}; + +static int nocursor; +module_param(nocursor, int, 0644); +MODULE_PARM_DESC(nocursor, "cursor enable/disable"); + +static int outp_rgb666; +module_param(outp_rgb666, int, 0); +MODULE_PARM_DESC(outp_rgb666, "Output 18-bit RGB666"); + +#define LCD_X_RES 480 /*Horizontal Resolution */ +#define LCD_Y_RES 272 /* Vertical Resolution */ + +#define LCD_BPP 24 /* Bit Per Pixel */ +#define DMA_BUS_SIZE 32 + +/* -- Horizontal synchronizing -- + * + * Timing characteristics taken from the SHARP LQ043T1DG01 datasheet + * (LCY-W-06602A Page 9 of 22) + * + * Clock Frequency 1/Tc Min 7.83 Typ 9.00 Max 9.26 MHz + * + * Period TH - 525 - Clock + * Pulse width THp - 41 - Clock + * Horizontal period THd - 480 - Clock + * Back porch THb - 2 - Clock + * Front porch THf - 2 - Clock + * + * -- Vertical synchronizing -- + * Period TV - 286 - Line + * Pulse width TVp - 10 - Line + * Vertical period TVd - 272 - Line + * Back porch TVb - 2 - Line + * Front porch TVf - 2 - Line + */ + +#define LCD_CLK (8*1000*1000) /* 8MHz */ + +/* # active data to transfer after Horizontal Delay clock */ +#define EPPI_HCOUNT LCD_X_RES + +/* # active lines to transfer after Vertical Delay clock */ +#define EPPI_VCOUNT LCD_Y_RES + +/* Samples per Line = 480 (active data) + 45 (padding) */ +#define EPPI_LINE 525 + +/* Lines per Frame = 272 (active data) + 14 (padding) */ +#define EPPI_FRAME 286 + +/* FS1 (Hsync) Width (Typical)*/ +#define EPPI_FS1W_HBL 41 + +/* FS1 (Hsync) Period (Typical) */ +#define EPPI_FS1P_AVPL EPPI_LINE + +/* Horizontal Delay clock after assertion of Hsync (Typical) */ +#define EPPI_HDELAY 43 + +/* FS2 (Vsync) Width = FS1 (Hsync) Period * 10 */ +#define EPPI_FS2W_LVB (EPPI_LINE * 10) + + /* FS2 (Vsync) Period = FS1 (Hsync) Period * Lines per Frame */ +#define EPPI_FS2P_LAVF (EPPI_LINE * EPPI_FRAME) + +/* Vertical Delay after assertion of Vsync (2 Lines) */ +#define EPPI_VDELAY 12 + +#define EPPI_CLIP 0xFF00FF00 + +/* EPPI Control register configuration value for RGB out + * - EPPI as Output + * GP 2 frame sync mode, + * Internal Clock generation disabled, Internal FS generation enabled, + * Receives samples on EPPI_CLK raising edge, Transmits samples on EPPI_CLK falling edge, + * FS1 & FS2 are active high, + * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out) + * DMA Unpacking disabled when RGB Formating is enabled, otherwise DMA unpacking enabled + * Swapping Enabled, + * One (DMA) Channel Mode, + * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output + * Regular watermark - when FIFO is 100% full, + * Urgent watermark - when FIFO is 75% full + */ + +#define EPPI_CONTROL (0x20136E2E | SWAPEN) + +static inline u16 get_eppi_clkdiv(u32 target_ppi_clk) +{ + u32 sclk = get_sclk(); + + /* EPPI_CLK = (SCLK) / (2 * (EPPI_CLKDIV[15:0] + 1)) */ + + return (((sclk / target_ppi_clk) / 2) - 1); +} + +static void config_ppi(struct bfin_bf54xfb_info *fbi) +{ + + u16 eppi_clkdiv = get_eppi_clkdiv(LCD_CLK); + + bfin_write_EPPI0_FS1W_HBL(EPPI_FS1W_HBL); + bfin_write_EPPI0_FS1P_AVPL(EPPI_FS1P_AVPL); + bfin_write_EPPI0_FS2W_LVB(EPPI_FS2W_LVB); + bfin_write_EPPI0_FS2P_LAVF(EPPI_FS2P_LAVF); + bfin_write_EPPI0_CLIP(EPPI_CLIP); + + bfin_write_EPPI0_FRAME(EPPI_FRAME); + bfin_write_EPPI0_LINE(EPPI_LINE); + + bfin_write_EPPI0_HCOUNT(EPPI_HCOUNT); + bfin_write_EPPI0_HDELAY(EPPI_HDELAY); + bfin_write_EPPI0_VCOUNT(EPPI_VCOUNT); + bfin_write_EPPI0_VDELAY(EPPI_VDELAY); + + bfin_write_EPPI0_CLKDIV(eppi_clkdiv); + +/* + * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out) + * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output + */ + if (outp_rgb666) + bfin_write_EPPI0_CONTROL((EPPI_CONTROL & ~DLENGTH) | DLEN_18 | + RGB_FMT_EN); + else + bfin_write_EPPI0_CONTROL(((EPPI_CONTROL & ~DLENGTH) | DLEN_24) & + ~RGB_FMT_EN); + + +} + +static int config_dma(struct bfin_bf54xfb_info *fbi) +{ + + set_dma_config(CH_EPPI0, + set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, + INTR_DISABLE, DIMENSION_2D, + DATA_SIZE_32)); + set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8); + set_dma_y_count(CH_EPPI0, LCD_Y_RES); + set_dma_y_modify(CH_EPPI0, DMA_BUS_SIZE / 8); + set_dma_start_addr(CH_EPPI0, (unsigned long)fbi->fb_buffer); + + return 0; +} + +static int request_ports(struct bfin_bf54xfb_info *fbi) +{ + + u16 eppi_req_18[] = EPPI0_18; + u16 disp = fbi->mach_info->disp; + + if (gpio_request(disp, NULL)) { + printk(KERN_ERR "Requesting GPIO %d faild\n", disp); + return -EFAULT; + } + + if (peripheral_request_list(eppi_req_18, DRIVER_NAME)) { + printk(KERN_ERR "Requesting Peripherals faild\n"); + gpio_free(disp); + return -EFAULT; + } + + if (!outp_rgb666) { + + u16 eppi_req_24[] = EPPI0_24; + + if (peripheral_request_list(eppi_req_24, DRIVER_NAME)) { + printk(KERN_ERR "Requesting Peripherals faild\n"); + peripheral_free_list(eppi_req_18); + gpio_free(disp); + return -EFAULT; + } + } + + gpio_direction_output(disp); + gpio_set_value(disp, 1); + + return 0; +} + +static void free_ports(struct bfin_bf54xfb_info *fbi) +{ + + u16 eppi_req_18[] = EPPI0_18; + + gpio_free(fbi->mach_info->disp); + + peripheral_free_list(eppi_req_18); + + if (!outp_rgb666) { + u16 eppi_req_24[] = EPPI0_24; + peripheral_free_list(eppi_req_24); + } +} + +static int bfin_bf54x_fb_open(struct fb_info *info, int user) +{ + struct bfin_bf54xfb_info *fbi = info->par; + + spin_lock(&fbi->lock); + fbi->lq043_open_cnt++; + + if (fbi->lq043_open_cnt <= 1) { + + bfin_write_EPPI0_CONTROL(0); + SSYNC(); + + config_dma(fbi); + config_ppi(fbi); + + /* start dma */ + enable_dma(CH_EPPI0); + bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_bf54x_fb_release(struct fb_info *info, int user) +{ + struct bfin_bf54xfb_info *fbi = info->par; + + spin_lock(&fbi->lock); + + fbi->lq043_open_cnt--; + fbi->lq043_mmap = 0; + + if (fbi->lq043_open_cnt <= 0) { + + bfin_write_EPPI0_CONTROL(0); + SSYNC(); + disable_dma(CH_EPPI0); + memset(fbi->fb_buffer, 0, info->fix.smem_len); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + + if (var->bits_per_pixel != LCD_BPP) { + pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, + var->bits_per_pixel); + return -EINVAL; + } + + if (info->var.xres != var->xres || info->var.yres != var->yres || + info->var.xres_virtual != var->xres_virtual || + info->var.yres_virtual != var->yres_virtual) { + pr_debug("%s: Resolution not supported: X%u x Y%u \n", + __FUNCTION__, var->xres, var->yres); + return -EINVAL; + } + + /* + * Memory limit + */ + + if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { + pr_debug("%s: Memory Limit requested yres_virtual = %u\n", + __FUNCTION__, var->yres_virtual); + return -ENOMEM; + } + + return 0; +} + +static int bfin_bf54x_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + + struct bfin_bf54xfb_info *fbi = info->par; + + if (fbi->lq043_mmap) + return -1; + + spin_lock(&fbi->lock); + fbi->lq043_mmap = 1; + spin_unlock(&fbi->lock); + + vma->vm_start = (unsigned long)(fbi->fb_buffer); + + vma->vm_end = vma->vm_start + info->fix.smem_len; + /* For those who don't understand how mmap works, go read + * Documentation/nommu-mmap.txt. + * For those that do, you will know that the VM_MAYSHARE flag + * must be set in the vma->vm_flags structure on noMMU + * Other flags can be set, and are documented in + * include/linux/mm.h + */ + vma->vm_flags |= VM_MAYSHARE; + + return 0; +} + +int bfin_bf54x_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + if (nocursor) + return 0; + else + return -EINVAL; /* just to force soft_cursor() call */ +} + +static int bfin_bf54x_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + u32 value; + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + value &= 0xFFFFFF; + + ((u32 *) (info->pseudo_palette))[regno] = value; + + } + + return 0; +} + +static struct fb_ops bfin_bf54x_fb_ops = { + .owner = THIS_MODULE, + .fb_open = bfin_bf54x_fb_open, + .fb_release = bfin_bf54x_fb_release, + .fb_check_var = bfin_bf54x_fb_check_var, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = bfin_bf54x_fb_mmap, + .fb_cursor = bfin_bf54x_fb_cursor, + .fb_setcolreg = bfin_bf54x_fb_setcolreg, +}; + +#ifndef NO_BL_SUPPORT +static int bl_get_brightness(struct backlight_device *bd) +{ + return 0; +} + +static struct backlight_ops bfin_lq043fb_bl_ops = { + .get_brightness = bl_get_brightness, +}; + +static struct backlight_device *bl_dev; + +static int bfin_lcd_get_power(struct lcd_device *dev) +{ + return 0; +} + +static int bfin_lcd_set_power(struct lcd_device *dev, int power) +{ + return 0; +} + +static int bfin_lcd_get_contrast(struct lcd_device *dev) +{ + return 0; +} + +static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast) +{ + + return 0; +} + +static int bfin_lcd_check_fb(struct fb_info *fi) +{ + if (!fi || (fi == &bfin_bf54x_fb)) + return 1; + return 0; +} + +static struct lcd_ops bfin_lcd_ops = { + .get_power = bfin_lcd_get_power, + .set_power = bfin_lcd_set_power, + .get_contrast = bfin_lcd_get_contrast, + .set_contrast = bfin_lcd_set_contrast, + .check_fb = bfin_lcd_check_fb, +}; + +static struct lcd_device *lcd_dev; +#endif + +static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) +{ + + /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/ + + u16 status = bfin_read_EPPI0_STATUS(); + + bfin_write_EPPI0_STATUS(0xFFFF); + + if (status) { + bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN); + disable_dma(CH_EPPI0); + + /* start dma */ + enable_dma(CH_EPPI0); + bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN); + bfin_write_EPPI0_STATUS(0xFFFF); + } + + return IRQ_HANDLED; +} + +static int __init bfin_bf54x_probe(struct platform_device *pdev) +{ + struct bfin_bf54xfb_info *info; + struct fb_info *fbinfo; + int ret; + + printk(KERN_INFO DRIVER_NAME ": FrameBuffer initializing...\n"); + + if (request_dma(CH_EPPI0, "CH_EPPI0") < 0) { + printk(KERN_ERR DRIVER_NAME + ": couldn't request CH_EPPI0 DMA\n"); + ret = -EFAULT; + goto out1; + } + + fbinfo = + framebuffer_alloc(sizeof(struct bfin_bf54xfb_info), &pdev->dev); + if (!fbinfo) { + ret = -ENOMEM; + goto out2; + } + + info = fbinfo->par; + info->fb = fbinfo; + info->dev = &pdev->dev; + + platform_set_drvdata(pdev, fbinfo); + + strcpy(fbinfo->fix.id, driver_name); + + info->mach_info = pdev->dev.platform_data; + + if (info->mach_info == NULL) { + dev_err(&pdev->dev, + "no platform data for lcd, cannot attach\n"); + ret = -EINVAL; + goto out3; + } + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = info->mach_info->height; + fbinfo->var.width = info->mach_info->width; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->fbops = &bfin_bf54x_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + + fbinfo->var.xres = info->mach_info->xres.defval; + fbinfo->var.xres_virtual = info->mach_info->xres.defval; + fbinfo->var.yres = info->mach_info->yres.defval; + fbinfo->var.yres_virtual = info->mach_info->yres.defval; + fbinfo->var.bits_per_pixel = info->mach_info->bpp.defval; + + fbinfo->var.upper_margin = 0; + fbinfo->var.lower_margin = 0; + fbinfo->var.vsync_len = 0; + + fbinfo->var.left_margin = 0; + fbinfo->var.right_margin = 0; + fbinfo->var.hsync_len = 0; + + fbinfo->var.red.offset = 16; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 0; + fbinfo->var.transp.offset = 0; + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; + fbinfo->var.transp.length = 0; + fbinfo->fix.smem_len = info->mach_info->xres.max * + info->mach_info->yres.max * info->mach_info->bpp.max / 8; + + fbinfo->fix.line_length = fbinfo->var.xres_virtual * + fbinfo->var.bits_per_pixel / 8; + + info->fb_buffer = + dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, + GFP_KERNEL); + + if (NULL == info->fb_buffer) { + printk(KERN_ERR DRIVER_NAME + ": couldn't allocate dma buffer.\n"); + ret = -ENOMEM; + goto out3; + } + + memset(info->fb_buffer, 0, fbinfo->fix.smem_len); + + fbinfo->screen_base = (void *)info->fb_buffer; + fbinfo->fix.smem_start = (int)info->fb_buffer; + + fbinfo->fbops = &bfin_bf54x_fb_ops; + + fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + if (!fbinfo->pseudo_palette) { + printk(KERN_ERR DRIVER_NAME + "Fail to allocate pseudo_palette\n"); + + ret = -ENOMEM; + goto out4; + } + + memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16); + + if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) + < 0) { + printk(KERN_ERR DRIVER_NAME + "Fail to allocate colormap (%d entries)\n", + BFIN_LCD_NBR_PALETTE_ENTRIES); + ret = -EFAULT; + goto out5; + } + + if (request_ports(info)) { + printk(KERN_ERR DRIVER_NAME ": couldn't request gpio port.\n"); + ret = -EFAULT; + goto out6; + } + + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + ret = -EINVAL; + goto out7; + } + + if (request_irq(info->irq, (void *)bfin_bf54x_irq_error, IRQF_DISABLED, + "PPI ERROR", info) < 0) { + printk(KERN_ERR DRIVER_NAME + ": unable to request PPI ERROR IRQ\n"); + ret = -EFAULT; + goto out7; + } + + if (register_framebuffer(fbinfo) < 0) { + printk(KERN_ERR DRIVER_NAME + ": unable to register framebuffer.\n"); + ret = -EINVAL; + goto out8; + } +#ifndef NO_BL_SUPPORT + bl_dev = + backlight_device_register("bf54x-bl", NULL, NULL, + &bfin_lq043fb_bl_ops); + bl_dev->props.max_brightness = 255; + + lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); + lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n"); +#endif + + return 0; + +out8: + free_irq(info->irq, info); +out7: + free_ports(info); +out6: + fb_dealloc_cmap(&fbinfo->cmap); +out5: + kfree(fbinfo->pseudo_palette); +out4: + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); +out3: + framebuffer_release(fbinfo); +out2: + free_dma(CH_EPPI0); +out1: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int bfin_bf54x_remove(struct platform_device *pdev) +{ + + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_bf54xfb_info *info = fbinfo->par; + + free_dma(CH_EPPI0); + free_irq(info->irq, info); + + if (info->fb_buffer != NULL) + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + + kfree(fbinfo->pseudo_palette); + fb_dealloc_cmap(&fbinfo->cmap); + +#ifndef NO_BL_SUPPORT + lcd_device_unregister(lcd_dev); + backlight_device_unregister(bl_dev); +#endif + + unregister_framebuffer(fbinfo); + + free_ports(info); + + printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_bf54x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_bf54xfb_info *info = fbinfo->par; + + bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN); + disable_dma(CH_EPPI0); + bfin_write_EPPI0_STATUS(0xFFFF); + + return 0; +} + +static int bfin_bf54x_resume(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_bf54xfb_info *info = fbinfo->par; + + enable_dma(CH_EPPI0); + bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN); + + return 0; +} +#else +#define bfin_bf54x_suspend NULL +#define bfin_bf54x_resume NULL +#endif + +static struct platform_driver bfin_bf54x_driver = { + .probe = bfin_bf54x_probe, + .remove = bfin_bf54x_remove, + .suspend = bfin_bf54x_suspend, + .resume = bfin_bf54x_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __devinit bfin_bf54x_driver_init(void) +{ + return platform_driver_register(&bfin_bf54x_driver); +} + +static void __exit bfin_bf54x_driver_cleanup(void) +{ + platform_driver_unregister(&bfin_bf54x_driver); +} + +MODULE_DESCRIPTION("Blackfin BF54x TFT LCD Driver"); +MODULE_LICENSE("GPL"); + +module_init(bfin_bf54x_driver_init); +module_exit(bfin_bf54x_driver_cleanup); diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 032210f45be..b07e419b12d 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -45,14 +45,14 @@ static void bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n) + int src_idx, int bits, unsigned n, u32 bswapmask) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); if (!shift) { // Same alignment for source and dest @@ -94,29 +94,34 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); } } else { + /* Different alignment for source and dest */ unsigned long d0, d1; int m; - // Different alignment for source and dest right = shift & (bits - 1); left = -shift & (bits - 1); + bswapmask &= shift; if (dst_idx+n <= bits) { // Single destination word if (last) first &= last; + d0 = FB_READL(src); + d0 = fb_rev_pixels_in_long(d0, bswapmask); if (shift > 0) { // Single source word - FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst); + d0 >>= right; } else if (src_idx+n <= bits) { // Single source word - FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst); + d0 <<= left;; } else { // 2 source words - d0 = FB_READL(src++); - d1 = FB_READL(src); - FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); + d1 = FB_READL(src + 1); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0<<left | d1>>right; } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), first), dst); } else { // Multiple destination words /** We must always remember the last value read, because in case @@ -125,25 +130,31 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src overlap with the current long from SRC. We store this value in 'd0'. */ d0 = FB_READL(src++); + d0 = fb_rev_pixels_in_long(d0, bswapmask); // Leading bits if (shift > 0) { // Single source word - FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst); + d1 = d0; + d0 >>= right; dst++; n -= bits - dst_idx; } else { // 2 source words d1 = FB_READL(src++); - FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst); - d0 = d1; + d1 = fb_rev_pixels_in_long(d1, bswapmask); + + d0 = d0<<left | d1>>right; dst++; n -= bits - dst_idx; } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), first), dst); + d0 = d1; // Main chunk m = n % bits; n /= bits; - while (n >= 4) { + while ((n >= 4) && !bswapmask) { d1 = FB_READL(src++); FB_WRITEL(d0 << left | d1 >> right, dst++); d0 = d1; @@ -160,7 +171,10 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src } while (n--) { d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0 << left | d1 >> right; + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(d0, dst++); d0 = d1; } @@ -168,12 +182,16 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src if (last) { if (m <= right) { // Single source word - FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst); + d0 <<= left; } else { // 2 source words d1 = FB_READL(src); - FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst); + d1 = fb_rev_pixels_in_long(d1, + bswapmask); + d0 = d0<<left | d1>>right; } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), last), dst); } } } @@ -185,7 +203,7 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src static void bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n) + int src_idx, int bits, unsigned n, u32 bswapmask) { unsigned long first, last; int shift; @@ -203,8 +221,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem shift = dst_idx-src_idx; - first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); - last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); + first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask); if (!shift) { // Same alignment for source and dest @@ -247,24 +265,32 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem } } else { // Different alignment for source and dest + unsigned long d0, d1; + int m; int const left = -shift & (bits-1); int const right = shift & (bits-1); + bswapmask &= shift; if ((unsigned long)dst_idx+1 >= n) { // Single destination word if (last) first &= last; + d0 = FB_READL(src); if (shift < 0) { // Single source word - FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst); + d0 <<= left; } else if (1+(unsigned long)src_idx >= n) { // Single source word - FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst); + d0 >>= right; } else { // 2 source words - FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst); + d1 = FB_READL(src - 1); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0>>right | d1<<left; } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), first), dst); } else { // Multiple destination words /** We must always remember the last value read, because in case @@ -272,27 +298,30 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem 1bpp), we always collect one full long for DST and that might overlap with the current long from SRC. We store this value in 'd0'. */ - unsigned long d0, d1; - int m; d0 = FB_READL(src--); + d0 = fb_rev_pixels_in_long(d0, bswapmask); // Leading bits if (shift < 0) { // Single source word - FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst); + d1 = d0; + d0 <<= left; } else { // 2 source words d1 = FB_READL(src--); - FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst); - d0 = d1; + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0>>right | d1<<left; } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), first), dst); + d0 = d1; dst--; n -= dst_idx+1; // Main chunk m = n % bits; n /= bits; - while (n >= 4) { + while ((n >= 4) && !bswapmask) { d1 = FB_READL(src--); FB_WRITEL(d0 >> right | d1 << left, dst--); d0 = d1; @@ -309,7 +338,10 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem } while (n--) { d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0 >> right | d1 << left; + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(d0, dst--); d0 = d1; } @@ -317,12 +349,16 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem if (last) { if (m <= left) { // Single source word - FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst); + d0 >>= right; } else { // 2 source words d1 = FB_READL(src); - FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst); + d1 = fb_rev_pixels_in_long(d1, + bswapmask); + d0 = d0>>right | d1<<left; } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), last), dst); } } } @@ -336,6 +372,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) unsigned long __iomem *dst = NULL, *src = NULL; int bits = BITS_PER_LONG, bytes = bits >> 3; int dst_idx = 0, src_idx = 0, rev_copy = 0; + u32 bswapmask = fb_compute_bswapmask(p); if (p->state != FBINFO_STATE_RUNNING) return; @@ -368,7 +405,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); bitcpy_rev(dst, dst_idx, src, src_idx, bits, - width*p->var.bits_per_pixel); + width*p->var.bits_per_pixel, bswapmask); } } else { while (height--) { @@ -377,7 +414,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); bitcpy(dst, dst_idx, src, src_idx, bits, - width*p->var.bits_per_pixel); + width*p->var.bits_per_pixel, bswapmask); dst_idx += bits_per_line; src_idx += bits_per_line; } diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 71623b4f8ca..23d70a12e4d 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -36,15 +36,16 @@ */ static void -bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) +bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, + unsigned n, int bits, u32 bswapmask) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -146,7 +147,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) +bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, + unsigned n, int bits, u32 bswapmask) { unsigned long val = pat, dat; unsigned long first, last; @@ -154,8 +156,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -303,8 +305,10 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->fbops->fb_sync) p->fbops->fb_sync(p); if (!left) { + u32 bswapmask = fb_compute_bswapmask(p); void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, - unsigned long pat, unsigned n, int bits) = NULL; + unsigned long pat, unsigned n, int bits, + u32 bswapmask) = NULL; switch (rect->rop) { case ROP_XOR: @@ -321,7 +325,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits); + fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask); dst_idx += p->fix.line_length*8; } } else { diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 261004473c8..f598907b42a 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -33,6 +33,7 @@ #include <linux/string.h> #include <linux/fb.h> #include <asm/types.h> +#include "fb_draw.h" #define DEBUG @@ -87,6 +88,7 @@ static inline void color_imageblit(const struct fb_image *image, u32 null_bits = 32 - bpp; u32 *palette = (u32 *) p->pseudo_palette; const u8 *src = image->data; + u32 bswapmask = fb_compute_bswapmask(p); dst2 = (u32 __iomem *) dst1; for (i = image->height; i--; ) { @@ -96,7 +98,7 @@ static inline void color_imageblit(const struct fb_image *image, val = 0; if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index)); + u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -107,7 +109,7 @@ static inline void color_imageblit(const struct fb_image *image, else color = *src; color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift); + val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); if (shift >= null_bits) { FB_WRITEL(val, dst++); @@ -119,7 +121,7 @@ static inline void color_imageblit(const struct fb_image *image, src++; } if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -147,7 +149,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * u32 spitch = (image->width+7)/8; const u8 *src = image->data, *s; u32 i, j, l; - + u32 bswapmask = fb_compute_bswapmask(p); + dst2 = (u32 __iomem *) dst1; fgcolor <<= FB_LEFT_POS(bpp); bgcolor <<= FB_LEFT_POS(bpp); @@ -161,7 +164,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write leading bits */ if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index)); + u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -169,7 +172,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift); + val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { @@ -184,7 +187,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write trailing bits */ if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 8269d704ab2..ce22bf5de35 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -45,7 +45,6 @@ #include <linux/delay.h> #include <linux/fb.h> #include <linux/init.h> -#include <linux/selection.h> #include <asm/pgtable.h> #ifdef CONFIG_ZORRO @@ -59,14 +58,13 @@ #endif #ifdef CONFIG_PPC_PREP #include <asm/machdep.h> -#define isPReP (machine_is(prep)) +#define isPReP machine_is(prep) #else #define isPReP 0 #endif -#include "video/vga.h" -#include "video/cirrus.h" - +#include <video/vga.h> +#include <video/cirrus.h> /***************************************************************** * @@ -82,7 +80,8 @@ /* debug output */ #ifdef CIRRUSFB_DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#define DPRINTK(fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) #else #define DPRINTK(fmt, args...) #endif @@ -90,19 +89,15 @@ /* debugging assertions */ #ifndef CIRRUSFB_NDEBUG #define assert(expr) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ - } + if (!(expr)) { \ + printk("Assertion failed! %s,%s,%s,line=%d\n", \ + #expr, __FILE__, __FUNCTION__, __LINE__); \ + } #else #define assert(expr) #endif -#define MB_ (1024*1024) -#define KB_ (1024) - -#define MAX_NUM_BOARDS 7 - +#define MB_ (1024 * 1024) /***************************************************************** * @@ -111,7 +106,7 @@ */ /* board types */ -typedef enum { +enum cirrus_board { BT_NONE = 0, BT_SD64, BT_PICCOLO, @@ -121,13 +116,12 @@ typedef enum { BT_ALPINE, /* GD543x/4x */ BT_GD5480, BT_LAGUNA, /* GD546x */ -} cirrusfb_board_t; - +}; /* * per-board-type information, used for enumerating and abstracting * chip-specific information - * NOTE: MUST be in the same order as cirrusfb_board_t in order to + * NOTE: MUST be in the same order as enum cirrus_board in order to * use direct indexing on this array * NOTE: '__initdata' cannot be used as some of this info * is required at runtime. Maybe separate into an init-only and @@ -139,7 +133,8 @@ static const struct cirrusfb_board_info_rec { /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */ bool init_sr07 : 1; /* init SR07 during init_vgachip() */ bool init_sr1f : 1; /* write SR1F during init_vgachip() */ - bool scrn_start_bit19 : 1; /* construct bit 19 of screen start address */ + /* construct bit 19 of screen start address */ + bool scrn_start_bit19 : 1; /* initial SR07 value, then for each mode */ unsigned char sr07; @@ -261,30 +256,28 @@ static const struct cirrusfb_board_info_rec { } }; - #ifdef CONFIG_PCI #define CHIP(id, btype) \ { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } static struct pci_device_id cirrusfb_pci_table[] = { - CHIP( PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE ), - CHIP( PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE ), - CHIP( PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE ), - CHIP( PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE ), /* GD-5440 is same id */ - CHIP( PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE ), - CHIP( PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE ), - CHIP( PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480 ), /* MacPicasso likely */ - CHIP( PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is 5446 */ - CHIP( PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */ - CHIP( PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */ - CHIP( PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/ + CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE), + CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE), + CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE), + CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */ + CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE), + CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE), + CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */ + CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */ + CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */ + CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */ + CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/ { 0, } }; MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); #undef CHIP #endif /* CONFIG_PCI */ - #ifdef CONFIG_ZORRO static const struct zorro_device_id cirrusfb_zorro_table[] = { { @@ -294,7 +287,7 @@ static const struct zorro_device_id cirrusfb_zorro_table[] = { .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, .driver_data = BT_PICCOLO, }, { - .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, + .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, .driver_data = BT_PICASSO, }, { .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, @@ -333,12 +326,7 @@ static const struct { }; #endif /* CONFIG_ZORRO */ - struct cirrusfb_regs { - __u32 line_length; /* in BYTES! */ - __u32 visual; - __u32 type; - long freq; long nom; long den; @@ -364,37 +352,23 @@ struct cirrusfb_regs { long VertBlankEnd; }; - - #ifdef CIRRUSFB_DEBUG -typedef enum { - CRT, - SEQ -} cirrusfb_dbg_reg_class_t; -#endif /* CIRRUSFB_DEBUG */ - - - +enum cirrusfb_dbg_reg_class { + CRT, + SEQ +}; +#endif /* CIRRUSFB_DEBUG */ /* info about board */ struct cirrusfb_info { - struct fb_info *info; - - u8 __iomem *fbmem; u8 __iomem *regbase; - u8 __iomem *mem; - unsigned long size; - cirrusfb_board_t btype; + enum cirrus_board btype; unsigned char SFR; /* Shadow of special function register */ - unsigned long fbmem_phys; - unsigned long fbregs_phys; - struct cirrusfb_regs currentmode; int blank_mode; u32 pseudo_palette[16]; - struct { u8 red, green, blue, pad; } palette[256]; #ifdef CONFIG_ZORRO struct zorro_dev *zdev; @@ -402,12 +376,11 @@ struct cirrusfb_info { #ifdef CONFIG_PCI struct pci_dev *pdev; #endif - void (*unmap)(struct cirrusfb_info *cinfo); + void (*unmap)(struct fb_info *info); }; - static unsigned cirrusfb_def_mode = 1; -static int noaccel = 0; +static int noaccel; /* * Predefined Video Modes @@ -441,7 +414,7 @@ static const struct { .lower_margin = 8, .hsync_len = 96, .vsync_len = 4, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED } }, { @@ -502,27 +475,29 @@ static const struct { /****************************************************************************/ /**** BEGIN PROTOTYPES ******************************************************/ - /*--- Interface used by the world ------------------------------------------*/ -static int cirrusfb_init (void); +static int cirrusfb_init(void); #ifndef MODULE -static int cirrusfb_setup (char *options); +static int cirrusfb_setup(char *options); #endif -static int cirrusfb_open (struct fb_info *info, int user); -static int cirrusfb_release (struct fb_info *info, int user); -static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info); -static int cirrusfb_check_var (struct fb_var_screeninfo *var, - struct fb_info *info); -static int cirrusfb_set_par (struct fb_info *info); -static int cirrusfb_pan_display (struct fb_var_screeninfo *var, - struct fb_info *info); -static int cirrusfb_blank (int blank_mode, struct fb_info *info); -static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region); -static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); -static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image); +static int cirrusfb_open(struct fb_info *info, int user); +static int cirrusfb_release(struct fb_info *info, int user); +static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); +static int cirrusfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int cirrusfb_set_par(struct fb_info *info); +static int cirrusfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int cirrusfb_blank(int blank_mode, struct fb_info *info); +static void cirrusfb_fillrect(struct fb_info *info, + const struct fb_fillrect *region); +static void cirrusfb_copyarea(struct fb_info *info, + const struct fb_copyarea *area); +static void cirrusfb_imageblit(struct fb_info *info, + const struct fb_image *image); /* function table of the above functions */ static struct fb_ops cirrusfb_ops = { @@ -540,68 +515,68 @@ static struct fb_ops cirrusfb_ops = { }; /*--- Hardware Specific Routines -------------------------------------------*/ -static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, +static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, struct cirrusfb_regs *regs, - const struct fb_info *info); + struct fb_info *info); /*--- Internal routines ----------------------------------------------------*/ -static void init_vgachip (struct cirrusfb_info *cinfo); -static void switch_monitor (struct cirrusfb_info *cinfo, int on); -static void WGen (const struct cirrusfb_info *cinfo, - int regnum, unsigned char val); -static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum); -static void AttrOn (const struct cirrusfb_info *cinfo); -static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val); -static void WSFR (struct cirrusfb_info *cinfo, unsigned char val); -static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val); -static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, - unsigned char green, - unsigned char blue); +static void init_vgachip(struct fb_info *info); +static void switch_monitor(struct cirrusfb_info *cinfo, int on); +static void WGen(const struct cirrusfb_info *cinfo, + int regnum, unsigned char val); +static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum); +static void AttrOn(const struct cirrusfb_info *cinfo); +static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val); +static void WSFR(struct cirrusfb_info *cinfo, unsigned char val); +static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val); +static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, + unsigned char red, unsigned char green, unsigned char blue); #if 0 -static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, - unsigned char *green, - unsigned char *blue); +static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, + unsigned char *red, unsigned char *green, + unsigned char *blue); #endif -static void cirrusfb_WaitBLT (u8 __iomem *regbase); -static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, - u_short curx, u_short cury, - u_short destx, u_short desty, - u_short width, u_short height, - u_short line_length); -static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, - u_short x, u_short y, - u_short width, u_short height, - u_char color, u_short line_length); - -static void bestclock (long freq, long *best, - long *nom, long *den, - long *div, long maxfreq); +static void cirrusfb_WaitBLT(u8 __iomem *regbase); +static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, + u_short curx, u_short cury, + u_short destx, u_short desty, + u_short width, u_short height, + u_short line_length); +static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, + u_short x, u_short y, + u_short width, u_short height, + u_char color, u_short line_length); + +static void bestclock(long freq, long *best, + long *nom, long *den, + long *div, long maxfreq); #ifdef CIRRUSFB_DEBUG -static void cirrusfb_dump (void); -static void cirrusfb_dbg_reg_dump (caddr_t regbase); -static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...); -static void cirrusfb_dbg_print_byte (const char *name, unsigned char val); +static void cirrusfb_dump(void); +static void cirrusfb_dbg_reg_dump(caddr_t regbase); +static void cirrusfb_dbg_print_regs(caddr_t regbase, + enum cirrusfb_dbg_reg_class reg_class, ...); +static void cirrusfb_dbg_print_byte(const char *name, unsigned char val); #endif /* CIRRUSFB_DEBUG */ /*** END PROTOTYPES ********************************************************/ /*****************************************************************************/ /*** BEGIN Interface Used by the World ***************************************/ -static int opencount = 0; +static int opencount; /*--- Open /dev/fbx ---------------------------------------------------------*/ -static int cirrusfb_open (struct fb_info *info, int user) +static int cirrusfb_open(struct fb_info *info, int user) { if (opencount++ == 0) - switch_monitor (info->par, 1); + switch_monitor(info->par, 1); return 0; } /*--- Close /dev/fbx --------------------------------------------------------*/ -static int cirrusfb_release (struct fb_info *info, int user) +static int cirrusfb_release(struct fb_info *info, int user) { if (--opencount == 0) - switch_monitor (info->par, 0); + switch_monitor(info->par, 0); return 0; } @@ -610,11 +585,11 @@ static int cirrusfb_release (struct fb_info *info, int user) /**** BEGIN Hardware specific Routines **************************************/ /* Get a good MCLK value */ -static long cirrusfb_get_mclk (long freq, int bpp, long *div) +static long cirrusfb_get_mclk(long freq, int bpp, long *div) { long mclk; - assert (div != NULL); + assert(div != NULL); /* Calculate MCLK, in case VCLK is high enough to require > 50MHz. * Assume a 64-bit data path for now. The formula is: @@ -624,23 +599,23 @@ static long cirrusfb_get_mclk (long freq, int bpp, long *div) mclk = (mclk * 12) / 10; if (mclk < 50000) mclk = 50000; - DPRINTK ("Use MCLK of %ld kHz\n", mclk); + DPRINTK("Use MCLK of %ld kHz\n", mclk); /* Calculate value for SR1F. Multiply by 2 so we can round up. */ mclk = ((mclk * 16) / 14318); mclk = (mclk + 1) / 2; - DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk); + DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk); /* Determine if we should use MCLK instead of VCLK, and if so, what we * should divide it by to get VCLK */ switch (freq) { case 24751 ... 25249: *div = 2; - DPRINTK ("Using VCLK = MCLK/2\n"); + DPRINTK("Using VCLK = MCLK/2\n"); break; case 49501 ... 50499: *div = 1; - DPRINTK ("Using VCLK = MCLK\n"); + DPRINTK("Using VCLK = MCLK\n"); break; default: *div = 0; @@ -653,7 +628,6 @@ static long cirrusfb_get_mclk (long freq, int bpp, long *div) static int cirrusfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - struct cirrusfb_info *cinfo = info->par; int nom, den; /* translyting from pixels->bytes */ int yres, i; static struct { int xres, yres; } modes[] = @@ -665,63 +639,55 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, { -1, -1 } }; switch (var->bits_per_pixel) { - case 0 ... 1: - var->bits_per_pixel = 1; + case 1: nom = 4; den = 8; break; /* 8 pixel per byte, only 1/4th of mem usable */ - case 2 ... 8: - var->bits_per_pixel = 8; - nom = 1; + case 8: + case 16: + case 24: + case 32: + nom = var->bits_per_pixel / 8; den = 1; break; /* 1 pixel == 1 byte */ - case 9 ... 16: - var->bits_per_pixel = 16; - nom = 2; - den = 1; - break; /* 2 bytes per pixel */ - case 17 ... 24: - var->bits_per_pixel = 24; - nom = 3; - den = 1; - break; /* 3 bytes per pixel */ - case 25 ... 32: - var->bits_per_pixel = 32; - nom = 4; - den = 1; - break; /* 4 bytes per pixel */ default: - printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n", + printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." + "color depth not supported.\n", var->xres, var->yres, var->bits_per_pixel); - DPRINTK ("EXIT - EINVAL error\n"); + DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } - if (var->xres * nom / den * var->yres > cinfo->size) { - printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", + if (var->xres * nom / den * var->yres > info->screen_size) { + printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." + "resolution too high to fit into video memory!\n", var->xres, var->yres, var->bits_per_pixel); - DPRINTK ("EXIT - EINVAL error\n"); + DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } /* use highest possible virtual resolution */ if (var->xres_virtual == -1 && var->yres_virtual == -1) { - printk ("cirrusfb: using maximum available virtual resolution\n"); + printk(KERN_INFO + "cirrusfb: using maximum available virtual resolution\n"); for (i = 0; modes[i].xres != -1; i++) { - if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2) + int size = modes[i].xres * nom / den * modes[i].yres; + if (size < info->screen_size / 2) break; } if (modes[i].xres == -1) { - printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n"); - DPRINTK ("EXIT - EINVAL error\n"); + printk(KERN_ERR "cirrusfb: could not find a virtual " + "resolution that fits into video memory!!\n"); + DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } var->xres_virtual = modes[i].xres; var->yres_virtual = modes[i].yres; - printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n", - var->xres_virtual, var->yres_virtual); + printk(KERN_INFO "cirrusfb: virtual resolution set to " + "maximum of %dx%d\n", var->xres_virtual, + var->yres_virtual); } if (var->xres_virtual < var->xres) @@ -744,23 +710,19 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, case 1: var->red.offset = 0; var->red.length = 1; - var->green.offset = 0; - var->green.length = 1; - var->blue.offset = 0; - var->blue.length = 1; + var->green = var->red; + var->blue = var->red; break; case 8: var->red.offset = 0; var->red.length = 6; - var->green.offset = 0; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 6; + var->green = var->red; + var->blue = var->red; break; case 16: - if(isPReP) { + if (isPReP) { var->red.offset = 2; var->green.offset = -3; var->blue.offset = 8; @@ -775,22 +737,8 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, break; case 24: - if(isPReP) { - var->red.offset = 8; - var->green.offset = 16; - var->blue.offset = 24; - } else { - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - } - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - break; - case 32: - if(isPReP) { + if (isPReP) { var->red.offset = 8; var->green.offset = 16; var->blue.offset = 24; @@ -825,54 +773,42 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, yres = (yres + 1) / 2; if (yres >= 1280) { - printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n"); - DPRINTK ("EXIT - EINVAL error\n"); + printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; " + "special treatment required! (TODO)\n"); + DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } return 0; } -static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, +static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, struct cirrusfb_regs *regs, - const struct fb_info *info) + struct fb_info *info) { long freq; long maxclock; - int maxclockidx = 0; + int maxclockidx = var->bits_per_pixel >> 3; struct cirrusfb_info *cinfo = info->par; int xres, hfront, hsync, hback; int yres, vfront, vsync, vback; - switch(var->bits_per_pixel) { + switch (var->bits_per_pixel) { case 1: - regs->line_length = var->xres_virtual / 8; - regs->visual = FB_VISUAL_MONO10; - maxclockidx = 0; + info->fix.line_length = var->xres_virtual / 8; + info->fix.visual = FB_VISUAL_MONO10; break; case 8: - regs->line_length = var->xres_virtual; - regs->visual = FB_VISUAL_PSEUDOCOLOR; - maxclockidx = 1; + info->fix.line_length = var->xres_virtual; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; case 16: - regs->line_length = var->xres_virtual * 2; - regs->visual = FB_VISUAL_DIRECTCOLOR; - maxclockidx = 2; - break; - case 24: - regs->line_length = var->xres_virtual * 3; - regs->visual = FB_VISUAL_DIRECTCOLOR; - maxclockidx = 3; - break; - case 32: - regs->line_length = var->xres_virtual * 4; - regs->visual = FB_VISUAL_DIRECTCOLOR; - maxclockidx = 4; + info->fix.line_length = var->xres_virtual * maxclockidx; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; break; default: @@ -882,12 +818,12 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, break; } - regs->type = FB_TYPE_PACKED_PIXELS; + info->fix.type = FB_TYPE_PACKED_PIXELS; /* convert from ps to kHz */ - freq = 1000000000 / var->pixclock; + freq = PICOS2KHZ(var->pixclock); - DPRINTK ("desired pixclock: %ld kHz\n", freq); + DPRINTK("desired pixclock: %ld kHz\n", freq); maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; regs->multiplexing = 0; @@ -902,8 +838,9 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, break; default: - printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock); - DPRINTK ("EXIT - return -EINVAL\n"); + printk(KERN_ERR "cirrusfb: Frequency greater " + "than maxclock (%ld kHz)\n", maxclock); + DPRINTK("EXIT - return -EINVAL\n"); return -EINVAL; } } @@ -914,14 +851,16 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, case 16: case 32: if (regs->HorizRes <= 800) - freq /= 2; /* Xbh has this type of clock for 32-bit */ + /* Xbh has this type of clock for 32-bit */ + freq /= 2; break; } #endif - bestclock (freq, ®s->freq, ®s->nom, ®s->den, ®s->div, - maxclock); - regs->mclk = cirrusfb_get_mclk (freq, var->bits_per_pixel, ®s->divMCLK); + bestclock(freq, ®s->freq, ®s->nom, ®s->den, ®s->div, + maxclock); + regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel, + ®s->divMCLK); xres = var->xres; hfront = var->right_margin; @@ -948,7 +887,8 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5; regs->HorizDispEnd = xres / 8 - 1; regs->HorizBlankStart = xres / 8; - regs->HorizBlankEnd = regs->HorizTotal + 5; /* does not count with "-5" */ + /* does not count with "-5" */ + regs->HorizBlankEnd = regs->HorizTotal + 5; regs->HorizSyncStart = (xres + hfront) / 8 + 1; regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1; @@ -976,23 +916,23 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, return 0; } - -static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int div) +static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val, + int div) { - assert (cinfo != NULL); + assert(cinfo != NULL); if (div == 2) { /* VCLK = MCLK/2 */ - unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E); - vga_wseq (cinfo->regbase, CL_SEQR1E, old | 0x1); - vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); + unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E); + vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1); + vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); } else if (div == 1) { /* VCLK = MCLK */ - unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E); - vga_wseq (cinfo->regbase, CL_SEQR1E, old & ~0x1); - vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); + unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E); + vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1); + vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); } else { - vga_wseq (cinfo->regbase, CL_SEQR1F, val & 0x3f); + vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f); } } @@ -1001,7 +941,7 @@ static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int d actually writes the values for a new video mode into the hardware, **************************************************************************/ -static int cirrusfb_set_par_foo (struct fb_info *info) +static int cirrusfb_set_par_foo(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; struct fb_var_screeninfo *var = &info->var; @@ -1011,15 +951,15 @@ static int cirrusfb_set_par_foo (struct fb_info *info) int offset = 0, err; const struct cirrusfb_board_info_rec *bi; - DPRINTK ("ENTER\n"); - DPRINTK ("Requested mode: %dx%dx%d\n", + DPRINTK("ENTER\n"); + DPRINTK("Requested mode: %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel); - DPRINTK ("pixclock: %d\n", var->pixclock); + DPRINTK("pixclock: %d\n", var->pixclock); - init_vgachip (cinfo); + init_vgachip(info); err = cirrusfb_decode_var(var, ®s, info); - if(err) { + if (err) { /* should never happen */ DPRINTK("mode change aborted. invalid var.\n"); return -EINVAL; @@ -1027,34 +967,35 @@ static int cirrusfb_set_par_foo (struct fb_info *info) bi = &cirrusfb_board_info[cinfo->btype]; - /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ - vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ + vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ /* if debugging is enabled, all parameters get output before writing */ - DPRINTK ("CRT0: %ld\n", regs.HorizTotal); - vga_wcrt (regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal); + DPRINTK("CRT0: %ld\n", regs.HorizTotal); + vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal); - DPRINTK ("CRT1: %ld\n", regs.HorizDispEnd); - vga_wcrt (regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd); + DPRINTK("CRT1: %ld\n", regs.HorizDispEnd); + vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd); - DPRINTK ("CRT2: %ld\n", regs.HorizBlankStart); - vga_wcrt (regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart); + DPRINTK("CRT2: %ld\n", regs.HorizBlankStart); + vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart); - DPRINTK ("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); /* + 128: Compatible read */ - vga_wcrt (regbase, VGA_CRTC_H_BLANK_END, 128 + (regs.HorizBlankEnd % 32)); + /* + 128: Compatible read */ + DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); + vga_wcrt(regbase, VGA_CRTC_H_BLANK_END, + 128 + (regs.HorizBlankEnd % 32)); - DPRINTK ("CRT4: %ld\n", regs.HorizSyncStart); - vga_wcrt (regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart); + DPRINTK("CRT4: %ld\n", regs.HorizSyncStart); + vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart); tmp = regs.HorizSyncEnd % 32; if (regs.HorizBlankEnd & 32) tmp += 128; - DPRINTK ("CRT5: %d\n", tmp); - vga_wcrt (regbase, VGA_CRTC_H_SYNC_END, tmp); + DPRINTK("CRT5: %d\n", tmp); + vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp); - DPRINTK ("CRT6: %ld\n", regs.VertTotal & 0xff); - vga_wcrt (regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff)); + DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff)); tmp = 16; /* LineCompare bit #9 */ if (regs.VertTotal & 256) @@ -1071,34 +1012,34 @@ static int cirrusfb_set_par_foo (struct fb_info *info) tmp |= 64; if (regs.VertSyncStart & 512) tmp |= 128; - DPRINTK ("CRT7: %d\n", tmp); - vga_wcrt (regbase, VGA_CRTC_OVERFLOW, tmp); + DPRINTK("CRT7: %d\n", tmp); + vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp); tmp = 0x40; /* LineCompare bit #8 */ if (regs.VertBlankStart & 512) tmp |= 0x20; if (var->vmode & FB_VMODE_DOUBLE) tmp |= 0x80; - DPRINTK ("CRT9: %d\n", tmp); - vga_wcrt (regbase, VGA_CRTC_MAX_SCAN, tmp); + DPRINTK("CRT9: %d\n", tmp); + vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp); - DPRINTK ("CRT10: %ld\n", regs.VertSyncStart & 0xff); - vga_wcrt (regbase, VGA_CRTC_V_SYNC_START, (regs.VertSyncStart & 0xff)); + DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff); - DPRINTK ("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16); - vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, (regs.VertSyncEnd % 16 + 64 + 32)); + DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16); + vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32); - DPRINTK ("CRT12: %ld\n", regs.VertDispEnd & 0xff); - vga_wcrt (regbase, VGA_CRTC_V_DISP_END, (regs.VertDispEnd & 0xff)); + DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff); - DPRINTK ("CRT15: %ld\n", regs.VertBlankStart & 0xff); - vga_wcrt (regbase, VGA_CRTC_V_BLANK_START, (regs.VertBlankStart & 0xff)); + DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff); - DPRINTK ("CRT16: %ld\n", regs.VertBlankEnd & 0xff); - vga_wcrt (regbase, VGA_CRTC_V_BLANK_END, (regs.VertBlankEnd & 0xff)); + DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff); - DPRINTK ("CRT18: 0xff\n"); - vga_wcrt (regbase, VGA_CRTC_LINE_COMPARE, 0xff); + DPRINTK("CRT18: 0xff\n"); + vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff); tmp = 0; if (var->vmode & FB_VMODE_INTERLACED) @@ -1112,57 +1053,63 @@ static int cirrusfb_set_par_foo (struct fb_info *info) if (regs.VertBlankEnd & 512) tmp |= 128; - DPRINTK ("CRT1a: %d\n", tmp); - vga_wcrt (regbase, CL_CRT1A, tmp); + DPRINTK("CRT1a: %d\n", tmp); + vga_wcrt(regbase, CL_CRT1A, tmp); /* set VCLK0 */ /* hardware RefClock: 14.31818 MHz */ /* formula: VClk = (OSC * N) / (D * (1+P)) */ /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ - vga_wseq (regbase, CL_SEQRB, regs.nom); + vga_wseq(regbase, CL_SEQRB, regs.nom); tmp = regs.den << 1; if (regs.div != 0) tmp |= 1; + /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ if ((cinfo->btype == BT_SD64) || (cinfo->btype == BT_ALPINE) || (cinfo->btype == BT_GD5480)) - tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ + tmp |= 0x80; - DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp); - vga_wseq (regbase, CL_SEQR1B, tmp); + DPRINTK("CL_SEQR1B: %ld\n", (long) tmp); + vga_wseq(regbase, CL_SEQR1B, tmp); if (regs.VertRes >= 1024) /* 1280x1024 */ - vga_wcrt (regbase, VGA_CRTC_MODE, 0xc7); + vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7); else /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit * address wrap, no compat. */ - vga_wcrt (regbase, VGA_CRTC_MODE, 0xc3); + vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3); -/* HAEH? vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ +/* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); + * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ /* don't know if it would hurt to also program this if no interlaced */ /* mode is used, but I feel better this way.. :-) */ if (var->vmode & FB_VMODE_INTERLACED) - vga_wcrt (regbase, VGA_CRTC_REGS, regs.HorizTotal / 2); + vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2); else - vga_wcrt (regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ + vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ - vga_wseq (regbase, VGA_SEQ_CHARACTER_MAP, 0); + vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0); /* adjust horizontal/vertical sync type (low/high) */ - tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */ + /* enable display memory & CRTC I/O address for color mode */ + tmp = 0x03; if (var->sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x40; if (var->sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80; - WGen (cinfo, VGA_MIS_W, tmp); + WGen(cinfo, VGA_MIS_W, tmp); - vga_wcrt (regbase, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */ - vga_wcrt (regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */ - vga_wcrt (regbase, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */ + /* Screen A Preset Row-Scan register */ + vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0); + /* text cursor on and start line */ + vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0); + /* text cursor end line */ + vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31); /****************************************************** * @@ -1172,8 +1119,8 @@ static int cirrusfb_set_par_foo (struct fb_info *info) /* programming for different color depths */ if (var->bits_per_pixel == 1) { - DPRINTK ("cirrusfb: preparing for 1 bit deep display\n"); - vga_wgfx (regbase, VGA_GFX_MODE, 0); /* mode register */ + DPRINTK("cirrusfb: preparing for 1 bit deep display\n"); + vga_wgfx(regbase, VGA_GFX_MODE, 0); /* mode register */ /* SR07 */ switch (cinfo->btype) { @@ -1184,71 +1131,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info) case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: - DPRINTK (" (for GD54xx)\n"); - vga_wseq (regbase, CL_SEQR7, + DPRINTK(" (for GD54xx)\n"); + vga_wseq(regbase, CL_SEQR7, regs.multiplexing ? bi->sr07_1bpp_mux : bi->sr07_1bpp); break; case BT_LAGUNA: - DPRINTK (" (for GD546x)\n"); - vga_wseq (regbase, CL_SEQR7, - vga_rseq (regbase, CL_SEQR7) & ~0x01); + DPRINTK(" (for GD546x)\n"); + vga_wseq(regbase, CL_SEQR7, + vga_rseq(regbase, CL_SEQR7) & ~0x01); break; default: - printk (KERN_WARNING "cirrusfb: unknown Board\n"); + printk(KERN_WARNING "cirrusfb: unknown Board\n"); break; } /* Extended Sequencer Mode */ switch (cinfo->btype) { case BT_SD64: - /* setting the SEQRF on SD64 is not necessary (only during init) */ - DPRINTK ("(for SD64)\n"); - vga_wseq (regbase, CL_SEQR1F, 0x1a); /* MCLK select */ + /* setting the SEQRF on SD64 is not necessary + * (only during init) + */ + DPRINTK("(for SD64)\n"); + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x1a); break; case BT_PICCOLO: - DPRINTK ("(for Piccolo)\n"); -/* ### ueberall 0x22? */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */ - vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ + case BT_SPECTRUM: + DPRINTK("(for Piccolo/Spectrum)\n"); + /* ### ueberall 0x22? */ + /* ##vorher 1c MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x22); + /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ + vga_wseq(regbase, CL_SEQRF, 0xb0); break; case BT_PICASSO: - DPRINTK ("(for Picasso)\n"); - vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */ - vga_wseq (regbase, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */ - break; - - case BT_SPECTRUM: - DPRINTK ("(for Spectrum)\n"); -/* ### ueberall 0x22? */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */ - vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */ + DPRINTK("(for Picasso)\n"); + /* ##vorher 22 MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x22); + /* ## vorher d0 avoid FIFO underruns..? */ + vga_wseq(regbase, CL_SEQRF, 0xd0); break; case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: case BT_LAGUNA: - DPRINTK (" (for GD54xx)\n"); + DPRINTK(" (for GD54xx)\n"); /* do nothing */ break; default: - printk (KERN_WARNING "cirrusfb: unknown Board\n"); + printk(KERN_WARNING "cirrusfb: unknown Board\n"); break; } - WGen (cinfo, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */ + /* pixel mask: pass-through for first plane */ + WGen(cinfo, VGA_PEL_MSK, 0x01); if (regs.multiplexing) - WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */ + /* hidden dac reg: 1280x1024 */ + WHDR(cinfo, 0x4a); else - WHDR (cinfo, 0); /* hidden dac: nothing */ - vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */ - vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */ + /* hidden dac: nothing */ + WHDR(cinfo, 0); + /* memory mode: odd/even, ext. memory */ + vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06); + /* plane mask: only write to first plane */ + vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01); offset = var->xres_virtual / 16; } @@ -1259,7 +1212,7 @@ static int cirrusfb_set_par_foo (struct fb_info *info) */ else if (var->bits_per_pixel == 8) { - DPRINTK ("cirrusfb: preparing for 8 bit deep display\n"); + DPRINTK("cirrusfb: preparing for 8 bit deep display\n"); switch (cinfo->btype) { case BT_SD64: case BT_PICCOLO: @@ -1268,75 +1221,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info) case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: - DPRINTK (" (for GD54xx)\n"); - vga_wseq (regbase, CL_SEQR7, + DPRINTK(" (for GD54xx)\n"); + vga_wseq(regbase, CL_SEQR7, regs.multiplexing ? bi->sr07_8bpp_mux : bi->sr07_8bpp); break; case BT_LAGUNA: - DPRINTK (" (for GD546x)\n"); - vga_wseq (regbase, CL_SEQR7, - vga_rseq (regbase, CL_SEQR7) | 0x01); + DPRINTK(" (for GD546x)\n"); + vga_wseq(regbase, CL_SEQR7, + vga_rseq(regbase, CL_SEQR7) | 0x01); break; default: - printk (KERN_WARNING "cirrusfb: unknown Board\n"); + printk(KERN_WARNING "cirrusfb: unknown Board\n"); break; } switch (cinfo->btype) { case BT_SD64: - vga_wseq (regbase, CL_SEQR1F, 0x1d); /* MCLK select */ + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x1d); break; case BT_PICCOLO: - vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - break; - case BT_PICASSO: - vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - break; - case BT_SPECTRUM: - vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */ - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ + /* ### vorher 1c MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x22); + /* Fast Page-Mode writes */ + vga_wseq(regbase, CL_SEQRF, 0xb0); break; case BT_PICASSO4: #ifdef CONFIG_ZORRO - vga_wseq (regbase, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */ + /* ### INCOMPLETE!! */ + vga_wseq(regbase, CL_SEQRF, 0xb8); #endif -/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ +/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ break; case BT_ALPINE: - DPRINTK (" (for GD543x)\n"); - cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); + DPRINTK(" (for GD543x)\n"); + cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); /* We already set SRF and SR1F */ break; case BT_GD5480: case BT_LAGUNA: - DPRINTK (" (for GD54xx)\n"); + DPRINTK(" (for GD54xx)\n"); /* do nothing */ break; default: - printk (KERN_WARNING "cirrusfb: unknown Board\n"); + printk(KERN_WARNING "cirrusfb: unknown Board\n"); break; } - vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ - WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ + /* mode register: 256 color mode */ + vga_wgfx(regbase, VGA_GFX_MODE, 64); + /* pixel mask: pass-through all planes */ + WGen(cinfo, VGA_PEL_MSK, 0xff); if (regs.multiplexing) - WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */ + /* hidden dac reg: 1280x1024 */ + WHDR(cinfo, 0x4a); else - WHDR (cinfo, 0); /* hidden dac: nothing */ - vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ - vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ + /* hidden dac: nothing */ + WHDR(cinfo, 0); + /* memory mode: chain4, ext. memory */ + vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); + /* plane mask: enable writing to all 4 planes */ + vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); offset = var->xres_virtual / 8; } @@ -1347,72 +1302,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info) */ else if (var->bits_per_pixel == 16) { - DPRINTK ("cirrusfb: preparing for 16 bit deep display\n"); + DPRINTK("cirrusfb: preparing for 16 bit deep display\n"); switch (cinfo->btype) { case BT_SD64: - vga_wseq (regbase, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */ - vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */ + /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq(regbase, CL_SEQR7, 0xf7); + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x1e); break; case BT_PICCOLO: - vga_wseq (regbase, CL_SEQR7, 0x87); - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + case BT_SPECTRUM: + vga_wseq(regbase, CL_SEQR7, 0x87); + /* Fast Page-Mode writes */ + vga_wseq(regbase, CL_SEQRF, 0xb0); + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO: - vga_wseq (regbase, CL_SEQR7, 0x27); - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ - break; - - case BT_SPECTRUM: - vga_wseq (regbase, CL_SEQR7, 0x87); - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + vga_wseq(regbase, CL_SEQR7, 0x27); + /* Fast Page-Mode writes */ + vga_wseq(regbase, CL_SEQRF, 0xb0); + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO4: - vga_wseq (regbase, CL_SEQR7, 0x27); -/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ + vga_wseq(regbase, CL_SEQR7, 0x27); +/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ break; case BT_ALPINE: - DPRINTK (" (for GD543x)\n"); + DPRINTK(" (for GD543x)\n"); if (regs.HorizRes >= 1024) - vga_wseq (regbase, CL_SEQR7, 0xa7); + vga_wseq(regbase, CL_SEQR7, 0xa7); else - vga_wseq (regbase, CL_SEQR7, 0xa3); - cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); + vga_wseq(regbase, CL_SEQR7, 0xa3); + cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); break; case BT_GD5480: - DPRINTK (" (for GD5480)\n"); - vga_wseq (regbase, CL_SEQR7, 0x17); + DPRINTK(" (for GD5480)\n"); + vga_wseq(regbase, CL_SEQR7, 0x17); /* We already set SRF and SR1F */ break; case BT_LAGUNA: - DPRINTK (" (for GD546x)\n"); - vga_wseq (regbase, CL_SEQR7, - vga_rseq (regbase, CL_SEQR7) & ~0x01); + DPRINTK(" (for GD546x)\n"); + vga_wseq(regbase, CL_SEQR7, + vga_rseq(regbase, CL_SEQR7) & ~0x01); break; default: - printk (KERN_WARNING "CIRRUSFB: unknown Board\n"); + printk(KERN_WARNING "CIRRUSFB: unknown Board\n"); break; } - vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ - WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ + /* mode register: 256 color mode */ + vga_wgfx(regbase, VGA_GFX_MODE, 64); + /* pixel mask: pass-through all planes */ + WGen(cinfo, VGA_PEL_MSK, 0xff); #ifdef CONFIG_PCI - WHDR (cinfo, 0xc0); /* Copy Xbh */ + WHDR(cinfo, 0xc0); /* Copy Xbh */ #elif defined(CONFIG_ZORRO) /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ - WHDR (cinfo, 0xa0); /* hidden dac reg: nothing special */ + WHDR(cinfo, 0xa0); /* hidden dac reg: nothing special */ #endif - vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ - vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ + /* memory mode: chain4, ext. memory */ + vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); + /* plane mask: enable writing to all 4 planes */ + vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); offset = var->xres_virtual / 4; } @@ -1423,64 +1383,70 @@ static int cirrusfb_set_par_foo (struct fb_info *info) */ else if (var->bits_per_pixel == 32) { - DPRINTK ("cirrusfb: preparing for 24/32 bit deep display\n"); + DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n"); switch (cinfo->btype) { case BT_SD64: - vga_wseq (regbase, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */ - vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */ + /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq(regbase, CL_SEQR7, 0xf9); + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x1e); break; case BT_PICCOLO: - vga_wseq (regbase, CL_SEQR7, 0x85); - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + case BT_SPECTRUM: + vga_wseq(regbase, CL_SEQR7, 0x85); + /* Fast Page-Mode writes */ + vga_wseq(regbase, CL_SEQRF, 0xb0); + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO: - vga_wseq (regbase, CL_SEQR7, 0x25); - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ - break; - - case BT_SPECTRUM: - vga_wseq (regbase, CL_SEQR7, 0x85); - vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */ - vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */ + vga_wseq(regbase, CL_SEQR7, 0x25); + /* Fast Page-Mode writes */ + vga_wseq(regbase, CL_SEQRF, 0xb0); + /* MCLK select */ + vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO4: - vga_wseq (regbase, CL_SEQR7, 0x25); -/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */ + vga_wseq(regbase, CL_SEQR7, 0x25); +/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ break; case BT_ALPINE: - DPRINTK (" (for GD543x)\n"); - vga_wseq (regbase, CL_SEQR7, 0xa9); - cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK); + DPRINTK(" (for GD543x)\n"); + vga_wseq(regbase, CL_SEQR7, 0xa9); + cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); break; case BT_GD5480: - DPRINTK (" (for GD5480)\n"); - vga_wseq (regbase, CL_SEQR7, 0x19); + DPRINTK(" (for GD5480)\n"); + vga_wseq(regbase, CL_SEQR7, 0x19); /* We already set SRF and SR1F */ break; case BT_LAGUNA: - DPRINTK (" (for GD546x)\n"); - vga_wseq (regbase, CL_SEQR7, - vga_rseq (regbase, CL_SEQR7) & ~0x01); + DPRINTK(" (for GD546x)\n"); + vga_wseq(regbase, CL_SEQR7, + vga_rseq(regbase, CL_SEQR7) & ~0x01); break; default: - printk (KERN_WARNING "cirrusfb: unknown Board\n"); + printk(KERN_WARNING "cirrusfb: unknown Board\n"); break; } - vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */ - WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ - WHDR (cinfo, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */ - vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ - vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ + /* mode register: 256 color mode */ + vga_wgfx(regbase, VGA_GFX_MODE, 64); + /* pixel mask: pass-through all planes */ + WGen(cinfo, VGA_PEL_MSK, 0xff); + /* hidden dac reg: 8-8-8 mode (24 or 32) */ + WHDR(cinfo, 0xc5); + /* memory mode: chain4, ext. memory */ + vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); + /* plane mask: enable writing to all 4 planes */ + vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); offset = var->xres_virtual / 4; } @@ -1490,48 +1456,67 @@ static int cirrusfb_set_par_foo (struct fb_info *info) * */ - else { - printk (KERN_ERR "cirrusfb: What's this?? requested color depth == %d.\n", + else + printk(KERN_ERR "cirrusfb: What's this?? " + " requested color depth == %d.\n", var->bits_per_pixel); - } - vga_wcrt (regbase, VGA_CRTC_OFFSET, offset & 0xff); + vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff); tmp = 0x22; if (offset & 0x100) tmp |= 0x10; /* offset overflow bit */ - vga_wcrt (regbase, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */ + /* screen start addr #16-18, fastpagemode cycles */ + vga_wcrt(regbase, CL_CRT1B, tmp); if (cinfo->btype == BT_SD64 || cinfo->btype == BT_PICASSO4 || cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) - vga_wcrt (regbase, CL_CRT1D, 0x00); /* screen start address bit 19 */ - - vga_wcrt (regbase, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */ - vga_wcrt (regbase, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */ - vga_wcrt (regbase, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */ - - vga_wattr (regbase, VGA_ATC_MODE, 1); /* controller mode */ - vga_wattr (regbase, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */ - vga_wattr (regbase, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */ - vga_wattr (regbase, CL_AR33, 0); /* pixel panning */ - vga_wattr (regbase, VGA_ATC_COLOR_PAGE, 0); /* color select */ + /* screen start address bit 19 */ + vga_wcrt(regbase, CL_CRT1D, 0x00); + + /* text cursor location high */ + vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0); + /* text cursor location low */ + vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0); + /* underline row scanline = at very bottom */ + vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0); + + /* controller mode */ + vga_wattr(regbase, VGA_ATC_MODE, 1); + /* overscan (border) color */ + vga_wattr(regbase, VGA_ATC_OVERSCAN, 0); + /* color plane enable */ + vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15); + /* pixel panning */ + vga_wattr(regbase, CL_AR33, 0); + /* color select */ + vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0); /* [ EGS: SetOffset(); ] */ /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */ - AttrOn (cinfo); - - vga_wgfx (regbase, VGA_GFX_SR_VALUE, 0); /* set/reset register */ - vga_wgfx (regbase, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */ - vga_wgfx (regbase, VGA_GFX_COMPARE_VALUE, 0); /* color compare */ - vga_wgfx (regbase, VGA_GFX_DATA_ROTATE, 0); /* data rotate */ - vga_wgfx (regbase, VGA_GFX_PLANE_READ, 0); /* read map select */ - vga_wgfx (regbase, VGA_GFX_MISC, 1); /* miscellaneous register */ - vga_wgfx (regbase, VGA_GFX_COMPARE_MASK, 15); /* color don't care */ - vga_wgfx (regbase, VGA_GFX_BIT_MASK, 255); /* bit mask */ - - vga_wseq (regbase, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */ + AttrOn(cinfo); + + /* set/reset register */ + vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0); + /* set/reset enable */ + vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0); + /* color compare */ + vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0); + /* data rotate */ + vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0); + /* read map select */ + vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0); + /* miscellaneous register */ + vga_wgfx(regbase, VGA_GFX_MISC, 1); + /* color don't care */ + vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15); + /* bit mask */ + vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255); + + /* graphics cursor attributes: nothing special */ + vga_wseq(regbase, CL_SEQR12, 0x0); /* finally, turn on everything - turn off "FullBandwidth" bit */ /* also, set "DotClock%2" bit where requested */ @@ -1542,36 +1527,33 @@ static int cirrusfb_set_par_foo (struct fb_info *info) tmp |= 0x08; */ - vga_wseq (regbase, VGA_SEQ_CLOCK_MODE, tmp); - DPRINTK ("CL_SEQR1: %d\n", tmp); + vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp); + DPRINTK("CL_SEQR1: %d\n", tmp); cinfo->currentmode = regs; - info->fix.type = regs.type; - info->fix.visual = regs.visual; - info->fix.line_length = regs.line_length; /* pan to requested offset */ - cirrusfb_pan_display (var, info); + cirrusfb_pan_display(var, info); #ifdef CIRRUSFB_DEBUG - cirrusfb_dump (); + cirrusfb_dump(); #endif - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); return 0; } /* for some reason incomprehensible to me, cirrusfb requires that you write * the registers twice for the settings to take..grr. -dte */ -static int cirrusfb_set_par (struct fb_info *info) +static int cirrusfb_set_par(struct fb_info *info) { - cirrusfb_set_par_foo (info); - return cirrusfb_set_par_foo (info); + cirrusfb_set_par_foo(info); + return cirrusfb_set_par_foo(info); } -static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) +static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; @@ -1584,34 +1566,18 @@ static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, green >>= (16 - info->var.green.length); blue >>= (16 - info->var.blue.length); - if (regno>=16) + if (regno >= 16) return 1; v = (red << info->var.red.offset) | (green << info->var.green.offset) | (blue << info->var.blue.offset); - switch (info->var.bits_per_pixel) { - case 8: - cinfo->pseudo_palette[regno] = v; - break; - case 16: - cinfo->pseudo_palette[regno] = v; - break; - case 24: - case 32: - cinfo->pseudo_palette[regno] = v; - break; - } + cinfo->pseudo_palette[regno] = v; return 0; } - cinfo->palette[regno].red = red; - cinfo->palette[regno].green = green; - cinfo->palette[regno].blue = blue; - - if (info->var.bits_per_pixel == 8) { - WClut (cinfo, regno, red >> 10, green >> 10, blue >> 10); - } + if (info->var.bits_per_pixel == 8) + WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10); return 0; @@ -1622,8 +1588,8 @@ static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, performs display panning - provided hardware permits this **************************************************************************/ -static int cirrusfb_pan_display (struct fb_var_screeninfo *var, - struct fb_info *info) +static int cirrusfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { int xoffset = 0; int yoffset = 0; @@ -1631,8 +1597,8 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, unsigned char tmp = 0, tmp2 = 0, xpix; struct cirrusfb_info *cinfo = info->par; - DPRINTK ("ENTER\n"); - DPRINTK ("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset); + DPRINTK("ENTER\n"); + DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset); /* no range checks for xoffset and yoffset, */ /* as fb_pan_display has already done this */ @@ -1645,7 +1611,7 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, xoffset = var->xoffset * info->var.bits_per_pixel / 8; yoffset = var->yoffset; - base = yoffset * cinfo->currentmode.line_length + xoffset; + base = yoffset * info->fix.line_length + xoffset; if (info->var.bits_per_pixel == 1) { /* base is already correct */ @@ -1655,11 +1621,13 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, xpix = (unsigned char) ((xoffset % 4) * 2); } - cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */ + cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */ /* lower 8 + 8 bits of screen start address */ - vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, (unsigned char) (base & 0xff)); - vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, (unsigned char) (base >> 8)); + vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, + (unsigned char) (base & 0xff)); + vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, + (unsigned char) (base >> 8)); /* construct bits 16, 17 and 18 of screen start address */ if (base & 0x10000) @@ -1669,50 +1637,49 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var, if (base & 0x40000) tmp |= 0x08; - tmp2 = (vga_rcrt (cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */ - vga_wcrt (cinfo->regbase, CL_CRT1B, tmp2); + /* 0xf2 is %11110010, exclude tmp bits */ + tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; + vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2); /* construct bit 19 of screen start address */ - if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) { - tmp2 = 0; - if (base & 0x80000) - tmp2 = 0x80; - vga_wcrt (cinfo->regbase, CL_CRT1D, tmp2); - } + if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) + vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80); - /* write pixel panning value to AR33; this does not quite work in 8bpp */ - /* ### Piccolo..? Will this work? */ + /* write pixel panning value to AR33; this does not quite work in 8bpp + * + * ### Piccolo..? Will this work? + */ if (info->var.bits_per_pixel == 1) - vga_wattr (cinfo->regbase, CL_AR33, xpix); + vga_wattr(cinfo->regbase, CL_AR33, xpix); - cirrusfb_WaitBLT (cinfo->regbase); + cirrusfb_WaitBLT(cinfo->regbase); - DPRINTK ("EXIT\n"); - return (0); + DPRINTK("EXIT\n"); + return 0; } - -static int cirrusfb_blank (int blank_mode, struct fb_info *info) +static int cirrusfb_blank(int blank_mode, struct fb_info *info) { /* - * Blank the screen if blank_mode != 0, else unblank. If blank == NULL - * then the caller blanks by setting the CLUT (Color Look Up Table) to all - * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due - * to e.g. a video mode which doesn't support it. 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 + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) + * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking + * failed due to e.g. a video mode which doesn't support it. + * 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 */ unsigned char val; struct cirrusfb_info *cinfo = info->par; int current_mode = cinfo->blank_mode; - DPRINTK ("ENTER, blank mode = %d\n", blank_mode); + DPRINTK("ENTER, blank mode = %d\n", blank_mode); if (info->state != FBINFO_STATE_RUNNING || current_mode == blank_mode) { - DPRINTK ("EXIT, returning 0\n"); + DPRINTK("EXIT, returning 0\n"); return 0; } @@ -1720,17 +1687,19 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info) if (current_mode == FB_BLANK_NORMAL || current_mode == FB_BLANK_UNBLANK) { /* unblank the screen */ - val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE); - vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */ + val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); + /* clear "FullBandwidth" bit */ + vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* and undo VESA suspend trickery */ - vga_wgfx (cinfo->regbase, CL_GRE, 0x00); + vga_wgfx(cinfo->regbase, CL_GRE, 0x00); } /* set new */ - if(blank_mode > FB_BLANK_NORMAL) { + if (blank_mode > FB_BLANK_NORMAL) { /* blank the screen */ - val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE); - vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */ + val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); + /* set "FullBandwidth" bit */ + vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); } switch (blank_mode) { @@ -1738,21 +1707,21 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info) case FB_BLANK_NORMAL: break; case FB_BLANK_VSYNC_SUSPEND: - vga_wgfx (cinfo->regbase, CL_GRE, 0x04); + vga_wgfx(cinfo->regbase, CL_GRE, 0x04); break; case FB_BLANK_HSYNC_SUSPEND: - vga_wgfx (cinfo->regbase, CL_GRE, 0x02); + vga_wgfx(cinfo->regbase, CL_GRE, 0x02); break; case FB_BLANK_POWERDOWN: - vga_wgfx (cinfo->regbase, CL_GRE, 0x06); + vga_wgfx(cinfo->regbase, CL_GRE, 0x06); break; default: - DPRINTK ("EXIT, returning 1\n"); + DPRINTK("EXIT, returning 1\n"); return 1; } cinfo->blank_mode = blank_mode; - DPRINTK ("EXIT, returning 0\n"); + DPRINTK("EXIT, returning 0\n"); /* Let fbcon do a soft blank for us */ return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; @@ -1761,45 +1730,51 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info) /****************************************************************************/ /**** BEGIN Internal Routines ***********************************************/ -static void init_vgachip (struct cirrusfb_info *cinfo) +static void init_vgachip(struct fb_info *info) { + struct cirrusfb_info *cinfo = info->par; const struct cirrusfb_board_info_rec *bi; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); - assert (cinfo != NULL); + assert(cinfo != NULL); bi = &cirrusfb_board_info[cinfo->btype]; /* reset board globally */ switch (cinfo->btype) { case BT_PICCOLO: - WSFR (cinfo, 0x01); - udelay (500); - WSFR (cinfo, 0x51); - udelay (500); + WSFR(cinfo, 0x01); + udelay(500); + WSFR(cinfo, 0x51); + udelay(500); break; case BT_PICASSO: - WSFR2 (cinfo, 0xff); - udelay (500); + WSFR2(cinfo, 0xff); + udelay(500); break; case BT_SD64: case BT_SPECTRUM: - WSFR (cinfo, 0x1f); - udelay (500); - WSFR (cinfo, 0x4f); - udelay (500); + WSFR(cinfo, 0x1f); + udelay(500); + WSFR(cinfo, 0x4f); + udelay(500); break; case BT_PICASSO4: - vga_wcrt (cinfo->regbase, CL_CRT51, 0x00); /* disable flickerfixer */ - mdelay (100); - vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */ - vga_wgfx (cinfo->regbase, CL_GR33, 0x00); /* put blitter into 542x compat */ - vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* mode */ + /* disable flickerfixer */ + vga_wcrt(cinfo->regbase, CL_CRT51, 0x00); + mdelay(100); + /* from Klaus' NetBSD driver: */ + vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); + /* put blitter into 542x compat */ + vga_wgfx(cinfo->regbase, CL_GR33, 0x00); + /* mode */ + vga_wgfx(cinfo->regbase, CL_GR31, 0x00); break; case BT_GD5480: - vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */ + /* from Klaus' NetBSD driver: */ + vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); break; case BT_ALPINE: @@ -1807,153 +1782,208 @@ static void init_vgachip (struct cirrusfb_info *cinfo) break; default: - printk (KERN_ERR "cirrusfb: Warning: Unknown board type\n"); + printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n"); break; } - assert (cinfo->size > 0); /* make sure RAM size set by this point */ + /* make sure RAM size set by this point */ + assert(info->screen_size > 0); /* the P4 is not fully initialized here; I rely on it having been */ /* inited under AmigaOS already, which seems to work just fine */ - /* (Klaus advised to do it this way) */ + /* (Klaus advised to do it this way) */ if (cinfo->btype != BT_PICASSO4) { - WGen (cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */ - WGen (cinfo, CL_POS102, 0x01); - WGen (cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */ + WGen(cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */ + WGen(cinfo, CL_POS102, 0x01); + WGen(cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */ if (cinfo->btype != BT_SD64) - WGen (cinfo, CL_VSSM2, 0x01); + WGen(cinfo, CL_VSSM2, 0x01); - vga_wseq (cinfo->regbase, CL_SEQR0, 0x03); /* reset sequencer logic */ + /* reset sequencer logic */ + vga_wseq(cinfo->regbase, CL_SEQR0, 0x03); - vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */ - WGen (cinfo, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */ + /* FullBandwidth (video off) and 8/9 dot clock */ + vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); + /* polarity (-/-), disable access to display memory, + * VGA_CRTC_START_HI base address: color + */ + WGen(cinfo, VGA_MIS_W, 0xc1); -/* vga_wgfx (cinfo->regbase, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */ - vga_wseq (cinfo->regbase, CL_SEQR6, 0x12); /* unlock all extension registers */ + /* "magic cookie" - doesn't make any sense to me.. */ +/* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */ + /* unlock all extension registers */ + vga_wseq(cinfo->regbase, CL_SEQR6, 0x12); - vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* reset blitter */ + /* reset blitter */ + vga_wgfx(cinfo->regbase, CL_GR31, 0x04); switch (cinfo->btype) { case BT_GD5480: - vga_wseq (cinfo->regbase, CL_SEQRF, 0x98); + vga_wseq(cinfo->regbase, CL_SEQRF, 0x98); break; case BT_ALPINE: break; case BT_SD64: - vga_wseq (cinfo->regbase, CL_SEQRF, 0xb8); + vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8); break; default: - vga_wseq (cinfo->regbase, CL_SEQR16, 0x0f); - vga_wseq (cinfo->regbase, CL_SEQRF, 0xb0); + vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f); + vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0); break; } } - vga_wseq (cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */ - vga_wseq (cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */ - vga_wseq (cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */ + /* plane mask: nothing */ + vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); + /* character map select: doesn't even matter in gx mode */ + vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); + /* memory mode: chain-4, no odd/even, ext. memory */ + vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); /* controller-internal base address of video memory */ if (bi->init_sr07) - vga_wseq (cinfo->regbase, CL_SEQR7, bi->sr07); + vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07); - /* vga_wseq (cinfo->regbase, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */ + /* vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */ + /* EEPROM control: shouldn't be necessary to write to this at all.. */ - vga_wseq (cinfo->regbase, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */ - vga_wseq (cinfo->regbase, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */ - vga_wseq (cinfo->regbase, CL_SEQR12, 0x00); /* graphics cursor attributes */ - vga_wseq (cinfo->regbase, CL_SEQR13, 0x00); /* graphics cursor pattern address */ + /* graphics cursor X position (incomplete; position gives rem. 3 bits */ + vga_wseq(cinfo->regbase, CL_SEQR10, 0x00); + /* graphics cursor Y position (..."... ) */ + vga_wseq(cinfo->regbase, CL_SEQR11, 0x00); + /* graphics cursor attributes */ + vga_wseq(cinfo->regbase, CL_SEQR12, 0x00); + /* graphics cursor pattern address */ + vga_wseq(cinfo->regbase, CL_SEQR13, 0x00); /* writing these on a P4 might give problems.. */ if (cinfo->btype != BT_PICASSO4) { - vga_wseq (cinfo->regbase, CL_SEQR17, 0x00); /* configuration readback and ext. color */ - vga_wseq (cinfo->regbase, CL_SEQR18, 0x02); /* signature generator */ + /* configuration readback and ext. color */ + vga_wseq(cinfo->regbase, CL_SEQR17, 0x00); + /* signature generator */ + vga_wseq(cinfo->regbase, CL_SEQR18, 0x02); } /* MCLK select etc. */ if (bi->init_sr1f) - vga_wseq (cinfo->regbase, CL_SEQR1F, bi->sr1f); - - vga_wcrt (cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */ - vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */ - vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */ - vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */ - vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */ - vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */ - vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */ - - vga_wcrt (cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */ - vga_wcrt (cinfo->regbase, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */ - vga_wcrt (cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */ + vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f); + + /* Screen A preset row scan: none */ + vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); + /* Text cursor start: disable text cursor */ + vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); + /* Text cursor end: - */ + vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); + /* Screen start address high: 0 */ + vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00); + /* Screen start address low: 0 */ + vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00); + /* text cursor location high: 0 */ + vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); + /* text cursor location low: 0 */ + vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); + + /* Underline Row scanline: - */ + vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); + /* mode control: timing enable, byte mode, no compat modes */ + vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3); + /* Line Compare: not needed */ + vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* ### add 0x40 for text modes with > 30 MHz pixclock */ - vga_wcrt (cinfo->regbase, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */ - - vga_wgfx (cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */ - vga_wgfx (cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */ - vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */ - vga_wgfx (cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */ - vga_wgfx (cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */ - vga_wgfx (cinfo->regbase, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */ - vga_wgfx (cinfo->regbase, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */ - vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */ - vga_wgfx (cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */ + /* ext. display controls: ext.adr. wrap */ + vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02); + + /* Set/Reset registes: - */ + vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); + /* Set/Reset enable: - */ + vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); + /* Color Compare: - */ + vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); + /* Data Rotate: - */ + vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); + /* Read Map Select: - */ + vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); + /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */ + vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00); + /* Miscellaneous: memory map base address, graphics mode */ + vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01); + /* Color Don't care: involve all planes */ + vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); + /* Bit Mask: no mask at all */ + vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); if (cinfo->btype == BT_ALPINE) - vga_wgfx (cinfo->regbase, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */ + /* (5434 can't have bit 3 set for bitblt) */ + vga_wgfx(cinfo->regbase, CL_GRB, 0x20); else - vga_wgfx (cinfo->regbase, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */ - - vga_wgfx (cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */ - vga_wgfx (cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */ - vga_wgfx (cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */ - /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); *//* Background color byte 1: - */ -/* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */ - - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */ - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE1, 0x01); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE2, 0x02); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE3, 0x03); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE4, 0x04); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE5, 0x05); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE6, 0x06); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE7, 0x07); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE8, 0x08); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTE9, 0x09); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTEA, 0x0a); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTEB, 0x0b); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTEC, 0x0c); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTED, 0x0d); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTEE, 0x0e); - vga_wattr (cinfo->regbase, VGA_ATC_PALETTEF, 0x0f); - - vga_wattr (cinfo->regbase, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */ - vga_wattr (cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */ - vga_wattr (cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */ -/* ### vga_wattr (cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */ - vga_wattr (cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */ - - WGen (cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ + /* Graphics controller mode extensions: finer granularity, + * 8byte data latches + */ + vga_wgfx(cinfo->regbase, CL_GRB, 0x28); + + vga_wgfx(cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */ + vga_wgfx(cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */ + vga_wgfx(cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */ + /* Background color byte 1: - */ + /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */ + /* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */ + + /* Attribute Controller palette registers: "identity mapping" */ + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e); + vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f); + + /* Attribute Controller mode: graphics mode */ + vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01); + /* Overscan color reg.: reg. 0 */ + vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); + /* Color Plane enable: Enable all 4 planes */ + vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); +/* ### vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */ + /* Color Select: - */ + vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); + + WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480) - WGen (cinfo, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */ + /* polarity (-/-), enable display mem, + * VGA_CRTC_START_HI i/o base = color + */ + WGen(cinfo, VGA_MIS_W, 0xc3); - vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */ - vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* - " - : "end-of-reset" */ + /* BLT Start/status: Blitter reset */ + vga_wgfx(cinfo->regbase, CL_GR31, 0x04); + /* - " - : "end-of-reset" */ + vga_wgfx(cinfo->regbase, CL_GR31, 0x00); /* misc... */ - WHDR (cinfo, 0); /* Hidden DAC register: - */ + WHDR(cinfo, 0); /* Hidden DAC register: - */ - printk (KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", cinfo->size); - DPRINTK ("EXIT\n"); + printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", + info->screen_size); + DPRINTK("EXIT\n"); return; } -static void switch_monitor (struct cirrusfb_info *cinfo, int on) +static void switch_monitor(struct cirrusfb_info *cinfo, int on) { #ifdef CONFIG_ZORRO /* only works on Zorro boards */ static int IsOn = 0; /* XXX not ok for multiple boards */ - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); if (cinfo->btype == BT_PICASSO4) return; /* nothing to switch */ @@ -1963,77 +1993,56 @@ static void switch_monitor (struct cirrusfb_info *cinfo, int on) return; /* nothing to switch */ if (cinfo->btype == BT_PICASSO) { if ((on && !IsOn) || (!on && IsOn)) - WSFR (cinfo, 0xff); + WSFR(cinfo, 0xff); - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); return; } if (on) { switch (cinfo->btype) { case BT_SD64: - WSFR (cinfo, cinfo->SFR | 0x21); + WSFR(cinfo, cinfo->SFR | 0x21); break; case BT_PICCOLO: - WSFR (cinfo, cinfo->SFR | 0x28); + WSFR(cinfo, cinfo->SFR | 0x28); break; case BT_SPECTRUM: - WSFR (cinfo, 0x6f); + WSFR(cinfo, 0x6f); break; default: /* do nothing */ break; } } else { switch (cinfo->btype) { case BT_SD64: - WSFR (cinfo, cinfo->SFR & 0xde); + WSFR(cinfo, cinfo->SFR & 0xde); break; case BT_PICCOLO: - WSFR (cinfo, cinfo->SFR & 0xd7); + WSFR(cinfo, cinfo->SFR & 0xd7); break; case BT_SPECTRUM: - WSFR (cinfo, 0x4f); + WSFR(cinfo, 0x4f); break; default: /* do nothing */ break; } } - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); #endif /* CONFIG_ZORRO */ } - /******************************************/ /* Linux 2.6-style accelerated functions */ /******************************************/ -static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo, - const struct fb_fillrect *region) -{ - int m; /* bytes per pixel */ - u32 color = (cinfo->info->fix.visual == FB_VISUAL_TRUECOLOR) ? - cinfo->pseudo_palette[region->color] : region->color; - - if(cinfo->info->var.bits_per_pixel == 1) { - cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel, - region->dx / 8, region->dy, - region->width / 8, region->height, - color, - cinfo->currentmode.line_length); - } else { - m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8; - cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel, - region->dx * m, region->dy, - region->width * m, region->height, - color, - cinfo->currentmode.line_length); - } - return; -} - -static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region) +static void cirrusfb_fillrect(struct fb_info *info, + const struct fb_fillrect *region) { - struct cirrusfb_info *cinfo = info->par; struct fb_fillrect modded; int vxres, vyres; + struct cirrusfb_info *cinfo = info->par; + int m = info->var.bits_per_pixel; + u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? + cinfo->pseudo_palette[region->color] : region->color; if (info->state != FBINFO_STATE_RUNNING) return; @@ -2047,49 +2056,30 @@ static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *r memcpy(&modded, region, sizeof(struct fb_fillrect)); - if(!modded.width || !modded.height || + if (!modded.width || !modded.height || modded.dx >= vxres || modded.dy >= vyres) return; - if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; - if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; - - cirrusfb_prim_fillrect(cinfo, &modded); -} - -static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo, - const struct fb_copyarea *area) -{ - int m; /* bytes per pixel */ - if(cinfo->info->var.bits_per_pixel == 1) { - cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel, - area->sx / 8, area->sy, - area->dx / 8, area->dy, - area->width / 8, area->height, - cinfo->currentmode.line_length); - } else { - m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8; - cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel, - area->sx * m, area->sy, - area->dx * m, area->dy, - area->width * m, area->height, - cinfo->currentmode.line_length); - } - return; + if (modded.dx + modded.width > vxres) + modded.width = vxres - modded.dx; + if (modded.dy + modded.height > vyres) + modded.height = vyres - modded.dy; + + cirrusfb_RectFill(cinfo->regbase, + info->var.bits_per_pixel, + (region->dx * m) / 8, region->dy, + (region->width * m) / 8, region->height, + color, + info->fix.line_length); } - -static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +static void cirrusfb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) { - struct cirrusfb_info *cinfo = info->par; struct fb_copyarea modded; u32 vxres, vyres; - modded.sx = area->sx; - modded.sy = area->sy; - modded.dx = area->dx; - modded.dy = area->dy; - modded.width = area->width; - modded.height = area->height; + struct cirrusfb_info *cinfo = info->par; + int m = info->var.bits_per_pixel; if (info->state != FBINFO_STATE_RUNNING) return; @@ -2100,90 +2090,106 @@ static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *ar vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; + memcpy(&modded, area, sizeof(struct fb_copyarea)); - if(!modded.width || !modded.height || + if (!modded.width || !modded.height || modded.sx >= vxres || modded.sy >= vyres || modded.dx >= vxres || modded.dy >= vyres) return; - if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx; - if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; - if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy; - if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; + if (modded.sx + modded.width > vxres) + modded.width = vxres - modded.sx; + if (modded.dx + modded.width > vxres) + modded.width = vxres - modded.dx; + if (modded.sy + modded.height > vyres) + modded.height = vyres - modded.sy; + if (modded.dy + modded.height > vyres) + modded.height = vyres - modded.dy; + + cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel, + (area->sx * m) / 8, area->sy, + (area->dx * m) / 8, area->dy, + (area->width * m) / 8, area->height, + info->fix.line_length); - cirrusfb_prim_copyarea(cinfo, &modded); } -static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image) +static void cirrusfb_imageblit(struct fb_info *info, + const struct fb_image *image) { struct cirrusfb_info *cinfo = info->par; - cirrusfb_WaitBLT(cinfo->regbase); + cirrusfb_WaitBLT(cinfo->regbase); cfb_imageblit(info, image); } - #ifdef CONFIG_PPC_PREP #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000) #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) -static void get_prep_addrs (unsigned long *display, unsigned long *registers) +static void get_prep_addrs(unsigned long *display, unsigned long *registers) { - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); *display = PREP_VIDEO_BASE; *registers = (unsigned long) PREP_IO_BASE; - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } #endif /* CONFIG_PPC_PREP */ - #ifdef CONFIG_PCI -static int release_io_ports = 0; +static int release_io_ports; /* Pulled the logic from XFree86 Cirrus driver to get the memory size, * based on the DRAM bandwidth bit and DRAM bank switching bit. This * works with 1MB, 2MB and 4MB configurations (which the Motorola boards * seem to have. */ -static unsigned int cirrusfb_get_memsize (u8 __iomem *regbase) +static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase) { unsigned long mem; unsigned char SRF; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); - SRF = vga_rseq (regbase, CL_SEQRF); + SRF = vga_rseq(regbase, CL_SEQRF); switch ((SRF & 0x18)) { - case 0x08: mem = 512 * 1024; break; - case 0x10: mem = 1024 * 1024; break; - /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory - * on the 5430. */ - case 0x18: mem = 2048 * 1024; break; - default: printk ("CLgenfb: Unknown memory size!\n"); + case 0x08: + mem = 512 * 1024; + break; + case 0x10: + mem = 1024 * 1024; + break; + /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory + * on the 5430. + */ + case 0x18: + mem = 2048 * 1024; + break; + default: + printk(KERN_WARNING "CLgenfb: Unknown memory size!\n"); mem = 1024 * 1024; } - if (SRF & 0x80) { - /* If DRAM bank switching is enabled, there must be twice as much - * memory installed. (4MB on the 5434) */ + if (SRF & 0x80) + /* If DRAM bank switching is enabled, there must be twice as much + * memory installed. (4MB on the 5434) + */ mem *= 2; - } + /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */ - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); return mem; } - - -static void get_pci_addrs (const struct pci_dev *pdev, - unsigned long *display, unsigned long *registers) +static void get_pci_addrs(const struct pci_dev *pdev, + unsigned long *display, unsigned long *registers) { - assert (pdev != NULL); - assert (display != NULL); - assert (registers != NULL); + assert(pdev != NULL); + assert(display != NULL); + assert(registers != NULL); - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); *display = 0; *registers = 0; @@ -2198,51 +2204,47 @@ static void get_pci_addrs (const struct pci_dev *pdev, *registers = pci_resource_start(pdev, 1); } - assert (*display != 0); + assert(*display != 0); - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } - -static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo) +static void cirrusfb_pci_unmap(struct fb_info *info) { + struct cirrusfb_info *cinfo = info->par; struct pci_dev *pdev = cinfo->pdev; - iounmap(cinfo->fbmem); + iounmap(info->screen_base); #if 0 /* if system didn't claim this region, we would... */ release_mem_region(0xA0000, 65535); #endif if (release_io_ports) release_region(0x3C0, 32); pci_release_regions(pdev); - framebuffer_release(cinfo->info); } #endif /* CONFIG_PCI */ - #ifdef CONFIG_ZORRO -static void __devexit cirrusfb_zorro_unmap (struct cirrusfb_info *cinfo) +static void __devexit cirrusfb_zorro_unmap(struct cirrusfb_info *cinfo) { zorro_release_device(cinfo->zdev); if (cinfo->btype == BT_PICASSO4) { cinfo->regbase -= 0x600000; - iounmap ((void *)cinfo->regbase); - iounmap ((void *)cinfo->fbmem); + iounmap((void *)cinfo->regbase); + iounmap(info->screen_base); } else { if (zorro_resource_start(cinfo->zdev) > 0x01000000) - iounmap ((void *)cinfo->fbmem); + iounmap(info->screen_base); } - framebuffer_release(cinfo->info); } #endif /* CONFIG_ZORRO */ -static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) +static int cirrusfb_set_fbinfo(struct fb_info *info) { - struct fb_info *info = cinfo->info; + struct cirrusfb_info *cinfo = info->par; struct fb_var_screeninfo *var = &info->var; - info->par = cinfo; info->pseudo_palette = cinfo->pseudo_palette; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_XPAN @@ -2252,7 +2254,6 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) if (noaccel) info->flags |= FBINFO_HWACCEL_DISABLED; info->fbops = &cirrusfb_ops; - info->screen_base = cinfo->fbmem; if (cinfo->btype == BT_GD5480) { if (var->bits_per_pixel == 16) info->screen_base += 1 * MB_; @@ -2266,18 +2267,15 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) /* monochrome: only 1 memory plane */ /* 8 bit and above: Use whole memory area */ - info->fix.smem_start = cinfo->fbmem_phys; - info->fix.smem_len = (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size; - info->fix.type = cinfo->currentmode.type; + info->fix.smem_len = info->screen_size; + if (var->bits_per_pixel == 1) + info->fix.smem_len /= 4; info->fix.type_aux = 0; - info->fix.visual = cinfo->currentmode.visual; info->fix.xpanstep = 1; info->fix.ypanstep = 1; info->fix.ywrapstep = 0; - info->fix.line_length = cinfo->currentmode.line_length; /* FIXME: map region at 0xB8000 if available, fill in here */ - info->fix.mmio_start = cinfo->fbregs_phys; info->fix.mmio_len = 0; info->fix.accel = FB_ACCEL_NONE; @@ -2286,23 +2284,23 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo) return 0; } -static int cirrusfb_register(struct cirrusfb_info *cinfo) +static int cirrusfb_register(struct fb_info *info) { - struct fb_info *info; + struct cirrusfb_info *cinfo = info->par; int err; - cirrusfb_board_t btype; + enum cirrus_board btype; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); - printk (KERN_INFO "cirrusfb: Driver for Cirrus Logic based graphic boards, v" CIRRUSFB_VERSION "\n"); + printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based " + "graphic boards, v" CIRRUSFB_VERSION "\n"); - info = cinfo->info; btype = cinfo->btype; /* sanity checks */ - assert (btype != BT_NONE); + assert(btype != BT_NONE); - DPRINTK ("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem); + DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base); /* Make pretend we've set the var so our structures are in a "good" */ /* state, even though we haven't written the mode to the hw yet... */ @@ -2317,47 +2315,49 @@ static int cirrusfb_register(struct cirrusfb_info *cinfo) } /* set all the vital stuff */ - cirrusfb_set_fbinfo(cinfo); + cirrusfb_set_fbinfo(info); err = register_framebuffer(info); if (err < 0) { - printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err); + printk(KERN_ERR "cirrusfb: could not register " + "fb device; err = %d!\n", err); goto err_dealloc_cmap; } - DPRINTK ("EXIT, returning 0\n"); + DPRINTK("EXIT, returning 0\n"); return 0; err_dealloc_cmap: fb_dealloc_cmap(&info->cmap); err_unmap_cirrusfb: - cinfo->unmap(cinfo); + cinfo->unmap(info); + framebuffer_release(info); return err; } -static void __devexit cirrusfb_cleanup (struct fb_info *info) +static void __devexit cirrusfb_cleanup(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); - switch_monitor (cinfo, 0); + switch_monitor(cinfo, 0); - unregister_framebuffer (info); - fb_dealloc_cmap (&info->cmap); - printk ("Framebuffer unregistered\n"); - cinfo->unmap(cinfo); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + printk("Framebuffer unregistered\n"); + cinfo->unmap(info); + framebuffer_release(info); - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } - #ifdef CONFIG_PCI -static int cirrusfb_pci_register (struct pci_dev *pdev, +static int cirrusfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) { struct cirrusfb_info *cinfo; struct fb_info *info; - cirrusfb_board_t btype; + enum cirrus_board btype; unsigned long board_addr, board_size; int ret; @@ -2375,35 +2375,37 @@ static int cirrusfb_pci_register (struct pci_dev *pdev, } cinfo = info->par; - cinfo->info = info; cinfo->pdev = pdev; - cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data; + cinfo->btype = btype = (enum cirrus_board) ent->driver_data; - DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n", + DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n", pdev->resource[0].start, btype); - DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start); + DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start); - if(isPReP) { - pci_write_config_dword (pdev, PCI_BASE_ADDRESS_0, 0x00000000); + if (isPReP) { + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000); #ifdef CONFIG_PPC_PREP - get_prep_addrs (&board_addr, &cinfo->fbregs_phys); + get_prep_addrs(&board_addr, &info->fix.mmio_start); #endif - /* PReP dies if we ioremap the IO registers, but it works w/out... */ - cinfo->regbase = (char __iomem *) cinfo->fbregs_phys; + /* PReP dies if we ioremap the IO registers, but it works w/out... */ + cinfo->regbase = (char __iomem *) info->fix.mmio_start; } else { - DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n"); - get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys); - cinfo->regbase = NULL; /* FIXME: this forces VGA. alternatives? */ + DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n"); + get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start); + /* FIXME: this forces VGA. alternatives? */ + cinfo->regbase = NULL; } - DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys); + DPRINTK("Board address: 0x%lx, register address: 0x%lx\n", + board_addr, info->fix.mmio_start); board_size = (btype == BT_GD5480) ? - 32 * MB_ : cirrusfb_get_memsize (cinfo->regbase); + 32 * MB_ : cirrusfb_get_memsize(cinfo->regbase); ret = pci_request_regions(pdev, "cirrusfb"); - if (ret <0) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n", + if (ret < 0) { + printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " + "abort\n", board_addr); goto err_release_fb; } @@ -2419,23 +2421,24 @@ static int cirrusfb_pci_register (struct pci_dev *pdev, if (request_region(0x3C0, 32, "cirrusfb")) release_io_ports = 1; - cinfo->fbmem = ioremap(board_addr, board_size); - if (!cinfo->fbmem) { + info->screen_base = ioremap(board_addr, board_size); + if (!info->screen_base) { ret = -EIO; goto err_release_legacy; } - cinfo->fbmem_phys = board_addr; - cinfo->size = board_size; + info->fix.smem_start = board_addr; + info->screen_size = board_size; cinfo->unmap = cirrusfb_pci_unmap; - printk (" RAM (%lu kB) at 0xx%lx, ", cinfo->size / KB_, board_addr); - printk ("Cirrus Logic chipset on PCI bus\n"); + printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ", + info->screen_size >> 10, board_addr); + printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n"); pci_set_drvdata(pdev, info); - ret = cirrusfb_register(cinfo); + ret = cirrusfb_register(info); if (ret) - iounmap(cinfo->fbmem); + iounmap(info->screen_base); return ret; err_release_legacy: @@ -2453,14 +2456,14 @@ err_out: return ret; } -static void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev) +static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); - cirrusfb_cleanup (info); + cirrusfb_cleanup(info); - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } static struct pci_driver cirrusfb_pci_driver = { @@ -2477,14 +2480,13 @@ static struct pci_driver cirrusfb_pci_driver = { }; #endif /* CONFIG_PCI */ - #ifdef CONFIG_ZORRO static int cirrusfb_zorro_register(struct zorro_dev *z, const struct zorro_device_id *ent) { struct cirrusfb_info *cinfo; struct fb_info *info; - cirrusfb_board_t btype; + enum cirrus_board btype; struct zorro_dev *z2 = NULL; unsigned long board_addr, board_size, size; int ret; @@ -2498,83 +2500,86 @@ static int cirrusfb_zorro_register(struct zorro_dev *z, info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); if (!info) { - printk (KERN_ERR "cirrusfb: could not allocate memory\n"); + printk(KERN_ERR "cirrusfb: could not allocate memory\n"); ret = -ENOMEM; goto err_out; } cinfo = info->par; - cinfo->info = info; cinfo->btype = btype; - assert (z > 0); - assert (z2 >= 0); - assert (btype != BT_NONE); + assert(z > 0); + assert(z2 >= 0); + assert(btype != BT_NONE); cinfo->zdev = z; board_addr = zorro_resource_start(z); board_size = zorro_resource_len(z); - cinfo->size = size; + info->screen_size = size; if (!zorro_request_device(z, "cirrusfb")) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n", + printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " + "abort\n", board_addr); ret = -EBUSY; goto err_release_fb; } - printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); + printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); ret = -EIO; if (btype == BT_PICASSO4) { - printk (" REG at $%lx\n", board_addr + 0x600000); + printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000); /* To be precise, for the P4 this is not the */ /* begin of the board, but the begin of RAM. */ /* for P4, map in its address space in 2 chunks (### TEST! ) */ /* (note the ugly hardcoded 16M number) */ - cinfo->regbase = ioremap (board_addr, 16777216); + cinfo->regbase = ioremap(board_addr, 16777216); if (!cinfo->regbase) goto err_release_region; - DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase); + DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", + cinfo->regbase); cinfo->regbase += 0x600000; - cinfo->fbregs_phys = board_addr + 0x600000; + info->fix.mmio_start = board_addr + 0x600000; - cinfo->fbmem_phys = board_addr + 16777216; - cinfo->fbmem = ioremap (cinfo->fbmem_phys, 16777216); - if (!cinfo->fbmem) + info->fix.smem_start = board_addr + 16777216; + info->screen_base = ioremap(info->fix.smem_start, 16777216); + if (!info->screen_base) goto err_unmap_regbase; } else { - printk (" REG at $%lx\n", (unsigned long) z2->resource.start); + printk(KERN_INFO " REG at $%lx\n", + (unsigned long) z2->resource.start); - cinfo->fbmem_phys = board_addr; + info->fix.smem_start = board_addr; if (board_addr > 0x01000000) - cinfo->fbmem = ioremap (board_addr, board_size); + info->screen_base = ioremap(board_addr, board_size); else - cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr); - if (!cinfo->fbmem) + info->screen_base = (caddr_t) ZTWO_VADDR(board_addr); + if (!info->screen_base) goto err_release_region; /* set address for REG area of board */ - cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start); - cinfo->fbregs_phys = z2->resource.start; + cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); + info->fix.mmio_start = z2->resource.start; - DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase); + DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", + cinfo->regbase); } cinfo->unmap = cirrusfb_zorro_unmap; - printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); + printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); zorro_set_drvdata(z, info); ret = cirrusfb_register(cinfo); if (ret) { if (btype == BT_PICASSO4) { - iounmap(cinfo->fbmem); + iounmap(info->screen_base); iounmap(cinfo->regbase - 0x600000); } else if (board_addr > 0x01000000) - iounmap(cinfo->fbmem); + iounmap(info->screen_base); } return ret; @@ -2592,11 +2597,11 @@ err_out: void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) { struct fb_info *info = zorro_get_drvdata(z); - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); - cirrusfb_cleanup (info); + cirrusfb_cleanup(info); - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } static struct zorro_driver cirrusfb_zorro_driver = { @@ -2628,26 +2633,24 @@ static int __init cirrusfb_init(void) return error; } - - #ifndef MODULE static int __init cirrusfb_setup(char *options) { char *this_opt, s[32]; int i; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); if (!options || !*options) return 0; - while ((this_opt = strsep (&options, ",")) != NULL) { + while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; DPRINTK("cirrusfb_setup: option '%s'\n", this_opt); for (i = 0; i < NUM_TOTAL_MODES; i++) { - sprintf (s, "mode:%s", cirrusfb_predefined[i].name); - if (strcmp (this_opt, s) == 0) + sprintf(s, "mode:%s", cirrusfb_predefined[i].name); + if (strcmp(this_opt, s) == 0) cirrusfb_def_mode = i; } if (!strcmp(this_opt, "noaccel")) @@ -2657,7 +2660,6 @@ static int __init cirrusfb_setup(char *options) { } #endif - /* * Modularization */ @@ -2666,7 +2668,7 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>"); MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips"); MODULE_LICENSE("GPL"); -static void __exit cirrusfb_exit (void) +static void __exit cirrusfb_exit(void) { #ifdef CONFIG_PCI pci_unregister_driver(&cirrusfb_pci_driver); @@ -2682,66 +2684,67 @@ module_init(cirrusfb_init); module_exit(cirrusfb_exit); #endif - /**********************************************************************/ /* about the following functions - I have used the same names for the */ /* functions as Markus Wild did in his Retina driver for NetBSD as */ /* they just made sense for this purpose. Apart from that, I wrote */ -/* these functions myself. */ +/* these functions myself. */ /**********************************************************************/ /*** WGen() - write into one of the external/general registers ***/ -static void WGen (const struct cirrusfb_info *cinfo, +static void WGen(const struct cirrusfb_info *cinfo, int regnum, unsigned char val) { unsigned long regofs = 0; if (cinfo->btype == BT_PICASSO) { /* Picasso II specific hack */ -/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */ +/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || + regnum == CL_VSSM2) */ if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) regofs = 0xfff; } - vga_w (cinfo->regbase, regofs + regnum, val); + vga_w(cinfo->regbase, regofs + regnum, val); } /*** RGen() - read out one of the external/general registers ***/ -static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum) +static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum) { unsigned long regofs = 0; if (cinfo->btype == BT_PICASSO) { /* Picasso II specific hack */ -/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */ +/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || + regnum == CL_VSSM2) */ if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D) regofs = 0xfff; } - return vga_r (cinfo->regbase, regofs + regnum); + return vga_r(cinfo->regbase, regofs + regnum); } /*** AttrOn() - turn on VideoEnable for Attribute controller ***/ -static void AttrOn (const struct cirrusfb_info *cinfo) +static void AttrOn(const struct cirrusfb_info *cinfo) { - assert (cinfo != NULL); + assert(cinfo != NULL); - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); - if (vga_rcrt (cinfo->regbase, CL_CRT24) & 0x80) { + if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) { /* if we're just in "write value" mode, write back the */ /* same value as before to not modify anything */ - vga_w (cinfo->regbase, VGA_ATT_IW, - vga_r (cinfo->regbase, VGA_ATT_R)); + vga_w(cinfo->regbase, VGA_ATT_IW, + vga_r(cinfo->regbase, VGA_ATT_R)); } /* turn on video bit */ -/* vga_w (cinfo->regbase, VGA_ATT_IW, 0x20); */ - vga_w (cinfo->regbase, VGA_ATT_IW, 0x33); +/* vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */ + vga_w(cinfo->regbase, VGA_ATT_IW, 0x33); /* dummy write on Reg0 to be on "write index" mode next time */ - vga_w (cinfo->regbase, VGA_ATT_IW, 0x00); + vga_w(cinfo->regbase, VGA_ATT_IW, 0x00); - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } /*** WHDR() - write into the Hidden DAC register ***/ @@ -2750,119 +2753,115 @@ static void AttrOn (const struct cirrusfb_info *cinfo) * registers of their functional group) here is a specialized routine for * accessing the HDR */ -static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val) +static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val) { unsigned char dummy; if (cinfo->btype == BT_PICASSO) { /* Klaus' hint for correct access to HDR on some boards */ /* first write 0 to pixel mask (3c6) */ - WGen (cinfo, VGA_PEL_MSK, 0x00); - udelay (200); + WGen(cinfo, VGA_PEL_MSK, 0x00); + udelay(200); /* next read dummy from pixel address (3c8) */ - dummy = RGen (cinfo, VGA_PEL_IW); - udelay (200); + dummy = RGen(cinfo, VGA_PEL_IW); + udelay(200); } /* now do the usual stuff to access the HDR */ - dummy = RGen (cinfo, VGA_PEL_MSK); - udelay (200); - dummy = RGen (cinfo, VGA_PEL_MSK); - udelay (200); - dummy = RGen (cinfo, VGA_PEL_MSK); - udelay (200); - dummy = RGen (cinfo, VGA_PEL_MSK); - udelay (200); + dummy = RGen(cinfo, VGA_PEL_MSK); + udelay(200); + dummy = RGen(cinfo, VGA_PEL_MSK); + udelay(200); + dummy = RGen(cinfo, VGA_PEL_MSK); + udelay(200); + dummy = RGen(cinfo, VGA_PEL_MSK); + udelay(200); - WGen (cinfo, VGA_PEL_MSK, val); - udelay (200); + WGen(cinfo, VGA_PEL_MSK, val); + udelay(200); if (cinfo->btype == BT_PICASSO) { /* now first reset HDR access counter */ - dummy = RGen (cinfo, VGA_PEL_IW); - udelay (200); + dummy = RGen(cinfo, VGA_PEL_IW); + udelay(200); /* and at the end, restore the mask value */ /* ## is this mask always 0xff? */ - WGen (cinfo, VGA_PEL_MSK, 0xff); - udelay (200); + WGen(cinfo, VGA_PEL_MSK, 0xff); + udelay(200); } } - /*** WSFR() - write to the "special function register" (SFR) ***/ -static void WSFR (struct cirrusfb_info *cinfo, unsigned char val) +static void WSFR(struct cirrusfb_info *cinfo, unsigned char val) { #ifdef CONFIG_ZORRO - assert (cinfo->regbase != NULL); + assert(cinfo->regbase != NULL); cinfo->SFR = val; - z_writeb (val, cinfo->regbase + 0x8000); + z_writeb(val, cinfo->regbase + 0x8000); #endif } /* The Picasso has a second register for switching the monitor bit */ -static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val) +static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val) { #ifdef CONFIG_ZORRO /* writing an arbitrary value to this one causes the monitor switcher */ /* to flip to Amiga display */ - assert (cinfo->regbase != NULL); + assert(cinfo->regbase != NULL); cinfo->SFR = val; - z_writeb (val, cinfo->regbase + 0x9000); + z_writeb(val, cinfo->regbase + 0x9000); #endif } - /*** WClut - set CLUT entry (range: 0..63) ***/ -static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, +static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue) { unsigned int data = VGA_PEL_D; /* address write mode register is not translated.. */ - vga_w (cinfo->regbase, VGA_PEL_IW, regnum); + vga_w(cinfo->regbase, VGA_PEL_IW, regnum); if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { /* but DAC data register IS, at least for Picasso II */ if (cinfo->btype == BT_PICASSO) data += 0xfff; - vga_w (cinfo->regbase, data, red); - vga_w (cinfo->regbase, data, green); - vga_w (cinfo->regbase, data, blue); + vga_w(cinfo->regbase, data, red); + vga_w(cinfo->regbase, data, green); + vga_w(cinfo->regbase, data, blue); } else { - vga_w (cinfo->regbase, data, blue); - vga_w (cinfo->regbase, data, green); - vga_w (cinfo->regbase, data, red); + vga_w(cinfo->regbase, data, blue); + vga_w(cinfo->regbase, data, green); + vga_w(cinfo->regbase, data, red); } } - #if 0 /*** RClut - read CLUT entry (range 0..63) ***/ -static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, +static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue) { unsigned int data = VGA_PEL_D; - vga_w (cinfo->regbase, VGA_PEL_IR, regnum); + vga_w(cinfo->regbase, VGA_PEL_IR, regnum); if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { if (cinfo->btype == BT_PICASSO) data += 0xfff; - *red = vga_r (cinfo->regbase, data); - *green = vga_r (cinfo->regbase, data); - *blue = vga_r (cinfo->regbase, data); + *red = vga_r(cinfo->regbase, data); + *green = vga_r(cinfo->regbase, data); + *blue = vga_r(cinfo->regbase, data); } else { - *blue = vga_r (cinfo->regbase, data); - *green = vga_r (cinfo->regbase, data); - *red = vga_r (cinfo->regbase, data); + *blue = vga_r(cinfo->regbase, data); + *green = vga_r(cinfo->regbase, data); + *red = vga_r(cinfo->regbase, data); } } #endif - /******************************************************************* cirrusfb_WaitBLT() @@ -2870,10 +2869,10 @@ static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned c *********************************************************************/ /* FIXME: use interrupts instead */ -static void cirrusfb_WaitBLT (u8 __iomem *regbase) +static void cirrusfb_WaitBLT(u8 __iomem *regbase) { /* now busy-wait until we're done */ - while (vga_rgfx (regbase, CL_GR31) & 0x08) + while (vga_rgfx(regbase, CL_GR31) & 0x08) /* do nothing */ ; } @@ -2883,15 +2882,17 @@ static void cirrusfb_WaitBLT (u8 __iomem *regbase) perform accelerated "scrolling" ********************************************************************/ -static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, - u_short curx, u_short cury, u_short destx, u_short desty, - u_short width, u_short height, u_short line_length) +static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, + u_short curx, u_short cury, + u_short destx, u_short desty, + u_short width, u_short height, + u_short line_length) { u_short nwidth, nheight; u_long nsrc, ndest; u_char bltmode; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); nwidth = width - 1; nheight = height - 1; @@ -2911,9 +2912,13 @@ static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, nsrc = (cury * line_length) + curx; ndest = (desty * line_length) + destx; } else { - /* this means start addresses are at the end, counting backwards */ - nsrc = cury * line_length + curx + nheight * line_length + nwidth; - ndest = desty * line_length + destx + nheight * line_length + nwidth; + /* this means start addresses are at the end, + * counting backwards + */ + nsrc = cury * line_length + curx + + nheight * line_length + nwidth; + ndest = desty * line_length + destx + + nheight * line_length + nwidth; } /* @@ -2929,52 +2934,65 @@ static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel, start/stop */ - cirrusfb_WaitBLT(regbase); + cirrusfb_WaitBLT(regbase); /* pitch: set to line_length */ - vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ - vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */ - vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */ - vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */ + /* dest pitch low */ + vga_wgfx(regbase, CL_GR24, line_length & 0xff); + /* dest pitch hi */ + vga_wgfx(regbase, CL_GR25, line_length >> 8); + /* source pitch low */ + vga_wgfx(regbase, CL_GR26, line_length & 0xff); + /* source pitch hi */ + vga_wgfx(regbase, CL_GR27, line_length >> 8); /* BLT width: actual number of pixels - 1 */ - vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ - vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */ + /* BLT width low */ + vga_wgfx(regbase, CL_GR20, nwidth & 0xff); + /* BLT width hi */ + vga_wgfx(regbase, CL_GR21, nwidth >> 8); /* BLT height: actual number of lines -1 */ - vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */ - vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */ + /* BLT height low */ + vga_wgfx(regbase, CL_GR22, nheight & 0xff); + /* BLT width hi */ + vga_wgfx(regbase, CL_GR23, nheight >> 8); /* BLT destination */ - vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */ - vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */ - vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */ + /* BLT dest low */ + vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff)); + /* BLT dest mid */ + vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8)); + /* BLT dest hi */ + vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT source */ - vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */ - vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */ - vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */ + /* BLT src low */ + vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff)); + /* BLT src mid */ + vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8)); + /* BLT src hi */ + vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT mode */ - vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */ + vga_wgfx(regbase, CL_GR30, bltmode); /* BLT mode */ /* BLT ROP: SrcCopy */ - vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */ + vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */ /* and finally: GO! */ - vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */ + vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } - /******************************************************************* cirrusfb_RectFill() perform accelerated rectangle fill ********************************************************************/ -static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, +static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, u_short x, u_short y, u_short width, u_short height, u_char color, u_short line_length) { @@ -2982,93 +3000,95 @@ static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel, u_long ndest; u_char op; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); nwidth = width - 1; nheight = height - 1; ndest = (y * line_length) + x; - cirrusfb_WaitBLT(regbase); + cirrusfb_WaitBLT(regbase); /* pitch: set to line_length */ - vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ - vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */ - vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */ - vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */ + vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ + vga_wgfx(regbase, CL_GR25, line_length >> 8); /* dest pitch hi */ + vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */ + vga_wgfx(regbase, CL_GR27, line_length >> 8); /* source pitch hi */ /* BLT width: actual number of pixels - 1 */ - vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ - vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */ + vga_wgfx(regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ + vga_wgfx(regbase, CL_GR21, nwidth >> 8); /* BLT width hi */ /* BLT height: actual number of lines -1 */ - vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */ - vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */ + vga_wgfx(regbase, CL_GR22, nheight & 0xff); /* BLT height low */ + vga_wgfx(regbase, CL_GR23, nheight >> 8); /* BLT width hi */ /* BLT destination */ - vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */ - vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */ - vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */ + /* BLT dest low */ + vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff)); + /* BLT dest mid */ + vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8)); + /* BLT dest hi */ + vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT source: set to 0 (is a dummy here anyway) */ - vga_wgfx (regbase, CL_GR2C, 0x00); /* BLT src low */ - vga_wgfx (regbase, CL_GR2D, 0x00); /* BLT src mid */ - vga_wgfx (regbase, CL_GR2E, 0x00); /* BLT src hi */ + vga_wgfx(regbase, CL_GR2C, 0x00); /* BLT src low */ + vga_wgfx(regbase, CL_GR2D, 0x00); /* BLT src mid */ + vga_wgfx(regbase, CL_GR2E, 0x00); /* BLT src hi */ /* This is a ColorExpand Blt, using the */ /* same color for foreground and background */ - vga_wgfx (regbase, VGA_GFX_SR_VALUE, color); /* foreground color */ - vga_wgfx (regbase, VGA_GFX_SR_ENABLE, color); /* background color */ + vga_wgfx(regbase, VGA_GFX_SR_VALUE, color); /* foreground color */ + vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color); /* background color */ op = 0xc0; if (bits_per_pixel == 16) { - vga_wgfx (regbase, CL_GR10, color); /* foreground color */ - vga_wgfx (regbase, CL_GR11, color); /* background color */ + vga_wgfx(regbase, CL_GR10, color); /* foreground color */ + vga_wgfx(regbase, CL_GR11, color); /* background color */ op = 0x50; op = 0xd0; } else if (bits_per_pixel == 32) { - vga_wgfx (regbase, CL_GR10, color); /* foreground color */ - vga_wgfx (regbase, CL_GR11, color); /* background color */ - vga_wgfx (regbase, CL_GR12, color); /* foreground color */ - vga_wgfx (regbase, CL_GR13, color); /* background color */ - vga_wgfx (regbase, CL_GR14, 0); /* foreground color */ - vga_wgfx (regbase, CL_GR15, 0); /* background color */ + vga_wgfx(regbase, CL_GR10, color); /* foreground color */ + vga_wgfx(regbase, CL_GR11, color); /* background color */ + vga_wgfx(regbase, CL_GR12, color); /* foreground color */ + vga_wgfx(regbase, CL_GR13, color); /* background color */ + vga_wgfx(regbase, CL_GR14, 0); /* foreground color */ + vga_wgfx(regbase, CL_GR15, 0); /* background color */ op = 0x50; op = 0xf0; } /* BLT mode: color expand, Enable 8x8 copy (faster?) */ - vga_wgfx (regbase, CL_GR30, op); /* BLT mode */ + vga_wgfx(regbase, CL_GR30, op); /* BLT mode */ /* BLT ROP: SrcCopy */ - vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */ + vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */ /* and finally: GO! */ - vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */ + vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } - /************************************************************************** * bestclock() - determine closest possible clock lower(?) than the * desired pixel clock **************************************************************************/ -static void bestclock (long freq, long *best, long *nom, +static void bestclock(long freq, long *best, long *nom, long *den, long *div, long maxfreq) { long n, h, d, f; - assert (best != NULL); - assert (nom != NULL); - assert (den != NULL); - assert (div != NULL); - assert (maxfreq > 0); + assert(best != NULL); + assert(nom != NULL); + assert(den != NULL); + assert(div != NULL); + assert(maxfreq > 0); *nom = 0; *den = 0; *div = 0; - DPRINTK ("ENTER\n"); + DPRINTK("ENTER\n"); if (freq < 8000) freq = 8000; @@ -3085,7 +3105,7 @@ static void bestclock (long freq, long *best, long *nom, if (d > 31) d = (d / 2) * 2; h = (14318 * n) / d; - if (abs (h - freq) < abs (*best - freq)) { + if (abs(h - freq) < abs(*best - freq)) { *best = h; *nom = n; if (d < 32) { @@ -3102,7 +3122,7 @@ static void bestclock (long freq, long *best, long *nom, if (d > 31) d = (d / 2) * 2; h = (14318 * n) / d; - if (abs (h - freq) < abs (*best - freq)) { + if (abs(h - freq) < abs(*best - freq)) { *best = h; *nom = n; if (d < 32) { @@ -3116,14 +3136,13 @@ static void bestclock (long freq, long *best, long *nom, } } - DPRINTK ("Best possible values for given frequency:\n"); - DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n", - freq, *nom, *den, *div); + DPRINTK("Best possible values for given frequency:\n"); + DPRINTK(" best: %ld kHz nom: %ld den: %ld div: %ld\n", + freq, *nom, *den, *div); - DPRINTK ("EXIT\n"); + DPRINTK("EXIT\n"); } - /* ------------------------------------------------------------------------- * * debugging functions @@ -3145,21 +3164,20 @@ static void bestclock (long freq, long *best, long *nom, */ static -void cirrusfb_dbg_print_byte (const char *name, unsigned char val) +void cirrusfb_dbg_print_byte(const char *name, unsigned char val) { - DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n", - name, val, - val & 0x80 ? '1' : '0', - val & 0x40 ? '1' : '0', - val & 0x20 ? '1' : '0', - val & 0x10 ? '1' : '0', - val & 0x08 ? '1' : '0', - val & 0x04 ? '1' : '0', - val & 0x02 ? '1' : '0', - val & 0x01 ? '1' : '0'); + DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n", + name, val, + val & 0x80 ? '1' : '0', + val & 0x40 ? '1' : '0', + val & 0x20 ? '1' : '0', + val & 0x10 ? '1' : '0', + val & 0x08 ? '1' : '0', + val & 0x04 ? '1' : '0', + val & 0x02 ? '1' : '0', + val & 0x01 ? '1' : '0'); } - /** * cirrusfb_dbg_print_regs * @base: If using newmmio, the newmmio base address, otherwise %NULL @@ -3172,25 +3190,26 @@ void cirrusfb_dbg_print_byte (const char *name, unsigned char val) */ static -void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...) +void cirrusfb_dbg_print_regs(caddr_t regbase, + enum cirrusfb_dbg_reg_class reg_class, ...) { va_list list; unsigned char val = 0; unsigned reg; char *name; - va_start (list, reg_class); + va_start(list, reg_class); - name = va_arg (list, char *); + name = va_arg(list, char *); while (name != NULL) { - reg = va_arg (list, int); + reg = va_arg(list, int); switch (reg_class) { case CRT: - val = vga_rcrt (regbase, (unsigned char) reg); + val = vga_rcrt(regbase, (unsigned char) reg); break; case SEQ: - val = vga_rseq (regbase, (unsigned char) reg); + val = vga_rseq(regbase, (unsigned char) reg); break; default: /* should never occur */ @@ -3198,15 +3217,14 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas break; } - cirrusfb_dbg_print_byte (name, val); + cirrusfb_dbg_print_byte(name, val); - name = va_arg (list, char *); + name = va_arg(list, char *); } - va_end (list); + va_end(list); } - /** * cirrusfb_dump * @cirrusfbinfo: @@ -3214,13 +3232,11 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas * DESCRIPTION: */ -static -void cirrusfb_dump (void) +static void cirrusfb_dump(void) { - cirrusfb_dbg_reg_dump (NULL); + cirrusfb_dbg_reg_dump(NULL); } - /** * cirrusfb_dbg_reg_dump * @base: If using newmmio, the newmmio base address, otherwise %NULL @@ -3232,11 +3248,11 @@ void cirrusfb_dump (void) */ static -void cirrusfb_dbg_reg_dump (caddr_t regbase) +void cirrusfb_dbg_reg_dump(caddr_t regbase) { - DPRINTK ("CIRRUSFB VGA CRTC register dump:\n"); + DPRINTK("CIRRUSFB VGA CRTC register dump:\n"); - cirrusfb_dbg_print_regs (regbase, CRT, + cirrusfb_dbg_print_regs(regbase, CRT, "CR00", 0x00, "CR01", 0x01, "CR02", 0x02, @@ -3286,11 +3302,11 @@ void cirrusfb_dbg_reg_dump (caddr_t regbase) "CR3F", 0x3F, NULL); - DPRINTK ("\n"); + DPRINTK("\n"); - DPRINTK ("CIRRUSFB VGA SEQ register dump:\n"); + DPRINTK("CIRRUSFB VGA SEQ register dump:\n"); - cirrusfb_dbg_print_regs (regbase, SEQ, + cirrusfb_dbg_print_regs(regbase, SEQ, "SR00", 0x00, "SR01", 0x01, "SR02", 0x02, @@ -3319,7 +3335,7 @@ void cirrusfb_dbg_reg_dump (caddr_t regbase) "SR1F", 0x1F, NULL); - DPRINTK ("\n"); + DPRINTK("\n"); } #endif /* CIRRUSFB_DEBUG */ diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index dea6579941b..17b5267f44d 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -29,7 +29,7 @@ #include <asm/hardware.h> #include <asm/mach-types.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/hardware/clps7111.h> #include <asm/arch/syspld.h> diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index e58c87b3e3a..0f32f4a00b2 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -78,7 +78,6 @@ #include <asm/fb.h> #include <asm/irq.h> #include <asm/system.h> -#include <asm/uaccess.h> #ifdef CONFIG_ATARI #include <asm/atariints.h> #endif @@ -2169,7 +2168,7 @@ static __inline__ void updatescrollmode(struct display *p, } static int fbcon_resize(struct vc_data *vc, unsigned int width, - unsigned int height) + unsigned int height, unsigned int user) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; @@ -2406,7 +2405,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) update_screen(vc); } - if (fbcon_is_inactive(vc, info) || + if (mode_switch || fbcon_is_inactive(vc, info) || ops->blank_state != FB_BLANK_UNBLANK) fbcon_del_cursor_timer(info); else diff --git a/drivers/video/console/font_10x18.c b/drivers/video/console/font_10x18.c index e6aa0eab5bb..6be72bb218e 100644 --- a/drivers/video/console/font_10x18.c +++ b/drivers/video/console/font_10x18.c @@ -5133,14 +5133,14 @@ static const unsigned char fontdata_10x18[FONTDATAMAX] = { const struct font_desc font_10x18 = { - FONT10x18_IDX, - "10x18", - 10, - 18, - fontdata_10x18, + .idx = FONT10x18_IDX, + .name = "10x18", + .width = 10, + .height = 18, + .data = fontdata_10x18, #ifdef __sparc__ - 5 + .pref = 5, #else - -1 + .pref = -1, #endif }; diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c index 89976cd9749..46e86e67aa6 100644 --- a/drivers/video/console/font_6x11.c +++ b/drivers/video/console/font_6x11.c @@ -3342,10 +3342,11 @@ static const unsigned char fontdata_6x11[FONTDATAMAX] = { const struct font_desc font_vga_6x11 = { - VGA6x11_IDX, - "ProFont6x11", - 6, - 11, - fontdata_6x11, - -2000 /* Try avoiding this font if possible unless on MAC */ + .idx = VGA6x11_IDX, + .name = "ProFont6x11", + .width = 6, + .height = 11, + .data = fontdata_6x11, + /* Try avoiding this font if possible unless on MAC */ + .pref = -2000, }; diff --git a/drivers/video/console/font_7x14.c b/drivers/video/console/font_7x14.c index bbf11664739..3b7dbf9c060 100644 --- a/drivers/video/console/font_7x14.c +++ b/drivers/video/console/font_7x14.c @@ -4109,10 +4109,10 @@ static const unsigned char fontdata_7x14[FONTDATAMAX] = { const struct font_desc font_7x14 = { - FONT7x14_IDX, - "7x14", - 7, - 14, - fontdata_7x14, - 0 + .idx = FONT7x14_IDX, + .name = "7x14", + .width = 7, + .height = 14, + .data = fontdata_7x14, + .pref = 0, }; diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c index 74fe86f28ff..00a0c67a5c7 100644 --- a/drivers/video/console/font_8x16.c +++ b/drivers/video/console/font_8x16.c @@ -5,6 +5,7 @@ /**********************************************/ #include <linux/font.h> +#include <linux/module.h> #define FONTDATAMAX 4096 @@ -4622,10 +4623,11 @@ static const unsigned char fontdata_8x16[FONTDATAMAX] = { const struct font_desc font_vga_8x16 = { - VGA8x16_IDX, - "VGA8x16", - 8, - 16, - fontdata_8x16, - 0 + .idx = VGA8x16_IDX, + .name = "VGA8x16", + .width = 8, + .height = 16, + .data = fontdata_8x16, + .pref = 0, }; +EXPORT_SYMBOL(font_vga_8x16); diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c index 26199f8ee90..9f56efe2cee 100644 --- a/drivers/video/console/font_8x8.c +++ b/drivers/video/console/font_8x8.c @@ -2574,10 +2574,10 @@ static const unsigned char fontdata_8x8[FONTDATAMAX] = { const struct font_desc font_vga_8x8 = { - VGA8x8_IDX, - "VGA8x8", - 8, - 8, - fontdata_8x8, - 0 + .idx = VGA8x8_IDX, + .name = "VGA8x8", + .width = 8, + .height = 8, + .data = fontdata_8x8, + .pref = 0, }; diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c index 40f3d4eeb19..639e31ae110 100644 --- a/drivers/video/console/font_acorn_8x8.c +++ b/drivers/video/console/font_acorn_8x8.c @@ -262,14 +262,14 @@ static const unsigned char acorndata_8x8[] = { }; const struct font_desc font_acorn_8x8 = { - ACORN8x8_IDX, - "Acorn8x8", - 8, - 8, - acorndata_8x8, + .idx = ACORN8x8_IDX, + .name = "Acorn8x8", + .width = 8, + .height = 8, + .data = acorndata_8x8, #ifdef CONFIG_ARCH_ACORN - 20 + .pref = 20, #else - 0 + .pref = 0, #endif }; diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c index d818234fdf1..a19a7f33133 100644 --- a/drivers/video/console/font_mini_4x6.c +++ b/drivers/video/console/font_mini_4x6.c @@ -2148,11 +2148,11 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = { }; const struct font_desc font_mini_4x6 = { - MINI4x6_IDX, - "MINI4x6", - 4, - 6, - fontdata_mini_4x6, - 3 + .idx = MINI4x6_IDX, + .name = "MINI4x6", + .width = 4, + .height = 6, + .data = fontdata_mini_4x6, + .pref = 3, }; diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c index e646c88f55c..dc6ad539ca4 100644 --- a/drivers/video/console/font_pearl_8x8.c +++ b/drivers/video/console/font_pearl_8x8.c @@ -2578,10 +2578,10 @@ static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = { }; const struct font_desc font_pearl_8x8 = { - PEARL8x8_IDX, - "PEARL8x8", - 8, - 8, - fontdata_pearl8x8, - 2 + .idx = PEARL8x8_IDX, + .name = "PEARL8x8", + .width = 8, + .height = 8, + .data = fontdata_pearl8x8, + .pref = 2, }; diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c index ab5eb93407b..d3643853c33 100644 --- a/drivers/video/console/font_sun12x22.c +++ b/drivers/video/console/font_sun12x22.c @@ -6152,14 +6152,14 @@ static const unsigned char fontdata_sun12x22[FONTDATAMAX] = { const struct font_desc font_sun_12x22 = { - SUN12x22_IDX, - "SUN12x22", - 12, - 22, - fontdata_sun12x22, + .idx = SUN12x22_IDX, + .name = "SUN12x22", + .width = 12, + .height = 22, + .data = fontdata_sun12x22, #ifdef __sparc__ - 5 + .pref = 5, #else - -1 + .pref = -1, #endif }; diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c index 41f910f5529..5abf290c6eb 100644 --- a/drivers/video/console/font_sun8x16.c +++ b/drivers/video/console/font_sun8x16.c @@ -262,14 +262,14 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = { }; const struct font_desc font_sun_8x16 = { - SUN8x16_IDX, - "SUN8x16", - 8, - 16, - fontdata_sun8x16, + .idx = SUN8x16_IDX, + .name = "SUN8x16", + .width = 8, + .height = 16, + .data = fontdata_sun8x16, #ifdef __sparc__ - 10 + .pref = 10, #else - -1 + .pref = -1, #endif }; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index dda0586ab3f..f57d7b2758b 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -98,14 +98,19 @@ static inline void newport_init_cmap(void) } } -static void newport_show_logo(void) +static struct linux_logo *newport_show_logo(void) { #ifdef CONFIG_LOGO_SGI_CLUT224 const struct linux_logo *logo = fb_find_logo(8); - const unsigned char *clut = logo->clut; - const unsigned char *data = logo->data; + const unsigned char *clut; + const unsigned char *data; unsigned long i; + if (!logo) + return NULL; + *clut = logo->clut; + *data = logo->data; + for (i = 0; i < logo->clutsize; i++) { newport_bfwait(npregs); newport_cmap_setaddr(npregs, i + 0x20); @@ -123,6 +128,8 @@ static void newport_show_logo(void) for (i = 0; i < logo->width*logo->height; i++) npregs->go.hostrw0 = *data++ << 24; + + return logo; #endif /* CONFIG_LOGO_SGI_CLUT224 */ } @@ -465,9 +472,10 @@ static int newport_switch(struct vc_data *vc) npregs->cset.topscan = 0x3ff; if (!logo_drawn) { - newport_show_logo(); - logo_drawn = 1; - logo_active = 1; + if (newport_show_logo()) { + logo_drawn = 1; + logo_active = 1; + } } return 1; diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c index 03cfb7ac573..25f835bf3d7 100644 --- a/drivers/video/console/softcursor.c +++ b/drivers/video/console/softcursor.c @@ -15,7 +15,6 @@ #include <linux/fb.h> #include <linux/slab.h> -#include <asm/uaccess.h> #include <asm/io.h> #include "fbcon.h" diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d18b73aafa0..e9afb7ebd56 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1278,13 +1278,14 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) #endif static int vgacon_resize(struct vc_data *c, unsigned int width, - unsigned int height) + unsigned int height, unsigned int user) { if (width % 2 || width > ORIG_VIDEO_COLS || height > (ORIG_VIDEO_LINES * vga_default_font_height)/ c->vc_font.height) - /* let svgatextmode tinker with video timings */ - return 0; + /* let svgatextmode tinker with video timings and + return success */ + return (user) ? 0 : -EINVAL; if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ vgacon_doresize(c, width, height); diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 30ede6e8830..9bb2cbfe4a3 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -50,7 +50,6 @@ #include <asm/io.h> #include <asm/pgtable.h> #include <asm/system.h> -#include <asm/uaccess.h> #ifdef __arm__ #include <asm/mach-types.h> diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index 33be46ccb54..cc2810ef5de 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c @@ -57,7 +57,7 @@ #include <asm/types.h> #include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <video/epson1355.h> diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 1a8643f053d..a0c5d9d90d7 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -19,7 +19,6 @@ #include <linux/interrupt.h> #include <linux/fb.h> #include <linux/list.h> -#include <asm/uaccess.h> /* to support deferred IO */ #include <linux/rmap.h> diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index c5c45203833..cdafbe14ef1 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -2,6 +2,7 @@ #define _FB_DRAW_H #include <asm/types.h> +#include <linux/fb.h> /* * Compose two values, using a bitmask as decision value @@ -69,4 +70,97 @@ pixel_to_pat( u32 bpp, u32 pixel) } } #endif + +#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE +#if BITS_PER_LONG == 64 +#define REV_PIXELS_MASK1 0x5555555555555555ul +#define REV_PIXELS_MASK2 0x3333333333333333ul +#define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful +#else +#define REV_PIXELS_MASK1 0x55555555ul +#define REV_PIXELS_MASK2 0x33333333ul +#define REV_PIXELS_MASK4 0x0f0f0f0ful +#endif + +static inline unsigned long fb_rev_pixels_in_long(unsigned long val, + u32 bswapmask) +{ + if (bswapmask & 1) + val = comp(val >> 1, val << 1, REV_PIXELS_MASK1); + if (bswapmask & 2) + val = comp(val >> 2, val << 2, REV_PIXELS_MASK2); + if (bswapmask & 3) + val = comp(val >> 4, val << 4, REV_PIXELS_MASK4); +} + +static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) +{ + u32 mask; + + if (!bswapmask) { + mask = FB_SHIFT_HIGH(~(u32)0, index); + } else { + mask = 0xff << FB_LEFT_POS(8); + mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); +#if defined(__i386__) || defined(__x86_64__) + /* Shift argument is limited to 0 - 31 on x86 based CPU's */ + if(index + bswapmask < 32) +#endif + mask |= FB_SHIFT_HIGH(~(u32)0, + (index + bswapmask) & ~(bswapmask)); + } + return mask; +} + +static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask) +{ + unsigned long mask; + + if (!bswapmask) { + mask = FB_SHIFT_HIGH(~0UL, index); + } else { + mask = 0xff << FB_LEFT_POS(8); + mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); +#if defined(__i386__) || defined(__x86_64__) + /* Shift argument is limited to 0 - 31 on x86 based CPU's */ + if(index + bswapmask < BITS_PER_LONG) +#endif + mask |= FB_SHIFT_HIGH(~0UL, + (index + bswapmask) & ~(bswapmask)); + } + return mask; +} + + +static inline u32 fb_compute_bswapmask(struct fb_info *info) +{ + u32 bswapmask = 0; + unsigned bpp = info->var.bits_per_pixel; + + if ((bpp < 8) && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B)) { + /* + * Reversed order of pixel layout in bytes + * works only for 1, 2 and 4 bpp + */ + bswapmask = 7 - bpp + 1; + } + return bswapmask; +} + +#else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ + +static inline unsigned long fb_rev_pixels_in_long(unsigned long val, + u32 bswapmask) +{ + return val; +} + +#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) +#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i)) +#define fb_compute_bswapmask(...) 0 + +#endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ + #endif /* FB_DRAW_H */ diff --git a/drivers/video/fb_sys_fops.c b/drivers/video/fb_sys_fops.c index cf2538d669c..ff275d7f3ea 100644 --- a/drivers/video/fb_sys_fops.c +++ b/drivers/video/fb_sys_fops.c @@ -11,7 +11,7 @@ */ #include <linux/fb.h> #include <linux/module.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos) diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index 148108afdd5..91b78e69150 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -15,8 +15,7 @@ #include <linux/module.h> #include <linux/fb.h> #include <linux/slab.h> - -#include <asm/uaccess.h> +#include <linux/uaccess.h> static u16 red2[] __read_mostly = { 0x0000, 0xaaaa diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 07402720470..1194f5e060e 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1567,8 +1567,6 @@ int fb_new_modelist(struct fb_info *info) static char *video_options[FB_MAX] __read_mostly; static int ofonly __read_mostly; -extern const char *global_mode_option; - /** * fb_get_options - get kernel boot parameters * @name: framebuffer name as it would appear in @@ -1636,7 +1634,7 @@ static int __init video_setup(char *options) } if (!global && !strstr(options, "fb:")) { - global_mode_option = options; + fb_mode_option = options; global = 1; } @@ -1663,7 +1661,6 @@ EXPORT_SYMBOL(register_framebuffer); EXPORT_SYMBOL(unregister_framebuffer); EXPORT_SYMBOL(num_registered_fb); EXPORT_SYMBOL(registered_fb); -EXPORT_SYMBOL(fb_prepare_logo); EXPORT_SYMBOL(fb_show_logo); EXPORT_SYMBOL(fb_set_var); EXPORT_SYMBOL(fb_blank); diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 438b9411905..4ba9c089441 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -591,7 +591,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) { struct fb_videomode *mode, *m; unsigned char *block; - int num = 0, i; + int num = 0, i, first = 1; mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); if (mode == NULL) @@ -608,8 +608,6 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) DPRINTK(" Detailed Timings\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { - int first = 1; - if (!(block[0] == 0x00 && block[1] == 0x00)) { get_detailed_timing(block, &mode[num]); if (first) { diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index 5e30b40c8c0..583185fd7c9 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -566,12 +566,7 @@ static int __init lxfb_setup(char *options) if (!options || !*options) return 0; - while (1) { - char *opt = strsep(&options, ","); - - if (opt == NULL) - break; - + while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c index abfcb50364c..94e0df8a6f6 100644 --- a/drivers/video/hecubafb.c +++ b/drivers/video/hecubafb.c @@ -45,7 +45,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/list.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> /* Apollo controller specific defines */ #define APOLLO_START_NEW_IMG 0xA0 diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 94f4511023d..3ab91bf2157 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -29,7 +29,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #if defined(CONFIG_PPC) #include <linux/nvram.h> diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index a1258989859..11609552a38 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -34,7 +34,6 @@ #include <asm/hardware.h> #include <asm/io.h> -#include <asm/uaccess.h> #include <asm/arch/imxfb.h> /* @@ -467,7 +466,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) info->var.vmode = FB_VMODE_NONINTERLACED; info->fbops = &imxfb_ops; - info->flags = FBINFO_FLAG_DEFAULT; + info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; fbi->rgb[RGB_16] = &def_rgb_16; fbi->rgb[RGB_8] = &def_rgb_8; @@ -480,6 +479,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) info->var.yres_virtual = inf->yres; fbi->max_bpp = inf->bpp; info->var.bits_per_pixel = inf->bpp; + info->var.nonstd = inf->nonstd; info->var.pixclock = inf->pixclock; info->var.hsync_len = inf->hsync_len; info->var.left_margin = inf->left_margin; diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 6148300fadd..2fe3f7def53 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -231,8 +231,8 @@ struct intelfb_hwstate { struct intelfb_heap_data { u32 physical; u8 __iomem *virtual; - u32 offset; // in GATT pages - u32 size; // in bytes + u32 offset; /* in GATT pages */ + u32 size; /* in bytes */ }; #ifdef CONFIG_FB_INTEL_I2C @@ -270,9 +270,9 @@ struct intelfb_info { struct intelfb_hwstate save_state; /* agpgart structs */ - struct agp_memory *gtt_fb_mem; // use all stolen memory or vram - struct agp_memory *gtt_ring_mem; // ring buffer - struct agp_memory *gtt_cursor_mem; // hw cursor + struct agp_memory *gtt_fb_mem; /* use all stolen memory or vram */ + struct agp_memory *gtt_ring_mem; /* ring buffer */ + struct agp_memory *gtt_cursor_mem; /* hw cursor */ /* use a gart reserved fb mem */ u8 fbmem_gart; @@ -346,7 +346,7 @@ struct intelfb_info { /* driver registered */ int registered; - + /* index into plls */ int pll_index; @@ -355,7 +355,10 @@ struct intelfb_info { struct intelfb_output_rec output[MAX_OUTPUTS]; }; -#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM)) +#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \ + ((dinfo)->chipset == INTEL_915GM) || \ + ((dinfo)->chipset == INTEL_945G) || \ + ((dinfo)->chipset==INTEL_945GM)) #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index 61e4c8759b2..94c08bb5acf 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -58,7 +58,8 @@ static void intelfb_gpio_setscl(void *data, int state) struct intelfb_info *dinfo = chan->dinfo; u32 val; - OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); + OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | + SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); val = INREG(chan->reg); } @@ -68,7 +69,8 @@ static void intelfb_gpio_setsda(void *data, int state) struct intelfb_info *dinfo = chan->dinfo; u32 val; - OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); + OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | + SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); val = INREG(chan->reg); } @@ -97,26 +99,26 @@ static int intelfb_gpio_getsda(void *data) } static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo, - struct intelfb_i2c_chan *chan, - const u32 reg, const char *name) + struct intelfb_i2c_chan *chan, + const u32 reg, const char *name) { int rc; - chan->dinfo = dinfo; - chan->reg = reg; + chan->dinfo = dinfo; + chan->reg = reg; snprintf(chan->adapter.name, sizeof(chan->adapter.name), "intelfb %s", name); - chan->adapter.owner = THIS_MODULE; - chan->adapter.id = I2C_HW_B_INTELFB; + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_HW_B_INTELFB; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->dinfo->pdev->dev; - chan->algo.setsda = intelfb_gpio_setsda; - chan->algo.setscl = intelfb_gpio_setscl; - chan->algo.getsda = intelfb_gpio_getsda; - chan->algo.getscl = intelfb_gpio_getscl; - chan->algo.udelay = 40; - chan->algo.timeout = 20; - chan->algo.data = chan; + chan->algo.setsda = intelfb_gpio_setsda; + chan->algo.setscl = intelfb_gpio_setscl; + chan->algo.getsda = intelfb_gpio_getsda; + chan->algo.getscl = intelfb_gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = 20; + chan->algo.data = chan; i2c_set_adapdata(&chan->adapter, chan); @@ -142,40 +144,44 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo) dinfo->output[i].type = INTELFB_OUTPUT_ANALOG; /* setup the DDC bus for analog output */ - intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A"); + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, + "CRTDDC_A"); i++; - /* need to add the output busses for each device - - this function is very incomplete - - i915GM has LVDS and TVOUT for example - */ - switch(dinfo->chipset) { + /* need to add the output busses for each device + - this function is very incomplete + - i915GM has LVDS and TVOUT for example + */ + switch(dinfo->chipset) { case INTEL_830M: case INTEL_845G: case INTEL_855GM: case INTEL_865G: dinfo->output[i].type = INTELFB_OUTPUT_DVO; - intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D"); - intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E"); + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, + GPIOD, "DVODDC_D"); + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, + GPIOE, "DVOI2C_E"); i++; break; case INTEL_915G: case INTEL_915GM: - /* has some LVDS + tv-out */ + /* has some LVDS + tv-out */ case INTEL_945G: case INTEL_945GM: /* SDVO ports have a single control bus - 2 devices */ dinfo->output[i].type = INTELFB_OUTPUT_SDVO; - intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E"); + intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, + GPIOE, "SDVOCTRL_E"); /* TODO: initialize the SDVO */ -// I830SDVOInit(pScrn, i, DVOB); + /* I830SDVOInit(pScrn, i, DVOB); */ i++; /* set up SDVOC */ dinfo->output[i].type = INTELFB_OUTPUT_SDVO; dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus; /* TODO: initialize the SDVO */ -// I830SDVOInit(pScrn, i, DVOC); + /* I830SDVOInit(pScrn, i, DVOC); */ i++; break; } diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index b75eda84858..0428f211f19 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -99,13 +99,6 @@ * Add vram option to reserve more memory than stolen by BIOS * Fix intelfbhw_pan_display typo * Add __initdata annotations - * - * TODO: - * - * - * Wish List: - * - * */ #include <linux/module.h> @@ -222,8 +215,8 @@ static struct pci_driver intelfb_driver = { /* Module description/parameters */ MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); -MODULE_DESCRIPTION( - "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets"); +MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS + " chipsets"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DEVICE_TABLE(pci, intelfb_pci_table); @@ -271,8 +264,7 @@ MODULE_PARM_DESC(mode, #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0) #define OPT_STRVAL(opt, name) (opt + strlen(name)) -static __inline__ char * -get_opt_string(const char *this_opt, const char *name) +static __inline__ char * get_opt_string(const char *this_opt, const char *name) { const char *p; int i; @@ -290,8 +282,8 @@ get_opt_string(const char *this_opt, const char *name) return ret; } -static __inline__ int -get_opt_int(const char *this_opt, const char *name, int *ret) +static __inline__ int get_opt_int(const char *this_opt, const char *name, + int *ret) { if (!ret) return 0; @@ -303,8 +295,8 @@ get_opt_int(const char *this_opt, const char *name, int *ret) return 1; } -static __inline__ int -get_opt_bool(const char *this_opt, const char *name, int *ret) +static __inline__ int get_opt_bool(const char *this_opt, const char *name, + int *ret) { if (!ret) return 0; @@ -324,8 +316,7 @@ get_opt_bool(const char *this_opt, const char *name, int *ret) return 1; } -static int __init -intelfb_setup(char *options) +static int __init intelfb_setup(char *options) { char *this_opt; @@ -355,7 +346,7 @@ intelfb_setup(char *options) continue; if (get_opt_bool(this_opt, "accel", &accel)) ; - else if (get_opt_int(this_opt, "vram", &vram)) + else if (get_opt_int(this_opt, "vram", &vram)) ; else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) ; @@ -376,8 +367,7 @@ intelfb_setup(char *options) #endif -static int __init -intelfb_init(void) +static int __init intelfb_init(void) { #ifndef MODULE char *option = NULL; @@ -401,8 +391,7 @@ intelfb_init(void) return pci_register_driver(&intelfb_driver); } -static void __exit -intelfb_exit(void) +static void __exit intelfb_exit(void) { DBG_MSG("intelfb_exit\n"); pci_unregister_driver(&intelfb_driver); @@ -428,8 +417,8 @@ static inline void __devinit set_mtrr(struct intelfb_info *dinfo) } static inline void unset_mtrr(struct intelfb_info *dinfo) { - if (dinfo->has_mtrr) - mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, + if (dinfo->has_mtrr) + mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, dinfo->aperture.size); } #else @@ -442,8 +431,7 @@ static inline void unset_mtrr(struct intelfb_info *dinfo) * driver init / cleanup * ***************************************************************/ -static void -cleanup(struct intelfb_info *dinfo) +static void cleanup(struct intelfb_info *dinfo) { DBG_MSG("cleanup\n"); @@ -499,8 +487,8 @@ cleanup(struct intelfb_info *dinfo) } while (0) -static int __devinit -intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit intelfb_pci_register(struct pci_dev *pdev, + const struct pci_device_id *ent) { struct fb_info *info; struct intelfb_info *dinfo; @@ -510,8 +498,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) int agp_memtype; const char *s; struct agp_bridge_data *bridge; - int aperture_bar = 0; - int mmio_bar = 1; + int aperture_bar = 0; + int mmio_bar = 1; int offset; DBG_MSG("intelfb_pci_register\n"); @@ -637,9 +625,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) dinfo->ring.size = RINGBUFFER_SIZE; dinfo->ring_tail_mask = dinfo->ring.size - 1; } - if (dinfo->hwcursor) { + if (dinfo->hwcursor) dinfo->cursor.size = HW_CURSOR_SIZE; - } /* Use agpgart to manage the GATT */ if (!(bridge = agp_backend_acquire(pdev))) { @@ -662,18 +649,15 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; /* set the mem offsets - set them after the already used pages */ - if (dinfo->accel) { + if (dinfo->accel) dinfo->ring.offset = offset + gtt_info.current_memory; - } - if (dinfo->hwcursor) { + if (dinfo->hwcursor) dinfo->cursor.offset = offset + + gtt_info.current_memory + (dinfo->ring.size >> 12); - } - if (dinfo->fbmem_gart) { + if (dinfo->fbmem_gart) dinfo->fb.offset = offset + + gtt_info.current_memory + (dinfo->ring.size >> 12) + (dinfo->cursor.size >> 12); - } /* Allocate memories (which aren't stolen) */ /* Map the fb and MMIO regions */ @@ -689,7 +673,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) dinfo->mmio_base = (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, - INTEL_REG_SIZE); + INTEL_REG_SIZE); if (!dinfo->mmio_base) { ERR_MSG("Cannot remap MMIO region.\n"); cleanup(dinfo); @@ -837,10 +821,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) if (bailearly == 3) bailout(dinfo); - if (FIXED_MODE(dinfo)) { - /* remap fb address */ + if (FIXED_MODE(dinfo)) /* remap fb address */ update_dinfo(dinfo, &dinfo->initial_var); - } if (bailearly == 4) bailout(dinfo); @@ -939,8 +921,7 @@ intelfb_pci_unregister(struct pci_dev *pdev) * helper functions * ***************************************************************/ -int __inline__ -intelfb_var_to_depth(const struct fb_var_screeninfo *var) +int __inline__ intelfb_var_to_depth(const struct fb_var_screeninfo *var) { DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", var->bits_per_pixel, var->green.length); @@ -956,8 +937,7 @@ intelfb_var_to_depth(const struct fb_var_screeninfo *var) } -static __inline__ int -var_to_refresh(const struct fb_var_screeninfo *var) +static __inline__ int var_to_refresh(const struct fb_var_screeninfo *var) { int xtot = var->xres + var->left_margin + var->right_margin + var->hsync_len; @@ -971,8 +951,7 @@ var_to_refresh(const struct fb_var_screeninfo *var) * Various intialisation functions * ***************************************************************/ -static void __devinit -get_initial_mode(struct intelfb_info *dinfo) +static void __devinit get_initial_mode(struct intelfb_info *dinfo) { struct fb_var_screeninfo *var; int xtot, ytot; @@ -1039,8 +1018,7 @@ get_initial_mode(struct intelfb_info *dinfo) } } -static int __devinit -intelfb_init_var(struct intelfb_info *dinfo) +static int __devinit intelfb_init_var(struct intelfb_info *dinfo) { struct fb_var_screeninfo *var; int msrc = 0; @@ -1087,10 +1065,9 @@ intelfb_init_var(struct intelfb_info *dinfo) } - if (!msrc) { + if (!msrc) msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, NULL, 0, NULL, 0); - } } if (!msrc) { @@ -1122,8 +1099,7 @@ intelfb_init_var(struct intelfb_info *dinfo) return 0; } -static int __devinit -intelfb_set_fbinfo(struct intelfb_info *dinfo) +static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo) { struct fb_info *info = dinfo->info; @@ -1159,8 +1135,8 @@ intelfb_set_fbinfo(struct intelfb_info *dinfo) } /* Update dinfo to match the active video mode. */ -static void -update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) +static void update_dinfo(struct intelfb_info *dinfo, + struct fb_var_screeninfo *var) { DBG_MSG("update_dinfo\n"); @@ -1208,36 +1184,32 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) * fbdev interface * ***************************************************************/ -static int -intelfb_open(struct fb_info *info, int user) +static int intelfb_open(struct fb_info *info, int user) { struct intelfb_info *dinfo = GET_DINFO(info); - if (user) { + if (user) dinfo->open++; - } return 0; } -static int -intelfb_release(struct fb_info *info, int user) +static int intelfb_release(struct fb_info *info, int user) { struct intelfb_info *dinfo = GET_DINFO(info); if (user) { dinfo->open--; msleep(1); - if (!dinfo->open) { + if (!dinfo->open) intelfbhw_disable_irq(dinfo); - } } return 0; } -static int -intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +static int intelfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) { int change_var = 0; struct fb_var_screeninfo v; @@ -1271,15 +1243,15 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } /* Check for a supported bpp. */ - if (v.bits_per_pixel <= 8) { + if (v.bits_per_pixel <= 8) v.bits_per_pixel = 8; - } else if (v.bits_per_pixel <= 16) { + else if (v.bits_per_pixel <= 16) { if (v.bits_per_pixel == 16) v.green.length = 6; v.bits_per_pixel = 16; - } else if (v.bits_per_pixel <= 32) { + } else if (v.bits_per_pixel <= 32) v.bits_per_pixel = 32; - } else + else return -EINVAL; change_var = ((info->var.xres != var->xres) || @@ -1361,10 +1333,9 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -static int -intelfb_set_par(struct fb_info *info) +static int intelfb_set_par(struct fb_info *info) { - struct intelfb_hwstate *hw; + struct intelfb_hwstate *hw; struct intelfb_info *dinfo = GET_DINFO(info); if (FIXED_MODE(dinfo)) { @@ -1372,9 +1343,9 @@ intelfb_set_par(struct fb_info *info) return -EINVAL; } - hw = kmalloc(sizeof(*hw), GFP_ATOMIC); - if (!hw) - return -ENOMEM; + hw = kmalloc(sizeof(*hw), GFP_ATOMIC); + if (!hw) + return -ENOMEM; DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); @@ -1384,15 +1355,15 @@ intelfb_set_par(struct fb_info *info) if (ACCEL(dinfo, info)) intelfbhw_2d_stop(dinfo); - memcpy(hw, &dinfo->save_state, sizeof(*hw)); - if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) - goto invalid_mode; - if (intelfbhw_program_mode(dinfo, hw, 0)) - goto invalid_mode; + memcpy(hw, &dinfo->save_state, sizeof(*hw)); + if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) + goto invalid_mode; + if (intelfbhw_program_mode(dinfo, hw, 0)) + goto invalid_mode; #if REGDUMP > 0 - intelfbhw_read_hw_state(dinfo, hw, 0); - intelfbhw_print_hw_state(dinfo, hw); + intelfbhw_read_hw_state(dinfo, hw, 0); + intelfbhw_print_hw_state(dinfo, hw); #endif update_dinfo(dinfo, &info->var); @@ -1408,9 +1379,9 @@ intelfb_set_par(struct fb_info *info) info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; - } else { + } else info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - } + kfree(hw); return 0; invalid_mode: @@ -1418,9 +1389,9 @@ invalid_mode: return -EINVAL; } -static int -intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *info) +static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { struct intelfb_info *dinfo = GET_DINFO(info); @@ -1463,23 +1434,22 @@ intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -static int -intelfb_blank(int blank, struct fb_info *info) +static int intelfb_blank(int blank, struct fb_info *info) { intelfbhw_do_blank(blank, info); return 0; } -static int -intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +static int intelfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { intelfbhw_pan_display(var, info); return 0; } /* When/if we have our own ioctls. */ -static int -intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int intelfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) { int retval = 0; struct intelfb_info *dinfo = GET_DINFO(info); @@ -1499,8 +1469,8 @@ intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) return retval; } -static void -intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) +static void intelfb_fillrect (struct fb_info *info, + const struct fb_fillrect *rect) { struct intelfb_info *dinfo = GET_DINFO(info); u32 rop, color; @@ -1514,7 +1484,7 @@ intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) if (rect->rop == ROP_COPY) rop = PAT_ROP_GXCOPY; - else // ROP_XOR + else /* ROP_XOR */ rop = PAT_ROP_GXXOR; if (dinfo->depth != 8) @@ -1528,8 +1498,8 @@ intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect) rop); } -static void -intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +static void intelfb_copyarea(struct fb_info *info, + const struct fb_copyarea *region) { struct intelfb_info *dinfo = GET_DINFO(info); @@ -1545,8 +1515,8 @@ intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) dinfo->pitch, info->var.bits_per_pixel); } -static void -intelfb_imageblit(struct fb_info *info, const struct fb_image *image) +static void intelfb_imageblit(struct fb_info *info, + const struct fb_image *image) { struct intelfb_info *dinfo = GET_DINFO(info); u32 fgcolor, bgcolor; @@ -1574,8 +1544,7 @@ intelfb_imageblit(struct fb_info *info, const struct fb_image *image) return cfb_imageblit(info, image); } -static int -intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +static int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct intelfb_info *dinfo = GET_DINFO(info); u32 physical; @@ -1689,8 +1658,7 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) return 0; } -static int -intelfb_sync(struct fb_info *info) +static int intelfb_sync(struct fb_info *info) { struct intelfb_info *dinfo = GET_DINFO(info); diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 6a47682d861..2a0e32074f7 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -56,17 +56,16 @@ static struct pll_min_max plls[PLLS_MAX] = { 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000, 48000, - 4, 2 }, //I8xx + 4, 2 }, /* I8xx */ { 75, 120, 10, 20, 5, 9, 4, 7, 5, 80, 1, 8, 1400000, 2800000, 200000, 96000, - 10, 5 } //I9xx + 10, 5 } /* I9xx */ }; -int -intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) +int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) { u32 tmp; if (!pdev || !dinfo) @@ -149,9 +148,8 @@ intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) } } -int -intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, - int *stolen_size) +int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, + int *stolen_size) { struct pci_dev *bridge_dev; u16 tmp; @@ -254,8 +252,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, } } -int -intelfbhw_check_non_crt(struct intelfb_info *dinfo) +int intelfbhw_check_non_crt(struct intelfb_info *dinfo) { int dvo = 0; @@ -271,8 +268,7 @@ intelfbhw_check_non_crt(struct intelfb_info *dinfo) return dvo; } -const char * -intelfbhw_dvo_to_string(int dvo) +const char * intelfbhw_dvo_to_string(int dvo) { if (dvo & DVOA_PORT) return "DVO port A"; @@ -287,9 +283,8 @@ intelfbhw_dvo_to_string(int dvo) } -int -intelfbhw_validate_mode(struct intelfb_info *dinfo, - struct fb_var_screeninfo *var) +int intelfbhw_validate_mode(struct intelfb_info *dinfo, + struct fb_var_screeninfo *var) { int bytes_per_pixel; int tmp; @@ -322,17 +317,26 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo, var->yres, VACTIVE_MASK + 1); return 1; } - - /* Check for interlaced/doublescan modes. */ - if (var->vmode & FB_VMODE_INTERLACED) { - WRN_MSG("Mode is interlaced.\n"); + if (var->xres < 4) { + WRN_MSG("X resolution too small (%d vs 4).\n", var->xres); + return 1; + } + if (var->yres < 4) { + WRN_MSG("Y resolution too small (%d vs 4).\n", var->yres); return 1; } + + /* Check for doublescan modes. */ if (var->vmode & FB_VMODE_DOUBLE) { WRN_MSG("Mode is double-scan.\n"); return 1; } + if ((var->vmode & FB_VMODE_INTERLACED) && (var->yres & 1)) { + WRN_MSG("Odd number of lines in interlaced mode\n"); + return 1; + } + /* Check if clock is OK. */ tmp = 1000000000 / var->pixclock; if (tmp < MIN_CLOCK) { @@ -349,8 +353,7 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo, return 0; } -int -intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_info *dinfo = GET_DINFO(info); u32 offset, xoffset, yoffset; @@ -372,9 +375,10 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) offset += dinfo->fb.offset << 12; dinfo->vsync.pan_offset = offset; - if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) { + if ((var->activate & FB_ACTIVATE_VBL) && + !intelfbhw_enable_irq(dinfo)) dinfo->vsync.pan_display = 1; - } else { + else { dinfo->vsync.pan_display = 0; OUTREG(DSPABASE, offset); } @@ -383,8 +387,7 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) } /* Blank the screen. */ -void -intelfbhw_do_blank(int blank, struct fb_info *info) +void intelfbhw_do_blank(int blank, struct fb_info *info) { struct intelfb_info *dinfo = GET_DINFO(info); u32 tmp; @@ -409,11 +412,10 @@ intelfbhw_do_blank(int blank, struct fb_info *info) DBG_MSG("cursor_on is %d\n", dinfo->cursor_on); #endif if (dinfo->cursor_on) { - if (blank) { + if (blank) intelfbhw_cursor_hide(dinfo); - } else { + else intelfbhw_cursor_show(dinfo); - } dinfo->cursor_on = 1; } dinfo->cursor_blanked = blank; @@ -441,19 +443,18 @@ intelfbhw_do_blank(int blank, struct fb_info *info) } -void -intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, - unsigned red, unsigned green, unsigned blue, - unsigned transp) +void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp) { + u32 palette_reg = (dinfo->pipe == PIPE_A) ? + PALETTE_A : PALETTE_B; + #if VERBOSE > 0 DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n", regno, red, green, blue); #endif - u32 palette_reg = (dinfo->pipe == PIPE_A) ? - PALETTE_A : PALETTE_B; - OUTREG(palette_reg + (regno << 2), (red << PALETTE_8_RED_SHIFT) | (green << PALETTE_8_GREEN_SHIFT) | @@ -461,9 +462,8 @@ intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, } -int -intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, - int flag) +int intelfbhw_read_hw_state(struct intelfb_info *dinfo, + struct intelfb_hwstate *hw, int flag) { int i; @@ -610,7 +610,8 @@ static int calc_vclock3(int index, int m, int n, int p) return plls[index].ref_clk * m / n / p; } -static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds) +static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, + int lvds) { struct pll_min_max *pll = &plls[index]; u32 m, vco, p; @@ -619,17 +620,16 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd n += 2; vco = pll->ref_clk * m / n; - if (index == PLLS_I8xx) { + if (index == PLLS_I8xx) p = ((p1 + 2) * (1 << (p2 + 1))); - } else { + else p = ((p1) * (p2 ? 5 : 10)); - } return vco / p; } #if REGDUMP -static void -intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) +static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, + int *o_p1, int *o_p2) { int p1, p2; @@ -638,7 +638,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) p1 = 1; else p1 = (dpll >> DPLL_P1_SHIFT) & 0xff; - + p1 = ffs(p1); p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK; @@ -656,8 +656,8 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2) #endif -void -intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) +void intelfbhw_print_hw_state(struct intelfb_info *dinfo, + struct intelfb_hwstate *hw) { #if REGDUMP int i, m1, m2, n, p1, p2; @@ -670,7 +670,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) printk("hw state dump start\n"); printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor); printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor); - printk(" VGAPD: 0x%08x\n", hw->vga_pd); + printk(" VGAPD: 0x%08x\n", hw->vga_pd); n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; @@ -689,7 +689,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2); printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", m1, m2, n, p1, p2); - printk(" VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0)); + printk(" VGA1: clock is %d\n", + calc_vclock(index, m1, m2, n, p1, p2, 0)); printk(" DPLL_A: 0x%08x\n", hw->dpll_a); printk(" DPLL_B: 0x%08x\n", hw->dpll_b); @@ -706,7 +707,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", m1, m2, n, p1, p2); - printk(" PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0)); + printk(" PLLA0: clock is %d\n", + calc_vclock(index, m1, m2, n, p1, p2, 0)); n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; @@ -716,7 +718,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", m1, m2, n, p1, p2); - printk(" PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0)); + printk(" PLLA1: clock is %d\n", + calc_vclock(index, m1, m2, n, p1, p2, 0)); #if 0 printk(" PALETTE_A:\n"); @@ -821,8 +824,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) /* Split the M parameter into M1 and M2. */ -static int -splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2) +static int splitm(int index, unsigned int m, unsigned int *retm1, + unsigned int *retm2) { int m1, m2; int testm; @@ -843,8 +846,8 @@ splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2) } /* Split the P parameter into P1 and P2. */ -static int -splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2) +static int splitp(int index, unsigned int p, unsigned int *retp1, + unsigned int *retp2) { int p1, p2; struct pll_min_max *pll = &plls[index]; @@ -878,9 +881,8 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2) } } -static int -calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, - u32 *retp2, u32 *retclock) +static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, + u32 *retn, u32 *retp1, u32 *retp2, u32 *retclock) { u32 m1, m2, n, p1, p2, n1, testm; u32 f_vco, p, p_best = 0, m, f_out = 0; @@ -975,8 +977,8 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re return 0; } -static __inline__ int -check_overflow(u32 value, u32 limit, const char *description) +static __inline__ int check_overflow(u32 value, u32 limit, + const char *description) { if (value > limit) { WRN_MSG("%s value %d exceeds limit %d\n", @@ -987,9 +989,9 @@ check_overflow(u32 value, u32 limit, const char *description) } /* It is assumed that hw is filled in with the initial state information. */ -int -intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, - struct fb_var_screeninfo *var) +int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, + struct intelfb_hwstate *hw, + struct fb_var_screeninfo *var) { int pipe = PIPE_A; u32 *dpll, *fp0, *fp1; @@ -1093,9 +1095,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, if (IS_I9XX(dinfo)) { *dpll |= (p2 << DPLL_I9XX_P2_SHIFT); *dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT; - } else { + } else *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT); - } *fp0 = (n << FP_N_DIVISOR_SHIFT) | (m1 << FP_M1_DIVISOR_SHIFT) | @@ -1139,6 +1140,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, hblank_end); vactive = var->yres; + if (var->vmode & FB_VMODE_INTERLACED) + vactive--; /* the chip adds 2 halflines automatically */ vsync_start = vactive + var->lower_margin; vsync_end = vsync_start + var->vsync_len; vtotal = vsync_end + var->upper_margin; @@ -1220,19 +1223,24 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, /* Set the palette to 8-bit mode. */ *pipe_conf &= ~PIPECONF_GAMMA; + + if (var->vmode & FB_VMODE_INTERLACED) + *pipe_conf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; + else + *pipe_conf &= ~PIPECONF_INTERLACE_MASK; + return 0; } /* Program a (non-VGA) video mode. */ -int -intelfbhw_program_mode(struct intelfb_info *dinfo, - const struct intelfb_hwstate *hw, int blank) +int intelfbhw_program_mode(struct intelfb_info *dinfo, + const struct intelfb_hwstate *hw, int blank) { int pipe = PIPE_A; u32 tmp; const u32 *dpll, *fp0, *fp1, *pipe_conf; const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; - u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg; + u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg, pipe_stat_reg; u32 hsync_reg, htotal_reg, hblank_reg; u32 vsync_reg, vtotal_reg, vblank_reg; u32 src_size_reg; @@ -1273,6 +1281,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, fp0_reg = FPB0; fp1_reg = FPB1; pipe_conf_reg = PIPEBCONF; + pipe_stat_reg = PIPEBSTAT; hsync_reg = HSYNC_B; htotal_reg = HTOTAL_B; hblank_reg = HBLANK_B; @@ -1296,6 +1305,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, fp0_reg = FPA0; fp1_reg = FPA1; pipe_conf_reg = PIPEACONF; + pipe_stat_reg = PIPEASTAT; hsync_reg = HSYNC_A; htotal_reg = HTOTAL_A; hblank_reg = HBLANK_A; @@ -1312,8 +1322,8 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, count = 0; do { - tmp_val[count%3] = INREG(0x70000); - if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2])) + tmp_val[count % 3] = INREG(PIPEA_DSL); + if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1] == tmp_val[2])) break; count++; udelay(1); @@ -1322,7 +1332,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, tmp &= ~PIPECONF_ENABLE; OUTREG(pipe_conf_reg, tmp); } - } while(count < 2000); + } while (count < 2000); OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE); @@ -1382,6 +1392,17 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, OUTREG(vtotal_reg, *vt); OUTREG(src_size_reg, *ss); + switch (dinfo->info->var.vmode & (FB_VMODE_INTERLACED | + FB_VMODE_ODD_FLD_FIRST)) { + case FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST: + OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_ODD_EN); + break; + case FB_VMODE_INTERLACED: /* even lines first */ + OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_EVEN_EN); + break; + default: /* non-interlaced */ + OUTREG(pipe_stat_reg, 0xFFFF); /* clear all status bits only */ + } /* Enable pipe */ OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); @@ -1446,8 +1467,7 @@ static u32 get_ring_space(struct intelfb_info *dinfo) return ring_space; } -static int -wait_ring(struct intelfb_info *dinfo, int n) +static int wait_ring(struct intelfb_info *dinfo, int n) { int i = 0; unsigned long end; @@ -1489,16 +1509,15 @@ wait_ring(struct intelfb_info *dinfo, int n) return i; } -static void -do_flush(struct intelfb_info *dinfo) { +static void do_flush(struct intelfb_info *dinfo) +{ START_RING(2); OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); OUT_RING(MI_NOOP); ADVANCE_RING(); } -void -intelfbhw_do_sync(struct intelfb_info *dinfo) +void intelfbhw_do_sync(struct intelfb_info *dinfo) { #if VERBOSE > 0 DBG_MSG("intelfbhw_do_sync\n"); @@ -1517,8 +1536,7 @@ intelfbhw_do_sync(struct intelfb_info *dinfo) dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE; } -static void -refresh_ring(struct intelfb_info *dinfo) +static void refresh_ring(struct intelfb_info *dinfo) { #if VERBOSE > 0 DBG_MSG("refresh_ring\n"); @@ -1529,8 +1547,7 @@ refresh_ring(struct intelfb_info *dinfo) dinfo->ring_space = get_ring_space(dinfo); } -static void -reset_state(struct intelfb_info *dinfo) +static void reset_state(struct intelfb_info *dinfo) { int i; u32 tmp; @@ -1560,12 +1577,11 @@ reset_state(struct intelfb_info *dinfo) } /* Stop the 2D engine, and turn off the ring buffer. */ -void -intelfbhw_2d_stop(struct intelfb_info *dinfo) +void intelfbhw_2d_stop(struct intelfb_info *dinfo) { #if VERBOSE > 0 - DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel, - dinfo->ring_active); + DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", + dinfo->accel, dinfo->ring_active); #endif if (!dinfo->accel) @@ -1580,8 +1596,7 @@ intelfbhw_2d_stop(struct intelfb_info *dinfo) * It is assumed that the graphics engine has been stopped by previously * calling intelfb_2d_stop(). */ -void -intelfbhw_2d_start(struct intelfb_info *dinfo) +void intelfbhw_2d_start(struct intelfb_info *dinfo) { #if VERBOSE > 0 DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", @@ -1605,9 +1620,8 @@ intelfbhw_2d_start(struct intelfb_info *dinfo) } /* 2D fillrect (solid fill or invert) */ -void -intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h, - u32 color, u32 pitch, u32 bpp, u32 rop) +void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, + u32 h, u32 color, u32 pitch, u32 bpp, u32 rop) { u32 br00, br09, br13, br14, br16; @@ -1696,9 +1710,9 @@ intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury, ADVANCE_RING(); } -int -intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, - u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp) +int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, + u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, + u32 bpp) { int nbytes, ndwords, pad, tmp; u32 br00, br09, br13, br18, br19, br22, br23; @@ -1785,8 +1799,7 @@ intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, } /* HW cursor functions. */ -void -intelfbhw_cursor_init(struct intelfb_info *dinfo) +void intelfbhw_cursor_init(struct intelfb_info *dinfo) { u32 tmp; @@ -1817,8 +1830,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo) } } -void -intelfbhw_cursor_hide(struct intelfb_info *dinfo) +void intelfbhw_cursor_hide(struct intelfb_info *dinfo) { u32 tmp; @@ -1843,8 +1855,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo) } } -void -intelfbhw_cursor_show(struct intelfb_info *dinfo) +void intelfbhw_cursor_show(struct intelfb_info *dinfo) { u32 tmp; @@ -1873,8 +1884,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo) } } -void -intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) +void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) { u32 tmp; @@ -1892,13 +1902,11 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); OUTREG(CURSOR_A_POSITION, tmp); - if (IS_I9XX(dinfo)) { + if (IS_I9XX(dinfo)) OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical); - } } -void -intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) +void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) { #if VERBOSE > 0 DBG_MSG("intelfbhw_cursor_setcolor\n"); @@ -1910,9 +1918,8 @@ intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg) OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK); } -void -intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, - u8 *data) +void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, + u8 *data) { u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; int i, j, w = width / 8; @@ -1940,8 +1947,8 @@ intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, } } -void -intelfbhw_cursor_reset(struct intelfb_info *dinfo) { +void intelfbhw_cursor_reset(struct intelfb_info *dinfo) +{ u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; int i, j; @@ -1961,72 +1968,72 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) { } } -static irqreturn_t -intelfbhw_irq(int irq, void *dev_id) { - int handled = 0; +static irqreturn_t intelfbhw_irq(int irq, void *dev_id) +{ u16 tmp; struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; spin_lock(&dinfo->int_lock); tmp = INREG16(IIR); - tmp &= VSYNC_PIPE_A_INTERRUPT; + if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) + tmp &= PIPE_A_EVENT_INTERRUPT; + else + tmp &= VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ if (tmp == 0) { spin_unlock(&dinfo->int_lock); - return IRQ_RETVAL(handled); + return IRQ_RETVAL(0); /* not us */ } - OUTREG16(IIR, tmp); + /* clear status bits 0-15 ASAP and don't touch bits 16-31 */ + OUTREG(PIPEASTAT, INREG(PIPEASTAT)); - if (tmp & VSYNC_PIPE_A_INTERRUPT) { - dinfo->vsync.count++; - if (dinfo->vsync.pan_display) { - dinfo->vsync.pan_display = 0; - OUTREG(DSPABASE, dinfo->vsync.pan_offset); - } - wake_up_interruptible(&dinfo->vsync.wait); - handled = 1; + OUTREG16(IIR, tmp); + if (dinfo->vsync.pan_display) { + dinfo->vsync.pan_display = 0; + OUTREG(DSPABASE, dinfo->vsync.pan_offset); } + dinfo->vsync.count++; + wake_up_interruptible(&dinfo->vsync.wait); + spin_unlock(&dinfo->int_lock); - return IRQ_RETVAL(handled); + return IRQ_RETVAL(1); } -int -intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) { - +int intelfbhw_enable_irq(struct intelfb_info *dinfo) +{ + u16 tmp; if (!test_and_set_bit(0, &dinfo->irq_flags)) { if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, - "intelfb", dinfo)) { + "intelfb", dinfo)) { clear_bit(0, &dinfo->irq_flags); return -EINVAL; } spin_lock_irq(&dinfo->int_lock); - OUTREG16(HWSTAM, 0xfffe); - OUTREG16(IMR, 0x0); - OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT); - spin_unlock_irq(&dinfo->int_lock); - } else if (reenable) { - u16 ier; - + OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */ + OUTREG16(IMR, 0); + } else spin_lock_irq(&dinfo->int_lock); - ier = INREG16(IER); - if ((ier & VSYNC_PIPE_A_INTERRUPT)) { - DBG_MSG("someone disabled the IRQ [%08X]\n", ier); - OUTREG(IER, VSYNC_PIPE_A_INTERRUPT); - } - spin_unlock_irq(&dinfo->int_lock); + + if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) + tmp = PIPE_A_EVENT_INTERRUPT; + else + tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ + if (tmp != INREG16(IER)) { + DBG_MSG("changing IER to 0x%X\n", tmp); + OUTREG16(IER, tmp); } + + spin_unlock_irq(&dinfo->int_lock); return 0; } -void -intelfbhw_disable_irq(struct intelfb_info *dinfo) { - u16 tmp; - +void intelfbhw_disable_irq(struct intelfb_info *dinfo) +{ if (test_and_clear_bit(0, &dinfo->irq_flags)) { if (dinfo->vsync.pan_display) { dinfo->vsync.pan_display = 0; @@ -2037,16 +2044,15 @@ intelfbhw_disable_irq(struct intelfb_info *dinfo) { OUTREG16(IMR, 0xffff); OUTREG16(IER, 0x0); - tmp = INREG16(IIR); - OUTREG16(IIR, tmp); + OUTREG16(IIR, INREG16(IIR)); /* clear IRQ requests */ spin_unlock_irq(&dinfo->int_lock); free_irq(dinfo->pdev->irq, dinfo); } } -int -intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) { +int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) +{ struct intelfb_vsync *vsync; unsigned int count; int ret; @@ -2059,18 +2065,16 @@ intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) { return -ENODEV; } - ret = intelfbhw_enable_irq(dinfo, 0); - if (ret) { + ret = intelfbhw_enable_irq(dinfo); + if (ret) return ret; - } count = vsync->count; - ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10); - if (ret < 0) { + ret = wait_event_interruptible_timeout(vsync->wait, + count != vsync->count, HZ / 10); + if (ret < 0) return ret; - } if (ret == 0) { - intelfbhw_enable_irq(dinfo, 1); DBG_MSG("wait_for_vsync timed out!\n"); return -ETIMEDOUT; } diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 8c54ba8fbdd..0b076bac321 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -83,7 +83,7 @@ */ #define RING_MIN_FREE 64 -#define IPEHR 0x2088 +#define IPEHR 0x2088 #define INSTDONE 0x2090 #define PRI_RING_EMPTY 1 @@ -93,7 +93,7 @@ #define IIR 0x20A4 #define IMR 0x20A8 #define VSYNC_PIPE_A_INTERRUPT (1 << 7) -#define PIPE_A_EVENT_INTERRUPT (1 << 4) +#define PIPE_A_EVENT_INTERRUPT (1 << 6) #define VSYNC_PIPE_B_INTERRUPT (1 << 5) #define PIPE_B_EVENT_INTERRUPT (1 << 4) #define HOST_PORT_EVENT_INTERRUPT (1 << 3) @@ -128,9 +128,9 @@ #define GPIOA 0x5010 #define GPIOB 0x5014 -#define GPIOC 0x5018 // this may be external DDC on i830 -#define GPIOD 0x501C // this is DVO DDC -#define GPIOE 0x5020 // this is DVO i2C +#define GPIOC 0x5018 /* this may be external DDC on i830 */ +#define GPIOD 0x501C /* this is DVO DDC */ +#define GPIOE 0x5020 /* this is DVO i2C */ #define GPIOF 0x5024 /* PLL registers */ @@ -269,15 +269,20 @@ #define PORT_ENABLE (1 << 31) #define PORT_PIPE_SELECT_SHIFT 30 #define PORT_TV_FLAGS_MASK 0xFF -#define PORT_TV_FLAGS 0xC4 // ripped from my BIOS - // to understand and correct +#define PORT_TV_FLAGS 0xC4 /* ripped from my BIOS + to understand and correct */ #define DVOA_SRCDIM 0x61124 #define DVOB_SRCDIM 0x61144 #define DVOC_SRCDIM 0x61164 +#define PIPEA_DSL 0x70000 +#define PIPEB_DSL 0x71000 #define PIPEACONF 0x70008 #define PIPEBCONF 0x71008 +#define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */ +#define PIPEBSTAT 0x71024 + #define PIPECONF_ENABLE (1 << 31) #define PIPECONF_DISABLE 0 #define PIPECONF_DOUBLE_WIDE (1 << 30) @@ -286,6 +291,35 @@ #define PIPECONF_UNLOCKED 0 #define PIPECONF_GAMMA (1 << 24) #define PIPECONF_PALETTE 0 +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) +#define PIPECONF_INTERLACE_MASK (7 << 21) + +/* enable bits, write 1 to enable */ +#define PIPESTAT_FIFO_UNDERRUN (1 << 31) +#define PIPESTAT_CRC_ERROR_EN (1 << 29) +#define PIPESTAT_CRC_DONE_EN (1 << 28) +#define PIPESTAT_HOTPLUG_EN (1 << 26) +#define PIPESTAT_VERTICAL_SYNC_EN (1 << 25) +#define PIPESTAT_DISPLINE_COMP_EN (1 << 24) +#define PIPESTAT_FLD_EVT_ODD_EN (1 << 21) +#define PIPESTAT_FLD_EVT_EVEN_EN (1 << 20) +#define PIPESTAT_TV_HOTPLUG_EN (1 << 18) +#define PIPESTAT_VBLANK_EN (1 << 17) +#define PIPESTAT_OVL_UPDATE_EN (1 << 16) +/* status bits, write 1 to clear */ +#define PIPESTAT_HOTPLUG_STATE (1 << 15) +#define PIPESTAT_CRC_ERROR (1 << 13) +#define PIPESTAT_CRC_DONE (1 << 12) +#define PIPESTAT_HOTPLUG (1 << 10) +#define PIPESTAT_VSYNC (1 << 9) +#define PIPESTAT_DISPLINE_COMP (1 << 8) +#define PIPESTAT_FLD_EVT_ODD (1 << 5) +#define PIPESTAT_FLD_EVT_EVEN (1 << 4) +#define PIPESTAT_TV_HOTPLUG (1 << 2) +#define PIPESTAT_VBLANK (1 << 1) +#define PIPESTAT_OVL_UPDATE (1 << 0) #define DISPARB 0x70030 #define DISPARB_AEND_MASK 0x1ff @@ -365,7 +399,7 @@ #define DISPPLANE_8BPP (0x2<<26) #define DISPPLANE_15_16BPP (0x4<<26) #define DISPPLANE_16BPP (0x5<<26) -#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) #define DISPPLANE_32BPP (0x7<<26) #define DISPPLANE_STEREO_ENABLE (1<<25) #define DISPPLANE_STEREO_DISABLE 0 @@ -567,7 +601,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, u8 *data); extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); -extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable); +extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c index 1c557990739..acb9370fdb1 100644 --- a/drivers/video/kyro/fbdev.c +++ b/drivers/video/kyro/fbdev.c @@ -21,7 +21,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #ifdef CONFIG_MTRR #include <asm/mtrr.h> #endif diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 2b0f799aa8d..a9283bae779 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -34,6 +34,10 @@ extern const struct linux_logo logo_superh_vga16; extern const struct linux_logo logo_superh_clut224; extern const struct linux_logo logo_m32r_clut224; +static int nologo; +module_param(nologo, bool, 0); +MODULE_PARM_DESC(nologo, "Disables startup logo"); + /* logo's are marked __initdata. Use __init_refok to tell * modpost that it is intended that this function uses data * marked __initdata. @@ -42,6 +46,9 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) { const struct linux_logo *logo = NULL; + if (nologo) + return NULL; + if (depth >= 1) { #ifdef CONFIG_LOGO_LINUX_MONO /* Generic Linux logo */ diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 86ca7b17900..b25972ac6ee 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -113,7 +113,7 @@ #include "matroxfb_g450.h" #include <linux/matroxfb.h> #include <linux/interrupt.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #ifdef CONFIG_PPC_PMAC #include <asm/machdep.h> diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 4b3344e0369..a6ab5b6a58d 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -15,7 +15,7 @@ #include "matroxfb_misc.h" #include "matroxfb_DAC1064.h" #include <linux/matroxfb.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> /* **************************************************** */ diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c index 4d610b405d4..6209a761f67 100644 --- a/drivers/video/matrox/matroxfb_g450.c +++ b/drivers/video/matrox/matroxfb_g450.c @@ -17,7 +17,6 @@ #include "matroxfb_DAC1064.h" #include "g450_pll.h" #include <linux/matroxfb.h> -#include <asm/uaccess.h> #include <asm/div64.h> #include "matroxfb_g450.h" diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index de0d755f901..49cd53e46c0 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -18,7 +18,6 @@ #include <linux/i2c.h> #include <linux/matroxfb.h> #include <asm/div64.h> -#include <asm/uaccess.h> #define MAVEN_I2CID (0x1B) diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 980d5f62390..80cd117ca65 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c @@ -1,7 +1,7 @@ /* * linux/drivers/video/mbx/mbxfb.c * - * Copyright (C) 2006 8D Technologies inc + * Copyright (C) 2006-2007 8D Technologies inc * Raphael Assenat <raph@8d.com> * - Added video overlay support * - Various improvements @@ -334,8 +334,8 @@ static int mbxfb_blank(int blank, struct fb_info *info) static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) { - u32 vsctrl, vbbase, vscadr, vsadr; - u32 sssize, spoctrl, svctrl, shctrl; + u32 vsctrl, vscadr, vsadr; + u32 sssize, spoctrl, shctrl; u32 vubase, vvbase; u32 vovrclk; @@ -349,13 +349,11 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) vscadr = readl(VSCADR); vubase = readl(VUBASE); vvbase = readl(VVBASE); + shctrl = readl(SHCTRL); spoctrl = readl(SPOCTRL); sssize = readl(SSSIZE); - - vbbase = Vbbase_Glalpha(set->alpha); - vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) | FMsk(VSCTRL_VSHEIGHT) | FMsk(VSCTRL_VPIXFMT) | @@ -364,38 +362,41 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) | VSCTRL_CSC_EN; - vscadr &= ~(VSCADR_STR_EN | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC | - FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) | - FMsk(VSCADR_VBASE_ADR) ); + vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) ); vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR)); vvbase &= ~(FMsk(VVBASE_VBASE_ADR)); - switch (set->fmt) - { - case MBXFB_FMT_YUV12: - vsctrl |= VSCTRL_VPIXFMT_YUV12; + switch (set->fmt) { + case MBXFB_FMT_YUV16: + vsctrl |= VSCTRL_VPIXFMT_YUV12; - set->Y_stride = ((set->width) + 0xf ) & ~0xf; + set->Y_stride = ((set->width) + 0xf ) & ~0xf; + break; + case MBXFB_FMT_YUV12: + vsctrl |= VSCTRL_VPIXFMT_YUV12; + set->Y_stride = ((set->width) + 0xf ) & ~0xf; + vubase |= VUBASE_UVHALFSTR; + + break; + case MBXFB_FMT_UY0VY1: + vsctrl |= VSCTRL_VPIXFMT_UY0VY1; + set->Y_stride = (set->width*2 + 0xf ) & ~0xf; + break; + case MBXFB_FMT_VY0UY1: + vsctrl |= VSCTRL_VPIXFMT_VY0UY1; + set->Y_stride = (set->width*2 + 0xf ) & ~0xf; + break; + case MBXFB_FMT_Y0UY1V: + vsctrl |= VSCTRL_VPIXFMT_Y0UY1V; + set->Y_stride = (set->width*2 + 0xf ) & ~0xf; + break; + case MBXFB_FMT_Y0VY1U: + vsctrl |= VSCTRL_VPIXFMT_Y0VY1U; + set->Y_stride = (set->width*2 + 0xf ) & ~0xf; break; - case MBXFB_FMT_UY0VY1: - vsctrl |= VSCTRL_VPIXFMT_UY0VY1; - set->Y_stride = (set->width*2 + 0xf ) & ~0xf; - break; - case MBXFB_FMT_VY0UY1: - vsctrl |= VSCTRL_VPIXFMT_VY0UY1; - set->Y_stride = (set->width*2 + 0xf ) & ~0xf; - break; - case MBXFB_FMT_Y0UY1V: - vsctrl |= VSCTRL_VPIXFMT_Y0UY1V; - set->Y_stride = (set->width*2 + 0xf ) & ~0xf; - break; - case MBXFB_FMT_Y0VY1U: - vsctrl |= VSCTRL_VPIXFMT_Y0VY1U; - set->Y_stride = (set->width*2 + 0xf ) & ~0xf; - break; - default: - return -EINVAL; + default: + return -EINVAL; } /* VSCTRL has the bits which sets the Video Pixel Format. @@ -417,8 +418,7 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) (0x60000 + set->mem_offset + set->V_offset)>>3); - vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_GLOB | - Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4); + vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4); if (set->enable) vscadr |= VSCADR_STR_EN; @@ -433,9 +433,8 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C | - FMsk(SPOCTRL_VORDER) | FMsk(SPOCTRL_VPITCH)); - spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height) - | SPOCTRL_VORDER_2TAP; + FMsk(SPOCTRL_VPITCH)); + spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height); /* Bypass horiz/vert scaler when same size */ if (set->scaled_width == set->width) @@ -443,14 +442,11 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) if (set->scaled_height == set->height) spoctrl |= SPOCTRL_V_SC_BP; - svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); - - shctrl = Shctrl_Hinitial(4<<11) - | Shctrl_Hpitch((set->width<<11)/set->scaled_width); + shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM); + shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width); /* Video plane registers */ write_reg(vsctrl, VSCTRL); - write_reg(vbbase, VBBASE); write_reg(vscadr, VSCADR); write_reg(vubase, VUBASE); write_reg(vvbase, VVBASE); @@ -459,28 +455,8 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) /* Video scaler registers */ write_reg(sssize, SSSIZE); write_reg(spoctrl, SPOCTRL); - write_reg(svctrl, SVCTRL); write_reg(shctrl, SHCTRL); - /* RAPH: Using those coefficients, the scaled - * image is quite blurry. I dont know how - * to improve them ; The chip documentation - * was not helpful.. */ - write_reg(0x21212121, VSCOEFF0); - write_reg(0x21212121, VSCOEFF1); - write_reg(0x21212121, VSCOEFF2); - write_reg(0x21212121, VSCOEFF3); - write_reg(0x21212121, VSCOEFF4); - write_reg(0x00000000, HSCOEFF0); - write_reg(0x00000000, HSCOEFF1); - write_reg(0x00000000, HSCOEFF2); - write_reg(0x03020201, HSCOEFF3); - write_reg(0x09070604, HSCOEFF4); - write_reg(0x0f0e0c0a, HSCOEFF5); - write_reg(0x15141211, HSCOEFF6); - write_reg(0x19181716, HSCOEFF7); - write_reg(0x00000019, HSCOEFF8); - /* Clock */ if (set->enable) vovrclk |= 1; @@ -492,27 +468,206 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) return 0; } +static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder) +{ + unsigned long gscadr, vscadr; + + if (porder->bottom == porder->top) + return -EINVAL; + + gscadr = readl(GSCADR); + vscadr = readl(VSCADR); + + gscadr &= ~(FMsk(GSCADR_BLEND_POS)); + vscadr &= ~(FMsk(VSCADR_BLEND_POS)); + + switch (porder->bottom) { + case MBXFB_PLANE_GRAPHICS: + gscadr |= GSCADR_BLEND_GFX; + break; + case MBXFB_PLANE_VIDEO: + vscadr |= VSCADR_BLEND_GFX; + break; + default: + return -EINVAL; + } + + switch (porder->top) { + case MBXFB_PLANE_GRAPHICS: + gscadr |= GSCADR_BLEND_VID; + break; + case MBXFB_PLANE_VIDEO: + vscadr |= GSCADR_BLEND_VID; + break; + default: + return -EINVAL; + } + + write_reg_dly(vscadr, VSCADR); + write_reg_dly(gscadr, GSCADR); + + return 0; + +} + +static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha) +{ + unsigned long vscadr, vbbase, vcmsk; + unsigned long gscadr, gbbase, gdrctrl; + + vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) | + Vbbase_Colkey(alpha->overlay_colorkey); + + gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) | + Gbbase_Colkey(alpha->graphics_colorkey); + + vcmsk = readl(VCMSK); + vcmsk &= ~(FMsk(VCMSK_COLKEY_M)); + vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask); + + gdrctrl = readl(GDRCTRL); + gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM)); + gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask); + + vscadr = readl(VSCADR); + vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN); + + gscadr = readl(GSCADR); + gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC); + + switch (alpha->overlay_colorkey_mode) { + case MBXFB_COLORKEY_DISABLED: + break; + case MBXFB_COLORKEY_PREVIOUS: + vscadr |= VSCADR_COLKEY_EN; + break; + case MBXFB_COLORKEY_CURRENT: + vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC; + break; + default: + return -EINVAL; + } + + switch (alpha->overlay_blend_mode) { + case MBXFB_ALPHABLEND_NONE: + vscadr |= VSCADR_BLEND_NONE; + break; + case MBXFB_ALPHABLEND_GLOBAL: + vscadr |= VSCADR_BLEND_GLOB; + break; + case MBXFB_ALPHABLEND_PIXEL: + vscadr |= VSCADR_BLEND_PIX; + break; + default: + return -EINVAL; + } + + switch (alpha->graphics_colorkey_mode) { + case MBXFB_COLORKEY_DISABLED: + break; + case MBXFB_COLORKEY_PREVIOUS: + gscadr |= GSCADR_COLKEY_EN; + break; + case MBXFB_COLORKEY_CURRENT: + gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC; + break; + default: + return -EINVAL; + } + + switch (alpha->graphics_blend_mode) { + case MBXFB_ALPHABLEND_NONE: + gscadr |= GSCADR_BLEND_NONE; + break; + case MBXFB_ALPHABLEND_GLOBAL: + gscadr |= GSCADR_BLEND_GLOB; + break; + case MBXFB_ALPHABLEND_PIXEL: + gscadr |= GSCADR_BLEND_PIX; + break; + default: + return -EINVAL; + } + + write_reg_dly(vbbase, VBBASE); + write_reg_dly(gbbase, GBBASE); + write_reg_dly(vcmsk, VCMSK); + write_reg_dly(gdrctrl, GDRCTRL); + write_reg_dly(gscadr, GSCADR); + write_reg_dly(vscadr, VSCADR); + + return 0; +} + static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct mbxfb_overlaySetup setup; + struct mbxfb_overlaySetup setup; + struct mbxfb_planeorder porder; + struct mbxfb_alphaCtl alpha; + struct mbxfb_reg reg; int res; + __u32 tmp; - if (cmd == MBXFB_IOCX_OVERLAY) + switch (cmd) { - if (copy_from_user(&setup, (void __user*)arg, - sizeof(struct mbxfb_overlaySetup))) + case MBXFB_IOCX_OVERLAY: + if (copy_from_user(&setup, (void __user*)arg, + sizeof(struct mbxfb_overlaySetup))) + return -EFAULT; + + res = mbxfb_setupOverlay(&setup); + if (res) + return res; + + if (copy_to_user((void __user*)arg, &setup, + sizeof(struct mbxfb_overlaySetup))) + return -EFAULT; + + return 0; + + case MBXFB_IOCS_PLANEORDER: + if (copy_from_user(&porder, (void __user*)arg, + sizeof(struct mbxfb_planeorder))) return -EFAULT; - res = mbxfb_setupOverlay(&setup); - if (res) - return res; + return mbxfb_ioctl_planeorder(&porder); - if (copy_to_user((void __user*)arg, &setup, - sizeof(struct mbxfb_overlaySetup))) + case MBXFB_IOCS_ALPHA: + if (copy_from_user(&alpha, (void __user*)arg, + sizeof(struct mbxfb_alphaCtl))) return -EFAULT; - return 0; + return mbxfb_ioctl_alphactl(&alpha); + + case MBXFB_IOCS_REG: + if (copy_from_user(®, (void __user*)arg, + sizeof(struct mbxfb_reg))) + return -EFAULT; + + if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ + return -EINVAL; + + tmp = readl(virt_base_2700 + reg.addr); + tmp &= ~reg.mask; + tmp |= reg.val & reg.mask; + writel(tmp, virt_base_2700 + reg.addr); + + return 0; + case MBXFB_IOCX_REG: + if (copy_from_user(®, (void __user*)arg, + sizeof(struct mbxfb_reg))) + return -EFAULT; + + if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ + return -EINVAL; + reg.val = readl(virt_base_2700 + reg.addr); + + if (copy_to_user((void __user*)arg, ®, + sizeof(struct mbxfb_reg))) + return -EFAULT; + + return 0; } return -EINVAL; } @@ -558,7 +713,6 @@ static void __devinit setup_memc(struct fb_info *fbi) LMTYPE); /* enable memory controller */ write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); - /* perform dummy reads */ for ( i = 0; i < 16; i++ ) { tmp = readl(fbi->screen_base); @@ -588,8 +742,8 @@ static void enable_clocks(struct fb_info *fbi) write_reg_dly(0x00000000, VOVRCLK); write_reg_dly(PIXCLK_EN, PIXCLK); write_reg_dly(MEMCLK_EN, MEMCLK); - write_reg_dly(0x00000006, M24CLK); - write_reg_dly(0x00000006, MBXCLK); + write_reg_dly(0x00000001, M24CLK); + write_reg_dly(0x00000001, MBXCLK); write_reg_dly(SDCLK_EN, SDCLK); write_reg_dly(0x00000001, PIXCLKDIV); } @@ -597,6 +751,7 @@ static void enable_clocks(struct fb_info *fbi) static void __devinit setup_graphics(struct fb_info *fbi) { unsigned long gsctrl; + unsigned long vscadr; gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) | Gsctrl_Height(fbi->var.yres); @@ -620,6 +775,11 @@ static void __devinit setup_graphics(struct fb_info *fbi) write_reg_dly(0x00ffffff, GDRCTRL); write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); write_reg_dly(0x00000000, GPLUT); + + vscadr = readl(VSCADR); + vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M)); + vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE; + write_reg_dly(vscadr, VSCADR); } static void __devinit setup_display(struct fb_info *fbi) @@ -638,13 +798,47 @@ static void __devinit setup_display(struct fb_info *fbi) static void __devinit enable_controller(struct fb_info *fbi) { + u32 svctrl, shctrl; + write_reg_dly(SYSRST_RST, SYSRST); + /* setup a timeout, raise drive strength */ + write_reg_dly(0xffffff0c, SYSCFG); enable_clocks(fbi); setup_memc(fbi); setup_graphics(fbi); setup_display(fbi); + + shctrl = readl(SHCTRL); + shctrl &= ~(FMsk(SHCTRL_HINITIAL)); + shctrl |= Shctrl_Hinitial(4<<11); + writel(shctrl, SHCTRL); + + svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); + writel(svctrl, SVCTRL); + + writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP + , SPOCTRL); + + /* Those coefficients are good for scaling up. For scaling + * down, the application has to calculate them. */ + write_reg(0xff000100, VSCOEFF0); + write_reg(0xfdfcfdfe, VSCOEFF1); + write_reg(0x170d0500, VSCOEFF2); + write_reg(0x3d372d22, VSCOEFF3); + write_reg(0x00000040, VSCOEFF4); + + write_reg(0xff010100, HSCOEFF0); + write_reg(0x00000000, HSCOEFF1); + write_reg(0x02010000, HSCOEFF2); + write_reg(0x01020302, HSCOEFF3); + write_reg(0xf9fbfe00, HSCOEFF4); + write_reg(0xfbf7f6f7, HSCOEFF5); + write_reg(0x1c110700, HSCOEFF6); + write_reg(0x3e393127, HSCOEFF7); + write_reg(0x00000040, HSCOEFF8); + } #ifdef CONFIG_PM diff --git a/drivers/video/mbx/reg_bits.h b/drivers/video/mbx/reg_bits.h index 9a24fb0c7d4..5f14b4befd7 100644 --- a/drivers/video/mbx/reg_bits.h +++ b/drivers/video/mbx/reg_bits.h @@ -215,7 +215,7 @@ /* GSCADR graphics stream control address register fields */ #define GSCADR_STR_EN (1 << 31) #define GSCADR_COLKEY_EN (1 << 30) -#define GSCADR_COLKEYSCR (1 << 29) +#define GSCADR_COLKEYSRC (1 << 29) #define GSCADR_BLEND_M Fld(2,27) #define GSCADR_BLEND_NONE ((0x0) << FShft(GSCADR_BLEND_M)) #define GSCADR_BLEND_INV ((0x1) << FShft(GSCADR_BLEND_M)) @@ -303,6 +303,67 @@ #define VSADR_YSTART Fld(11,0) #define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART)) +/* VSCTRL - Video Surface Control Register */ +#define VSCTRL_VPIXFMT Fld(4,27) +#define VSCTRL_VPIXFMT_YUV12 ((0x9) << FShft(VSCTRL_VPIXFMT)) +#define VSCTRL_VPIXFMT_UY0VY1 ((0xc) << FShft(VSCTRL_VPIXFMT)) +#define VSCTRL_VPIXFMT_VY0UY1 ((0xd) << FShft(VSCTRL_VPIXFMT)) +#define VSCTRL_VPIXFMT_Y0UY1V ((0xe) << FShft(VSCTRL_VPIXFMT)) +#define VSCTRL_VPIXFMT_Y0VY1U ((0xf) << FShft(VSCTRL_VPIXFMT)) +#define VSCTRL_GAMMA_EN (1 << 26) +#define VSCTRL_CSC_EN (1 << 25) +#define VSCTRL_COSITED (1 << 22) +#define VSCTRL_VSWIDTH Fld(11,11) +#define Vsctrl_Width(Pixels) /* Video Width [1-2048] */ \ + (((Pixels) - 1) << FShft(VSCTRL_VSWIDTH)) +#define VSCTRL_VSHEIGHT Fld(11,0) +#define Vsctrl_Height(Pixels) /* Video Height [1-2048] */ \ + (((Pixels) - 1) << FShft(VSCTRL_VSHEIGHT)) + +/* VBBASE - Video Blending Base Register */ +#define VBBASE_GLALPHA Fld(8,24) +#define Vbbase_Glalpha(x) ((x) << FShft(VBBASE_GLALPHA)) + +#define VBBASE_COLKEY Fld(24,0) +#define Vbbase_Colkey(x) ((x) << FShft(VBBASE_COLKEY)) + +/* VCMSK - Video Color Key Mask Register */ +#define VCMSK_COLKEY_M Fld(24,0) +#define Vcmsk_colkey_m(x) ((x) << FShft(VCMSK_COLKEY_M)) + +/* VSCADR - Video Stream Control Rddress Register */ +#define VSCADR_STR_EN (1 << 31) +#define VSCADR_COLKEY_EN (1 << 30) +#define VSCADR_COLKEYSRC (1 << 29) +#define VSCADR_BLEND_M Fld(2,27) +#define VSCADR_BLEND_NONE ((0x0) << FShft(VSCADR_BLEND_M)) +#define VSCADR_BLEND_INV ((0x1) << FShft(VSCADR_BLEND_M)) +#define VSCADR_BLEND_GLOB ((0x2) << FShft(VSCADR_BLEND_M)) +#define VSCADR_BLEND_PIX ((0x3) << FShft(VSCADR_BLEND_M)) +#define VSCADR_BLEND_POS Fld(2,24) +#define VSCADR_BLEND_GFX ((0x0) << FShft(VSCADR_BLEND_POS)) +#define VSCADR_BLEND_VID ((0x1) << FShft(VSCADR_BLEND_POS)) +#define VSCADR_BLEND_CUR ((0x2) << FShft(VSCADR_BLEND_POS)) +#define VSCADR_VBASE_ADR Fld(23,0) +#define Vscadr_Vbase_Adr(x) ((x) << FShft(VSCADR_VBASE_ADR)) + +/* VUBASE - Video U Base Register */ +#define VUBASE_UVHALFSTR (1 << 31) +#define VUBASE_UBASE_ADR Fld(24,0) +#define Vubase_Ubase_Adr(x) ((x) << FShft(VUBASE_UBASE_ADR)) + +/* VVBASE - Video V Base Register */ +#define VVBASE_VBASE_ADR Fld(24,0) +#define Vvbase_Vbase_Adr(x) ((x) << FShft(VVBASE_VBASE_ADR)) + +/* VSADR - Video Stride Address Register */ +#define VSADR_SRCSTRIDE Fld(10,22) +#define Vsadr_Srcstride(x) ((x) << FShft(VSADR_SRCSTRIDE)) +#define VSADR_XSTART Fld(11,11) +#define Vsadr_Xstart(x) ((x) << FShft(VSADR_XSTART)) +#define VSADR_YSTART Fld(11,0) +#define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART)) + /* HCCTRL - Hardware Cursor Register fields */ #define HCCTRL_CUR_EN (1 << 31) #define HCCTRL_COLKEY_EN (1 << 29) @@ -479,6 +540,30 @@ #define DINTRE_HBLNK1_EN (1 << 1) #define DINTRE_HBLNK0_EN (1 << 0) +/* DINTRS - Display Interrupt Status Register */ +#define DINTRS_CUR_OR_S (1 << 18) +#define DINTRS_STR2_OR_S (1 << 17) +#define DINTRS_STR1_OR_S (1 << 16) +#define DINTRS_CUR_UR_S (1 << 6) +#define DINTRS_STR2_UR_S (1 << 5) +#define DINTRS_STR1_UR_S (1 << 4) +#define DINTRS_VEVENT1_S (1 << 3) +#define DINTRS_VEVENT0_S (1 << 2) +#define DINTRS_HBLNK1_S (1 << 1) +#define DINTRS_HBLNK0_S (1 << 0) + +/* DINTRE - Display Interrupt Enable Register */ +#define DINTRE_CUR_OR_EN (1 << 18) +#define DINTRE_STR2_OR_EN (1 << 17) +#define DINTRE_STR1_OR_EN (1 << 16) +#define DINTRE_CUR_UR_EN (1 << 6) +#define DINTRE_STR2_UR_EN (1 << 5) +#define DINTRE_STR1_UR_EN (1 << 4) +#define DINTRE_VEVENT1_EN (1 << 3) +#define DINTRE_VEVENT0_EN (1 << 2) +#define DINTRE_HBLNK1_EN (1 << 1) +#define DINTRE_HBLNK0_EN (1 << 0) + /* DLSTS - display load status register */ #define DLSTS_RLD_ADONE (1 << 23) diff --git a/drivers/video/mbx/regs.h b/drivers/video/mbx/regs.h index a7c63d865aa..063099d4883 100644 --- a/drivers/video/mbx/regs.h +++ b/drivers/video/mbx/regs.h @@ -30,7 +30,7 @@ #define VOVRCLK __REG_2700G(0x00000044) #define PIXCLK __REG_2700G(0x00000048) #define MEMCLK __REG_2700G(0x0000004c) -#define M24CLK __REG_2700G(0x00000054) +#define M24CLK __REG_2700G(0x00000050) #define MBXCLK __REG_2700G(0x00000054) #define SDCLK __REG_2700G(0x00000058) #define PIXCLKDIV __REG_2700G(0x0000005c) diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 3741ad72940..42f5d76a877 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -27,7 +27,7 @@ #define DPRINTK(fmt, args...) #endif -const char *global_mode_option; +const char *fb_mode_option; /* * Standard video mode definitions (taken from XFree86) @@ -72,7 +72,7 @@ static const struct fb_videomode modedb[] = { 0, FB_VMODE_NONINTERLACED }, { /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ - NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, + NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0, FB_VMODE_INTERLACED }, { /* 800x600 @ 72 Hz, 48.0 kHz hsync */ @@ -120,11 +120,11 @@ static const struct fb_videomode modedb[] = { 0, FB_VMODE_NONINTERLACED }, { /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ - NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, + NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0, FB_VMODE_NONINTERLACED }, { /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ - NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, + NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ @@ -253,7 +253,7 @@ static const struct fb_videomode modedb[] = { FB_VMODE_NONINTERLACED }, { /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ - NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, + NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ @@ -306,7 +306,7 @@ const struct fb_videomode vesa_modes[] = { FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 12 1024x768i-43 VESA */ - { NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, + { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, FB_MODE_IS_VESA }, /* 13 1024x768-60 VESA */ @@ -383,7 +383,7 @@ const struct fb_videomode vesa_modes[] = { { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 33 1920x1440-75 VESA */ - { NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, + { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, }; EXPORT_SYMBOL(vesa_modes); @@ -510,7 +510,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, default_bpp = 8; /* Did the user specify a video mode? */ - if (mode_option || (mode_option = global_mode_option)) { + if (mode_option || (mode_option = fb_mode_option)) { const char *name = mode_option; unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0, refresh_specified = 0; @@ -606,26 +606,43 @@ done: DPRINTK("Trying specified video mode%s %ix%i\n", refresh_specified ? "" : " (ignoring refresh rate)", xres, yres); - diff = refresh; + if (!refresh_specified) { + /* + * If the caller has provided a custom mode database and a + * valid monspecs structure, we look for the mode with the + * highest refresh rate. Otherwise we play it safe it and + * try to find a mode with a refresh rate closest to the + * standard 60 Hz. + */ + if (db != modedb && + info->monspecs.vfmin && info->monspecs.vfmax && + info->monspecs.hfmin && info->monspecs.hfmax && + info->monspecs.dclkmax) { + refresh = 1000; + } else { + refresh = 60; + } + } + + diff = -1; best = -1; for (i = 0; i < dbsize; i++) { - if (name_matches(db[i], name, namelen) || - (res_specified && res_matches(db[i], xres, yres))) { - if(!fb_try_mode(var, info, &db[i], bpp)) { - if(!refresh_specified || db[i].refresh == refresh) - return 1; - else { - if(diff > abs(db[i].refresh - refresh)) { - diff = abs(db[i].refresh - refresh); - best = i; - } + if ((name_matches(db[i], name, namelen) || + (res_specified && res_matches(db[i], xres, yres))) && + !fb_try_mode(var, info, &db[i], bpp)) { + if (refresh_specified && db[i].refresh == refresh) { + return 1; + } else { + if (abs(db[i].refresh - refresh) < diff) { + diff = abs(db[i].refresh - refresh); + best = i; } } } } if (best != -1) { fb_try_mode(var, info, &db[best], bpp); - return 2; + return (refresh_specified) ? 2 : 1; } diff = xres + yres; @@ -938,6 +955,7 @@ void fb_destroy_modelist(struct list_head *head) kfree(pos); } } +EXPORT_SYMBOL_GPL(fb_destroy_modelist); /** * fb_videomode_to_modelist: convert mode array to mode list diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 731d7a5c5aa..4b6a99b5be0 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -72,7 +72,6 @@ #include <asm/irq.h> #include <asm/pgtable.h> #include <asm/system.h> -#include <asm/uaccess.h> #ifdef CONFIG_MTRR #include <asm/mtrr.h> diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index afe4567e1ff..6fd7cb8f9b8 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -125,11 +125,13 @@ void nvidia_create_i2c_busses(struct nvidia_par *par) par->chan[1].par = par; par->chan[2].par = par; - par->chan[0].ddc_base = 0x36; - nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", I2C_CLASS_HWMON); + par->chan[0].ddc_base = (par->reverse_i2c) ? 0x36 : 0x3e; + nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", + (par->reverse_i2c) ? I2C_CLASS_HWMON : 0); - par->chan[1].ddc_base = 0x3e; - nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", 0); + par->chan[1].ddc_base = (par->reverse_i2c) ? 0x3e : 0x36; + nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", + (par->reverse_i2c) ? 0 : I2C_CLASS_HWMON); par->chan[2].ddc_base = 0x50; nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2", 0); diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index 2fdf77ec39f..f132aab8c5d 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h @@ -135,6 +135,7 @@ struct nvidia_par { int paneltweak; int LVDS; int pm_state; + int reverse_i2c; u32 crtcSync_read; u32 fpSyncs; u32 dmaPut; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index a7fe214f0f7..30e14eb1f51 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -79,6 +79,7 @@ static int noscale __devinitdata = 0; static int paneltweak __devinitdata = 0; static int vram __devinitdata = 0; static int bpp __devinitdata = 8; +static int reverse_i2c __devinitdata; #ifdef CONFIG_MTRR static int nomtrr __devinitdata = 0; #endif @@ -1305,6 +1306,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, par->CRTCnumber = forceCRTC; par->FpScale = (!noscale); par->paneltweak = paneltweak; + par->reverse_i2c = reverse_i2c; /* enable IO and mem if not already done */ pci_read_config_word(pd, PCI_COMMAND, &cmd); @@ -1486,6 +1488,8 @@ static int __devinit nvidiafb_setup(char *options) noaccel = 1; } else if (!strncmp(this_opt, "noscale", 7)) { noscale = 1; + } else if (!strncmp(this_opt, "reverse_i2c", 11)) { + reverse_i2c = 1; } else if (!strncmp(this_opt, "paneltweak:", 11)) { paneltweak = simple_strtoul(this_opt+11, NULL, 0); } else if (!strncmp(this_opt, "vram:", 5)) { @@ -1582,6 +1586,8 @@ MODULE_PARM_DESC(mode_option, "Specify initial video mode"); module_param(bpp, int, 0); MODULE_PARM_DESC(bpp, "pixel width in bits" "(default=8)"); +module_param(reverse_i2c, int, 0); +MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus"); #ifdef CONFIG_MTRR module_param(nomtrr, bool, 0); MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 10c0cc6e93f..5591dfb22b1 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -11,7 +11,7 @@ * and additional input from James Simmon's port of Hannu Mallat's tdfx * driver. * - * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I + * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I * have no access to other pm2fb implementations. Sparc (and thus * hopefully other big-endian) devices now work, thanks to a lot of * testing work by Ron Murray. I have no access to CVision hardware, @@ -38,6 +38,9 @@ #include <linux/fb.h> #include <linux/init.h> #include <linux/pci.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif #include <video/permedia2.h> #include <video/cvisionppc.h> @@ -52,15 +55,19 @@ #undef PM2FB_MASTER_DEBUG #ifdef PM2FB_MASTER_DEBUG -#define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) +#define DPRINTK(a, b...) \ + printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) #else -#define DPRINTK(a,b...) +#define DPRINTK(a, b...) #endif +#define PM2_PIXMAP_SIZE (1600 * 4) + /* * Driver data */ -static char *mode __devinitdata = NULL; +static int hwcursor = 1; +static char *mode __devinitdata; /* * The XFree GLINT driver will (I think to implement hardware cursor @@ -73,6 +80,11 @@ static char *mode __devinitdata = NULL; */ static int lowhsync; static int lowvsync; +static int noaccel __devinitdata; +/* mtrr option */ +#ifdef CONFIG_MTRR +static int nomtrr __devinitdata; +#endif /* * The hardware state of the graphics card that isn't part of the @@ -88,6 +100,7 @@ struct pm2fb_par u32 mem_control; /* MemControl reg at probe */ u32 boot_address; /* BootAddress reg at probe */ u32 palette[16]; + int mtrr_handle; }; /* @@ -135,60 +148,39 @@ static struct fb_var_screeninfo pm2fb_var __devinitdata = { * Utility functions */ -static inline u32 RD32(unsigned char __iomem *base, s32 off) -{ - return fb_readl(base + off); -} - -static inline void WR32(unsigned char __iomem *base, s32 off, u32 v) +static inline u32 pm2_RD(struct pm2fb_par *p, s32 off) { - fb_writel(v, base + off); + return fb_readl(p->v_regs + off); } -static inline u32 pm2_RD(struct pm2fb_par* p, s32 off) +static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v) { - return RD32(p->v_regs, off); + fb_writel(v, p->v_regs + off); } -static inline void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) +static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx) { - WR32(p->v_regs, off, v); + pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); + mb(); + return pm2_RD(p, PM2R_RD_INDEXED_DATA); } -static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) +static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx) { - int index = PM2R_RD_INDEXED_DATA; - switch (p->type) { - case PM2_TYPE_PERMEDIA2: - pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); - break; - case PM2_TYPE_PERMEDIA2V: - pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); - index = PM2VR_RD_INDEXED_DATA; - break; - } + pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); mb(); - return pm2_RD(p, index); + return pm2_RD(p, PM2VR_RD_INDEXED_DATA); } -static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v) { - int index = PM2R_RD_INDEXED_DATA; - switch (p->type) { - case PM2_TYPE_PERMEDIA2: - pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); - break; - case PM2_TYPE_PERMEDIA2V: - pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); - index = PM2VR_RD_INDEXED_DATA; - break; - } + pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); wmb(); - pm2_WR(p, index, v); + pm2_WR(p, PM2R_RD_INDEXED_DATA, v); wmb(); } -static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v) { pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); wmb(); @@ -199,10 +191,10 @@ static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT #define WAIT_FIFO(p, a) #else -static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) +static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a) { - while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a ); - mb(); + while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a) + cpu_relax(); } #endif @@ -238,7 +230,7 @@ static u32 partprod(u32 xres) for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++) ; - if ( pp_table[i].width == 0 ) + if (pp_table[i].width == 0) DPRINTK("invalid width %u\n", xres); return pp_table[i].pp; } @@ -246,25 +238,22 @@ static u32 partprod(u32 xres) static u32 to3264(u32 timing, int bpp, int is64) { switch (bpp) { + case 24: + timing *= 3; case 8: - timing >>= 2 + is64; - break; + timing >>= 1; case 16: - timing >>= 1 + is64; - break; - case 24: - timing = (timing * 3) >> (2 + is64); - break; + timing >>= 1; case 32: - if (is64) - timing >>= 1; break; } + if (is64) + timing >>= 1; return timing; } -static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, - unsigned char* pp) +static void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn, + unsigned char *pp) { unsigned char m; unsigned char n; @@ -278,13 +267,13 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, for (m = 2; m; m++) { f = PM2_REFERENCE_CLOCK * m / n; if (f >= 150000 && f <= 300000) { - for ( p = 0; p < 5; p++, f >>= 1) { - curr = ( clk > f ) ? clk - f : f - clk; - if ( curr < delta ) { - delta=curr; - *mm=m; - *nn=n; - *pp=p; + for (p = 0; p < 5; p++, f >>= 1) { + curr = (clk > f) ? clk - f : f - clk; + if (curr < delta) { + delta = curr; + *mm = m; + *nn = n; + *pp = p; } } } @@ -292,8 +281,8 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, } } -static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, - unsigned char* pp) +static void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn, + unsigned char *pp) { unsigned char m; unsigned char n; @@ -302,23 +291,24 @@ static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, s32 delta = 1000; *mm = *nn = *pp = 0; - for ( m = 1; m < 128; m++) { + for (m = 1; m < 128; m++) { for (n = 2 * m + 1; n; n++) { - for ( p = 0; p < 2; p++) { - f = ( PM2_REFERENCE_CLOCK >> ( p + 1 )) * n / m; - if ( clk > f - delta && clk < f + delta ) { - delta = ( clk > f ) ? clk - f : f - clk; - *mm=m; - *nn=n; - *pp=p; + for (p = 0; p < 2; p++) { + f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m; + if (clk > f - delta && clk < f + delta) { + delta = (clk > f) ? clk - f : f - clk; + *mm = m; + *nn = n; + *pp = p; } } } } } -static void clear_palette(struct pm2fb_par* p) { - int i=256; +static void clear_palette(struct pm2fb_par *p) +{ + int i = 256; WAIT_FIFO(p, 1); pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); @@ -331,14 +321,14 @@ static void clear_palette(struct pm2fb_par* p) { } } -static void reset_card(struct pm2fb_par* p) +static void reset_card(struct pm2fb_par *p) { if (p->type == PM2_TYPE_PERMEDIA2V) pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); pm2_WR(p, PM2R_RESET_STATUS, 0); mb(); while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET) - ; + cpu_relax(); mb(); #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT DPRINTK("FIFO disconnect enabled\n"); @@ -354,11 +344,11 @@ static void reset_card(struct pm2fb_par* p) pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config); } -static void reset_config(struct pm2fb_par* p) +static void reset_config(struct pm2fb_par *p) { - WAIT_FIFO(p, 52); + WAIT_FIFO(p, 53); pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) & - ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); + ~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED)); pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); pm2_WR(p, PM2R_FIFO_CONTROL, 0); @@ -393,31 +383,32 @@ static void reset_config(struct pm2fb_par* p) pm2_WR(p, PM2R_STATISTICS_MODE, 0); pm2_WR(p, PM2R_SCISSOR_MODE, 0); pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); + pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff); switch (p->type) { case PM2_TYPE_PERMEDIA2: pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); + pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); + pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); + pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); + pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); + pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); break; case PM2_TYPE_PERMEDIA2V: pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ break; } - pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); - pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); - pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); - pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); - pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0); } -static void set_aperture(struct pm2fb_par* p, u32 depth) +static void set_aperture(struct pm2fb_par *p, u32 depth) { /* * The hardware is little-endian. When used in big-endian * hosts, the on-chip aperture settings are used where * possible to translate from host to card byte order. */ - WAIT_FIFO(p, 4); + WAIT_FIFO(p, 2); #ifdef __LITTLE_ENDIAN pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); #else @@ -440,11 +431,11 @@ static void set_aperture(struct pm2fb_par* p, u32 depth) } #endif - // We don't use aperture two, so this may be superflous + /* We don't use aperture two, so this may be superflous */ pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD); } -static void set_color(struct pm2fb_par* p, unsigned char regno, +static void set_color(struct pm2fb_par *p, unsigned char regno, unsigned char r, unsigned char g, unsigned char b) { WAIT_FIFO(p, 4); @@ -457,7 +448,7 @@ static void set_color(struct pm2fb_par* p, unsigned char regno, pm2_WR(p, PM2R_RD_PALETTE_DATA, b); } -static void set_memclock(struct pm2fb_par* par, u32 clk) +static void set_memclock(struct pm2fb_par *par, u32 clk) { int i; unsigned char m, n, p; @@ -465,7 +456,7 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) switch (par->type) { case PM2_TYPE_PERMEDIA2V: pm2v_mnp(clk/2, &m, &n, &p); - WAIT_FIFO(par, 8); + WAIT_FIFO(par, 12); pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8); pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0); pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m); @@ -473,10 +464,9 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p); pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1); rmb(); - for (i = 256; - i && !(pm2_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2); - i--) - ; + for (i = 256; i; i--) + if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2) + break; pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); break; case PM2_TYPE_PERMEDIA2: @@ -488,15 +478,14 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); rmb(); - for (i = 256; - i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); - i--) - ; + for (i = 256; i; i--) + if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED) + break; break; } } -static void set_pixclock(struct pm2fb_par* par, u32 clk) +static void set_pixclock(struct pm2fb_par *par, u32 clk) { int i; unsigned char m, n, p; @@ -504,17 +493,16 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk) switch (par->type) { case PM2_TYPE_PERMEDIA2: pm2_mnp(clk, &m, &n, &p); - WAIT_FIFO(par, 8); + WAIT_FIFO(par, 10); pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); rmb(); - for (i = 256; - i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); - i--) - ; + for (i = 256; i; i--) + if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED) + break; break; case PM2_TYPE_PERMEDIA2V: pm2v_mnp(clk/2, &m, &n, &p); @@ -528,11 +516,10 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk) } } -static void set_video(struct pm2fb_par* p, u32 video) { +static void set_video(struct pm2fb_par *p, u32 video) +{ u32 tmp; - u32 vsync; - - vsync = video; + u32 vsync = video; DPRINTK("video = 0x%x\n", video); @@ -542,10 +529,10 @@ static void set_video(struct pm2fb_par* p, u32 video) { * driver may well. So always set +hsync/+vsync and then set * the RAMDAC to invert the sync if necessary. */ - vsync &= ~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK); - vsync |= PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH; + vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK); + vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH; - WAIT_FIFO(p, 5); + WAIT_FIFO(p, 3); pm2_WR(p, PM2R_VIDEO_CONTROL, vsync); switch (p->type) { @@ -564,16 +551,11 @@ static void set_video(struct pm2fb_par* p, u32 video) { if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) tmp |= 4; /* invert vsync */ pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp); - pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); break; } } /* - * - */ - -/** * pm2fb_check_var - Optional function. Validates a var passed in. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer @@ -594,15 +576,22 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } if (var->xres != var->xres_virtual) { - DPRINTK("virtual x resolution != physical x resolution not supported\n"); + DPRINTK("virtual x resolution != " + "physical x resolution not supported\n"); return -EINVAL; } if (var->yres > var->yres_virtual) { - DPRINTK("virtual y resolution < physical y resolution not possible\n"); + DPRINTK("virtual y resolution < " + "physical y resolution not possible\n"); return -EINVAL; } + /* permedia cannot blit over 2048 */ + if (var->yres_virtual > 2047) { + var->yres_virtual = 2047; + } + if (var->xoffset) { DPRINTK("xoffset not supported\n"); return -EINVAL; @@ -614,7 +603,7 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ - lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); + lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); if (var->xres < 320 || var->xres > 1600) { DPRINTK("width not supported: %u\n", var->xres); @@ -633,15 +622,18 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { - DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); + DPRINTK("pixclock too high (%ldKHz)\n", + PICOS2KHZ(var->pixclock)); return -EINVAL; } var->transp.offset = 0; var->transp.length = 0; - switch(var->bits_per_pixel) { + switch (var->bits_per_pixel) { case 8: - var->red.length = var->green.length = var->blue.length = 8; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; break; case 16: var->red.offset = 11; @@ -657,7 +649,9 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; - var->red.length = var->green.length = var->blue.length = 8; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; break; case 24: #ifdef __BIG_ENDIAN @@ -668,10 +662,13 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->blue.offset = 0; #endif var->green.offset = 8; - var->red.length = var->green.length = var->blue.length = 8; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; break; } - var->height = var->width = -1; + var->height = -1; + var->width = -1; var->accel_flags = 0; /* Can't mmap if this is on */ @@ -691,7 +688,9 @@ static int pm2fb_set_par(struct fb_info *info) { struct pm2fb_par *par = info->par; u32 pixclock; - u32 width, height, depth; + u32 width = (info->var.xres_virtual + 7) & ~7; + u32 height = info->var.yres_virtual; + u32 depth = (info->var.bits_per_pixel + 7) & ~7; u32 hsstart, hsend, hbend, htotal; u32 vsstart, vsend, vbend, vtotal; u32 stride; @@ -701,22 +700,19 @@ static int pm2fb_set_par(struct fb_info *info) u32 txtmap = 0; u32 pixsize = 0; u32 clrformat = 0; - u32 xres; + u32 misc = 1; /* 8-bit DAC */ + u32 xres = (info->var.xres + 31) & ~31; int data64; reset_card(par); reset_config(par); clear_palette(par); - if ( par->memclock ) + if (par->memclock) set_memclock(par, par->memclock); - width = (info->var.xres_virtual + 7) & ~7; - height = info->var.yres_virtual; - depth = (info->var.bits_per_pixel + 7) & ~7; depth = (depth > 32) ? 32 : depth; data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V; - xres = (info->var.xres + 31) & ~31; pixclock = PICOS2KHZ(info->var.pixclock); if (pixclock > PM2_MAX_PIXCLOCK) { DPRINTK("pixclock too high (%uKHz)\n", pixclock); @@ -731,7 +727,8 @@ static int pm2fb_set_par(struct fb_info *info) ? info->var.lower_margin - 1 : 0; /* FIXME! */ vsend = info->var.lower_margin + info->var.vsync_len - 1; - vbend = info->var.lower_margin + info->var.vsync_len + info->var.upper_margin; + vbend = info->var.lower_margin + info->var.vsync_len + + info->var.upper_margin; vtotal = info->var.yres + vbend - 1; stride = to3264(width, depth, 1); base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); @@ -744,25 +741,25 @@ static int pm2fb_set_par(struct fb_info *info) video |= PM2F_HSYNC_ACT_LOW; } else video |= PM2F_HSYNC_ACT_HIGH; - } - else + } else video |= PM2F_HSYNC_ACT_LOW; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) { if (lowvsync) { DPRINTK("ignoring +vsync, using -vsync.\n"); video |= PM2F_VSYNC_ACT_LOW; } else video |= PM2F_VSYNC_ACT_HIGH; - } - else + } else video |= PM2F_VSYNC_ACT_LOW; - if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) { + + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { DPRINTK("interlaced not supported\n"); return -EINVAL; } - if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE) + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) video |= PM2F_LINE_DOUBLE; - if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW) + if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) video |= PM2F_VIDEO_ENABLE; par->video = video; @@ -783,12 +780,10 @@ static int pm2fb_set_par(struct fb_info *info) mb(); WAIT_FIFO(par, 19); - pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, - ( depth == 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF); switch (depth) { case 8: pm2_WR(par, PM2R_FB_READ_PIXEL, 0); - clrformat = 0x0e; + clrformat = 0x2e; break; case 16: pm2_WR(par, PM2R_FB_READ_PIXEL, 1); @@ -796,6 +791,7 @@ static int pm2fb_set_par(struct fb_info *info) txtmap = PM2F_TEXTEL_SIZE_16; pixsize = 1; clrformat = 0x70; + misc |= 8; break; case 32: pm2_WR(par, PM2R_FB_READ_PIXEL, 2); @@ -803,6 +799,7 @@ static int pm2fb_set_par(struct fb_info *info) txtmap = PM2F_TEXTEL_SIZE_32; pixsize = 2; clrformat = 0x20; + misc |= 8; break; case 24: pm2_WR(par, PM2R_FB_READ_PIXEL, 4); @@ -810,6 +807,7 @@ static int pm2fb_set_par(struct fb_info *info) txtmap = PM2F_TEXTEL_SIZE_24; pixsize = 4; clrformat = 0x20; + misc |= 8; break; } pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE); @@ -834,14 +832,19 @@ static int pm2fb_set_par(struct fb_info *info) pm2_WR(par, PM2R_SCREEN_BASE, base); wmb(); set_video(par, video); - WAIT_FIFO(par, 4); + WAIT_FIFO(par, 10); switch (par->type) { case PM2_TYPE_PERMEDIA2: pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode); + pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, + (depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF); break; case PM2_TYPE_PERMEDIA2V: + pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0); pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize); pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat); + pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc); + pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0); break; } set_pixclock(par, pixclock); @@ -872,16 +875,15 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, struct pm2fb_par *par = info->par; if (regno >= info->cmap.len) /* no. of hw registers */ - return 1; + return -EINVAL; /* * Program hardware... do anything you want with transp */ /* grayscale works only partially under directcolor */ - if (info->var.grayscale) { - /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + if (info->var.grayscale) red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; - } /* Directcolor: * var->{color}.offset contains start of bitfield @@ -931,7 +933,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, u32 v; if (regno >= 16) - return 1; + return -EINVAL; v = (red << info->var.red.offset) | (green << info->var.green.offset) | @@ -948,8 +950,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, break; } return 0; - } - else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) set_color(par, regno, red, green, blue); return 0; @@ -972,11 +973,9 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var, { struct pm2fb_par *p = info->par; u32 base; - u32 depth; - u32 xres; + u32 depth = (var->bits_per_pixel + 7) & ~7; + u32 xres = (var->xres + 31) & ~31; - xres = (var->xres + 31) & ~31; - depth = (var->bits_per_pixel + 7) & ~7; depth = (depth > 32) ? 32 : depth; base = to3264(var->yoffset * xres + var->xoffset, depth, 1); WAIT_FIFO(p, 1); @@ -1018,15 +1017,15 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info) break; case FB_BLANK_VSYNC_SUSPEND: /* VSync: Off */ - video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW ); + video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW); break; case FB_BLANK_HSYNC_SUSPEND: /* HSync: Off */ - video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW ); + video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW); break; case FB_BLANK_POWERDOWN: /* HSync: Off, VSync: Off */ - video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW); + video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW); break; } set_video(par, video); @@ -1042,48 +1041,20 @@ static int pm2fb_sync(struct fb_info *info) mb(); do { while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0) - udelay(10); - rmb(); + cpu_relax(); } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); return 0; } -/* - * block operation. copy=0: rectangle fill, copy=1: rectangle copy. - */ -static void pm2fb_block_op(struct fb_info* info, int copy, - s32 xsrc, s32 ysrc, - s32 x, s32 y, s32 w, s32 h, - u32 color) { - struct pm2fb_par *par = info->par; - - if (!w || !h) - return; - WAIT_FIFO(par, 5); - pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE | - PM2F_CONFIG_FB_READ_SOURCE_ENABLE); - if (copy) - pm2_WR(par, PM2R_FB_SOURCE_DELTA, - ((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff)); - else - pm2_WR(par, PM2R_FB_BLOCK_COLOR, color); - pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x); - pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w); - wmb(); - pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | - (x<xsrc ? PM2F_INCREASE_X : 0) | - (y<ysrc ? PM2F_INCREASE_Y : 0) | - (copy ? 0 : PM2F_RENDER_FASTFILL)); -} - -static void pm2fb_fillrect (struct fb_info *info, +static void pm2fb_fillrect(struct fb_info *info, const struct fb_fillrect *region) { + struct pm2fb_par *par = info->par; struct fb_fillrect modded; int vxres, vyres; u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? - ((u32*)info->pseudo_palette)[region->color] : region->color; + ((u32 *)info->pseudo_palette)[region->color] : region->color; if (info->state != FBINFO_STATE_RUNNING) return; @@ -1098,31 +1069,46 @@ static void pm2fb_fillrect (struct fb_info *info, memcpy(&modded, region, sizeof(struct fb_fillrect)); - if(!modded.width || !modded.height || - modded.dx >= vxres || modded.dy >= vyres) + if (!modded.width || !modded.height || + modded.dx >= vxres || modded.dy >= vyres) return; - if(modded.dx + modded.width > vxres) + if (modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; - if(modded.dy + modded.height > vyres) + if (modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; - if(info->var.bits_per_pixel == 8) + if (info->var.bits_per_pixel == 8) color |= color << 8; - if(info->var.bits_per_pixel <= 16) + if (info->var.bits_per_pixel <= 16) color |= color << 16; - if(info->var.bits_per_pixel != 24) - pm2fb_block_op(info, 0, 0, 0, - modded.dx, modded.dy, - modded.width, modded.height, color); - else - cfb_fillrect(info, region); + WAIT_FIFO(par, 3); + pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE); + pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx); + pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width); + if (info->var.bits_per_pixel != 24) { + WAIT_FIFO(par, 2); + pm2_WR(par, PM2R_FB_BLOCK_COLOR, color); + wmb(); + pm2_WR(par, PM2R_RENDER, + PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL); + } else { + WAIT_FIFO(par, 4); + pm2_WR(par, PM2R_COLOR_DDA_MODE, 1); + pm2_WR(par, PM2R_CONSTANT_COLOR, color); + wmb(); + pm2_WR(par, PM2R_RENDER, + PM2F_RENDER_RECTANGLE | + PM2F_INCREASE_X | PM2F_INCREASE_Y ); + pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); + } } static void pm2fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { + struct pm2fb_par *par = info->par; struct fb_copyarea modded; u32 vxres, vyres; @@ -1138,23 +1124,359 @@ static void pm2fb_copyarea(struct fb_info *info, vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; - if(!modded.width || !modded.height || - modded.sx >= vxres || modded.sy >= vyres || - modded.dx >= vxres || modded.dy >= vyres) + if (!modded.width || !modded.height || + modded.sx >= vxres || modded.sy >= vyres || + modded.dx >= vxres || modded.dy >= vyres) return; - if(modded.sx + modded.width > vxres) + if (modded.sx + modded.width > vxres) modded.width = vxres - modded.sx; - if(modded.dx + modded.width > vxres) + if (modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; - if(modded.sy + modded.height > vyres) + if (modded.sy + modded.height > vyres) modded.height = vyres - modded.sy; - if(modded.dy + modded.height > vyres) + if (modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; - pm2fb_block_op(info, 1, modded.sx, modded.sy, - modded.dx, modded.dy, - modded.width, modded.height, 0); + WAIT_FIFO(par, 5); + pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE | + PM2F_CONFIG_FB_READ_SOURCE_ENABLE); + pm2_WR(par, PM2R_FB_SOURCE_DELTA, + ((modded.sy - modded.dy) & 0xfff) << 16 | + ((modded.sx - modded.dx) & 0xfff)); + pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx); + pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width); + wmb(); + pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | + (modded.dx < modded.sx ? PM2F_INCREASE_X : 0) | + (modded.dy < modded.sy ? PM2F_INCREASE_Y : 0)); +} + +static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct pm2fb_par *par = info->par; + u32 height = image->height; + u32 fgx, bgx; + const u32 *src = (const u32 *)image->data; + u32 xres = (info->var.xres + 31) & ~31; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) { + cfb_imageblit(info, image); + return; + } + switch (info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + fgx = image->fg_color; + bgx = image->bg_color; + break; + case FB_VISUAL_TRUECOLOR: + default: + fgx = par->palette[image->fg_color]; + bgx = par->palette[image->bg_color]; + break; + } + if (info->var.bits_per_pixel == 8) { + fgx |= fgx << 8; + bgx |= bgx << 8; + } + if (info->var.bits_per_pixel <= 16) { + fgx |= fgx << 16; + bgx |= bgx << 16; + } + + WAIT_FIFO(par, 13); + pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres)); + pm2_WR(par, PM2R_SCISSOR_MIN_XY, + ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff)); + pm2_WR(par, PM2R_SCISSOR_MAX_XY, + (((image->dy + image->height) & 0x0fff) << 16) | + ((image->dx + image->width) & 0x0fff)); + pm2_WR(par, PM2R_SCISSOR_MODE, 1); + /* GXcopy & UNIT_ENABLE */ + pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1); + pm2_WR(par, PM2R_RECTANGLE_ORIGIN, + ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff)); + pm2_WR(par, PM2R_RECTANGLE_SIZE, + ((image->height & 0x0fff) << 16) | + ((image->width) & 0x0fff)); + if (info->var.bits_per_pixel == 24) { + pm2_WR(par, PM2R_COLOR_DDA_MODE, 1); + /* clear area */ + pm2_WR(par, PM2R_CONSTANT_COLOR, bgx); + pm2_WR(par, PM2R_RENDER, + PM2F_RENDER_RECTANGLE | + PM2F_INCREASE_X | PM2F_INCREASE_Y); + /* BitMapPackEachScanline & invert bits and byte order*/ + /* force background */ + pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7)); + pm2_WR(par, PM2R_CONSTANT_COLOR, fgx); + pm2_WR(par, PM2R_RENDER, + PM2F_RENDER_RECTANGLE | + PM2F_INCREASE_X | PM2F_INCREASE_Y | + PM2F_RENDER_SYNC_ON_BIT_MASK); + } else { + pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); + /* clear area */ + pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx); + pm2_WR(par, PM2R_RENDER, + PM2F_RENDER_RECTANGLE | + PM2F_RENDER_FASTFILL | + PM2F_INCREASE_X | PM2F_INCREASE_Y); + /* invert bits and byte order*/ + pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7)); + pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx); + pm2_WR(par, PM2R_RENDER, + PM2F_RENDER_RECTANGLE | + PM2F_INCREASE_X | PM2F_INCREASE_Y | + PM2F_RENDER_FASTFILL | + PM2F_RENDER_SYNC_ON_BIT_MASK); + } + + while (height--) { + int width = ((image->width + 7) >> 3) + + info->pixmap.scan_align - 1; + width >>= 2; + WAIT_FIFO(par, width); + while (width--) { + pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src); + src++; + } + } + WAIT_FIFO(par, 3); + pm2_WR(par, PM2R_RASTERIZER_MODE, 0); + pm2_WR(par, PM2R_COLOR_DDA_MODE, 0); + pm2_WR(par, PM2R_SCISSOR_MODE, 0); +} + +/* + * Hardware cursor support. + */ +static const u8 cursor_bits_lookup[16] = { + 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, + 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 +}; + +static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct pm2fb_par *par = info->par; + u8 mode = PM2F_CURSORMODE_TYPE_X; + int x = cursor->image.dx - info->var.xoffset; + int y = cursor->image.dy - info->var.yoffset; + + if (cursor->enable) + mode |= PM2F_CURSORMODE_CURSOR_ENABLE; + + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode); + + if (!cursor->enable) + x = 2047; /* push it outside display */ + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf); + + /* + * If the cursor is not be changed this means either we want the + * current cursor state (if enable is set) or we want to query what + * we can do with the cursor (if enable is not set) + */ + if (!cursor->set) + return 0; + + if (cursor->set & FB_CUR_SETHOT) { + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT, + cursor->hot.x & 0x3f); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT, + cursor->hot.y & 0x3f); + } + + if (cursor->set & FB_CUR_SETCMAP) { + u32 fg_idx = cursor->image.fg_color; + u32 bg_idx = cursor->image.bg_color; + struct fb_cmap cmap = info->cmap; + + /* the X11 driver says one should use these color registers */ + pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0, + cmap.red[bg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1, + cmap.green[bg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2, + cmap.blue[bg_idx] >> 8 ); + + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3, + cmap.red[fg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4, + cmap.green[fg_idx] >> 8 ); + pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5, + cmap.blue[fg_idx] >> 8 ); + pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); + } + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + u8 *bitmap = (u8 *)cursor->image.data; + u8 *mask = (u8 *)cursor->mask; + int i; + int pos = PM2VI_RD_CURSOR_PATTERN; + + for (i = 0; i < cursor->image.height; i++) { + int j = (cursor->image.width + 7) >> 3; + int k = 8 - j; + + pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); + + for (; j > 0; j--) { + u8 data = *bitmap ^ *mask; + + if (cursor->rop == ROP_COPY) + data = *mask & *bitmap; + /* Upper 4 bits of bitmap data */ + pm2v_RDAC_WR(par, pos++, + cursor_bits_lookup[data >> 4] | + (cursor_bits_lookup[*mask >> 4] << 1)); + /* Lower 4 bits of bitmap */ + pm2v_RDAC_WR(par, pos++, + cursor_bits_lookup[data & 0xf] | + (cursor_bits_lookup[*mask & 0xf] << 1)); + bitmap++; + mask++; + } + for (; k > 0; k--) { + pm2v_RDAC_WR(par, pos++, 0); + pm2v_RDAC_WR(par, pos++, 0); + } + } + + while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) { + pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8); + pm2v_RDAC_WR(par, pos++, 0); + } + + pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); + } + return 0; +} + +static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct pm2fb_par *par = info->par; + u8 mode; + + if (!hwcursor) + return -EINVAL; /* just to force soft_cursor() call */ + + /* Too large of a cursor or wrong bpp :-( */ + if (cursor->image.width > 64 || + cursor->image.height > 64 || + cursor->image.depth > 1) + return -EINVAL; + + if (par->type == PM2_TYPE_PERMEDIA2V) + return pm2vfb_cursor(info, cursor); + + mode = 0x40; + if (cursor->enable) + mode = 0x43; + + pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode); + + /* + * If the cursor is not be changed this means either we want the + * current cursor state (if enable is set) or we want to query what + * we can do with the cursor (if enable is not set) + */ + if (!cursor->set) + return 0; + + if (cursor->set & FB_CUR_SETPOS) { + int x = cursor->image.dx - info->var.xoffset + 63; + int y = cursor->image.dy - info->var.yoffset + 63; + + WAIT_FIFO(par, 4); + pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff); + pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7); + pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff); + pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7); + } + + if (cursor->set & FB_CUR_SETCMAP) { + u32 fg_idx = cursor->image.fg_color; + u32 bg_idx = cursor->image.bg_color; + + WAIT_FIFO(par, 7); + pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1); + pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, + info->cmap.red[bg_idx] >> 8); + pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, + info->cmap.green[bg_idx] >> 8); + pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, + info->cmap.blue[bg_idx] >> 8); + + pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, + info->cmap.red[fg_idx] >> 8); + pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, + info->cmap.green[fg_idx] >> 8); + pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, + info->cmap.blue[fg_idx] >> 8); + } + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + u8 *bitmap = (u8 *)cursor->image.data; + u8 *mask = (u8 *)cursor->mask; + int i; + + WAIT_FIFO(par, 1); + pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); + + for (i = 0; i < cursor->image.height; i++) { + int j = (cursor->image.width + 7) >> 3; + int k = 8 - j; + + WAIT_FIFO(par, 8); + for (; j > 0; j--) { + u8 data = *bitmap ^ *mask; + + if (cursor->rop == ROP_COPY) + data = *mask & *bitmap; + /* bitmap data */ + pm2_WR(par, PM2R_RD_CURSOR_DATA, data); + bitmap++; + mask++; + } + for (; k > 0; k--) + pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); + } + for (; i < 64; i++) { + int j = 8; + WAIT_FIFO(par, 8); + while (j-- > 0) + pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); + } + + mask = (u8 *)cursor->mask; + for (i = 0; i < cursor->image.height; i++) { + int j = (cursor->image.width + 7) >> 3; + int k = 8 - j; + + WAIT_FIFO(par, 8); + for (; j > 0; j--) { + /* mask */ + pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask); + mask++; + } + for (; k > 0; k--) + pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); + } + for (; i < 64; i++) { + int j = 8; + WAIT_FIFO(par, 8); + while (j-- > 0) + pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); + } + } + return 0; } /* ------------ Hardware Independent Functions ------------ */ @@ -1172,8 +1494,9 @@ static struct fb_ops pm2fb_ops = { .fb_pan_display = pm2fb_pan_display, .fb_fillrect = pm2fb_fillrect, .fb_copyarea = pm2fb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_imageblit = pm2fb_imageblit, .fb_sync = pm2fb_sync, + .fb_cursor = pm2fb_cursor, }; /* @@ -1194,16 +1517,17 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, { struct pm2fb_par *default_par; struct fb_info *info; - int err, err_retval = -ENXIO; + int err; + int retval = -ENXIO; err = pci_enable_device(pdev); - if ( err ) { + if (err) { printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); return err; } info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev); - if ( !info ) + if (!info) return -ENOMEM; default_par = info->par; @@ -1236,14 +1560,14 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); /* Registers - request region and map it. */ - if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, - "pm2fb regbase") ) { + if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, + "pm2fb regbase")) { printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n"); goto err_exit_neither; } default_par->v_regs = ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); - if ( !default_par->v_regs ) { + if (!default_par->v_regs) { printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n", pm2fb_fix.id); release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); @@ -1258,72 +1582,101 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, default_par->mem_control, default_par->boot_address, default_par->mem_config); - if(default_par->mem_control == 0 && + if (default_par->mem_control == 0 && default_par->boot_address == 0x31 && default_par->mem_config == 0x259fffff) { default_par->memclock = CVPPC_MEMCLOCK; - default_par->mem_control=0; - default_par->boot_address=0x20; - default_par->mem_config=0xe6002021; + default_par->mem_control = 0; + default_par->boot_address = 0x20; + default_par->mem_config = 0xe6002021; if (pdev->subsystem_vendor == 0x1048 && pdev->subsystem_device == 0x0a31) { - DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", + DPRINTK("subsystem_vendor: %04x, " + "subsystem_device: %04x\n", pdev->subsystem_vendor, pdev->subsystem_device); - DPRINTK("We have not been initialized by VGA BIOS " - "and are running on an Elsa Winner 2000 Office\n"); + DPRINTK("We have not been initialized by VGA BIOS and " + "are running on an Elsa Winner 2000 Office\n"); DPRINTK("Initializing card timings manually...\n"); - default_par->memclock=70000; + default_par->memclock = 100000; } if (pdev->subsystem_vendor == 0x3d3d && pdev->subsystem_device == 0x0100) { - DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", + DPRINTK("subsystem_vendor: %04x, " + "subsystem_device: %04x\n", pdev->subsystem_vendor, pdev->subsystem_device); - DPRINTK("We have not been initialized by VGA BIOS " - "and are running on an 3dlabs reference board\n"); + DPRINTK("We have not been initialized by VGA BIOS and " + "are running on an 3dlabs reference board\n"); DPRINTK("Initializing card timings manually...\n"); - default_par->memclock=74894; + default_par->memclock = 74894; } } /* Now work out how big lfb is going to be. */ - switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { + switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { case PM2F_MEM_BANKS_1: - pm2fb_fix.smem_len=0x200000; + pm2fb_fix.smem_len = 0x200000; break; case PM2F_MEM_BANKS_2: - pm2fb_fix.smem_len=0x400000; + pm2fb_fix.smem_len = 0x400000; break; case PM2F_MEM_BANKS_3: - pm2fb_fix.smem_len=0x600000; + pm2fb_fix.smem_len = 0x600000; break; case PM2F_MEM_BANKS_4: - pm2fb_fix.smem_len=0x800000; + pm2fb_fix.smem_len = 0x800000; break; } pm2fb_fix.smem_start = pci_resource_start(pdev, 1); /* Linear frame buffer - request region and map it. */ - if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len, - "pm2fb smem") ) { + if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len, + "pm2fb smem")) { printk(KERN_WARNING "pm2fb: Can't reserve smem.\n"); goto err_exit_mmio; } info->screen_base = ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len); - if ( !info->screen_base ) { + if (!info->screen_base) { printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n"); release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); goto err_exit_mmio; } +#ifdef CONFIG_MTRR + default_par->mtrr_handle = -1; + if (!nomtrr) + default_par->mtrr_handle = + mtrr_add(pm2fb_fix.smem_start, + pm2fb_fix.smem_len, + MTRR_TYPE_WRCOMB, 1); +#endif + info->fbops = &pm2fb_ops; info->fix = pm2fb_fix; info->pseudo_palette = default_par->palette; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT; + info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL); + if (!info->pixmap.addr) { + retval = -ENOMEM; + goto err_exit_pixmap; + } + info->pixmap.size = PM2_PIXMAP_SIZE; + info->pixmap.buf_align = 4; + info->pixmap.scan_align = 4; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + + if (noaccel) { + printk(KERN_DEBUG "disabling acceleration\n"); + info->flags |= FBINFO_HWACCEL_DISABLED; + info->pixmap.scan_align = 1; + } + if (!mode) mode = "640x480@60"; @@ -1350,6 +1703,8 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, err_exit_all: fb_dealloc_cmap(&info->cmap); err_exit_both: + kfree(info->pixmap.addr); + err_exit_pixmap: iounmap(info->screen_base); release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); err_exit_mmio: @@ -1357,7 +1712,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); err_exit_neither: framebuffer_release(info); - return err_retval; + return retval; } /** @@ -1369,34 +1724,34 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, */ static void __devexit pm2fb_remove(struct pci_dev *pdev) { - struct fb_info* info = pci_get_drvdata(pdev); - struct fb_fix_screeninfo* fix = &info->fix; + struct fb_info *info = pci_get_drvdata(pdev); + struct fb_fix_screeninfo *fix = &info->fix; struct pm2fb_par *par = info->par; unregister_framebuffer(info); +#ifdef CONFIG_MTRR + if (par->mtrr_handle >= 0) + mtrr_del(par->mtrr_handle, info->fix.smem_start, + info->fix.smem_len); +#endif /* CONFIG_MTRR */ iounmap(info->screen_base); release_mem_region(fix->smem_start, fix->smem_len); iounmap(par->v_regs); release_mem_region(fix->mmio_start, fix->mmio_len); pci_set_drvdata(pdev, NULL); + kfree(info->pixmap.addr); kfree(info); } static struct pci_device_id pm2fb_id_table[] = { { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, - { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA << 8, - 0xff00, 0 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, } }; @@ -1418,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table); */ static int __init pm2fb_setup(char *options) { - char* this_opt; + char *this_opt; if (!options || !*options) return 0; @@ -1426,13 +1781,20 @@ static int __init pm2fb_setup(char *options) while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; - if(!strcmp(this_opt, "lowhsync")) { + if (!strcmp(this_opt, "lowhsync")) lowhsync = 1; - } else if(!strcmp(this_opt, "lowvsync")) { + else if (!strcmp(this_opt, "lowvsync")) lowvsync = 1; - } else { + else if (!strncmp(this_opt, "hwcursor=", 9)) + hwcursor = simple_strtoul(this_opt + 9, NULL, 0); +#ifdef CONFIG_MTRR + else if (!strncmp(this_opt, "nomtrr", 6)) + nomtrr = 1; +#endif + else if (!strncmp(this_opt, "noaccel", 7)) + noaccel = 1; + else mode = this_opt; - } } return 0; } @@ -1474,6 +1836,15 @@ module_param(lowhsync, bool, 0); MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); module_param(lowvsync, bool, 0); MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); +module_param(noaccel, bool, 0); +MODULE_PARM_DESC(noaccel, "Disable acceleration"); +module_param(hwcursor, int, 0644); +MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " + "(1=enable, 0=disable, default=1)"); +#ifdef CONFIG_MTRR +module_param(nomtrr, bool, 0); +MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); +#endif MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>"); MODULE_DESCRIPTION("Permedia2 framebuffer device driver"); diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 5b3f54c0918..070659992c1 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -32,6 +32,9 @@ #include <linux/fb.h> #include <linux/init.h> #include <linux/pci.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif #include <video/pm3fb.h> @@ -41,15 +44,25 @@ #undef PM3FB_MASTER_DEBUG #ifdef PM3FB_MASTER_DEBUG -#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) +#define DPRINTK(a, b...) \ + printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) #else -#define DPRINTK(a,b...) +#define DPRINTK(a, b...) #endif +#define PM3_PIXMAP_SIZE (2048 * 4) + /* * Driver data */ +static int hwcursor = 1; static char *mode_option __devinitdata; +static int noaccel __devinitdata; + +/* mtrr option */ +#ifdef CONFIG_MTRR +static int nomtrr __devinitdata; +#endif /* * This structure defines the hardware state of the graphics card. Normally @@ -61,8 +74,9 @@ static char *mode_option __devinitdata; struct pm3_par { unsigned char __iomem *v_regs;/* virtual address of p_regs */ u32 video; /* video flags before blanking */ - u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ + u32 base; /* screen base in 128 bits unit */ u32 palette[16]; + int mtrr_handle; }; /* @@ -96,7 +110,8 @@ static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) static inline void PM3_WAIT(struct pm3_par *par, u32 n) { - while (PM3_READ_REG(par, PM3InFIFOSpace) < n); + while (PM3_READ_REG(par, PM3InFIFOSpace) < n) + cpu_relax(); } static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) @@ -133,7 +148,7 @@ static void pm3fb_clear_colormap(struct pm3_par *par, } -/* Calculating various clock parameter */ +/* Calculating various clock parameters */ static void pm3fb_calculate_clock(unsigned long reqclock, unsigned char *prescale, unsigned char *feedback, @@ -164,7 +179,7 @@ static void pm3fb_calculate_clock(unsigned long reqclock, static inline int pm3fb_depth(const struct fb_var_screeninfo *var) { - if ( var->bits_per_pixel == 16 ) + if (var->bits_per_pixel == 16) return var->red.length + var->green.length + var->blue.length; @@ -195,8 +210,8 @@ static int pm3fb_sync(struct fb_info *info) PM3_WRITE_REG(par, PM3Sync, 0); mb(); do { - while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0); - rmb(); + while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0) + cpu_relax(); } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); return 0; @@ -276,15 +291,22 @@ static void pm3fb_init_engine(struct fb_info *info) PM3_WAIT(par, 2); { - unsigned long rm = 1; + /* invert bits in bitmask */ + unsigned long rm = 1 | (3 << 7); switch (info->var.bits_per_pixel) { case 8: PM3_WRITE_REG(par, PM3PixelSize, PM3PixelSize_GLOBAL_8BIT); +#ifdef __BIG_ENDIAN + rm |= 3 << 15; +#endif break; case 16: PM3_WRITE_REG(par, PM3PixelSize, PM3PixelSize_GLOBAL_16BIT); +#ifdef __BIG_ENDIAN + rm |= 2 << 15; +#endif break; case 32: PM3_WRITE_REG(par, PM3PixelSize, @@ -342,7 +364,7 @@ static void pm3fb_init_engine(struct fb_info *info) PM3_WRITE_REG(par, PM3dXDom, 0x0); PM3_WRITE_REG(par, PM3dXSub, 0x0); - PM3_WRITE_REG(par, PM3dY, (1 << 16)); + PM3_WRITE_REG(par, PM3dY, 1 << 16); PM3_WRITE_REG(par, PM3StartXDom, 0x0); PM3_WRITE_REG(par, PM3StartXSub, 0x0); PM3_WRITE_REG(par, PM3StartY, 0x0); @@ -357,71 +379,350 @@ static void pm3fb_init_engine(struct fb_info *info) pm3fb_sync(info); } -static void pm3fb_fillrect (struct fb_info *info, +static void pm3fb_fillrect(struct fb_info *info, const struct fb_fillrect *region) { struct pm3_par *par = info->par; struct fb_fillrect modded; int vxres, vyres; + int rop; u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? - ((u32*)info->pseudo_palette)[region->color] : region->color; + ((u32 *)info->pseudo_palette)[region->color] : region->color; if (info->state != FBINFO_STATE_RUNNING) return; - if ((info->flags & FBINFO_HWACCEL_DISABLED) || - region->rop != ROP_COPY ) { + if (info->flags & FBINFO_HWACCEL_DISABLED) { cfb_fillrect(info, region); return; } + if (region->rop == ROP_COPY ) + rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */ + else + rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */ + PM3Config2D_FBDestReadEnable; vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; memcpy(&modded, region, sizeof(struct fb_fillrect)); - if(!modded.width || !modded.height || - modded.dx >= vxres || modded.dy >= vyres) + if (!modded.width || !modded.height || + modded.dx >= vxres || modded.dy >= vyres) return; - if(modded.dx + modded.width > vxres) + if (modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; - if(modded.dy + modded.height > vyres) + if (modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; - if(info->var.bits_per_pixel == 8) + if (info->var.bits_per_pixel == 8) color |= color << 8; - if(info->var.bits_per_pixel <= 16) + if (info->var.bits_per_pixel <= 16) color |= color << 16; PM3_WAIT(par, 4); - + /* ROP Ox3 is GXcopy */ PM3_WRITE_REG(par, PM3Config2D, - PM3Config2D_UseConstantSource | - PM3Config2D_ForegroundROPEnable | - (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ - PM3Config2D_FBWriteEnable); + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + rop | + PM3Config2D_FBWriteEnable); PM3_WRITE_REG(par, PM3ForegroundColor, color); PM3_WRITE_REG(par, PM3RectanglePosition, - (PM3RectanglePosition_XOffset(modded.dx)) | - (PM3RectanglePosition_YOffset(modded.dy))); + PM3RectanglePosition_XOffset(modded.dx) | + PM3RectanglePosition_YOffset(modded.dy)); PM3_WRITE_REG(par, PM3Render2D, PM3Render2D_XPositive | PM3Render2D_YPositive | PM3Render2D_Operation_Normal | PM3Render2D_SpanOperation | - (PM3Render2D_Width(modded.width)) | - (PM3Render2D_Height(modded.height))); + PM3Render2D_Width(modded.width) | + PM3Render2D_Height(modded.height)); +} + +static void pm3fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct pm3_par *par = info->par; + struct fb_copyarea modded; + u32 vxres, vyres; + int x_align, o_x, o_y; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED) { + cfb_copyarea(info, area); + return; + } + + memcpy(&modded, area, sizeof(struct fb_copyarea)); + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if (!modded.width || !modded.height || + modded.sx >= vxres || modded.sy >= vyres || + modded.dx >= vxres || modded.dy >= vyres) + return; + + if (modded.sx + modded.width > vxres) + modded.width = vxres - modded.sx; + if (modded.dx + modded.width > vxres) + modded.width = vxres - modded.dx; + if (modded.sy + modded.height > vyres) + modded.height = vyres - modded.sy; + if (modded.dy + modded.height > vyres) + modded.height = vyres - modded.dy; + + o_x = modded.sx - modded.dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ + o_y = modded.sy - modded.dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ + + x_align = (modded.sx & 0x1f); + + PM3_WAIT(par, 6); + + PM3_WRITE_REG(par, PM3Config2D, + PM3Config2D_UserScissorEnable | + PM3Config2D_ForegroundROPEnable | + PM3Config2D_Blocking | + PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); + + PM3_WRITE_REG(par, PM3ScissorMinXY, + ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff)); + PM3_WRITE_REG(par, PM3ScissorMaxXY, + (((modded.dy + modded.height) & 0x0fff) << 16) | + ((modded.dx + modded.width) & 0x0fff)); + + PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, + PM3FBSourceReadBufferOffset_XOffset(o_x) | + PM3FBSourceReadBufferOffset_YOffset(o_y)); + + PM3_WRITE_REG(par, PM3RectanglePosition, + PM3RectanglePosition_XOffset(modded.dx - x_align) | + PM3RectanglePosition_YOffset(modded.dy)); + + PM3_WRITE_REG(par, PM3Render2D, + ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) | + ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) | + PM3Render2D_Operation_Normal | + PM3Render2D_SpanOperation | + PM3Render2D_FBSourceReadEnable | + PM3Render2D_Width(modded.width + x_align) | + PM3Render2D_Height(modded.height)); +} + +static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct pm3_par *par = info->par; + u32 height = image->height; + u32 fgx, bgx; + const u32 *src = (const u32 *)image->data; + + if (info->state != FBINFO_STATE_RUNNING) + return; + if (info->flags & FBINFO_HWACCEL_DISABLED) { + cfb_imageblit(info, image); + return; + } + switch (info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + fgx = image->fg_color; + bgx = image->bg_color; + break; + case FB_VISUAL_TRUECOLOR: + default: + fgx = par->palette[image->fg_color]; + bgx = par->palette[image->bg_color]; + break; + } + if (image->depth != 1) + return cfb_imageblit(info, image); + + if (info->var.bits_per_pixel == 8) { + fgx |= fgx << 8; + bgx |= bgx << 8; + } + if (info->var.bits_per_pixel <= 16) { + fgx |= fgx << 16; + bgx |= bgx << 16; + } + + PM3_WAIT(par, 7); + + PM3_WRITE_REG(par, PM3ForegroundColor, fgx); + PM3_WRITE_REG(par, PM3BackgroundColor, bgx); + + /* ROP Ox3 is GXcopy */ + PM3_WRITE_REG(par, PM3Config2D, + PM3Config2D_UserScissorEnable | + PM3Config2D_UseConstantSource | + PM3Config2D_ForegroundROPEnable | + PM3Config2D_ForegroundROP(0x3) | + PM3Config2D_OpaqueSpan | + PM3Config2D_FBWriteEnable); + PM3_WRITE_REG(par, PM3ScissorMinXY, + ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff)); + PM3_WRITE_REG(par, PM3ScissorMaxXY, + (((image->dy + image->height) & 0x0fff) << 16) | + ((image->dx + image->width) & 0x0fff)); + PM3_WRITE_REG(par, PM3RectanglePosition, + PM3RectanglePosition_XOffset(image->dx) | + PM3RectanglePosition_YOffset(image->dy)); + PM3_WRITE_REG(par, PM3Render2D, + PM3Render2D_XPositive | + PM3Render2D_YPositive | + PM3Render2D_Operation_SyncOnBitMask | + PM3Render2D_SpanOperation | + PM3Render2D_Width(image->width) | + PM3Render2D_Height(image->height)); + + + while (height--) { + int width = ((image->width + 7) >> 3) + + info->pixmap.scan_align - 1; + width >>= 2; + + while (width >= PM3_FIFO_SIZE) { + int i = PM3_FIFO_SIZE - 1; + + PM3_WAIT(par, PM3_FIFO_SIZE); + while (i--) { + PM3_WRITE_REG(par, PM3BitMaskPattern, *src); + src++; + } + width -= PM3_FIFO_SIZE - 1; + } + + PM3_WAIT(par, width + 1); + while (width--) { + PM3_WRITE_REG(par, PM3BitMaskPattern, *src); + src++; + } + } } /* end of acceleration functions */ +/* + * Hardware Cursor support. + */ +static const u8 cursor_bits_lookup[16] = { + 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, + 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 +}; + +static int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct pm3_par *par = info->par; + u8 mode; + + if (!hwcursor) + return -EINVAL; /* just to force soft_cursor() call */ + + /* Too large of a cursor or wrong bpp :-( */ + if (cursor->image.width > 64 || + cursor->image.height > 64 || + cursor->image.depth > 1) + return -EINVAL; + + mode = PM3RD_CursorMode_TYPE_X; + if (cursor->enable) + mode |= PM3RD_CursorMode_CURSOR_ENABLE; + + PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode); + + /* + * If the cursor is not be changed this means either we want the + * current cursor state (if enable is set) or we want to query what + * we can do with the cursor (if enable is not set) + */ + if (!cursor->set) + return 0; + + if (cursor->set & FB_CUR_SETPOS) { + int x = cursor->image.dx - info->var.xoffset; + int y = cursor->image.dy - info->var.yoffset; + + PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff); + PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf); + PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff); + PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf); + } + + if (cursor->set & FB_CUR_SETHOT) { + PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX, + cursor->hot.x & 0x3f); + PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY, + cursor->hot.y & 0x3f); + } + + if (cursor->set & FB_CUR_SETCMAP) { + u32 fg_idx = cursor->image.fg_color; + u32 bg_idx = cursor->image.bg_color; + struct fb_cmap cmap = info->cmap; + + /* the X11 driver says one should use these color registers */ + PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39), + cmap.red[fg_idx] >> 8 ); + PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40), + cmap.green[fg_idx] >> 8 ); + PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41), + cmap.blue[fg_idx] >> 8 ); + + PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42), + cmap.red[bg_idx] >> 8 ); + PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43), + cmap.green[bg_idx] >> 8 ); + PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44), + cmap.blue[bg_idx] >> 8 ); + } + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + u8 *bitmap = (u8 *)cursor->image.data; + u8 *mask = (u8 *)cursor->mask; + int i; + int pos = PM3RD_CursorPattern(0); + + for (i = 0; i < cursor->image.height; i++) { + int j = (cursor->image.width + 7) >> 3; + int k = 8 - j; + + for (; j > 0; j--) { + u8 data = *bitmap ^ *mask; + + if (cursor->rop == ROP_COPY) + data = *mask & *bitmap; + /* Upper 4 bits of bitmap data */ + PM3_WRITE_DAC_REG(par, pos++, + cursor_bits_lookup[data >> 4] | + (cursor_bits_lookup[*mask >> 4] << 1)); + /* Lower 4 bits of bitmap */ + PM3_WRITE_DAC_REG(par, pos++, + cursor_bits_lookup[data & 0xf] | + (cursor_bits_lookup[*mask & 0xf] << 1)); + bitmap++; + mask++; + } + for (; k > 0; k--) { + PM3_WRITE_DAC_REG(par, pos++, 0); + PM3_WRITE_DAC_REG(par, pos++, 0); + } + } + while (pos < PM3RD_CursorPattern(1024)) + PM3_WRITE_DAC_REG(par, pos++, 0); + } + return 0; +} + /* write the mode to registers */ static void pm3fb_write_mode(struct fb_info *info) { struct pm3_par *par = info->par; - char tempsync = 0x00, tempmisc = 0x00; + char tempsync = 0x00; + char tempmisc = 0x00; const u32 hsstart = info->var.right_margin; const u32 hsend = hsstart + info->var.hsync_len; const u32 hbend = hsend + info->var.left_margin; @@ -618,47 +919,57 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) unsigned bpp = var->red.length + var->green.length + var->blue.length + var->transp.length; - if ( bpp != var->bits_per_pixel ) { + if (bpp != var->bits_per_pixel) { /* set predefined mode for bits_per_pixel settings */ - switch(var->bits_per_pixel) { + switch (var->bits_per_pixel) { case 8: - var->red.length = var->green.length = var->blue.length = 8; - var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; var->transp.offset = 0; var->transp.length = 0; break; case 16: - var->red.length = var->blue.length = 5; + var->red.length = 5; + var->blue.length = 5; var->green.length = 6; var->transp.length = 0; break; case 32: - var->red.length = var->green.length = var->blue.length = 8; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; var->transp.length = 8; break; default: - DPRINTK("depth not supported: %u\n", var->bits_per_pixel); + DPRINTK("depth not supported: %u\n", + var->bits_per_pixel); return -EINVAL; } } /* it is assumed BGRA order */ - if (var->bits_per_pixel > 8 ) - { + if (var->bits_per_pixel > 8 ) { var->blue.offset = 0; var->green.offset = var->blue.length; var->red.offset = var->green.offset + var->green.length; var->transp.offset = var->red.offset + var->red.length; } - var->height = var->width = -1; + var->height = -1; + var->width = -1; if (var->xres != var->xres_virtual) { - DPRINTK("virtual x resolution != physical x resolution not supported\n"); + DPRINTK("virtual x resolution != " + "physical x resolution not supported\n"); return -EINVAL; } if (var->yres > var->yres_virtual) { - DPRINTK("virtual y resolution < physical y resolution not possible\n"); + DPRINTK("virtual y resolution < " + "physical y resolution not possible\n"); return -EINVAL; } @@ -673,7 +984,7 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ - lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); + lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); if (var->xres < 200 || var->xres > 2048) { DPRINTK("width not supported: %u\n", var->xres); @@ -692,7 +1003,8 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { - DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); + DPRINTK("pixclock too high (%ldKHz)\n", + PICOS2KHZ(var->pixclock)); return -EINVAL; } @@ -709,7 +1021,7 @@ static int pm3fb_set_par(struct fb_info *info) const u32 xres = (info->var.xres + 31) & ~31; const unsigned bpp = info->var.bits_per_pixel; - par->base = pm3fb_shift_bpp(bpp,(info->var.yoffset * xres) + par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres) + info->var.xoffset); par->video = 0; @@ -725,15 +1037,12 @@ static int pm3fb_set_par(struct fb_info *info) if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) par->video |= PM3VideoControl_LINE_DOUBLE_ON; - else - par->video |= PM3VideoControl_LINE_DOUBLE_OFF; if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) par->video |= PM3VideoControl_ENABLE; - else { - par->video |= PM3VideoControl_DISABLE; + else DPRINTK("PM3Video disabled\n"); - } + switch (bpp) { case 8: par->video |= PM3VideoControl_PIXELSIZE_8BIT; @@ -751,13 +1060,11 @@ static int pm3fb_set_par(struct fb_info *info) info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = ((info->var.xres_virtual + 7) & ~7) - * bpp / 8; + info->fix.line_length = ((info->var.xres_virtual + 7) >> 3) * bpp; /* pm3fb_clear_memory(info, 0);*/ pm3fb_clear_colormap(par, 0, 0, 0); - PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, - PM3RD_CursorMode_CURSOR_DISABLE); + PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0); pm3fb_init_engine(info); pm3fb_write_mode(info); return 0; @@ -773,10 +1080,9 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, return -EINVAL; /* grayscale works only partially under directcolor */ - if (info->var.grayscale) { - /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + if (info->var.grayscale) red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; - } /* Directcolor: * var->{color}.offset contains start of bitfield @@ -790,8 +1096,8 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, * * Pseudocolor: * var->{color}.offset is 0 - * var->{color}.length contains width of DAC or the number of unique - * colors available (color depth) + * var->{color}.length contains width of DAC or the number + * of unique colors available (color depth) * pseudo_palette is not used * RAMDAC[X] is programmed to (red, green, blue) * color depth = var->{color}.length @@ -801,7 +1107,7 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, * This is the point where the color is converted to something that * is acceptable by the hardware. */ -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) +#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) red = CNVT_TOHW(red, info->var.red.length); green = CNVT_TOHW(green, info->var.green.length); blue = CNVT_TOHW(blue, info->var.blue.length); @@ -825,12 +1131,11 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, break; case 16: case 32: - ((u32*)(info->pseudo_palette))[regno] = v; + ((u32 *)(info->pseudo_palette))[regno] = v; break; } return 0; - } - else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) pm3fb_set_color(par, regno, red, green, blue); return 0; @@ -871,7 +1176,7 @@ static int pm3fb_blank(int blank_mode, struct fb_info *info) video |= PM3VideoControl_ENABLE; break; case FB_BLANK_NORMAL: - video &= ~(PM3VideoControl_ENABLE); + video &= ~PM3VideoControl_ENABLE; break; case FB_BLANK_HSYNC_SUSPEND: video &= ~(PM3VideoControl_HSYNC_MASK | @@ -892,7 +1197,7 @@ static int pm3fb_blank(int blank_mode, struct fb_info *info) } PM3_WAIT(par, 1); - PM3_WRITE_REG(par,PM3VideoControl, video); + PM3_WRITE_REG(par, PM3VideoControl, video); return 0; } @@ -907,10 +1212,11 @@ static struct fb_ops pm3fb_ops = { .fb_setcolreg = pm3fb_setcolreg, .fb_pan_display = pm3fb_pan_display, .fb_fillrect = pm3fb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_copyarea = pm3fb_copyarea, + .fb_imageblit = pm3fb_imageblit, .fb_blank = pm3fb_blank, .fb_sync = pm3fb_sync, + .fb_cursor = pm3fb_cursor, }; /* ------------------------------------------------------------------------- */ @@ -923,7 +1229,8 @@ static struct fb_ops pm3fb_ops = { /* the pm3fb_fix.smem_start is also set */ static unsigned long pm3fb_size_memory(struct pm3_par *par) { - unsigned long memsize = 0, tempBypass, i, temp1, temp2; + unsigned long memsize = 0; + unsigned long tempBypass, i, temp1, temp2; unsigned char __iomem *screen_mem; pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ @@ -951,7 +1258,9 @@ static unsigned long pm3fb_size_memory(struct pm3_par *par) PM3_WAIT(par, 1); PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); - /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ + /* pm3 split up memory, replicates, and do a lot of + * nasty stuff IMHO ;-) + */ for (i = 0; i < 32; i++) { fb_writel(i * 0x00345678, (screen_mem + (i * 1048576))); @@ -1008,8 +1317,9 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, { struct fb_info *info; struct pm3_par *par; - struct device* device = &dev->dev; /* for pci drivers */ - int err, retval = -ENXIO; + struct device *device = &dev->dev; /* for pci drivers */ + int err; + int retval = -ENXIO; err = pci_enable_device(dev); if (err) { @@ -1031,6 +1341,10 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, */ pm3fb_fix.mmio_start = pci_resource_start(dev, 0); pm3fb_fix.mmio_len = PM3_REGS_SIZE; +#if defined(__BIG_ENDIAN) + pm3fb_fix.mmio_start += PM3_REGS_SIZE; + DPRINTK("Adjusting register base for big-endian.\n"); +#endif /* Registers - request region and map it. */ if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, @@ -1047,15 +1361,10 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, goto err_exit_neither; } -#if defined(__BIG_ENDIAN) - pm3fb_fix.mmio_start += PM3_REGS_SIZE; - DPRINTK("Adjusting register base for big-endian.\n"); -#endif /* Linear frame buffer - request region and map it. */ pm3fb_fix.smem_start = pci_resource_start(dev, 1); pm3fb_fix.smem_len = pm3fb_size_memory(par); - if (!pm3fb_fix.smem_len) - { + if (!pm3fb_fix.smem_len) { printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); goto err_exit_mmio; } @@ -1073,6 +1382,12 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, } info->screen_size = pm3fb_fix.smem_len; +#ifdef CONFIG_MTRR + if (!nomtrr) + par->mtrr_handle = mtrr_add(pm3fb_fix.smem_start, + pm3fb_fix.smem_len, + MTRR_TYPE_WRCOMB, 1); +#endif info->fbops = &pm3fb_ops; par->video = PM3_READ_REG(par, PM3VideoControl); @@ -1080,7 +1395,26 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, info->fix = pm3fb_fix; info->pseudo_palette = par->palette; info->flags = FBINFO_DEFAULT | - FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/ + FBINFO_HWACCEL_XPAN | + FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_FILLRECT; + + if (noaccel) { + printk(KERN_DEBUG "disabling acceleration\n"); + info->flags |= FBINFO_HWACCEL_DISABLED; + } + info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL); + if (!info->pixmap.addr) { + retval = -ENOMEM; + goto err_exit_pixmap; + } + info->pixmap.size = PM3_PIXMAP_SIZE; + info->pixmap.buf_align = 4; + info->pixmap.scan_align = 4; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; /* * This should give a reasonable default video mode. The following is @@ -1118,6 +1452,8 @@ static int __devinit pm3fb_probe(struct pci_dev *dev, err_exit_all: fb_dealloc_cmap(&info->cmap); err_exit_both: + kfree(info->pixmap.addr); + err_exit_pixmap: iounmap(info->screen_base); release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); err_exit_mmio: @@ -1142,12 +1478,18 @@ static void __devexit pm3fb_remove(struct pci_dev *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); +#ifdef CONFIG_MTRR + if (par->mtrr_handle >= 0) + mtrr_del(par->mtrr_handle, info->fix.smem_start, + info->fix.smem_len); +#endif /* CONFIG_MTRR */ iounmap(info->screen_base); release_mem_region(fix->smem_start, fix->smem_len); iounmap(par->v_regs); release_mem_region(fix->mmio_start, fix->mmio_len); pci_set_drvdata(dev, NULL); + kfree(info->pixmap.addr); framebuffer_release(info); } } @@ -1168,21 +1510,76 @@ static struct pci_driver pm3fb_driver = { MODULE_DEVICE_TABLE(pci, pm3fb_id_table); +#ifndef MODULE + /* + * Setup + */ + +/* + * Only necessary if your driver takes special options, + * otherwise we fall back on the generic fb_setup(). + */ +static int __init pm3fb_setup(char *options) +{ + char *this_opt; + + /* Parse user speficied options (`video=pm3fb:') */ + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + else if (!strncmp(this_opt, "noaccel", 7)) + noaccel = 1; + else if (!strncmp(this_opt, "hwcursor=", 9)) + hwcursor = simple_strtoul(this_opt + 9, NULL, 0); +#ifdef CONFIG_MTRR + else if (!strncmp(this_opt, "nomtrr", 6)) + nomtrr = 1; +#endif + else + mode_option = this_opt; + } + return 0; +} +#endif /* MODULE */ + static int __init pm3fb_init(void) { + /* + * For kernel boot options (in 'video=pm3fb:<options>' format) + */ #ifndef MODULE - if (fb_get_options("pm3fb", NULL)) + char *option = NULL; + + if (fb_get_options("pm3fb", &option)) return -ENODEV; + pm3fb_setup(option); #endif + return pci_register_driver(&pm3fb_driver); } +#ifdef MODULE static void __exit pm3fb_exit(void) { pci_unregister_driver(&pm3fb_driver); } -module_init(pm3fb_init); module_exit(pm3fb_exit); +#endif +module_init(pm3fb_init); + +module_param(noaccel, bool, 0); +MODULE_PARM_DESC(noaccel, "Disable acceleration"); +module_param(hwcursor, int, 0644); +MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " + "(1=enable, 0=disable, default=1)"); +#ifdef CONFIG_MTRR +module_param(nomtrr, bool, 0); +MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); +#endif +MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 264d37243fa..3a3f80f6521 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -147,16 +147,23 @@ static int __init pmagbafb_probe(struct device *dev) resource_size_t start, len; struct fb_info *info; struct pmagbafb_par *par; + int err; info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev); - if (!info) + if (!info) { + printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id); return -ENOMEM; + } par = info->par; dev_set_drvdata(dev, info); - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + printk(KERN_ERR "%s: Cannot allocate color map\n", + dev->bus_id); + err = -ENOMEM; goto err_alloc; + } info->fbops = &pmagbafb_ops; info->fix = pmagbafb_fix; @@ -166,28 +173,41 @@ static int __init pmagbafb_probe(struct device *dev) /* Request the I/O MEM resource. */ start = tdev->resource.start; len = tdev->resource.end - start + 1; - if (!request_mem_region(start, len, dev->bus_id)) + if (!request_mem_region(start, len, dev->bus_id)) { + printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id); + err = -EBUSY; goto err_cmap; + } /* MMIO mapping setup. */ info->fix.mmio_start = start; par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); - if (!par->mmio) + if (!par->mmio) { + printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id); + err = -ENOMEM; goto err_resource; + } par->dac = par->mmio + PMAG_BA_BT459; /* Frame buffer mapping setup. */ info->fix.smem_start = start + PMAG_BA_FBMEM; info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); - if (!info->screen_base) + if (!info->screen_base) { + printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id); + err = -ENOMEM; goto err_mmio_map; + } info->screen_size = info->fix.smem_len; pmagbafb_erase_cursor(info); - if (register_framebuffer(info) < 0) + err = register_framebuffer(info); + if (err < 0) { + printk(KERN_ERR "%s: Cannot register framebuffer\n", + dev->bus_id); goto err_smem_map; + } get_device(dev); @@ -211,7 +231,7 @@ err_cmap: err_alloc: framebuffer_release(info); - return -ENXIO; + return err; } static int __exit pmagbafb_remove(struct device *dev) diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index 7a0ce7d5af6..9b80597241b 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c @@ -254,16 +254,23 @@ static int __init pmagbbfb_probe(struct device *dev) struct pmagbbfb_par *par; char freq0[12], freq1[12]; u32 vid_base; + int err; info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev); - if (!info) + if (!info) { + printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id); return -ENOMEM; + } par = info->par; dev_set_drvdata(dev, info); - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + printk(KERN_ERR "%s: Cannot allocate color map\n", + dev->bus_id); + err = -ENOMEM; goto err_alloc; + } info->fbops = &pmagbbfb_ops; info->fix = pmagbbfb_fix; @@ -273,22 +280,31 @@ static int __init pmagbbfb_probe(struct device *dev) /* Request the I/O MEM resource. */ start = tdev->resource.start; len = tdev->resource.end - start + 1; - if (!request_mem_region(start, len, dev->bus_id)) + if (!request_mem_region(start, len, dev->bus_id)) { + printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id); + err = -EBUSY; goto err_cmap; + } /* MMIO mapping setup. */ info->fix.mmio_start = start; par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); - if (!par->mmio) + if (!par->mmio) { + printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id); + err = -ENOMEM; goto err_resource; + } par->sfb = par->mmio + PMAGB_B_SFB; par->dac = par->mmio + PMAGB_B_BT459; /* Frame buffer mapping setup. */ info->fix.smem_start = start + PMAGB_B_FBMEM; par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); - if (!par->smem) + if (!par->smem) { + printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id); + err = -ENOMEM; goto err_mmio_map; + } vid_base = sfb_read(par, SFB_REG_VID_BASE); info->screen_base = (void __iomem *)par->smem + vid_base * 0x1000; info->screen_size = info->fix.smem_len - 2 * vid_base * 0x1000; @@ -297,8 +313,12 @@ static int __init pmagbbfb_probe(struct device *dev) pmagbbfb_screen_setup(info); pmagbbfb_osc_setup(info); - if (register_framebuffer(info) < 0) + err = register_framebuffer(info); + if (err < 0) { + printk(KERN_ERR "%s: Cannot register framebuffer\n", + dev->bus_id); goto err_smem_map; + } get_device(dev); @@ -330,7 +350,7 @@ err_cmap: err_alloc: framebuffer_release(info); - return -ENXIO; + return err; } static int __exit pmagbbfb_remove(struct device *dev) diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c index f29e66e2d77..685761a0732 100644 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ b/drivers/video/pnx4008/pnxrgbfb.c @@ -26,7 +26,6 @@ #include <linux/init.h> #include <linux/platform_device.h> -#include <asm/uaccess.h> #include "sdum.h" #include "fbcommon.h" diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 646ec823c16..b3463ddcfd6 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -22,22 +22,14 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> -#include <linux/tty.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/console.h> #include <linux/ioctl.h> -#include <linux/notifier.h> -#include <linux/reboot.h> #include <linux/kthread.h> #include <linux/freezer.h> - -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/fb.h> #include <linux/init.h> -#include <asm/time.h> #include <asm/abs_addr.h> #include <asm/lv1call.h> @@ -48,12 +40,6 @@ #define DEVICE_NAME "ps3fb" -#ifdef PS3FB_DEBUG -#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) -#else -#define DPRINTK(fmt, args...) -#endif - #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 #define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 @@ -66,8 +52,10 @@ #define L1GPU_DISPLAY_SYNC_VSYNC 2 #define DDR_SIZE (0) /* used no ddr */ -#define GPU_OFFSET (64 * 1024) +#define GPU_CMD_BUF_SIZE (64 * 1024) #define GPU_IOIF (0x0d000000UL) +#define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64) +#define GPU_MAX_LINE_LENGTH (65536 - 64) #define PS3FB_FULL_MODE_BIT 0x80 @@ -131,13 +119,12 @@ struct ps3fb_priv { u64 context_handle, memory_handle; void *xdr_ea; + size_t xdr_size; struct gpu_driver_info *dinfo; - u32 res_index; u64 vblank_count; /* frame count */ wait_queue_head_t wait_vsync; - u32 num_frames; /* num of frame buffers */ atomic_t ext_flip; /* on/off flip with vsync */ atomic_t f_count; /* fb_open count */ int is_blanked; @@ -146,6 +133,18 @@ struct ps3fb_priv { }; static struct ps3fb_priv ps3fb; +struct ps3fb_par { + u32 pseudo_palette[16]; + int mode_id, new_mode_id; + int res_index; + unsigned int num_frames; /* num of frame buffers */ + unsigned int width; + unsigned int height; + unsigned long full_offset; /* start of fullscreen DDR fb */ + unsigned long fb_offset; /* start of actual DDR fb */ + unsigned long pan_offset; +}; + struct ps3fb_res_table { u32 xres; u32 yres; @@ -294,29 +293,31 @@ static const struct fb_videomode ps3fb_modedb[] = { #define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */ #define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */ #define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */ -#define BPP 4 /* number of bytes per pixel */ -#define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP) -#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) +#define BPP 4 /* number of bytes per pixel */ + +/* Start of the virtual frame buffer (relative to fullscreen ) */ +#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP) + static int ps3fb_mode; module_param(ps3fb_mode, int, 0); static char *mode_option __devinitdata; -static int ps3fb_get_res_table(u32 xres, u32 yres) +static int ps3fb_get_res_table(u32 xres, u32 yres, int mode) { int full_mode; unsigned int i; u32 x, y, f; - full_mode = (ps3fb_mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0; + full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0; for (i = 0;; i++) { x = ps3fb_res[i].xres; y = ps3fb_res[i].yres; f = ps3fb_res[i].type; if (!x) { - DPRINTK("ERROR: ps3fb_get_res_table()\n"); + pr_debug("ERROR: ps3fb_get_res_table()\n"); return -1; } @@ -335,7 +336,7 @@ static int ps3fb_get_res_table(u32 xres, u32 yres) } static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, - u32 *line_length) + u32 *ddr_line_length, u32 *xdr_line_length) { unsigned int i, mode; @@ -350,31 +351,41 @@ static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, var->upper_margin == ps3fb_modedb[i].upper_margin && var->lower_margin == ps3fb_modedb[i].lower_margin && var->sync == ps3fb_modedb[i].sync && - (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) { - /* Cropped broadcast modes use the full line_length */ - *line_length = - ps3fb_modedb[i < 10 ? i + 13 : i].xres * 4; - /* Full broadcast modes have the full mode bit set */ - mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1; - - DPRINTK("ps3fb_find_mode: mode %u\n", mode); - return mode; - } + (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) + goto found; - DPRINTK("ps3fb_find_mode: mode not found\n"); + pr_debug("ps3fb_find_mode: mode not found\n"); return 0; +found: + /* Cropped broadcast modes use the full line length */ + *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP; + + if (ps3_compare_firmware_version(1, 9, 0) >= 0) { + *xdr_line_length = GPU_ALIGN_UP(max(var->xres, + var->xres_virtual) * BPP); + if (*xdr_line_length > GPU_MAX_LINE_LENGTH) + *xdr_line_length = GPU_MAX_LINE_LENGTH; + } else + *xdr_line_length = *ddr_line_length; + + /* Full broadcast modes have the full mode bit set */ + mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1; + + pr_debug("ps3fb_find_mode: mode %u\n", mode); + + return mode; } -static const struct fb_videomode *ps3fb_default_mode(void) +static const struct fb_videomode *ps3fb_default_mode(int id) { - u32 mode = ps3fb_mode & PS3AV_MODE_MASK; + u32 mode = id & PS3AV_MODE_MASK; u32 flags; if (mode < 1 || mode > 13) return NULL; - flags = ps3fb_mode & ~PS3AV_MODE_MASK; + flags = id & ~PS3AV_MODE_MASK; if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { /* Full broadcast mode */ @@ -384,55 +395,77 @@ static const struct fb_videomode *ps3fb_default_mode(void) return &ps3fb_modedb[mode - 1]; } -static int ps3fb_sync(u32 frame) +static void ps3fb_sync_image(struct device *dev, u64 frame_offset, + u64 dst_offset, u64 src_offset, u32 width, + u32 height, u32 dst_line_length, + u32 src_line_length) { - int i, status; - u32 xres, yres; - u64 fb_ioif, offset; - - i = ps3fb.res_index; - xres = ps3fb_res[i].xres; - yres = ps3fb_res[i].yres; + int status; + u64 line_length; - if (frame > ps3fb.num_frames - 1) { - printk(KERN_WARNING "%s: invalid frame number (%u)\n", - __func__, frame); - return -EINVAL; - } - offset = xres * yres * BPP * frame; + line_length = dst_line_length; + if (src_line_length != dst_line_length) + line_length |= (u64)src_line_length << 32; - fb_ioif = GPU_IOIF + FB_OFF(i) + offset; status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, - offset, fb_ioif, + dst_offset, GPU_IOIF + src_offset, L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | - (xres << 16) | yres, - xres * BPP); /* line_length */ + (width << 16) | height, + line_length); if (status) - printk(KERN_ERR - "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", - __func__, status); + dev_err(dev, + "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", + __func__, status); #ifdef HEAD_A status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 0, offset, 0, 0); + 0, frame_offset, 0, 0); if (status) - printk(KERN_ERR - "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", + __func__, status); #endif #ifdef HEAD_B status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 1, offset, 0, 0); + 1, frame_offset, 0, 0); if (status) - printk(KERN_ERR - "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", + __func__, status); #endif - return 0; } +static int ps3fb_sync(struct fb_info *info, u32 frame) +{ + struct ps3fb_par *par = info->par; + int i, error = 0; + u32 ddr_line_length, xdr_line_length; + u64 ddr_base, xdr_base; + + acquire_console_sem(); + + if (frame > par->num_frames - 1) { + dev_dbg(info->device, "%s: invalid frame number (%u)\n", + __func__, frame); + error = -EINVAL; + goto out; + } + + i = par->res_index; + xdr_line_length = info->fix.line_length; + ddr_line_length = ps3fb_res[i].xres * BPP; + xdr_base = frame * info->var.yres_virtual * xdr_line_length; + ddr_base = frame * ps3fb_res[i].yres * ddr_line_length; + + ps3fb_sync_image(info->device, ddr_base + par->full_offset, + ddr_base + par->fb_offset, xdr_base + par->pan_offset, + par->width, par->height, ddr_line_length, + xdr_line_length); + +out: + release_console_sem(); + return error; +} static int ps3fb_open(struct fb_info *info, int user) { @@ -445,7 +478,7 @@ static int ps3fb_release(struct fb_info *info, int user) if (atomic_dec_and_test(&ps3fb.f_count)) { if (atomic_read(&ps3fb.ext_flip)) { atomic_set(&ps3fb.ext_flip, 0); - ps3fb_sync(0); /* single buffer */ + ps3fb_sync(info, 0); /* single buffer */ } } return 0; @@ -461,39 +494,37 @@ static int ps3fb_release(struct fb_info *info, int user) static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - u32 line_length; + u32 xdr_line_length, ddr_line_length; int mode; - int i; - DPRINTK("var->xres:%u info->var.xres:%u\n", var->xres, info->var.xres); - DPRINTK("var->yres:%u info->var.yres:%u\n", var->yres, info->var.yres); + dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres, + info->var.xres); + dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres, + info->var.yres); /* FIXME For now we do exact matches only */ - mode = ps3fb_find_mode(var, &line_length); + mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length); if (!mode) return -EINVAL; - /* - * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! - * as FB_VMODE_SMOOTH_XPAN is only used internally - */ + /* Virtual screen */ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; - if (var->vmode & FB_VMODE_CONUPDATE) { - var->vmode |= FB_VMODE_YWRAP; - var->xoffset = info->var.xoffset; - var->yoffset = info->var.yoffset; + if (var->xres_virtual > xdr_line_length / BPP) { + dev_dbg(info->device, + "Horizontal virtual screen size too large\n"); + return -EINVAL; } - /* Virtual screen and panning are not supported */ - if (var->xres_virtual > var->xres || var->yres_virtual > var->yres || - var->xoffset || var->yoffset) { - DPRINTK("Virtual screen and panning are not supported\n"); + if (var->xoffset + var->xres > var->xres_virtual || + var->yoffset + var->yres > var->yres_virtual) { + dev_dbg(info->device, "panning out-of-range\n"); return -EINVAL; } - var->xres_virtual = var->xres; - var->yres_virtual = var->yres; - /* We support ARGB8888 only */ if (var->bits_per_pixel > 32 || var->grayscale || var->red.offset > 16 || var->green.offset > 8 || @@ -502,7 +533,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->blue.length > 8 || var->transp.length > 8 || var->red.msb_right || var->green.msb_right || var->blue.msb_right || var->transp.msb_right || var->nonstd) { - DPRINTK("We support ARGB8888 only\n"); + dev_dbg(info->device, "We support ARGB8888 only\n"); return -EINVAL; } @@ -522,14 +553,13 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) /* Rotation is not supported */ if (var->rotate) { - DPRINTK("Rotation is not supported\n"); + dev_dbg(info->device, "Rotation is not supported\n"); return -EINVAL; } /* Memory limit */ - i = ps3fb_get_res_table(var->xres, var->yres); - if (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP > ps3fb_videomemory.size) { - DPRINTK("Not enough memory\n"); + if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) { + dev_dbg(info->device, "Not enough memory\n"); return -ENOMEM; } @@ -545,36 +575,69 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int ps3fb_set_par(struct fb_info *info) { - unsigned int mode; + struct ps3fb_par *par = info->par; + unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines; int i; unsigned long offset; - static int first = 1; + u64 dst; - DPRINTK("xres:%d xv:%d yres:%d yv:%d clock:%d\n", + dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n", info->var.xres, info->var.xres_virtual, info->var.yres, info->var.yres_virtual, info->var.pixclock); - i = ps3fb_get_res_table(info->var.xres, info->var.yres); - ps3fb.res_index = i; - mode = ps3fb_find_mode(&info->var, &info->fix.line_length); + mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length); if (!mode) return -EINVAL; - offset = FB_OFF(i) + VP_OFF(i); - info->fix.smem_len = ps3fb_videomemory.size - offset; - info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; - memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); + i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); + par->res_index = i; + + info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); + info->fix.smem_len = ps3fb.xdr_size; + info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; + info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; + info->fix.line_length = xdr_line_length; + + info->screen_base = (char __iomem *)ps3fb.xdr_ea; - ps3fb.num_frames = ps3fb_videomemory.size/ - (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP); + par->num_frames = ps3fb.xdr_size / + max(ps3fb_res[i].yres * ddr_line_length, + info->var.yres_virtual * xdr_line_length); /* Keep the special bits we cannot set using fb_var_screeninfo */ - ps3fb_mode = (ps3fb_mode & ~PS3AV_MODE_MASK) | mode; + par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; + + par->width = info->var.xres; + par->height = info->var.yres; + offset = VP_OFF(i); + par->fb_offset = GPU_ALIGN_UP(offset); + par->full_offset = par->fb_offset - offset; + par->pan_offset = info->var.yoffset * xdr_line_length + + info->var.xoffset * BPP; + + if (par->new_mode_id != par->mode_id) { + if (ps3av_set_video_mode(par->new_mode_id)) { + par->new_mode_id = par->mode_id; + return -EINVAL; + } + par->mode_id = par->new_mode_id; + } - if (ps3av_set_video_mode(ps3fb_mode, first)) - return -EINVAL; + /* Clear XDR frame buffer memory */ + memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); + + /* Clear DDR frame buffer memory */ + lines = ps3fb_res[i].yres * par->num_frames; + if (par->full_offset) + lines++; + maxlines = ps3fb.xdr_size / ddr_line_length; + for (dst = 0; lines; dst += maxlines * ddr_line_length) { + unsigned int l = min(lines, maxlines); + ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l, + ddr_line_length, ddr_line_length); + lines -= l; + } - first = 0; return 0; } @@ -601,6 +664,16 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red, return 0; } +static int ps3fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct ps3fb_par *par = info->par; + + par->pan_offset = var->yoffset * info->fix.line_length + + var->xoffset * BPP; + return 0; +} + /* * As we have a virtual frame buffer, we need our own mmap function */ @@ -608,24 +681,19 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red, static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned long size, offset; - int i; - - i = ps3fb_get_res_table(info->var.xres, info->var.yres); - if (i == -1) - return -EINVAL; size = vma->vm_end - vma->vm_start; offset = vma->vm_pgoff << PAGE_SHIFT; if (offset + size > info->fix.smem_len) return -EINVAL; - offset += info->fix.smem_start + FB_OFF(i) + VP_OFF(i); + offset += info->fix.smem_start; if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, size, vma->vm_page_prot)) return -EAGAIN; - printk(KERN_DEBUG "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", offset, - vma->vm_start); + dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", + offset, vma->vm_start); return 0; } @@ -637,7 +705,7 @@ static int ps3fb_blank(int blank, struct fb_info *info) { int retval; - DPRINTK("%s: blank:%d\n", __func__, blank); + dev_dbg(info->device, "%s: blank:%d\n", __func__, blank); switch (blank) { case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: @@ -664,7 +732,7 @@ static int ps3fb_get_vblank(struct fb_vblank *vblank) return 0; } -int ps3fb_wait_for_vsync(u32 crtc) +static int ps3fb_wait_for_vsync(u32 crtc) { int ret; u64 count; @@ -679,9 +747,7 @@ int ps3fb_wait_for_vsync(u32 crtc) return 0; } -EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); - -void ps3fb_flip_ctl(int on, void *data) +static void ps3fb_flip_ctl(int on, void *data) { struct ps3fb_priv *priv = data; if (on) @@ -699,14 +765,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; - u32 val, old_mode; + u32 val; int retval = -EFAULT; switch (cmd) { case FBIOGET_VBLANK: { struct fb_vblank vblank; - DPRINTK("FBIOGET_VBLANK:\n"); + dev_dbg(info->device, "FBIOGET_VBLANK:\n"); retval = ps3fb_get_vblank(&vblank); if (retval) break; @@ -719,7 +785,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, case FBIO_WAITFORVSYNC: { u32 crt; - DPRINTK("FBIO_WAITFORVSYNC:\n"); + dev_dbg(info->device, "FBIO_WAITFORVSYNC:\n"); if (get_user(crt, (u32 __user *) arg)) break; @@ -729,6 +795,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, case PS3FB_IOCTL_SETMODE: { + struct ps3fb_par *par = info->par; const struct fb_videomode *mode; struct fb_var_screeninfo var; @@ -736,15 +803,13 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, break; if (!(val & PS3AV_MODE_MASK)) { - u32 id = ps3av_get_auto_mode(0); + u32 id = ps3av_get_auto_mode(); if (id > 0) val = (val & ~PS3AV_MODE_MASK) | id; } - DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val); + dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val); retval = -EINVAL; - old_mode = ps3fb_mode; - ps3fb_mode = val; - mode = ps3fb_default_mode(); + mode = ps3fb_default_mode(val); if (mode) { var = info->var; fb_videomode_to_var(&var, mode); @@ -752,45 +817,44 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, info->flags |= FBINFO_MISC_USEREVENT; /* Force, in case only special bits changed */ var.activate |= FB_ACTIVATE_FORCE; + par->new_mode_id = val; retval = fb_set_var(info, &var); info->flags &= ~FBINFO_MISC_USEREVENT; release_console_sem(); } - if (retval) - ps3fb_mode = old_mode; break; } case PS3FB_IOCTL_GETMODE: val = ps3av_get_mode(); - DPRINTK("PS3FB_IOCTL_GETMODE:%x\n", val); + dev_dbg(info->device, "PS3FB_IOCTL_GETMODE:%x\n", val); if (!copy_to_user(argp, &val, sizeof(val))) retval = 0; break; case PS3FB_IOCTL_SCREENINFO: { + struct ps3fb_par *par = info->par; struct ps3fb_ioctl_res res; - int i = ps3fb.res_index; - DPRINTK("PS3FB_IOCTL_SCREENINFO:\n"); - res.xres = ps3fb_res[i].xres; - res.yres = ps3fb_res[i].yres; - res.xoff = ps3fb_res[i].xoff; - res.yoff = ps3fb_res[i].yoff; - res.num_frames = ps3fb.num_frames; + dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n"); + res.xres = info->fix.line_length / BPP; + res.yres = info->var.yres_virtual; + res.xoff = (res.xres - info->var.xres) / 2; + res.yoff = (res.yres - info->var.yres) / 2; + res.num_frames = par->num_frames; if (!copy_to_user(argp, &res, sizeof(res))) retval = 0; break; } case PS3FB_IOCTL_ON: - DPRINTK("PS3FB_IOCTL_ON:\n"); + dev_dbg(info->device, "PS3FB_IOCTL_ON:\n"); atomic_inc(&ps3fb.ext_flip); retval = 0; break; case PS3FB_IOCTL_OFF: - DPRINTK("PS3FB_IOCTL_OFF:\n"); + dev_dbg(info->device, "PS3FB_IOCTL_OFF:\n"); atomic_dec_if_positive(&ps3fb.ext_flip); retval = 0; break; @@ -799,8 +863,8 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, if (copy_from_user(&val, argp, sizeof(val))) break; - DPRINTK("PS3FB_IOCTL_FSEL:%d\n", val); - retval = ps3fb_sync(val); + dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val); + retval = ps3fb_sync(info, val); break; default: @@ -812,13 +876,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, static int ps3fbd(void *arg) { + struct fb_info *info = arg; + set_freezable(); while (!kthread_should_stop()) { try_to_freeze(); set_current_state(TASK_INTERRUPTIBLE); if (ps3fb.is_kicked) { ps3fb.is_kicked = 0; - ps3fb_sync(0); /* single buffer */ + ps3fb_sync(info, 0); /* single buffer */ } schedule(); } @@ -827,14 +893,15 @@ static int ps3fbd(void *arg) static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) { + struct device *dev = ptr; u64 v1; int status; struct display_head *head = &ps3fb.dinfo->display_head[1]; status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_context_intr failed: %d\n", __func__, + status); return IRQ_NONE; } @@ -854,35 +921,35 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, - struct ps3_system_bus_device *dev) + struct device *dev) { int error; - DPRINTK("version_driver:%x\n", dinfo->version_driver); - DPRINTK("irq outlet:%x\n", dinfo->irq.irq_outlet); - DPRINTK("version_gpu:%x memory_size:%x ch:%x core_freq:%d mem_freq:%d\n", + dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); + dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); + dev_dbg(dev, + "version_gpu: %x memory_size: %x ch: %x core_freq: %d " + "mem_freq:%d\n", dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { - printk(KERN_ERR "%s: version_driver err:%x\n", __func__, - dinfo->version_driver); + dev_err(dev, "%s: version_driver err:%x\n", __func__, + dinfo->version_driver); return -EINVAL; } error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, &ps3fb.irq_no); if (error) { - printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__, - error); + dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); return error; } error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, DEVICE_NAME, dev); if (error) { - printk(KERN_ERR "%s: request_irq failed %d\n", __func__, - error); + dev_err(dev, "%s: request_irq failed %d\n", __func__, error); ps3_irq_plug_destroy(ps3fb.irq_no); return error; } @@ -892,29 +959,31 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, return 0; } -static int ps3fb_xdr_settings(u64 xdr_lpar) +static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) { int status; status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, ps3fb_videomemory.size, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", + __func__, status); return -ENXIO; } - DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", + dev_dbg(dev, + "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar, virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size); status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, - xdr_lpar, ps3fb_videomemory.size, - GPU_IOIF, 0); + xdr_lpar + ps3fb.xdr_size, + GPU_CMD_BUF_SIZE, + GPU_IOIF + ps3fb.xdr_size, 0); if (status) { - printk(KERN_ERR - "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", - __func__, status); + dev_err(dev, + "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", + __func__, status); return -ENXIO; } return 0; @@ -928,6 +997,7 @@ static struct fb_ops ps3fb_ops = { .fb_check_var = ps3fb_check_var, .fb_set_par = ps3fb_set_par, .fb_setcolreg = ps3fb_setcolreg, + .fb_pan_display = ps3fb_pan_display, .fb_fillrect = sys_fillrect, .fb_copyarea = sys_copyarea, .fb_imageblit = sys_imageblit, @@ -944,7 +1014,7 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static int ps3fb_set_sync(void) +static int ps3fb_set_sync(struct device *dev) { int status; @@ -953,8 +1023,10 @@ static int ps3fb_set_sync(void) L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC " - "failed: %d\n", __func__, status); + dev_err(dev, + "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " + "%d\n", + __func__, status); return -1; } #endif @@ -964,8 +1036,10 @@ static int ps3fb_set_sync(void) 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE " - "failed: %d\n", __func__, status); + dev_err(dev, + "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " + "%d\n", + __func__, status); return -1; } #endif @@ -975,6 +1049,7 @@ static int ps3fb_set_sync(void) static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) { struct fb_info *info; + struct ps3fb_par *par; int retval = -ENOMEM; u32 xres, yres; u64 ddr_lpar = 0; @@ -983,98 +1058,106 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; - int status; - unsigned long offset; + int status, res_index; struct task_struct *task; status = ps3_open_hv_device(dev); if (status) { - printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__); + dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", + __func__); goto err; } if (!ps3fb_mode) ps3fb_mode = ps3av_get_mode(); - DPRINTK("ps3av_mode:%d\n", ps3fb_mode); + dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode); if (ps3fb_mode > 0 && !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { - ps3fb.res_index = ps3fb_get_res_table(xres, yres); - DPRINTK("res_index:%d\n", ps3fb.res_index); + res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); + dev_dbg(&dev->core, "res_index:%d\n", res_index); } else - ps3fb.res_index = GPU_RES_INDEX; + res_index = GPU_RES_INDEX; atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ init_waitqueue_head(&ps3fb.wait_vsync); - ps3fb.num_frames = 1; - ps3fb_set_sync(); + ps3fb_set_sync(&dev->core); /* get gpu context handle */ status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, &ps3fb.memory_handle, &ddr_lpar); if (status) { - printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n", - __func__, status); + dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", + __func__, status); goto err; } - DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar); + dev_dbg(&dev->core, "ddr:lpar:0x%lx\n", ddr_lpar); status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0, &ps3fb.context_handle, &lpar_dma_control, &lpar_driver_info, &lpar_reports, &lpar_reports_size); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n", - __func__, status); + dev_err(&dev->core, + "%s: lv1_gpu_context_attribute failed: %d\n", __func__, + status); goto err_gpu_memory_free; } /* vsync interrupt */ ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); if (!ps3fb.dinfo) { - printk(KERN_ERR "%s: ioremap failed\n", __func__); + dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } - retval = ps3fb_vsync_settings(ps3fb.dinfo, dev); + retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); if (retval) goto err_iounmap_dinfo; - /* xdr frame buffer */ + /* XDR frame buffer */ ps3fb.xdr_ea = ps3fb_videomemory.address; xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea)); - retval = ps3fb_xdr_settings(xdr_lpar); + + /* Clear memory to prevent kernel info leakage into userspace */ + memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); + + /* The GPU command buffer is at the end of video memory */ + ps3fb.xdr_size = ps3fb_videomemory.size - GPU_CMD_BUF_SIZE; + + retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); if (retval) goto err_free_irq; - /* - * ps3fb must clear memory to prevent kernel info - * leakage into userspace - */ - memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); - info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); + info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) goto err_free_irq; - offset = FB_OFF(ps3fb.res_index) + VP_OFF(ps3fb.res_index); - info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; + par = info->par; + par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ + par->new_mode_id = ps3fb_mode; + par->res_index = res_index; + par->num_frames = 1; + + info->screen_base = (char __iomem *)ps3fb.xdr_ea; info->fbops = &ps3fb_ops; info->fix = ps3fb_fix; info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); - info->fix.smem_len = ps3fb_videomemory.size - offset; - info->pseudo_palette = info->par; - info->par = NULL; - info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; + info->fix.smem_len = ps3fb.xdr_size; + info->pseudo_palette = par->pseudo_palette; + info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST | + FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; retval = fb_alloc_cmap(&info->cmap, 256, 0); if (retval < 0) goto err_framebuffer_release; if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, - ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(), 32)) { + ARRAY_SIZE(ps3fb_modedb), + ps3fb_default_mode(par->new_mode_id), 32)) { retval = -EINVAL; goto err_fb_dealloc; } @@ -1088,9 +1171,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) dev->core.driver_data = info; - printk(KERN_INFO - "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", - info->node, ps3fb_videomemory.size >> 10); + dev_info(info->device, "%s %s, using %lu KiB of video memory\n", + dev_driver_string(info->dev), info->dev->bus_id, + ps3fb.xdr_size >> 10); task = kthread_run(ps3fbd, info, DEVICE_NAME); if (IS_ERR(task)) { @@ -1127,7 +1210,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) int status; struct fb_info *info = dev->core.driver_data; - DPRINTK(" -> %s:%d\n", __func__, __LINE__); + dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); ps3fb_flip_ctl(0, &ps3fb); /* flip off */ ps3fb.dinfo->irq.mask = 0; @@ -1152,14 +1235,16 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) status = lv1_gpu_context_free(ps3fb.context_handle); if (status) - DPRINTK("lv1_gpu_context_free failed: %d\n", status); + dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", + status); status = lv1_gpu_memory_free(ps3fb.memory_handle); if (status) - DPRINTK("lv1_gpu_memory_free failed: %d\n", status); + dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", + status); ps3_close_hv_device(dev); - DPRINTK(" <- %s:%d\n", __func__, __LINE__); + dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); return 0; } @@ -1212,9 +1297,9 @@ static int __init ps3fb_init(void) static void __exit ps3fb_exit(void) { - DPRINTK(" -> %s:%d\n", __func__, __LINE__); + pr_debug(" -> %s:%d\n", __func__, __LINE__); ps3_system_bus_driver_unregister(&ps3fb_driver); - DPRINTK(" <- %s:%d\n", __func__, __LINE__); + pr_debug(" <- %s:%d\n", __func__, __LINE__); } module_init(ps3fb_init); diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 06805c9b237..6a3d0b57489 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -72,7 +72,7 @@ #endif #ifdef CONFIG_SH_STORE_QUEUES -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/cpu/sq.h> #endif diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index f9b12ab5964..10f912df2da 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -43,7 +43,6 @@ #include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/uaccess.h> #include <asm/div64.h> #include <asm/arch/pxa-regs.h> #include <asm/arch/bitfield.h> @@ -108,20 +107,38 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info) { struct pxafb_info *fbi = (struct pxafb_info *)info; - u_int val, ret = 1; + u_int val; - if (regno < fbi->palette_size) { - if (fbi->fb.var.grayscale) { - val = ((blue >> 8) & 0x00ff); - } else { - val = ((red >> 0) & 0xf800); - val |= ((green >> 5) & 0x07e0); - val |= ((blue >> 11) & 0x001f); - } + if (regno >= fbi->palette_size) + return 1; + + if (fbi->fb.var.grayscale) { + fbi->palette_cpu[regno] = ((blue >> 8) & 0x00ff); + return 0; + } + + switch (fbi->lccr4 & LCCR4_PAL_FOR_MASK) { + case LCCR4_PAL_FOR_0: + val = ((red >> 0) & 0xf800); + val |= ((green >> 5) & 0x07e0); + val |= ((blue >> 11) & 0x001f); fbi->palette_cpu[regno] = val; - ret = 0; + break; + case LCCR4_PAL_FOR_1: + val = ((red << 8) & 0x00f80000); + val |= ((green >> 0) & 0x0000fc00); + val |= ((blue >> 8) & 0x000000f8); + ((u32*)(fbi->palette_cpu))[regno] = val; + break; + case LCCR4_PAL_FOR_2: + val = ((red << 8) & 0x00fc0000); + val |= ((green >> 0) & 0x0000fc00); + val |= ((blue >> 8) & 0x000000fc); + ((u32*)(fbi->palette_cpu))[regno] = val; + break; } - return ret; + + return 0; } static int @@ -363,7 +380,10 @@ static int pxafb_set_par(struct fb_info *info) else fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel; - palette_mem_size = fbi->palette_size * sizeof(u16); + if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) + palette_mem_size = fbi->palette_size * sizeof(u16); + else + palette_mem_size = fbi->palette_size * sizeof(u32); pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); @@ -680,7 +700,13 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma; fbi->dmadesc_palette_cpu->fidr = 0; - fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL; + if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) + fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size * + sizeof(u16); + else + fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size * + sizeof(u32); + fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL; if (var->bits_per_pixel == 16) { /* palette shouldn't be loaded in true-color mode */ @@ -719,6 +745,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * fbi->reg_lccr1 = new_regs.lccr1; fbi->reg_lccr2 = new_regs.lccr2; fbi->reg_lccr3 = new_regs.lccr3; + fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK); + fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK); set_hsync_time(fbi, pcd); local_irq_restore(flags); @@ -825,6 +853,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi) pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1); pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2); pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3); + pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4); } static void pxafb_disable_controller(struct pxafb_info *fbi) @@ -1094,10 +1123,13 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi) * dma_writecombine_mmap) */ fbi->fb.fix.smem_start = fbi->screen_dma; - fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; - palette_mem_size = fbi->palette_size * sizeof(u16); + if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) + palette_mem_size = fbi->palette_size * sizeof(u16); + else + palette_mem_size = fbi->palette_size * sizeof(u32); + pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); @@ -1160,6 +1192,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) fbi->lccr0 = inf->lccr0; fbi->lccr3 = inf->lccr3; + fbi->lccr4 = inf->lccr4; fbi->state = C_STARTUP; fbi->task_state = (u_char)-1; diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index f8605b807b0..d920b8a14c3 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h @@ -71,6 +71,7 @@ struct pxafb_info { u_int lccr0; u_int lccr3; + u_int lccr4; u_int cmap_inverse:1, cmap_static:1, unused:30; @@ -79,6 +80,7 @@ struct pxafb_info { u_int reg_lccr1; u_int reg_lccr2; u_int reg_lccr3; + u_int reg_lccr4; unsigned long hsync_time; diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 8a4c6470d79..ae08d458709 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -20,7 +20,7 @@ * * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org> * - Added the possibility to set on or off the - * debugging mesaages + * debugging messages * - Replaced 0 and 1 by on or off when reading the * /sys files * @@ -31,8 +31,8 @@ * - add pixel clock divisor control * * 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Removed the use of currcon as it no more exist - * - Added LCD power sysfs interface + * - Removed the use of currcon as it no more exists + * - Added LCD power sysfs interface * * 2004-11-03: Ben Dooks <ben-linux@fluff.org> * - minor cleanups @@ -49,12 +49,12 @@ * - Suppress command line options * * 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org> - * - code cleanup + * - code cleanup * * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Renamed from h1940fb.c to s3c2410fb.c - * - Add support for different devices - * - Backlight support + * - Renamed from h1940fb.c to s3c2410fb.c + * - Add support for different devices + * - Backlight support * * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at> * - added clock (de-)allocation code @@ -82,13 +82,10 @@ #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> -#include <linux/workqueue.h> -#include <linux/wait.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <asm/io.h> -#include <asm/uaccess.h> #include <asm/div64.h> #include <asm/mach/map.h> @@ -102,14 +99,11 @@ #include "s3c2410fb.h" - -static struct s3c2410fb_mach_info *mach_info; - /* Debugging stuff */ #ifdef CONFIG_FB_S3C2410_DEBUG -static int debug = 1; +static int debug = 1; #else -static int debug = 0; +static int debug = 0; #endif #define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } @@ -119,48 +113,48 @@ static int debug = 0; /* s3c2410fb_set_lcdaddr * * initialise lcd controller address pointers -*/ - -static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi) + */ +static void s3c2410fb_set_lcdaddr(struct fb_info *info) { - struct fb_var_screeninfo *var = &fbi->fb->var; unsigned long saddr1, saddr2, saddr3; + struct s3c2410fb_info *fbi = info->par; + void __iomem *regs = fbi->io; - saddr1 = fbi->fb->fix.smem_start >> 1; - saddr2 = fbi->fb->fix.smem_start; - saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8; - saddr2>>= 1; + saddr1 = info->fix.smem_start >> 1; + saddr2 = info->fix.smem_start; + saddr2 += info->fix.line_length * info->var.yres; + saddr2 >>= 1; - saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff); + saddr3 = S3C2410_OFFSIZE(0) | + S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff); dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); dprintk("LCDSADDR3 = 0x%08lx\n", saddr3); - writel(saddr1, S3C2410_LCDSADDR1); - writel(saddr2, S3C2410_LCDSADDR2); - writel(saddr3, S3C2410_LCDSADDR3); + writel(saddr1, regs + S3C2410_LCDSADDR1); + writel(saddr2, regs + S3C2410_LCDSADDR2); + writel(saddr3, regs + S3C2410_LCDSADDR3); } /* s3c2410fb_calc_pixclk() * * calculate divisor for clk->pixclk -*/ - + */ static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, unsigned long pixclk) { unsigned long clk = clk_get_rate(fbi->clk); unsigned long long div; - /* pixclk is in picoseoncds, our clock is in Hz + /* pixclk is in picoseconds, our clock is in Hz * * Hz -> picoseconds is / 10^-12 */ div = (unsigned long long)clk * pixclk; - do_div(div,1000000UL); - do_div(div,1000000UL); + div >>= 12; /* div / 2^12 */ + do_div(div, 625 * 625UL * 625); /* div / 5^12 */ dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div); return div; @@ -176,246 +170,278 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct s3c2410fb_info *fbi = info->par; + struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data; + struct s3c2410fb_display *display = NULL; + struct s3c2410fb_display *default_display = mach_info->displays + + mach_info->default_display; + int type = default_display->type; + unsigned i; dprintk("check_var(var=%p, info=%p)\n", var, info); /* validate x/y resolution */ + /* choose default mode if possible */ + if (var->yres == default_display->yres && + var->xres == default_display->xres && + var->bits_per_pixel == default_display->bpp) + display = default_display; + else + for (i = 0; i < mach_info->num_displays; i++) + if (type == mach_info->displays[i].type && + var->yres == mach_info->displays[i].yres && + var->xres == mach_info->displays[i].xres && + var->bits_per_pixel == mach_info->displays[i].bpp) { + display = mach_info->displays + i; + break; + } - if (var->yres > fbi->mach_info->yres.max) - var->yres = fbi->mach_info->yres.max; - else if (var->yres < fbi->mach_info->yres.min) - var->yres = fbi->mach_info->yres.min; - - if (var->xres > fbi->mach_info->xres.max) - var->yres = fbi->mach_info->xres.max; - else if (var->xres < fbi->mach_info->xres.min) - var->xres = fbi->mach_info->xres.min; - - /* validate bpp */ - - if (var->bits_per_pixel > fbi->mach_info->bpp.max) - var->bits_per_pixel = fbi->mach_info->bpp.max; - else if (var->bits_per_pixel < fbi->mach_info->bpp.min) - var->bits_per_pixel = fbi->mach_info->bpp.min; + if (!display) { + dprintk("wrong resolution or depth %dx%d at %d bpp\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + /* it is always the size as the display */ + var->xres_virtual = display->xres; + var->yres_virtual = display->yres; + var->height = display->height; + var->width = display->width; + + /* copy lcd settings */ + var->pixclock = display->pixclock; + var->left_margin = display->left_margin; + var->right_margin = display->right_margin; + var->upper_margin = display->upper_margin; + var->lower_margin = display->lower_margin; + var->vsync_len = display->vsync_len; + var->hsync_len = display->hsync_len; + + fbi->regs.lcdcon5 = display->lcdcon5; + /* set display type */ + fbi->regs.lcdcon1 = display->type; + + var->transp.offset = 0; + var->transp.length = 0; /* set r/g/b positions */ switch (var->bits_per_pixel) { - case 1: - case 2: - case 4: - var->red.offset = 0; - var->red.length = var->bits_per_pixel; - var->green = var->red; - var->blue = var->red; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 8: - if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) { - /* 8 bpp 332 */ - var->red.length = 3; - var->red.offset = 5; - var->green.length = 3; - var->green.offset = 2; - var->blue.length = 2; - var->blue.offset = 0; - var->transp.length = 0; - } else { - var->red.offset = 0; - var->red.length = var->bits_per_pixel; - var->green = var->red; - var->blue = var->red; - var->transp.offset = 0; - var->transp.length = 0; - } - break; - case 12: - /* 12 bpp 444 */ - var->red.length = 4; - var->red.offset = 8; - var->green.length = 4; - var->green.offset = 4; - var->blue.length = 4; + case 1: + case 2: + case 4: + var->red.offset = 0; + var->red.length = var->bits_per_pixel; + var->green = var->red; + var->blue = var->red; + break; + case 8: + if (display->type != S3C2410_LCDCON1_TFT) { + /* 8 bpp 332 */ + var->red.length = 3; + var->red.offset = 5; + var->green.length = 3; + var->green.offset = 2; + var->blue.length = 2; var->blue.offset = 0; - var->transp.length = 0; - break; - - default: - case 16: - if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) { - /* 16 bpp, 565 format */ - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - var->transp.length = 0; - } else { - /* 16 bpp, 5551 format */ - var->red.offset = 11; - var->green.offset = 6; - var->blue.offset = 1; - var->red.length = 5; - var->green.length = 5; - var->blue.length = 5; - var->transp.length = 0; - } - break; - case 24: - /* 24 bpp 888 */ + } else { + var->red.offset = 0; var->red.length = 8; - var->red.offset = 16; - var->green.length = 8; - var->green.offset = 8; - var->blue.length = 8; - var->blue.offset = 0; - var->transp.length = 0; - break; - + var->green = var->red; + var->blue = var->red; + } + break; + case 12: + /* 12 bpp 444 */ + var->red.length = 4; + var->red.offset = 8; + var->green.length = 4; + var->green.offset = 4; + var->blue.length = 4; + var->blue.offset = 0; + break; + default: + case 16: + if (display->lcdcon5 & S3C2410_LCDCON5_FRM565) { + /* 16 bpp, 565 format */ + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + } else { + /* 16 bpp, 5551 format */ + var->red.offset = 11; + var->green.offset = 6; + var->blue.offset = 1; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + } + break; + case 32: + /* 24 bpp 888 and 8 dummy */ + var->red.length = 8; + var->red.offset = 16; + var->green.length = 8; + var->green.offset = 8; + var->blue.length = 8; + var->blue.offset = 0; + break; } return 0; } - -/* s3c2410fb_activate_var +/* s3c2410fb_calculate_stn_lcd_regs * - * activate (set) the controller from the given framebuffer - * information -*/ - -static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, - struct fb_var_screeninfo *var) + * calculate register values from var settings + */ +static void s3c2410fb_calculate_stn_lcd_regs(const struct fb_info *info, + struct s3c2410fb_hw *regs) { - int hs; + const struct s3c2410fb_info *fbi = info->par; + const struct fb_var_screeninfo *var = &info->var; + int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT; + int hs = var->xres >> 2; + unsigned wdly = (var->left_margin >> 4) - 1; + unsigned wlh = (var->hsync_len >> 4) - 1; - fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK; - fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT; + if (type != S3C2410_LCDCON1_STN4) + hs >>= 1; - dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); - dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); - dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); + switch (var->bits_per_pixel) { + case 1: + regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP; + break; + case 2: + regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY; + break; + case 4: + regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY; + break; + case 8: + regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP; + hs *= 3; + break; + case 12: + regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP; + hs *= 3; + break; - fbi->regs.lcdcon1 |= fbi->mach_info->type; - - if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) - switch (var->bits_per_pixel) { - case 1: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; - break; - case 2: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; - break; - case 4: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; - break; - case 8: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; - break; - case 16: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; - break; - - default: - /* invalid pixel depth */ - dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); - } - else - switch (var->bits_per_pixel) { - case 1: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP; - break; - case 2: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY; - break; - case 4: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY; - break; - case 8: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP; - break; - case 12: - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP; - break; - - default: - /* invalid pixel depth */ - dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); - } + default: + /* invalid pixel depth */ + dev_err(fbi->dev, "invalid bpp %d\n", + var->bits_per_pixel); + } + /* update X/Y info */ + dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", + var->left_margin, var->right_margin, var->hsync_len); - /* check to see if we need to update sync/borders */ + regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1); - if (!fbi->mach_info->fixed_syncs) { - dprintk("setting vert: up=%d, low=%d, sync=%d\n", - var->upper_margin, var->lower_margin, - var->vsync_len); + if (wdly > 3) + wdly = 3; - dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", - var->left_margin, var->right_margin, - var->hsync_len); + if (wlh > 3) + wlh = 3; - fbi->regs.lcdcon2 = - S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | - S3C2410_LCDCON2_VFPD(var->lower_margin - 1) | - S3C2410_LCDCON2_VSPW(var->vsync_len - 1); + regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) | + S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) | + S3C2410_LCDCON3_HOZVAL(hs - 1); - fbi->regs.lcdcon3 = - S3C2410_LCDCON3_HBPD(var->right_margin - 1) | - S3C2410_LCDCON3_HFPD(var->left_margin - 1); + regs->lcdcon4 = S3C2410_LCDCON4_WLH(wlh); +} - fbi->regs.lcdcon4 &= ~S3C2410_LCDCON4_HSPW(0xff); - fbi->regs.lcdcon4 |= S3C2410_LCDCON4_HSPW(var->hsync_len - 1); - } +/* s3c2410fb_calculate_tft_lcd_regs + * + * calculate register values from var settings + */ +static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info, + struct s3c2410fb_hw *regs) +{ + const struct s3c2410fb_info *fbi = info->par; + const struct fb_var_screeninfo *var = &info->var; + switch (var->bits_per_pixel) { + case 1: + regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; + break; + case 2: + regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; + break; + case 4: + regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; + break; + case 8: + regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; + regs->lcdcon5 |= S3C2410_LCDCON5_BSWP | + S3C2410_LCDCON5_FRM565; + regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP; + break; + case 16: + regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; + regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP; + regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP; + break; + case 32: + regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP; + regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP | + S3C2410_LCDCON5_HWSWP | + S3C2410_LCDCON5_BPP24BL); + break; + default: + /* invalid pixel depth */ + dev_err(fbi->dev, "invalid bpp %d\n", + var->bits_per_pixel); + } /* update X/Y info */ + dprintk("setting vert: up=%d, low=%d, sync=%d\n", + var->upper_margin, var->lower_margin, var->vsync_len); - fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); - fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1); - - switch(fbi->mach_info->type) { - case S3C2410_LCDCON1_DSCAN4: - case S3C2410_LCDCON1_STN8: - hs = var->xres / 8; - break; - case S3C2410_LCDCON1_STN4: - hs = var->xres / 4; - break; - default: - case S3C2410_LCDCON1_TFT: - hs = var->xres; - break; - - } + dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", + var->left_margin, var->right_margin, var->hsync_len); - /* Special cases : STN color displays */ - if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \ - || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) { - hs = hs * 3; - } + regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) | + S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | + S3C2410_LCDCON2_VFPD(var->lower_margin - 1) | + S3C2410_LCDCON2_VSPW(var->vsync_len - 1); + regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) | + S3C2410_LCDCON3_HFPD(var->left_margin - 1) | + S3C2410_LCDCON3_HOZVAL(var->xres - 1); - fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff); - fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1); + regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1); +} - if (var->pixclock > 0) { - int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); +/* s3c2410fb_activate_var + * + * activate (set) the controller from the given framebuffer + * information + */ +static void s3c2410fb_activate_var(struct fb_info *info) +{ + struct s3c2410fb_info *fbi = info->par; + void __iomem *regs = fbi->io; + int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT; + struct fb_var_screeninfo *var = &info->var; + int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2; - if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) { - clkdiv = (clkdiv / 2) -1; - if (clkdiv < 0) - clkdiv = 0; - } - else { - clkdiv = (clkdiv / 2); - if (clkdiv < 2) - clkdiv = 2; - } + dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); + dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); + dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); - fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff); - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); + if (type == S3C2410_LCDCON1_TFT) { + s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs); + --clkdiv; + if (clkdiv < 0) + clkdiv = 0; + } else { + s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs); + if (clkdiv < 2) + clkdiv = 2; } + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); + /* write new registers */ dprintk("new register set:\n"); @@ -425,47 +451,48 @@ static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4); dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5); - writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); - writel(fbi->regs.lcdcon2, S3C2410_LCDCON2); - writel(fbi->regs.lcdcon3, S3C2410_LCDCON3); - writel(fbi->regs.lcdcon4, S3C2410_LCDCON4); - writel(fbi->regs.lcdcon5, S3C2410_LCDCON5); + writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, + regs + S3C2410_LCDCON1); + writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2); + writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3); + writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4); + writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5); /* set lcd address pointers */ - s3c2410fb_set_lcdaddr(fbi); + s3c2410fb_set_lcdaddr(info); - writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID, + writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); } - /* - * s3c2410fb_set_par - Optional function. Alters the hardware state. + * s3c2410fb_set_par - Alters the hardware state. * @info: frame buffer structure that represents a single frame buffer * */ static int s3c2410fb_set_par(struct fb_info *info) { - struct s3c2410fb_info *fbi = info->par; struct fb_var_screeninfo *var = &info->var; - switch (var->bits_per_pixel) - { - case 16: - fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR; - break; - case 1: - fbi->fb->fix.visual = FB_VISUAL_MONO01; - break; - default: - fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; + switch (var->bits_per_pixel) { + case 32: + case 16: + case 12: + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + case 1: + info->fix.visual = FB_VISUAL_MONO01; + break; + default: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; } - fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8; + info->fix.line_length = (var->width * var->bits_per_pixel) / 8; /* activate this new configuration */ - s3c2410fb_activate_var(fbi, var); + s3c2410fb_activate_var(info); return 0; } @@ -493,7 +520,8 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi, } /* from pxafb.c */ -static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) { chan &= 0xffff; chan >>= 16 - bf->length; @@ -505,20 +533,22 @@ static int s3c2410fb_setcolreg(unsigned regno, unsigned transp, struct fb_info *info) { struct s3c2410fb_info *fbi = info->par; + void __iomem *regs = fbi->io; unsigned int val; - /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", regno, red, green, blue); */ + /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", + regno, red, green, blue); */ - switch (fbi->fb->fix.visual) { + switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: - /* true-colour, use pseuo-palette */ + /* true-colour, use pseudo-palette */ if (regno < 16) { - u32 *pal = fbi->fb->pseudo_palette; + u32 *pal = info->pseudo_palette; - val = chan_to_field(red, &fbi->fb->var.red); - val |= chan_to_field(green, &fbi->fb->var.green); - val |= chan_to_field(blue, &fbi->fb->var.blue); + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue, &info->var.blue); pal[regno] = val; } @@ -528,25 +558,24 @@ static int s3c2410fb_setcolreg(unsigned regno, if (regno < 256) { /* currently assume RGB 5-6-5 mode */ - val = ((red >> 0) & 0xf800); - val |= ((green >> 5) & 0x07e0); - val |= ((blue >> 11) & 0x001f); + val = (red >> 0) & 0xf800; + val |= (green >> 5) & 0x07e0; + val |= (blue >> 11) & 0x001f; - writel(val, S3C2410_TFTPAL(regno)); + writel(val, regs + S3C2410_TFTPAL(regno)); schedule_palette_update(fbi, regno, val); } break; default: - return 1; /* unknown type */ + return 1; /* unknown type */ } return 0; } - -/** +/* * s3c2410fb_blank * @blank_mode: the blank mode we want. * @info: frame buffer structure that represents a single frame buffer @@ -564,31 +593,31 @@ static int s3c2410fb_setcolreg(unsigned regno, */ static int s3c2410fb_blank(int blank_mode, struct fb_info *info) { - dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); + struct s3c2410fb_info *fbi = info->par; + void __iomem *regs = fbi->io; - if (mach_info == NULL) - return -EINVAL; + dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); if (blank_mode == FB_BLANK_UNBLANK) - writel(0x0, S3C2410_TPAL); + writel(0x0, regs + S3C2410_TPAL); else { dprintk("setting TPAL to output 0x000000\n"); - writel(S3C2410_TPAL_EN, S3C2410_TPAL); + writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL); } return 0; } -static int s3c2410fb_debug_show(struct device *dev, struct device_attribute *attr, char *buf) +static int s3c2410fb_debug_show(struct device *dev, + struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off"); } -static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - if (mach_info == NULL) - return -EINVAL; +static int s3c2410fb_debug_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ if (len < 1) return -EINVAL; @@ -607,10 +636,7 @@ static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *at return len; } - -static DEVICE_ATTR(debug, 0666, - s3c2410fb_debug_show, - s3c2410fb_debug_store); +static DEVICE_ATTR(debug, 0666, s3c2410fb_debug_show, s3c2410fb_debug_store); static struct fb_ops s3c2410fb_ops = { .owner = THIS_MODULE, @@ -623,7 +649,6 @@ static struct fb_ops s3c2410fb_ops = { .fb_imageblit = cfb_imageblit, }; - /* * s3c2410fb_map_video_memory(): * Allocates the DRAM memory for the frame buffer. This buffer is @@ -632,36 +657,38 @@ static struct fb_ops s3c2410fb_ops = { * cache. Once this area is remapped, all virtual memory * access to the video memory should occur at the new region. */ -static int __init s3c2410fb_map_video_memory(struct s3c2410fb_info *fbi) +static int __init s3c2410fb_map_video_memory(struct fb_info *info) { - dprintk("map_video_memory(fbi=%p)\n", fbi); + struct s3c2410fb_info *fbi = info->par; + dma_addr_t map_dma; + unsigned map_size = PAGE_ALIGN(info->fix.smem_len); - fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE); - fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, - &fbi->map_dma, GFP_KERNEL); + dprintk("map_video_memory(fbi=%p)\n", fbi); - fbi->map_size = fbi->fb->fix.smem_len; + info->screen_base = dma_alloc_writecombine(fbi->dev, map_size, + &map_dma, GFP_KERNEL); - if (fbi->map_cpu) { + if (info->screen_base) { /* prevent initial garbage on screen */ dprintk("map_video_memory: clear %p:%08x\n", - fbi->map_cpu, fbi->map_size); - memset(fbi->map_cpu, 0xf0, fbi->map_size); + info->screen_base, map_size); + memset(info->screen_base, 0xf0, map_size); - fbi->screen_dma = fbi->map_dma; - fbi->fb->screen_base = fbi->map_cpu; - fbi->fb->fix.smem_start = fbi->screen_dma; + info->fix.smem_start = map_dma; - dprintk("map_video_memory: dma=%08x cpu=%p size=%08x\n", - fbi->map_dma, fbi->map_cpu, fbi->fb->fix.smem_len); + dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n", + info->fix.smem_start, info->screen_base, map_size); } - return fbi->map_cpu ? 0 : -ENOMEM; + return info->screen_base ? 0 : -ENOMEM; } -static inline void s3c2410fb_unmap_video_memory(struct s3c2410fb_info *fbi) +static inline void s3c2410fb_unmap_video_memory(struct fb_info *info) { - dma_free_writecombine(fbi->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma); + struct s3c2410fb_info *fbi = info->par; + + dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len), + info->screen_base, info->fix.smem_start); } static inline void modify_gpio(void __iomem *reg, @@ -673,13 +700,13 @@ static inline void modify_gpio(void __iomem *reg, writel(tmp | set, reg); } - /* * s3c2410fb_init_registers - Initialise all LCD-related registers */ - -static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) +static int s3c2410fb_init_registers(struct fb_info *info) { + struct s3c2410fb_info *fbi = info->par; + struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data; unsigned long flags; void __iomem *regs = fbi->io; @@ -696,14 +723,6 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) local_irq_restore(flags); - writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); - writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2); - writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3); - writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4); - writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5); - - s3c2410fb_set_lcdaddr(fbi); - dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); writel(mach_info->lpcsel, regs + S3C2410_LPCSEL); @@ -712,22 +731,19 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) /* ensure temporary palette disabled */ writel(0x00, regs + S3C2410_TPAL); - /* Enable video by setting the ENVID bit to 1 */ - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID; - writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); return 0; } static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) { unsigned int i; - unsigned long ent; void __iomem *regs = fbi->io; fbi->palette_ready = 0; for (i = 0; i < 256; i++) { - if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR) + unsigned long ent = fbi->palette_buffer[i]; + if (ent == PALETTE_BUFF_CLEAR) continue; writel(ent, regs + S3C2410_TFTPAL(i)); @@ -761,13 +777,14 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static char driver_name[]="s3c2410fb"; +static char driver_name[] = "s3c2410fb"; static int __init s3c2410fb_probe(struct platform_device *pdev) { struct s3c2410fb_info *info; - struct fb_info *fbinfo; - struct s3c2410fb_hw *mregs; + struct s3c2410fb_display *display; + struct fb_info *fbinfo; + struct s3c2410fb_mach_info *mach_info; struct resource *res; int ret; int irq; @@ -777,11 +794,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) mach_info = pdev->dev.platform_data; if (mach_info == NULL) { - dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n"); + dev_err(&pdev->dev, + "no platform data for lcd, cannot attach\n"); return -EINVAL; } - mregs = &mach_info->regs; + display = mach_info->displays + mach_info->default_display; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -790,22 +808,22 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) } fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); - if (!fbinfo) { + if (!fbinfo) return -ENOMEM; - } + + platform_set_drvdata(pdev, fbinfo); info = fbinfo->par; - info->fb = fbinfo; info->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { - dev_err(&pdev->dev, "failed to get memory registersn"); + dev_err(&pdev->dev, "failed to get memory registers\n"); ret = -ENXIO; goto dealloc_fb; } - size = (res->end - res->start)+1; + size = (res->end - res->start) + 1; info->mem = request_mem_region(res->start, size, pdev->name); if (info->mem == NULL) { dev_err(&pdev->dev, "failed to get memory region\n"); @@ -820,21 +838,14 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) goto release_mem; } - platform_set_drvdata(pdev, fbinfo); - dprintk("devinit\n"); strcpy(fbinfo->fix.id, driver_name); - memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); - - /* Stop the video and unset ENVID if set */ - info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; + /* Stop the video */ lcdcon1 = readl(info->io + S3C2410_LCDCON1); writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); - info->mach_info = pdev->dev.platform_data; - fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; fbinfo->fix.type_aux = 0; fbinfo->fix.xpanstep = 0; @@ -844,8 +855,6 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) fbinfo->var.nonstd = 0; fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.height = mach_info->height; - fbinfo->var.width = mach_info->width; fbinfo->var.accel_flags = 0; fbinfo->var.vmode = FB_VMODE_NONINTERLACED; @@ -853,32 +862,6 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) fbinfo->flags = FBINFO_FLAG_DEFAULT; fbinfo->pseudo_palette = &info->pseudo_pal; - fbinfo->var.xres = mach_info->xres.defval; - fbinfo->var.xres_virtual = mach_info->xres.defval; - fbinfo->var.yres = mach_info->yres.defval; - fbinfo->var.yres_virtual = mach_info->yres.defval; - fbinfo->var.bits_per_pixel = mach_info->bpp.defval; - - fbinfo->var.upper_margin = S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1; - fbinfo->var.lower_margin = S3C2410_LCDCON2_GET_VFPD(mregs->lcdcon2) + 1; - fbinfo->var.vsync_len = S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1; - - fbinfo->var.left_margin = S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1; - fbinfo->var.right_margin = S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1; - fbinfo->var.hsync_len = S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1; - - fbinfo->var.red.offset = 11; - fbinfo->var.green.offset = 5; - fbinfo->var.blue.offset = 0; - fbinfo->var.transp.offset = 0; - fbinfo->var.red.length = 5; - fbinfo->var.green.length = 6; - fbinfo->var.blue.length = 5; - fbinfo->var.transp.length = 0; - fbinfo->fix.smem_len = mach_info->xres.max * - mach_info->yres.max * - mach_info->bpp.max / 8; - for (i = 0; i < 256; i++) info->palette_buffer[i] = PALETTE_BUFF_CLEAR; @@ -901,23 +884,39 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) msleep(1); + /* find maximum required memory size for display */ + for (i = 0; i < mach_info->num_displays; i++) { + unsigned long smem_len = mach_info->displays[i].xres; + + smem_len *= mach_info->displays[i].yres; + smem_len *= mach_info->displays[i].bpp; + smem_len >>= 3; + if (fbinfo->fix.smem_len < smem_len) + fbinfo->fix.smem_len = smem_len; + } + /* Initialize video memory */ - ret = s3c2410fb_map_video_memory(info); + ret = s3c2410fb_map_video_memory(fbinfo); if (ret) { - printk( KERN_ERR "Failed to allocate video RAM: %d\n", ret); + printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; goto release_clock; } dprintk("got video memory\n"); - ret = s3c2410fb_init_registers(info); + fbinfo->var.xres = display->xres; + fbinfo->var.yres = display->yres; + fbinfo->var.bits_per_pixel = display->bpp; + + s3c2410fb_init_registers(fbinfo); - ret = s3c2410fb_check_var(&fbinfo->var, fbinfo); + s3c2410fb_check_var(&fbinfo->var, fbinfo); ret = register_framebuffer(fbinfo); if (ret < 0) { - printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret); + printk(KERN_ERR "Failed to register framebuffer device: %d\n", + ret); goto free_video_memory; } @@ -930,18 +929,19 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) return 0; free_video_memory: - s3c2410fb_unmap_video_memory(info); + s3c2410fb_unmap_video_memory(fbinfo); release_clock: clk_disable(info->clk); clk_put(info->clk); release_irq: - free_irq(irq,info); + free_irq(irq, info); release_regs: iounmap(info->io); release_mem: release_resource(info->mem); kfree(info->mem); dealloc_fb: + platform_set_drvdata(pdev, NULL); framebuffer_release(fbinfo); return ret; } @@ -949,8 +949,7 @@ dealloc_fb: /* s3c2410fb_stop_lcd * * shutdown the lcd controller -*/ - + */ static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) { unsigned long flags; @@ -968,28 +967,33 @@ static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) */ static int s3c2410fb_remove(struct platform_device *pdev) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct fb_info *fbinfo = platform_get_drvdata(pdev); struct s3c2410fb_info *info = fbinfo->par; int irq; + unregister_framebuffer(fbinfo); + s3c2410fb_stop_lcd(info); msleep(1); - s3c2410fb_unmap_video_memory(info); + s3c2410fb_unmap_video_memory(fbinfo); - if (info->clk) { - clk_disable(info->clk); - clk_put(info->clk); - info->clk = NULL; + if (info->clk) { + clk_disable(info->clk); + clk_put(info->clk); + info->clk = NULL; } irq = platform_get_irq(pdev, 0); - free_irq(irq,info); + free_irq(irq, info); + + iounmap(info->io); release_resource(info->mem); kfree(info->mem); - iounmap(info->io); - unregister_framebuffer(fbinfo); + + platform_set_drvdata(pdev, NULL); + framebuffer_release(fbinfo); return 0; } @@ -997,7 +1001,6 @@ static int s3c2410fb_remove(struct platform_device *pdev) #ifdef CONFIG_PM /* suspend and resume support for the lcd controller */ - static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) { struct fb_info *fbinfo = platform_get_drvdata(dev); @@ -1044,7 +1047,7 @@ static struct platform_driver s3c2410fb_driver = { }, }; -int __devinit s3c2410fb_init(void) +int __init s3c2410fb_init(void) { return platform_driver_register(&s3c2410fb_driver); } @@ -1054,10 +1057,10 @@ static void __exit s3c2410fb_cleanup(void) platform_driver_unregister(&s3c2410fb_driver); } - module_init(s3c2410fb_init); module_exit(s3c2410fb_cleanup); -MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, Ben Dooks <ben-linux@fluff.org>"); +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " + "Ben Dooks <ben-linux@fluff.org>"); MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index 17c7915b7ac..6ce5dc26c5f 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h @@ -16,7 +16,7 @@ * * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> * - Renamed from h1940fb.h to s3c2410fb.h - * - Chenged h1940 to s3c2410 + * - Changed h1940 to s3c2410 * * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org> * - First version @@ -26,25 +26,14 @@ #define __S3C2410FB_H struct s3c2410fb_info { - struct fb_info *fb; struct device *dev; struct clk *clk; struct resource *mem; void __iomem *io; - struct s3c2410fb_mach_info *mach_info; - - /* raw memory addresses */ - dma_addr_t map_dma; /* physical */ - u_char * map_cpu; /* virtual */ - u_int map_size; - struct s3c2410fb_hw regs; - /* addresses of pieces placed in raw buffer */ - u_char * screen_cpu; /* virtual address of buffer */ - dma_addr_t screen_dma; /* physical address of buffer */ unsigned int palette_ready; /* keep these registers in case we need to re-write palette */ diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index d11735895a0..7d53bc23b9c 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -400,11 +400,17 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct s3fb_info *par = info->par; int rv, mem, step; + u16 m, n, r; /* Find appropriate format */ rv = svga_match_format (s3fb_formats, var, NULL); - if ((rv < 0) || ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6))) - { /* 24bpp on VIRGE VX, 32bpp on others */ + + /* 32bpp mode is not supported on VIRGE VX, + 24bpp is not supported on others */ + if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6)) + rv = -EINVAL; + + if (rv < 0) { printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); return rv; } @@ -422,20 +428,26 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) /* Check whether have enough memory */ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; - if (mem > info->screen_size) - { + if (mem > info->screen_size) { printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); return -EINVAL; } rv = svga_check_timings (&s3_timing_regs, var, info->node); - if (rv < 0) - { + if (rv < 0) { printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); return rv; } + rv = svga_compute_pll(&s3_pll, PICOS2KHZ(var->pixclock), &m, &n, &r, + info->node); + if (rv < 0) { + printk(KERN_ERR "fb%d: invalid pixclock value requested\n", + info->node); + return rv; + } + return 0; } diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 5d2a4a4b731..ab2b2110478 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -178,7 +178,6 @@ #include <asm/hardware.h> #include <asm/io.h> #include <asm/mach-types.h> -#include <asm/uaccess.h> #include <asm/arch/assabet.h> #include <asm/arch/shannon.h> diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index b855f4a34af..37b135d5d12 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -57,7 +57,6 @@ #include <asm/irq.h> #include <asm/pgtable.h> #include <asm/system.h> -#include <asm/uaccess.h> #ifdef CONFIG_MTRR #include <asm/mtrr.h> diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index e8ccace0125..bc7d2368373 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -58,7 +58,7 @@ #include <linux/capability.h> #include <linux/fs.h> #include <linux/types.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/io.h> #ifdef CONFIG_MTRR #include <asm/mtrr.h> diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 64779e70408..62321458f71 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -780,7 +780,7 @@ static int __devinit xxxfb_probe(struct pci_dev *dev, * * NOTE: This field is currently unused. */ - info->pixmap.scan_align = 32; + info->pixmap.access_align = 32; /***************************** End optional stage ***************************/ /* diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index c86df126f93..1be95a68d69 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -28,6 +28,7 @@ #include <linux/wait.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/console.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -62,6 +63,8 @@ struct sm501fb_info { struct resource *regs_res; /* registers resource */ struct sm501_platdata_fb *pdata; /* our platform data */ + unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ + int irq; int swap_endian; /* set to swap rgb=>bgr */ void __iomem *regs; /* remapped registers */ @@ -774,6 +777,11 @@ static int sm501fb_set_par_pnl(struct fb_info *info) writel(control, fbi->regs + SM501_DC_PANEL_CONTROL); sm501fb_sync_regs(fbi); + /* ensure the panel interface is not tristated at this point */ + + sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL, + 0, SM501_SYSCTRL_PANEL_TRISTATE); + /* power the panel up */ sm501fb_panel_power(fbi, 1); return 0; @@ -1687,19 +1695,25 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info, goto err_nocursor; } + dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb); + dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor); + memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size); memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size); - /* blank the relevant interface to ensure unit power minimised */ (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); + acquire_console_sem(); + fb_set_suspend(fbi, 1); + release_console_sem(); + return 0; err_nocursor: vfree(par->store_fb); + par->store_fb = NULL; return -ENOMEM; - } static void sm501fb_resume_fb(struct sm501fb_info *info, @@ -1717,8 +1731,20 @@ static void sm501fb_resume_fb(struct sm501fb_info *info, /* restore the data */ - memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size); - memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size); + dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb); + dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor); + + if (par->store_fb) + memcpy_toio(par->screen.k_addr, par->store_fb, + par->screen.size); + + if (par->store_cursor) + memcpy_toio(par->cursor.k_addr, par->store_cursor, + par->cursor.size); + + acquire_console_sem(); + fb_set_suspend(fbi, 0); + release_console_sem(); vfree(par->store_fb); vfree(par->store_cursor); @@ -1731,6 +1757,9 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state) { struct sm501fb_info *info = platform_get_drvdata(pdev); + /* store crt control to resume with */ + info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); + sm501fb_suspend_fb(info, HEAD_CRT); sm501fb_suspend_fb(info, HEAD_PANEL); @@ -1740,12 +1769,24 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state) return 0; } +#define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \ + SM501_DC_CRT_CONTROL_SEL) + + static int sm501fb_resume(struct platform_device *pdev) { struct sm501fb_info *info = platform_get_drvdata(pdev); + unsigned long crt_ctrl; sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1); + /* restore the items we want to be saved for crt control */ + + crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); + crt_ctrl &= ~SM501_CRT_CTRL_SAVE; + crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE; + writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL); + sm501fb_resume_fb(info, HEAD_CRT); sm501fb_resume_fb(info, HEAD_PANEL); diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 5eff28ce4f4..97784f9c184 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -88,7 +88,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <video/sstfb.h> diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 25df928d37d..9c710670157 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -598,9 +598,11 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf /* ------------------------------------------------------------------------- */ -int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix) +static inline int match_format(const struct svga_fb_format *frm, + struct fb_var_screeninfo *var) { int i = 0; + int stored = -EINVAL; while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL) { @@ -609,25 +611,38 @@ int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo (var->green.length <= frm->green.length) && (var->blue.length <= frm->blue.length) && (var->transp.length <= frm->transp.length) && - (var->nonstd == frm->nonstd)) { - var->bits_per_pixel = frm->bits_per_pixel; - var->red = frm->red; - var->green = frm->green; - var->blue = frm->blue; - var->transp = frm->transp; - var->nonstd = frm->nonstd; - if (fix != NULL) { - fix->type = frm->type; - fix->type_aux = frm->type_aux; - fix->visual = frm->visual; - fix->xpanstep = frm->xpanstep; - } + (var->nonstd == frm->nonstd)) return i; - } + if (var->bits_per_pixel == frm->bits_per_pixel) + stored = i; i++; frm++; } - return -EINVAL; + return stored; +} + +int svga_match_format(const struct svga_fb_format *frm, + struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix) +{ + int i = match_format(frm, var); + + if (i >= 0) { + var->bits_per_pixel = frm[i].bits_per_pixel; + var->red = frm[i].red; + var->green = frm[i].green; + var->blue = frm[i].blue; + var->transp = frm[i].transp; + var->nonstd = frm[i].nonstd; + if (fix != NULL) { + fix->type = frm[i].type; + fix->type_aux = frm[i].type_aux; + fix->visual = frm[i].visual; + fix->xpanstep = frm[i].xpanstep; + } + } + + return i; } diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 689ce0270b8..057bdd59380 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -4,13 +4,13 @@ * * Author: Hannu Mallat <hmallat@cc.hut.fi> * - * Copyright © 1999 Hannu Mallat + * Copyright © 1999 Hannu Mallat * All rights reserved * * Created : Thu Sep 23 18:17:43 1999, hmallat * Last modified: Tue Nov 2 21:19:47 1999, hmallat * - * Lots of the information here comes from the Daryll Strauss' Banshee + * Lots of the information here comes from the Daryll Strauss' Banshee * patches to the XF86 server, and the rest comes from the 3dfx * Banshee specification. I'm very much indebted to Daryll for his * work on the X server. @@ -23,7 +23,7 @@ * behave very differently from the Voodoo3/4/5. For anyone wanting to * use frame buffer on the Voodoo1/2, see the sstfb driver (which is * located at http://www.sourceforge.net/projects/sstfb). - * + * * While I _am_ grateful to 3Dfx for releasing the specs for Banshee, * I do wish the next version is a bit more complete. Without the XF86 * patches I couldn't have gotten even this far... for instance, the @@ -33,9 +33,8 @@ * * The structure of this driver comes pretty much from the Permedia * driver by Ilario Nardinocchi, which in turn is based on skeletonfb. - * + * * TODO: - * - support for 16/32 bpp needs fixing (funky bootup penguin) * - multihead support (basically need to support an array of fb_infos) * - support other architectures (PPC, Alpha); does the fact that the VGA * core can be accessed only thru I/O (not memory mapped) complicate @@ -43,18 +42,18 @@ * * Version history: * - * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons + * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons * - * 0.1.3 (released 1999-11-02) added Attila's panning support, code - * reorg, hwcursor address page size alignment - * (for mmaping both frame buffer and regs), - * and my changes to get rid of hardcoded - * VGA i/o register locations (uses PCI - * configuration info now) - * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and - * improvements - * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga. - * 0.1.0 (released 1999-10-06) initial version + * 0.1.3 (released 1999-11-02) added Attila's panning support, code + * reorg, hwcursor address page size alignment + * (for mmaping both frame buffer and regs), + * and my changes to get rid of hardcoded + * VGA i/o register locations (uses PCI + * configuration info now) + * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and + * improvements + * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga. + * 0.1.0 (released 1999-10-06) initial version * */ @@ -64,24 +63,32 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/slab.h> -#include <linux/delay.h> -#include <linux/interrupt.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/nvram.h> #include <asm/io.h> -#include <linux/timer.h> -#include <linux/spinlock.h> #include <video/tdfx.h> -#undef TDFXFB_DEBUG -#ifdef TDFXFB_DEBUG -#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b) +#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __FUNCTION__ , ## b) + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> #else -#define DPRINTK(a,b...) -#endif +/* duplicate asm/mtrr.h defines to work on archs without mtrr */ +#define MTRR_TYPE_WRCOMB 1 + +static inline int mtrr_add(unsigned long base, unsigned long size, + unsigned int type, char increment) +{ + return -ENODEV; +} +static inline int mtrr_del(int reg, unsigned long base, + unsigned long size) +{ + return -ENODEV; +} +#endif #define BANSHEE_MAX_PIXCLOCK 270000 #define VOODOO3_MAX_PIXCLOCK 300000 @@ -90,9 +97,9 @@ static struct fb_fix_screeninfo tdfx_fix __devinitdata = { .id = "3Dfx", .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_PSEUDOCOLOR, + .visual = FB_VISUAL_PSEUDOCOLOR, .ypanstep = 1, - .ywrapstep = 1, + .ywrapstep = 1, .accel = FB_ACCEL_3DFX_BANSHEE }; @@ -102,7 +109,7 @@ static struct fb_var_screeninfo tdfx_var __devinitdata = { .yres = 480, .xres_virtual = 640, .yres_virtual = 1024, - .bits_per_pixel =8, + .bits_per_pixel = 8, .red = {0, 8, 0}, .blue = {0, 8, 0}, .green = {0, 8, 0}, @@ -142,103 +149,79 @@ static struct pci_device_id tdfxfb_id_table[] = { static struct pci_driver tdfxfb_driver = { .name = "tdfxfb", - .id_table = tdfxfb_id_table, - .probe = tdfxfb_probe, - .remove = __devexit_p(tdfxfb_remove), + .id_table = tdfxfb_id_table, + .probe = tdfxfb_probe, + .remove = __devexit_p(tdfxfb_remove), }; MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); /* - * Frame buffer device API + * Driver data */ -static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); -static int tdfxfb_set_par(struct fb_info *info); -static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); -static int tdfxfb_blank(int blank, struct fb_info *info); -static int tdfxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); -static int banshee_wait_idle(struct fb_info *info); -#ifdef CONFIG_FB_3DFX_ACCEL -static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); -static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image); -#endif /* CONFIG_FB_3DFX_ACCEL */ - -static struct fb_ops tdfxfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = tdfxfb_check_var, - .fb_set_par = tdfxfb_set_par, - .fb_setcolreg = tdfxfb_setcolreg, - .fb_blank = tdfxfb_blank, - .fb_pan_display = tdfxfb_pan_display, - .fb_sync = banshee_wait_idle, -#ifdef CONFIG_FB_3DFX_ACCEL - .fb_fillrect = tdfxfb_fillrect, - .fb_copyarea = tdfxfb_copyarea, - .fb_imageblit = tdfxfb_imageblit, -#else - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -#endif -}; - -/* - * do_xxx: Hardware-specific functions - */ -static u32 do_calc_pll(int freq, int *freq_out); -static void do_write_regs(struct fb_info *info, struct banshee_reg *reg); -static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short); - -/* - * Driver data - */ -static int nopan = 0; -static int nowrap = 1; // not implemented (yet) -static char *mode_option __devinitdata = NULL; - -/* ------------------------------------------------------------------------- - * Hardware-specific funcions +static int nopan; +static int nowrap = 1; /* not implemented (yet) */ +static int hwcursor = 1; +static char *mode_option __devinitdata; +/* mtrr option */ +static int nomtrr __devinitdata; + +/* ------------------------------------------------------------------------- + * Hardware-specific funcions * ------------------------------------------------------------------------- */ -#ifdef VGA_REG_IO -static inline u8 vga_inb(struct tdfx_par *par, u32 reg) { return inb(reg); } - -static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) { outb(val, reg); } -#else -static inline u8 vga_inb(struct tdfx_par *par, u32 reg) { - return inb(par->iobase + reg - 0x300); +static inline u8 vga_inb(struct tdfx_par *par, u32 reg) +{ + return inb(par->iobase + reg - 0x300); } -static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) { - outb(val, par->iobase + reg - 0x300); + +static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) +{ + outb(val, par->iobase + reg - 0x300); } -#endif -static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) { - vga_outb(par, GRA_I, idx); vga_outb(par, GRA_D, val); +static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) +{ + vga_outb(par, GRA_I, idx); + wmb(); + vga_outb(par, GRA_D, val); + wmb(); } -static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) { - vga_outb(par, SEQ_I, idx); vga_outb(par, SEQ_D, val); +static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) +{ + vga_outb(par, SEQ_I, idx); + wmb(); + vga_outb(par, SEQ_D, val); + wmb(); } -static inline u8 seq_inb(struct tdfx_par *par, u32 idx) { - vga_outb(par, SEQ_I, idx); return vga_inb(par, SEQ_D); +static inline u8 seq_inb(struct tdfx_par *par, u32 idx) +{ + vga_outb(par, SEQ_I, idx); + mb(); + return vga_inb(par, SEQ_D); } -static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) { - vga_outb(par, CRT_I, idx); vga_outb(par, CRT_D, val); +static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) +{ + vga_outb(par, CRT_I, idx); + wmb(); + vga_outb(par, CRT_D, val); + wmb(); } -static inline u8 crt_inb(struct tdfx_par *par, u32 idx) { - vga_outb(par, CRT_I, idx); return vga_inb(par, CRT_D); +static inline u8 crt_inb(struct tdfx_par *par, u32 idx) +{ + vga_outb(par, CRT_I, idx); + mb(); + return vga_inb(par, CRT_D); } -static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val) +static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val) { unsigned char tmp; - + tmp = vga_inb(par, IS1_R); vga_outb(par, ATT_IW, idx); vga_outb(par, ATT_IW, val); @@ -267,10 +250,11 @@ static inline void vga_enable_video(struct tdfx_par *par) static inline void vga_enable_palette(struct tdfx_par *par) { vga_inb(par, IS1_R); + mb(); vga_outb(par, ATT_IW, 0x20); } -static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg) +static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg) { return readl(par->regbase_virt + reg); } @@ -284,9 +268,10 @@ static inline void banshee_make_room(struct tdfx_par *par, int size) { /* Note: The Voodoo3's onboard FIFO has 32 slots. This loop * won't quit if you ask for more. */ - while((tdfx_inl(par, STATUS) & 0x1f) < size-1); + while ((tdfx_inl(par, STATUS) & 0x1f) < size - 1) + cpu_relax(); } - + static int banshee_wait_idle(struct fb_info *info) { struct tdfx_par *par = info->par; @@ -295,28 +280,31 @@ static int banshee_wait_idle(struct fb_info *info) banshee_make_room(par, 1); tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP); - while(1) { - i = (tdfx_inl(par, STATUS) & STATUS_BUSY) ? 0 : i + 1; - if(i == 3) break; - } + do { + if ((tdfx_inl(par, STATUS) & STATUS_BUSY) == 0) + i++; + } while (i < 3); + return 0; } /* - * Set the color of a palette entry in 8bpp mode + * Set the color of a palette entry in 8bpp mode */ static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c) -{ +{ banshee_make_room(par, 2); tdfx_outl(par, DACADDR, regno); + /* read after write makes it working */ + tdfx_inl(par, DACADDR); tdfx_outl(par, DACDATA, c); } -static u32 do_calc_pll(int freq, int* freq_out) +static u32 do_calc_pll(int freq, int *freq_out) { int m, n, k, best_m, best_n, best_k, best_error; int fref = 14318; - + best_error = freq; best_n = best_m = best_k = 0; @@ -326,27 +314,28 @@ static u32 do_calc_pll(int freq, int* freq_out) * Estimate value of n that produces target frequency * with current m and k */ - int n_estimated = (freq * (m + 2) * (1 << k) / fref) - 2; + int n_estimated = ((freq * (m + 2) << k) / fref) - 2; /* Search neighborhood of estimated n */ - for (n = max(0, n_estimated - 1); - n <= min(255, n_estimated + 1); n++) { + for (n = max(0, n_estimated); + n <= min(255, n_estimated + 1); + n++) { /* * Calculate PLL freqency with current m, k and * estimated n */ - int f = fref * (n + 2) / (m + 2) / (1 << k); - int error = abs (f - freq); + int f = (fref * (n + 2) / (m + 2)) >> k; + int error = abs(f - freq); /* - * If this is the closest we've come to the + * If this is the closest we've come to the * target frequency then remember n, m and k */ - if (error < best_error) { + if (error < best_error) { best_error = error; - best_n = n; - best_m = m; - best_k = k; + best_n = n; + best_m = m; + best_k = k; } } } @@ -355,12 +344,12 @@ static u32 do_calc_pll(int freq, int* freq_out) n = best_n; m = best_m; k = best_k; - *freq_out = fref*(n + 2)/(m + 2)/(1 << k); + *freq_out = (fref * (n + 2) / (m + 2)) >> k; return (n << 8) | (m << 2) | k; } -static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) +static void do_write_regs(struct fb_info *info, struct banshee_reg *reg) { struct tdfx_par *par = info->par; int i; @@ -372,13 +361,13 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */ banshee_make_room(par, 3); - tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF); - tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001); + tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF); + tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001); #if 0 tdfx_outl(par, PLLCTRL1, reg->mempll); tdfx_outl(par, PLLCTRL2, reg->gfxpll); #endif - tdfx_outl(par, PLLCTRL0, reg->vidpll); + tdfx_outl(par, PLLCTRL0, reg->vidpll); vga_outb(par, MISC_W, reg->misc[0x00] | 0x01); @@ -400,72 +389,65 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) vga_enable_palette(par); vga_enable_video(par); - banshee_make_room(par, 11); - tdfx_outl(par, VGAINIT0, reg->vgainit0); - tdfx_outl(par, DACMODE, reg->dacmode); - tdfx_outl(par, VIDDESKSTRIDE, reg->stride); - tdfx_outl(par, HWCURPATADDR, 0); - - tdfx_outl(par, VIDSCREENSIZE,reg->screensize); - tdfx_outl(par, VIDDESKSTART, reg->startaddr); - tdfx_outl(par, VIDPROCCFG, reg->vidcfg); - tdfx_outl(par, VGAINIT1, reg->vgainit1); - tdfx_outl(par, MISCINIT0, reg->miscinit0); - - banshee_make_room(par, 8); - tdfx_outl(par, SRCBASE, reg->srcbase); - tdfx_outl(par, DSTBASE, reg->dstbase); - tdfx_outl(par, COMMANDEXTRA_2D, 0); - tdfx_outl(par, CLIP0MIN, 0); - tdfx_outl(par, CLIP0MAX, 0x0fff0fff); - tdfx_outl(par, CLIP1MIN, 0); - tdfx_outl(par, CLIP1MAX, 0x0fff0fff); - tdfx_outl(par, SRCXY, 0); + banshee_make_room(par, 9); + tdfx_outl(par, VGAINIT0, reg->vgainit0); + tdfx_outl(par, DACMODE, reg->dacmode); + tdfx_outl(par, VIDDESKSTRIDE, reg->stride); + tdfx_outl(par, HWCURPATADDR, reg->curspataddr); + + tdfx_outl(par, VIDSCREENSIZE, reg->screensize); + tdfx_outl(par, VIDDESKSTART, reg->startaddr); + tdfx_outl(par, VIDPROCCFG, reg->vidcfg); + tdfx_outl(par, VGAINIT1, reg->vgainit1); + tdfx_outl(par, MISCINIT0, reg->miscinit0); + + banshee_make_room(par, 8); + tdfx_outl(par, SRCBASE, reg->startaddr); + tdfx_outl(par, DSTBASE, reg->startaddr); + tdfx_outl(par, COMMANDEXTRA_2D, 0); + tdfx_outl(par, CLIP0MIN, 0); + tdfx_outl(par, CLIP0MAX, 0x0fff0fff); + tdfx_outl(par, CLIP1MIN, 0); + tdfx_outl(par, CLIP1MAX, 0x0fff0fff); + tdfx_outl(par, SRCXY, 0); banshee_wait_idle(info); } -static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) +static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) { - u32 draminit0; - u32 draminit1; + u32 draminit0 = tdfx_inl(par, DRAMINIT0); + u32 draminit1 = tdfx_inl(par, DRAMINIT1); u32 miscinit1; - - int num_chips; + int num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4; int chip_size; /* in MB */ - u32 lfbsize; - int has_sgram; + int has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM; - draminit0 = tdfx_inl(par, DRAMINIT0); - draminit1 = tdfx_inl(par, DRAMINIT1); - - num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4; - if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) { /* Banshee/Voodoo3 */ - has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM; - chip_size = has_sgram ? ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 2 : 1) - : 2; + chip_size = 2; + if (has_sgram && (draminit0 & DRAMINIT0_SGRAM_TYPE)) + chip_size = 1; } else { /* Voodoo4/5 */ has_sgram = 0; - chip_size = 1 << ((draminit0 & DRAMINIT0_SGRAM_TYPE_MASK) >> DRAMINIT0_SGRAM_TYPE_SHIFT); + chip_size = draminit0 & DRAMINIT0_SGRAM_TYPE_MASK; + chip_size = 1 << (chip_size >> DRAMINIT0_SGRAM_TYPE_SHIFT); } - lfbsize = num_chips * chip_size * 1024 * 1024; /* disable block writes for SDRAM */ miscinit1 = tdfx_inl(par, MISCINIT1); miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS; miscinit1 |= MISCINIT1_CLUT_INV; - banshee_make_room(par, 1); + banshee_make_room(par, 1); tdfx_outl(par, MISCINIT1, miscinit1); - return lfbsize; + return num_chips * chip_size * 1024l * 1024; } /* ------------------------------------------------------------------------- */ -static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) +static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct tdfx_par *par = info->par; u32 lpitch; @@ -486,103 +468,113 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) DPRINTK("xoffset not supported\n"); return -EINVAL; } + var->yoffset = 0; - /* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */ - /* no direct information about device id now? use max_pixclock for this... */ + /* + * Banshee doesn't support interlace, but Voodoo4/5 and probably + * Voodoo3 do. + * no direct information about device id now? + * use max_pixclock for this... + */ if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) && - (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) { + (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) { DPRINTK("interlace not supported\n"); return -EINVAL; } var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ - lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); - + lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); + if (var->xres < 320 || var->xres > 2048) { DPRINTK("width not supported: %u\n", var->xres); return -EINVAL; } - + if (var->yres < 200 || var->yres > 2048) { DPRINTK("height not supported: %u\n", var->yres); return -EINVAL; } - + if (lpitch * var->yres_virtual > info->fix.smem_len) { - var->yres_virtual = info->fix.smem_len/lpitch; + var->yres_virtual = info->fix.smem_len / lpitch; if (var->yres_virtual < var->yres) { DPRINTK("no memory for screen (%ux%ux%u)\n", - var->xres, var->yres_virtual, var->bits_per_pixel); + var->xres, var->yres_virtual, + var->bits_per_pixel); return -EINVAL; } } - + if (PICOS2KHZ(var->pixclock) > par->max_pixclock) { - DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock)); + DPRINTK("pixclock too high (%ldKHz)\n", + PICOS2KHZ(var->pixclock)); return -EINVAL; } - switch(var->bits_per_pixel) { - case 8: - var->red.length = var->green.length = var->blue.length = 8; - break; - case 16: - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - break; - case 24: - var->red.offset=16; - var->green.offset=8; - var->blue.offset=0; - var->red.length = var->green.length = var->blue.length = 8; - case 32: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = var->green.length = var->blue.length = 8; - break; + var->transp.offset = 0; + var->transp.length = 0; + switch (var->bits_per_pixel) { + case 8: + var->red.length = 8; + var->red.offset = 0; + var->green = var->red; + var->blue = var->red; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 32: + var->transp.offset = 24; + var->transp.length = 8; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 8; + break; } - var->height = var->width = -1; - + var->width = -1; + var->height = -1; + var->accel_flags = FB_ACCELF_TEXT; - - DPRINTK("Checking graphics mode at %dx%d depth %d\n", var->xres, var->yres, var->bits_per_pixel); + + DPRINTK("Checking graphics mode at %dx%d depth %d\n", + var->xres, var->yres, var->bits_per_pixel); return 0; } static int tdfxfb_set_par(struct fb_info *info) { struct tdfx_par *par = info->par; - u32 hdispend, hsyncsta, hsyncend, htotal; + u32 hdispend = info->var.xres; + u32 hsyncsta = hdispend + info->var.right_margin; + u32 hsyncend = hsyncsta + info->var.hsync_len; + u32 htotal = hsyncend + info->var.left_margin; u32 hd, hs, he, ht, hbs, hbe; u32 vd, vs, ve, vt, vbs, vbe; struct banshee_reg reg; int fout, freq; - u32 wd, cpp; - - par->baseline = 0; - + u32 wd; + u32 cpp = (info->var.bits_per_pixel + 7) >> 3; + memset(®, 0, sizeof(reg)); - cpp = (info->var.bits_per_pixel + 7)/8; - - reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0); + + reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | + VIDCFG_CURS_X11 | + ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | + (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0); /* PLL settings */ freq = PICOS2KHZ(info->var.pixclock); - reg.dacmode = 0; - reg.vidcfg &= ~VIDCFG_2X; - - hdispend = info->var.xres; - hsyncsta = hdispend + info->var.right_margin; - hsyncend = hsyncsta + info->var.hsync_len; - htotal = hsyncend + info->var.left_margin; + reg.vidcfg &= ~VIDCFG_2X; - if (freq > par->max_pixclock/2) { + if (freq > par->max_pixclock / 2) { freq = freq > par->max_pixclock ? par->max_pixclock : freq; reg.dacmode |= DACMODE_2X; reg.vidcfg |= VIDCFG_2X; @@ -591,8 +583,9 @@ static int tdfxfb_set_par(struct fb_info *info) hsyncend >>= 1; htotal >>= 1; } - - hd = wd = (hdispend >> 3) - 1; + + wd = (hdispend >> 3) - 1; + hd = wd; hs = (hsyncsta >> 3) - 1; he = (hsyncend >> 3) - 1; ht = (htotal >> 3) - 1; @@ -600,28 +593,30 @@ static int tdfxfb_set_par(struct fb_info *info) hbe = ht; if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { - vbs = vd = (info->var.yres << 1) - 1; + vd = (info->var.yres << 1) - 1; vs = vd + (info->var.lower_margin << 1); ve = vs + (info->var.vsync_len << 1); - vbe = vt = ve + (info->var.upper_margin << 1) - 1; + vt = ve + (info->var.upper_margin << 1) - 1; + reg.screensize = info->var.xres | (info->var.yres << 13); + reg.vidcfg |= VIDCFG_HALF_MODE; + reg.crt[0x09] = 0x80; } else { - vbs = vd = info->var.yres - 1; + vd = info->var.yres - 1; vs = vd + info->var.lower_margin; ve = vs + info->var.vsync_len; - vbe = vt = ve + info->var.upper_margin - 1; + vt = ve + info->var.upper_margin - 1; + reg.screensize = info->var.xres | (info->var.yres << 12); + reg.vidcfg &= ~VIDCFG_HALF_MODE; } - + vbs = vd; + vbe = vt; + /* this is all pretty standard VGA register stuffing */ - reg.misc[0x00] = 0x0f | + reg.misc[0x00] = 0x0f | (info->var.xres < 400 ? 0xa0 : info->var.xres < 480 ? 0x60 : info->var.xres < 768 ? 0xe0 : 0x20); - - reg.gra[0x00] = 0x00; - reg.gra[0x01] = 0x00; - reg.gra[0x02] = 0x00; - reg.gra[0x03] = 0x00; - reg.gra[0x04] = 0x00; + reg.gra[0x05] = 0x40; reg.gra[0x06] = 0x05; reg.gra[0x07] = 0x0f; @@ -644,10 +639,7 @@ static int tdfxfb_set_par(struct fb_info *info) reg.att[0x0e] = 0x0e; reg.att[0x0f] = 0x0f; reg.att[0x10] = 0x41; - reg.att[0x11] = 0x00; reg.att[0x12] = 0x0f; - reg.att[0x13] = 0x00; - reg.att[0x14] = 0x00; reg.seq[0x00] = 0x03; reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */ @@ -660,146 +652,133 @@ static int tdfxfb_set_par(struct fb_info *info) reg.crt[0x02] = hbs; reg.crt[0x03] = 0x80 | (hbe & 0x1f); reg.crt[0x04] = hs; - reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); + reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); reg.crt[0x06] = vt; reg.crt[0x07] = ((vs & 0x200) >> 2) | ((vd & 0x200) >> 3) | ((vt & 0x200) >> 4) | 0x10 | ((vbs & 0x100) >> 5) | - ((vs & 0x100) >> 6) | - ((vd & 0x100) >> 7) | - ((vt & 0x100) >> 8); - reg.crt[0x08] = 0x00; - reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4); - reg.crt[0x0a] = 0x00; - reg.crt[0x0b] = 0x00; - reg.crt[0x0c] = 0x00; - reg.crt[0x0d] = 0x00; - reg.crt[0x0e] = 0x00; - reg.crt[0x0f] = 0x00; + ((vs & 0x100) >> 6) | + ((vd & 0x100) >> 7) | + ((vt & 0x100) >> 8); + reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4); reg.crt[0x10] = vs; - reg.crt[0x11] = (ve & 0x0f) | 0x20; + reg.crt[0x11] = (ve & 0x0f) | 0x20; reg.crt[0x12] = vd; reg.crt[0x13] = wd; - reg.crt[0x14] = 0x00; reg.crt[0x15] = vbs; - reg.crt[0x16] = vbe + 1; + reg.crt[0x16] = vbe + 1; reg.crt[0x17] = 0xc3; reg.crt[0x18] = 0xff; - + /* Banshee's nonvga stuff */ - reg.ext[0x00] = (((ht & 0x100) >> 8) | - ((hd & 0x100) >> 6) | + reg.ext[0x00] = (((ht & 0x100) >> 8) | + ((hd & 0x100) >> 6) | ((hbs & 0x100) >> 4) | - ((hbe & 0x40) >> 1) | - ((hs & 0x100) >> 2) | - ((he & 0x20) << 2)); - reg.ext[0x01] = (((vt & 0x400) >> 10) | - ((vd & 0x400) >> 8) | - ((vbs & 0x400) >> 6) | - ((vbe & 0x400) >> 4)); - - reg.vgainit0 = VGAINIT0_8BIT_DAC | + ((hbe & 0x40) >> 1) | + ((hs & 0x100) >> 2) | + ((he & 0x20) << 2)); + reg.ext[0x01] = (((vt & 0x400) >> 10) | + ((vd & 0x400) >> 8) | + ((vbs & 0x400) >> 6) | + ((vbe & 0x400) >> 4)); + + reg.vgainit0 = VGAINIT0_8BIT_DAC | VGAINIT0_EXT_ENABLE | VGAINIT0_WAKEUP_3C3 | VGAINIT0_ALT_READBACK | VGAINIT0_EXTSHIFTOUT; reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff; + if (hwcursor) + reg.curspataddr = info->fix.smem_len; + reg.cursloc = 0; - - reg.cursc0 = 0; + + reg.cursc0 = 0; reg.cursc1 = 0xffffff; - - reg.stride = info->var.xres * cpp; - reg.startaddr = par->baseline * reg.stride; - reg.srcbase = reg.startaddr; - reg.dstbase = reg.startaddr; - /* PLL settings */ - freq = PICOS2KHZ(info->var.pixclock); + reg.stride = info->var.xres * cpp; + reg.startaddr = info->var.yoffset * reg.stride + + info->var.xoffset * cpp; - reg.dacmode &= ~DACMODE_2X; - reg.vidcfg &= ~VIDCFG_2X; - if (freq > par->max_pixclock/2) { - freq = freq > par->max_pixclock ? par->max_pixclock : freq; - reg.dacmode |= DACMODE_2X; - reg.vidcfg |= VIDCFG_2X; - } reg.vidpll = do_calc_pll(freq, &fout); #if 0 reg.mempll = do_calc_pll(..., &fout); reg.gfxpll = do_calc_pll(..., &fout); #endif - if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { - reg.screensize = info->var.xres | (info->var.yres << 13); - reg.vidcfg |= VIDCFG_HALF_MODE; - reg.crt[0x09] |= 0x80; - } else { - reg.screensize = info->var.xres | (info->var.yres << 12); - reg.vidcfg &= ~VIDCFG_HALF_MODE; - } if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) reg.vidcfg |= VIDCFG_INTERLACE; reg.miscinit0 = tdfx_inl(par, MISCINIT0); #if defined(__BIG_ENDIAN) switch (info->var.bits_per_pixel) { - case 8: - case 24: - reg.miscinit0 &= ~(1 << 30); - reg.miscinit0 &= ~(1 << 31); - break; - case 16: - reg.miscinit0 |= (1 << 30); - reg.miscinit0 |= (1 << 31); - break; - case 32: - reg.miscinit0 |= (1 << 30); - reg.miscinit0 &= ~(1 << 31); - break; + case 8: + case 24: + reg.miscinit0 &= ~(1 << 30); + reg.miscinit0 &= ~(1 << 31); + break; + case 16: + reg.miscinit0 |= (1 << 30); + reg.miscinit0 |= (1 << 31); + break; + case 32: + reg.miscinit0 |= (1 << 30); + reg.miscinit0 &= ~(1 << 31); + break; } -#endif +#endif do_write_regs(info, ®); /* Now change fb_fix_screeninfo according to changes in par */ - info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3); - info->fix.visual = (info->var.bits_per_pixel == 8) + info->fix.line_length = reg.stride; + info->fix.visual = (info->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); - return 0; + DPRINTK("Graphics mode is now set at %dx%d depth %d\n", + info->var.xres, info->var.yres, info->var.bits_per_pixel); + return 0; } /* A handy macro shamelessly pinched from matroxfb */ -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) +#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) -static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue,unsigned transp,struct fb_info *info) +static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { struct tdfx_par *par = info->par; u32 rgbcol; - - if (regno >= info->cmap.len || regno > 255) return 1; - + + if (regno >= info->cmap.len || regno > 255) + return 1; + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + blue = (red * 77 + green * 151 + blue * 28) >> 8; + green = blue; + red = blue; + } + switch (info->fix.visual) { case FB_VISUAL_PSEUDOCOLOR: - rgbcol =(((u32)red & 0xff00) << 8) | - (((u32)green & 0xff00) << 0) | - (((u32)blue & 0xff00) >> 8); + rgbcol = (((u32)red & 0xff00) << 8) | + (((u32)green & 0xff00) << 0) | + (((u32)blue & 0xff00) >> 8); do_setpalentry(par, regno, rgbcol); break; /* Truecolor has no hardware color palettes. */ case FB_VISUAL_TRUECOLOR: if (regno < 16) { - rgbcol = (CNVT_TOHW( red, info->var.red.length) << + rgbcol = (CNVT_TOHW(red, info->var.red.length) << info->var.red.offset) | - (CNVT_TOHW( green, info->var.green.length) << + (CNVT_TOHW(green, info->var.green.length) << info->var.green.offset) | - (CNVT_TOHW( blue, info->var.blue.length) << + (CNVT_TOHW(blue, info->var.blue.length) << info->var.blue.offset) | - (CNVT_TOHW( transp, info->var.transp.length) << + (CNVT_TOHW(transp, info->var.transp.length) << info->var.transp.offset); par->palette[regno] = rgbcol; } @@ -815,287 +794,325 @@ static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ static int tdfxfb_blank(int blank, struct fb_info *info) -{ +{ struct tdfx_par *par = info->par; - u32 dacmode, state = 0, vgablank = 0; + int vgablank = 1; + u32 dacmode = tdfx_inl(par, DACMODE); - dacmode = tdfx_inl(par, DACMODE); + dacmode &= ~(BIT(1) | BIT(3)); switch (blank) { - case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */ - state = 0; - vgablank = 0; - break; - case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */ - state = 0; - vgablank = 1; - break; - case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */ - state = BIT(3); - vgablank = 1; - break; - case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */ - state = BIT(1); - vgablank = 1; - break; - case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */ - state = BIT(1) | BIT(3); - vgablank = 1; - break; + case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */ + vgablank = 0; + break; + case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */ + break; + case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */ + dacmode |= BIT(3); + break; + case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */ + dacmode |= BIT(1); + break; + case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */ + dacmode |= BIT(1) | BIT(3); + break; } - dacmode &= ~(BIT(1) | BIT(3)); - dacmode |= state; - banshee_make_room(par, 1); + banshee_make_room(par, 1); tdfx_outl(par, DACMODE, dacmode); - if (vgablank) + if (vgablank) vga_disable_video(par); else vga_enable_video(par); return 0; } -/* +/* * Set the starting position of the visible screen to var->yoffset - */ + */ static int tdfxfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { struct tdfx_par *par = info->par; - u32 addr; + u32 addr = var->yoffset * info->fix.line_length; if (nopan || var->xoffset || (var->yoffset > var->yres_virtual)) return -EINVAL; if ((var->yoffset + var->yres > var->yres_virtual && nowrap)) return -EINVAL; - addr = var->yoffset * info->fix.line_length; banshee_make_room(par, 1); tdfx_outl(par, VIDDESKSTART, addr); - + info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; + info->var.yoffset = var->yoffset; return 0; } #ifdef CONFIG_FB_3DFX_ACCEL /* - * FillRect 2D command (solidfill or invert (via ROP_XOR)) + * FillRect 2D command (solidfill or invert (via ROP_XOR)) */ -static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +static void tdfxfb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) { struct tdfx_par *par = info->par; u32 bpp = info->var.bits_per_pixel; u32 stride = info->fix.line_length; - u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); + u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); int tdfx_rop; - - if (rect->rop == ROP_COPY) + u32 dx = rect->dx; + u32 dy = rect->dy; + u32 dstbase = 0; + + if (rect->rop == ROP_COPY) tdfx_rop = TDFX_ROP_COPY; - else + else tdfx_rop = TDFX_ROP_XOR; - banshee_make_room(par, 5); - tdfx_outl(par, DSTFORMAT, fmt); + /* asume always rect->height < 4096 */ + if (dy + rect->height > 4095) { + dstbase = stride * dy; + dy = 0; + } + /* asume always rect->width < 4096 */ + if (dx + rect->width > 4095) { + dstbase += dx * bpp >> 3; + dx = 0; + } + banshee_make_room(par, 6); + tdfx_outl(par, DSTFORMAT, fmt); if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { - tdfx_outl(par, COLORFORE, rect->color); + tdfx_outl(par, COLORFORE, rect->color); } else { /* FB_VISUAL_TRUECOLOR */ tdfx_outl(par, COLORFORE, par->palette[rect->color]); } - tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); - tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); - tdfx_outl(par, LAUNCH_2D, rect->dx | (rect->dy << 16)); + tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); + tdfx_outl(par, DSTBASE, dstbase); + tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); + tdfx_outl(par, LAUNCH_2D, dx | (dy << 16)); } /* - * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) + * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) */ -static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +static void tdfxfb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) { struct tdfx_par *par = info->par; - u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy; + u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy; u32 bpp = info->var.bits_per_pixel; u32 stride = info->fix.line_length; u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); - u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); - + u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); + u32 dstbase = 0; + u32 srcbase = 0; + + /* asume always area->height < 4096 */ + if (sy + area->height > 4095) { + srcbase = stride * sy; + sy = 0; + } + /* asume always area->width < 4096 */ + if (sx + area->width > 4095) { + srcbase += sx * bpp >> 3; + sx = 0; + } + /* asume always area->height < 4096 */ + if (dy + area->height > 4095) { + dstbase = stride * dy; + dy = 0; + } + /* asume always area->width < 4096 */ + if (dx + area->width > 4095) { + dstbase += dx * bpp >> 3; + dx = 0; + } + if (area->sx <= area->dx) { - //-X + /* -X */ blitcmd |= BIT(14); sx += area->width - 1; dx += area->width - 1; } if (area->sy <= area->dy) { - //-Y + /* -Y */ blitcmd |= BIT(15); sy += area->height - 1; dy += area->height - 1; } - - banshee_make_room(par, 6); - tdfx_outl(par, SRCFORMAT, fmt); - tdfx_outl(par, DSTFORMAT, fmt); - tdfx_outl(par, COMMAND_2D, blitcmd); - tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); - tdfx_outl(par, DSTXY, dx | (dy << 16)); - tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); + banshee_make_room(par, 8); + + tdfx_outl(par, SRCFORMAT, fmt); + tdfx_outl(par, DSTFORMAT, fmt); + tdfx_outl(par, COMMAND_2D, blitcmd); + tdfx_outl(par, DSTSIZE, area->width | (area->height << 16)); + tdfx_outl(par, DSTXY, dx | (dy << 16)); + tdfx_outl(par, SRCBASE, srcbase); + tdfx_outl(par, DSTBASE, dstbase); + tdfx_outl(par, LAUNCH_2D, sx | (sy << 16)); } -static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) +static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) { struct tdfx_par *par = info->par; - int size = image->height * ((image->width * image->depth + 7)>>3); + int size = image->height * ((image->width * image->depth + 7) >> 3); int fifo_free; int i, stride = info->fix.line_length; u32 bpp = info->var.bits_per_pixel; - u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); + u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13); u8 *chardata = (u8 *) image->data; u32 srcfmt; + u32 dx = image->dx; + u32 dy = image->dy; + u32 dstbase = 0; if (image->depth != 1) { - //banshee_make_room(par, 6 + ((size + 3) >> 2)); - //srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000; +#ifdef BROKEN_CODE + banshee_make_room(par, 6 + ((size + 3) >> 2)); + srcfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13) | + 0x400000; +#else cfb_imageblit(info, image); +#endif return; - } else { - banshee_make_room(par, 8); - switch (info->fix.visual) { - case FB_VISUAL_PSEUDOCOLOR: + } + banshee_make_room(par, 9); + switch (info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: tdfx_outl(par, COLORFORE, image->fg_color); tdfx_outl(par, COLORBACK, image->bg_color); - break; - case FB_VISUAL_TRUECOLOR: - default: - tdfx_outl(par, COLORFORE, - par->palette[image->fg_color]); - tdfx_outl(par, COLORBACK, - par->palette[image->bg_color]); - } + break; + case FB_VISUAL_TRUECOLOR: + default: + tdfx_outl(par, COLORFORE, + par->palette[image->fg_color]); + tdfx_outl(par, COLORBACK, + par->palette[image->bg_color]); + } #ifdef __BIG_ENDIAN - srcfmt = 0x400000 | BIT(20); + srcfmt = 0x400000 | BIT(20); #else - srcfmt = 0x400000; + srcfmt = 0x400000; #endif - } + /* asume always image->height < 4096 */ + if (dy + image->height > 4095) { + dstbase = stride * dy; + dy = 0; + } + /* asume always image->width < 4096 */ + if (dx + image->width > 4095) { + dstbase += dx * bpp >> 3; + dx = 0; + } - tdfx_outl(par, SRCXY, 0); - tdfx_outl(par, DSTXY, image->dx | (image->dy << 16)); - tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); - tdfx_outl(par, SRCFORMAT, srcfmt); - tdfx_outl(par, DSTFORMAT, dstfmt); - tdfx_outl(par, DSTSIZE, image->width | (image->height << 16)); + tdfx_outl(par, DSTBASE, dstbase); + tdfx_outl(par, SRCXY, 0); + tdfx_outl(par, DSTXY, dx | (dy << 16)); + tdfx_outl(par, COMMAND_2D, + COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); + tdfx_outl(par, SRCFORMAT, srcfmt); + tdfx_outl(par, DSTFORMAT, dstfmt); + tdfx_outl(par, DSTSIZE, image->width | (image->height << 16)); /* A count of how many free FIFO entries we've requested. * When this goes negative, we need to request more. */ fifo_free = 0; - /* Send four bytes at a time of data */ - for (i = (size >> 2) ; i > 0; i--) { - if(--fifo_free < 0) { - fifo_free=31; - banshee_make_room(par,fifo_free); + /* Send four bytes at a time of data */ + for (i = (size >> 2); i > 0; i--) { + if (--fifo_free < 0) { + fifo_free = 31; + banshee_make_room(par, fifo_free); } - tdfx_outl(par, LAUNCH_2D,*(u32*)chardata); - chardata += 4; - } - - /* Send the leftovers now */ - banshee_make_room(par,3); - i = size%4; - switch (i) { - case 0: break; - case 1: tdfx_outl(par, LAUNCH_2D,*chardata); break; - case 2: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata); break; - case 3: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break; + tdfx_outl(par, LAUNCH_2D, *(u32 *)chardata); + chardata += 4; + } + + /* Send the leftovers now */ + banshee_make_room(par, 3); + switch (size % 4) { + case 0: + break; + case 1: + tdfx_outl(par, LAUNCH_2D, *chardata); + break; + case 2: + tdfx_outl(par, LAUNCH_2D, *(u16 *)chardata); + break; + case 3: + tdfx_outl(par, LAUNCH_2D, + *(u16 *)chardata | (chardata[3] << 24)); + break; } } #endif /* CONFIG_FB_3DFX_ACCEL */ -#ifdef TDFX_HARDWARE_CURSOR static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct tdfx_par *par = info->par; - unsigned long flags; + u32 vidcfg; - /* - * If the cursor is not be changed this means either we want the - * current cursor state (if enable is set) or we want to query what - * we can do with the cursor (if enable is not set) - */ - if (!cursor->set) return 0; + if (!hwcursor) + return -EINVAL; /* just to force soft_cursor() call */ - /* Too large of a cursor :-( */ - if (cursor->image.width > 64 || cursor->image.height > 64) - return -ENXIO; + /* Too large of a cursor or wrong bpp :-( */ + if (cursor->image.width > 64 || + cursor->image.height > 64 || + cursor->image.depth > 1) + return -EINVAL; - /* - * If we are going to be changing things we should disable - * the cursor first - */ - if (info->cursor.enable) { - spin_lock_irqsave(&par->DAClock, flags); - info->cursor.enable = 0; - del_timer(&(par->hwcursor.timer)); - tdfx_outl(par, VIDPROCCFG, par->hwcursor.disable); - spin_unlock_irqrestore(&par->DAClock, flags); - } + vidcfg = tdfx_inl(par, VIDPROCCFG); + if (cursor->enable) + tdfx_outl(par, VIDPROCCFG, vidcfg | VIDCFG_HWCURSOR_ENABLE); + else + tdfx_outl(par, VIDPROCCFG, vidcfg & ~VIDCFG_HWCURSOR_ENABLE); - /* Disable the Cursor */ - if ((cursor->set && FB_CUR_SETCUR) && !cursor->enable) + /* + * If the cursor is not be changed this means either we want the + * current cursor state (if enable is set) or we want to query what + * we can do with the cursor (if enable is not set) + */ + if (!cursor->set) return 0; /* fix cursor color - XFree86 forgets to restore it properly */ - if (cursor->set && FB_CUR_SETCMAP) { - struct fb_cmap cmap = cursor->image.cmap; + if (cursor->set & FB_CUR_SETCMAP) { + struct fb_cmap cmap = info->cmap; + u32 bg_idx = cursor->image.bg_color; + u32 fg_idx = cursor->image.fg_color; unsigned long bg_color, fg_color; - cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */ - fg_color = ((cmap.red[cmap.start] << 16) | - (cmap.green[cmap.start] << 8) | - (cmap.blue[cmap.start])); - bg_color = ((cmap.red[cmap.start+1] << 16) | - (cmap.green[cmap.start+1] << 8) | - (cmap.blue[cmap.start+1])); - fb_copy_cmap(&cmap, &info->cursor.image.cmap); - spin_lock_irqsave(&par->DAClock, flags); + fg_color = (((u32)cmap.red[fg_idx] & 0xff00) << 8) | + (((u32)cmap.green[fg_idx] & 0xff00) << 0) | + (((u32)cmap.blue[fg_idx] & 0xff00) >> 8); + bg_color = (((u32)cmap.red[bg_idx] & 0xff00) << 8) | + (((u32)cmap.green[bg_idx] & 0xff00) << 0) | + (((u32)cmap.blue[bg_idx] & 0xff00) >> 8); banshee_make_room(par, 2); tdfx_outl(par, HWCURC0, bg_color); tdfx_outl(par, HWCURC1, fg_color); - spin_unlock_irqrestore(&par->DAClock, flags); } - if (cursor->set && FB_CUR_SETPOS) { - int x, y; + if (cursor->set & FB_CUR_SETPOS) { + int x = cursor->image.dx; + int y = cursor->image.dy - info->var.yoffset; - x = cursor->image.dx; - y = cursor->image.dy; - y -= info->var.yoffset; - info->cursor.image.dx = x; - info->cursor.image.dy = y; x += 63; y += 63; - spin_lock_irqsave(&par->DAClock, flags); banshee_make_room(par, 1); tdfx_outl(par, HWCURLOC, (y << 16) + x); - spin_unlock_irqrestore(&par->DAClock, flags); } - - /* Not supported so we fake it */ - if (cursor->set && FB_CUR_SETHOT) { - info->cursor.hot.x = cursor->hot.x; - info->cursor.hot.y = cursor->hot.y; - } - - if (cursor->set && FB_CUR_SETSHAPE) { + if (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) { /* - * Voodoo 3 and above cards use 2 monochrome cursor patterns. + * Voodoo 3 and above cards use 2 monochrome cursor patterns. * The reason is so the card can fetch 8 words at a time * and are stored on chip for use for the next 8 scanlines. * This reduces the number of times for access to draw the * cursor for each screen refresh. * Each pattern is a bitmap of 64 bit wide and 64 bit high - * (total of 8192 bits or 1024 Kbytes). The two patterns are + * (total of 8192 bits or 1024 bytes). The two patterns are * stored in such a way that pattern 0 always resides in the * lower half (least significant 64 bits) of a 128 bit word * and pattern 1 the upper half. If you examine the data of @@ -1106,50 +1123,54 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) * (128 bits) which is the maximum cursor width times two for * the two monochrome patterns. */ - u8 *cursorbase = (u8 *) info->cursor.image.data; - char *bitmap = (char *)cursor->image.data; - char *mask = (char *) cursor->mask; - int i, j, k, h = 0; - - for (i = 0; i < 64; i++) { - if (i < cursor->image.height) { - j = (cursor->image.width + 7) >> 3; - k = 8 - j; - - for (;j > 0; j--) { - /* Pattern 0. Copy the cursor bitmap to it */ - fb_writeb(*bitmap, cursorbase + h); - bitmap++; - /* Pattern 1. Copy the cursor mask to it */ - fb_writeb(*mask, cursorbase + h + 8); - mask++; - h++; - } - for (;k > 0; k--) { - fb_writeb(0, cursorbase + h); - fb_writeb(~0, cursorbase + h + 8); - h++; - } - } else { - fb_writel(0, cursorbase + h); - fb_writel(0, cursorbase + h + 4); - fb_writel(~0, cursorbase + h + 8); - fb_writel(~0, cursorbase + h + 12); - h += 16; + u8 __iomem *cursorbase = info->screen_base + info->fix.smem_len; + u8 *bitmap = (u8 *)cursor->image.data; + u8 *mask = (u8 *)cursor->mask; + int i; + + fb_memset(cursorbase, 0, 1024); + + for (i = 0; i < cursor->image.height; i++) { + int h = 0; + int j = (cursor->image.width + 7) >> 3; + + for (; j > 0; j--) { + u8 data = *mask ^ *bitmap; + if (cursor->rop == ROP_COPY) + data = *mask & *bitmap; + /* Pattern 0. Copy the cursor mask to it */ + fb_writeb(*mask, cursorbase + h); + mask++; + /* Pattern 1. Copy the cursor bitmap to it */ + fb_writeb(data, cursorbase + h + 8); + bitmap++; + h++; } + cursorbase += 16; } } - /* Turn the cursor on */ - cursor->enable = 1; - info->cursor = *cursor; - mod_timer(&par->hwcursor.timer, jiffies+HZ/2); - spin_lock_irqsave(&par->DAClock, flags); - banshee_make_room(par, 1); - tdfx_outl(par, VIDPROCCFG, par->hwcursor.enable); - spin_unlock_irqrestore(&par->DAClock, flags); return 0; } + +static struct fb_ops tdfxfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = tdfxfb_check_var, + .fb_set_par = tdfxfb_set_par, + .fb_setcolreg = tdfxfb_setcolreg, + .fb_blank = tdfxfb_blank, + .fb_pan_display = tdfxfb_pan_display, + .fb_sync = banshee_wait_idle, + .fb_cursor = tdfxfb_cursor, +#ifdef CONFIG_FB_3DFX_ACCEL + .fb_fillrect = tdfxfb_fillrect, + .fb_copyarea = tdfxfb_copyarea, + .fb_imageblit = tdfxfb_imageblit, +#else + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, #endif +}; /** * tdfxfb_probe - Device Initializiation @@ -1161,14 +1182,15 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) * */ static int __devinit tdfxfb_probe(struct pci_dev *pdev, - const struct pci_device_id *id) + const struct pci_device_id *id) { struct tdfx_par *default_par; struct fb_info *info; int err, lpitch; - if ((err = pci_enable_device(pdev))) { - printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "tdfxfb: Can't enable pdev: %d\n", err); return err; } @@ -1176,139 +1198,145 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, if (!info) return -ENOMEM; - + default_par = info->par; - + /* Configure the default fb_fix_screeninfo first */ switch (pdev->device) { - case PCI_DEVICE_ID_3DFX_BANSHEE: - strcat(tdfx_fix.id, " Banshee"); - default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK; - break; - case PCI_DEVICE_ID_3DFX_VOODOO3: - strcat(tdfx_fix.id, " Voodoo3"); - default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK; - break; - case PCI_DEVICE_ID_3DFX_VOODOO5: - strcat(tdfx_fix.id, " Voodoo5"); - default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK; - break; + case PCI_DEVICE_ID_3DFX_BANSHEE: + strcat(tdfx_fix.id, " Banshee"); + default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK; + break; + case PCI_DEVICE_ID_3DFX_VOODOO3: + strcat(tdfx_fix.id, " Voodoo3"); + default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK; + break; + case PCI_DEVICE_ID_3DFX_VOODOO5: + strcat(tdfx_fix.id, " Voodoo5"); + default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK; + break; } tdfx_fix.mmio_start = pci_resource_start(pdev, 0); tdfx_fix.mmio_len = pci_resource_len(pdev, 0); - default_par->regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); - if (!default_par->regbase_virt) { - printk("fb: Can't remap %s register area.\n", tdfx_fix.id); + if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len, + "tdfx regbase")) { + printk(KERN_ERR "tdfxfb: Can't reserve regbase\n"); goto out_err; } - - if (!request_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), "tdfx regbase")) { - printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n"); - goto out_err; - } + + default_par->regbase_virt = + ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); + if (!default_par->regbase_virt) { + printk(KERN_ERR "fb: Can't remap %s register area.\n", + tdfx_fix.id); + goto out_err_regbase; + } tdfx_fix.smem_start = pci_resource_start(pdev, 1); - if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) { - printk("fb: Can't count %s memory.\n", tdfx_fix.id); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - goto out_err; + tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device); + if (!tdfx_fix.smem_len) { + printk(KERN_ERR "fb: Can't count %s memory.\n", tdfx_fix.id); + goto out_err_regbase; } - if (!request_mem_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1), "tdfx smem")) { - printk(KERN_WARNING "tdfxfb: Can't reserve smem\n"); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - goto out_err; + if (!request_mem_region(tdfx_fix.smem_start, + pci_resource_len(pdev, 1), "tdfx smem")) { + printk(KERN_ERR "tdfxfb: Can't reserve smem\n"); + goto out_err_regbase; } - info->screen_base = ioremap_nocache(tdfx_fix.smem_start, + info->screen_base = ioremap_nocache(tdfx_fix.smem_start, tdfx_fix.smem_len); if (!info->screen_base) { - printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id); - release_mem_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - goto out_err; + printk(KERN_ERR "fb: Can't remap %s framebuffer.\n", + tdfx_fix.id); + goto out_err_screenbase; } default_par->iobase = pci_resource_start(pdev, 2); - + if (!request_region(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2), "tdfx iobase")) { - printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n"); - release_mem_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - goto out_err; + pci_resource_len(pdev, 2), "tdfx iobase")) { + printk(KERN_ERR "tdfxfb: Can't reserve iobase\n"); + goto out_err_screenbase; } - printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10); + printk(KERN_INFO "fb: %s memory = %dK\n", tdfx_fix.id, + tdfx_fix.smem_len >> 10); + + default_par->mtrr_handle = -1; + if (!nomtrr) + default_par->mtrr_handle = + mtrr_add(tdfx_fix.smem_start, tdfx_fix.smem_len, + MTRR_TYPE_WRCOMB, 1); tdfx_fix.ypanstep = nopan ? 0 : 1; tdfx_fix.ywrapstep = nowrap ? 0 : 1; - + info->fbops = &tdfxfb_ops; - info->fix = tdfx_fix; + info->fix = tdfx_fix; info->pseudo_palette = default_par->palette; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; #ifdef CONFIG_FB_3DFX_ACCEL - info->flags |= FBINFO_HWACCEL_FILLRECT | - FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT; + info->flags |= FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_READS_FAST; #endif + /* reserve 8192 bits for cursor */ + /* the 2.4 driver says PAGE_MASK boundary is not enough for Voodoo4 */ + if (hwcursor) + info->fix.smem_len = (info->fix.smem_len - 1024) & + (PAGE_MASK << 1); if (!mode_option) mode_option = "640x480@60"; - - err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); + + err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err || err == 4) info->var = tdfx_var; /* maximize virtual vertical length */ lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); - info->var.yres_virtual = info->fix.smem_len/lpitch; + info->var.yres_virtual = info->fix.smem_len / lpitch; if (info->var.yres_virtual < info->var.yres) - goto out_err; - -#ifdef CONFIG_FB_3DFX_ACCEL - /* - * FIXME: Limit var->yres_virtual to 4096 because of screen artifacts - * during scrolling. This is only present if 2D acceleration is - * enabled. - */ - if (info->var.yres_virtual > 4096) - info->var.yres_virtual = 4096; -#endif /* CONFIG_FB_3DFX_ACCEL */ + goto out_err_iobase; if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { - printk(KERN_WARNING "tdfxfb: Can't allocate color map\n"); - goto out_err; + printk(KERN_ERR "tdfxfb: Can't allocate color map\n"); + goto out_err_iobase; } if (register_framebuffer(info) < 0) { - printk("tdfxfb: can't register framebuffer\n"); + printk(KERN_ERR "tdfxfb: can't register framebuffer\n"); fb_dealloc_cmap(&info->cmap); - goto out_err; + goto out_err_iobase; } /* * Our driver data */ pci_set_drvdata(pdev, info); - return 0; + return 0; -out_err: +out_err_iobase: + if (default_par->mtrr_handle >= 0) + mtrr_del(default_par->mtrr_handle, info->fix.smem_start, + info->fix.smem_len); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); +out_err_screenbase: + if (info->screen_base) + iounmap(info->screen_base); + release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1)); +out_err_regbase: /* * Cleanup after anything that was remapped/allocated. */ if (default_par->regbase_virt) iounmap(default_par->regbase_virt); - if (info->screen_base) - iounmap(info->screen_base); + release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len); +out_err: framebuffer_release(info); return -ENXIO; } @@ -1316,7 +1344,7 @@ out_err: #ifndef MODULE static void tdfxfb_setup(char *options) { - char* this_opt; + char *this_opt; if (!options || !*options) return; @@ -1324,10 +1352,16 @@ static void tdfxfb_setup(char *options) while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; - if(!strcmp(this_opt, "nopan")) { + if (!strcmp(this_opt, "nopan")) { nopan = 1; - } else if(!strcmp(this_opt, "nowrap")) { + } else if (!strcmp(this_opt, "nowrap")) { nowrap = 1; + } else if (!strncmp(this_opt, "hwcursor=", 9)) { + hwcursor = simple_strtoul(this_opt + 9, NULL, 0); +#ifdef CONFIG_MTRR + } else if (!strncmp(this_opt, "nomtrr", 6)) { + nomtrr = 1; +#endif } else { mode_option = this_opt; } @@ -1350,6 +1384,9 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev) struct tdfx_par *par = info->par; unregister_framebuffer(info); + if (par->mtrr_handle >= 0) + mtrr_del(par->mtrr_handle, info->fix.smem_start, + info->fix.smem_len); iounmap(par->regbase_virt); iounmap(info->screen_base); @@ -1374,17 +1411,25 @@ static int __init tdfxfb_init(void) tdfxfb_setup(option); #endif - return pci_register_driver(&tdfxfb_driver); + return pci_register_driver(&tdfxfb_driver); } static void __exit tdfxfb_exit(void) { - pci_unregister_driver(&tdfxfb_driver); + pci_unregister_driver(&tdfxfb_driver); } MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>"); MODULE_DESCRIPTION("3Dfx framebuffer device driver"); MODULE_LICENSE("GPL"); - + +module_param(hwcursor, int, 0644); +MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " + "(1=enable, 0=disable, default=1)"); +#ifdef CONFIG_MTRR +module_param(nomtrr, bool, 0); +MODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)"); +#endif + module_init(tdfxfb_init); module_exit(tdfxfb_exit); diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index d292a37ec7d..680642c089c 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -5,7 +5,7 @@ * Copyright (C) 1997 Geert Uytterhoeven * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha * Copyright (C) 2002 Richard Henderson - * Copyright (C) 2006 Maciej W. Rozycki + * Copyright (C) 2006, 2007 Maciej W. Rozycki * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -13,6 +13,7 @@ */ #include <linux/bitrev.h> +#include <linux/compiler.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/errno.h> @@ -636,15 +637,6 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) is8bpp = info->var.bits_per_pixel == 8; - /* For copies that aren't pixel expansion, there's little we - can do better than the generic code. */ - /* ??? There is a DMA write mode; I wonder if that could be - made to pull the data from the image buffer... */ - if (image->depth > 1) { - cfb_imageblit(info, image); - return; - } - dx = image->dx; dy = image->dy; width = image->width; @@ -654,6 +646,9 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) line_length = info->fix.line_length; rincr = (width + 7) / 8; + /* A shift below cannot cope with. */ + if (unlikely(width == 0)) + return; /* Crop the image to the screen. */ if (dx > vxres || dy > vyres) return; @@ -709,9 +704,10 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) unsigned long bwidth; /* Handle common case of imaging a single character, in - a font less than 32 pixels wide. */ + a font less than or 32 pixels wide. */ - pixelmask = (1 << width) - 1; + /* Avoid a shift by 32; width > 0 implied. */ + pixelmask = (2ul << (width - 1)) - 1; pixelmask <<= shift; __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG); wmb(); diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index c699864b6f4..70fb4ee2b42 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -1,18 +1,19 @@ /* * Frame buffer driver for Trident Blade and Image series * - * Copyright 2001,2002 - Jani Monoses <jani@iv.ro> + * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro> * * * CREDITS:(in order of appearance) - * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video - * Special thanks ;) to Mattia Crivellini <tia@mclink.it> - * much inspired by the XFree86 4.x Trident driver sources by Alan Hourihane - * the FreeVGA project - * Francesco Salvestrini <salvestrini@users.sf.net> XP support,code,suggestions + * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video + * Special thanks ;) to Mattia Crivellini <tia@mclink.it> + * much inspired by the XFree86 4.x Trident driver sources + * by Alan Hourihane the FreeVGA project + * Francesco Salvestrini <salvestrini@users.sf.net> XP support, + * code, suggestions * TODO: - * timing value tweaking so it looks good on every monitor in every mode - * TGUI acceleration + * timing value tweaking so it looks good on every monitor in every mode + * TGUI acceleration */ #include <linux/module.h> @@ -26,11 +27,11 @@ #define VERSION "0.7.8-NEWAPI" struct tridentfb_par { - int vclk; //in MHz - void __iomem * io_virt; //iospace virtual memory address + int vclk; /* in MHz */ + void __iomem *io_virt; /* iospace virtual memory address */ }; -static unsigned char eng_oper; //engine operation... +static unsigned char eng_oper; /* engine operation... */ static struct fb_ops tridentfb_ops; static struct tridentfb_par default_par; @@ -39,11 +40,10 @@ static struct tridentfb_par default_par; static struct fb_info fb_info; static u32 pseudo_pal[16]; - static struct fb_var_screeninfo default_var; static struct fb_fix_screeninfo tridentfb_fix = { - .id = "Trident", + .id = "Trident", .type = FB_TYPE_PACKED_PIXELS, .ypanstep = 1, .visual = FB_VISUAL_PSEUDOCOLOR, @@ -55,11 +55,10 @@ static int chip_id; static int defaultaccel; static int displaytype; - /* defaults which are normally overriden by user values */ /* video mode */ -static char * mode = "640x480"; +static char *mode = "640x480"; static int bpp = 8; static int noaccel; @@ -74,7 +73,6 @@ static int memsize; static int memdiff; static int nativex; - module_param(mode, charp, 0); module_param(bpp, int, 0); module_param(center, int, 0); @@ -86,88 +84,85 @@ module_param(nativex, int, 0); module_param(fp, int, 0); module_param(crt, int, 0); - static int chip3D; static int chipcyber; static int is3Dchip(int id) { - return ((id == BLADE3D) || (id == CYBERBLADEE4) || - (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) || - (id == CYBER9397) || (id == CYBER9397DVD) || - (id == CYBER9520) || (id == CYBER9525DVD) || - (id == IMAGE975) || (id == IMAGE985) || - (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) || - (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) || - (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) || - (id == CYBERBLADEXPAi1)); + return ((id == BLADE3D) || (id == CYBERBLADEE4) || + (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) || + (id == CYBER9397) || (id == CYBER9397DVD) || + (id == CYBER9520) || (id == CYBER9525DVD) || + (id == IMAGE975) || (id == IMAGE985) || + (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) || + (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) || + (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) || + (id == CYBERBLADEXPAi1)); } static int iscyber(int id) { switch (id) { - case CYBER9388: - case CYBER9382: - case CYBER9385: - case CYBER9397: - case CYBER9397DVD: - case CYBER9520: - case CYBER9525DVD: - case CYBERBLADEE4: - case CYBERBLADEi7D: - case CYBERBLADEi1: - case CYBERBLADEi1D: - case CYBERBLADEAi1: - case CYBERBLADEAi1D: - case CYBERBLADEXPAi1: - return 1; - - case CYBER9320: - case TGUI9660: - case IMAGE975: - case IMAGE985: - case BLADE3D: - case CYBERBLADEi7: /* VIA MPV4 integrated version */ + case CYBER9388: + case CYBER9382: + case CYBER9385: + case CYBER9397: + case CYBER9397DVD: + case CYBER9520: + case CYBER9525DVD: + case CYBERBLADEE4: + case CYBERBLADEi7D: + case CYBERBLADEi1: + case CYBERBLADEi1D: + case CYBERBLADEAi1: + case CYBERBLADEAi1D: + case CYBERBLADEXPAi1: + return 1; - default: - /* case CYBERBLDAEXPm8: Strange */ - /* case CYBERBLDAEXPm16: Strange */ - return 0; + case CYBER9320: + case TGUI9660: + case IMAGE975: + case IMAGE985: + case BLADE3D: + case CYBERBLADEi7: /* VIA MPV4 integrated version */ + + default: + /* case CYBERBLDAEXPm8: Strange */ + /* case CYBERBLDAEXPm16: Strange */ + return 0; } } -#define CRT 0x3D0 //CRTC registers offset for color display +#define CRT 0x3D0 /* CRTC registers offset for color display */ #ifndef TRIDENT_MMIO #define TRIDENT_MMIO 1 #endif #if TRIDENT_MMIO - #define t_outb(val,reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg) + #define t_outb(val, reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg) #define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg) #else - #define t_outb(val,reg) outb(val,reg) + #define t_outb(val, reg) outb(val, reg) #define t_inb(reg) inb(reg) #endif static struct accel_switch { - void (*init_accel)(int,int); - void (*wait_engine)(void); - void (*fill_rect)(__u32,__u32,__u32,__u32,__u32,__u32); - void (*copy_rect)(__u32,__u32,__u32,__u32,__u32,__u32); + void (*init_accel) (int, int); + void (*wait_engine) (void); + void (*fill_rect) (u32, u32, u32, u32, u32, u32); + void (*copy_rect) (u32, u32, u32, u32, u32, u32); } *acc; -#define writemmr(r,v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r) +#define writemmr(r, v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r) #define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r) - - /* * Blade specific acceleration. */ -#define point(x,y) ((y)<<16|(x)) +#define point(x, y) ((y) << 16 | (x)) #define STA 0x2120 #define CMD 0x2144 #define ROP 0x2148 @@ -179,64 +174,71 @@ static struct accel_switch { #define ROP_S 0xCC -static void blade_init_accel(int pitch,int bpp) +static void blade_init_accel(int pitch, int bpp) { - int v1 = (pitch>>3)<<20; - int tmp = 0,v2; + int v1 = (pitch >> 3) << 20; + int tmp = 0, v2; switch (bpp) { - case 8:tmp = 0;break; - case 15:tmp = 5;break; - case 16:tmp = 1;break; - case 24: - case 32:tmp = 2;break; + case 8: + tmp = 0; + break; + case 15: + tmp = 5; + break; + case 16: + tmp = 1; + break; + case 24: + case 32: + tmp = 2; + break; } - v2 = v1 | (tmp<<29); - writemmr(0x21C0,v2); - writemmr(0x21C4,v2); - writemmr(0x21B8,v2); - writemmr(0x21BC,v2); - writemmr(0x21D0,v1); - writemmr(0x21D4,v1); - writemmr(0x21C8,v1); - writemmr(0x21CC,v1); - writemmr(0x216C,0); + v2 = v1 | (tmp << 29); + writemmr(0x21C0, v2); + writemmr(0x21C4, v2); + writemmr(0x21B8, v2); + writemmr(0x21BC, v2); + writemmr(0x21D0, v1); + writemmr(0x21D4, v1); + writemmr(0x21C8, v1); + writemmr(0x21CC, v1); + writemmr(0x216C, 0); } static void blade_wait_engine(void) { - while(readmmr(STA) & 0xFA800000); + while (readmmr(STA) & 0xFA800000) ; } -static void blade_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop) +static void blade_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) { - writemmr(CLR,c); - writemmr(ROP,rop ? 0x66:ROP_S); - writemmr(CMD,0x20000000|1<<19|1<<4|2<<2); + writemmr(CLR, c); + writemmr(ROP, rop ? 0x66 : ROP_S); + writemmr(CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); - writemmr(DR1,point(x,y)); - writemmr(DR2,point(x+w-1,y+h-1)); + writemmr(DR1, point(x, y)); + writemmr(DR2, point(x + w - 1, y + h - 1)); } -static void blade_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) +static void blade_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) { - __u32 s1,s2,d1,d2; + u32 s1, s2, d1, d2; int direction = 2; - s1 = point(x1,y1); - s2 = point(x1+w-1,y1+h-1); - d1 = point(x2,y2); - d2 = point(x2+w-1,y2+h-1); + s1 = point(x1, y1); + s2 = point(x1 + w - 1, y1 + h - 1); + d1 = point(x2, y2); + d2 = point(x2 + w - 1, y2 + h - 1); if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) - direction = 0; - + direction = 0; - writemmr(ROP,ROP_S); - writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction); + writemmr(ROP, ROP_S); + writemmr(CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction); - writemmr(SR1,direction?s2:s1); - writemmr(SR2,direction?s1:s2); - writemmr(DR1,direction?d2:d1); - writemmr(DR2,direction?d1:d2); + writemmr(SR1, direction ? s2 : s1); + writemmr(SR2, direction ? s1 : s2); + writemmr(DR1, direction ? d2 : d1); + writemmr(DR2, direction ? d1 : d2); } static struct accel_switch accel_blade = { @@ -246,51 +248,72 @@ static struct accel_switch accel_blade = { blade_copy_rect, }; - /* * BladeXP specific acceleration functions */ #define ROP_P 0xF0 -#define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff)) +#define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff)) -static void xp_init_accel(int pitch,int bpp) +static void xp_init_accel(int pitch, int bpp) { - int tmp = 0,v1; + int tmp = 0, v1; unsigned char x = 0; switch (bpp) { - case 8: x = 0; break; - case 16: x = 1; break; - case 24: x = 3; break; - case 32: x = 2; break; + case 8: + x = 0; + break; + case 16: + x = 1; + break; + case 24: + x = 3; + break; + case 32: + x = 2; + break; } switch (pitch << (bpp >> 3)) { - case 8192: - case 512: x |= 0x00; break; - case 1024: x |= 0x04; break; - case 2048: x |= 0x08; break; - case 4096: x |= 0x0C; break; + case 8192: + case 512: + x |= 0x00; + break; + case 1024: + x |= 0x04; + break; + case 2048: + x |= 0x08; + break; + case 4096: + x |= 0x0C; + break; } - t_outb(x,0x2125); + t_outb(x, 0x2125); eng_oper = x | 0x40; switch (bpp) { - case 8: tmp = 18; break; - case 15: - case 16: tmp = 19; break; - case 24: - case 32: tmp = 20; break; + case 8: + tmp = 18; + break; + case 15: + case 16: + tmp = 19; + break; + case 24: + case 32: + tmp = 20; + break; } v1 = pitch << tmp; - writemmr(0x2154,v1); - writemmr(0x2150,v1); - t_outb(3,0x2126); + writemmr(0x2154, v1); + writemmr(0x2150, v1); + t_outb(3, 0x2126); } static void xp_wait_engine(void) @@ -318,24 +341,24 @@ static void xp_wait_engine(void) } } -static void xp_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop) +static void xp_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) { - writemmr(0x2127,ROP_P); - writemmr(0x2158,c); - writemmr(0x2128,0x4000); - writemmr(0x2140,masked_point(h,w)); - writemmr(0x2138,masked_point(y,x)); - t_outb(0x01,0x2124); - t_outb(eng_oper,0x2125); + writemmr(0x2127, ROP_P); + writemmr(0x2158, c); + writemmr(0x2128, 0x4000); + writemmr(0x2140, masked_point(h, w)); + writemmr(0x2138, masked_point(y, x)); + t_outb(0x01, 0x2124); + t_outb(eng_oper, 0x2125); } -static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) +static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) { int direction; - __u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; + u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; direction = 0x0004; - + if ((x1 < x2) && (y1 == y2)) { direction |= 0x0200; x1_tmp = x1 + w - 1; @@ -344,53 +367,60 @@ static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) x1_tmp = x1; x2_tmp = x2; } - + if (y1 < y2) { direction |= 0x0100; y1_tmp = y1 + h - 1; y2_tmp = y2 + h - 1; - } else { + } else { y1_tmp = y1; y2_tmp = y2; } - writemmr(0x2128,direction); - t_outb(ROP_S,0x2127); - writemmr(0x213C,masked_point(y1_tmp,x1_tmp)); - writemmr(0x2138,masked_point(y2_tmp,x2_tmp)); - writemmr(0x2140,masked_point(h,w)); - t_outb(0x01,0x2124); + writemmr(0x2128, direction); + t_outb(ROP_S, 0x2127); + writemmr(0x213C, masked_point(y1_tmp, x1_tmp)); + writemmr(0x2138, masked_point(y2_tmp, x2_tmp)); + writemmr(0x2140, masked_point(h, w)); + t_outb(0x01, 0x2124); } static struct accel_switch accel_xp = { - xp_init_accel, + xp_init_accel, xp_wait_engine, xp_fill_rect, xp_copy_rect, }; - /* * Image specific acceleration functions */ -static void image_init_accel(int pitch,int bpp) +static void image_init_accel(int pitch, int bpp) { int tmp = 0; - switch (bpp) { - case 8:tmp = 0;break; - case 15:tmp = 5;break; - case 16:tmp = 1;break; - case 24: - case 32:tmp = 2;break; + switch (bpp) { + case 8: + tmp = 0; + break; + case 15: + tmp = 5; + break; + case 16: + tmp = 1; + break; + case 24: + case 32: + tmp = 2; + break; } writemmr(0x2120, 0xF0000000); - writemmr(0x2120, 0x40000000|tmp); + writemmr(0x2120, 0x40000000 | tmp); writemmr(0x2120, 0x80000000); writemmr(0x2144, 0x00000000); writemmr(0x2148, 0x00000000); writemmr(0x2150, 0x00000000); writemmr(0x2154, 0x00000000); - writemmr(0x2120, 0x60000000|(pitch<<16) |pitch); + writemmr(0x2120, 0x60000000 | (pitch << 16) | pitch); writemmr(0x216C, 0x00000000); writemmr(0x2170, 0x00000000); writemmr(0x217C, 0x00000000); @@ -400,44 +430,43 @@ static void image_init_accel(int pitch,int bpp) static void image_wait_engine(void) { - while(readmmr(0x2164) & 0xF0000000); + while (readmmr(0x2164) & 0xF0000000) ; } -static void image_fill_rect(__u32 x, __u32 y, __u32 w, __u32 h, __u32 c, __u32 rop) +static void image_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) { - writemmr(0x2120,0x80000000); - writemmr(0x2120,0x90000000|ROP_S); + writemmr(0x2120, 0x80000000); + writemmr(0x2120, 0x90000000 | ROP_S); - writemmr(0x2144,c); + writemmr(0x2144, c); - writemmr(DR1,point(x,y)); - writemmr(DR2,point(x+w-1,y+h-1)); + writemmr(DR1, point(x, y)); + writemmr(DR2, point(x + w - 1, y + h - 1)); - writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9); + writemmr(0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9); } -static void image_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h) +static void image_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) { - __u32 s1,s2,d1,d2; + u32 s1, s2, d1, d2; int direction = 2; - s1 = point(x1,y1); - s2 = point(x1+w-1,y1+h-1); - d1 = point(x2,y2); - d2 = point(x2+w-1,y2+h-1); - - if ((y1 > y2) || ((y1 == y2) && (x1 >x2))) - direction = 0; - - writemmr(0x2120,0x80000000); - writemmr(0x2120,0x90000000|ROP_S); - - writemmr(SR1,direction?s2:s1); - writemmr(SR2,direction?s1:s2); - writemmr(DR1,direction?d2:d1); - writemmr(DR2,direction?d1:d2); - writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction); -} + s1 = point(x1, y1); + s2 = point(x1 + w - 1, y1 + h - 1); + d1 = point(x2, y2); + d2 = point(x2 + w - 1, y2 + h - 1); + if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) + direction = 0; + + writemmr(0x2120, 0x80000000); + writemmr(0x2120, 0x90000000 | ROP_S); + + writemmr(SR1, direction ? s2 : s1); + writemmr(SR2, direction ? s1 : s2); + writemmr(DR1, direction ? d2 : d1); + writemmr(DR2, direction ? d1 : d2); + writemmr(0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction); +} static struct accel_switch accel_image = { image_init_accel, @@ -450,30 +479,34 @@ static struct accel_switch accel_image = { * Accel functions called by the upper layers */ #ifdef CONFIG_FB_TRIDENT_ACCEL -static void tridentfb_fillrect(struct fb_info * info, const struct fb_fillrect *fr) +static void tridentfb_fillrect(struct fb_info *info, + const struct fb_fillrect *fr) { int bpp = info->var.bits_per_pixel; int col = 0; - + switch (bpp) { - default: - case 8: col |= fr->color; - col |= col << 8; - col |= col << 16; - break; - case 16: col = ((u32 *)(info->pseudo_palette))[fr->color]; - - break; - case 32: col = ((u32 *)(info->pseudo_palette))[fr->color]; - break; - } - + default: + case 8: + col |= fr->color; + col |= col << 8; + col |= col << 16; + break; + case 16: + col = ((u32 *)(info->pseudo_palette))[fr->color]; + break; + case 32: + col = ((u32 *)(info->pseudo_palette))[fr->color]; + break; + } + acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop); acc->wait_engine(); } -static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca) +static void tridentfb_copyarea(struct fb_info *info, + const struct fb_copyarea *ca) { - acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height); + acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height); acc->wait_engine(); } #else /* !CONFIG_FB_TRIDENT_ACCEL */ @@ -488,14 +521,14 @@ static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *c static inline unsigned char read3X4(int reg) { - struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par; + struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; writeb(reg, par->io_virt + CRT + 4); - return readb( par->io_virt + CRT + 5); + return readb(par->io_virt + CRT + 5); } static inline void write3X4(int reg, unsigned char val) { - struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par; + struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; writeb(reg, par->io_virt + CRT + 4); writeb(val, par->io_virt + CRT + 5); } @@ -520,7 +553,7 @@ static inline unsigned char read3CE(int reg) static inline void writeAttr(int reg, unsigned char val) { - readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index + readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */ t_outb(reg, 0x3C0); t_outb(val, 0x3C0); } @@ -540,32 +573,41 @@ static inline void enable_mmio(void) /* Unprotect registers */ outb(NewMode1, 0x3C4); outb(0x80, 0x3C5); - + /* Enable MMIO */ - outb(PCIReg, 0x3D4); + outb(PCIReg, 0x3D4); outb(inb(0x3D5) | 0x01, 0x3D5); } - #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) /* Return flat panel's maximum x resolution */ static int __devinit get_nativex(void) { - int x,y,tmp; + int x, y, tmp; if (nativex) return nativex; - tmp = (read3CE(VertStretch) >> 4) & 3; + tmp = (read3CE(VertStretch) >> 4) & 3; switch (tmp) { - case 0: x = 1280; y = 1024; break; - case 2: x = 1024; y = 768; break; - case 3: x = 800; y = 600; break; - case 4: x = 1400; y = 1050; break; - case 1: - default:x = 640; y = 480; break; + case 0: + x = 1280; y = 1024; + break; + case 2: + x = 1024; y = 768; + break; + case 3: + x = 800; y = 600; + break; + case 4: + x = 1400; y = 1050; + break; + case 1: + default: + x = 640; y = 480; + break; } output("%dx%d flat panel found\n", x, y); @@ -576,25 +618,26 @@ static int __devinit get_nativex(void) static void set_lwidth(int width) { write3X4(Offset, width & 0xFF); - write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4)); + write3X4(AddColReg, + (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4)); } /* For resolutions smaller than FP resolution stretch */ static void screen_stretch(void) { - if (chip_id != CYBERBLADEXPAi1) - write3CE(BiosReg,0); - else - write3CE(BiosReg,8); - write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1); - write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1); + if (chip_id != CYBERBLADEXPAi1) + write3CE(BiosReg, 0); + else + write3CE(BiosReg, 8); + write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1); + write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1); } /* For resolutions smaller than FP resolution center */ static void screen_center(void) { - write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80); - write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80); + write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80); + write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80); } /* Address of first shown pixel in display memory */ @@ -602,40 +645,42 @@ static void set_screen_start(int base) { write3X4(StartAddrLow, base & 0xFF); write3X4(StartAddrHigh, (base & 0xFF00) >> 8); - write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11)); - write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17)); + write3X4(CRTCModuleTest, + (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11)); + write3X4(CRTHiOrd, + (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17)); } /* Use 20.12 fixed-point for NTSC value and frequency calculation */ -#define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 ) +#define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 ) /* Set dotclock frequency */ static void set_vclk(int freq) { - int m,n,k; - int f,fi,d,di; - unsigned char lo=0,hi=0; + int m, n, k; + int f, fi, d, di; + unsigned char lo = 0, hi = 0; d = 20; - for(k = 2;k>=0;k--) - for(m = 0;m<63;m++) - for(n = 0;n<128;n++) { - fi = calc_freq(n,m,k); - if ((di = abs(fi - freq)) < d) { - d = di; - f = fi; - lo = n; - hi = (k<<6) | m; - } - } + for (k = 2; k >= 0; k--) + for (m = 0; m < 63; m++) + for (n = 0; n < 128; n++) { + fi = calc_freq(n, m, k); + if ((di = abs(fi - freq)) < d) { + d = di; + f = fi; + lo = n; + hi = (k << 6) | m; + } + } if (chip3D) { - write3C4(ClockHigh,hi); - write3C4(ClockLow,lo); + write3C4(ClockHigh, hi); + write3C4(ClockLow, lo); } else { - outb(lo,0x43C8); - outb(hi,0x43C9); + outb(lo, 0x43C8); + outb(hi, 0x43C9); } - debug("VCLK = %X %X\n",hi,lo); + debug("VCLK = %X %X\n", hi, lo); } /* Set number of lines for flat panels*/ @@ -663,7 +708,7 @@ static unsigned int __devinit get_displaytype(void) return DISPLAY_FP; if (crt || !chipcyber) return DISPLAY_CRT; - return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT; + return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT; } /* Try detecting the video memory size */ @@ -676,100 +721,136 @@ static unsigned int __devinit get_memsize(void) if (memsize) k = memsize * Kb; else - switch (chip_id) { - case CYBER9525DVD: k = 2560 * Kb; break; + switch (chip_id) { + case CYBER9525DVD: + k = 2560 * Kb; + break; default: tmp = read3X4(SPR) & 0x0F; switch (tmp) { - case 0x01: k = 512; break; - case 0x02: k = 6 * Mb; break; /* XP */ - case 0x03: k = 1 * Mb; break; - case 0x04: k = 8 * Mb; break; - case 0x06: k = 10 * Mb; break; /* XP */ - case 0x07: k = 2 * Mb; break; - case 0x08: k = 12 * Mb; break; /* XP */ - case 0x0A: k = 14 * Mb; break; /* XP */ - case 0x0C: k = 16 * Mb; break; /* XP */ - case 0x0E: /* XP */ - - tmp2 = read3C4(0xC1); - switch (tmp2) { - case 0x00: k = 20 * Mb; break; - case 0x01: k = 24 * Mb; break; - case 0x10: k = 28 * Mb; break; - case 0x11: k = 32 * Mb; break; - default: k = 1 * Mb; break; - } + case 0x01: + k = 512; + break; + case 0x02: + k = 6 * Mb; /* XP */ + break; + case 0x03: + k = 1 * Mb; + break; + case 0x04: + k = 8 * Mb; + break; + case 0x06: + k = 10 * Mb; /* XP */ + break; + case 0x07: + k = 2 * Mb; + break; + case 0x08: + k = 12 * Mb; /* XP */ + break; + case 0x0A: + k = 14 * Mb; /* XP */ + break; + case 0x0C: + k = 16 * Mb; /* XP */ + break; + case 0x0E: /* XP */ + + tmp2 = read3C4(0xC1); + switch (tmp2) { + case 0x00: + k = 20 * Mb; + break; + case 0x01: + k = 24 * Mb; + break; + case 0x10: + k = 28 * Mb; + break; + case 0x11: + k = 32 * Mb; + break; + default: + k = 1 * Mb; + break; + } + break; + + case 0x0F: + k = 4 * Mb; + break; + default: + k = 1 * Mb; break; - - case 0x0F: k = 4 * Mb; break; - default: k = 1 * Mb; } - } + } k -= memdiff * Kb; - output("framebuffer size = %d Kb\n", k/Kb); + output("framebuffer size = %d Kb\n", k / Kb); return k; } /* See if we can handle the video mode described in var */ -static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +static int tridentfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) { int bpp = var->bits_per_pixel; debug("enter\n"); /* check color depth */ - if (bpp == 24 ) + if (bpp == 24) bpp = var->bits_per_pixel = 32; - /* check whether resolution fits on panel and in memory*/ + /* check whether resolution fits on panel and in memory */ if (flatpanel && nativex && var->xres > nativex) return -EINVAL; - if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len) + if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len) return -EINVAL; switch (bpp) { - case 8: - var->red.offset = 0; - var->green.offset = 0; - var->blue.offset = 0; - var->red.length = 6; - var->green.length = 6; - var->blue.length = 6; - break; - case 16: - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - break; - case 32: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - break; - default: - return -EINVAL; + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + default: + return -EINVAL; } debug("exit\n"); return 0; } + /* Pan the display */ static int tridentfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { unsigned int offset; debug("enter\n"); offset = (var->xoffset + (var->yoffset * var->xres)) - * var->bits_per_pixel/32; + * var->bits_per_pixel / 32; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; set_screen_start(offset); @@ -777,36 +858,38 @@ static int tridentfb_pan_display(struct fb_var_screeninfo *var, return 0; } -#define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81) -#define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E) +#define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81) +#define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E) /* Set the hardware to the requested video mode */ static int tridentfb_set_par(struct fb_info *info) { - struct tridentfb_par * par = (struct tridentfb_par *)(info->par); - u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend, - vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend; - struct fb_var_screeninfo *var = &info->var; + struct tridentfb_par *par = (struct tridentfb_par *)(info->par); + u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend; + u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; + struct fb_var_screeninfo *var = &info->var; int bpp = var->bits_per_pixel; unsigned char tmp; debug("enter\n"); - htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10; - hdispend = var->xres/8 - 1; - hsyncstart = (var->xres + var->right_margin)/8; - hsyncend = var->hsync_len/8; + hdispend = var->xres / 8 - 1; + hsyncstart = (var->xres + var->right_margin) / 8; + hsyncend = var->hsync_len / 8; + htotal = + (var->xres + var->left_margin + var->right_margin + + var->hsync_len) / 8 - 10; hblankstart = hdispend + 1; hblankend = htotal + 5; - vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2; vdispend = var->yres - 1; vsyncstart = var->yres + var->lower_margin; vsyncend = var->vsync_len; + vtotal = var->upper_margin + vsyncstart + vsyncend - 2; vblankstart = var->yres; vblankend = vtotal + 2; enable_mmio(); crtc_unlock(); - write3CE(CyberControl,8); + write3CE(CyberControl, 8); if (flatpanel && var->xres < nativex) { /* @@ -814,18 +897,18 @@ static int tridentfb_set_par(struct fb_info *info) * than requested resolution decide whether * we stretch or center */ - t_outb(0xEB,0x3C2); + t_outb(0xEB, 0x3C2); shadowmode_on(); - if (center) + if (center) screen_center(); else if (stretch) screen_stretch(); } else { - t_outb(0x2B,0x3C2); - write3CE(CyberControl,8); + t_outb(0x2B, 0x3C2); + write3CE(CyberControl, 8); } /* vertical timing values */ @@ -834,15 +917,15 @@ static int tridentfb_set_par(struct fb_info *info) write3X4(CRTVSyncStart, vsyncstart & 0xFF); write3X4(CRTVSyncEnd, (vsyncend & 0x0F)); write3X4(CRTVBlankStart, vblankstart & 0xFF); - write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/); + write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ ); /* horizontal timing values */ write3X4(CRTHTotal, htotal & 0xFF); write3X4(CRTHDispEnd, hdispend & 0xFF); write3X4(CRTHSyncStart, hsyncstart & 0xFF); - write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2)); + write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); write3X4(CRTHBlankStart, hblankstart & 0xFF); - write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/); + write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ ); /* higher bits of vertical timing values */ tmp = 0x10; @@ -856,7 +939,7 @@ static int tridentfb_set_par(struct fb_info *info) if (vsyncstart & 0x200) tmp |= 0x80; write3X4(CRTOverflow, tmp); - tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10 + tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */ if (vtotal & 0x400) tmp |= 0x80; if (vblankstart & 0x400) tmp |= 0x40; if (vsyncstart & 0x400) tmp |= 0x20; @@ -867,84 +950,100 @@ static int tridentfb_set_par(struct fb_info *info) if (htotal & 0x800) tmp |= 0x800 >> 11; if (hblankstart & 0x800) tmp |= 0x800 >> 7; write3X4(HorizOverflow, tmp); - + tmp = 0x40; if (vblankstart & 0x200) tmp |= 0x20; -//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes +//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */ write3X4(CRTMaxScanLine, tmp); - write3X4(CRTLineCompare,0xFF); - write3X4(CRTPRowScan,0); - write3X4(CRTModeControl,0xC3); + write3X4(CRTLineCompare, 0xFF); + write3X4(CRTPRowScan, 0); + write3X4(CRTModeControl, 0xC3); - write3X4(LinearAddReg,0x20); //enable linear addressing + write3X4(LinearAddReg, 0x20); /* enable linear addressing */ - tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80; - write3X4(CRTCModuleTest,tmp); //enable access extended memory + tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80; + write3X4(CRTCModuleTest, tmp); /* enable access extended memory */ - write3X4(GraphEngReg, 0x80); //enable GE for text acceleration + write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */ -#ifdef CONFIG_FB_TRIDENT_ACCEL - acc->init_accel(info->var.xres,bpp); +#ifdef CONFIG_FB_TRIDENT_ACCEL + acc->init_accel(info->var.xres, bpp); #endif - + switch (bpp) { - case 8: tmp = 0x00; break; - case 16: tmp = 0x05; break; - case 24: tmp = 0x29; break; - case 32: tmp = 0x09; + case 8: + tmp = 0x00; + break; + case 16: + tmp = 0x05; + break; + case 24: + tmp = 0x29; + break; + case 32: + tmp = 0x09; + break; } write3X4(PixelBusReg, tmp); tmp = 0x10; if (chipcyber) - tmp |= 0x20; - write3X4(DRAMControl, tmp); //both IO,linear enable + tmp |= 0x20; + write3X4(DRAMControl, tmp); /* both IO, linear enable */ write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40); - write3X4(Performance,0x92); - write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable + write3X4(Performance, 0x92); + write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */ /* convert from picoseconds to MHz */ - par->vclk = 1000000/info->var.pixclock; + par->vclk = 1000000 / info->var.pixclock; if (bpp == 32) - par->vclk *=2; + par->vclk *= 2; set_vclk(par->vclk); - write3C4(0,3); - write3C4(1,1); //set char clock 8 dots wide - write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode - write3C4(3,0); - write3C4(4,0x0E); //memory mode enable bitmaps ?? + write3C4(0, 3); + write3C4(1, 1); /* set char clock 8 dots wide */ + write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */ + write3C4(3, 0); + write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */ - write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp - //chain4 mode display and CPU path - write3CE(0x5,0x40); //no CGA compat,allow 256 col - write3CE(0x6,0x05); //graphics mode - write3CE(0x7,0x0F); //planes? + write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */ + /* chain4 mode display and CPU path */ + write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */ + write3CE(0x6, 0x05); /* graphics mode */ + write3CE(0x7, 0x0F); /* planes? */ if (chip_id == CYBERBLADEXPAi1) { /* This fixes snow-effect in 32 bpp */ - write3X4(CRTHSyncStart,0x84); + write3X4(CRTHSyncStart, 0x84); } - writeAttr(0x10,0x41); //graphics mode and support 256 color modes - writeAttr(0x12,0x0F); //planes - writeAttr(0x13,0); //horizontal pel panning + writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */ + writeAttr(0x12, 0x0F); /* planes */ + writeAttr(0x13, 0); /* horizontal pel panning */ - //colors - for(tmp = 0;tmp < 0x10;tmp++) - writeAttr(tmp,tmp); - readb(par->io_virt + CRT + 0x0A); //flip-flop to index - t_outb(0x20, 0x3C0); //enable attr + /* colors */ + for (tmp = 0; tmp < 0x10; tmp++) + writeAttr(tmp, tmp); + readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */ + t_outb(0x20, 0x3C0); /* enable attr */ switch (bpp) { - case 8: tmp = 0;break; //256 colors - case 15: tmp = 0x10;break; - case 16: tmp = 0x30;break; //hicolor - case 24: //truecolor - case 32: tmp = 0xD0;break; + case 8: + tmp = 0; + break; + case 15: + tmp = 0x10; + break; + case 16: + tmp = 0x30; + break; + case 24: + case 32: + tmp = 0xD0; + break; } t_inb(0x3C8); @@ -952,37 +1051,36 @@ static int tridentfb_set_par(struct fb_info *info) t_inb(0x3C6); t_inb(0x3C6); t_inb(0x3C6); - t_outb(tmp,0x3C6); + t_outb(tmp, 0x3C6); t_inb(0x3C8); if (flatpanel) set_number_of_lines(info->var.yres); - set_lwidth(info->var.xres * bpp/(4*16)); + set_lwidth(info->var.xres * bpp / (4 * 16)); info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = info->var.xres * (bpp >> 3); - info->cmap.len = (bpp == 8) ? 256: 16; + info->fix.line_length = info->var.xres * (bpp >> 3); + info->cmap.len = (bpp == 8) ? 256 : 16; debug("exit\n"); return 0; } /* Set one color register */ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) + unsigned blue, unsigned transp, + struct fb_info *info) { int bpp = info->var.bits_per_pixel; if (regno >= info->cmap.len) return 1; - if (bpp == 8) { - t_outb(0xFF,0x3C6); - t_outb(regno,0x3C8); + t_outb(0xFF, 0x3C6); + t_outb(regno, 0x3C8); - t_outb(red>>10,0x3C9); - t_outb(green>>10,0x3C9); - t_outb(blue>>10,0x3C9); + t_outb(red >> 10, 0x3C9); + t_outb(green >> 10, 0x3C9); + t_outb(blue >> 10, 0x3C9); } else if (regno < 16) { if (bpp == 16) { /* RGB 565 */ @@ -994,29 +1092,28 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, ((u32 *)(info->pseudo_palette))[regno] = col; } else if (bpp == 32) /* ARGB 8888 */ ((u32*)info->pseudo_palette)[regno] = - ((transp & 0xFF00) <<16) | - ((red & 0xFF00) << 8) | + ((transp & 0xFF00) << 16) | + ((red & 0xFF00) << 8) | ((green & 0xFF00)) | - ((blue & 0xFF00)>>8); + ((blue & 0xFF00) >> 8); } -// debug("exit\n"); +/* debug("exit\n"); */ return 0; } /* Try blanking the screen.For flat panels it does nothing */ static int tridentfb_blank(int blank_mode, struct fb_info *info) { - unsigned char PMCont,DPMSCont; + unsigned char PMCont, DPMSCont; debug("enter\n"); if (flatpanel) return 0; - t_outb(0x04,0x83C8); /* Read DPMS Control */ + t_outb(0x04, 0x83C8); /* Read DPMS Control */ PMCont = t_inb(0x83C6) & 0xFC; DPMSCont = read3CE(PowerStatus) & 0xFC; - switch (blank_mode) - { + switch (blank_mode) { case FB_BLANK_UNBLANK: /* Screen: On, HSync: On, VSync: On */ case FB_BLANK_NORMAL: @@ -1039,11 +1136,11 @@ static int tridentfb_blank(int blank_mode, struct fb_info *info) PMCont |= 0x00; DPMSCont |= 0x03; break; - } + } - write3CE(PowerStatus,DPMSCont); - t_outb(4,0x83C8); - t_outb(PMCont,0x83C6); + write3CE(PowerStatus, DPMSCont); + t_outb(4, 0x83C8); + t_outb(PMCont, 0x83C6); debug("exit\n"); @@ -1051,7 +1148,20 @@ static int tridentfb_blank(int blank_mode, struct fb_info *info) return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; } -static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id) +static struct fb_ops tridentfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = tridentfb_setcolreg, + .fb_pan_display = tridentfb_pan_display, + .fb_blank = tridentfb_blank, + .fb_check_var = tridentfb_check_var, + .fb_set_par = tridentfb_set_par, + .fb_fillrect = tridentfb_fillrect, + .fb_copyarea = tridentfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static int __devinit trident_pci_probe(struct pci_dev * dev, + const struct pci_device_id * id) { int err; unsigned char revision; @@ -1062,31 +1172,42 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de chip_id = id->device; - if(chip_id == CYBERBLADEi1) + if (chip_id == CYBERBLADEi1) output("*** Please do use cyblafb, Cyberblade/i1 support " "will soon be removed from tridentfb!\n"); /* If PCI id is 0x9660 then further detect chip type */ - + if (chip_id == TGUI9660) { - outb(RevisionID,0x3C4); - revision = inb(0x3C5); - + outb(RevisionID, 0x3C4); + revision = inb(0x3C5); + switch (revision) { - case 0x22: - case 0x23: chip_id = CYBER9397;break; - case 0x2A: chip_id = CYBER9397DVD;break; - case 0x30: - case 0x33: - case 0x34: - case 0x35: - case 0x38: - case 0x3A: - case 0xB3: chip_id = CYBER9385;break; - case 0x40 ... 0x43: chip_id = CYBER9382;break; - case 0x4A: chip_id = CYBER9388;break; - default:break; + case 0x22: + case 0x23: + chip_id = CYBER9397; + break; + case 0x2A: + chip_id = CYBER9397DVD; + break; + case 0x30: + case 0x33: + case 0x34: + case 0x35: + case 0x38: + case 0x3A: + case 0xB3: + chip_id = CYBER9385; + break; + case 0x40 ... 0x43: + chip_id = CYBER9382; + break; + case 0x4A: + chip_id = CYBER9388; + break; + default: + break; } } @@ -1095,8 +1216,7 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de if (is_xp(chip_id)) { acc = &accel_xp; - } else - if (is_blade(chip_id)) { + } else if (is_blade(chip_id)) { acc = &accel_blade; } else { acc = &accel_image; @@ -1108,8 +1228,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de fb_info.par = &default_par; /* setup MMIO region */ - tridentfb_fix.mmio_start = pci_resource_start(dev,1); - tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000; + tridentfb_fix.mmio_start = pci_resource_start(dev, 1); + tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000; if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) { debug("request_region failed!\n"); @@ -1125,11 +1245,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de } enable_mmio(); - + /* setup framebuffer memory */ - tridentfb_fix.smem_start = pci_resource_start(dev,0); + tridentfb_fix.smem_start = pci_resource_start(dev, 0); tridentfb_fix.smem_len = get_memsize(); - + if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) { debug("request_mem_region failed!\n"); err = -1; @@ -1137,7 +1257,7 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de } fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start, - tridentfb_fix.smem_len); + tridentfb_fix.smem_len); if (!fb_info.screen_base) { release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); @@ -1147,13 +1267,13 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de } output("%s board found\n", pci_name(dev)); -#if 0 - output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n", +#if 0 + output("Trident board found : mem = %X, io = %X, mem_v = %X, io_v = %X\n", tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt); #endif displaytype = get_displaytype(); - if(flatpanel) + if (flatpanel) nativex = get_nativex(); fb_info.fix = tridentfb_fix; @@ -1166,11 +1286,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de #endif fb_info.pseudo_palette = pseudo_pal; - if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) { + if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) { err = -EINVAL; goto out_unmap; } - fb_alloc_cmap(&fb_info.cmap,256,0); + fb_alloc_cmap(&fb_info.cmap, 256, 0); if (defaultaccel && acc) default_var.accel_flags |= FB_ACCELF_TEXT; else @@ -1184,8 +1304,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de goto out_unmap; } output("fb%d: %s frame buffer device %dx%d-%dbpp\n", - fb_info.node, fb_info.fix.id,default_var.xres, - default_var.yres,default_var.bits_per_pixel); + fb_info.node, fb_info.fix.id, default_var.xres, + default_var.yres, default_var.bits_per_pixel); return 0; out_unmap: @@ -1196,7 +1316,7 @@ out_unmap: return err; } -static void __devexit trident_pci_remove(struct pci_dev * dev) +static void __devexit trident_pci_remove(struct pci_dev *dev) { struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par; unregister_framebuffer(&fb_info); @@ -1208,69 +1328,70 @@ static void __devexit trident_pci_remove(struct pci_dev * dev) /* List of boards that we are trying to support */ static struct pci_device_id trident_devices[] = { - {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,} -}; - -MODULE_DEVICE_TABLE(pci,trident_devices); +}; + +MODULE_DEVICE_TABLE(pci, trident_devices); static struct pci_driver tridentfb_pci_driver = { - .name = "tridentfb", - .id_table = trident_devices, - .probe = trident_pci_probe, - .remove = __devexit_p(trident_pci_remove) + .name = "tridentfb", + .id_table = trident_devices, + .probe = trident_pci_probe, + .remove = __devexit_p(trident_pci_remove) }; /* * Parse user specified options (`video=trident:') * example: - * video=trident:800x600,bpp=16,noaccel + * video=trident:800x600,bpp=16,noaccel */ #ifndef MODULE static int tridentfb_setup(char *options) { - char * opt; + char *opt; if (!options || !*options) return 0; - while((opt = strsep(&options,",")) != NULL ) { - if (!*opt) continue; - if (!strncmp(opt,"noaccel",7)) + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + if (!strncmp(opt, "noaccel", 7)) noaccel = 1; - else if (!strncmp(opt,"fp",2)) + else if (!strncmp(opt, "fp", 2)) displaytype = DISPLAY_FP; - else if (!strncmp(opt,"crt",3)) + else if (!strncmp(opt, "crt", 3)) displaytype = DISPLAY_CRT; - else if (!strncmp(opt,"bpp=",4)) - bpp = simple_strtoul(opt+4,NULL,0); - else if (!strncmp(opt,"center",6)) + else if (!strncmp(opt, "bpp=", 4)) + bpp = simple_strtoul(opt + 4, NULL, 0); + else if (!strncmp(opt, "center", 6)) center = 1; - else if (!strncmp(opt,"stretch",7)) + else if (!strncmp(opt, "stretch", 7)) stretch = 1; - else if (!strncmp(opt,"memsize=",8)) - memsize = simple_strtoul(opt+8,NULL,0); - else if (!strncmp(opt,"memdiff=",8)) - memdiff = simple_strtoul(opt+8,NULL,0); - else if (!strncmp(opt,"nativex=",8)) - nativex = simple_strtoul(opt+8,NULL,0); + else if (!strncmp(opt, "memsize=", 8)) + memsize = simple_strtoul(opt + 8, NULL, 0); + else if (!strncmp(opt, "memdiff=", 8)) + memdiff = simple_strtoul(opt + 8, NULL, 0); + else if (!strncmp(opt, "nativex=", 8)) + nativex = simple_strtoul(opt + 8, NULL, 0); else mode = opt; } @@ -1296,18 +1417,6 @@ static void __exit tridentfb_exit(void) pci_unregister_driver(&tridentfb_pci_driver); } -static struct fb_ops tridentfb_ops = { - .owner = THIS_MODULE, - .fb_setcolreg = tridentfb_setcolreg, - .fb_pan_display = tridentfb_pan_display, - .fb_blank = tridentfb_blank, - .fb_check_var = tridentfb_check_var, - .fb_set_par = tridentfb_set_par, - .fb_fillrect = tridentfb_fillrect, - .fb_copyarea= tridentfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - module_init(tridentfb_init); module_exit(tridentfb_exit); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c new file mode 100644 index 00000000000..b983d262ab7 --- /dev/null +++ b/drivers/video/uvesafb.c @@ -0,0 +1,2066 @@ +/* + * A framebuffer driver for VBE 2.0+ compliant video cards + * + * (c) 2007 Michal Januszewski <spock@gentoo.org> + * Loosely based upon the vesafb driver. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/skbuff.h> +#include <linux/timer.h> +#include <linux/completion.h> +#include <linux/connector.h> +#include <linux/random.h> +#include <linux/platform_device.h> +#include <linux/limits.h> +#include <linux/fb.h> +#include <linux/io.h> +#include <linux/mutex.h> +#include <video/edid.h> +#include <video/uvesafb.h> +#ifdef CONFIG_X86 +#include <video/vga.h> +#endif +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif +#include "edid.h" + +static struct cb_id uvesafb_cn_id = { + .idx = CN_IDX_V86D, + .val = CN_VAL_V86D_UVESAFB +}; +static char v86d_path[PATH_MAX] = "/sbin/v86d"; +static char v86d_started; /* has v86d been started by uvesafb? */ + +static struct fb_fix_screeninfo uvesafb_fix __devinitdata = { + .id = "VESA VGA", + .type = FB_TYPE_PACKED_PIXELS, + .accel = FB_ACCEL_NONE, + .visual = FB_VISUAL_TRUECOLOR, +}; + +static int mtrr __devinitdata = 3; /* enable mtrr by default */ +static int blank __devinitdata = 1; /* enable blanking by default */ +static int ypan __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */ +static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */ +static int nocrtc __devinitdata; /* ignore CRTC settings */ +static int noedid __devinitdata; /* don't try DDC transfers */ +static int vram_remap __devinitdata; /* set amt. of memory to be used */ +static int vram_total __devinitdata; /* set total amount of memory */ +static u16 maxclk __devinitdata; /* maximum pixel clock */ +static u16 maxvf __devinitdata; /* maximum vertical frequency */ +static u16 maxhf __devinitdata; /* maximum horizontal frequency */ +static u16 vbemode __devinitdata; /* force use of a specific VBE mode */ +static char *mode_option __devinitdata; + +static struct uvesafb_ktask *uvfb_tasks[UVESAFB_TASKS_MAX]; +static DEFINE_MUTEX(uvfb_lock); + +/* + * A handler for replies from userspace. + * + * Make sure each message passes consistency checks and if it does, + * find the kernel part of the task struct, copy the registers and + * the buffer contents and then complete the task. + */ +static void uvesafb_cn_callback(void *data) +{ + struct cn_msg *msg = data; + struct uvesafb_task *utask; + struct uvesafb_ktask *task; + + if (msg->seq >= UVESAFB_TASKS_MAX) + return; + + mutex_lock(&uvfb_lock); + task = uvfb_tasks[msg->seq]; + + if (!task || msg->ack != task->ack) { + mutex_unlock(&uvfb_lock); + return; + } + + utask = (struct uvesafb_task *)msg->data; + + /* Sanity checks for the buffer length. */ + if (task->t.buf_len < utask->buf_len || + utask->buf_len > msg->len - sizeof(*utask)) { + mutex_unlock(&uvfb_lock); + return; + } + + uvfb_tasks[msg->seq] = NULL; + mutex_unlock(&uvfb_lock); + + memcpy(&task->t, utask, sizeof(*utask)); + + if (task->t.buf_len && task->buf) + memcpy(task->buf, utask + 1, task->t.buf_len); + + complete(task->done); + return; +} + +static int uvesafb_helper_start(void) +{ + char *envp[] = { + "HOME=/", + "PATH=/sbin:/bin", + NULL, + }; + + char *argv[] = { + v86d_path, + NULL, + }; + + return call_usermodehelper(v86d_path, argv, envp, 1); +} + +/* + * Execute a uvesafb task. + * + * Returns 0 if the task is executed successfully. + * + * A message sent to the userspace consists of the uvesafb_task + * struct and (optionally) a buffer. The uvesafb_task struct is + * a simplified version of uvesafb_ktask (its kernel counterpart) + * containing only the register values, flags and the length of + * the buffer. + * + * Each message is assigned a sequence number (increased linearly) + * and a random ack number. The sequence number is used as a key + * for the uvfb_tasks array which holds pointers to uvesafb_ktask + * structs for all requests. + */ +static int uvesafb_exec(struct uvesafb_ktask *task) +{ + static int seq; + struct cn_msg *m; + int err; + int len = sizeof(task->t) + task->t.buf_len; + + /* + * Check whether the message isn't longer than the maximum + * allowed by connector. + */ + if (sizeof(*m) + len > CONNECTOR_MAX_MSG_SIZE) { + printk(KERN_WARNING "uvesafb: message too long (%d), " + "can't execute task\n", (int)(sizeof(*m) + len)); + return -E2BIG; + } + + m = kzalloc(sizeof(*m) + len, GFP_KERNEL); + if (!m) + return -ENOMEM; + + init_completion(task->done); + + memcpy(&m->id, &uvesafb_cn_id, sizeof(m->id)); + m->seq = seq; + m->len = len; + m->ack = random32(); + + /* uvesafb_task structure */ + memcpy(m + 1, &task->t, sizeof(task->t)); + + /* Buffer */ + memcpy((u8 *)(m + 1) + sizeof(task->t), task->buf, task->t.buf_len); + + /* + * Save the message ack number so that we can find the kernel + * part of this task when a reply is received from userspace. + */ + task->ack = m->ack; + + mutex_lock(&uvfb_lock); + + /* If all slots are taken -- bail out. */ + if (uvfb_tasks[seq]) { + mutex_unlock(&uvfb_lock); + return -EBUSY; + } + + /* Save a pointer to the kernel part of the task struct. */ + uvfb_tasks[seq] = task; + mutex_unlock(&uvfb_lock); + + err = cn_netlink_send(m, 0, gfp_any()); + if (err == -ESRCH) { + /* + * Try to start the userspace helper if sending + * the request failed the first time. + */ + err = uvesafb_helper_start(); + if (err) { + printk(KERN_ERR "uvesafb: failed to execute %s\n", + v86d_path); + printk(KERN_ERR "uvesafb: make sure that the v86d " + "helper is installed and executable\n"); + } else { + v86d_started = 1; + err = cn_netlink_send(m, 0, gfp_any()); + } + } + kfree(m); + + if (!err && !(task->t.flags & TF_EXIT)) + err = !wait_for_completion_timeout(task->done, + msecs_to_jiffies(UVESAFB_TIMEOUT)); + + mutex_lock(&uvfb_lock); + uvfb_tasks[seq] = NULL; + mutex_unlock(&uvfb_lock); + + seq++; + if (seq >= UVESAFB_TASKS_MAX) + seq = 0; + + return err; +} + +/* + * Free a uvesafb_ktask struct. + */ +static void uvesafb_free(struct uvesafb_ktask *task) +{ + if (task) { + if (task->done) + kfree(task->done); + kfree(task); + } +} + +/* + * Prepare a uvesafb_ktask struct to be used again. + */ +static void uvesafb_reset(struct uvesafb_ktask *task) +{ + struct completion *cpl = task->done; + + memset(task, 0, sizeof(*task)); + task->done = cpl; +} + +/* + * Allocate and prepare a uvesafb_ktask struct. + */ +static struct uvesafb_ktask *uvesafb_prep(void) +{ + struct uvesafb_ktask *task; + + task = kzalloc(sizeof(*task), GFP_KERNEL); + if (task) { + task->done = kzalloc(sizeof(*task->done), GFP_KERNEL); + if (!task->done) { + kfree(task); + task = NULL; + } + } + return task; +} + +static void uvesafb_setup_var(struct fb_var_screeninfo *var, + struct fb_info *info, struct vbe_mode_ib *mode) +{ + struct uvesafb_par *par = info->par; + + var->vmode = FB_VMODE_NONINTERLACED; + var->sync = FB_SYNC_VERT_HIGH_ACT; + + var->xres = mode->x_res; + var->yres = mode->y_res; + var->xres_virtual = mode->x_res; + var->yres_virtual = (par->ypan) ? + info->fix.smem_len / mode->bytes_per_scan_line : + mode->y_res; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = mode->bits_per_pixel; + + if (var->bits_per_pixel == 15) + var->bits_per_pixel = 16; + + if (var->bits_per_pixel > 8) { + var->red.offset = mode->red_off; + var->red.length = mode->red_len; + var->green.offset = mode->green_off; + var->green.length = mode->green_len; + var->blue.offset = mode->blue_off; + var->blue.length = mode->blue_len; + var->transp.offset = mode->rsvd_off; + var->transp.length = mode->rsvd_len; + } else { + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->transp.offset = 0; + + /* + * We're assuming that we can switch the DAC to 8 bits. If + * this proves to be incorrect, we'll update the fields + * later in set_par(). + */ + if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC) { + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + } else { + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + var->transp.length = 0; + } + } +} + +static int uvesafb_vbe_find_mode(struct uvesafb_par *par, + int xres, int yres, int depth, unsigned char flags) +{ + int i, match = -1, h = 0, d = 0x7fffffff; + + for (i = 0; i < par->vbe_modes_cnt; i++) { + h = abs(par->vbe_modes[i].x_res - xres) + + abs(par->vbe_modes[i].y_res - yres) + + abs(depth - par->vbe_modes[i].depth); + + /* + * We have an exact match in terms of resolution + * and depth. + */ + if (h == 0) + return i; + + if (h < d || (h == d && par->vbe_modes[i].depth > depth)) { + d = h; + match = i; + } + } + i = 1; + + if (flags & UVESAFB_EXACT_DEPTH && + par->vbe_modes[match].depth != depth) + i = 0; + + if (flags & UVESAFB_EXACT_RES && d > 24) + i = 0; + + if (i != 0) + return match; + else + return -1; +} + +static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par) +{ + struct uvesafb_ktask *task; + u8 *state; + int err; + + if (!par->vbe_state_size) + return NULL; + + state = kmalloc(par->vbe_state_size, GFP_KERNEL); + if (!state) + return NULL; + + task = uvesafb_prep(); + if (!task) { + kfree(state); + return NULL; + } + + task->t.regs.eax = 0x4f04; + task->t.regs.ecx = 0x000f; + task->t.regs.edx = 0x0001; + task->t.flags = TF_BUF_RET | TF_BUF_ESBX; + task->t.buf_len = par->vbe_state_size; + task->buf = state; + err = uvesafb_exec(task); + + if (err || (task->t.regs.eax & 0xffff) != 0x004f) { + printk(KERN_WARNING "uvesafb: VBE get state call " + "failed (eax=0x%x, err=%d)\n", + task->t.regs.eax, err); + kfree(state); + state = NULL; + } + + uvesafb_free(task); + return state; +} + +static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf) +{ + struct uvesafb_ktask *task; + int err; + + if (!state_buf) + return; + + task = uvesafb_prep(); + if (!task) + return; + + task->t.regs.eax = 0x4f04; + task->t.regs.ecx = 0x000f; + task->t.regs.edx = 0x0002; + task->t.buf_len = par->vbe_state_size; + task->t.flags = TF_BUF_ESBX; + task->buf = state_buf; + + err = uvesafb_exec(task); + if (err || (task->t.regs.eax & 0xffff) != 0x004f) + printk(KERN_WARNING "uvesafb: VBE state restore call " + "failed (eax=0x%x, err=%d)\n", + task->t.regs.eax, err); + + uvesafb_free(task); +} + +static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task, + struct uvesafb_par *par) +{ + int err; + + task->t.regs.eax = 0x4f00; + task->t.flags = TF_VBEIB; + task->t.buf_len = sizeof(struct vbe_ib); + task->buf = &par->vbe_ib; + strncpy(par->vbe_ib.vbe_signature, "VBE2", 4); + + err = uvesafb_exec(task); + if (err || (task->t.regs.eax & 0xffff) != 0x004f) { + printk(KERN_ERR "uvesafb: Getting VBE info block failed " + "(eax=0x%x, err=%d)\n", (u32)task->t.regs.eax, + err); + return -EINVAL; + } + + if (par->vbe_ib.vbe_version < 0x0200) { + printk(KERN_ERR "uvesafb: Sorry, pre-VBE 2.0 cards are " + "not supported.\n"); + return -EINVAL; + } + + if (!par->vbe_ib.mode_list_ptr) { + printk(KERN_ERR "uvesafb: Missing mode list!\n"); + return -EINVAL; + } + + printk(KERN_INFO "uvesafb: "); + + /* + * Convert string pointers and the mode list pointer into + * usable addresses. Print informational messages about the + * video adapter and its vendor. + */ + if (par->vbe_ib.oem_vendor_name_ptr) + printk("%s, ", + ((char *)task->buf) + par->vbe_ib.oem_vendor_name_ptr); + + if (par->vbe_ib.oem_product_name_ptr) + printk("%s, ", + ((char *)task->buf) + par->vbe_ib.oem_product_name_ptr); + + if (par->vbe_ib.oem_product_rev_ptr) + printk("%s, ", + ((char *)task->buf) + par->vbe_ib.oem_product_rev_ptr); + + if (par->vbe_ib.oem_string_ptr) + printk("OEM: %s, ", + ((char *)task->buf) + par->vbe_ib.oem_string_ptr); + + printk("VBE v%d.%d\n", ((par->vbe_ib.vbe_version & 0xff00) >> 8), + par->vbe_ib.vbe_version & 0xff); + + return 0; +} + +static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task, + struct uvesafb_par *par) +{ + int off = 0, err; + u16 *mode; + + par->vbe_modes_cnt = 0; + + /* Count available modes. */ + mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr); + while (*mode != 0xffff) { + par->vbe_modes_cnt++; + mode++; + } + + par->vbe_modes = kzalloc(sizeof(struct vbe_mode_ib) * + par->vbe_modes_cnt, GFP_KERNEL); + if (!par->vbe_modes) + return -ENOMEM; + + /* Get info about all available modes. */ + mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr); + while (*mode != 0xffff) { + struct vbe_mode_ib *mib; + + uvesafb_reset(task); + task->t.regs.eax = 0x4f01; + task->t.regs.ecx = (u32) *mode; + task->t.flags = TF_BUF_RET | TF_BUF_ESDI; + task->t.buf_len = sizeof(struct vbe_mode_ib); + task->buf = par->vbe_modes + off; + + err = uvesafb_exec(task); + if (err || (task->t.regs.eax & 0xffff) != 0x004f) { + printk(KERN_ERR "uvesafb: Getting mode info block " + "for mode 0x%x failed (eax=0x%x, err=%d)\n", + *mode, (u32)task->t.regs.eax, err); + return -EINVAL; + } + + mib = task->buf; + mib->mode_id = *mode; + + /* + * We only want modes that are supported with the current + * hardware configuration, color, graphics and that have + * support for the LFB. + */ + if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK && + mib->bits_per_pixel >= 8) + off++; + else + par->vbe_modes_cnt--; + + mode++; + mib->depth = mib->red_len + mib->green_len + mib->blue_len; + + /* + * Handle 8bpp modes and modes with broken color component + * lengths. + */ + if (mib->depth == 0 || (mib->depth == 24 && + mib->bits_per_pixel == 32)) + mib->depth = mib->bits_per_pixel; + } + + return 0; +} + +/* + * The Protected Mode Interface is 32-bit x86 code, so we only run it on + * x86 and not x86_64. + */ +#ifdef CONFIG_X86_32 +static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task, + struct uvesafb_par *par) +{ + int i, err; + + uvesafb_reset(task); + task->t.regs.eax = 0x4f0a; + task->t.regs.ebx = 0x0; + err = uvesafb_exec(task); + + if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) { + par->pmi_setpal = par->ypan = 0; + } else { + par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4) + + task->t.regs.edi); + par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1]; + par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2]; + printk(KERN_INFO "uvesafb: protected mode interface info at " + "%04x:%04x\n", + (u16)task->t.regs.es, (u16)task->t.regs.edi); + printk(KERN_INFO "uvesafb: pmi: set display start = %p, " + "set palette = %p\n", par->pmi_start, + par->pmi_pal); + + if (par->pmi_base[3]) { + printk(KERN_INFO "uvesafb: pmi: ports = "); + for (i = par->pmi_base[3]/2; + par->pmi_base[i] != 0xffff; i++) + printk("%x ", par->pmi_base[i]); + printk("\n"); + + if (par->pmi_base[i] != 0xffff) { + printk(KERN_INFO "uvesafb: can't handle memory" + " requests, pmi disabled\n"); + par->ypan = par->pmi_setpal = 0; + } + } + } + return 0; +} +#endif /* CONFIG_X86_32 */ + +/* + * Check whether a video mode is supported by the Video BIOS and is + * compatible with the monitor limits. + */ +static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode, + struct fb_info *info) +{ + if (info->monspecs.gtf) { + fb_videomode_to_var(&info->var, mode); + if (fb_validate_mode(&info->var, info)) + return 0; + } + + if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8, + UVESAFB_EXACT_RES) == -1) + return 0; + + return 1; +} + +static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task, + struct fb_info *info) +{ + struct uvesafb_par *par = info->par; + int err = 0; + + if (noedid || par->vbe_ib.vbe_version < 0x0300) + return -EINVAL; + + task->t.regs.eax = 0x4f15; + task->t.regs.ebx = 0; + task->t.regs.ecx = 0; + task->t.buf_len = 0; + task->t.flags = 0; + + err = uvesafb_exec(task); + + if ((task->t.regs.eax & 0xffff) != 0x004f || err) + return -EINVAL; + + if ((task->t.regs.ebx & 0x3) == 3) { + printk(KERN_INFO "uvesafb: VBIOS/hardware supports both " + "DDC1 and DDC2 transfers\n"); + } else if ((task->t.regs.ebx & 0x3) == 2) { + printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 " + "transfers\n"); + } else if ((task->t.regs.ebx & 0x3) == 1) { + printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 " + "transfers\n"); + } else { + printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support " + "DDC transfers\n"); + return -EINVAL; + } + + task->t.regs.eax = 0x4f15; + task->t.regs.ebx = 1; + task->t.regs.ecx = task->t.regs.edx = 0; + task->t.flags = TF_BUF_RET | TF_BUF_ESDI; + task->t.buf_len = EDID_LENGTH; + task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL); + + err = uvesafb_exec(task); + + if ((task->t.regs.eax & 0xffff) == 0x004f && !err) { + fb_edid_to_monspecs(task->buf, &info->monspecs); + + if (info->monspecs.vfmax && info->monspecs.hfmax) { + /* + * If the maximum pixel clock wasn't specified in + * the EDID block, set it to 300 MHz. + */ + if (info->monspecs.dclkmax == 0) + info->monspecs.dclkmax = 300 * 1000000; + info->monspecs.gtf = 1; + } + } else { + err = -EINVAL; + } + + kfree(task->buf); + return err; +} + +static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task, + struct fb_info *info) +{ + struct uvesafb_par *par = info->par; + int i; + + memset(&info->monspecs, 0, sizeof(info->monspecs)); + + /* + * If we don't get all necessary data from the EDID block, + * mark it as incompatible with the GTF and set nocrtc so + * that we always use the default BIOS refresh rate. + */ + if (uvesafb_vbe_getedid(task, info)) { + info->monspecs.gtf = 0; + par->nocrtc = 1; + } + + /* Kernel command line overrides. */ + if (maxclk) + info->monspecs.dclkmax = maxclk * 1000000; + if (maxvf) + info->monspecs.vfmax = maxvf; + if (maxhf) + info->monspecs.hfmax = maxhf * 1000; + + /* + * In case DDC transfers are not supported, the user can provide + * monitor limits manually. Lower limits are set to "safe" values. + */ + if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) { + info->monspecs.dclkmin = 0; + info->monspecs.vfmin = 60; + info->monspecs.hfmin = 29000; + info->monspecs.gtf = 1; + par->nocrtc = 0; + } + + if (info->monspecs.gtf) + printk(KERN_INFO + "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, " + "clk = %d MHz\n", info->monspecs.vfmax, + (int)(info->monspecs.hfmax / 1000), + (int)(info->monspecs.dclkmax / 1000000)); + else + printk(KERN_INFO "uvesafb: no monitor limits have been set, " + "default refresh rate will be used\n"); + + /* Add VBE modes to the modelist. */ + for (i = 0; i < par->vbe_modes_cnt; i++) { + struct fb_var_screeninfo var; + struct vbe_mode_ib *mode; + struct fb_videomode vmode; + + mode = &par->vbe_modes[i]; + memset(&var, 0, sizeof(var)); + + var.xres = mode->x_res; + var.yres = mode->y_res; + + fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info); + fb_var_to_videomode(&vmode, &var); + fb_add_videomode(&vmode, &info->modelist); + } + + /* Add valid VESA modes to our modelist. */ + for (i = 0; i < VESA_MODEDB_SIZE; i++) { + if (uvesafb_is_valid_mode((struct fb_videomode *) + &vesa_modes[i], info)) + fb_add_videomode(&vesa_modes[i], &info->modelist); + } + + for (i = 0; i < info->monspecs.modedb_len; i++) { + if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info)) + fb_add_videomode(&info->monspecs.modedb[i], + &info->modelist); + } + + return; +} + +static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task, + struct uvesafb_par *par) +{ + int err; + + uvesafb_reset(task); + + /* + * Get the VBE state buffer size. We want all available + * hardware state data (CL = 0x0f). + */ + task->t.regs.eax = 0x4f04; + task->t.regs.ecx = 0x000f; + task->t.regs.edx = 0x0000; + task->t.flags = 0; + + err = uvesafb_exec(task); + + if (err || (task->t.regs.eax & 0xffff) != 0x004f) { + printk(KERN_WARNING "uvesafb: VBE state buffer size " + "cannot be determined (eax=0x%x, err=%d)\n", + task->t.regs.eax, err); + par->vbe_state_size = 0; + return; + } + + par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff); +} + +static int __devinit uvesafb_vbe_init(struct fb_info *info) +{ + struct uvesafb_ktask *task = NULL; + struct uvesafb_par *par = info->par; + int err; + + task = uvesafb_prep(); + if (!task) + return -ENOMEM; + + err = uvesafb_vbe_getinfo(task, par); + if (err) + goto out; + + err = uvesafb_vbe_getmodes(task, par); + if (err) + goto out; + + par->nocrtc = nocrtc; +#ifdef CONFIG_X86_32 + par->pmi_setpal = pmi_setpal; + par->ypan = ypan; + + if (par->pmi_setpal || par->ypan) + uvesafb_vbe_getpmi(task, par); +#else + /* The protected mode interface is not available on non-x86. */ + par->pmi_setpal = par->ypan = 0; +#endif + + INIT_LIST_HEAD(&info->modelist); + uvesafb_vbe_getmonspecs(task, info); + uvesafb_vbe_getstatesize(task, par); + +out: uvesafb_free(task); + return err; +} + +static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) +{ + struct list_head *pos; + struct fb_modelist *modelist; + struct fb_videomode *mode; + struct uvesafb_par *par = info->par; + int i, modeid; + + /* Has the user requested a specific VESA mode? */ + if (vbemode) { + for (i = 0; i < par->vbe_modes_cnt; i++) { + if (par->vbe_modes[i].mode_id == vbemode) { + fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, + &info->var, info); + /* + * With pixclock set to 0, the default BIOS + * timings will be used in set_par(). + */ + info->var.pixclock = 0; + modeid = i; + goto gotmode; + } + } + printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is " + "unavailable\n", vbemode); + vbemode = 0; + } + + /* Count the modes in the modelist */ + i = 0; + list_for_each(pos, &info->modelist) + i++; + + /* + * Convert the modelist into a modedb so that we can use it with + * fb_find_mode(). + */ + mode = kzalloc(i * sizeof(*mode), GFP_KERNEL); + if (mode) { + i = 0; + list_for_each(pos, &info->modelist) { + modelist = list_entry(pos, struct fb_modelist, list); + mode[i] = modelist->mode; + i++; + } + + if (!mode_option) + mode_option = UVESAFB_DEFAULT_MODE; + + i = fb_find_mode(&info->var, info, mode_option, mode, i, + NULL, 8); + + kfree(mode); + } + + /* fb_find_mode() failed */ + if (i == 0 || i >= 3) { + info->var.xres = 640; + info->var.yres = 480; + mode = (struct fb_videomode *) + fb_find_best_mode(&info->var, &info->modelist); + + if (mode) { + fb_videomode_to_var(&info->var, mode); + } else { + modeid = par->vbe_modes[0].mode_id; + fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, + &info->var, info); + goto gotmode; + } + } + + /* Look for a matching VBE mode. */ + modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, + info->var.bits_per_pixel, UVESAFB_EXACT_RES); + + if (modeid == -1) + return -EINVAL; + +gotmode: + uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]); + + /* + * If we are not VBE3.0+ compliant, we're done -- the BIOS will + * ignore our timings anyway. + */ + if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc) + fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, + &info->var, info); + + return modeid; +} + +static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count, + int start, struct fb_info *info) +{ + struct uvesafb_ktask *task; + struct uvesafb_par *par = info->par; + int i = par->mode_idx; + int err = 0; + + /* + * We support palette modifications for 8 bpp modes only, so + * there can never be more than 256 entries. + */ + if (start + count > 256) + return -EINVAL; + +#ifdef CONFIG_X86 + /* Use VGA registers if mode is VGA-compatible. */ + if (i >= 0 && i < par->vbe_modes_cnt && + par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) { + for (i = 0; i < count; i++) { + outb_p(start + i, dac_reg); + outb_p(entries[i].red, dac_val); + outb_p(entries[i].green, dac_val); + outb_p(entries[i].blue, dac_val); + } + } +#ifdef CONFIG_X86_32 + else if (par->pmi_setpal) { + __asm__ __volatile__( + "call *(%%esi)" + : /* no return value */ + : "a" (0x4f09), /* EAX */ + "b" (0), /* EBX */ + "c" (count), /* ECX */ + "d" (start), /* EDX */ + "D" (entries), /* EDI */ + "S" (&par->pmi_pal)); /* ESI */ + } +#endif /* CONFIG_X86_32 */ + else +#endif /* CONFIG_X86 */ + { + task = uvesafb_prep(); + if (!task) + return -ENOMEM; + + task->t.regs.eax = 0x4f09; + task->t.regs.ebx = 0x0; + task->t.regs.ecx = count; + task->t.regs.edx = start; + task->t.flags = TF_BUF_ESDI; + task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count; + task->buf = entries; + + err = uvesafb_exec(task); + if ((task->t.regs.eax & 0xffff) != 0x004f) + err = 1; + + uvesafb_free(task); + } + return err; +} + +static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct uvesafb_pal_entry entry; + int shift = 16 - info->var.green.length; + int err = 0; + + if (regno >= info->cmap.len) + return -EINVAL; + + if (info->var.bits_per_pixel == 8) { + entry.red = red >> shift; + entry.green = green >> shift; + entry.blue = blue >> shift; + entry.pad = 0; + + err = uvesafb_setpalette(&entry, 1, regno, info); + } else if (regno < 16) { + switch (info->var.bits_per_pixel) { + case 16: + if (info->var.red.offset == 10) { + /* 1:5:5:5 */ + ((u32 *) (info->pseudo_palette))[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } else { + /* 0:5:6:5 */ + ((u32 *) (info->pseudo_palette))[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + } + break; + + case 24: + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + } + } + return err; +} + +static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) +{ + struct uvesafb_pal_entry *entries; + int shift = 16 - info->var.green.length; + int i, err = 0; + + if (info->var.bits_per_pixel == 8) { + if (cmap->start + cmap->len > info->cmap.start + + info->cmap.len || cmap->start < info->cmap.start) + return -EINVAL; + + entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < cmap->len; i++) { + entries[i].red = cmap->red[i] >> shift; + entries[i].green = cmap->green[i] >> shift; + entries[i].blue = cmap->blue[i] >> shift; + entries[i].pad = 0; + } + err = uvesafb_setpalette(entries, cmap->len, cmap->start, info); + kfree(entries); + } else { + /* + * For modes with bpp > 8, we only set the pseudo palette in + * the fb_info struct. We rely on uvesafb_setcolreg to do all + * sanity checking. + */ + for (i = 0; i < cmap->len; i++) { + err |= uvesafb_setcolreg(cmap->start + i, cmap->red[i], + cmap->green[i], cmap->blue[i], + 0, info); + } + } + return err; +} + +static int uvesafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ +#ifdef CONFIG_X86_32 + int offset; + struct uvesafb_par *par = info->par; + + offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4; + + /* + * It turns out it's not the best idea to do panning via vm86, + * so we only allow it if we have a PMI. + */ + if (par->pmi_start) { + __asm__ __volatile__( + "call *(%%edi)" + : /* no return value */ + : "a" (0x4f07), /* EAX */ + "b" (0), /* EBX */ + "c" (offset), /* ECX */ + "d" (offset >> 16), /* EDX */ + "D" (&par->pmi_start)); /* EDI */ + } +#endif + return 0; +} + +static int uvesafb_blank(int blank, struct fb_info *info) +{ + struct uvesafb_par *par = info->par; + struct uvesafb_ktask *task; + int err = 1; + +#ifdef CONFIG_X86 + if (par->vbe_ib.capabilities & VBE_CAP_VGACOMPAT) { + int loop = 10000; + u8 seq = 0, crtc17 = 0; + + if (blank == FB_BLANK_POWERDOWN) { + seq = 0x20; + crtc17 = 0x00; + err = 0; + } else { + seq = 0x00; + crtc17 = 0x80; + err = (blank == FB_BLANK_UNBLANK) ? 0 : -EINVAL; + } + + vga_wseq(NULL, 0x00, 0x01); + seq |= vga_rseq(NULL, 0x01) & ~0x20; + vga_wseq(NULL, 0x00, seq); + + crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80; + while (loop--); + vga_wcrt(NULL, 0x17, crtc17); + vga_wseq(NULL, 0x00, 0x03); + } else +#endif /* CONFIG_X86 */ + { + task = uvesafb_prep(); + if (!task) + return -ENOMEM; + + task->t.regs.eax = 0x4f10; + switch (blank) { + case FB_BLANK_UNBLANK: + task->t.regs.ebx = 0x0001; + break; + case FB_BLANK_NORMAL: + task->t.regs.ebx = 0x0101; /* standby */ + break; + case FB_BLANK_POWERDOWN: + task->t.regs.ebx = 0x0401; /* powerdown */ + break; + default: + goto out; + } + + err = uvesafb_exec(task); + if (err || (task->t.regs.eax & 0xffff) != 0x004f) + err = 1; +out: uvesafb_free(task); + } + return err; +} + +static int uvesafb_open(struct fb_info *info, int user) +{ + struct uvesafb_par *par = info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt && par->vbe_state_size) + par->vbe_state_orig = uvesafb_vbe_state_save(par); + + atomic_inc(&par->ref_count); + return 0; +} + +static int uvesafb_release(struct fb_info *info, int user) +{ + struct uvesafb_ktask *task = NULL; + struct uvesafb_par *par = info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt) + return -EINVAL; + + if (cnt != 1) + goto out; + + task = uvesafb_prep(); + if (!task) + goto out; + + /* First, try to set the standard 80x25 text mode. */ + task->t.regs.eax = 0x0003; + uvesafb_exec(task); + + /* + * Now try to restore whatever hardware state we might have + * saved when the fb device was first opened. + */ + uvesafb_vbe_state_restore(par, par->vbe_state_orig); +out: + atomic_dec(&par->ref_count); + if (task) + uvesafb_free(task); + return 0; +} + +static int uvesafb_set_par(struct fb_info *info) +{ + struct uvesafb_par *par = info->par; + struct uvesafb_ktask *task = NULL; + struct vbe_crtc_ib *crtc = NULL; + struct vbe_mode_ib *mode = NULL; + int i, err = 0, depth = info->var.bits_per_pixel; + + if (depth > 8 && depth != 32) + depth = info->var.red.length + info->var.green.length + + info->var.blue.length; + + i = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, depth, + UVESAFB_EXACT_RES | UVESAFB_EXACT_DEPTH); + if (i >= 0) + mode = &par->vbe_modes[i]; + else + return -EINVAL; + + task = uvesafb_prep(); + if (!task) + return -ENOMEM; +setmode: + task->t.regs.eax = 0x4f02; + task->t.regs.ebx = mode->mode_id | 0x4000; /* use LFB */ + + if (par->vbe_ib.vbe_version >= 0x0300 && !par->nocrtc && + info->var.pixclock != 0) { + task->t.regs.ebx |= 0x0800; /* use CRTC data */ + task->t.flags = TF_BUF_ESDI; + crtc = kzalloc(sizeof(struct vbe_crtc_ib), GFP_KERNEL); + if (!crtc) { + err = -ENOMEM; + goto out; + } + crtc->horiz_start = info->var.xres + info->var.right_margin; + crtc->horiz_end = crtc->horiz_start + info->var.hsync_len; + crtc->horiz_total = crtc->horiz_end + info->var.left_margin; + + crtc->vert_start = info->var.yres + info->var.lower_margin; + crtc->vert_end = crtc->vert_start + info->var.vsync_len; + crtc->vert_total = crtc->vert_end + info->var.upper_margin; + + crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000; + crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock / + (crtc->vert_total * crtc->horiz_total))); + + if (info->var.vmode & FB_VMODE_DOUBLE) + crtc->flags |= 0x1; + if (info->var.vmode & FB_VMODE_INTERLACED) + crtc->flags |= 0x2; + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + crtc->flags |= 0x4; + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + crtc->flags |= 0x8; + memcpy(&par->crtc, crtc, sizeof(*crtc)); + } else { + memset(&par->crtc, 0, sizeof(*crtc)); + } + + task->t.buf_len = sizeof(struct vbe_crtc_ib); + task->buf = &par->crtc; + + err = uvesafb_exec(task); + if (err || (task->t.regs.eax & 0xffff) != 0x004f) { + /* + * The mode switch might have failed because we tried to + * use our own timings. Try again with the default timings. + */ + if (crtc != NULL) { + printk(KERN_WARNING "uvesafb: mode switch failed " + "(eax=0x%x, err=%d). Trying again with " + "default timings.\n", task->t.regs.eax, err); + uvesafb_reset(task); + kfree(crtc); + crtc = NULL; + info->var.pixclock = 0; + goto setmode; + } else { + printk(KERN_ERR "uvesafb: mode switch failed (eax=" + "0x%x, err=%d)\n", task->t.regs.eax, err); + err = -EINVAL; + goto out; + } + } + par->mode_idx = i; + + /* For 8bpp modes, always try to set the DAC to 8 bits. */ + if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC && + mode->bits_per_pixel <= 8) { + uvesafb_reset(task); + task->t.regs.eax = 0x4f08; + task->t.regs.ebx = 0x0800; + + err = uvesafb_exec(task); + if (err || (task->t.regs.eax & 0xffff) != 0x004f || + ((task->t.regs.ebx & 0xff00) >> 8) != 8) { + /* + * We've failed to set the DAC palette format - + * time to correct var. + */ + info->var.red.length = 6; + info->var.green.length = 6; + info->var.blue.length = 6; + } + } + + info->fix.visual = (info->var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + info->fix.line_length = mode->bytes_per_scan_line; + +out: if (crtc != NULL) + kfree(crtc); + uvesafb_free(task); + + return err; +} + +static void uvesafb_check_limits(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + const struct fb_videomode *mode; + struct uvesafb_par *par = info->par; + + /* + * If pixclock is set to 0, then we're using default BIOS timings + * and thus don't have to perform any checks here. + */ + if (!var->pixclock) + return; + + if (par->vbe_ib.vbe_version < 0x0300) { + fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, var, info); + return; + } + + if (!fb_validate_mode(var, info)) + return; + + mode = fb_find_best_mode(var, &info->modelist); + if (mode) { + if (mode->xres == var->xres && mode->yres == var->yres && + !(mode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))) { + fb_videomode_to_var(var, mode); + return; + } + } + + if (info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info)) + return; + /* Use default refresh rate */ + var->pixclock = 0; +} + +static int uvesafb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct uvesafb_par *par = info->par; + struct vbe_mode_ib *mode = NULL; + int match = -1; + int depth = var->red.length + var->green.length + var->blue.length; + + /* + * Various apps will use bits_per_pixel to set the color depth, + * which is theoretically incorrect, but which we'll try to handle + * here. + */ + if (depth == 0 || abs(depth - var->bits_per_pixel) >= 8) + depth = var->bits_per_pixel; + + match = uvesafb_vbe_find_mode(par, var->xres, var->yres, depth, + UVESAFB_EXACT_RES); + if (match == -1) + return -EINVAL; + + mode = &par->vbe_modes[match]; + uvesafb_setup_var(var, info, mode); + + /* + * Check whether we have remapped enough memory for this mode. + * We might be called at an early stage, when we haven't remapped + * any memory yet, in which case we simply skip the check. + */ + if (var->yres * mode->bytes_per_scan_line > info->fix.smem_len + && info->fix.smem_len) + return -EINVAL; + + if ((var->vmode & FB_VMODE_DOUBLE) && + !(par->vbe_modes[match].mode_attr & 0x100)) + var->vmode &= ~FB_VMODE_DOUBLE; + + if ((var->vmode & FB_VMODE_INTERLACED) && + !(par->vbe_modes[match].mode_attr & 0x200)) + var->vmode &= ~FB_VMODE_INTERLACED; + + uvesafb_check_limits(var, info); + + var->xres_virtual = var->xres; + var->yres_virtual = (par->ypan) ? + info->fix.smem_len / mode->bytes_per_scan_line : + var->yres; + return 0; +} + +static void uvesafb_save_state(struct fb_info *info) +{ + struct uvesafb_par *par = info->par; + + if (par->vbe_state_saved) + kfree(par->vbe_state_saved); + + par->vbe_state_saved = uvesafb_vbe_state_save(par); +} + +static void uvesafb_restore_state(struct fb_info *info) +{ + struct uvesafb_par *par = info->par; + + uvesafb_vbe_state_restore(par, par->vbe_state_saved); +} + +static struct fb_ops uvesafb_ops = { + .owner = THIS_MODULE, + .fb_open = uvesafb_open, + .fb_release = uvesafb_release, + .fb_setcolreg = uvesafb_setcolreg, + .fb_setcmap = uvesafb_setcmap, + .fb_pan_display = uvesafb_pan_display, + .fb_blank = uvesafb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_check_var = uvesafb_check_var, + .fb_set_par = uvesafb_set_par, + .fb_save_state = uvesafb_save_state, + .fb_restore_state = uvesafb_restore_state, +}; + +static void __devinit uvesafb_init_info(struct fb_info *info, + struct vbe_mode_ib *mode) +{ + unsigned int size_vmode; + unsigned int size_remap; + unsigned int size_total; + struct uvesafb_par *par = info->par; + int i, h; + + info->pseudo_palette = ((u8 *)info->par + sizeof(struct uvesafb_par)); + info->fix = uvesafb_fix; + info->fix.ypanstep = par->ypan ? 1 : 0; + info->fix.ywrapstep = (par->ypan > 1) ? 1 : 0; + + /* + * If we were unable to get the state buffer size, disable + * functions for saving and restoring the hardware state. + */ + if (par->vbe_state_size == 0) { + info->fbops->fb_save_state = NULL; + info->fbops->fb_restore_state = NULL; + } + + /* Disable blanking if the user requested so. */ + if (!blank) + info->fbops->fb_blank = NULL; + + /* + * Find out how much IO memory is required for the mode with + * the highest resolution. + */ + size_remap = 0; + for (i = 0; i < par->vbe_modes_cnt; i++) { + h = par->vbe_modes[i].bytes_per_scan_line * + par->vbe_modes[i].y_res; + if (h > size_remap) + size_remap = h; + } + size_remap *= 2; + + /* + * size_vmode -- that is the amount of memory needed for the + * used video mode, i.e. the minimum amount of + * memory we need. + */ + if (mode != NULL) { + size_vmode = info->var.yres * mode->bytes_per_scan_line; + } else { + size_vmode = info->var.yres * info->var.xres * + ((info->var.bits_per_pixel + 7) >> 3); + } + + /* + * size_total -- all video memory we have. Used for mtrr + * entries, resource allocation and bounds + * checking. + */ + size_total = par->vbe_ib.total_memory * 65536; + if (vram_total) + size_total = vram_total * 1024 * 1024; + if (size_total < size_vmode) + size_total = size_vmode; + + /* + * size_remap -- the amount of video memory we are going to + * use for vesafb. With modern cards it is no + * option to simply use size_total as th + * wastes plenty of kernel address space. + */ + if (vram_remap) + size_remap = vram_remap * 1024 * 1024; + if (size_remap < size_vmode) + size_remap = size_vmode; + if (size_remap > size_total) + size_remap = size_total; + + info->fix.smem_len = size_remap; + info->fix.smem_start = mode->phys_base_ptr; + + /* + * We have to set yres_virtual here because when setup_var() was + * called, smem_len wasn't defined yet. + */ + info->var.yres_virtual = info->fix.smem_len / + mode->bytes_per_scan_line; + + if (par->ypan && info->var.yres_virtual > info->var.yres) { + printk(KERN_INFO "uvesafb: scrolling: %s " + "using protected mode interface, " + "yres_virtual=%d\n", + (par->ypan > 1) ? "ywrap" : "ypan", + info->var.yres_virtual); + } else { + printk(KERN_INFO "uvesafb: scrolling: redraw\n"); + info->var.yres_virtual = info->var.yres; + par->ypan = 0; + } + + info->flags = FBINFO_FLAG_DEFAULT | + (par->ypan) ? FBINFO_HWACCEL_YPAN : 0; + + if (!par->ypan) + info->fbops->fb_pan_display = NULL; +} + +static void uvesafb_init_mtrr(struct fb_info *info) +{ +#ifdef CONFIG_MTRR + if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) { + int temp_size = info->fix.smem_len; + unsigned int type = 0; + + switch (mtrr) { + case 1: + type = MTRR_TYPE_UNCACHABLE; + break; + case 2: + type = MTRR_TYPE_WRBACK; + break; + case 3: + type = MTRR_TYPE_WRCOMB; + break; + case 4: + type = MTRR_TYPE_WRTHROUGH; + break; + default: + type = 0; + break; + } + + if (type) { + int rc; + + /* Find the largest power-of-two */ + while (temp_size & (temp_size - 1)) + temp_size &= (temp_size - 1); + + /* Try and find a power of two to add */ + do { + rc = mtrr_add(info->fix.smem_start, + temp_size, type, 1); + temp_size >>= 1; + } while (temp_size >= PAGE_SIZE && rc == -EINVAL); + } + } +#endif /* CONFIG_MTRR */ +} + + +static ssize_t uvesafb_show_vbe_ver(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + + return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version); +} + +static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL); + +static ssize_t uvesafb_show_vbe_modes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + int ret = 0, i; + + for (i = 0; i < par->vbe_modes_cnt && ret < PAGE_SIZE; i++) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "%dx%d-%d, 0x%.4x\n", + par->vbe_modes[i].x_res, par->vbe_modes[i].y_res, + par->vbe_modes[i].depth, par->vbe_modes[i].mode_id); + } + + return ret; +} + +static DEVICE_ATTR(vbe_modes, S_IRUGO, uvesafb_show_vbe_modes, NULL); + +static ssize_t uvesafb_show_vendor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + + if (par->vbe_ib.oem_vendor_name_ptr) + return snprintf(buf, PAGE_SIZE, "%s\n", (char *) + (&par->vbe_ib) + par->vbe_ib.oem_vendor_name_ptr); + else + return 0; +} + +static DEVICE_ATTR(oem_vendor, S_IRUGO, uvesafb_show_vendor, NULL); + +static ssize_t uvesafb_show_product_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + + if (par->vbe_ib.oem_product_name_ptr) + return snprintf(buf, PAGE_SIZE, "%s\n", (char *) + (&par->vbe_ib) + par->vbe_ib.oem_product_name_ptr); + else + return 0; +} + +static DEVICE_ATTR(oem_product_name, S_IRUGO, uvesafb_show_product_name, NULL); + +static ssize_t uvesafb_show_product_rev(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + + if (par->vbe_ib.oem_product_rev_ptr) + return snprintf(buf, PAGE_SIZE, "%s\n", (char *) + (&par->vbe_ib) + par->vbe_ib.oem_product_rev_ptr); + else + return 0; +} + +static DEVICE_ATTR(oem_product_rev, S_IRUGO, uvesafb_show_product_rev, NULL); + +static ssize_t uvesafb_show_oem_string(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + + if (par->vbe_ib.oem_string_ptr) + return snprintf(buf, PAGE_SIZE, "%s\n", + (char *)(&par->vbe_ib) + par->vbe_ib.oem_string_ptr); + else + return 0; +} + +static DEVICE_ATTR(oem_string, S_IRUGO, uvesafb_show_oem_string, NULL); + +static ssize_t uvesafb_show_nocrtc(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + + return snprintf(buf, PAGE_SIZE, "%d\n", par->nocrtc); +} + +static ssize_t uvesafb_store_nocrtc(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); + struct uvesafb_par *par = info->par; + + if (count > 0) { + if (buf[0] == '0') + par->nocrtc = 0; + else + par->nocrtc = 1; + } + return count; +} + +static DEVICE_ATTR(nocrtc, S_IRUGO | S_IWUSR, uvesafb_show_nocrtc, + uvesafb_store_nocrtc); + +static struct attribute *uvesafb_dev_attrs[] = { + &dev_attr_vbe_version.attr, + &dev_attr_vbe_modes.attr, + &dev_attr_oem_vendor.attr, + &dev_attr_oem_product_name.attr, + &dev_attr_oem_product_rev.attr, + &dev_attr_oem_string.attr, + &dev_attr_nocrtc.attr, + NULL, +}; + +static struct attribute_group uvesafb_dev_attgrp = { + .name = NULL, + .attrs = uvesafb_dev_attrs, +}; + +static int __devinit uvesafb_probe(struct platform_device *dev) +{ + struct fb_info *info; + struct vbe_mode_ib *mode = NULL; + struct uvesafb_par *par; + int err = 0, i; + + info = framebuffer_alloc(sizeof(*par) + sizeof(u32) * 256, &dev->dev); + if (!info) + return -ENOMEM; + + par = info->par; + + err = uvesafb_vbe_init(info); + if (err) { + printk(KERN_ERR "uvesafb: vbe_init() failed with %d\n", err); + goto out; + } + + info->fbops = &uvesafb_ops; + + i = uvesafb_vbe_init_mode(info); + if (i < 0) { + err = -EINVAL; + goto out; + } else { + mode = &par->vbe_modes[i]; + } + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + err = -ENXIO; + goto out; + } + + uvesafb_init_info(info, mode); + + if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, + "uvesafb")) { + printk(KERN_ERR "uvesafb: cannot reserve video memory at " + "0x%lx\n", info->fix.smem_start); + err = -EIO; + goto out_mode; + } + + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + + if (!info->screen_base) { + printk(KERN_ERR + "uvesafb: abort, cannot ioremap 0x%x bytes of video " + "memory at 0x%lx\n", + info->fix.smem_len, info->fix.smem_start); + err = -EIO; + goto out_mem; + } + + if (!request_region(0x3c0, 32, "uvesafb")) { + printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n"); + err = -EIO; + goto out_unmap; + } + + uvesafb_init_mtrr(info); + platform_set_drvdata(dev, info); + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR + "uvesafb: failed to register framebuffer device\n"); + err = -EINVAL; + goto out_reg; + } + + printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, " + "using %dk, total %dk\n", info->fix.smem_start, + info->screen_base, info->fix.smem_len/1024, + par->vbe_ib.total_memory * 64); + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + + err = sysfs_create_group(&dev->dev.kobj, &uvesafb_dev_attgrp); + if (err != 0) + printk(KERN_WARNING "fb%d: failed to register attributes\n", + info->node); + + return 0; + +out_reg: + release_region(0x3c0, 32); +out_unmap: + iounmap(info->screen_base); +out_mem: + release_mem_region(info->fix.smem_start, info->fix.smem_len); +out_mode: + if (!list_empty(&info->modelist)) + fb_destroy_modelist(&info->modelist); + fb_destroy_modedb(info->monspecs.modedb); + fb_dealloc_cmap(&info->cmap); +out: + if (par->vbe_modes) + kfree(par->vbe_modes); + + framebuffer_release(info); + return err; +} + +static int uvesafb_remove(struct platform_device *dev) +{ + struct fb_info *info = platform_get_drvdata(dev); + + if (info) { + struct uvesafb_par *par = info->par; + + sysfs_remove_group(&dev->dev.kobj, &uvesafb_dev_attgrp); + unregister_framebuffer(info); + release_region(0x3c0, 32); + iounmap(info->screen_base); + release_mem_region(info->fix.smem_start, info->fix.smem_len); + fb_destroy_modedb(info->monspecs.modedb); + fb_dealloc_cmap(&info->cmap); + + if (par) { + if (par->vbe_modes) + kfree(par->vbe_modes); + if (par->vbe_state_orig) + kfree(par->vbe_state_orig); + if (par->vbe_state_saved) + kfree(par->vbe_state_saved); + } + + framebuffer_release(info); + } + return 0; +} + +static struct platform_driver uvesafb_driver = { + .probe = uvesafb_probe, + .remove = uvesafb_remove, + .driver = { + .name = "uvesafb", + }, +}; + +static struct platform_device *uvesafb_device; + +#ifndef MODULE +static int __devinit uvesafb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + + if (!strcmp(this_opt, "redraw")) + ypan = 0; + else if (!strcmp(this_opt, "ypan")) + ypan = 1; + else if (!strcmp(this_opt, "ywrap")) + ypan = 2; + else if (!strcmp(this_opt, "vgapal")) + pmi_setpal = 0; + else if (!strcmp(this_opt, "pmipal")) + pmi_setpal = 1; + else if (!strncmp(this_opt, "mtrr:", 5)) + mtrr = simple_strtoul(this_opt+5, NULL, 0); + else if (!strcmp(this_opt, "nomtrr")) + mtrr = 0; + else if (!strcmp(this_opt, "nocrtc")) + nocrtc = 1; + else if (!strcmp(this_opt, "noedid")) + noedid = 1; + else if (!strcmp(this_opt, "noblank")) + blank = 0; + else if (!strncmp(this_opt, "vtotal:", 7)) + vram_total = simple_strtoul(this_opt + 7, NULL, 0); + else if (!strncmp(this_opt, "vremap:", 7)) + vram_remap = simple_strtoul(this_opt + 7, NULL, 0); + else if (!strncmp(this_opt, "maxhf:", 6)) + maxhf = simple_strtoul(this_opt + 6, NULL, 0); + else if (!strncmp(this_opt, "maxvf:", 6)) + maxvf = simple_strtoul(this_opt + 6, NULL, 0); + else if (!strncmp(this_opt, "maxclk:", 7)) + maxclk = simple_strtoul(this_opt + 7, NULL, 0); + else if (!strncmp(this_opt, "vbemode:", 8)) + vbemode = simple_strtoul(this_opt + 8, NULL, 0); + else if (this_opt[0] >= '0' && this_opt[0] <= '9') { + mode_option = this_opt; + } else { + printk(KERN_WARNING + "uvesafb: unrecognized option %s\n", this_opt); + } + } + + return 0; +} +#endif /* !MODULE */ + +static ssize_t show_v86d(struct device_driver *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", v86d_path); +} + +static ssize_t store_v86d(struct device_driver *dev, const char *buf, + size_t count) +{ + strncpy(v86d_path, buf, PATH_MAX); + return count; +} + +static DRIVER_ATTR(v86d, S_IRUGO | S_IWUSR, show_v86d, store_v86d); + +static int __devinit uvesafb_init(void) +{ + int err; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("uvesafb", &option)) + return -ENODEV; + uvesafb_setup(option); +#endif + err = cn_add_callback(&uvesafb_cn_id, "uvesafb", uvesafb_cn_callback); + if (err) + return err; + + err = platform_driver_register(&uvesafb_driver); + + if (!err) { + uvesafb_device = platform_device_alloc("uvesafb", 0); + if (uvesafb_device) + err = platform_device_add(uvesafb_device); + else + err = -ENOMEM; + + if (err) { + platform_device_put(uvesafb_device); + platform_driver_unregister(&uvesafb_driver); + cn_del_callback(&uvesafb_cn_id); + return err; + } + + err = driver_create_file(&uvesafb_driver.driver, + &driver_attr_v86d); + if (err) { + printk(KERN_WARNING "uvesafb: failed to register " + "attributes\n"); + err = 0; + } + } + return err; +} + +module_init(uvesafb_init); + +static void __devexit uvesafb_exit(void) +{ + struct uvesafb_ktask *task; + + if (v86d_started) { + task = uvesafb_prep(); + if (task) { + task->t.flags = TF_EXIT; + uvesafb_exec(task); + uvesafb_free(task); + } + } + + cn_del_callback(&uvesafb_cn_id); + driver_remove_file(&uvesafb_driver.driver, &driver_attr_v86d); + platform_device_unregister(uvesafb_device); + platform_driver_unregister(&uvesafb_driver); +} + +module_exit(uvesafb_exit); + +static inline int param_get_scroll(char *buffer, struct kernel_param *kp) +{ + return 0; +} + +static inline int param_set_scroll(const char *val, struct kernel_param *kp) +{ + ypan = 0; + + if (!strcmp(val, "redraw")) + ypan = 0; + else if (!strcmp(val, "ypan")) + ypan = 1; + else if (!strcmp(val, "ywrap")) + ypan = 2; + + return 0; +} + +#define param_check_scroll(name, p) __param_check(name, p, void); + +module_param_named(scroll, ypan, scroll, 0); +MODULE_PARM_DESC(scroll, + "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'"); +module_param_named(vgapal, pmi_setpal, invbool, 0); +MODULE_PARM_DESC(vgapal, "Set palette using VGA registers"); +module_param_named(pmipal, pmi_setpal, bool, 0); +MODULE_PARM_DESC(pmipal, "Set palette using PMI calls"); +module_param(mtrr, uint, 0); +MODULE_PARM_DESC(mtrr, + "Memory Type Range Registers setting. Use 0 to disable."); +module_param(blank, bool, 0); +MODULE_PARM_DESC(blank, "Enable hardware blanking"); +module_param(nocrtc, bool, 0); +MODULE_PARM_DESC(nocrtc, "Ignore CRTC timings when setting modes"); +module_param(noedid, bool, 0); +MODULE_PARM_DESC(noedid, + "Ignore EDID-provided monitor limits when setting modes"); +module_param(vram_remap, uint, 0); +MODULE_PARM_DESC(vram_remap, "Set amount of video memory to be used [MiB]"); +module_param(vram_total, uint, 0); +MODULE_PARM_DESC(vram_total, "Set total amount of video memoery [MiB]"); +module_param(maxclk, ushort, 0); +MODULE_PARM_DESC(maxclk, "Maximum pixelclock [MHz], overrides EDID data"); +module_param(maxhf, ushort, 0); +MODULE_PARM_DESC(maxhf, + "Maximum horizontal frequency [kHz], overrides EDID data"); +module_param(maxvf, ushort, 0); +MODULE_PARM_DESC(maxvf, + "Maximum vertical frequency [Hz], overrides EDID data"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, + "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\""); +module_param(vbemode, ushort, 0); +MODULE_PARM_DESC(vbemode, + "VBE mode number to set, overrides the 'mode' option"); +module_param_string(v86d, v86d_path, PATH_MAX, 0660); +MODULE_PARM_DESC(v86d, "Path to the v86d userspace helper."); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Januszewski <spock@gentoo.org>"); +MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphics boards"); + diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index de531c90771..ff9e805c43b 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -39,7 +39,6 @@ #include <asm/cacheflush.h> #include <asm/tlbflush.h> #include <linux/mmzone.h> -#include <asm/uaccess.h> /* #define VERMILION_DEBUG */ diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 64ee78c3c12..072638a9528 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -21,7 +21,6 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> -#include <asm/uaccess.h> #include <linux/fb.h> #include <linux/init.h> @@ -38,6 +37,48 @@ static void *videomemory; static u_long videomemorysize = VIDEOMEMSIZE; module_param(videomemorysize, ulong, 0); +/********************************************************************** + * + * Memory management + * + **********************************************************************/ +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + static struct fb_var_screeninfo vfb_default __initdata = { .xres = 640, .yres = 480, @@ -372,7 +413,33 @@ static int vfb_pan_display(struct fb_var_screeninfo *var, static int vfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - return -EINVAL; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long page, pos; + + if (offset + size > info->fix.smem_len) { + return -EINVAL; + } + + pos = (unsigned long)info->fix.smem_start + offset; + + while (size > 0) { + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + return 0; + } #ifndef MODULE @@ -407,7 +474,7 @@ static int __init vfb_probe(struct platform_device *dev) /* * For real video cards we use ioremap. */ - if (!(videomemory = vmalloc(videomemorysize))) + if (!(videomemory = rvmalloc(videomemorysize))) return retval; /* @@ -430,6 +497,8 @@ static int __init vfb_probe(struct platform_device *dev) if (!retval || (retval == 4)) info->var = vfb_default; + vfb_fix.smem_start = (unsigned long) videomemory; + vfb_fix.smem_len = videomemorysize; info->fix = vfb_fix; info->pseudo_palette = info->par; info->par = NULL; @@ -453,7 +522,7 @@ err2: err1: framebuffer_release(info); err: - vfree(videomemory); + rvfree(videomemory, videomemorysize); return retval; } @@ -463,7 +532,7 @@ static int vfb_remove(struct platform_device *dev) if (info) { unregister_framebuffer(info); - vfree(videomemory); + rvfree(videomemory, videomemorysize); framebuffer_release(info); } return 0; |