diff options
462 files changed, 24350 insertions, 36047 deletions
diff --git a/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt b/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt new file mode 100644 index 00000000000..5aeee53ff9f --- /dev/null +++ b/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt @@ -0,0 +1,9 @@ +NVIDIA compliant embedded controller + +Required properties: +- compatible : should be "nvidia,nvec". +- reg : the iomem of the i2c slave controller +- interrupts : the interrupt line of the i2c slave controller +- clock-frequency : the frequency of the i2c bus +- gpios : the gpio used for ec request +- slave-addr: the i2c address of the slave controller diff --git a/MAINTAINERS b/MAINTAINERS index 1e7d9044265..78b078e8e0a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -184,11 +184,6 @@ S: Maintained F: Documentation/filesystems/9p.txt F: fs/9p/ -A2232 SERIAL BOARD DRIVER -L: linux-m68k@lists.linux-m68k.org -S: Orphan -F: drivers/staging/generic_serial/ser_a2232* - AACRAID SCSI RAID DRIVER M: Adaptec OEM Raid Solutions <aacraid@adaptec.com> L: linux-scsi@vger.kernel.org @@ -1587,7 +1582,7 @@ M: Franky (Zhenhui) Lin <frankyl@broadcom.com> M: Kan Yan <kanyan@broadcom.com> L: linux-wireless@vger.kernel.org S: Supported -F: drivers/staging/brcm80211/ +F: drivers/net/wireless/brcm80211/ BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER M: Bhanu Prakash Gollapudi <bprakash@broadcom.com> @@ -1891,12 +1886,6 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/compal-laptop.c -COMPUTONE INTELLIPORT MULTIPORT CARD -W: http://www.wittsend.com/computone.html -S: Orphan -F: Documentation/serial/computone.txt -F: drivers/staging/tty/ip2/ - CONEXANT ACCESSRUNNER USB DRIVER M: Simon Arlott <cxacru@fire.lp0.eu> L: accessrunner-general@lists.sourceforge.net @@ -2200,15 +2189,6 @@ F: drivers/md/dm* F: include/linux/device-mapper.h F: include/linux/dm-*.h -DIGI INTL. EPCA DRIVER -M: "Digi International, Inc" <Eng.Linux@digi.com> -L: Eng.Linux@digi.com -W: http://www.digi.com -S: Orphan -F: Documentation/serial/digiepca.txt -F: drivers/staging/tty/epca* -F: drivers/staging/tty/digi* - DIOLAN U2C-12 I2C DRIVER M: Guenter Roeck <guenter.roeck@ericsson.com> L: linux-i2c@vger.kernel.org @@ -5555,11 +5535,6 @@ M: Maxim Levitsky <maximlevitsky@gmail.com> S: Maintained F: drivers/memstick/host/r592.* -RISCOM8 DRIVER -S: Orphan -F: Documentation/serial/riscom8.txt -F: drivers/staging/tty/riscom8* - ROCKETPORT DRIVER P: Comtrol Corp. W: http://www.comtrol.com @@ -6222,11 +6197,6 @@ F: arch/arm/mach-spear3xx/spear3*0_evb.c F: arch/arm/mach-spear6xx/spear600.c F: arch/arm/mach-spear6xx/spear600_evb.c -SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER -S: Orphan -F: Documentation/serial/specialix.txt -F: drivers/staging/tty/specialix* - SPI SUBSYSTEM M: Grant Likely <grant.likely@secretlab.ca> L: spi-devel-general@lists.sourceforge.net @@ -6304,11 +6274,6 @@ M: Manu Abraham <abraham.manu@gmail.com> S: Odd Fixes F: drivers/staging/crystalhd/ -STAGING - CYPRESS WESTBRIDGE SUPPORT -M: David Cross <david.cross@cypress.com> -S: Odd Fixes -F: drivers/staging/westbridge/ - STAGING - ECHO CANCELLER M: Steve Underwood <steveu@coppice.org> M: David Rowe <david@rowetel.com> @@ -6414,7 +6379,7 @@ S: Odd Fixes F: drivers/staging/winbond/ STAGING - XGI Z7,Z9,Z11 PCI DISPLAY DRIVER -M: Arnaud Patard <apatard@mandriva.com> +M: Arnaud Patard <arnaud.patard@rtp-net.org> S: Odd Fixes F: drivers/staging/xgifb/ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9845afb37cc..b98285446a5 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -342,4 +342,6 @@ config VMXNET3 To compile this driver as a module, choose M here: the module will be called vmxnet3. +source "drivers/net/hyperv/Kconfig" + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1988881853a..a6b8ce11a22 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -68,3 +68,5 @@ obj-$(CONFIG_USB_USBNET) += usb/ obj-$(CONFIG_USB_ZD1201) += usb/ obj-$(CONFIG_USB_IPHETH) += usb/ obj-$(CONFIG_USB_CDC_PHONET) += usb/ + +obj-$(CONFIG_HYPERV_NET) += hyperv/ diff --git a/drivers/net/hyperv/Kconfig b/drivers/net/hyperv/Kconfig new file mode 100644 index 00000000000..936968d2355 --- /dev/null +++ b/drivers/net/hyperv/Kconfig @@ -0,0 +1,5 @@ +config HYPERV_NET + tristate "Microsoft Hyper-V virtual network driver" + depends on HYPERV + help + Select this option to enable the Hyper-V virtual network driver. diff --git a/drivers/net/hyperv/Makefile b/drivers/net/hyperv/Makefile new file mode 100644 index 00000000000..c8a66827100 --- /dev/null +++ b/drivers/net/hyperv/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o + +hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o diff --git a/drivers/staging/hv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index ac1ec840512..dec5836ae07 100644 --- a/drivers/staging/hv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -39,9 +39,6 @@ struct xferpage_packet { u32 count; }; -/* The number of pages which are enough to cover jumbo frame buffer. */ -#define NETVSC_PACKET_MAXPAGE 4 - /* * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame * within the RNDIS @@ -77,8 +74,9 @@ struct hv_netvsc_packet { u32 total_data_buflen; /* Points to the send/receive buffer where the ethernet frame is */ + void *data; u32 page_buf_cnt; - struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE]; + struct hv_page_buffer page_buf[0]; }; struct netvsc_device_info { @@ -87,6 +85,27 @@ struct netvsc_device_info { int ring_size; }; +enum rndis_device_state { + RNDIS_DEV_UNINITIALIZED = 0, + RNDIS_DEV_INITIALIZING, + RNDIS_DEV_INITIALIZED, + RNDIS_DEV_DATAINITIALIZED, +}; + +struct rndis_device { + struct netvsc_device *net_dev; + + enum rndis_device_state state; + bool link_state; + atomic_t new_req_id; + + spinlock_t request_lock; + struct list_head req_list; + + unsigned char hw_mac_adr[ETH_ALEN]; +}; + + /* Interface */ int netvsc_device_add(struct hv_device *device, void *additional_info); int netvsc_device_remove(struct hv_device *device); @@ -109,11 +128,13 @@ int rndis_filter_receive(struct hv_device *dev, int rndis_filter_send(struct hv_device *dev, struct hv_netvsc_packet *pkt); +int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); + + #define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF) #define NVSP_PROTOCOL_VERSION_1 2 -#define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 -#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 +#define NVSP_PROTOCOL_VERSION_2 0x30002 enum { NVSP_MSG_TYPE_NONE = 0, @@ -138,11 +159,36 @@ enum { NVSP_MSG1_TYPE_SEND_RNDIS_PKT, NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE, - /* - * This should be set to the number of messages for the version with - * the maximum number of messages. - */ - NVSP_NUM_MSG_PER_VERSION = 9, + /* Version 2 messages */ + NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF, + NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF_COMP, + NVSP_MSG2_TYPE_REVOKE_CHIMNEY_DELEGATED_BUF, + + NVSP_MSG2_TYPE_RESUME_CHIMNEY_RX_INDICATION, + + NVSP_MSG2_TYPE_TERMINATE_CHIMNEY, + NVSP_MSG2_TYPE_TERMINATE_CHIMNEY_COMP, + + NVSP_MSG2_TYPE_INDICATE_CHIMNEY_EVENT, + + NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT, + NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT_COMP, + + NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ, + NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ_COMP, + + NVSP_MSG2_TYPE_ALLOC_RXBUF, + NVSP_MSG2_TYPE_ALLOC_RXBUF_COMP, + + NVSP_MSG2_TYPE_FREE_RXBUF, + + NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT, + NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT_COMP, + + NVSP_MSG2_TYPE_SEND_NDIS_CONFIG, + + NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE, + NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, }; enum { @@ -153,6 +199,7 @@ enum { NVSP_STAT_PROTOCOL_TOO_OLD, NVSP_STAT_INVALID_RNDIS_PKT, NVSP_STAT_BUSY, + NVSP_STAT_PROTOCOL_UNSUPPORTED, NVSP_STAT_MAX, }; @@ -337,9 +384,69 @@ union nvsp_1_message_uber { send_rndis_pkt_complete; } __packed; + +/* + * Network VSP protocol version 2 messages: + */ +struct nvsp_2_vsc_capability { + union { + u64 data; + struct { + u64 vmq:1; + u64 chimney:1; + u64 sriov:1; + u64 ieee8021q:1; + u64 correlation_id:1; + }; + }; +} __packed; + +struct nvsp_2_send_ndis_config { + u32 mtu; + u32 reserved; + struct nvsp_2_vsc_capability capability; +} __packed; + +/* Allocate receive buffer */ +struct nvsp_2_alloc_rxbuf { + /* Allocation ID to match the allocation request and response */ + u32 alloc_id; + + /* Length of the VM shared memory receive buffer that needs to + * be allocated + */ + u32 len; +} __packed; + +/* Allocate receive buffer complete */ +struct nvsp_2_alloc_rxbuf_comp { + /* The NDIS_STATUS code for buffer allocation */ + u32 status; + + u32 alloc_id; + + /* GPADL handle for the allocated receive buffer */ + u32 gpadl_handle; + + /* Receive buffer ID */ + u64 recv_buf_id; +} __packed; + +struct nvsp_2_free_rxbuf { + u64 recv_buf_id; +} __packed; + +union nvsp_2_message_uber { + struct nvsp_2_send_ndis_config send_ndis_config; + struct nvsp_2_alloc_rxbuf alloc_rxbuf; + struct nvsp_2_alloc_rxbuf_comp alloc_rxbuf_comp; + struct nvsp_2_free_rxbuf free_rxbuf; +} __packed; + union nvsp_all_messages { union nvsp_message_init_uber init_msg; union nvsp_1_message_uber v1_msg; + union nvsp_2_message_uber v2_msg; } __packed; /* ALL Messages */ @@ -349,12 +456,9 @@ struct nvsp_message { } __packed; +#define NETVSC_MTU 65536 - -/* #define NVSC_MIN_PROTOCOL_VERSION 1 */ -/* #define NVSC_MAX_PROTOCOL_VERSION 1 */ - -#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */ +#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*2) /* 2MB */ #define NETVSC_RECEIVE_BUFFER_ID 0xcafe @@ -369,7 +473,10 @@ struct nvsp_message { struct netvsc_device { struct hv_device *dev; + u32 nvsp_version; + atomic_t num_outstanding_sends; + bool start_remove; bool destroy; /* * List of free preallocated hv_netvsc_packet to represent receive diff --git a/drivers/staging/hv/netvsc.c b/drivers/net/hyperv/netvsc.c index b902579c7fe..8965b45ce5a 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -28,6 +28,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/netdevice.h> +#include <linux/if_ether.h> #include "hyperv_net.h" @@ -41,7 +42,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device) if (!net_device) return NULL; - + net_device->start_remove = false; net_device->destroy = false; net_device->dev = device; net_device->ndev = ndev; @@ -230,19 +231,16 @@ static int netvsc_init_recv_buf(struct hv_device *device) net_device->recv_section_cnt = init_packet->msg. v1_msg.send_recv_buf_complete.num_sections; - net_device->recv_section = kmalloc(net_device->recv_section_cnt - * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL); + net_device->recv_section = kmemdup( + init_packet->msg.v1_msg.send_recv_buf_complete.sections, + net_device->recv_section_cnt * + sizeof(struct nvsp_1_receive_buffer_section), + GFP_KERNEL); if (net_device->recv_section == NULL) { ret = -EINVAL; goto cleanup; } - memcpy(net_device->recv_section, - init_packet->msg.v1_msg. - send_recv_buf_complete.sections, - net_device->recv_section_cnt * - sizeof(struct nvsp_1_receive_buffer_section)); - /* * For 1st release, there should only be 1 section that represents the * entire receive buffer @@ -263,27 +261,18 @@ exit: } -static int netvsc_connect_vsp(struct hv_device *device) +/* Negotiate NVSP protocol version */ +static int negotiate_nvsp_ver(struct hv_device *device, + struct netvsc_device *net_device, + struct nvsp_message *init_packet, + u32 nvsp_ver) { int ret, t; - struct netvsc_device *net_device; - struct nvsp_message *init_packet; - int ndis_version; - struct net_device *ndev; - - net_device = get_outbound_net_device(device); - if (!net_device) - return -ENODEV; - ndev = net_device->ndev; - - init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; - init_packet->msg.init_msg.init.min_protocol_ver = - NVSP_MIN_PROTOCOL_VERSION; - init_packet->msg.init_msg.init.max_protocol_ver = - NVSP_MAX_PROTOCOL_VERSION; + init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver; + init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver; /* Send the init request */ ret = vmbus_sendpacket(device->channel, init_packet, @@ -293,26 +282,62 @@ static int netvsc_connect_vsp(struct hv_device *device) VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) - goto cleanup; + return ret; t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } + if (t == 0) + return -ETIMEDOUT; if (init_packet->msg.init_msg.init_complete.status != - NVSP_STAT_SUCCESS) { - ret = -EINVAL; - goto cleanup; - } + NVSP_STAT_SUCCESS) + return -EINVAL; - if (init_packet->msg.init_msg.init_complete. - negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) { + if (nvsp_ver != NVSP_PROTOCOL_VERSION_2) + return 0; + + /* NVSPv2 only: Send NDIS config */ + memset(init_packet, 0, sizeof(struct nvsp_message)); + init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG; + init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu; + + ret = vmbus_sendpacket(device->channel, init_packet, + sizeof(struct nvsp_message), + (unsigned long)init_packet, + VM_PKT_DATA_INBAND, 0); + + return ret; +} + +static int netvsc_connect_vsp(struct hv_device *device) +{ + int ret; + struct netvsc_device *net_device; + struct nvsp_message *init_packet; + int ndis_version; + struct net_device *ndev; + + net_device = get_outbound_net_device(device); + if (!net_device) + return -ENODEV; + ndev = net_device->ndev; + + init_packet = &net_device->channel_init_pkt; + + /* Negotiate the latest NVSP protocol supported */ + if (negotiate_nvsp_ver(device, net_device, init_packet, + NVSP_PROTOCOL_VERSION_2) == 0) { + net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2; + } else if (negotiate_nvsp_ver(device, net_device, init_packet, + NVSP_PROTOCOL_VERSION_1) == 0) { + net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1; + } else { ret = -EPROTO; goto cleanup; } + + pr_debug("Negotiated NVSP version:%x\n", net_device->nvsp_version); + /* Send the ndis version */ memset(init_packet, 0, sizeof(struct nvsp_message)); @@ -438,6 +463,9 @@ static void netvsc_send_completion(struct hv_device *device, nvsc_packet->completion.send.send_completion_ctx); atomic_dec(&net_device->num_outstanding_sends); + + if (netif_queue_stopped(ndev) && !net_device->start_remove) + netif_wake_queue(ndev); } else { netdev_err(ndev, "Unknown send completion packet type- " "%d received!!\n", nvsp_packet->hdr.msg_type); @@ -488,11 +516,16 @@ int netvsc_send(struct hv_device *device, } - if (ret != 0) + if (ret == 0) { + atomic_inc(&net_device->num_outstanding_sends); + } else if (ret == -EAGAIN) { + netif_stop_queue(ndev); + if (atomic_read(&net_device->num_outstanding_sends) < 1) + netif_wake_queue(ndev); + } else { netdev_err(ndev, "Unable to send packet %p ret %d\n", packet, ret); - else - atomic_inc(&net_device->num_outstanding_sends); + } return ret; } @@ -598,12 +631,10 @@ static void netvsc_receive(struct hv_device *device, struct vmtransfer_page_packet_header *vmxferpage_packet; struct nvsp_message *nvsp_packet; struct hv_netvsc_packet *netvsc_packet = NULL; - unsigned long start; - unsigned long end, end_virtual; /* struct netvsc_driver *netvscDriver; */ struct xferpage_packet *xferpage_packet = NULL; - int i, j; - int count = 0, bytes_remain = 0; + int i; + int count = 0; unsigned long flags; struct net_device *ndev; @@ -712,53 +743,10 @@ static void netvsc_receive(struct hv_device *device, netvsc_packet->completion.recv.recv_completion_tid = vmxferpage_packet->d.trans_id; + netvsc_packet->data = (void *)((unsigned long)net_device-> + recv_buf + vmxferpage_packet->ranges[i].byte_offset); netvsc_packet->total_data_buflen = vmxferpage_packet->ranges[i].byte_count; - netvsc_packet->page_buf_cnt = 1; - - netvsc_packet->page_buf[0].len = - vmxferpage_packet->ranges[i].byte_count; - - start = virt_to_phys((void *)((unsigned long)net_device-> - recv_buf + vmxferpage_packet->ranges[i].byte_offset)); - - netvsc_packet->page_buf[0].pfn = start >> PAGE_SHIFT; - end_virtual = (unsigned long)net_device->recv_buf - + vmxferpage_packet->ranges[i].byte_offset - + vmxferpage_packet->ranges[i].byte_count - 1; - end = virt_to_phys((void *)end_virtual); - - /* Calculate the page relative offset */ - netvsc_packet->page_buf[0].offset = - vmxferpage_packet->ranges[i].byte_offset & - (PAGE_SIZE - 1); - if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) { - /* Handle frame across multiple pages: */ - netvsc_packet->page_buf[0].len = - (netvsc_packet->page_buf[0].pfn << - PAGE_SHIFT) - + PAGE_SIZE - start; - bytes_remain = netvsc_packet->total_data_buflen - - netvsc_packet->page_buf[0].len; - for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) { - netvsc_packet->page_buf[j].offset = 0; - if (bytes_remain <= PAGE_SIZE) { - netvsc_packet->page_buf[j].len = - bytes_remain; - bytes_remain = 0; - } else { - netvsc_packet->page_buf[j].len = - PAGE_SIZE; - bytes_remain -= PAGE_SIZE; - } - netvsc_packet->page_buf[j].pfn = - virt_to_phys((void *)(end_virtual - - bytes_remain)) >> PAGE_SHIFT; - netvsc_packet->page_buf_cnt++; - if (bytes_remain == 0) - break; - } - } /* Pass it to the upper layer */ rndis_filter_receive(device, netvsc_packet); diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 93b0e91cbf9..462d05f05e8 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -43,24 +43,59 @@ struct net_device_context { /* point back to our device context */ struct hv_device *device_ctx; - atomic_t avail; struct delayed_work dwork; }; -#define PACKET_PAGES_LOWATER 8 -/* Need this many pages to handle worst case fragmented packet */ -#define PACKET_PAGES_HIWATER (MAX_SKB_FRAGS + 2) - static int ring_size = 128; module_param(ring_size, int, S_IRUGO); MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)"); -/* no-op so the netdev core doesn't return -EINVAL when modifying the the - * multicast address list in SIOCADDMULTI. hv is setup to get all multicast - * when it calls RndisFilterOnOpen() */ +struct set_multicast_work { + struct work_struct work; + struct net_device *net; +}; + +static void do_set_multicast(struct work_struct *w) +{ + struct set_multicast_work *swk = + container_of(w, struct set_multicast_work, work); + struct net_device *net = swk->net; + + struct net_device_context *ndevctx = netdev_priv(net); + struct netvsc_device *nvdev; + struct rndis_device *rdev; + + nvdev = hv_get_drvdata(ndevctx->device_ctx); + if (nvdev == NULL) + return; + + rdev = nvdev->extension; + if (rdev == NULL) + return; + + if (net->flags & IFF_PROMISC) + rndis_filter_set_packet_filter(rdev, + NDIS_PACKET_TYPE_PROMISCUOUS); + else + rndis_filter_set_packet_filter(rdev, + NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_DIRECTED); + + kfree(w); +} + static void netvsc_set_multicast_list(struct net_device *net) { + struct set_multicast_work *swk = + kmalloc(sizeof(struct set_multicast_work), GFP_ATOMIC); + if (swk == NULL) + return; + + swk->net = net; + INIT_WORK(&swk->work, do_set_multicast); + schedule_work(&swk->work); } static int netvsc_open(struct net_device *net) @@ -104,18 +139,8 @@ static void netvsc_xmit_completion(void *context) kfree(packet); - if (skb) { - struct net_device *net = skb->dev; - struct net_device_context *net_device_ctx = netdev_priv(net); - unsigned int num_pages = skb_shinfo(skb)->nr_frags + 2; - + if (skb) dev_kfree_skb_any(skb); - - atomic_add(num_pages, &net_device_ctx->avail); - if (atomic_read(&net_device_ctx->avail) >= - PACKET_PAGES_HIWATER) - netif_wake_queue(net); - } } static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) @@ -123,12 +148,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_netvsc_packet *packet; int ret; - unsigned int i, num_pages; + unsigned int i, num_pages, npg_data; - /* Add 1 for skb->data and additional one for RNDIS */ - num_pages = skb_shinfo(skb)->nr_frags + 1 + 1; - if (num_pages > atomic_read(&net_device_ctx->avail)) - return NETDEV_TX_BUSY; + /* Add multipage for skb->data and additional one for RNDIS */ + npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) + >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1; + num_pages = skb_shinfo(skb)->nr_frags + npg_data + 1; /* Allocate a netvsc packet based on # of frags. */ packet = kzalloc(sizeof(struct hv_netvsc_packet) + @@ -151,21 +176,36 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->page_buf_cnt = num_pages; /* Initialize it from the skb */ - packet->total_data_buflen = skb->len; + packet->total_data_buflen = skb->len; /* Start filling in the page buffers starting after RNDIS buffer. */ packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; packet->page_buf[1].offset = (unsigned long)skb->data & (PAGE_SIZE - 1); - packet->page_buf[1].len = skb_headlen(skb); + if (npg_data == 1) + packet->page_buf[1].len = skb_headlen(skb); + else + packet->page_buf[1].len = PAGE_SIZE + - packet->page_buf[1].offset; + + for (i = 2; i <= npg_data; i++) { + packet->page_buf[i].pfn = virt_to_phys(skb->data + + PAGE_SIZE * (i-1)) >> PAGE_SHIFT; + packet->page_buf[i].offset = 0; + packet->page_buf[i].len = PAGE_SIZE; + } + if (npg_data > 1) + packet->page_buf[npg_data].len = (((unsigned long)skb->data + + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1; /* Additional fragments are after SKB data */ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { const skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - packet->page_buf[i+2].pfn = page_to_pfn(skb_frag_page(f)); - packet->page_buf[i+2].offset = f->page_offset; - packet->page_buf[i+2].len = skb_frag_size(f); + packet->page_buf[i+npg_data+1].pfn = + page_to_pfn(skb_frag_page(f)); + packet->page_buf[i+npg_data+1].offset = f->page_offset; + packet->page_buf[i+npg_data+1].len = skb_frag_size(f); } /* Set the completion routine */ @@ -178,10 +218,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) if (ret == 0) { net->stats.tx_bytes += skb->len; net->stats.tx_packets++; - - atomic_sub(num_pages, &net_device_ctx->avail); - if (atomic_read(&net_device_ctx->avail) < PACKET_PAGES_LOWATER) - netif_stop_queue(net); } else { /* we are shutting down or bus overloaded, just drop packet */ net->stats.tx_dropped++; @@ -232,9 +268,6 @@ int netvsc_recv_callback(struct hv_device *device_obj, { struct net_device *net = dev_get_drvdata(&device_obj->device); struct sk_buff *skb; - void *data; - int i; - unsigned long flags; struct netvsc_device *net_device; net_device = hv_get_drvdata(device_obj); @@ -253,27 +286,12 @@ int netvsc_recv_callback(struct hv_device *device_obj, return 0; } - /* for kmap_atomic */ - local_irq_save(flags); - /* * Copy to skb. This copy is needed here since the memory pointed by * hv_netvsc_packet cannot be deallocated */ - for (i = 0; i < packet->page_buf_cnt; i++) { - data = kmap_atomic(pfn_to_page(packet->page_buf[i].pfn), - KM_IRQ1); - data = (void *)(unsigned long)data + - packet->page_buf[i].offset; - - memcpy(skb_put(skb, packet->page_buf[i].len), data, - packet->page_buf[i].len); - - kunmap_atomic((void *)((unsigned long)data - - packet->page_buf[i].offset), KM_IRQ1); - } - - local_irq_restore(flags); + memcpy(skb_put(skb, packet->total_data_buflen), packet->data, + packet->total_data_buflen); skb->protocol = eth_type_trans(skb, net); skb->ip_summed = CHECKSUM_NONE; @@ -299,6 +317,39 @@ static void netvsc_get_drvinfo(struct net_device *net, strcpy(info->fw_version, "N/A"); } +static int netvsc_change_mtu(struct net_device *ndev, int mtu) +{ + struct net_device_context *ndevctx = netdev_priv(ndev); + struct hv_device *hdev = ndevctx->device_ctx; + struct netvsc_device *nvdev = hv_get_drvdata(hdev); + struct netvsc_device_info device_info; + int limit = ETH_DATA_LEN; + + if (nvdev == NULL || nvdev->destroy) + return -ENODEV; + + if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2) + limit = NETVSC_MTU; + + if (mtu < 68 || mtu > limit) + return -EINVAL; + + nvdev->start_remove = true; + cancel_delayed_work_sync(&ndevctx->dwork); + netif_stop_queue(ndev); + rndis_filter_device_remove(hdev); + + ndev->mtu = mtu; + + ndevctx->device_ctx = hdev; + hv_set_drvdata(hdev, ndev); + device_info.ring_size = ring_size; + rndis_filter_device_add(hdev, &device_info); + netif_wake_queue(ndev); + + return 0; +} + static const struct ethtool_ops ethtool_ops = { .get_drvinfo = netvsc_get_drvinfo, .get_link = ethtool_op_get_link, @@ -309,7 +360,7 @@ static const struct net_device_ops device_ops = { .ndo_stop = netvsc_close, .ndo_start_xmit = netvsc_start_xmit, .ndo_set_rx_mode = netvsc_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, + .ndo_change_mtu = netvsc_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, }; @@ -351,7 +402,6 @@ static int netvsc_probe(struct hv_device *dev, net_device_ctx = netdev_priv(net); net_device_ctx->device_ctx = dev; - atomic_set(&net_device_ctx->avail, ring_size); hv_set_drvdata(dev, net); INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp); @@ -403,6 +453,8 @@ static int netvsc_remove(struct hv_device *dev) return 0; } + net_device->start_remove = true; + ndev_ctx = netdev_priv(net); cancel_delayed_work_sync(&ndev_ctx->dwork); diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index bafccb36004..da181f9a49d 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -30,26 +30,6 @@ #include "hyperv_net.h" -enum rndis_device_state { - RNDIS_DEV_UNINITIALIZED = 0, - RNDIS_DEV_INITIALIZING, - RNDIS_DEV_INITIALIZED, - RNDIS_DEV_DATAINITIALIZED, -}; - -struct rndis_device { - struct netvsc_device *net_dev; - - enum rndis_device_state state; - bool link_state; - atomic_t new_req_id; - - spinlock_t request_lock; - struct list_head req_list; - - unsigned char hw_mac_adr[ETH_ALEN]; -}; - struct rndis_request { struct list_head list_ent; struct completion wait_event; @@ -329,7 +309,6 @@ static void rndis_filter_receive_data(struct rndis_device *dev, { struct rndis_packet *rndis_pkt; u32 data_offset; - int i; rndis_pkt = &msg->msg.pkt; @@ -342,17 +321,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; pkt->total_data_buflen -= data_offset; - pkt->page_buf[0].offset += data_offset; - pkt->page_buf[0].len -= data_offset; - - /* Drop the 0th page, if rndis data go beyond page boundary */ - if (pkt->page_buf[0].offset >= PAGE_SIZE) { - pkt->page_buf[1].offset = pkt->page_buf[0].offset - PAGE_SIZE; - pkt->page_buf[1].len -= pkt->page_buf[1].offset; - pkt->page_buf_cnt--; - for (i = 0; i < pkt->page_buf_cnt; i++) - pkt->page_buf[i] = pkt->page_buf[i+1]; - } + pkt->data = (void *)((unsigned long)pkt->data + data_offset); pkt->is_data_pkt = true; @@ -387,11 +356,7 @@ int rndis_filter_receive(struct hv_device *dev, return -ENODEV; } - rndis_hdr = (struct rndis_message *)kmap_atomic( - pfn_to_page(pkt->page_buf[0].pfn), KM_IRQ0); - - rndis_hdr = (void *)((unsigned long)rndis_hdr + - pkt->page_buf[0].offset); + rndis_hdr = pkt->data; /* Make sure we got a valid rndis message */ if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) && @@ -407,8 +372,6 @@ int rndis_filter_receive(struct hv_device *dev, sizeof(struct rndis_message) : rndis_hdr->msg_len); - kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset, KM_IRQ0); - dump_rndis_message(dev, &rndis_msg); switch (rndis_msg.ndis_msg_type) { @@ -522,8 +485,7 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev) return ret; } -static int rndis_filter_set_packet_filter(struct rndis_device *dev, - u32 new_filter) +int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) { struct rndis_request *request; struct rndis_set_request *set; diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 25cdff36a78..21e2f4b87f1 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -72,8 +72,6 @@ source "drivers/staging/octeon/Kconfig" source "drivers/staging/serqt_usb2/Kconfig" -source "drivers/staging/spectra/Kconfig" - source "drivers/staging/quatech_usb2/Kconfig" source "drivers/staging/vt6655/Kconfig" @@ -116,8 +114,6 @@ source "drivers/staging/bcm/Kconfig" source "drivers/staging/ft1000/Kconfig" -source "drivers/staging/intel_sst/Kconfig" - source "drivers/staging/speakup/Kconfig" source "drivers/staging/cptm1217/Kconfig" @@ -132,4 +128,8 @@ source "drivers/staging/nvec/Kconfig" source "drivers/staging/media/Kconfig" +source "drivers/staging/omapdrm/Kconfig" + +source "drivers/staging/android/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a25f3f26c7f..7c5808d7212 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_RTS_PSTOR) += rts_pstor/ obj-$(CONFIG_RTS5139) += rts5139/ -obj-$(CONFIG_SPECTRA) += spectra/ obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_POHMELFS) += pohmelfs/ obj-$(CONFIG_IDE_PHISON) += phison/ @@ -50,10 +49,11 @@ obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/ obj-$(CONFIG_USB_ENESTORAGE) += keucr/ obj-$(CONFIG_BCM_WIMAX) += bcm/ obj-$(CONFIG_FT1000) += ft1000/ -obj-$(CONFIG_SND_INTEL_SST) += intel_sst/ obj-$(CONFIG_SPEAKUP) += speakup/ obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ obj-$(CONFIG_DRM_PSB) += gma500/ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_MFD_NVEC) += nvec/ +obj-$(CONFIG_DRM_OMAP) += omapdrm/ +obj-$(CONFIG_ANDROID) += android/ diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig new file mode 100644 index 00000000000..becf711117e --- /dev/null +++ b/drivers/staging/android/Kconfig @@ -0,0 +1,110 @@ +menu "Android" + +config ANDROID + bool "Android Drivers" + default N + ---help--- + Enable support for various drivers needed on the Android platform + +if ANDROID + +config ANDROID_BINDER_IPC + bool "Android Binder IPC Driver" + default n + +config ASHMEM + bool "Enable the Anonymous Shared Memory Subsystem" + default n + depends on SHMEM || TINY_SHMEM + help + The ashmem subsystem is a new shared memory allocator, similar to + POSIX SHM but with different behavior and sporting a simpler + file-based API. + +config ANDROID_LOGGER + tristate "Android log driver" + default n + +config ANDROID_RAM_CONSOLE + bool "Android RAM buffer console" + default n + +config ANDROID_RAM_CONSOLE_ENABLE_VERBOSE + bool "Enable verbose console messages on Android RAM console" + default y + depends on ANDROID_RAM_CONSOLE + +menuconfig ANDROID_RAM_CONSOLE_ERROR_CORRECTION + bool "Android RAM Console Enable error correction" + default n + depends on ANDROID_RAM_CONSOLE + depends on !ANDROID_RAM_CONSOLE_EARLY_INIT + select REED_SOLOMON + select REED_SOLOMON_ENC8 + select REED_SOLOMON_DEC8 + +if ANDROID_RAM_CONSOLE_ERROR_CORRECTION + +config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE + int "Android RAM Console Data data size" + default 128 + help + Must be a power of 2. + +config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE + int "Android RAM Console ECC size" + default 16 + +config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE + int "Android RAM Console Symbol size" + default 8 + +config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL + hex "Android RAM Console Polynomial" + default 0x19 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 4) + default 0x29 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 5) + default 0x61 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 6) + default 0x89 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 7) + default 0x11d if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 8) + +endif # ANDROID_RAM_CONSOLE_ERROR_CORRECTION + +config ANDROID_RAM_CONSOLE_EARLY_INIT + bool "Start Android RAM console early" + default n + depends on ANDROID_RAM_CONSOLE + +config ANDROID_RAM_CONSOLE_EARLY_ADDR + hex "Android RAM console virtual address" + default 0 + depends on ANDROID_RAM_CONSOLE_EARLY_INIT + +config ANDROID_RAM_CONSOLE_EARLY_SIZE + hex "Android RAM console buffer size" + default 0 + depends on ANDROID_RAM_CONSOLE_EARLY_INIT + +config ANDROID_TIMED_OUTPUT + bool "Timed output class driver" + default y + +config ANDROID_TIMED_GPIO + tristate "Android timed gpio driver" + depends on GENERIC_GPIO && ANDROID_TIMED_OUTPUT + default n + +config ANDROID_LOW_MEMORY_KILLER + bool "Android Low Memory Killer" + default N + ---help--- + Register processes to be killed when memory is low + +config ANDROID_PMEM + bool "Android pmem allocator" + depends on ARM + +source "drivers/staging/android/switch/Kconfig" + +endif # if ANDROID + +endmenu diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile new file mode 100644 index 00000000000..eaed1ff64f0 --- /dev/null +++ b/drivers/staging/android/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o +obj-$(CONFIG_ASHMEM) += ashmem.o +obj-$(CONFIG_ANDROID_LOGGER) += logger.o +obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o +obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o +obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o +obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o +obj-$(CONFIG_ANDROID_PMEM) += pmem.o +obj-$(CONFIG_ANDROID_SWITCH) += switch/ diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO new file mode 100644 index 00000000000..e59c5be4be2 --- /dev/null +++ b/drivers/staging/android/TODO @@ -0,0 +1,10 @@ +TODO: + - checkpatch.pl cleanups + - sparse fixes + - rename files to be not so "generic" + - make sure things build as modules properly + - add proper arch dependancies as needed + - audit userspace interfaces to make sure they are sane + +Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc: +Brian Swetland <swetland@google.com> diff --git a/drivers/staging/android/android_pmem.h b/drivers/staging/android/android_pmem.h new file mode 100644 index 00000000000..f633621f5be --- /dev/null +++ b/drivers/staging/android/android_pmem.h @@ -0,0 +1,93 @@ +/* include/linux/android_pmem.h + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _ANDROID_PMEM_H_ +#define _ANDROID_PMEM_H_ + +#define PMEM_IOCTL_MAGIC 'p' +#define PMEM_GET_PHYS _IOW(PMEM_IOCTL_MAGIC, 1, unsigned int) +#define PMEM_MAP _IOW(PMEM_IOCTL_MAGIC, 2, unsigned int) +#define PMEM_GET_SIZE _IOW(PMEM_IOCTL_MAGIC, 3, unsigned int) +#define PMEM_UNMAP _IOW(PMEM_IOCTL_MAGIC, 4, unsigned int) +/* This ioctl will allocate pmem space, backing the file, it will fail + * if the file already has an allocation, pass it the len as the argument + * to the ioctl */ +#define PMEM_ALLOCATE _IOW(PMEM_IOCTL_MAGIC, 5, unsigned int) +/* This will connect a one pmem file to another, pass the file that is already + * backed in memory as the argument to the ioctl + */ +#define PMEM_CONNECT _IOW(PMEM_IOCTL_MAGIC, 6, unsigned int) +/* Returns the total size of the pmem region it is sent to as a pmem_region + * struct (with offset set to 0). + */ +#define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, unsigned int) +#define PMEM_CACHE_FLUSH _IOW(PMEM_IOCTL_MAGIC, 8, unsigned int) + +struct android_pmem_platform_data +{ + const char* name; + /* starting physical address of memory region */ + unsigned long start; + /* size of memory region */ + unsigned long size; + /* set to indicate the region should not be managed with an allocator */ + unsigned no_allocator; + /* set to indicate maps of this region should be cached, if a mix of + * cached and uncached is desired, set this and open the device with + * O_SYNC to get an uncached region */ + unsigned cached; + /* The MSM7k has bits to enable a write buffer in the bus controller*/ + unsigned buffered; +}; + +struct pmem_region { + unsigned long offset; + unsigned long len; +}; + +#ifdef CONFIG_ANDROID_PMEM +int is_pmem_file(struct file *file); +int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, + unsigned long *end, struct file **filp); +int get_pmem_user_addr(struct file *file, unsigned long *start, + unsigned long *end); +void put_pmem_file(struct file* file); +void flush_pmem_file(struct file *file, unsigned long start, unsigned long len); +int pmem_setup(struct android_pmem_platform_data *pdata, + long (*ioctl)(struct file *, unsigned int, unsigned long), + int (*release)(struct inode *, struct file *)); +int pmem_remap(struct pmem_region *region, struct file *file, + unsigned operation); + +#else +static inline int is_pmem_file(struct file *file) { return 0; } +static inline int get_pmem_file(int fd, unsigned long *start, + unsigned long *vstart, unsigned long *end, + struct file **filp) { return -ENOSYS; } +static inline int get_pmem_user_addr(struct file *file, unsigned long *start, + unsigned long *end) { return -ENOSYS; } +static inline void put_pmem_file(struct file* file) { return; } +static inline void flush_pmem_file(struct file *file, unsigned long start, + unsigned long len) { return; } +static inline int pmem_setup(struct android_pmem_platform_data *pdata, + long (*ioctl)(struct file *, unsigned int, unsigned long), + int (*release)(struct inode *, struct file *)) { return -ENOSYS; } + +static inline int pmem_remap(struct pmem_region *region, struct file *file, + unsigned operation) { return -ENOSYS; } +#endif + +#endif //_ANDROID_PPP_H_ + diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c new file mode 100644 index 00000000000..99052bfd3a2 --- /dev/null +++ b/drivers/staging/android/ashmem.c @@ -0,0 +1,752 @@ +/* mm/ashmem.c +** +** Anonymous Shared Memory Subsystem, ashmem +** +** Copyright (C) 2008 Google, Inc. +** +** Robert Love <rlove@google.com> +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** 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. +*/ + +#include <linux/module.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/security.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/uaccess.h> +#include <linux/personality.h> +#include <linux/bitops.h> +#include <linux/mutex.h> +#include <linux/shmem_fs.h> +#include "ashmem.h" + +#define ASHMEM_NAME_PREFIX "dev/ashmem/" +#define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1) +#define ASHMEM_FULL_NAME_LEN (ASHMEM_NAME_LEN + ASHMEM_NAME_PREFIX_LEN) + +/* + * ashmem_area - anonymous shared memory area + * Lifecycle: From our parent file's open() until its release() + * Locking: Protected by `ashmem_mutex' + * Big Note: Mappings do NOT pin this structure; it dies on close() + */ +struct ashmem_area { + char name[ASHMEM_FULL_NAME_LEN]; /* optional name in /proc/pid/maps */ + struct list_head unpinned_list; /* list of all ashmem areas */ + struct file *file; /* the shmem-based backing file */ + size_t size; /* size of the mapping, in bytes */ + unsigned long prot_mask; /* allowed prot bits, as vm_flags */ +}; + +/* + * ashmem_range - represents an interval of unpinned (evictable) pages + * Lifecycle: From unpin to pin + * Locking: Protected by `ashmem_mutex' + */ +struct ashmem_range { + struct list_head lru; /* entry in LRU list */ + struct list_head unpinned; /* entry in its area's unpinned list */ + struct ashmem_area *asma; /* associated area */ + size_t pgstart; /* starting page, inclusive */ + size_t pgend; /* ending page, inclusive */ + unsigned int purged; /* ASHMEM_NOT or ASHMEM_WAS_PURGED */ +}; + +/* LRU list of unpinned pages, protected by ashmem_mutex */ +static LIST_HEAD(ashmem_lru_list); + +/* Count of pages on our LRU list, protected by ashmem_mutex */ +static unsigned long lru_count; + +/* + * ashmem_mutex - protects the list of and each individual ashmem_area + * + * Lock Ordering: ashmex_mutex -> i_mutex -> i_alloc_sem + */ +static DEFINE_MUTEX(ashmem_mutex); + +static struct kmem_cache *ashmem_area_cachep __read_mostly; +static struct kmem_cache *ashmem_range_cachep __read_mostly; + +#define range_size(range) \ + ((range)->pgend - (range)->pgstart + 1) + +#define range_on_lru(range) \ + ((range)->purged == ASHMEM_NOT_PURGED) + +#define page_range_subsumes_range(range, start, end) \ + (((range)->pgstart >= (start)) && ((range)->pgend <= (end))) + +#define page_range_subsumed_by_range(range, start, end) \ + (((range)->pgstart <= (start)) && ((range)->pgend >= (end))) + +#define page_in_range(range, page) \ + (((range)->pgstart <= (page)) && ((range)->pgend >= (page))) + +#define page_range_in_range(range, start, end) \ + (page_in_range(range, start) || page_in_range(range, end) || \ + page_range_subsumes_range(range, start, end)) + +#define range_before_page(range, page) \ + ((range)->pgend < (page)) + +#define PROT_MASK (PROT_EXEC | PROT_READ | PROT_WRITE) + +static inline void lru_add(struct ashmem_range *range) +{ + list_add_tail(&range->lru, &ashmem_lru_list); + lru_count += range_size(range); +} + +static inline void lru_del(struct ashmem_range *range) +{ + list_del(&range->lru); + lru_count -= range_size(range); +} + +/* + * range_alloc - allocate and initialize a new ashmem_range structure + * + * 'asma' - associated ashmem_area + * 'prev_range' - the previous ashmem_range in the sorted asma->unpinned list + * 'purged' - initial purge value (ASMEM_NOT_PURGED or ASHMEM_WAS_PURGED) + * 'start' - starting page, inclusive + * 'end' - ending page, inclusive + * + * Caller must hold ashmem_mutex. + */ +static int range_alloc(struct ashmem_area *asma, + struct ashmem_range *prev_range, unsigned int purged, + size_t start, size_t end) +{ + struct ashmem_range *range; + + range = kmem_cache_zalloc(ashmem_range_cachep, GFP_KERNEL); + if (unlikely(!range)) + return -ENOMEM; + + range->asma = asma; + range->pgstart = start; + range->pgend = end; + range->purged = purged; + + list_add_tail(&range->unpinned, &prev_range->unpinned); + + if (range_on_lru(range)) + lru_add(range); + + return 0; +} + +static void range_del(struct ashmem_range *range) +{ + list_del(&range->unpinned); + if (range_on_lru(range)) + lru_del(range); + kmem_cache_free(ashmem_range_cachep, range); +} + +/* + * range_shrink - shrinks a range + * + * Caller must hold ashmem_mutex. + */ +static inline void range_shrink(struct ashmem_range *range, + size_t start, size_t end) +{ + size_t pre = range_size(range); + + range->pgstart = start; + range->pgend = end; + + if (range_on_lru(range)) + lru_count -= pre - range_size(range); +} + +static int ashmem_open(struct inode *inode, struct file *file) +{ + struct ashmem_area *asma; + int ret; + + ret = generic_file_open(inode, file); + if (unlikely(ret)) + return ret; + + asma = kmem_cache_zalloc(ashmem_area_cachep, GFP_KERNEL); + if (unlikely(!asma)) + return -ENOMEM; + + INIT_LIST_HEAD(&asma->unpinned_list); + memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN); + asma->prot_mask = PROT_MASK; + file->private_data = asma; + + return 0; +} + +static int ashmem_release(struct inode *ignored, struct file *file) +{ + struct ashmem_area *asma = file->private_data; + struct ashmem_range *range, *next; + + mutex_lock(&ashmem_mutex); + list_for_each_entry_safe(range, next, &asma->unpinned_list, unpinned) + range_del(range); + mutex_unlock(&ashmem_mutex); + + if (asma->file) + fput(asma->file); + kmem_cache_free(ashmem_area_cachep, asma); + + return 0; +} + +static ssize_t ashmem_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct ashmem_area *asma = file->private_data; + int ret = 0; + + mutex_lock(&ashmem_mutex); + + /* If size is not set, or set to 0, always return EOF. */ + if (asma->size == 0) + goto out; + + if (!asma->file) { + ret = -EBADF; + goto out; + } + + ret = asma->file->f_op->read(asma->file, buf, len, pos); + if (ret < 0) + goto out; + + /** Update backing file pos, since f_ops->read() doesn't */ + asma->file->f_pos = *pos; + +out: + mutex_unlock(&ashmem_mutex); + return ret; +} + +static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin) +{ + struct ashmem_area *asma = file->private_data; + int ret; + + mutex_lock(&ashmem_mutex); + + if (asma->size == 0) { + ret = -EINVAL; + goto out; + } + + if (!asma->file) { + ret = -EBADF; + goto out; + } + + ret = asma->file->f_op->llseek(asma->file, offset, origin); + if (ret < 0) + goto out; + + /** Copy f_pos from backing file, since f_ops->llseek() sets it */ + file->f_pos = asma->file->f_pos; + +out: + mutex_unlock(&ashmem_mutex); + return ret; +} + +static inline unsigned long calc_vm_may_flags(unsigned long prot) +{ + return _calc_vm_trans(prot, PROT_READ, VM_MAYREAD) | + _calc_vm_trans(prot, PROT_WRITE, VM_MAYWRITE) | + _calc_vm_trans(prot, PROT_EXEC, VM_MAYEXEC); +} + +static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ashmem_area *asma = file->private_data; + int ret = 0; + + mutex_lock(&ashmem_mutex); + + /* user needs to SET_SIZE before mapping */ + if (unlikely(!asma->size)) { + ret = -EINVAL; + goto out; + } + + /* requested protection bits must match our allowed protection mask */ + if (unlikely((vma->vm_flags & ~calc_vm_prot_bits(asma->prot_mask)) & + calc_vm_prot_bits(PROT_MASK))) { + ret = -EPERM; + goto out; + } + vma->vm_flags &= ~calc_vm_may_flags(~asma->prot_mask); + + if (!asma->file) { + char *name = ASHMEM_NAME_DEF; + struct file *vmfile; + + if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') + name = asma->name; + + /* ... and allocate the backing shmem file */ + vmfile = shmem_file_setup(name, asma->size, vma->vm_flags); + if (unlikely(IS_ERR(vmfile))) { + ret = PTR_ERR(vmfile); + goto out; + } + asma->file = vmfile; + } + get_file(asma->file); + + /* + * XXX - Reworked to use shmem_zero_setup() instead of + * shmem_set_file while we're in staging. -jstultz + */ + if (vma->vm_flags & VM_SHARED) { + ret = shmem_zero_setup(vma); + if (ret) { + fput(asma->file); + goto out; + } + } + + if (vma->vm_file) + fput(vma->vm_file); + vma->vm_file = asma->file; + vma->vm_flags |= VM_CAN_NONLINEAR; + +out: + mutex_unlock(&ashmem_mutex); + return ret; +} + +/* + * ashmem_shrink - our cache shrinker, called from mm/vmscan.c :: shrink_slab + * + * 'nr_to_scan' is the number of objects (pages) to prune, or 0 to query how + * many objects (pages) we have in total. + * + * 'gfp_mask' is the mask of the allocation that got us into this mess. + * + * Return value is the number of objects (pages) remaining, or -1 if we cannot + * proceed without risk of deadlock (due to gfp_mask). + * + * We approximate LRU via least-recently-unpinned, jettisoning unpinned partial + * chunks of ashmem regions LRU-wise one-at-a-time until we hit 'nr_to_scan' + * pages freed. + */ +static int ashmem_shrink(struct shrinker *s, struct shrink_control *sc) +{ + struct ashmem_range *range, *next; + + /* We might recurse into filesystem code, so bail out if necessary */ + if (sc->nr_to_scan && !(sc->gfp_mask & __GFP_FS)) + return -1; + if (!sc->nr_to_scan) + return lru_count; + + mutex_lock(&ashmem_mutex); + list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) { + struct inode *inode = range->asma->file->f_dentry->d_inode; + loff_t start = range->pgstart * PAGE_SIZE; + loff_t end = (range->pgend + 1) * PAGE_SIZE - 1; + + vmtruncate_range(inode, start, end); + range->purged = ASHMEM_WAS_PURGED; + lru_del(range); + + sc->nr_to_scan -= range_size(range); + if (sc->nr_to_scan <= 0) + break; + } + mutex_unlock(&ashmem_mutex); + + return lru_count; +} + +static struct shrinker ashmem_shrinker = { + .shrink = ashmem_shrink, + .seeks = DEFAULT_SEEKS * 4, +}; + +static int set_prot_mask(struct ashmem_area *asma, unsigned long prot) +{ + int ret = 0; + + mutex_lock(&ashmem_mutex); + + /* the user can only remove, not add, protection bits */ + if (unlikely((asma->prot_mask & prot) != prot)) { + ret = -EINVAL; + goto out; + } + + /* does the application expect PROT_READ to imply PROT_EXEC? */ + if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) + prot |= PROT_EXEC; + + asma->prot_mask = prot; + +out: + mutex_unlock(&ashmem_mutex); + return ret; +} + +static int set_name(struct ashmem_area *asma, void __user *name) +{ + int ret = 0; + + mutex_lock(&ashmem_mutex); + + /* cannot change an existing mapping's name */ + if (unlikely(asma->file)) { + ret = -EINVAL; + goto out; + } + + if (unlikely(copy_from_user(asma->name + ASHMEM_NAME_PREFIX_LEN, + name, ASHMEM_NAME_LEN))) + ret = -EFAULT; + asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0'; + +out: + mutex_unlock(&ashmem_mutex); + + return ret; +} + +static int get_name(struct ashmem_area *asma, void __user *name) +{ + int ret = 0; + + mutex_lock(&ashmem_mutex); + if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') { + size_t len; + + /* + * Copying only `len', instead of ASHMEM_NAME_LEN, bytes + * prevents us from revealing one user's stack to another. + */ + len = strlen(asma->name + ASHMEM_NAME_PREFIX_LEN) + 1; + if (unlikely(copy_to_user(name, + asma->name + ASHMEM_NAME_PREFIX_LEN, len))) + ret = -EFAULT; + } else { + if (unlikely(copy_to_user(name, ASHMEM_NAME_DEF, + sizeof(ASHMEM_NAME_DEF)))) + ret = -EFAULT; + } + mutex_unlock(&ashmem_mutex); + + return ret; +} + +/* + * ashmem_pin - pin the given ashmem region, returning whether it was + * previously purged (ASHMEM_WAS_PURGED) or not (ASHMEM_NOT_PURGED). + * + * Caller must hold ashmem_mutex. + */ +static int ashmem_pin(struct ashmem_area *asma, size_t pgstart, size_t pgend) +{ + struct ashmem_range *range, *next; + int ret = ASHMEM_NOT_PURGED; + + list_for_each_entry_safe(range, next, &asma->unpinned_list, unpinned) { + /* moved past last applicable page; we can short circuit */ + if (range_before_page(range, pgstart)) + break; + + /* + * The user can ask us to pin pages that span multiple ranges, + * or to pin pages that aren't even unpinned, so this is messy. + * + * Four cases: + * 1. The requested range subsumes an existing range, so we + * just remove the entire matching range. + * 2. The requested range overlaps the start of an existing + * range, so we just update that range. + * 3. The requested range overlaps the end of an existing + * range, so we just update that range. + * 4. The requested range punches a hole in an existing range, + * so we have to update one side of the range and then + * create a new range for the other side. + */ + if (page_range_in_range(range, pgstart, pgend)) { + ret |= range->purged; + + /* Case #1: Easy. Just nuke the whole thing. */ + if (page_range_subsumes_range(range, pgstart, pgend)) { + range_del(range); + continue; + } + + /* Case #2: We overlap from the start, so adjust it */ + if (range->pgstart >= pgstart) { + range_shrink(range, pgend + 1, range->pgend); + continue; + } + + /* Case #3: We overlap from the rear, so adjust it */ + if (range->pgend <= pgend) { + range_shrink(range, range->pgstart, pgstart-1); + continue; + } + + /* + * Case #4: We eat a chunk out of the middle. A bit + * more complicated, we allocate a new range for the + * second half and adjust the first chunk's endpoint. + */ + range_alloc(asma, range, range->purged, + pgend + 1, range->pgend); + range_shrink(range, range->pgstart, pgstart - 1); + break; + } + } + + return ret; +} + +/* + * ashmem_unpin - unpin the given range of pages. Returns zero on success. + * + * Caller must hold ashmem_mutex. + */ +static int ashmem_unpin(struct ashmem_area *asma, size_t pgstart, size_t pgend) +{ + struct ashmem_range *range, *next; + unsigned int purged = ASHMEM_NOT_PURGED; + +restart: + list_for_each_entry_safe(range, next, &asma->unpinned_list, unpinned) { + /* short circuit: this is our insertion point */ + if (range_before_page(range, pgstart)) + break; + + /* + * The user can ask us to unpin pages that are already entirely + * or partially pinned. We handle those two cases here. + */ + if (page_range_subsumed_by_range(range, pgstart, pgend)) + return 0; + if (page_range_in_range(range, pgstart, pgend)) { + pgstart = min_t(size_t, range->pgstart, pgstart), + pgend = max_t(size_t, range->pgend, pgend); + purged |= range->purged; + range_del(range); + goto restart; + } + } + + return range_alloc(asma, range, purged, pgstart, pgend); +} + +/* + * ashmem_get_pin_status - Returns ASHMEM_IS_UNPINNED if _any_ pages in the + * given interval are unpinned and ASHMEM_IS_PINNED otherwise. + * + * Caller must hold ashmem_mutex. + */ +static int ashmem_get_pin_status(struct ashmem_area *asma, size_t pgstart, + size_t pgend) +{ + struct ashmem_range *range; + int ret = ASHMEM_IS_PINNED; + + list_for_each_entry(range, &asma->unpinned_list, unpinned) { + if (range_before_page(range, pgstart)) + break; + if (page_range_in_range(range, pgstart, pgend)) { + ret = ASHMEM_IS_UNPINNED; + break; + } + } + + return ret; +} + +static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, + void __user *p) +{ + struct ashmem_pin pin; + size_t pgstart, pgend; + int ret = -EINVAL; + + if (unlikely(!asma->file)) + return -EINVAL; + + if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) + return -EFAULT; + + /* per custom, you can pass zero for len to mean "everything onward" */ + if (!pin.len) + pin.len = PAGE_ALIGN(asma->size) - pin.offset; + + if (unlikely((pin.offset | pin.len) & ~PAGE_MASK)) + return -EINVAL; + + if (unlikely(((__u32) -1) - pin.offset < pin.len)) + return -EINVAL; + + if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len)) + return -EINVAL; + + pgstart = pin.offset / PAGE_SIZE; + pgend = pgstart + (pin.len / PAGE_SIZE) - 1; + + mutex_lock(&ashmem_mutex); + + switch (cmd) { + case ASHMEM_PIN: + ret = ashmem_pin(asma, pgstart, pgend); + break; + case ASHMEM_UNPIN: + ret = ashmem_unpin(asma, pgstart, pgend); + break; + case ASHMEM_GET_PIN_STATUS: + ret = ashmem_get_pin_status(asma, pgstart, pgend); + break; + } + + mutex_unlock(&ashmem_mutex); + + return ret; +} + +static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ashmem_area *asma = file->private_data; + long ret = -ENOTTY; + + switch (cmd) { + case ASHMEM_SET_NAME: + ret = set_name(asma, (void __user *) arg); + break; + case ASHMEM_GET_NAME: + ret = get_name(asma, (void __user *) arg); + break; + case ASHMEM_SET_SIZE: + ret = -EINVAL; + if (!asma->file) { + ret = 0; + asma->size = (size_t) arg; + } + break; + case ASHMEM_GET_SIZE: + ret = asma->size; + break; + case ASHMEM_SET_PROT_MASK: + ret = set_prot_mask(asma, arg); + break; + case ASHMEM_GET_PROT_MASK: + ret = asma->prot_mask; + break; + case ASHMEM_PIN: + case ASHMEM_UNPIN: + case ASHMEM_GET_PIN_STATUS: + ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg); + break; + case ASHMEM_PURGE_ALL_CACHES: + ret = -EPERM; + if (capable(CAP_SYS_ADMIN)) { + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + .nr_to_scan = 0, + }; + ret = ashmem_shrink(&ashmem_shrinker, &sc); + sc.nr_to_scan = ret; + ashmem_shrink(&ashmem_shrinker, &sc); + } + break; + } + + return ret; +} + +static struct file_operations ashmem_fops = { + .owner = THIS_MODULE, + .open = ashmem_open, + .release = ashmem_release, + .read = ashmem_read, + .llseek = ashmem_llseek, + .mmap = ashmem_mmap, + .unlocked_ioctl = ashmem_ioctl, + .compat_ioctl = ashmem_ioctl, +}; + +static struct miscdevice ashmem_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "ashmem", + .fops = &ashmem_fops, +}; + +static int __init ashmem_init(void) +{ + int ret; + + ashmem_area_cachep = kmem_cache_create("ashmem_area_cache", + sizeof(struct ashmem_area), + 0, 0, NULL); + if (unlikely(!ashmem_area_cachep)) { + printk(KERN_ERR "ashmem: failed to create slab cache\n"); + return -ENOMEM; + } + + ashmem_range_cachep = kmem_cache_create("ashmem_range_cache", + sizeof(struct ashmem_range), + 0, 0, NULL); + if (unlikely(!ashmem_range_cachep)) { + printk(KERN_ERR "ashmem: failed to create slab cache\n"); + return -ENOMEM; + } + + ret = misc_register(&ashmem_misc); + if (unlikely(ret)) { + printk(KERN_ERR "ashmem: failed to register misc device!\n"); + return ret; + } + + register_shrinker(&ashmem_shrinker); + + printk(KERN_INFO "ashmem: initialized\n"); + + return 0; +} + +static void __exit ashmem_exit(void) +{ + int ret; + + unregister_shrinker(&ashmem_shrinker); + + ret = misc_deregister(&ashmem_misc); + if (unlikely(ret)) + printk(KERN_ERR "ashmem: failed to unregister misc device!\n"); + + kmem_cache_destroy(ashmem_range_cachep); + kmem_cache_destroy(ashmem_area_cachep); + + printk(KERN_INFO "ashmem: unloaded\n"); +} + +module_init(ashmem_init); +module_exit(ashmem_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/ashmem.h b/drivers/staging/android/ashmem.h new file mode 100644 index 00000000000..1976b10ef93 --- /dev/null +++ b/drivers/staging/android/ashmem.h @@ -0,0 +1,48 @@ +/* + * include/linux/ashmem.h + * + * Copyright 2008 Google Inc. + * Author: Robert Love + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#ifndef _LINUX_ASHMEM_H +#define _LINUX_ASHMEM_H + +#include <linux/limits.h> +#include <linux/ioctl.h> + +#define ASHMEM_NAME_LEN 256 + +#define ASHMEM_NAME_DEF "dev/ashmem" + +/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */ +#define ASHMEM_NOT_PURGED 0 +#define ASHMEM_WAS_PURGED 1 + +/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */ +#define ASHMEM_IS_UNPINNED 0 +#define ASHMEM_IS_PINNED 1 + +struct ashmem_pin { + __u32 offset; /* offset into region, in bytes, page-aligned */ + __u32 len; /* length forward from offset, in bytes, page-aligned */ +}; + +#define __ASHMEMIOC 0x77 + +#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN]) +#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN]) +#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t) +#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4) +#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long) +#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6) +#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin) +#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin) +#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9) +#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10) + +#endif /* _LINUX_ASHMEM_H */ diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c new file mode 100644 index 00000000000..7491801a661 --- /dev/null +++ b/drivers/staging/android/binder.c @@ -0,0 +1,3600 @@ +/* binder.c + * + * Android IPC Subsystem + * + * Copyright (C) 2007-2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <asm/cacheflush.h> +#include <linux/fdtable.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/list.h> +#include <linux/miscdevice.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/nsproxy.h> +#include <linux/poll.h> +#include <linux/debugfs.h> +#include <linux/rbtree.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> + +#include "binder.h" + +static DEFINE_MUTEX(binder_lock); +static DEFINE_MUTEX(binder_deferred_lock); + +static HLIST_HEAD(binder_procs); +static HLIST_HEAD(binder_deferred_list); +static HLIST_HEAD(binder_dead_nodes); + +static struct dentry *binder_debugfs_dir_entry_root; +static struct dentry *binder_debugfs_dir_entry_proc; +static struct binder_node *binder_context_mgr_node; +static uid_t binder_context_mgr_uid = -1; +static int binder_last_id; +static struct workqueue_struct *binder_deferred_workqueue; + +#define BINDER_DEBUG_ENTRY(name) \ +static int binder_##name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, binder_##name##_show, inode->i_private); \ +} \ +\ +static const struct file_operations binder_##name##_fops = { \ + .owner = THIS_MODULE, \ + .open = binder_##name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + +static int binder_proc_show(struct seq_file *m, void *unused); +BINDER_DEBUG_ENTRY(proc); + +/* This is only defined in include/asm-arm/sizes.h */ +#ifndef SZ_1K +#define SZ_1K 0x400 +#endif + +#ifndef SZ_4M +#define SZ_4M 0x400000 +#endif + +#define FORBIDDEN_MMAP_FLAGS (VM_WRITE) + +#define BINDER_SMALL_BUF_SIZE (PAGE_SIZE * 64) + +enum { + BINDER_DEBUG_USER_ERROR = 1U << 0, + BINDER_DEBUG_FAILED_TRANSACTION = 1U << 1, + BINDER_DEBUG_DEAD_TRANSACTION = 1U << 2, + BINDER_DEBUG_OPEN_CLOSE = 1U << 3, + BINDER_DEBUG_DEAD_BINDER = 1U << 4, + BINDER_DEBUG_DEATH_NOTIFICATION = 1U << 5, + BINDER_DEBUG_READ_WRITE = 1U << 6, + BINDER_DEBUG_USER_REFS = 1U << 7, + BINDER_DEBUG_THREADS = 1U << 8, + BINDER_DEBUG_TRANSACTION = 1U << 9, + BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10, + BINDER_DEBUG_FREE_BUFFER = 1U << 11, + BINDER_DEBUG_INTERNAL_REFS = 1U << 12, + BINDER_DEBUG_BUFFER_ALLOC = 1U << 13, + BINDER_DEBUG_PRIORITY_CAP = 1U << 14, + BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15, +}; +static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | + BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; +module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); + +static int binder_debug_no_lock; +module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); + +static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); +static int binder_stop_on_user_error; + +static int binder_set_stop_on_user_error(const char *val, + struct kernel_param *kp) +{ + int ret; + ret = param_set_int(val, kp); + if (binder_stop_on_user_error < 2) + wake_up(&binder_user_error_wait); + return ret; +} +module_param_call(stop_on_user_error, binder_set_stop_on_user_error, + param_get_int, &binder_stop_on_user_error, S_IWUSR | S_IRUGO); + +#define binder_debug(mask, x...) \ + do { \ + if (binder_debug_mask & mask) \ + printk(KERN_INFO x); \ + } while (0) + +#define binder_user_error(x...) \ + do { \ + if (binder_debug_mask & BINDER_DEBUG_USER_ERROR) \ + printk(KERN_INFO x); \ + if (binder_stop_on_user_error) \ + binder_stop_on_user_error = 2; \ + } while (0) + +enum binder_stat_types { + BINDER_STAT_PROC, + BINDER_STAT_THREAD, + BINDER_STAT_NODE, + BINDER_STAT_REF, + BINDER_STAT_DEATH, + BINDER_STAT_TRANSACTION, + BINDER_STAT_TRANSACTION_COMPLETE, + BINDER_STAT_COUNT +}; + +struct binder_stats { + int br[_IOC_NR(BR_FAILED_REPLY) + 1]; + int bc[_IOC_NR(BC_DEAD_BINDER_DONE) + 1]; + int obj_created[BINDER_STAT_COUNT]; + int obj_deleted[BINDER_STAT_COUNT]; +}; + +static struct binder_stats binder_stats; + +static inline void binder_stats_deleted(enum binder_stat_types type) +{ + binder_stats.obj_deleted[type]++; +} + +static inline void binder_stats_created(enum binder_stat_types type) +{ + binder_stats.obj_created[type]++; +} + +struct binder_transaction_log_entry { + int debug_id; + int call_type; + int from_proc; + int from_thread; + int target_handle; + int to_proc; + int to_thread; + int to_node; + int data_size; + int offsets_size; +}; +struct binder_transaction_log { + int next; + int full; + struct binder_transaction_log_entry entry[32]; +}; +static struct binder_transaction_log binder_transaction_log; +static struct binder_transaction_log binder_transaction_log_failed; + +static struct binder_transaction_log_entry *binder_transaction_log_add( + struct binder_transaction_log *log) +{ + struct binder_transaction_log_entry *e; + e = &log->entry[log->next]; + memset(e, 0, sizeof(*e)); + log->next++; + if (log->next == ARRAY_SIZE(log->entry)) { + log->next = 0; + log->full = 1; + } + return e; +} + +struct binder_work { + struct list_head entry; + enum { + BINDER_WORK_TRANSACTION = 1, + BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_NODE, + BINDER_WORK_DEAD_BINDER, + BINDER_WORK_DEAD_BINDER_AND_CLEAR, + BINDER_WORK_CLEAR_DEATH_NOTIFICATION, + } type; +}; + +struct binder_node { + int debug_id; + struct binder_work work; + union { + struct rb_node rb_node; + struct hlist_node dead_node; + }; + struct binder_proc *proc; + struct hlist_head refs; + int internal_strong_refs; + int local_weak_refs; + int local_strong_refs; + void __user *ptr; + void __user *cookie; + unsigned has_strong_ref:1; + unsigned pending_strong_ref:1; + unsigned has_weak_ref:1; + unsigned pending_weak_ref:1; + unsigned has_async_transaction:1; + unsigned accept_fds:1; + unsigned min_priority:8; + struct list_head async_todo; +}; + +struct binder_ref_death { + struct binder_work work; + void __user *cookie; +}; + +struct binder_ref { + /* Lookups needed: */ + /* node + proc => ref (transaction) */ + /* desc + proc => ref (transaction, inc/dec ref) */ + /* node => refs + procs (proc exit) */ + int debug_id; + struct rb_node rb_node_desc; + struct rb_node rb_node_node; + struct hlist_node node_entry; + struct binder_proc *proc; + struct binder_node *node; + uint32_t desc; + int strong; + int weak; + struct binder_ref_death *death; +}; + +struct binder_buffer { + struct list_head entry; /* free and allocated entries by addesss */ + struct rb_node rb_node; /* free entry by size or allocated entry */ + /* by address */ + unsigned free:1; + unsigned allow_user_free:1; + unsigned async_transaction:1; + unsigned debug_id:29; + + struct binder_transaction *transaction; + + struct binder_node *target_node; + size_t data_size; + size_t offsets_size; + uint8_t data[0]; +}; + +enum binder_deferred_state { + BINDER_DEFERRED_PUT_FILES = 0x01, + BINDER_DEFERRED_FLUSH = 0x02, + BINDER_DEFERRED_RELEASE = 0x04, +}; + +struct binder_proc { + struct hlist_node proc_node; + struct rb_root threads; + struct rb_root nodes; + struct rb_root refs_by_desc; + struct rb_root refs_by_node; + int pid; + struct vm_area_struct *vma; + struct task_struct *tsk; + struct files_struct *files; + struct hlist_node deferred_work_node; + int deferred_work; + void *buffer; + ptrdiff_t user_buffer_offset; + + struct list_head buffers; + struct rb_root free_buffers; + struct rb_root allocated_buffers; + size_t free_async_space; + + struct page **pages; + size_t buffer_size; + uint32_t buffer_free; + struct list_head todo; + wait_queue_head_t wait; + struct binder_stats stats; + struct list_head delivered_death; + int max_threads; + int requested_threads; + int requested_threads_started; + int ready_threads; + long default_priority; + struct dentry *debugfs_entry; +}; + +enum { + BINDER_LOOPER_STATE_REGISTERED = 0x01, + BINDER_LOOPER_STATE_ENTERED = 0x02, + BINDER_LOOPER_STATE_EXITED = 0x04, + BINDER_LOOPER_STATE_INVALID = 0x08, + BINDER_LOOPER_STATE_WAITING = 0x10, + BINDER_LOOPER_STATE_NEED_RETURN = 0x20 +}; + +struct binder_thread { + struct binder_proc *proc; + struct rb_node rb_node; + int pid; + int looper; + struct binder_transaction *transaction_stack; + struct list_head todo; + uint32_t return_error; /* Write failed, return error code in read buf */ + uint32_t return_error2; /* Write failed, return error code in read */ + /* buffer. Used when sending a reply to a dead process that */ + /* we are also waiting on */ + wait_queue_head_t wait; + struct binder_stats stats; +}; + +struct binder_transaction { + int debug_id; + struct binder_work work; + struct binder_thread *from; + struct binder_transaction *from_parent; + struct binder_proc *to_proc; + struct binder_thread *to_thread; + struct binder_transaction *to_parent; + unsigned need_reply:1; + /* unsigned is_dead:1; */ /* not used at the moment */ + + struct binder_buffer *buffer; + unsigned int code; + unsigned int flags; + long priority; + long saved_priority; + uid_t sender_euid; +}; + +static void +binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); + +/* + * copied from get_unused_fd_flags + */ +int task_get_unused_fd_flags(struct binder_proc *proc, int flags) +{ + struct files_struct *files = proc->files; + int fd, error; + struct fdtable *fdt; + unsigned long rlim_cur; + unsigned long irqs; + + if (files == NULL) + return -ESRCH; + + error = -EMFILE; + spin_lock(&files->file_lock); + +repeat: + fdt = files_fdtable(files); + fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds, + files->next_fd); + + /* + * N.B. For clone tasks sharing a files structure, this test + * will limit the total number of files that can be opened. + */ + rlim_cur = 0; + if (lock_task_sighand(proc->tsk, &irqs)) { + rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; + unlock_task_sighand(proc->tsk, &irqs); + } + if (fd >= rlim_cur) + goto out; + + /* Do we need to expand the fd array or fd set? */ + error = expand_files(files, fd); + if (error < 0) + goto out; + + if (error) { + /* + * If we needed to expand the fs array we + * might have blocked - try again. + */ + error = -EMFILE; + goto repeat; + } + + FD_SET(fd, fdt->open_fds); + if (flags & O_CLOEXEC) + FD_SET(fd, fdt->close_on_exec); + else + FD_CLR(fd, fdt->close_on_exec); + files->next_fd = fd + 1; +#if 1 + /* Sanity check */ + if (fdt->fd[fd] != NULL) { + printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); + fdt->fd[fd] = NULL; + } +#endif + error = fd; + +out: + spin_unlock(&files->file_lock); + return error; +} + +/* + * copied from fd_install + */ +static void task_fd_install( + struct binder_proc *proc, unsigned int fd, struct file *file) +{ + struct files_struct *files = proc->files; + struct fdtable *fdt; + + if (files == NULL) + return; + + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + BUG_ON(fdt->fd[fd] != NULL); + rcu_assign_pointer(fdt->fd[fd], file); + spin_unlock(&files->file_lock); +} + +/* + * copied from __put_unused_fd in open.c + */ +static void __put_unused_fd(struct files_struct *files, unsigned int fd) +{ + struct fdtable *fdt = files_fdtable(files); + __FD_CLR(fd, fdt->open_fds); + if (fd < files->next_fd) + files->next_fd = fd; +} + +/* + * copied from sys_close + */ +static long task_close_fd(struct binder_proc *proc, unsigned int fd) +{ + struct file *filp; + struct files_struct *files = proc->files; + struct fdtable *fdt; + int retval; + + if (files == NULL) + return -ESRCH; + + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + if (fd >= fdt->max_fds) + goto out_unlock; + filp = fdt->fd[fd]; + if (!filp) + goto out_unlock; + rcu_assign_pointer(fdt->fd[fd], NULL); + FD_CLR(fd, fdt->close_on_exec); + __put_unused_fd(files, fd); + spin_unlock(&files->file_lock); + retval = filp_close(filp, files); + + /* can't restart close syscall because file table entry was cleared */ + if (unlikely(retval == -ERESTARTSYS || + retval == -ERESTARTNOINTR || + retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK)) + retval = -EINTR; + + return retval; + +out_unlock: + spin_unlock(&files->file_lock); + return -EBADF; +} + +static void binder_set_nice(long nice) +{ + long min_nice; + if (can_nice(current, nice)) { + set_user_nice(current, nice); + return; + } + min_nice = 20 - current->signal->rlim[RLIMIT_NICE].rlim_cur; + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "binder: %d: nice value %ld not allowed use " + "%ld instead\n", current->pid, nice, min_nice); + set_user_nice(current, min_nice); + if (min_nice < 20) + return; + binder_user_error("binder: %d RLIMIT_NICE not set\n", current->pid); +} + +static size_t binder_buffer_size(struct binder_proc *proc, + struct binder_buffer *buffer) +{ + if (list_is_last(&buffer->entry, &proc->buffers)) + return proc->buffer + proc->buffer_size - (void *)buffer->data; + else + return (size_t)list_entry(buffer->entry.next, + struct binder_buffer, entry) - (size_t)buffer->data; +} + +static void binder_insert_free_buffer(struct binder_proc *proc, + struct binder_buffer *new_buffer) +{ + struct rb_node **p = &proc->free_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + size_t buffer_size; + size_t new_buffer_size; + + BUG_ON(!new_buffer->free); + + new_buffer_size = binder_buffer_size(proc, new_buffer); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: add free buffer, size %zd, " + "at %p\n", proc->pid, new_buffer_size, new_buffer); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + + buffer_size = binder_buffer_size(proc, buffer); + + if (new_buffer_size < buffer_size) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &proc->free_buffers); +} + +static void binder_insert_allocated_buffer(struct binder_proc *proc, + struct binder_buffer *new_buffer) +{ + struct rb_node **p = &proc->allocated_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + + BUG_ON(new_buffer->free); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (new_buffer < buffer) + p = &parent->rb_left; + else if (new_buffer > buffer) + p = &parent->rb_right; + else + BUG(); + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers); +} + +static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, + void __user *user_ptr) +{ + struct rb_node *n = proc->allocated_buffers.rb_node; + struct binder_buffer *buffer; + struct binder_buffer *kern_ptr; + + kern_ptr = user_ptr - proc->user_buffer_offset + - offsetof(struct binder_buffer, data); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (kern_ptr < buffer) + n = n->rb_left; + else if (kern_ptr > buffer) + n = n->rb_right; + else + return buffer; + } + return NULL; +} + +static int binder_update_page_range(struct binder_proc *proc, int allocate, + void *start, void *end, + struct vm_area_struct *vma) +{ + void *page_addr; + unsigned long user_page_addr; + struct vm_struct tmp_area; + struct page **page; + struct mm_struct *mm; + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: %s pages %p-%p\n", proc->pid, + allocate ? "allocate" : "free", start, end); + + if (end <= start) + return 0; + + if (vma) + mm = NULL; + else + mm = get_task_mm(proc->tsk); + + if (mm) { + down_write(&mm->mmap_sem); + vma = proc->vma; + } + + if (allocate == 0) + goto free_range; + + if (vma == NULL) { + printk(KERN_ERR "binder: %d: binder_alloc_buf failed to " + "map pages in userspace, no vma\n", proc->pid); + goto err_no_vma; + } + + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + int ret; + struct page **page_array_ptr; + page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; + + BUG_ON(*page); + *page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (*page == NULL) { + printk(KERN_ERR "binder: %d: binder_alloc_buf failed " + "for page at %p\n", proc->pid, page_addr); + goto err_alloc_page_failed; + } + tmp_area.addr = page_addr; + tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */; + page_array_ptr = page; + ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr); + if (ret) { + printk(KERN_ERR "binder: %d: binder_alloc_buf failed " + "to map page at %p in kernel\n", + proc->pid, page_addr); + goto err_map_kernel_failed; + } + user_page_addr = + (uintptr_t)page_addr + proc->user_buffer_offset; + ret = vm_insert_page(vma, user_page_addr, page[0]); + if (ret) { + printk(KERN_ERR "binder: %d: binder_alloc_buf failed " + "to map page at %lx in userspace\n", + proc->pid, user_page_addr); + goto err_vm_insert_page_failed; + } + /* vm_insert_page does not seem to increment the refcount */ + } + if (mm) { + up_write(&mm->mmap_sem); + mmput(mm); + } + return 0; + +free_range: + for (page_addr = end - PAGE_SIZE; page_addr >= start; + page_addr -= PAGE_SIZE) { + page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; + if (vma) + zap_page_range(vma, (uintptr_t)page_addr + + proc->user_buffer_offset, PAGE_SIZE, NULL); +err_vm_insert_page_failed: + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); +err_map_kernel_failed: + __free_page(*page); + *page = NULL; +err_alloc_page_failed: + ; + } +err_no_vma: + if (mm) { + up_write(&mm->mmap_sem); + mmput(mm); + } + return -ENOMEM; +} + +static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, + size_t data_size, + size_t offsets_size, int is_async) +{ + struct rb_node *n = proc->free_buffers.rb_node; + struct binder_buffer *buffer; + size_t buffer_size; + struct rb_node *best_fit = NULL; + void *has_page_addr; + void *end_page_addr; + size_t size; + + if (proc->vma == NULL) { + printk(KERN_ERR "binder: %d: binder_alloc_buf, no vma\n", + proc->pid); + return NULL; + } + + size = ALIGN(data_size, sizeof(void *)) + + ALIGN(offsets_size, sizeof(void *)); + + if (size < data_size || size < offsets_size) { + binder_user_error("binder: %d: got transaction with invalid " + "size %zd-%zd\n", proc->pid, data_size, offsets_size); + return NULL; + } + + if (is_async && + proc->free_async_space < size + sizeof(struct binder_buffer)) { + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: binder_alloc_buf size %zd" + "failed, no async space left\n", proc->pid, size); + return NULL; + } + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + buffer_size = binder_buffer_size(proc, buffer); + + if (size < buffer_size) { + best_fit = n; + n = n->rb_left; + } else if (size > buffer_size) + n = n->rb_right; + else { + best_fit = n; + break; + } + } + if (best_fit == NULL) { + printk(KERN_ERR "binder: %d: binder_alloc_buf size %zd failed, " + "no address space\n", proc->pid, size); + return NULL; + } + if (n == NULL) { + buffer = rb_entry(best_fit, struct binder_buffer, rb_node); + buffer_size = binder_buffer_size(proc, buffer); + } + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: binder_alloc_buf size %zd got buff" + "er %p size %zd\n", proc->pid, size, buffer, buffer_size); + + has_page_addr = + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); + if (n == NULL) { + if (size + sizeof(struct binder_buffer) + 4 >= buffer_size) + buffer_size = size; /* no room for other buffers */ + else + buffer_size = size + sizeof(struct binder_buffer); + } + end_page_addr = + (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size); + if (end_page_addr > has_page_addr) + end_page_addr = has_page_addr; + if (binder_update_page_range(proc, 1, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) + return NULL; + + rb_erase(best_fit, &proc->free_buffers); + buffer->free = 0; + binder_insert_allocated_buffer(proc, buffer); + if (buffer_size != size) { + struct binder_buffer *new_buffer = (void *)buffer->data + size; + list_add(&new_buffer->entry, &buffer->entry); + new_buffer->free = 1; + binder_insert_free_buffer(proc, new_buffer); + } + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: binder_alloc_buf size %zd got " + "%p\n", proc->pid, size, buffer); + buffer->data_size = data_size; + buffer->offsets_size = offsets_size; + buffer->async_transaction = is_async; + if (is_async) { + proc->free_async_space -= size + sizeof(struct binder_buffer); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "binder: %d: binder_alloc_buf size %zd " + "async free %zd\n", proc->pid, size, + proc->free_async_space); + } + + return buffer; +} + +static void *buffer_start_page(struct binder_buffer *buffer) +{ + return (void *)((uintptr_t)buffer & PAGE_MASK); +} + +static void *buffer_end_page(struct binder_buffer *buffer) +{ + return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK); +} + +static void binder_delete_free_buffer(struct binder_proc *proc, + struct binder_buffer *buffer) +{ + struct binder_buffer *prev, *next = NULL; + int free_page_end = 1; + int free_page_start = 1; + + BUG_ON(proc->buffers.next == &buffer->entry); + prev = list_entry(buffer->entry.prev, struct binder_buffer, entry); + BUG_ON(!prev->free); + if (buffer_end_page(prev) == buffer_start_page(buffer)) { + free_page_start = 0; + if (buffer_end_page(prev) == buffer_end_page(buffer)) + free_page_end = 0; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: merge free, buffer %p " + "share page with %p\n", proc->pid, buffer, prev); + } + + if (!list_is_last(&buffer->entry, &proc->buffers)) { + next = list_entry(buffer->entry.next, + struct binder_buffer, entry); + if (buffer_start_page(next) == buffer_end_page(buffer)) { + free_page_end = 0; + if (buffer_start_page(next) == + buffer_start_page(buffer)) + free_page_start = 0; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: merge free, buffer" + " %p share page with %p\n", proc->pid, + buffer, prev); + } + } + list_del(&buffer->entry); + if (free_page_start || free_page_end) { + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: merge free, buffer %p do " + "not share page%s%s with with %p or %p\n", + proc->pid, buffer, free_page_start ? "" : " end", + free_page_end ? "" : " start", prev, next); + binder_update_page_range(proc, 0, free_page_start ? + buffer_start_page(buffer) : buffer_end_page(buffer), + (free_page_end ? buffer_end_page(buffer) : + buffer_start_page(buffer)) + PAGE_SIZE, NULL); + } +} + +static void binder_free_buf(struct binder_proc *proc, + struct binder_buffer *buffer) +{ + size_t size, buffer_size; + + buffer_size = binder_buffer_size(proc, buffer); + + size = ALIGN(buffer->data_size, sizeof(void *)) + + ALIGN(buffer->offsets_size, sizeof(void *)); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder: %d: binder_free_buf %p size %zd buffer" + "_size %zd\n", proc->pid, buffer, size, buffer_size); + + BUG_ON(buffer->free); + BUG_ON(size > buffer_size); + BUG_ON(buffer->transaction != NULL); + BUG_ON((void *)buffer < proc->buffer); + BUG_ON((void *)buffer > proc->buffer + proc->buffer_size); + + if (buffer->async_transaction) { + proc->free_async_space += size + sizeof(struct binder_buffer); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "binder: %d: binder_free_buf size %zd " + "async free %zd\n", proc->pid, size, + proc->free_async_space); + } + + binder_update_page_range(proc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), + NULL); + rb_erase(&buffer->rb_node, &proc->allocated_buffers); + buffer->free = 1; + if (!list_is_last(&buffer->entry, &proc->buffers)) { + struct binder_buffer *next = list_entry(buffer->entry.next, + struct binder_buffer, entry); + if (next->free) { + rb_erase(&next->rb_node, &proc->free_buffers); + binder_delete_free_buffer(proc, next); + } + } + if (proc->buffers.next != &buffer->entry) { + struct binder_buffer *prev = list_entry(buffer->entry.prev, + struct binder_buffer, entry); + if (prev->free) { + binder_delete_free_buffer(proc, buffer); + rb_erase(&prev->rb_node, &proc->free_buffers); + buffer = prev; + } + } + binder_insert_free_buffer(proc, buffer); +} + +static struct binder_node *binder_get_node(struct binder_proc *proc, + void __user *ptr) +{ + struct rb_node *n = proc->nodes.rb_node; + struct binder_node *node; + + while (n) { + node = rb_entry(n, struct binder_node, rb_node); + + if (ptr < node->ptr) + n = n->rb_left; + else if (ptr > node->ptr) + n = n->rb_right; + else + return node; + } + return NULL; +} + +static struct binder_node *binder_new_node(struct binder_proc *proc, + void __user *ptr, + void __user *cookie) +{ + struct rb_node **p = &proc->nodes.rb_node; + struct rb_node *parent = NULL; + struct binder_node *node; + + while (*p) { + parent = *p; + node = rb_entry(parent, struct binder_node, rb_node); + + if (ptr < node->ptr) + p = &(*p)->rb_left; + else if (ptr > node->ptr) + p = &(*p)->rb_right; + else + return NULL; + } + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (node == NULL) + return NULL; + binder_stats_created(BINDER_STAT_NODE); + rb_link_node(&node->rb_node, parent, p); + rb_insert_color(&node->rb_node, &proc->nodes); + node->debug_id = ++binder_last_id; + node->proc = proc; + node->ptr = ptr; + node->cookie = cookie; + node->work.type = BINDER_WORK_NODE; + INIT_LIST_HEAD(&node->work.entry); + INIT_LIST_HEAD(&node->async_todo); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: %d:%d node %d u%p c%p created\n", + proc->pid, current->pid, node->debug_id, + node->ptr, node->cookie); + return node; +} + +static int binder_inc_node(struct binder_node *node, int strong, int internal, + struct list_head *target_list) +{ + if (strong) { + if (internal) { + if (target_list == NULL && + node->internal_strong_refs == 0 && + !(node == binder_context_mgr_node && + node->has_strong_ref)) { + printk(KERN_ERR "binder: invalid inc strong " + "node for %d\n", node->debug_id); + return -EINVAL; + } + node->internal_strong_refs++; + } else + node->local_strong_refs++; + if (!node->has_strong_ref && target_list) { + list_del_init(&node->work.entry); + list_add_tail(&node->work.entry, target_list); + } + } else { + if (!internal) + node->local_weak_refs++; + if (!node->has_weak_ref && list_empty(&node->work.entry)) { + if (target_list == NULL) { + printk(KERN_ERR "binder: invalid inc weak node " + "for %d\n", node->debug_id); + return -EINVAL; + } + list_add_tail(&node->work.entry, target_list); + } + } + return 0; +} + +static int binder_dec_node(struct binder_node *node, int strong, int internal) +{ + if (strong) { + if (internal) + node->internal_strong_refs--; + else + node->local_strong_refs--; + if (node->local_strong_refs || node->internal_strong_refs) + return 0; + } else { + if (!internal) + node->local_weak_refs--; + if (node->local_weak_refs || !hlist_empty(&node->refs)) + return 0; + } + if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { + if (list_empty(&node->work.entry)) { + list_add_tail(&node->work.entry, &node->proc->todo); + wake_up_interruptible(&node->proc->wait); + } + } else { + if (hlist_empty(&node->refs) && !node->local_strong_refs && + !node->local_weak_refs) { + list_del_init(&node->work.entry); + if (node->proc) { + rb_erase(&node->rb_node, &node->proc->nodes); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: refless node %d deleted\n", + node->debug_id); + } else { + hlist_del(&node->dead_node); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: dead node %d deleted\n", + node->debug_id); + } + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); + } + } + + return 0; +} + + +static struct binder_ref *binder_get_ref(struct binder_proc *proc, + uint32_t desc) +{ + struct rb_node *n = proc->refs_by_desc.rb_node; + struct binder_ref *ref; + + while (n) { + ref = rb_entry(n, struct binder_ref, rb_node_desc); + + if (desc < ref->desc) + n = n->rb_left; + else if (desc > ref->desc) + n = n->rb_right; + else + return ref; + } + return NULL; +} + +static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, + struct binder_node *node) +{ + struct rb_node *n; + struct rb_node **p = &proc->refs_by_node.rb_node; + struct rb_node *parent = NULL; + struct binder_ref *ref, *new_ref; + + while (*p) { + parent = *p; + ref = rb_entry(parent, struct binder_ref, rb_node_node); + + if (node < ref->node) + p = &(*p)->rb_left; + else if (node > ref->node) + p = &(*p)->rb_right; + else + return ref; + } + new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (new_ref == NULL) + return NULL; + binder_stats_created(BINDER_STAT_REF); + new_ref->debug_id = ++binder_last_id; + new_ref->proc = proc; + new_ref->node = node; + rb_link_node(&new_ref->rb_node_node, parent, p); + rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); + + new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1; + for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { + ref = rb_entry(n, struct binder_ref, rb_node_desc); + if (ref->desc > new_ref->desc) + break; + new_ref->desc = ref->desc + 1; + } + + p = &proc->refs_by_desc.rb_node; + while (*p) { + parent = *p; + ref = rb_entry(parent, struct binder_ref, rb_node_desc); + + if (new_ref->desc < ref->desc) + p = &(*p)->rb_left; + else if (new_ref->desc > ref->desc) + p = &(*p)->rb_right; + else + BUG(); + } + rb_link_node(&new_ref->rb_node_desc, parent, p); + rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); + if (node) { + hlist_add_head(&new_ref->node_entry, &node->refs); + + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: %d new ref %d desc %d for " + "node %d\n", proc->pid, new_ref->debug_id, + new_ref->desc, node->debug_id); + } else { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: %d new ref %d desc %d for " + "dead node\n", proc->pid, new_ref->debug_id, + new_ref->desc); + } + return new_ref; +} + +static void binder_delete_ref(struct binder_ref *ref) +{ + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: %d delete ref %d desc %d for " + "node %d\n", ref->proc->pid, ref->debug_id, + ref->desc, ref->node->debug_id); + + rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); + rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); + if (ref->strong) + binder_dec_node(ref->node, 1, 1); + hlist_del(&ref->node_entry); + binder_dec_node(ref->node, 0, 1); + if (ref->death) { + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "binder: %d delete ref %d desc %d " + "has death notification\n", ref->proc->pid, + ref->debug_id, ref->desc); + list_del(&ref->death->work.entry); + kfree(ref->death); + binder_stats_deleted(BINDER_STAT_DEATH); + } + kfree(ref); + binder_stats_deleted(BINDER_STAT_REF); +} + +static int binder_inc_ref(struct binder_ref *ref, int strong, + struct list_head *target_list) +{ + int ret; + if (strong) { + if (ref->strong == 0) { + ret = binder_inc_node(ref->node, 1, 1, target_list); + if (ret) + return ret; + } + ref->strong++; + } else { + if (ref->weak == 0) { + ret = binder_inc_node(ref->node, 0, 1, target_list); + if (ret) + return ret; + } + ref->weak++; + } + return 0; +} + + +static int binder_dec_ref(struct binder_ref *ref, int strong) +{ + if (strong) { + if (ref->strong == 0) { + binder_user_error("binder: %d invalid dec strong, " + "ref %d desc %d s %d w %d\n", + ref->proc->pid, ref->debug_id, + ref->desc, ref->strong, ref->weak); + return -EINVAL; + } + ref->strong--; + if (ref->strong == 0) { + int ret; + ret = binder_dec_node(ref->node, strong, 1); + if (ret) + return ret; + } + } else { + if (ref->weak == 0) { + binder_user_error("binder: %d invalid dec weak, " + "ref %d desc %d s %d w %d\n", + ref->proc->pid, ref->debug_id, + ref->desc, ref->strong, ref->weak); + return -EINVAL; + } + ref->weak--; + } + if (ref->strong == 0 && ref->weak == 0) + binder_delete_ref(ref); + return 0; +} + +static void binder_pop_transaction(struct binder_thread *target_thread, + struct binder_transaction *t) +{ + if (target_thread) { + BUG_ON(target_thread->transaction_stack != t); + BUG_ON(target_thread->transaction_stack->from != target_thread); + target_thread->transaction_stack = + target_thread->transaction_stack->from_parent; + t->from = NULL; + } + t->need_reply = 0; + if (t->buffer) + t->buffer->transaction = NULL; + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); +} + +static void binder_send_failed_reply(struct binder_transaction *t, + uint32_t error_code) +{ + struct binder_thread *target_thread; + BUG_ON(t->flags & TF_ONE_WAY); + while (1) { + target_thread = t->from; + if (target_thread) { + if (target_thread->return_error != BR_OK && + target_thread->return_error2 == BR_OK) { + target_thread->return_error2 = + target_thread->return_error; + target_thread->return_error = BR_OK; + } + if (target_thread->return_error == BR_OK) { + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "binder: send failed reply for " + "transaction %d to %d:%d\n", + t->debug_id, target_thread->proc->pid, + target_thread->pid); + + binder_pop_transaction(target_thread, t); + target_thread->return_error = error_code; + wake_up_interruptible(&target_thread->wait); + } else { + printk(KERN_ERR "binder: reply failed, target " + "thread, %d:%d, has error code %d " + "already\n", target_thread->proc->pid, + target_thread->pid, + target_thread->return_error); + } + return; + } else { + struct binder_transaction *next = t->from_parent; + + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "binder: send failed reply " + "for transaction %d, target dead\n", + t->debug_id); + + binder_pop_transaction(target_thread, t); + if (next == NULL) { + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "binder: reply failed," + " no target thread at root\n"); + return; + } + t = next; + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "binder: reply failed, no target " + "thread -- retry %d\n", t->debug_id); + } + } +} + +static void binder_transaction_buffer_release(struct binder_proc *proc, + struct binder_buffer *buffer, + size_t *failed_at) +{ + size_t *offp, *off_end; + int debug_id = buffer->debug_id; + + binder_debug(BINDER_DEBUG_TRANSACTION, + "binder: %d buffer release %d, size %zd-%zd, failed at %p\n", + proc->pid, buffer->debug_id, + buffer->data_size, buffer->offsets_size, failed_at); + + if (buffer->target_node) + binder_dec_node(buffer->target_node, 1, 0); + + offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *))); + if (failed_at) + off_end = failed_at; + else + off_end = (void *)offp + buffer->offsets_size; + for (; offp < off_end; offp++) { + struct flat_binder_object *fp; + if (*offp > buffer->data_size - sizeof(*fp) || + buffer->data_size < sizeof(*fp) || + !IS_ALIGNED(*offp, sizeof(void *))) { + printk(KERN_ERR "binder: transaction release %d bad" + "offset %zd, size %zd\n", debug_id, + *offp, buffer->data_size); + continue; + } + fp = (struct flat_binder_object *)(buffer->data + *offp); + switch (fp->type) { + case BINDER_TYPE_BINDER: + case BINDER_TYPE_WEAK_BINDER: { + struct binder_node *node = binder_get_node(proc, fp->binder); + if (node == NULL) { + printk(KERN_ERR "binder: transaction release %d" + " bad node %p\n", debug_id, fp->binder); + break; + } + binder_debug(BINDER_DEBUG_TRANSACTION, + " node %d u%p\n", + node->debug_id, node->ptr); + binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); + } break; + case BINDER_TYPE_HANDLE: + case BINDER_TYPE_WEAK_HANDLE: { + struct binder_ref *ref = binder_get_ref(proc, fp->handle); + if (ref == NULL) { + printk(KERN_ERR "binder: transaction release %d" + " bad handle %ld\n", debug_id, + fp->handle); + break; + } + binder_debug(BINDER_DEBUG_TRANSACTION, + " ref %d desc %d (node %d)\n", + ref->debug_id, ref->desc, ref->node->debug_id); + binder_dec_ref(ref, fp->type == BINDER_TYPE_HANDLE); + } break; + + case BINDER_TYPE_FD: + binder_debug(BINDER_DEBUG_TRANSACTION, + " fd %ld\n", fp->handle); + if (failed_at) + task_close_fd(proc, fp->handle); + break; + + default: + printk(KERN_ERR "binder: transaction release %d bad " + "object type %lx\n", debug_id, fp->type); + break; + } + } +} + +static void binder_transaction(struct binder_proc *proc, + struct binder_thread *thread, + struct binder_transaction_data *tr, int reply) +{ + struct binder_transaction *t; + struct binder_work *tcomplete; + size_t *offp, *off_end; + struct binder_proc *target_proc; + struct binder_thread *target_thread = NULL; + struct binder_node *target_node = NULL; + struct list_head *target_list; + wait_queue_head_t *target_wait; + struct binder_transaction *in_reply_to = NULL; + struct binder_transaction_log_entry *e; + uint32_t return_error; + + e = binder_transaction_log_add(&binder_transaction_log); + e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); + e->from_proc = proc->pid; + e->from_thread = thread->pid; + e->target_handle = tr->target.handle; + e->data_size = tr->data_size; + e->offsets_size = tr->offsets_size; + + if (reply) { + in_reply_to = thread->transaction_stack; + if (in_reply_to == NULL) { + binder_user_error("binder: %d:%d got reply transaction " + "with no transaction stack\n", + proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + goto err_empty_call_stack; + } + binder_set_nice(in_reply_to->saved_priority); + if (in_reply_to->to_thread != thread) { + binder_user_error("binder: %d:%d got reply transaction " + "with bad transaction stack," + " transaction %d has target %d:%d\n", + proc->pid, thread->pid, in_reply_to->debug_id, + in_reply_to->to_proc ? + in_reply_to->to_proc->pid : 0, + in_reply_to->to_thread ? + in_reply_to->to_thread->pid : 0); + return_error = BR_FAILED_REPLY; + in_reply_to = NULL; + goto err_bad_call_stack; + } + thread->transaction_stack = in_reply_to->to_parent; + target_thread = in_reply_to->from; + if (target_thread == NULL) { + return_error = BR_DEAD_REPLY; + goto err_dead_binder; + } + if (target_thread->transaction_stack != in_reply_to) { + binder_user_error("binder: %d:%d got reply transaction " + "with bad target transaction stack %d, " + "expected %d\n", + proc->pid, thread->pid, + target_thread->transaction_stack ? + target_thread->transaction_stack->debug_id : 0, + in_reply_to->debug_id); + return_error = BR_FAILED_REPLY; + in_reply_to = NULL; + target_thread = NULL; + goto err_dead_binder; + } + target_proc = target_thread->proc; + } else { + if (tr->target.handle) { + struct binder_ref *ref; + ref = binder_get_ref(proc, tr->target.handle); + if (ref == NULL) { + binder_user_error("binder: %d:%d got " + "transaction to invalid handle\n", + proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + goto err_invalid_target_handle; + } + target_node = ref->node; + } else { + target_node = binder_context_mgr_node; + if (target_node == NULL) { + return_error = BR_DEAD_REPLY; + goto err_no_context_mgr_node; + } + } + e->to_node = target_node->debug_id; + target_proc = target_node->proc; + if (target_proc == NULL) { + return_error = BR_DEAD_REPLY; + goto err_dead_binder; + } + if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { + struct binder_transaction *tmp; + tmp = thread->transaction_stack; + if (tmp->to_thread != thread) { + binder_user_error("binder: %d:%d got new " + "transaction with bad transaction stack" + ", transaction %d has target %d:%d\n", + proc->pid, thread->pid, tmp->debug_id, + tmp->to_proc ? tmp->to_proc->pid : 0, + tmp->to_thread ? + tmp->to_thread->pid : 0); + return_error = BR_FAILED_REPLY; + goto err_bad_call_stack; + } + while (tmp) { + if (tmp->from && tmp->from->proc == target_proc) + target_thread = tmp->from; + tmp = tmp->from_parent; + } + } + } + if (target_thread) { + e->to_thread = target_thread->pid; + target_list = &target_thread->todo; + target_wait = &target_thread->wait; + } else { + target_list = &target_proc->todo; + target_wait = &target_proc->wait; + } + e->to_proc = target_proc->pid; + + /* TODO: reuse incoming transaction for reply */ + t = kzalloc(sizeof(*t), GFP_KERNEL); + if (t == NULL) { + return_error = BR_FAILED_REPLY; + goto err_alloc_t_failed; + } + binder_stats_created(BINDER_STAT_TRANSACTION); + + tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); + if (tcomplete == NULL) { + return_error = BR_FAILED_REPLY; + goto err_alloc_tcomplete_failed; + } + binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); + + t->debug_id = ++binder_last_id; + e->debug_id = t->debug_id; + + if (reply) + binder_debug(BINDER_DEBUG_TRANSACTION, + "binder: %d:%d BC_REPLY %d -> %d:%d, " + "data %p-%p size %zd-%zd\n", + proc->pid, thread->pid, t->debug_id, + target_proc->pid, target_thread->pid, + tr->data.ptr.buffer, tr->data.ptr.offsets, + tr->data_size, tr->offsets_size); + else + binder_debug(BINDER_DEBUG_TRANSACTION, + "binder: %d:%d BC_TRANSACTION %d -> " + "%d - node %d, data %p-%p size %zd-%zd\n", + proc->pid, thread->pid, t->debug_id, + target_proc->pid, target_node->debug_id, + tr->data.ptr.buffer, tr->data.ptr.offsets, + tr->data_size, tr->offsets_size); + + if (!reply && !(tr->flags & TF_ONE_WAY)) + t->from = thread; + else + t->from = NULL; + t->sender_euid = proc->tsk->cred->euid; + t->to_proc = target_proc; + t->to_thread = target_thread; + t->code = tr->code; + t->flags = tr->flags; + t->priority = task_nice(current); + t->buffer = binder_alloc_buf(target_proc, tr->data_size, + tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); + if (t->buffer == NULL) { + return_error = BR_FAILED_REPLY; + goto err_binder_alloc_buf_failed; + } + t->buffer->allow_user_free = 0; + t->buffer->debug_id = t->debug_id; + t->buffer->transaction = t; + t->buffer->target_node = target_node; + if (target_node) + binder_inc_node(target_node, 1, 0, NULL); + + offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); + + if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { + binder_user_error("binder: %d:%d got transaction with invalid " + "data ptr\n", proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + goto err_copy_data_failed; + } + if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { + binder_user_error("binder: %d:%d got transaction with invalid " + "offsets ptr\n", proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + goto err_copy_data_failed; + } + if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { + binder_user_error("binder: %d:%d got transaction with " + "invalid offsets size, %zd\n", + proc->pid, thread->pid, tr->offsets_size); + return_error = BR_FAILED_REPLY; + goto err_bad_offset; + } + off_end = (void *)offp + tr->offsets_size; + for (; offp < off_end; offp++) { + struct flat_binder_object *fp; + if (*offp > t->buffer->data_size - sizeof(*fp) || + t->buffer->data_size < sizeof(*fp) || + !IS_ALIGNED(*offp, sizeof(void *))) { + binder_user_error("binder: %d:%d got transaction with " + "invalid offset, %zd\n", + proc->pid, thread->pid, *offp); + return_error = BR_FAILED_REPLY; + goto err_bad_offset; + } + fp = (struct flat_binder_object *)(t->buffer->data + *offp); + switch (fp->type) { + case BINDER_TYPE_BINDER: + case BINDER_TYPE_WEAK_BINDER: { + struct binder_ref *ref; + struct binder_node *node = binder_get_node(proc, fp->binder); + if (node == NULL) { + node = binder_new_node(proc, fp->binder, fp->cookie); + if (node == NULL) { + return_error = BR_FAILED_REPLY; + goto err_binder_new_node_failed; + } + node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; + node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); + } + if (fp->cookie != node->cookie) { + binder_user_error("binder: %d:%d sending u%p " + "node %d, cookie mismatch %p != %p\n", + proc->pid, thread->pid, + fp->binder, node->debug_id, + fp->cookie, node->cookie); + goto err_binder_get_ref_for_node_failed; + } + ref = binder_get_ref_for_node(target_proc, node); + if (ref == NULL) { + return_error = BR_FAILED_REPLY; + goto err_binder_get_ref_for_node_failed; + } + if (fp->type == BINDER_TYPE_BINDER) + fp->type = BINDER_TYPE_HANDLE; + else + fp->type = BINDER_TYPE_WEAK_HANDLE; + fp->handle = ref->desc; + binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, + &thread->todo); + + binder_debug(BINDER_DEBUG_TRANSACTION, + " node %d u%p -> ref %d desc %d\n", + node->debug_id, node->ptr, ref->debug_id, + ref->desc); + } break; + case BINDER_TYPE_HANDLE: + case BINDER_TYPE_WEAK_HANDLE: { + struct binder_ref *ref = binder_get_ref(proc, fp->handle); + if (ref == NULL) { + binder_user_error("binder: %d:%d got " + "transaction with invalid " + "handle, %ld\n", proc->pid, + thread->pid, fp->handle); + return_error = BR_FAILED_REPLY; + goto err_binder_get_ref_failed; + } + if (ref->node->proc == target_proc) { + if (fp->type == BINDER_TYPE_HANDLE) + fp->type = BINDER_TYPE_BINDER; + else + fp->type = BINDER_TYPE_WEAK_BINDER; + fp->binder = ref->node->ptr; + fp->cookie = ref->node->cookie; + binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); + binder_debug(BINDER_DEBUG_TRANSACTION, + " ref %d desc %d -> node %d u%p\n", + ref->debug_id, ref->desc, ref->node->debug_id, + ref->node->ptr); + } else { + struct binder_ref *new_ref; + new_ref = binder_get_ref_for_node(target_proc, ref->node); + if (new_ref == NULL) { + return_error = BR_FAILED_REPLY; + goto err_binder_get_ref_for_node_failed; + } + fp->handle = new_ref->desc; + binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); + binder_debug(BINDER_DEBUG_TRANSACTION, + " ref %d desc %d -> ref %d desc %d (node %d)\n", + ref->debug_id, ref->desc, new_ref->debug_id, + new_ref->desc, ref->node->debug_id); + } + } break; + + case BINDER_TYPE_FD: { + int target_fd; + struct file *file; + + if (reply) { + if (!(in_reply_to->flags & TF_ACCEPT_FDS)) { + binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n", + proc->pid, thread->pid, fp->handle); + return_error = BR_FAILED_REPLY; + goto err_fd_not_allowed; + } + } else if (!target_node->accept_fds) { + binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n", + proc->pid, thread->pid, fp->handle); + return_error = BR_FAILED_REPLY; + goto err_fd_not_allowed; + } + + file = fget(fp->handle); + if (file == NULL) { + binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n", + proc->pid, thread->pid, fp->handle); + return_error = BR_FAILED_REPLY; + goto err_fget_failed; + } + target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); + if (target_fd < 0) { + fput(file); + return_error = BR_FAILED_REPLY; + goto err_get_unused_fd_failed; + } + task_fd_install(target_proc, target_fd, file); + binder_debug(BINDER_DEBUG_TRANSACTION, + " fd %ld -> %d\n", fp->handle, target_fd); + /* TODO: fput? */ + fp->handle = target_fd; + } break; + + default: + binder_user_error("binder: %d:%d got transactio" + "n with invalid object type, %lx\n", + proc->pid, thread->pid, fp->type); + return_error = BR_FAILED_REPLY; + goto err_bad_object_type; + } + } + if (reply) { + BUG_ON(t->buffer->async_transaction != 0); + binder_pop_transaction(target_thread, in_reply_to); + } else if (!(t->flags & TF_ONE_WAY)) { + BUG_ON(t->buffer->async_transaction != 0); + t->need_reply = 1; + t->from_parent = thread->transaction_stack; + thread->transaction_stack = t; + } else { + BUG_ON(target_node == NULL); + BUG_ON(t->buffer->async_transaction != 1); + if (target_node->has_async_transaction) { + target_list = &target_node->async_todo; + target_wait = NULL; + } else + target_node->has_async_transaction = 1; + } + t->work.type = BINDER_WORK_TRANSACTION; + list_add_tail(&t->work.entry, target_list); + tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + list_add_tail(&tcomplete->entry, &thread->todo); + if (target_wait) + wake_up_interruptible(target_wait); + return; + +err_get_unused_fd_failed: +err_fget_failed: +err_fd_not_allowed: +err_binder_get_ref_for_node_failed: +err_binder_get_ref_failed: +err_binder_new_node_failed: +err_bad_object_type: +err_bad_offset: +err_copy_data_failed: + binder_transaction_buffer_release(target_proc, t->buffer, offp); + t->buffer->transaction = NULL; + binder_free_buf(target_proc, t->buffer); +err_binder_alloc_buf_failed: + kfree(tcomplete); + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); +err_alloc_tcomplete_failed: + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); +err_alloc_t_failed: +err_bad_call_stack: +err_empty_call_stack: +err_dead_binder: +err_invalid_target_handle: +err_no_context_mgr_node: + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "binder: %d:%d transaction failed %d, size %zd-%zd\n", + proc->pid, thread->pid, return_error, + tr->data_size, tr->offsets_size); + + { + struct binder_transaction_log_entry *fe; + fe = binder_transaction_log_add(&binder_transaction_log_failed); + *fe = *e; + } + + BUG_ON(thread->return_error != BR_OK); + if (in_reply_to) { + thread->return_error = BR_TRANSACTION_COMPLETE; + binder_send_failed_reply(in_reply_to, return_error); + } else + thread->return_error = return_error; +} + +int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, + void __user *buffer, int size, signed long *consumed) +{ + uint32_t cmd; + void __user *ptr = buffer + *consumed; + void __user *end = buffer + size; + + while (ptr < end && thread->return_error == BR_OK) { + if (get_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { + binder_stats.bc[_IOC_NR(cmd)]++; + proc->stats.bc[_IOC_NR(cmd)]++; + thread->stats.bc[_IOC_NR(cmd)]++; + } + switch (cmd) { + case BC_INCREFS: + case BC_ACQUIRE: + case BC_RELEASE: + case BC_DECREFS: { + uint32_t target; + struct binder_ref *ref; + const char *debug_string; + + if (get_user(target, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (target == 0 && binder_context_mgr_node && + (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) { + ref = binder_get_ref_for_node(proc, + binder_context_mgr_node); + if (ref->desc != target) { + binder_user_error("binder: %d:" + "%d tried to acquire " + "reference to desc 0, " + "got %d instead\n", + proc->pid, thread->pid, + ref->desc); + } + } else + ref = binder_get_ref(proc, target); + if (ref == NULL) { + binder_user_error("binder: %d:%d refcou" + "nt change on invalid ref %d\n", + proc->pid, thread->pid, target); + break; + } + switch (cmd) { + case BC_INCREFS: + debug_string = "IncRefs"; + binder_inc_ref(ref, 0, NULL); + break; + case BC_ACQUIRE: + debug_string = "Acquire"; + binder_inc_ref(ref, 1, NULL); + break; + case BC_RELEASE: + debug_string = "Release"; + binder_dec_ref(ref, 1); + break; + case BC_DECREFS: + default: + debug_string = "DecRefs"; + binder_dec_ref(ref, 0); + break; + } + binder_debug(BINDER_DEBUG_USER_REFS, + "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n", + proc->pid, thread->pid, debug_string, ref->debug_id, + ref->desc, ref->strong, ref->weak, ref->node->debug_id); + break; + } + case BC_INCREFS_DONE: + case BC_ACQUIRE_DONE: { + void __user *node_ptr; + void *cookie; + struct binder_node *node; + + if (get_user(node_ptr, (void * __user *)ptr)) + return -EFAULT; + ptr += sizeof(void *); + if (get_user(cookie, (void * __user *)ptr)) + return -EFAULT; + ptr += sizeof(void *); + node = binder_get_node(proc, node_ptr); + if (node == NULL) { + binder_user_error("binder: %d:%d " + "%s u%p no match\n", + proc->pid, thread->pid, + cmd == BC_INCREFS_DONE ? + "BC_INCREFS_DONE" : + "BC_ACQUIRE_DONE", + node_ptr); + break; + } + if (cookie != node->cookie) { + binder_user_error("binder: %d:%d %s u%p node %d" + " cookie mismatch %p != %p\n", + proc->pid, thread->pid, + cmd == BC_INCREFS_DONE ? + "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", + node_ptr, node->debug_id, + cookie, node->cookie); + break; + } + if (cmd == BC_ACQUIRE_DONE) { + if (node->pending_strong_ref == 0) { + binder_user_error("binder: %d:%d " + "BC_ACQUIRE_DONE node %d has " + "no pending acquire request\n", + proc->pid, thread->pid, + node->debug_id); + break; + } + node->pending_strong_ref = 0; + } else { + if (node->pending_weak_ref == 0) { + binder_user_error("binder: %d:%d " + "BC_INCREFS_DONE node %d has " + "no pending increfs request\n", + proc->pid, thread->pid, + node->debug_id); + break; + } + node->pending_weak_ref = 0; + } + binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); + binder_debug(BINDER_DEBUG_USER_REFS, + "binder: %d:%d %s node %d ls %d lw %d\n", + proc->pid, thread->pid, + cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", + node->debug_id, node->local_strong_refs, node->local_weak_refs); + break; + } + case BC_ATTEMPT_ACQUIRE: + printk(KERN_ERR "binder: BC_ATTEMPT_ACQUIRE not supported\n"); + return -EINVAL; + case BC_ACQUIRE_RESULT: + printk(KERN_ERR "binder: BC_ACQUIRE_RESULT not supported\n"); + return -EINVAL; + + case BC_FREE_BUFFER: { + void __user *data_ptr; + struct binder_buffer *buffer; + + if (get_user(data_ptr, (void * __user *)ptr)) + return -EFAULT; + ptr += sizeof(void *); + + buffer = binder_buffer_lookup(proc, data_ptr); + if (buffer == NULL) { + binder_user_error("binder: %d:%d " + "BC_FREE_BUFFER u%p no match\n", + proc->pid, thread->pid, data_ptr); + break; + } + if (!buffer->allow_user_free) { + binder_user_error("binder: %d:%d " + "BC_FREE_BUFFER u%p matched " + "unreturned buffer\n", + proc->pid, thread->pid, data_ptr); + break; + } + binder_debug(BINDER_DEBUG_FREE_BUFFER, + "binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", + proc->pid, thread->pid, data_ptr, buffer->debug_id, + buffer->transaction ? "active" : "finished"); + + if (buffer->transaction) { + buffer->transaction->buffer = NULL; + buffer->transaction = NULL; + } + if (buffer->async_transaction && buffer->target_node) { + BUG_ON(!buffer->target_node->has_async_transaction); + if (list_empty(&buffer->target_node->async_todo)) + buffer->target_node->has_async_transaction = 0; + else + list_move_tail(buffer->target_node->async_todo.next, &thread->todo); + } + binder_transaction_buffer_release(proc, buffer, NULL); + binder_free_buf(proc, buffer); + break; + } + + case BC_TRANSACTION: + case BC_REPLY: { + struct binder_transaction_data tr; + + if (copy_from_user(&tr, ptr, sizeof(tr))) + return -EFAULT; + ptr += sizeof(tr); + binder_transaction(proc, thread, &tr, cmd == BC_REPLY); + break; + } + + case BC_REGISTER_LOOPER: + binder_debug(BINDER_DEBUG_THREADS, + "binder: %d:%d BC_REGISTER_LOOPER\n", + proc->pid, thread->pid); + if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { + thread->looper |= BINDER_LOOPER_STATE_INVALID; + binder_user_error("binder: %d:%d ERROR:" + " BC_REGISTER_LOOPER called " + "after BC_ENTER_LOOPER\n", + proc->pid, thread->pid); + } else if (proc->requested_threads == 0) { + thread->looper |= BINDER_LOOPER_STATE_INVALID; + binder_user_error("binder: %d:%d ERROR:" + " BC_REGISTER_LOOPER called " + "without request\n", + proc->pid, thread->pid); + } else { + proc->requested_threads--; + proc->requested_threads_started++; + } + thread->looper |= BINDER_LOOPER_STATE_REGISTERED; + break; + case BC_ENTER_LOOPER: + binder_debug(BINDER_DEBUG_THREADS, + "binder: %d:%d BC_ENTER_LOOPER\n", + proc->pid, thread->pid); + if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) { + thread->looper |= BINDER_LOOPER_STATE_INVALID; + binder_user_error("binder: %d:%d ERROR:" + " BC_ENTER_LOOPER called after " + "BC_REGISTER_LOOPER\n", + proc->pid, thread->pid); + } + thread->looper |= BINDER_LOOPER_STATE_ENTERED; + break; + case BC_EXIT_LOOPER: + binder_debug(BINDER_DEBUG_THREADS, + "binder: %d:%d BC_EXIT_LOOPER\n", + proc->pid, thread->pid); + thread->looper |= BINDER_LOOPER_STATE_EXITED; + break; + + case BC_REQUEST_DEATH_NOTIFICATION: + case BC_CLEAR_DEATH_NOTIFICATION: { + uint32_t target; + void __user *cookie; + struct binder_ref *ref; + struct binder_ref_death *death; + + if (get_user(target, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (get_user(cookie, (void __user * __user *)ptr)) + return -EFAULT; + ptr += sizeof(void *); + ref = binder_get_ref(proc, target); + if (ref == NULL) { + binder_user_error("binder: %d:%d %s " + "invalid ref %d\n", + proc->pid, thread->pid, + cmd == BC_REQUEST_DEATH_NOTIFICATION ? + "BC_REQUEST_DEATH_NOTIFICATION" : + "BC_CLEAR_DEATH_NOTIFICATION", + target); + break; + } + + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, + "binder: %d:%d %s %p ref %d desc %d s %d w %d for node %d\n", + proc->pid, thread->pid, + cmd == BC_REQUEST_DEATH_NOTIFICATION ? + "BC_REQUEST_DEATH_NOTIFICATION" : + "BC_CLEAR_DEATH_NOTIFICATION", + cookie, ref->debug_id, ref->desc, + ref->strong, ref->weak, ref->node->debug_id); + + if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { + if (ref->death) { + binder_user_error("binder: %d:%" + "d BC_REQUEST_DEATH_NOTI" + "FICATION death notific" + "ation already set\n", + proc->pid, thread->pid); + break; + } + death = kzalloc(sizeof(*death), GFP_KERNEL); + if (death == NULL) { + thread->return_error = BR_ERROR; + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "binder: %d:%d " + "BC_REQUEST_DEATH_NOTIFICATION failed\n", + proc->pid, thread->pid); + break; + } + binder_stats_created(BINDER_STAT_DEATH); + INIT_LIST_HEAD(&death->work.entry); + death->cookie = cookie; + ref->death = death; + if (ref->node->proc == NULL) { + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&ref->death->work.entry, &thread->todo); + } else { + list_add_tail(&ref->death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); + } + } + } else { + if (ref->death == NULL) { + binder_user_error("binder: %d:%" + "d BC_CLEAR_DEATH_NOTIFI" + "CATION death notificat" + "ion not active\n", + proc->pid, thread->pid); + break; + } + death = ref->death; + if (death->cookie != cookie) { + binder_user_error("binder: %d:%" + "d BC_CLEAR_DEATH_NOTIFI" + "CATION death notificat" + "ion cookie mismatch " + "%p != %p\n", + proc->pid, thread->pid, + death->cookie, cookie); + break; + } + ref->death = NULL; + if (list_empty(&death->work.entry)) { + death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&death->work.entry, &thread->todo); + } else { + list_add_tail(&death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); + } + } else { + BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); + death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; + } + } + } break; + case BC_DEAD_BINDER_DONE: { + struct binder_work *w; + void __user *cookie; + struct binder_ref_death *death = NULL; + if (get_user(cookie, (void __user * __user *)ptr)) + return -EFAULT; + + ptr += sizeof(void *); + list_for_each_entry(w, &proc->delivered_death, entry) { + struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); + if (tmp_death->cookie == cookie) { + death = tmp_death; + break; + } + } + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "binder: %d:%d BC_DEAD_BINDER_DONE %p found %p\n", + proc->pid, thread->pid, cookie, death); + if (death == NULL) { + binder_user_error("binder: %d:%d BC_DEAD" + "_BINDER_DONE %p not found\n", + proc->pid, thread->pid, cookie); + break; + } + + list_del_init(&death->work.entry); + if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { + death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&death->work.entry, &thread->todo); + } else { + list_add_tail(&death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); + } + } + } break; + + default: + printk(KERN_ERR "binder: %d:%d unknown command %d\n", + proc->pid, thread->pid, cmd); + return -EINVAL; + } + *consumed = ptr - buffer; + } + return 0; +} + +void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, + uint32_t cmd) +{ + if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { + binder_stats.br[_IOC_NR(cmd)]++; + proc->stats.br[_IOC_NR(cmd)]++; + thread->stats.br[_IOC_NR(cmd)]++; + } +} + +static int binder_has_proc_work(struct binder_proc *proc, + struct binder_thread *thread) +{ + return !list_empty(&proc->todo) || + (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); +} + +static int binder_has_thread_work(struct binder_thread *thread) +{ + return !list_empty(&thread->todo) || thread->return_error != BR_OK || + (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); +} + +static int binder_thread_read(struct binder_proc *proc, + struct binder_thread *thread, + void __user *buffer, int size, + signed long *consumed, int non_block) +{ + void __user *ptr = buffer + *consumed; + void __user *end = buffer + size; + + int ret = 0; + int wait_for_proc_work; + + if (*consumed == 0) { + if (put_user(BR_NOOP, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + } + +retry: + wait_for_proc_work = thread->transaction_stack == NULL && + list_empty(&thread->todo); + + if (thread->return_error != BR_OK && ptr < end) { + if (thread->return_error2 != BR_OK) { + if (put_user(thread->return_error2, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (ptr == end) + goto done; + thread->return_error2 = BR_OK; + } + if (put_user(thread->return_error, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + thread->return_error = BR_OK; + goto done; + } + + + thread->looper |= BINDER_LOOPER_STATE_WAITING; + if (wait_for_proc_work) + proc->ready_threads++; + mutex_unlock(&binder_lock); + if (wait_for_proc_work) { + if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED))) { + binder_user_error("binder: %d:%d ERROR: Thread waiting " + "for process work before calling BC_REGISTER_" + "LOOPER or BC_ENTER_LOOPER (state %x)\n", + proc->pid, thread->pid, thread->looper); + wait_event_interruptible(binder_user_error_wait, + binder_stop_on_user_error < 2); + } + binder_set_nice(proc->default_priority); + if (non_block) { + if (!binder_has_proc_work(proc, thread)) + ret = -EAGAIN; + } else + ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread)); + } else { + if (non_block) { + if (!binder_has_thread_work(thread)) + ret = -EAGAIN; + } else + ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread)); + } + mutex_lock(&binder_lock); + if (wait_for_proc_work) + proc->ready_threads--; + thread->looper &= ~BINDER_LOOPER_STATE_WAITING; + + if (ret) + return ret; + + while (1) { + uint32_t cmd; + struct binder_transaction_data tr; + struct binder_work *w; + struct binder_transaction *t = NULL; + + if (!list_empty(&thread->todo)) + w = list_first_entry(&thread->todo, struct binder_work, entry); + else if (!list_empty(&proc->todo) && wait_for_proc_work) + w = list_first_entry(&proc->todo, struct binder_work, entry); + else { + if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */ + goto retry; + break; + } + + if (end - ptr < sizeof(tr) + 4) + break; + + switch (w->type) { + case BINDER_WORK_TRANSACTION: { + t = container_of(w, struct binder_transaction, work); + } break; + case BINDER_WORK_TRANSACTION_COMPLETE: { + cmd = BR_TRANSACTION_COMPLETE; + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, + "binder: %d:%d BR_TRANSACTION_COMPLETE\n", + proc->pid, thread->pid); + + list_del(&w->entry); + kfree(w); + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); + } break; + case BINDER_WORK_NODE: { + struct binder_node *node = container_of(w, struct binder_node, work); + uint32_t cmd = BR_NOOP; + const char *cmd_name; + int strong = node->internal_strong_refs || node->local_strong_refs; + int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; + if (weak && !node->has_weak_ref) { + cmd = BR_INCREFS; + cmd_name = "BR_INCREFS"; + node->has_weak_ref = 1; + node->pending_weak_ref = 1; + node->local_weak_refs++; + } else if (strong && !node->has_strong_ref) { + cmd = BR_ACQUIRE; + cmd_name = "BR_ACQUIRE"; + node->has_strong_ref = 1; + node->pending_strong_ref = 1; + node->local_strong_refs++; + } else if (!strong && node->has_strong_ref) { + cmd = BR_RELEASE; + cmd_name = "BR_RELEASE"; + node->has_strong_ref = 0; + } else if (!weak && node->has_weak_ref) { + cmd = BR_DECREFS; + cmd_name = "BR_DECREFS"; + node->has_weak_ref = 0; + } + if (cmd != BR_NOOP) { + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user(node->ptr, (void * __user *)ptr)) + return -EFAULT; + ptr += sizeof(void *); + if (put_user(node->cookie, (void * __user *)ptr)) + return -EFAULT; + ptr += sizeof(void *); + + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_USER_REFS, + "binder: %d:%d %s %d u%p c%p\n", + proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie); + } else { + list_del_init(&w->entry); + if (!weak && !strong) { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: %d:%d node %d u%p c%p deleted\n", + proc->pid, thread->pid, node->debug_id, + node->ptr, node->cookie); + rb_erase(&node->rb_node, &proc->nodes); + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); + } else { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "binder: %d:%d node %d u%p c%p state unchanged\n", + proc->pid, thread->pid, node->debug_id, node->ptr, + node->cookie); + } + } + } break; + case BINDER_WORK_DEAD_BINDER: + case BINDER_WORK_DEAD_BINDER_AND_CLEAR: + case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { + struct binder_ref_death *death; + uint32_t cmd; + + death = container_of(w, struct binder_ref_death, work); + if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) + cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; + else + cmd = BR_DEAD_BINDER; + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user(death->cookie, (void * __user *)ptr)) + return -EFAULT; + ptr += sizeof(void *); + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, + "binder: %d:%d %s %p\n", + proc->pid, thread->pid, + cmd == BR_DEAD_BINDER ? + "BR_DEAD_BINDER" : + "BR_CLEAR_DEATH_NOTIFICATION_DONE", + death->cookie); + + if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { + list_del(&w->entry); + kfree(death); + binder_stats_deleted(BINDER_STAT_DEATH); + } else + list_move(&w->entry, &proc->delivered_death); + if (cmd == BR_DEAD_BINDER) + goto done; /* DEAD_BINDER notifications can cause transactions */ + } break; + } + + if (!t) + continue; + + BUG_ON(t->buffer == NULL); + if (t->buffer->target_node) { + struct binder_node *target_node = t->buffer->target_node; + tr.target.ptr = target_node->ptr; + tr.cookie = target_node->cookie; + t->saved_priority = task_nice(current); + if (t->priority < target_node->min_priority && + !(t->flags & TF_ONE_WAY)) + binder_set_nice(t->priority); + else if (!(t->flags & TF_ONE_WAY) || + t->saved_priority > target_node->min_priority) + binder_set_nice(target_node->min_priority); + cmd = BR_TRANSACTION; + } else { + tr.target.ptr = NULL; + tr.cookie = NULL; + cmd = BR_REPLY; + } + tr.code = t->code; + tr.flags = t->flags; + tr.sender_euid = t->sender_euid; + + if (t->from) { + struct task_struct *sender = t->from->proc->tsk; + tr.sender_pid = task_tgid_nr_ns(sender, + current->nsproxy->pid_ns); + } else { + tr.sender_pid = 0; + } + + tr.data_size = t->buffer->data_size; + tr.offsets_size = t->buffer->offsets_size; + tr.data.ptr.buffer = (void *)t->buffer->data + + proc->user_buffer_offset; + tr.data.ptr.offsets = tr.data.ptr.buffer + + ALIGN(t->buffer->data_size, + sizeof(void *)); + + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (copy_to_user(ptr, &tr, sizeof(tr))) + return -EFAULT; + ptr += sizeof(tr); + + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_TRANSACTION, + "binder: %d:%d %s %d %d:%d, cmd %d" + "size %zd-%zd ptr %p-%p\n", + proc->pid, thread->pid, + (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : + "BR_REPLY", + t->debug_id, t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, cmd, + t->buffer->data_size, t->buffer->offsets_size, + tr.data.ptr.buffer, tr.data.ptr.offsets); + + list_del(&t->work.entry); + t->buffer->allow_user_free = 1; + if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { + t->to_parent = thread->transaction_stack; + t->to_thread = thread; + thread->transaction_stack = t; + } else { + t->buffer->transaction = NULL; + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); + } + break; + } + +done: + + *consumed = ptr - buffer; + if (proc->requested_threads + proc->ready_threads == 0 && + proc->requested_threads_started < proc->max_threads && + (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ + /*spawn a new thread if we leave this out */) { + proc->requested_threads++; + binder_debug(BINDER_DEBUG_THREADS, + "binder: %d:%d BR_SPAWN_LOOPER\n", + proc->pid, thread->pid); + if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) + return -EFAULT; + } + return 0; +} + +static void binder_release_work(struct list_head *list) +{ + struct binder_work *w; + while (!list_empty(list)) { + w = list_first_entry(list, struct binder_work, entry); + list_del_init(&w->entry); + switch (w->type) { + case BINDER_WORK_TRANSACTION: { + struct binder_transaction *t; + + t = container_of(w, struct binder_transaction, work); + if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) + binder_send_failed_reply(t, BR_DEAD_REPLY); + } break; + case BINDER_WORK_TRANSACTION_COMPLETE: { + kfree(w); + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); + } break; + default: + break; + } + } + +} + +static struct binder_thread *binder_get_thread(struct binder_proc *proc) +{ + struct binder_thread *thread = NULL; + struct rb_node *parent = NULL; + struct rb_node **p = &proc->threads.rb_node; + + while (*p) { + parent = *p; + thread = rb_entry(parent, struct binder_thread, rb_node); + + if (current->pid < thread->pid) + p = &(*p)->rb_left; + else if (current->pid > thread->pid) + p = &(*p)->rb_right; + else + break; + } + if (*p == NULL) { + thread = kzalloc(sizeof(*thread), GFP_KERNEL); + if (thread == NULL) + return NULL; + binder_stats_created(BINDER_STAT_THREAD); + thread->proc = proc; + thread->pid = current->pid; + init_waitqueue_head(&thread->wait); + INIT_LIST_HEAD(&thread->todo); + rb_link_node(&thread->rb_node, parent, p); + rb_insert_color(&thread->rb_node, &proc->threads); + thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; + thread->return_error = BR_OK; + thread->return_error2 = BR_OK; + } + return thread; +} + +static int binder_free_thread(struct binder_proc *proc, + struct binder_thread *thread) +{ + struct binder_transaction *t; + struct binder_transaction *send_reply = NULL; + int active_transactions = 0; + + rb_erase(&thread->rb_node, &proc->threads); + t = thread->transaction_stack; + if (t && t->to_thread == thread) + send_reply = t; + while (t) { + active_transactions++; + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "binder: release %d:%d transaction %d " + "%s, still active\n", proc->pid, thread->pid, + t->debug_id, + (t->to_thread == thread) ? "in" : "out"); + + if (t->to_thread == thread) { + t->to_proc = NULL; + t->to_thread = NULL; + if (t->buffer) { + t->buffer->transaction = NULL; + t->buffer = NULL; + } + t = t->to_parent; + } else if (t->from == thread) { + t->from = NULL; + t = t->from_parent; + } else + BUG(); + } + if (send_reply) + binder_send_failed_reply(send_reply, BR_DEAD_REPLY); + binder_release_work(&thread->todo); + kfree(thread); + binder_stats_deleted(BINDER_STAT_THREAD); + return active_transactions; +} + +static unsigned int binder_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct binder_proc *proc = filp->private_data; + struct binder_thread *thread = NULL; + int wait_for_proc_work; + + mutex_lock(&binder_lock); + thread = binder_get_thread(proc); + + wait_for_proc_work = thread->transaction_stack == NULL && + list_empty(&thread->todo) && thread->return_error == BR_OK; + mutex_unlock(&binder_lock); + + if (wait_for_proc_work) { + if (binder_has_proc_work(proc, thread)) + return POLLIN; + poll_wait(filp, &proc->wait, wait); + if (binder_has_proc_work(proc, thread)) + return POLLIN; + } else { + if (binder_has_thread_work(thread)) + return POLLIN; + poll_wait(filp, &thread->wait, wait); + if (binder_has_thread_work(thread)) + return POLLIN; + } + return 0; +} + +static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret; + struct binder_proc *proc = filp->private_data; + struct binder_thread *thread; + unsigned int size = _IOC_SIZE(cmd); + void __user *ubuf = (void __user *)arg; + + /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ + + ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); + if (ret) + return ret; + + mutex_lock(&binder_lock); + thread = binder_get_thread(proc); + if (thread == NULL) { + ret = -ENOMEM; + goto err; + } + + switch (cmd) { + case BINDER_WRITE_READ: { + struct binder_write_read bwr; + if (size != sizeof(struct binder_write_read)) { + ret = -EINVAL; + goto err; + } + if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { + ret = -EFAULT; + goto err; + } + binder_debug(BINDER_DEBUG_READ_WRITE, + "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n", + proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, + bwr.read_size, bwr.read_buffer); + + if (bwr.write_size > 0) { + ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); + if (ret < 0) { + bwr.read_consumed = 0; + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) + ret = -EFAULT; + goto err; + } + } + if (bwr.read_size > 0) { + ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); + if (!list_empty(&proc->todo)) + wake_up_interruptible(&proc->wait); + if (ret < 0) { + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) + ret = -EFAULT; + goto err; + } + } + binder_debug(BINDER_DEBUG_READ_WRITE, + "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n", + proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, + bwr.read_consumed, bwr.read_size); + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { + ret = -EFAULT; + goto err; + } + break; + } + case BINDER_SET_MAX_THREADS: + if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { + ret = -EINVAL; + goto err; + } + break; + case BINDER_SET_CONTEXT_MGR: + if (binder_context_mgr_node != NULL) { + printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n"); + ret = -EBUSY; + goto err; + } + if (binder_context_mgr_uid != -1) { + if (binder_context_mgr_uid != current->cred->euid) { + printk(KERN_ERR "binder: BINDER_SET_" + "CONTEXT_MGR bad uid %d != %d\n", + current->cred->euid, + binder_context_mgr_uid); + ret = -EPERM; + goto err; + } + } else + binder_context_mgr_uid = current->cred->euid; + binder_context_mgr_node = binder_new_node(proc, NULL, NULL); + if (binder_context_mgr_node == NULL) { + ret = -ENOMEM; + goto err; + } + binder_context_mgr_node->local_weak_refs++; + binder_context_mgr_node->local_strong_refs++; + binder_context_mgr_node->has_strong_ref = 1; + binder_context_mgr_node->has_weak_ref = 1; + break; + case BINDER_THREAD_EXIT: + binder_debug(BINDER_DEBUG_THREADS, "binder: %d:%d exit\n", + proc->pid, thread->pid); + binder_free_thread(proc, thread); + thread = NULL; + break; + case BINDER_VERSION: + if (size != sizeof(struct binder_version)) { + ret = -EINVAL; + goto err; + } + if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) { + ret = -EINVAL; + goto err; + } + break; + default: + ret = -EINVAL; + goto err; + } + ret = 0; +err: + if (thread) + thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; + mutex_unlock(&binder_lock); + wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); + if (ret && ret != -ERESTARTSYS) + printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); + return ret; +} + +static void binder_vma_open(struct vm_area_struct *vma) +{ + struct binder_proc *proc = vma->vm_private_data; + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", + proc->pid, vma->vm_start, vma->vm_end, + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); + dump_stack(); +} + +static void binder_vma_close(struct vm_area_struct *vma) +{ + struct binder_proc *proc = vma->vm_private_data; + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", + proc->pid, vma->vm_start, vma->vm_end, + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); + proc->vma = NULL; + binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); +} + +static struct vm_operations_struct binder_vm_ops = { + .open = binder_vma_open, + .close = binder_vma_close, +}; + +static int binder_mmap(struct file *filp, struct vm_area_struct *vma) +{ + int ret; + struct vm_struct *area; + struct binder_proc *proc = filp->private_data; + const char *failure_string; + struct binder_buffer *buffer; + + if ((vma->vm_end - vma->vm_start) > SZ_4M) + vma->vm_end = vma->vm_start + SZ_4M; + + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", + proc->pid, vma->vm_start, vma->vm_end, + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); + + if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) { + ret = -EPERM; + failure_string = "bad vm_flags"; + goto err_bad_arg; + } + vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; + + if (proc->buffer) { + ret = -EBUSY; + failure_string = "already mapped"; + goto err_already_mapped; + } + + area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); + if (area == NULL) { + ret = -ENOMEM; + failure_string = "get_vm_area"; + goto err_get_vm_area_failed; + } + proc->buffer = area->addr; + proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; + +#ifdef CONFIG_CPU_CACHE_VIPT + if (cache_is_vipt_aliasing()) { + while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { + printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); + vma->vm_start += PAGE_SIZE; + } + } +#endif + proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL); + if (proc->pages == NULL) { + ret = -ENOMEM; + failure_string = "alloc page array"; + goto err_alloc_pages_failed; + } + proc->buffer_size = vma->vm_end - vma->vm_start; + + vma->vm_ops = &binder_vm_ops; + vma->vm_private_data = proc; + + if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) { + ret = -ENOMEM; + failure_string = "alloc small buf"; + goto err_alloc_small_buf_failed; + } + buffer = proc->buffer; + INIT_LIST_HEAD(&proc->buffers); + list_add(&buffer->entry, &proc->buffers); + buffer->free = 1; + binder_insert_free_buffer(proc, buffer); + proc->free_async_space = proc->buffer_size / 2; + barrier(); + proc->files = get_files_struct(current); + proc->vma = vma; + + /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", + proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ + return 0; + +err_alloc_small_buf_failed: + kfree(proc->pages); + proc->pages = NULL; +err_alloc_pages_failed: + vfree(proc->buffer); + proc->buffer = NULL; +err_get_vm_area_failed: +err_already_mapped: +err_bad_arg: + printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", + proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); + return ret; +} + +static int binder_open(struct inode *nodp, struct file *filp) +{ + struct binder_proc *proc; + + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", + current->group_leader->pid, current->pid); + + proc = kzalloc(sizeof(*proc), GFP_KERNEL); + if (proc == NULL) + return -ENOMEM; + get_task_struct(current); + proc->tsk = current; + INIT_LIST_HEAD(&proc->todo); + init_waitqueue_head(&proc->wait); + proc->default_priority = task_nice(current); + mutex_lock(&binder_lock); + binder_stats_created(BINDER_STAT_PROC); + hlist_add_head(&proc->proc_node, &binder_procs); + proc->pid = current->group_leader->pid; + INIT_LIST_HEAD(&proc->delivered_death); + filp->private_data = proc; + mutex_unlock(&binder_lock); + + if (binder_debugfs_dir_entry_proc) { + char strbuf[11]; + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); + proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + binder_debugfs_dir_entry_proc, proc, &binder_proc_fops); + } + + return 0; +} + +static int binder_flush(struct file *filp, fl_owner_t id) +{ + struct binder_proc *proc = filp->private_data; + + binder_defer_work(proc, BINDER_DEFERRED_FLUSH); + + return 0; +} + +static void binder_deferred_flush(struct binder_proc *proc) +{ + struct rb_node *n; + int wake_count = 0; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); + thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; + if (thread->looper & BINDER_LOOPER_STATE_WAITING) { + wake_up_interruptible(&thread->wait); + wake_count++; + } + } + wake_up_interruptible_all(&proc->wait); + + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "binder_flush: %d woke %d threads\n", proc->pid, + wake_count); +} + +static int binder_release(struct inode *nodp, struct file *filp) +{ + struct binder_proc *proc = filp->private_data; + debugfs_remove(proc->debugfs_entry); + binder_defer_work(proc, BINDER_DEFERRED_RELEASE); + + return 0; +} + +static void binder_deferred_release(struct binder_proc *proc) +{ + struct hlist_node *pos; + struct binder_transaction *t; + struct rb_node *n; + int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; + + BUG_ON(proc->vma); + BUG_ON(proc->files); + + hlist_del(&proc->proc_node); + if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "binder_release: %d context_mgr_node gone\n", + proc->pid); + binder_context_mgr_node = NULL; + } + + threads = 0; + active_transactions = 0; + while ((n = rb_first(&proc->threads))) { + struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); + threads++; + active_transactions += binder_free_thread(proc, thread); + } + nodes = 0; + incoming_refs = 0; + while ((n = rb_first(&proc->nodes))) { + struct binder_node *node = rb_entry(n, struct binder_node, rb_node); + + nodes++; + rb_erase(&node->rb_node, &proc->nodes); + list_del_init(&node->work.entry); + if (hlist_empty(&node->refs)) { + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); + } else { + struct binder_ref *ref; + int death = 0; + + node->proc = NULL; + node->local_strong_refs = 0; + node->local_weak_refs = 0; + hlist_add_head(&node->dead_node, &binder_dead_nodes); + + hlist_for_each_entry(ref, pos, &node->refs, node_entry) { + incoming_refs++; + if (ref->death) { + death++; + if (list_empty(&ref->death->work.entry)) { + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + list_add_tail(&ref->death->work.entry, &ref->proc->todo); + wake_up_interruptible(&ref->proc->wait); + } else + BUG(); + } + } + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "binder: node %d now dead, " + "refs %d, death %d\n", node->debug_id, + incoming_refs, death); + } + } + outgoing_refs = 0; + while ((n = rb_first(&proc->refs_by_desc))) { + struct binder_ref *ref = rb_entry(n, struct binder_ref, + rb_node_desc); + outgoing_refs++; + binder_delete_ref(ref); + } + binder_release_work(&proc->todo); + buffers = 0; + + while ((n = rb_first(&proc->allocated_buffers))) { + struct binder_buffer *buffer = rb_entry(n, struct binder_buffer, + rb_node); + t = buffer->transaction; + if (t) { + t->buffer = NULL; + buffer->transaction = NULL; + printk(KERN_ERR "binder: release proc %d, " + "transaction %d, not freed\n", + proc->pid, t->debug_id); + /*BUG();*/ + } + binder_free_buf(proc, buffer); + buffers++; + } + + binder_stats_deleted(BINDER_STAT_PROC); + + page_count = 0; + if (proc->pages) { + int i; + for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { + if (proc->pages[i]) { + void *page_addr = proc->buffer + i * PAGE_SIZE; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "binder_release: %d: " + "page %d at %p not freed\n", + proc->pid, i, + page_addr); + unmap_kernel_range((unsigned long)page_addr, + PAGE_SIZE); + __free_page(proc->pages[i]); + page_count++; + } + } + kfree(proc->pages); + vfree(proc->buffer); + } + + put_task_struct(proc->tsk); + + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "binder_release: %d threads %d, nodes %d (ref %d), " + "refs %d, active transactions %d, buffers %d, " + "pages %d\n", + proc->pid, threads, nodes, incoming_refs, outgoing_refs, + active_transactions, buffers, page_count); + + kfree(proc); +} + +static void binder_deferred_func(struct work_struct *work) +{ + struct binder_proc *proc; + struct files_struct *files; + + int defer; + do { + mutex_lock(&binder_lock); + mutex_lock(&binder_deferred_lock); + if (!hlist_empty(&binder_deferred_list)) { + proc = hlist_entry(binder_deferred_list.first, + struct binder_proc, deferred_work_node); + hlist_del_init(&proc->deferred_work_node); + defer = proc->deferred_work; + proc->deferred_work = 0; + } else { + proc = NULL; + defer = 0; + } + mutex_unlock(&binder_deferred_lock); + + files = NULL; + if (defer & BINDER_DEFERRED_PUT_FILES) { + files = proc->files; + if (files) + proc->files = NULL; + } + + if (defer & BINDER_DEFERRED_FLUSH) + binder_deferred_flush(proc); + + if (defer & BINDER_DEFERRED_RELEASE) + binder_deferred_release(proc); /* frees proc */ + + mutex_unlock(&binder_lock); + if (files) + put_files_struct(files); + } while (proc); +} +static DECLARE_WORK(binder_deferred_work, binder_deferred_func); + +static void +binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) +{ + mutex_lock(&binder_deferred_lock); + proc->deferred_work |= defer; + if (hlist_unhashed(&proc->deferred_work_node)) { + hlist_add_head(&proc->deferred_work_node, + &binder_deferred_list); + queue_work(binder_deferred_workqueue, &binder_deferred_work); + } + mutex_unlock(&binder_deferred_lock); +} + +static void print_binder_transaction(struct seq_file *m, const char *prefix, + struct binder_transaction *t) +{ + seq_printf(m, + "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", + prefix, t->debug_id, t, + t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, + t->to_proc ? t->to_proc->pid : 0, + t->to_thread ? t->to_thread->pid : 0, + t->code, t->flags, t->priority, t->need_reply); + if (t->buffer == NULL) { + seq_puts(m, " buffer free\n"); + return; + } + if (t->buffer->target_node) + seq_printf(m, " node %d", + t->buffer->target_node->debug_id); + seq_printf(m, " size %zd:%zd data %p\n", + t->buffer->data_size, t->buffer->offsets_size, + t->buffer->data); +} + +static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) +{ + seq_printf(m, "%s %d: %p size %zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, + buffer->data_size, buffer->offsets_size, + buffer->transaction ? "active" : "delivered"); +} + +static void print_binder_work(struct seq_file *m, const char *prefix, + const char *transaction_prefix, + struct binder_work *w) +{ + struct binder_node *node; + struct binder_transaction *t; + + switch (w->type) { + case BINDER_WORK_TRANSACTION: + t = container_of(w, struct binder_transaction, work); + print_binder_transaction(m, transaction_prefix, t); + break; + case BINDER_WORK_TRANSACTION_COMPLETE: + seq_printf(m, "%stransaction complete\n", prefix); + break; + case BINDER_WORK_NODE: + node = container_of(w, struct binder_node, work); + seq_printf(m, "%snode work %d: u%p c%p\n", + prefix, node->debug_id, node->ptr, node->cookie); + break; + case BINDER_WORK_DEAD_BINDER: + seq_printf(m, "%shas dead binder\n", prefix); + break; + case BINDER_WORK_DEAD_BINDER_AND_CLEAR: + seq_printf(m, "%shas cleared dead binder\n", prefix); + break; + case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: + seq_printf(m, "%shas cleared death notification\n", prefix); + break; + default: + seq_printf(m, "%sunknown work: type %d\n", prefix, w->type); + break; + } +} + +static void print_binder_thread(struct seq_file *m, + struct binder_thread *thread, + int print_always) +{ + struct binder_transaction *t; + struct binder_work *w; + size_t start_pos = m->count; + size_t header_pos; + + seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); + header_pos = m->count; + t = thread->transaction_stack; + while (t) { + if (t->from == thread) { + print_binder_transaction(m, + " outgoing transaction", t); + t = t->from_parent; + } else if (t->to_thread == thread) { + print_binder_transaction(m, + " incoming transaction", t); + t = t->to_parent; + } else { + print_binder_transaction(m, " bad transaction", t); + t = NULL; + } + } + list_for_each_entry(w, &thread->todo, entry) { + print_binder_work(m, " ", " pending transaction", w); + } + if (!print_always && m->count == header_pos) + m->count = start_pos; +} + +static void print_binder_node(struct seq_file *m, struct binder_node *node) +{ + struct binder_ref *ref; + struct hlist_node *pos; + struct binder_work *w; + int count; + + count = 0; + hlist_for_each_entry(ref, pos, &node->refs, node_entry) + count++; + + seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", + node->debug_id, node->ptr, node->cookie, + node->has_strong_ref, node->has_weak_ref, + node->local_strong_refs, node->local_weak_refs, + node->internal_strong_refs, count); + if (count) { + seq_puts(m, " proc"); + hlist_for_each_entry(ref, pos, &node->refs, node_entry) + seq_printf(m, " %d", ref->proc->pid); + } + seq_puts(m, "\n"); + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work(m, " ", + " pending async transaction", w); +} + +static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) +{ + seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n", + ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", + ref->node->debug_id, ref->strong, ref->weak, ref->death); +} + +static void print_binder_proc(struct seq_file *m, + struct binder_proc *proc, int print_all) +{ + struct binder_work *w; + struct rb_node *n; + size_t start_pos = m->count; + size_t header_pos; + + seq_printf(m, "proc %d\n", proc->pid); + header_pos = m->count; + + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) + print_binder_thread(m, rb_entry(n, struct binder_thread, + rb_node), print_all); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { + struct binder_node *node = rb_entry(n, struct binder_node, + rb_node); + if (print_all || node->has_async_transaction) + print_binder_node(m, node); + } + if (print_all) { + for (n = rb_first(&proc->refs_by_desc); + n != NULL; + n = rb_next(n)) + print_binder_ref(m, rb_entry(n, struct binder_ref, + rb_node_desc)); + } + for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) + print_binder_buffer(m, " buffer", + rb_entry(n, struct binder_buffer, rb_node)); + list_for_each_entry(w, &proc->todo, entry) + print_binder_work(m, " ", " pending transaction", w); + list_for_each_entry(w, &proc->delivered_death, entry) { + seq_puts(m, " has delivered dead binder\n"); + break; + } + if (!print_all && m->count == header_pos) + m->count = start_pos; +} + +static const char *binder_return_strings[] = { + "BR_ERROR", + "BR_OK", + "BR_TRANSACTION", + "BR_REPLY", + "BR_ACQUIRE_RESULT", + "BR_DEAD_REPLY", + "BR_TRANSACTION_COMPLETE", + "BR_INCREFS", + "BR_ACQUIRE", + "BR_RELEASE", + "BR_DECREFS", + "BR_ATTEMPT_ACQUIRE", + "BR_NOOP", + "BR_SPAWN_LOOPER", + "BR_FINISHED", + "BR_DEAD_BINDER", + "BR_CLEAR_DEATH_NOTIFICATION_DONE", + "BR_FAILED_REPLY" +}; + +static const char *binder_command_strings[] = { + "BC_TRANSACTION", + "BC_REPLY", + "BC_ACQUIRE_RESULT", + "BC_FREE_BUFFER", + "BC_INCREFS", + "BC_ACQUIRE", + "BC_RELEASE", + "BC_DECREFS", + "BC_INCREFS_DONE", + "BC_ACQUIRE_DONE", + "BC_ATTEMPT_ACQUIRE", + "BC_REGISTER_LOOPER", + "BC_ENTER_LOOPER", + "BC_EXIT_LOOPER", + "BC_REQUEST_DEATH_NOTIFICATION", + "BC_CLEAR_DEATH_NOTIFICATION", + "BC_DEAD_BINDER_DONE" +}; + +static const char *binder_objstat_strings[] = { + "proc", + "thread", + "node", + "ref", + "death", + "transaction", + "transaction_complete" +}; + +static void print_binder_stats(struct seq_file *m, const char *prefix, + struct binder_stats *stats) +{ + int i; + + BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != + ARRAY_SIZE(binder_command_strings)); + for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { + if (stats->bc[i]) + seq_printf(m, "%s%s: %d\n", prefix, + binder_command_strings[i], stats->bc[i]); + } + + BUILD_BUG_ON(ARRAY_SIZE(stats->br) != + ARRAY_SIZE(binder_return_strings)); + for (i = 0; i < ARRAY_SIZE(stats->br); i++) { + if (stats->br[i]) + seq_printf(m, "%s%s: %d\n", prefix, + binder_return_strings[i], stats->br[i]); + } + + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + ARRAY_SIZE(binder_objstat_strings)); + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + ARRAY_SIZE(stats->obj_deleted)); + for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { + if (stats->obj_created[i] || stats->obj_deleted[i]) + seq_printf(m, "%s%s: active %d total %d\n", prefix, + binder_objstat_strings[i], + stats->obj_created[i] - stats->obj_deleted[i], + stats->obj_created[i]); + } +} + +static void print_binder_proc_stats(struct seq_file *m, + struct binder_proc *proc) +{ + struct binder_work *w; + struct rb_node *n; + int count, strong, weak; + + seq_printf(m, "proc %d\n", proc->pid); + count = 0; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) + count++; + seq_printf(m, " threads: %d\n", count); + seq_printf(m, " requested threads: %d+%d/%d\n" + " ready threads %d\n" + " free async space %zd\n", proc->requested_threads, + proc->requested_threads_started, proc->max_threads, + proc->ready_threads, proc->free_async_space); + count = 0; + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) + count++; + seq_printf(m, " nodes: %d\n", count); + count = 0; + strong = 0; + weak = 0; + for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { + struct binder_ref *ref = rb_entry(n, struct binder_ref, + rb_node_desc); + count++; + strong += ref->strong; + weak += ref->weak; + } + seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); + + count = 0; + for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) + count++; + seq_printf(m, " buffers: %d\n", count); + + count = 0; + list_for_each_entry(w, &proc->todo, entry) { + switch (w->type) { + case BINDER_WORK_TRANSACTION: + count++; + break; + default: + break; + } + } + seq_printf(m, " pending transactions: %d\n", count); + + print_binder_stats(m, " ", &proc->stats); +} + + +static int binder_state_show(struct seq_file *m, void *unused) +{ + struct binder_proc *proc; + struct hlist_node *pos; + struct binder_node *node; + int do_lock = !binder_debug_no_lock; + + if (do_lock) + mutex_lock(&binder_lock); + + seq_puts(m, "binder state:\n"); + + if (!hlist_empty(&binder_dead_nodes)) + seq_puts(m, "dead nodes:\n"); + hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) + print_binder_node(m, node); + + hlist_for_each_entry(proc, pos, &binder_procs, proc_node) + print_binder_proc(m, proc, 1); + if (do_lock) + mutex_unlock(&binder_lock); + return 0; +} + +static int binder_stats_show(struct seq_file *m, void *unused) +{ + struct binder_proc *proc; + struct hlist_node *pos; + int do_lock = !binder_debug_no_lock; + + if (do_lock) + mutex_lock(&binder_lock); + + seq_puts(m, "binder stats:\n"); + + print_binder_stats(m, "", &binder_stats); + + hlist_for_each_entry(proc, pos, &binder_procs, proc_node) + print_binder_proc_stats(m, proc); + if (do_lock) + mutex_unlock(&binder_lock); + return 0; +} + +static int binder_transactions_show(struct seq_file *m, void *unused) +{ + struct binder_proc *proc; + struct hlist_node *pos; + int do_lock = !binder_debug_no_lock; + + if (do_lock) + mutex_lock(&binder_lock); + + seq_puts(m, "binder transactions:\n"); + hlist_for_each_entry(proc, pos, &binder_procs, proc_node) + print_binder_proc(m, proc, 0); + if (do_lock) + mutex_unlock(&binder_lock); + return 0; +} + +static int binder_proc_show(struct seq_file *m, void *unused) +{ + struct binder_proc *proc = m->private; + int do_lock = !binder_debug_no_lock; + + if (do_lock) + mutex_lock(&binder_lock); + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, proc, 1); + if (do_lock) + mutex_unlock(&binder_lock); + return 0; +} + +static void print_binder_transaction_log_entry(struct seq_file *m, + struct binder_transaction_log_entry *e) +{ + seq_printf(m, + "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n", + e->debug_id, (e->call_type == 2) ? "reply" : + ((e->call_type == 1) ? "async" : "call "), e->from_proc, + e->from_thread, e->to_proc, e->to_thread, e->to_node, + e->target_handle, e->data_size, e->offsets_size); +} + +static int binder_transaction_log_show(struct seq_file *m, void *unused) +{ + struct binder_transaction_log *log = m->private; + int i; + + if (log->full) { + for (i = log->next; i < ARRAY_SIZE(log->entry); i++) + print_binder_transaction_log_entry(m, &log->entry[i]); + } + for (i = 0; i < log->next; i++) + print_binder_transaction_log_entry(m, &log->entry[i]); + return 0; +} + +static const struct file_operations binder_fops = { + .owner = THIS_MODULE, + .poll = binder_poll, + .unlocked_ioctl = binder_ioctl, + .mmap = binder_mmap, + .open = binder_open, + .flush = binder_flush, + .release = binder_release, +}; + +static struct miscdevice binder_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "binder", + .fops = &binder_fops +}; + +BINDER_DEBUG_ENTRY(state); +BINDER_DEBUG_ENTRY(stats); +BINDER_DEBUG_ENTRY(transactions); +BINDER_DEBUG_ENTRY(transaction_log); + +static int __init binder_init(void) +{ + int ret; + + binder_deferred_workqueue = create_singlethread_workqueue("binder"); + if (!binder_deferred_workqueue) + return -ENOMEM; + + binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); + if (binder_debugfs_dir_entry_root) + binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", + binder_debugfs_dir_entry_root); + ret = misc_register(&binder_miscdev); + if (binder_debugfs_dir_entry_root) { + debugfs_create_file("state", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_state_fops); + debugfs_create_file("stats", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_stats_fops); + debugfs_create_file("transactions", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_transactions_fops); + debugfs_create_file("transaction_log", + S_IRUGO, + binder_debugfs_dir_entry_root, + &binder_transaction_log, + &binder_transaction_log_fops); + debugfs_create_file("failed_transaction_log", + S_IRUGO, + binder_debugfs_dir_entry_root, + &binder_transaction_log_failed, + &binder_transaction_log_fops); + } + return ret; +} + +device_initcall(binder_init); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h new file mode 100644 index 00000000000..25ab6f2759e --- /dev/null +++ b/drivers/staging/android/binder.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2008 Google, Inc. + * + * Based on, but no longer compatible with, the original + * OpenBinder.org binder driver interface, which is: + * + * Copyright (c) 2005 Palmsource, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _LINUX_BINDER_H +#define _LINUX_BINDER_H + +#include <linux/ioctl.h> + +#define B_PACK_CHARS(c1, c2, c3, c4) \ + ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) +#define B_TYPE_LARGE 0x85 + +enum { + BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE), + BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE), + BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE), + BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE), + BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), +}; + +enum { + FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, + FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, +}; + +/* + * This is the flattened representation of a Binder object for transfer + * between processes. The 'offsets' supplied as part of a binder transaction + * contains offsets into the data where these structures occur. The Binder + * driver takes care of re-writing the structure type and data as it moves + * between processes. + */ +struct flat_binder_object { + /* 8 bytes for large_flat_header. */ + unsigned long type; + unsigned long flags; + + /* 8 bytes of data. */ + union { + void *binder; /* local object */ + signed long handle; /* remote object */ + }; + + /* extra data associated with local object */ + void *cookie; +}; + +/* + * On 64-bit platforms where user code may run in 32-bits the driver must + * translate the buffer (and local binder) addresses apropriately. + */ + +struct binder_write_read { + signed long write_size; /* bytes to write */ + signed long write_consumed; /* bytes consumed by driver */ + unsigned long write_buffer; + signed long read_size; /* bytes to read */ + signed long read_consumed; /* bytes consumed by driver */ + unsigned long read_buffer; +}; + +/* Use with BINDER_VERSION, driver fills in fields. */ +struct binder_version { + /* driver protocol version -- increment with incompatible change */ + signed long protocol_version; +}; + +/* This is the current protocol version. */ +#define BINDER_CURRENT_PROTOCOL_VERSION 7 + +#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) +#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, int64_t) +#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t) +#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int) +#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int) +#define BINDER_THREAD_EXIT _IOW('b', 8, int) +#define BINDER_VERSION _IOWR('b', 9, struct binder_version) + +/* + * NOTE: Two special error codes you should check for when calling + * in to the driver are: + * + * EINTR -- The operation has been interupted. This should be + * handled by retrying the ioctl() until a different error code + * is returned. + * + * ECONNREFUSED -- The driver is no longer accepting operations + * from your process. That is, the process is being destroyed. + * You should handle this by exiting from your process. Note + * that once this error code is returned, all further calls to + * the driver from any thread will return this same code. + */ + +enum transaction_flags { + TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */ + TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */ + TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ + TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ +}; + +struct binder_transaction_data { + /* The first two are only used for bcTRANSACTION and brTRANSACTION, + * identifying the target and contents of the transaction. + */ + union { + size_t handle; /* target descriptor of command transaction */ + void *ptr; /* target descriptor of return transaction */ + } target; + void *cookie; /* target object cookie */ + unsigned int code; /* transaction command */ + + /* General information about the transaction. */ + unsigned int flags; + pid_t sender_pid; + uid_t sender_euid; + size_t data_size; /* number of bytes of data */ + size_t offsets_size; /* number of bytes of offsets */ + + /* If this transaction is inline, the data immediately + * follows here; otherwise, it ends with a pointer to + * the data buffer. + */ + union { + struct { + /* transaction data */ + const void *buffer; + /* offsets from buffer to flat_binder_object structs */ + const void *offsets; + } ptr; + uint8_t buf[8]; + } data; +}; + +struct binder_ptr_cookie { + void *ptr; + void *cookie; +}; + +struct binder_pri_desc { + int priority; + int desc; +}; + +struct binder_pri_ptr_cookie { + int priority; + void *ptr; + void *cookie; +}; + +enum BinderDriverReturnProtocol { + BR_ERROR = _IOR('r', 0, int), + /* + * int: error code + */ + + BR_OK = _IO('r', 1), + /* No parameters! */ + + BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), + BR_REPLY = _IOR('r', 3, struct binder_transaction_data), + /* + * binder_transaction_data: the received command. + */ + + BR_ACQUIRE_RESULT = _IOR('r', 4, int), + /* + * not currently supported + * int: 0 if the last bcATTEMPT_ACQUIRE was not successful. + * Else the remote object has acquired a primary reference. + */ + + BR_DEAD_REPLY = _IO('r', 5), + /* + * The target of the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) is no longer with us. No parameters. + */ + + BR_TRANSACTION_COMPLETE = _IO('r', 6), + /* + * No parameters... always refers to the last transaction requested + * (including replies). Note that this will be sent even for + * asynchronous transactions. + */ + + BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie), + BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie), + BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie), + BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie), + /* + * void *: ptr to binder + * void *: cookie for binder + */ + + BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie), + /* + * not currently supported + * int: priority + * void *: ptr to binder + * void *: cookie for binder + */ + + BR_NOOP = _IO('r', 12), + /* + * No parameters. Do nothing and examine the next command. It exists + * primarily so that we can replace it with a BR_SPAWN_LOOPER command. + */ + + BR_SPAWN_LOOPER = _IO('r', 13), + /* + * No parameters. The driver has determined that a process has no + * threads waiting to service incomming transactions. When a process + * receives this command, it must spawn a new service thread and + * register it via bcENTER_LOOPER. + */ + + BR_FINISHED = _IO('r', 14), + /* + * not currently supported + * stop threadpool thread + */ + + BR_DEAD_BINDER = _IOR('r', 15, void *), + /* + * void *: cookie + */ + BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *), + /* + * void *: cookie + */ + + BR_FAILED_REPLY = _IO('r', 17), + /* + * The the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. + */ +}; + +enum BinderDriverCommandProtocol { + BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), + BC_REPLY = _IOW('c', 1, struct binder_transaction_data), + /* + * binder_transaction_data: the sent command. + */ + + BC_ACQUIRE_RESULT = _IOW('c', 2, int), + /* + * not currently supported + * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful. + * Else you have acquired a primary reference on the object. + */ + + BC_FREE_BUFFER = _IOW('c', 3, int), + /* + * void *: ptr to transaction data received on a read + */ + + BC_INCREFS = _IOW('c', 4, int), + BC_ACQUIRE = _IOW('c', 5, int), + BC_RELEASE = _IOW('c', 6, int), + BC_DECREFS = _IOW('c', 7, int), + /* + * int: descriptor + */ + + BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie), + BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie), + /* + * void *: ptr to binder + * void *: cookie for binder + */ + + BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc), + /* + * not currently supported + * int: priority + * int: descriptor + */ + + BC_REGISTER_LOOPER = _IO('c', 11), + /* + * No parameters. + * Register a spawned looper thread with the device. + */ + + BC_ENTER_LOOPER = _IO('c', 12), + BC_EXIT_LOOPER = _IO('c', 13), + /* + * No parameters. + * These two commands are sent as an application-level thread + * enters and exits the binder loop, respectively. They are + * used so the binder can have an accurate count of the number + * of looping threads it has available. + */ + + BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie), + /* + * void *: ptr to binder + * void *: cookie + */ + + BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie), + /* + * void *: ptr to binder + * void *: cookie + */ + + BC_DEAD_BINDER_DONE = _IOW('c', 16, void *), + /* + * void *: cookie + */ +}; + +#endif /* _LINUX_BINDER_H */ + diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c new file mode 100644 index 00000000000..ffc2d043dd8 --- /dev/null +++ b/drivers/staging/android/logger.c @@ -0,0 +1,616 @@ +/* + * drivers/misc/logger.c + * + * A Logging Subsystem + * + * Copyright (C) 2007-2008 Google, Inc. + * + * Robert Love <rlove@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/poll.h> +#include <linux/slab.h> +#include <linux/time.h> +#include "logger.h" + +#include <asm/ioctls.h> + +/* + * struct logger_log - represents a specific log, such as 'main' or 'radio' + * + * This structure lives from module insertion until module removal, so it does + * not need additional reference counting. The structure is protected by the + * mutex 'mutex'. + */ +struct logger_log { + unsigned char *buffer;/* the ring buffer itself */ + struct miscdevice misc; /* misc device representing the log */ + wait_queue_head_t wq; /* wait queue for readers */ + struct list_head readers; /* this log's readers */ + struct mutex mutex; /* mutex protecting buffer */ + size_t w_off; /* current write head offset */ + size_t head; /* new readers start here */ + size_t size; /* size of the log */ +}; + +/* + * struct logger_reader - a logging device open for reading + * + * This object lives from open to release, so we don't need additional + * reference counting. The structure is protected by log->mutex. + */ +struct logger_reader { + struct logger_log *log; /* associated log */ + struct list_head list; /* entry in logger_log's list */ + size_t r_off; /* current read head offset */ +}; + +/* logger_offset - returns index 'n' into the log via (optimized) modulus */ +#define logger_offset(n) ((n) & (log->size - 1)) + +/* + * file_get_log - Given a file structure, return the associated log + * + * This isn't aesthetic. We have several goals: + * + * 1) Need to quickly obtain the associated log during an I/O operation + * 2) Readers need to maintain state (logger_reader) + * 3) Writers need to be very fast (open() should be a near no-op) + * + * In the reader case, we can trivially go file->logger_reader->logger_log. + * For a writer, we don't want to maintain a logger_reader, so we just go + * file->logger_log. Thus what file->private_data points at depends on whether + * or not the file was opened for reading. This function hides that dirtiness. + */ +static inline struct logger_log *file_get_log(struct file *file) +{ + if (file->f_mode & FMODE_READ) { + struct logger_reader *reader = file->private_data; + return reader->log; + } else + return file->private_data; +} + +/* + * get_entry_len - Grabs the length of the payload of the next entry starting + * from 'off'. + * + * Caller needs to hold log->mutex. + */ +static __u32 get_entry_len(struct logger_log *log, size_t off) +{ + __u16 val; + + switch (log->size - off) { + case 1: + memcpy(&val, log->buffer + off, 1); + memcpy(((char *) &val) + 1, log->buffer, 1); + break; + default: + memcpy(&val, log->buffer + off, 2); + } + + return sizeof(struct logger_entry) + val; +} + +/* + * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the + * user-space buffer 'buf'. Returns 'count' on success. + * + * Caller must hold log->mutex. + */ +static ssize_t do_read_log_to_user(struct logger_log *log, + struct logger_reader *reader, + char __user *buf, + size_t count) +{ + size_t len; + + /* + * We read from the log in two disjoint operations. First, we read from + * the current read head offset up to 'count' bytes or to the end of + * the log, whichever comes first. + */ + len = min(count, log->size - reader->r_off); + if (copy_to_user(buf, log->buffer + reader->r_off, len)) + return -EFAULT; + + /* + * Second, we read any remaining bytes, starting back at the head of + * the log. + */ + if (count != len) + if (copy_to_user(buf + len, log->buffer, count - len)) + return -EFAULT; + + reader->r_off = logger_offset(reader->r_off + count); + + return count; +} + +/* + * logger_read - our log's read() method + * + * Behavior: + * + * - O_NONBLOCK works + * - If there are no log entries to read, blocks until log is written to + * - Atomically reads exactly one log entry + * + * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read + * buffer is insufficient to hold next entry. + */ +static ssize_t logger_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct logger_reader *reader = file->private_data; + struct logger_log *log = reader->log; + ssize_t ret; + DEFINE_WAIT(wait); + +start: + while (1) { + prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE); + + mutex_lock(&log->mutex); + ret = (log->w_off == reader->r_off); + mutex_unlock(&log->mutex); + if (!ret) + break; + + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + + if (signal_pending(current)) { + ret = -EINTR; + break; + } + + schedule(); + } + + finish_wait(&log->wq, &wait); + if (ret) + return ret; + + mutex_lock(&log->mutex); + + /* is there still something to read or did we race? */ + if (unlikely(log->w_off == reader->r_off)) { + mutex_unlock(&log->mutex); + goto start; + } + + /* get the size of the next entry */ + ret = get_entry_len(log, reader->r_off); + if (count < ret) { + ret = -EINVAL; + goto out; + } + + /* get exactly one entry from the log */ + ret = do_read_log_to_user(log, reader, buf, ret); + +out: + mutex_unlock(&log->mutex); + + return ret; +} + +/* + * get_next_entry - return the offset of the first valid entry at least 'len' + * bytes after 'off'. + * + * Caller must hold log->mutex. + */ +static size_t get_next_entry(struct logger_log *log, size_t off, size_t len) +{ + size_t count = 0; + + do { + size_t nr = get_entry_len(log, off); + off = logger_offset(off + nr); + count += nr; + } while (count < len); + + return off; +} + +/* + * clock_interval - is a < c < b in mod-space? Put another way, does the line + * from a to b cross c? + */ +static inline int clock_interval(size_t a, size_t b, size_t c) +{ + if (b < a) { + if (a < c || b >= c) + return 1; + } else { + if (a < c && b >= c) + return 1; + } + + return 0; +} + +/* + * fix_up_readers - walk the list of all readers and "fix up" any who were + * lapped by the writer; also do the same for the default "start head". + * We do this by "pulling forward" the readers and start head to the first + * entry after the new write head. + * + * The caller needs to hold log->mutex. + */ +static void fix_up_readers(struct logger_log *log, size_t len) +{ + size_t old = log->w_off; + size_t new = logger_offset(old + len); + struct logger_reader *reader; + + if (clock_interval(old, new, log->head)) + log->head = get_next_entry(log, log->head, len); + + list_for_each_entry(reader, &log->readers, list) + if (clock_interval(old, new, reader->r_off)) + reader->r_off = get_next_entry(log, reader->r_off, len); +} + +/* + * do_write_log - writes 'len' bytes from 'buf' to 'log' + * + * The caller needs to hold log->mutex. + */ +static void do_write_log(struct logger_log *log, const void *buf, size_t count) +{ + size_t len; + + len = min(count, log->size - log->w_off); + memcpy(log->buffer + log->w_off, buf, len); + + if (count != len) + memcpy(log->buffer, buf + len, count - len); + + log->w_off = logger_offset(log->w_off + count); + +} + +/* + * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to + * the log 'log' + * + * The caller needs to hold log->mutex. + * + * Returns 'count' on success, negative error code on failure. + */ +static ssize_t do_write_log_from_user(struct logger_log *log, + const void __user *buf, size_t count) +{ + size_t len; + + len = min(count, log->size - log->w_off); + if (len && copy_from_user(log->buffer + log->w_off, buf, len)) + return -EFAULT; + + if (count != len) + if (copy_from_user(log->buffer, buf + len, count - len)) + return -EFAULT; + + log->w_off = logger_offset(log->w_off + count); + + return count; +} + +/* + * logger_aio_write - our write method, implementing support for write(), + * writev(), and aio_write(). Writes are our fast path, and we try to optimize + * them above all else. + */ +ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t ppos) +{ + struct logger_log *log = file_get_log(iocb->ki_filp); + size_t orig = log->w_off; + struct logger_entry header; + struct timespec now; + ssize_t ret = 0; + + now = current_kernel_time(); + + header.pid = current->tgid; + header.tid = current->pid; + header.sec = now.tv_sec; + header.nsec = now.tv_nsec; + header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD); + + /* null writes succeed, return zero */ + if (unlikely(!header.len)) + return 0; + + mutex_lock(&log->mutex); + + /* + * Fix up any readers, pulling them forward to the first readable + * entry after (what will be) the new write offset. We do this now + * because if we partially fail, we can end up with clobbered log + * entries that encroach on readable buffer. + */ + fix_up_readers(log, sizeof(struct logger_entry) + header.len); + + do_write_log(log, &header, sizeof(struct logger_entry)); + + while (nr_segs-- > 0) { + size_t len; + ssize_t nr; + + /* figure out how much of this vector we can keep */ + len = min_t(size_t, iov->iov_len, header.len - ret); + + /* write out this segment's payload */ + nr = do_write_log_from_user(log, iov->iov_base, len); + if (unlikely(nr < 0)) { + log->w_off = orig; + mutex_unlock(&log->mutex); + return nr; + } + + iov++; + ret += nr; + } + + mutex_unlock(&log->mutex); + + /* wake up any blocked readers */ + wake_up_interruptible(&log->wq); + + return ret; +} + +static struct logger_log *get_log_from_minor(int); + +/* + * logger_open - the log's open() file operation + * + * Note how near a no-op this is in the write-only case. Keep it that way! + */ +static int logger_open(struct inode *inode, struct file *file) +{ + struct logger_log *log; + int ret; + + ret = nonseekable_open(inode, file); + if (ret) + return ret; + + log = get_log_from_minor(MINOR(inode->i_rdev)); + if (!log) + return -ENODEV; + + if (file->f_mode & FMODE_READ) { + struct logger_reader *reader; + + reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL); + if (!reader) + return -ENOMEM; + + reader->log = log; + INIT_LIST_HEAD(&reader->list); + + mutex_lock(&log->mutex); + reader->r_off = log->head; + list_add_tail(&reader->list, &log->readers); + mutex_unlock(&log->mutex); + + file->private_data = reader; + } else + file->private_data = log; + + return 0; +} + +/* + * logger_release - the log's release file operation + * + * Note this is a total no-op in the write-only case. Keep it that way! + */ +static int logger_release(struct inode *ignored, struct file *file) +{ + if (file->f_mode & FMODE_READ) { + struct logger_reader *reader = file->private_data; + list_del(&reader->list); + kfree(reader); + } + + return 0; +} + +/* + * logger_poll - the log's poll file operation, for poll/select/epoll + * + * Note we always return POLLOUT, because you can always write() to the log. + * Note also that, strictly speaking, a return value of POLLIN does not + * guarantee that the log is readable without blocking, as there is a small + * chance that the writer can lap the reader in the interim between poll() + * returning and the read() request. + */ +static unsigned int logger_poll(struct file *file, poll_table *wait) +{ + struct logger_reader *reader; + struct logger_log *log; + unsigned int ret = POLLOUT | POLLWRNORM; + + if (!(file->f_mode & FMODE_READ)) + return ret; + + reader = file->private_data; + log = reader->log; + + poll_wait(file, &log->wq, wait); + + mutex_lock(&log->mutex); + if (log->w_off != reader->r_off) + ret |= POLLIN | POLLRDNORM; + mutex_unlock(&log->mutex); + + return ret; +} + +static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct logger_log *log = file_get_log(file); + struct logger_reader *reader; + long ret = -ENOTTY; + + mutex_lock(&log->mutex); + + switch (cmd) { + case LOGGER_GET_LOG_BUF_SIZE: + ret = log->size; + break; + case LOGGER_GET_LOG_LEN: + if (!(file->f_mode & FMODE_READ)) { + ret = -EBADF; + break; + } + reader = file->private_data; + if (log->w_off >= reader->r_off) + ret = log->w_off - reader->r_off; + else + ret = (log->size - reader->r_off) + log->w_off; + break; + case LOGGER_GET_NEXT_ENTRY_LEN: + if (!(file->f_mode & FMODE_READ)) { + ret = -EBADF; + break; + } + reader = file->private_data; + if (log->w_off != reader->r_off) + ret = get_entry_len(log, reader->r_off); + else + ret = 0; + break; + case LOGGER_FLUSH_LOG: + if (!(file->f_mode & FMODE_WRITE)) { + ret = -EBADF; + break; + } + list_for_each_entry(reader, &log->readers, list) + reader->r_off = log->w_off; + log->head = log->w_off; + ret = 0; + break; + } + + mutex_unlock(&log->mutex); + + return ret; +} + +static const struct file_operations logger_fops = { + .owner = THIS_MODULE, + .read = logger_read, + .aio_write = logger_aio_write, + .poll = logger_poll, + .unlocked_ioctl = logger_ioctl, + .compat_ioctl = logger_ioctl, + .open = logger_open, + .release = logger_release, +}; + +/* + * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which + * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than + * LONG_MAX minus LOGGER_ENTRY_MAX_LEN. + */ +#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \ +static unsigned char _buf_ ## VAR[SIZE]; \ +static struct logger_log VAR = { \ + .buffer = _buf_ ## VAR, \ + .misc = { \ + .minor = MISC_DYNAMIC_MINOR, \ + .name = NAME, \ + .fops = &logger_fops, \ + .parent = NULL, \ + }, \ + .wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \ + .readers = LIST_HEAD_INIT(VAR .readers), \ + .mutex = __MUTEX_INITIALIZER(VAR .mutex), \ + .w_off = 0, \ + .head = 0, \ + .size = SIZE, \ +}; + +DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024) +DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024) +DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024) +DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024) + +static struct logger_log *get_log_from_minor(int minor) +{ + if (log_main.misc.minor == minor) + return &log_main; + if (log_events.misc.minor == minor) + return &log_events; + if (log_radio.misc.minor == minor) + return &log_radio; + if (log_system.misc.minor == minor) + return &log_system; + return NULL; +} + +static int __init init_log(struct logger_log *log) +{ + int ret; + + ret = misc_register(&log->misc); + if (unlikely(ret)) { + printk(KERN_ERR "logger: failed to register misc " + "device for log '%s'!\n", log->misc.name); + return ret; + } + + printk(KERN_INFO "logger: created %luK log '%s'\n", + (unsigned long) log->size >> 10, log->misc.name); + + return 0; +} + +static int __init logger_init(void) +{ + int ret; + + ret = init_log(&log_main); + if (unlikely(ret)) + goto out; + + ret = init_log(&log_events); + if (unlikely(ret)) + goto out; + + ret = init_log(&log_radio); + if (unlikely(ret)) + goto out; + + ret = init_log(&log_system); + if (unlikely(ret)) + goto out; + +out: + return ret; +} +device_initcall(logger_init); diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h new file mode 100644 index 00000000000..2cb06e9d8f9 --- /dev/null +++ b/drivers/staging/android/logger.h @@ -0,0 +1,49 @@ +/* include/linux/logger.h + * + * Copyright (C) 2007-2008 Google, Inc. + * Author: Robert Love <rlove@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _LINUX_LOGGER_H +#define _LINUX_LOGGER_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +struct logger_entry { + __u16 len; /* length of the payload */ + __u16 __pad; /* no matter what, we get 2 bytes of padding */ + __s32 pid; /* generating process's pid */ + __s32 tid; /* generating process's tid */ + __s32 sec; /* seconds since Epoch */ + __s32 nsec; /* nanoseconds */ + char msg[0]; /* the entry's payload */ +}; + +#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ +#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ +#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */ +#define LOGGER_LOG_MAIN "log_main" /* everything else */ + +#define LOGGER_ENTRY_MAX_LEN (4*1024) +#define LOGGER_ENTRY_MAX_PAYLOAD \ + (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry)) + +#define __LOGGERIO 0xAE + +#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */ +#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ +#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ +#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ + +#endif /* _LINUX_LOGGER_H */ diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c new file mode 100644 index 00000000000..2d8d2b79610 --- /dev/null +++ b/drivers/staging/android/lowmemorykiller.c @@ -0,0 +1,219 @@ +/* drivers/misc/lowmemorykiller.c + * + * The lowmemorykiller driver lets user-space specify a set of memory thresholds + * where processes with a range of oom_adj values will get killed. Specify the + * minimum oom_adj values in /sys/module/lowmemorykiller/parameters/adj and the + * number of free pages in /sys/module/lowmemorykiller/parameters/minfree. Both + * files take a comma separated list of numbers in ascending order. + * + * For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and + * "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill + * processes with a oom_adj value of 8 or higher when the free memory drops + * below 4096 pages and kill processes with a oom_adj value of 0 or higher + * when the free memory drops below 1024 pages. + * + * The driver considers memory used for caches to be free, but if a large + * percentage of the cached memory is locked this can be very inaccurate + * and processes may not get killed until the normal oom killer is triggered. + * + * Copyright (C) 2007-2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/oom.h> +#include <linux/sched.h> +#include <linux/profile.h> +#include <linux/notifier.h> + +static uint32_t lowmem_debug_level = 2; +static int lowmem_adj[6] = { + 0, + 1, + 6, + 12, +}; +static int lowmem_adj_size = 4; +static size_t lowmem_minfree[6] = { + 3 * 512, /* 6MB */ + 2 * 1024, /* 8MB */ + 4 * 1024, /* 16MB */ + 16 * 1024, /* 64MB */ +}; +static int lowmem_minfree_size = 4; + +static struct task_struct *lowmem_deathpending; + +#define lowmem_print(level, x...) \ + do { \ + if (lowmem_debug_level >= (level)) \ + printk(x); \ + } while (0) + +static int +task_notify_func(struct notifier_block *self, unsigned long val, void *data); + +static struct notifier_block task_nb = { + .notifier_call = task_notify_func, +}; + +static int +task_notify_func(struct notifier_block *self, unsigned long val, void *data) +{ + struct task_struct *task = data; + if (task == lowmem_deathpending) { + lowmem_deathpending = NULL; + task_handoff_unregister(&task_nb); + } + return NOTIFY_OK; +} + +static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) +{ + struct task_struct *p; + struct task_struct *selected = NULL; + int rem = 0; + int tasksize; + int i; + int min_adj = OOM_ADJUST_MAX + 1; + int selected_tasksize = 0; + int selected_oom_adj; + int array_size = ARRAY_SIZE(lowmem_adj); + int other_free = global_page_state(NR_FREE_PAGES); + int other_file = global_page_state(NR_FILE_PAGES) - + global_page_state(NR_SHMEM); + + /* + * If we already have a death outstanding, then + * bail out right away; indicating to vmscan + * that we have nothing further to offer on + * this pass. + * + * Note: Currently you need CONFIG_PROFILING + * for this to work correctly. + */ + if (lowmem_deathpending) + return 0; + + if (lowmem_adj_size < array_size) + array_size = lowmem_adj_size; + if (lowmem_minfree_size < array_size) + array_size = lowmem_minfree_size; + for (i = 0; i < array_size; i++) { + if (other_free < lowmem_minfree[i] && + other_file < lowmem_minfree[i]) { + min_adj = lowmem_adj[i]; + break; + } + } + if (sc->nr_to_scan > 0) + lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n", + sc->nr_to_scan, sc->gfp_mask, other_free, + other_file, min_adj); + rem = global_page_state(NR_ACTIVE_ANON) + + global_page_state(NR_ACTIVE_FILE) + + global_page_state(NR_INACTIVE_ANON) + + global_page_state(NR_INACTIVE_FILE); + if (sc->nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) { + lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n", + sc->nr_to_scan, sc->gfp_mask, rem); + return rem; + } + selected_oom_adj = min_adj; + + read_lock(&tasklist_lock); + for_each_process(p) { + struct mm_struct *mm; + struct signal_struct *sig; + int oom_adj; + + task_lock(p); + mm = p->mm; + sig = p->signal; + if (!mm || !sig) { + task_unlock(p); + continue; + } + oom_adj = sig->oom_adj; + if (oom_adj < min_adj) { + task_unlock(p); + continue; + } + tasksize = get_mm_rss(mm); + task_unlock(p); + if (tasksize <= 0) + continue; + if (selected) { + if (oom_adj < selected_oom_adj) + continue; + if (oom_adj == selected_oom_adj && + tasksize <= selected_tasksize) + continue; + } + selected = p; + selected_tasksize = tasksize; + selected_oom_adj = oom_adj; + lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", + p->pid, p->comm, oom_adj, tasksize); + } + if (selected) { + lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", + selected->pid, selected->comm, + selected_oom_adj, selected_tasksize); + /* + * If CONFIG_PROFILING is off, then task_handoff_register() + * is a nop. In that case we don't want to stall the killer + * by setting lowmem_deathpending. + */ +#ifdef CONFIG_PROFILING + lowmem_deathpending = selected; + task_handoff_register(&task_nb); +#endif + force_sig(SIGKILL, selected); + rem -= selected_tasksize; + } + lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", + sc->nr_to_scan, sc->gfp_mask, rem); + read_unlock(&tasklist_lock); + return rem; +} + +static struct shrinker lowmem_shrinker = { + .shrink = lowmem_shrink, + .seeks = DEFAULT_SEEKS * 16 +}; + +static int __init lowmem_init(void) +{ + register_shrinker(&lowmem_shrinker); + return 0; +} + +static void __exit lowmem_exit(void) +{ + unregister_shrinker(&lowmem_shrinker); +} + +module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); +module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, + S_IRUGO | S_IWUSR); +module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, + S_IRUGO | S_IWUSR); +module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); + +module_init(lowmem_init); +module_exit(lowmem_exit); + +MODULE_LICENSE("GPL"); + diff --git a/drivers/staging/android/pmem.c b/drivers/staging/android/pmem.c new file mode 100644 index 00000000000..7d97032c650 --- /dev/null +++ b/drivers/staging/android/pmem.c @@ -0,0 +1,1345 @@ +/* pmem.c + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/miscdevice.h> +#include <linux/platform_device.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/mm.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/debugfs.h> +#include <linux/mempolicy.h> +#include <linux/sched.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/cacheflush.h> +#include "android_pmem.h" + +#define PMEM_MAX_DEVICES 10 +#define PMEM_MAX_ORDER 128 +#define PMEM_MIN_ALLOC PAGE_SIZE + +#define PMEM_DEBUG 1 + +/* indicates that a refernce to this file has been taken via get_pmem_file, + * the file should not be released until put_pmem_file is called */ +#define PMEM_FLAGS_BUSY 0x1 +/* indicates that this is a suballocation of a larger master range */ +#define PMEM_FLAGS_CONNECTED 0x1 << 1 +/* indicates this is a master and not a sub allocation and that it is mmaped */ +#define PMEM_FLAGS_MASTERMAP 0x1 << 2 +/* submap and unsubmap flags indicate: + * 00: subregion has never been mmaped + * 10: subregion has been mmaped, reference to the mm was taken + * 11: subretion has ben released, refernece to the mm still held + * 01: subretion has been released, reference to the mm has been released + */ +#define PMEM_FLAGS_SUBMAP 0x1 << 3 +#define PMEM_FLAGS_UNSUBMAP 0x1 << 4 + + +struct pmem_data { + /* in alloc mode: an index into the bitmap + * in no_alloc mode: the size of the allocation */ + int index; + /* see flags above for descriptions */ + unsigned int flags; + /* protects this data field, if the mm_mmap sem will be held at the + * same time as this sem, the mm sem must be taken first (as this is + * the order for vma_open and vma_close ops */ + struct rw_semaphore sem; + /* info about the mmaping process */ + struct vm_area_struct *vma; + /* task struct of the mapping process */ + struct task_struct *task; + /* process id of teh mapping process */ + pid_t pid; + /* file descriptor of the master */ + int master_fd; + /* file struct of the master */ + struct file *master_file; + /* a list of currently available regions if this is a suballocation */ + struct list_head region_list; + /* a linked list of data so we can access them for debugging */ + struct list_head list; +#if PMEM_DEBUG + int ref; +#endif +}; + +struct pmem_bits { + unsigned allocated:1; /* 1 if allocated, 0 if free */ + unsigned order:7; /* size of the region in pmem space */ +}; + +struct pmem_region_node { + struct pmem_region region; + struct list_head list; +}; + +#define PMEM_DEBUG_MSGS 0 +#if PMEM_DEBUG_MSGS +#define DLOG(fmt,args...) \ + do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ + ##args); } \ + while (0) +#else +#define DLOG(x...) do {} while (0) +#endif + +struct pmem_info { + struct miscdevice dev; + /* physical start address of the remaped pmem space */ + unsigned long base; + /* vitual start address of the remaped pmem space */ + unsigned char __iomem *vbase; + /* total size of the pmem space */ + unsigned long size; + /* number of entries in the pmem space */ + unsigned long num_entries; + /* pfn of the garbage page in memory */ + unsigned long garbage_pfn; + /* index of the garbage page in the pmem space */ + int garbage_index; + /* the bitmap for the region indicating which entries are allocated + * and which are free */ + struct pmem_bits *bitmap; + /* indicates the region should not be managed with an allocator */ + unsigned no_allocator; + /* indicates maps of this region should be cached, if a mix of + * cached and uncached is desired, set this and open the device with + * O_SYNC to get an uncached region */ + unsigned cached; + unsigned buffered; + /* in no_allocator mode the first mapper gets the whole space and sets + * this flag */ + unsigned allocated; + /* for debugging, creates a list of pmem file structs, the + * data_list_lock should be taken before pmem_data->sem if both are + * needed */ + struct mutex data_list_lock; + struct list_head data_list; + /* pmem_sem protects the bitmap array + * a write lock should be held when modifying entries in bitmap + * a read lock should be held when reading data from bits or + * dereferencing a pointer into bitmap + * + * pmem_data->sem protects the pmem data of a particular file + * Many of the function that require the pmem_data->sem have a non- + * locking version for when the caller is already holding that sem. + * + * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER: + * down(pmem_data->sem) => down(bitmap_sem) + */ + struct rw_semaphore bitmap_sem; + + long (*ioctl)(struct file *, unsigned int, unsigned long); + int (*release)(struct inode *, struct file *); +}; + +static struct pmem_info pmem[PMEM_MAX_DEVICES]; +static int id_count; + +#define PMEM_IS_FREE(id, index) !(pmem[id].bitmap[index].allocated) +#define PMEM_ORDER(id, index) pmem[id].bitmap[index].order +#define PMEM_BUDDY_INDEX(id, index) (index ^ (1 << PMEM_ORDER(id, index))) +#define PMEM_NEXT_INDEX(id, index) (index + (1 << PMEM_ORDER(id, index))) +#define PMEM_OFFSET(index) (index * PMEM_MIN_ALLOC) +#define PMEM_START_ADDR(id, index) (PMEM_OFFSET(index) + pmem[id].base) +#define PMEM_LEN(id, index) ((1 << PMEM_ORDER(id, index)) * PMEM_MIN_ALLOC) +#define PMEM_END_ADDR(id, index) (PMEM_START_ADDR(id, index) + \ + PMEM_LEN(id, index)) +#define PMEM_START_VADDR(id, index) (PMEM_OFFSET(id, index) + pmem[id].vbase) +#define PMEM_END_VADDR(id, index) (PMEM_START_VADDR(id, index) + \ + PMEM_LEN(id, index)) +#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED) +#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK))) +#define PMEM_IS_SUBMAP(data) ((data->flags & PMEM_FLAGS_SUBMAP) && \ + (!(data->flags & PMEM_FLAGS_UNSUBMAP))) + +static int pmem_release(struct inode *, struct file *); +static int pmem_mmap(struct file *, struct vm_area_struct *); +static int pmem_open(struct inode *, struct file *); +static long pmem_ioctl(struct file *, unsigned int, unsigned long); + +struct file_operations pmem_fops = { + .release = pmem_release, + .mmap = pmem_mmap, + .open = pmem_open, + .unlocked_ioctl = pmem_ioctl, +}; + +static int get_id(struct file *file) +{ + return MINOR(file->f_dentry->d_inode->i_rdev); +} + +int is_pmem_file(struct file *file) +{ + int id; + + if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode)) + return 0; + id = get_id(file); + if (unlikely(id >= PMEM_MAX_DEVICES)) + return 0; + if (unlikely(file->f_dentry->d_inode->i_rdev != + MKDEV(MISC_MAJOR, pmem[id].dev.minor))) + return 0; + return 1; +} + +static int has_allocation(struct file *file) +{ + struct pmem_data *data; + /* check is_pmem_file first if not accessed via pmem_file_ops */ + + if (unlikely(!file->private_data)) + return 0; + data = (struct pmem_data *)file->private_data; + if (unlikely(data->index < 0)) + return 0; + return 1; +} + +static int is_master_owner(struct file *file) +{ + struct file *master_file; + struct pmem_data *data; + int put_needed, ret = 0; + + if (!is_pmem_file(file) || !has_allocation(file)) + return 0; + data = (struct pmem_data *)file->private_data; + if (PMEM_FLAGS_MASTERMAP & data->flags) + return 1; + master_file = fget_light(data->master_fd, &put_needed); + if (master_file && data->master_file == master_file) + ret = 1; + fput_light(master_file, put_needed); + return ret; +} + +static int pmem_free(int id, int index) +{ + /* caller should hold the write lock on pmem_sem! */ + int buddy, curr = index; + DLOG("index %d\n", index); + + if (pmem[id].no_allocator) { + pmem[id].allocated = 0; + return 0; + } + /* clean up the bitmap, merging any buddies */ + pmem[id].bitmap[curr].allocated = 0; + /* find a slots buddy Buddy# = Slot# ^ (1 << order) + * if the buddy is also free merge them + * repeat until the buddy is not free or end of the bitmap is reached + */ + do { + buddy = PMEM_BUDDY_INDEX(id, curr); + if (PMEM_IS_FREE(id, buddy) && + PMEM_ORDER(id, buddy) == PMEM_ORDER(id, curr)) { + PMEM_ORDER(id, buddy)++; + PMEM_ORDER(id, curr)++; + curr = min(buddy, curr); + } else { + break; + } + } while (curr < pmem[id].num_entries); + + return 0; +} + +static void pmem_revoke(struct file *file, struct pmem_data *data); + +static int pmem_release(struct inode *inode, struct file *file) +{ + struct pmem_data *data = (struct pmem_data *)file->private_data; + struct pmem_region_node *region_node; + struct list_head *elt, *elt2; + int id = get_id(file), ret = 0; + + + mutex_lock(&pmem[id].data_list_lock); + /* if this file is a master, revoke all the memory in the connected + * files */ + if (PMEM_FLAGS_MASTERMAP & data->flags) { + struct pmem_data *sub_data; + list_for_each(elt, &pmem[id].data_list) { + sub_data = list_entry(elt, struct pmem_data, list); + down_read(&sub_data->sem); + if (PMEM_IS_SUBMAP(sub_data) && + file == sub_data->master_file) { + up_read(&sub_data->sem); + pmem_revoke(file, sub_data); + } else + up_read(&sub_data->sem); + } + } + list_del(&data->list); + mutex_unlock(&pmem[id].data_list_lock); + + + down_write(&data->sem); + + /* if its not a conencted file and it has an allocation, free it */ + if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) { + down_write(&pmem[id].bitmap_sem); + ret = pmem_free(id, data->index); + up_write(&pmem[id].bitmap_sem); + } + + /* if this file is a submap (mapped, connected file), downref the + * task struct */ + if (PMEM_FLAGS_SUBMAP & data->flags) + if (data->task) { + put_task_struct(data->task); + data->task = NULL; + } + + file->private_data = NULL; + + list_for_each_safe(elt, elt2, &data->region_list) { + region_node = list_entry(elt, struct pmem_region_node, list); + list_del(elt); + kfree(region_node); + } + BUG_ON(!list_empty(&data->region_list)); + + up_write(&data->sem); + kfree(data); + if (pmem[id].release) + ret = pmem[id].release(inode, file); + + return ret; +} + +static int pmem_open(struct inode *inode, struct file *file) +{ + struct pmem_data *data; + int id = get_id(file); + int ret = 0; + + DLOG("current %u file %p(%d)\n", current->pid, file, file_count(file)); + /* setup file->private_data to indicate its unmapped */ + /* you can only open a pmem device one time */ + if (file->private_data != NULL) + return -1; + data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL); + if (!data) { + printk("pmem: unable to allocate memory for pmem metadata."); + return -1; + } + data->flags = 0; + data->index = -1; + data->task = NULL; + data->vma = NULL; + data->pid = 0; + data->master_file = NULL; +#if PMEM_DEBUG + data->ref = 0; +#endif + INIT_LIST_HEAD(&data->region_list); + init_rwsem(&data->sem); + + file->private_data = data; + INIT_LIST_HEAD(&data->list); + + mutex_lock(&pmem[id].data_list_lock); + list_add(&data->list, &pmem[id].data_list); + mutex_unlock(&pmem[id].data_list_lock); + return ret; +} + +static unsigned long pmem_order(unsigned long len) +{ + int i; + + len = (len + PMEM_MIN_ALLOC - 1)/PMEM_MIN_ALLOC; + len--; + for (i = 0; i < sizeof(len)*8; i++) + if (len >> i == 0) + break; + return i; +} + +static int pmem_allocate(int id, unsigned long len) +{ + /* caller should hold the write lock on pmem_sem! */ + /* return the corresponding pdata[] entry */ + int curr = 0; + int end = pmem[id].num_entries; + int best_fit = -1; + unsigned long order = pmem_order(len); + + if (pmem[id].no_allocator) { + DLOG("no allocator"); + if ((len > pmem[id].size) || pmem[id].allocated) + return -1; + pmem[id].allocated = 1; + return len; + } + + if (order > PMEM_MAX_ORDER) + return -1; + DLOG("order %lx\n", order); + + /* look through the bitmap: + * if you find a free slot of the correct order use it + * otherwise, use the best fit (smallest with size > order) slot + */ + while (curr < end) { + if (PMEM_IS_FREE(id, curr)) { + if (PMEM_ORDER(id, curr) == (unsigned char)order) { + /* set the not free bit and clear others */ + best_fit = curr; + break; + } + if (PMEM_ORDER(id, curr) > (unsigned char)order && + (best_fit < 0 || + PMEM_ORDER(id, curr) < PMEM_ORDER(id, best_fit))) + best_fit = curr; + } + curr = PMEM_NEXT_INDEX(id, curr); + } + + /* if best_fit < 0, there are no suitable slots, + * return an error + */ + if (best_fit < 0) { + printk("pmem: no space left to allocate!\n"); + return -1; + } + + /* now partition the best fit: + * split the slot into 2 buddies of order - 1 + * repeat until the slot is of the correct order + */ + while (PMEM_ORDER(id, best_fit) > (unsigned char)order) { + int buddy; + PMEM_ORDER(id, best_fit) -= 1; + buddy = PMEM_BUDDY_INDEX(id, best_fit); + PMEM_ORDER(id, buddy) = PMEM_ORDER(id, best_fit); + } + pmem[id].bitmap[best_fit].allocated = 1; + return best_fit; +} + +static pgprot_t pmem_access_prot(struct file *file, pgprot_t vma_prot) +{ + int id = get_id(file); +#ifdef pgprot_noncached + if (pmem[id].cached == 0 || file->f_flags & O_SYNC) + return pgprot_noncached(vma_prot); +#endif +#ifdef pgprot_ext_buffered + else if (pmem[id].buffered) + return pgprot_ext_buffered(vma_prot); +#endif + return vma_prot; +} + +static unsigned long pmem_start_addr(int id, struct pmem_data *data) +{ + if (pmem[id].no_allocator) + return PMEM_START_ADDR(id, 0); + else + return PMEM_START_ADDR(id, data->index); + +} + +static void *pmem_start_vaddr(int id, struct pmem_data *data) +{ + return pmem_start_addr(id, data) - pmem[id].base + pmem[id].vbase; +} + +static unsigned long pmem_len(int id, struct pmem_data *data) +{ + if (pmem[id].no_allocator) + return data->index; + else + return PMEM_LEN(id, data->index); +} + +static int pmem_map_garbage(int id, struct vm_area_struct *vma, + struct pmem_data *data, unsigned long offset, + unsigned long len) +{ + int i, garbage_pages = len >> PAGE_SHIFT; + + vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE; + for (i = 0; i < garbage_pages; i++) { + if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE), + pmem[id].garbage_pfn)) + return -EAGAIN; + } + return 0; +} + +static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma, + struct pmem_data *data, unsigned long offset, + unsigned long len) +{ + int garbage_pages; + DLOG("unmap offset %lx len %lx\n", offset, len); + + BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); + + garbage_pages = len >> PAGE_SHIFT; + zap_page_range(vma, vma->vm_start + offset, len, NULL); + pmem_map_garbage(id, vma, data, offset, len); + return 0; +} + +static int pmem_map_pfn_range(int id, struct vm_area_struct *vma, + struct pmem_data *data, unsigned long offset, + unsigned long len) +{ + DLOG("map offset %lx len %lx\n", offset, len); + BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start)); + BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end)); + BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); + BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset)); + + if (io_remap_pfn_range(vma, vma->vm_start + offset, + (pmem_start_addr(id, data) + offset) >> PAGE_SHIFT, + len, vma->vm_page_prot)) { + return -EAGAIN; + } + return 0; +} + +static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma, + struct pmem_data *data, unsigned long offset, + unsigned long len) +{ + /* hold the mm semp for the vma you are modifying when you call this */ + BUG_ON(!vma); + zap_page_range(vma, vma->vm_start + offset, len, NULL); + return pmem_map_pfn_range(id, vma, data, offset, len); +} + +static void pmem_vma_open(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct pmem_data *data = file->private_data; + int id = get_id(file); + /* this should never be called as we don't support copying pmem + * ranges via fork */ + BUG_ON(!has_allocation(file)); + down_write(&data->sem); + /* remap the garbage pages, forkers don't get access to the data */ + pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end); + up_write(&data->sem); +} + +static void pmem_vma_close(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct pmem_data *data = file->private_data; + + DLOG("current %u ppid %u file %p count %d\n", current->pid, + current->parent->pid, file, file_count(file)); + if (unlikely(!is_pmem_file(file) || !has_allocation(file))) { + printk(KERN_WARNING "pmem: something is very wrong, you are " + "closing a vm backing an allocation that doesn't " + "exist!\n"); + return; + } + down_write(&data->sem); + if (data->vma == vma) { + data->vma = NULL; + if ((data->flags & PMEM_FLAGS_CONNECTED) && + (data->flags & PMEM_FLAGS_SUBMAP)) + data->flags |= PMEM_FLAGS_UNSUBMAP; + } + /* the kernel is going to free this vma now anyway */ + up_write(&data->sem); +} + +static struct vm_operations_struct vm_ops = { + .open = pmem_vma_open, + .close = pmem_vma_close, +}; + +static int pmem_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct pmem_data *data; + int index; + unsigned long vma_size = vma->vm_end - vma->vm_start; + int ret = 0, id = get_id(file); + + if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) { +#if PMEM_DEBUG + printk(KERN_ERR "pmem: mmaps must be at offset zero, aligned" + " and a multiple of pages_size.\n"); +#endif + return -EINVAL; + } + + data = (struct pmem_data *)file->private_data; + down_write(&data->sem); + /* check this file isn't already mmaped, for submaps check this file + * has never been mmaped */ + if ((data->flags & PMEM_FLAGS_SUBMAP) || + (data->flags & PMEM_FLAGS_UNSUBMAP)) { +#if PMEM_DEBUG + printk(KERN_ERR "pmem: you can only mmap a pmem file once, " + "this file is already mmaped. %x\n", data->flags); +#endif + ret = -EINVAL; + goto error; + } + /* if file->private_data == unalloced, alloc*/ + if (data && data->index == -1) { + down_write(&pmem[id].bitmap_sem); + index = pmem_allocate(id, vma->vm_end - vma->vm_start); + up_write(&pmem[id].bitmap_sem); + data->index = index; + } + /* either no space was available or an error occured */ + if (!has_allocation(file)) { + ret = -EINVAL; + printk("pmem: could not find allocation for map.\n"); + goto error; + } + + if (pmem_len(id, data) < vma_size) { +#if PMEM_DEBUG + printk(KERN_WARNING "pmem: mmap size [%lu] does not match" + "size of backing region [%lu].\n", vma_size, + pmem_len(id, data)); +#endif + ret = -EINVAL; + goto error; + } + + vma->vm_pgoff = pmem_start_addr(id, data) >> PAGE_SHIFT; + vma->vm_page_prot = pmem_access_prot(file, vma->vm_page_prot); + + if (data->flags & PMEM_FLAGS_CONNECTED) { + struct pmem_region_node *region_node; + struct list_head *elt; + if (pmem_map_garbage(id, vma, data, 0, vma_size)) { + printk("pmem: mmap failed in kernel!\n"); + ret = -EAGAIN; + goto error; + } + list_for_each(elt, &data->region_list) { + region_node = list_entry(elt, struct pmem_region_node, + list); + DLOG("remapping file: %p %lx %lx\n", file, + region_node->region.offset, + region_node->region.len); + if (pmem_remap_pfn_range(id, vma, data, + region_node->region.offset, + region_node->region.len)) { + ret = -EAGAIN; + goto error; + } + } + data->flags |= PMEM_FLAGS_SUBMAP; + get_task_struct(current->group_leader); + data->task = current->group_leader; + data->vma = vma; +#if PMEM_DEBUG + data->pid = current->pid; +#endif + DLOG("submmapped file %p vma %p pid %u\n", file, vma, + current->pid); + } else { + if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) { + printk(KERN_INFO "pmem: mmap failed in kernel!\n"); + ret = -EAGAIN; + goto error; + } + data->flags |= PMEM_FLAGS_MASTERMAP; + data->pid = current->pid; + } + vma->vm_ops = &vm_ops; +error: + up_write(&data->sem); + return ret; +} + +/* the following are the api for accessing pmem regions by other drivers + * from inside the kernel */ +int get_pmem_user_addr(struct file *file, unsigned long *start, + unsigned long *len) +{ + struct pmem_data *data; + if (!is_pmem_file(file) || !has_allocation(file)) { +#if PMEM_DEBUG + printk(KERN_INFO "pmem: requested pmem data from invalid" + "file.\n"); +#endif + return -1; + } + data = (struct pmem_data *)file->private_data; + down_read(&data->sem); + if (data->vma) { + *start = data->vma->vm_start; + *len = data->vma->vm_end - data->vma->vm_start; + } else { + *start = 0; + *len = 0; + } + up_read(&data->sem); + return 0; +} + +int get_pmem_addr(struct file *file, unsigned long *start, + unsigned long *vstart, unsigned long *len) +{ + struct pmem_data *data; + int id; + + if (!is_pmem_file(file) || !has_allocation(file)) { + return -1; + } + + data = (struct pmem_data *)file->private_data; + if (data->index == -1) { +#if PMEM_DEBUG + printk(KERN_INFO "pmem: requested pmem data from file with no " + "allocation.\n"); + return -1; +#endif + } + id = get_id(file); + + down_read(&data->sem); + *start = pmem_start_addr(id, data); + *len = pmem_len(id, data); + *vstart = (unsigned long)pmem_start_vaddr(id, data); + up_read(&data->sem); +#if PMEM_DEBUG + down_write(&data->sem); + data->ref++; + up_write(&data->sem); +#endif + return 0; +} + +int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, + unsigned long *len, struct file **filp) +{ + struct file *file; + + file = fget(fd); + if (unlikely(file == NULL)) { + printk(KERN_INFO "pmem: requested data from file descriptor " + "that doesn't exist."); + return -1; + } + + if (get_pmem_addr(file, start, vstart, len)) + goto end; + + if (filp) + *filp = file; + return 0; +end: + fput(file); + return -1; +} + +void put_pmem_file(struct file *file) +{ + struct pmem_data *data; + int id; + + if (!is_pmem_file(file)) + return; + id = get_id(file); + data = (struct pmem_data *)file->private_data; +#if PMEM_DEBUG + down_write(&data->sem); + if (data->ref == 0) { + printk("pmem: pmem_put > pmem_get %s (pid %d)\n", + pmem[id].dev.name, data->pid); + BUG(); + } + data->ref--; + up_write(&data->sem); +#endif + fput(file); +} + +void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len) +{ + struct pmem_data *data; + int id; + void *vaddr; + struct pmem_region_node *region_node; + struct list_head *elt; + void *flush_start, *flush_end; + + if (!is_pmem_file(file) || !has_allocation(file)) { + return; + } + + id = get_id(file); + data = (struct pmem_data *)file->private_data; + if (!pmem[id].cached || file->f_flags & O_SYNC) + return; + + down_read(&data->sem); + vaddr = pmem_start_vaddr(id, data); + /* if this isn't a submmapped file, flush the whole thing */ + if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) { + dmac_flush_range(vaddr, vaddr + pmem_len(id, data)); + goto end; + } + /* otherwise, flush the region of the file we are drawing */ + list_for_each(elt, &data->region_list) { + region_node = list_entry(elt, struct pmem_region_node, list); + if ((offset >= region_node->region.offset) && + ((offset + len) <= (region_node->region.offset + + region_node->region.len))) { + flush_start = vaddr + region_node->region.offset; + flush_end = flush_start + region_node->region.len; + dmac_flush_range(flush_start, flush_end); + break; + } + } +end: + up_read(&data->sem); +} + +static int pmem_connect(unsigned long connect, struct file *file) +{ + struct pmem_data *data = (struct pmem_data *)file->private_data; + struct pmem_data *src_data; + struct file *src_file; + int ret = 0, put_needed; + + down_write(&data->sem); + /* retrieve the src file and check it is a pmem file with an alloc */ + src_file = fget_light(connect, &put_needed); + DLOG("connect %p to %p\n", file, src_file); + if (!src_file) { + printk("pmem: src file not found!\n"); + ret = -EINVAL; + goto err_no_file; + } + if (unlikely(!is_pmem_file(src_file) || !has_allocation(src_file))) { + printk(KERN_INFO "pmem: src file is not a pmem file or has no " + "alloc!\n"); + ret = -EINVAL; + goto err_bad_file; + } + src_data = (struct pmem_data *)src_file->private_data; + + if (has_allocation(file) && (data->index != src_data->index)) { + printk("pmem: file is already mapped but doesn't match this" + " src_file!\n"); + ret = -EINVAL; + goto err_bad_file; + } + data->index = src_data->index; + data->flags |= PMEM_FLAGS_CONNECTED; + data->master_fd = connect; + data->master_file = src_file; + +err_bad_file: + fput_light(src_file, put_needed); +err_no_file: + up_write(&data->sem); + return ret; +} + +static void pmem_unlock_data_and_mm(struct pmem_data *data, + struct mm_struct *mm) +{ + up_write(&data->sem); + if (mm != NULL) { + up_write(&mm->mmap_sem); + mmput(mm); + } +} + +static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data, + struct mm_struct **locked_mm) +{ + int ret = 0; + struct mm_struct *mm = NULL; + *locked_mm = NULL; +lock_mm: + down_read(&data->sem); + if (PMEM_IS_SUBMAP(data)) { + mm = get_task_mm(data->task); + if (!mm) { +#if PMEM_DEBUG + printk("pmem: can't remap task is gone!\n"); +#endif + up_read(&data->sem); + return -1; + } + } + up_read(&data->sem); + + if (mm) + down_write(&mm->mmap_sem); + + down_write(&data->sem); + /* check that the file didn't get mmaped before we could take the + * data sem, this should be safe b/c you can only submap each file + * once */ + if (PMEM_IS_SUBMAP(data) && !mm) { + pmem_unlock_data_and_mm(data, mm); + up_write(&data->sem); + goto lock_mm; + } + /* now check that vma.mm is still there, it could have been + * deleted by vma_close before we could get the data->sem */ + if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) { + /* might as well release this */ + if (data->flags & PMEM_FLAGS_SUBMAP) { + put_task_struct(data->task); + data->task = NULL; + /* lower the submap flag to show the mm is gone */ + data->flags &= ~(PMEM_FLAGS_SUBMAP); + } + pmem_unlock_data_and_mm(data, mm); + return -1; + } + *locked_mm = mm; + return ret; +} + +int pmem_remap(struct pmem_region *region, struct file *file, + unsigned operation) +{ + int ret; + struct pmem_region_node *region_node; + struct mm_struct *mm = NULL; + struct list_head *elt, *elt2; + int id = get_id(file); + struct pmem_data *data = (struct pmem_data *)file->private_data; + + /* pmem region must be aligned on a page boundry */ + if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) || + !PMEM_IS_PAGE_ALIGNED(region->len))) { +#if PMEM_DEBUG + printk("pmem: request for unaligned pmem suballocation " + "%lx %lx\n", region->offset, region->len); +#endif + return -EINVAL; + } + + /* if userspace requests a region of len 0, there's nothing to do */ + if (region->len == 0) + return 0; + + /* lock the mm and data */ + ret = pmem_lock_data_and_mm(file, data, &mm); + if (ret) + return 0; + + /* only the owner of the master file can remap the client fds + * that back in it */ + if (!is_master_owner(file)) { +#if PMEM_DEBUG + printk("pmem: remap requested from non-master process\n"); +#endif + ret = -EINVAL; + goto err; + } + + /* check that the requested range is within the src allocation */ + if (unlikely((region->offset > pmem_len(id, data)) || + (region->len > pmem_len(id, data)) || + (region->offset + region->len > pmem_len(id, data)))) { +#if PMEM_DEBUG + printk(KERN_INFO "pmem: suballoc doesn't fit in src_file!\n"); +#endif + ret = -EINVAL; + goto err; + } + + if (operation == PMEM_MAP) { + region_node = kmalloc(sizeof(struct pmem_region_node), + GFP_KERNEL); + if (!region_node) { + ret = -ENOMEM; +#if PMEM_DEBUG + printk(KERN_INFO "No space to allocate metadata!"); +#endif + goto err; + } + region_node->region = *region; + list_add(®ion_node->list, &data->region_list); + } else if (operation == PMEM_UNMAP) { + int found = 0; + list_for_each_safe(elt, elt2, &data->region_list) { + region_node = list_entry(elt, struct pmem_region_node, + list); + if (region->len == 0 || + (region_node->region.offset == region->offset && + region_node->region.len == region->len)) { + list_del(elt); + kfree(region_node); + found = 1; + } + } + if (!found) { +#if PMEM_DEBUG + printk("pmem: Unmap region does not map any mapped " + "region!"); +#endif + ret = -EINVAL; + goto err; + } + } + + if (data->vma && PMEM_IS_SUBMAP(data)) { + if (operation == PMEM_MAP) + ret = pmem_remap_pfn_range(id, data->vma, data, + region->offset, region->len); + else if (operation == PMEM_UNMAP) + ret = pmem_unmap_pfn_range(id, data->vma, data, + region->offset, region->len); + } + +err: + pmem_unlock_data_and_mm(data, mm); + return ret; +} + +static void pmem_revoke(struct file *file, struct pmem_data *data) +{ + struct pmem_region_node *region_node; + struct list_head *elt, *elt2; + struct mm_struct *mm = NULL; + int id = get_id(file); + int ret = 0; + + data->master_file = NULL; + ret = pmem_lock_data_and_mm(file, data, &mm); + /* if lock_data_and_mm fails either the task that mapped the fd, or + * the vma that mapped it have already gone away, nothing more + * needs to be done */ + if (ret) + return; + /* unmap everything */ + /* delete the regions and region list nothing is mapped any more */ + if (data->vma) + list_for_each_safe(elt, elt2, &data->region_list) { + region_node = list_entry(elt, struct pmem_region_node, + list); + pmem_unmap_pfn_range(id, data->vma, data, + region_node->region.offset, + region_node->region.len); + list_del(elt); + kfree(region_node); + } + /* delete the master file */ + pmem_unlock_data_and_mm(data, mm); +} + +static void pmem_get_size(struct pmem_region *region, struct file *file) +{ + struct pmem_data *data = (struct pmem_data *)file->private_data; + int id = get_id(file); + + if (!has_allocation(file)) { + region->offset = 0; + region->len = 0; + return; + } else { + region->offset = pmem_start_addr(id, data); + region->len = pmem_len(id, data); + } + DLOG("offset %lx len %lx\n", region->offset, region->len); +} + + +static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pmem_data *data; + int id = get_id(file); + + switch (cmd) { + case PMEM_GET_PHYS: + { + struct pmem_region region; + DLOG("get_phys\n"); + if (!has_allocation(file)) { + region.offset = 0; + region.len = 0; + } else { + data = (struct pmem_data *)file->private_data; + region.offset = pmem_start_addr(id, data); + region.len = pmem_len(id, data); + } + printk(KERN_INFO "pmem: request for physical address of pmem region " + "from process %d.\n", current->pid); + if (copy_to_user((void __user *)arg, ®ion, + sizeof(struct pmem_region))) + return -EFAULT; + break; + } + case PMEM_MAP: + { + struct pmem_region region; + if (copy_from_user(®ion, (void __user *)arg, + sizeof(struct pmem_region))) + return -EFAULT; + data = (struct pmem_data *)file->private_data; + return pmem_remap(®ion, file, PMEM_MAP); + } + break; + case PMEM_UNMAP: + { + struct pmem_region region; + if (copy_from_user(®ion, (void __user *)arg, + sizeof(struct pmem_region))) + return -EFAULT; + data = (struct pmem_data *)file->private_data; + return pmem_remap(®ion, file, PMEM_UNMAP); + break; + } + case PMEM_GET_SIZE: + { + struct pmem_region region; + DLOG("get_size\n"); + pmem_get_size(®ion, file); + if (copy_to_user((void __user *)arg, ®ion, + sizeof(struct pmem_region))) + return -EFAULT; + break; + } + case PMEM_GET_TOTAL_SIZE: + { + struct pmem_region region; + DLOG("get total size\n"); + region.offset = 0; + get_id(file); + region.len = pmem[id].size; + if (copy_to_user((void __user *)arg, ®ion, + sizeof(struct pmem_region))) + return -EFAULT; + break; + } + case PMEM_ALLOCATE: + { + if (has_allocation(file)) + return -EINVAL; + data = (struct pmem_data *)file->private_data; + data->index = pmem_allocate(id, arg); + break; + } + case PMEM_CONNECT: + DLOG("connect\n"); + return pmem_connect(arg, file); + break; + case PMEM_CACHE_FLUSH: + { + struct pmem_region region; + DLOG("flush\n"); + if (copy_from_user(®ion, (void __user *)arg, + sizeof(struct pmem_region))) + return -EFAULT; + flush_pmem_file(file, region.offset, region.len); + break; + } + default: + if (pmem[id].ioctl) + return pmem[id].ioctl(file, cmd, arg); + return -EINVAL; + } + return 0; +} + +#if PMEM_DEBUG +static ssize_t debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t debug_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct list_head *elt, *elt2; + struct pmem_data *data; + struct pmem_region_node *region_node; + int id = (int)file->private_data; + const int debug_bufmax = 4096; + static char buffer[4096]; + int n = 0; + + DLOG("debug open\n"); + n = scnprintf(buffer, debug_bufmax, + "pid #: mapped regions (offset, len) (offset,len)...\n"); + + mutex_lock(&pmem[id].data_list_lock); + list_for_each(elt, &pmem[id].data_list) { + data = list_entry(elt, struct pmem_data, list); + down_read(&data->sem); + n += scnprintf(buffer + n, debug_bufmax - n, "pid %u:", + data->pid); + list_for_each(elt2, &data->region_list) { + region_node = list_entry(elt2, struct pmem_region_node, + list); + n += scnprintf(buffer + n, debug_bufmax - n, + "(%lx,%lx) ", + region_node->region.offset, + region_node->region.len); + } + n += scnprintf(buffer + n, debug_bufmax - n, "\n"); + up_read(&data->sem); + } + mutex_unlock(&pmem[id].data_list_lock); + + n++; + buffer[n] = 0; + return simple_read_from_buffer(buf, count, ppos, buffer, n); +} + +static struct file_operations debug_fops = { + .read = debug_read, + .open = debug_open, +}; +#endif + +#if 0 +static struct miscdevice pmem_dev = { + .name = "pmem", + .fops = &pmem_fops, +}; +#endif + +int pmem_setup(struct android_pmem_platform_data *pdata, + long (*ioctl)(struct file *, unsigned int, unsigned long), + int (*release)(struct inode *, struct file *)) +{ + int err = 0; + int i, index = 0; + int id = id_count; + id_count++; + + pmem[id].no_allocator = pdata->no_allocator; + pmem[id].cached = pdata->cached; + pmem[id].buffered = pdata->buffered; + pmem[id].base = pdata->start; + pmem[id].size = pdata->size; + pmem[id].ioctl = ioctl; + pmem[id].release = release; + init_rwsem(&pmem[id].bitmap_sem); + mutex_init(&pmem[id].data_list_lock); + INIT_LIST_HEAD(&pmem[id].data_list); + pmem[id].dev.name = pdata->name; + pmem[id].dev.minor = id; + pmem[id].dev.fops = &pmem_fops; + printk(KERN_INFO "%s: %d init\n", pdata->name, pdata->cached); + + err = misc_register(&pmem[id].dev); + if (err) { + printk(KERN_ALERT "Unable to register pmem driver!\n"); + goto err_cant_register_device; + } + pmem[id].num_entries = pmem[id].size / PMEM_MIN_ALLOC; + + pmem[id].bitmap = kmalloc(pmem[id].num_entries * + sizeof(struct pmem_bits), GFP_KERNEL); + if (!pmem[id].bitmap) + goto err_no_mem_for_metadata; + + memset(pmem[id].bitmap, 0, sizeof(struct pmem_bits) * + pmem[id].num_entries); + + for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--) { + if ((pmem[id].num_entries) & 1<<i) { + PMEM_ORDER(id, index) = i; + index = PMEM_NEXT_INDEX(id, index); + } + } + + if (pmem[id].cached) + pmem[id].vbase = ioremap_cached(pmem[id].base, + pmem[id].size); +#ifdef ioremap_ext_buffered + else if (pmem[id].buffered) + pmem[id].vbase = ioremap_ext_buffered(pmem[id].base, + pmem[id].size); +#endif + else + pmem[id].vbase = ioremap(pmem[id].base, pmem[id].size); + + if (pmem[id].vbase == 0) + goto error_cant_remap; + + pmem[id].garbage_pfn = page_to_pfn(alloc_page(GFP_KERNEL)); + if (pmem[id].no_allocator) + pmem[id].allocated = 0; + +#if PMEM_DEBUG + debugfs_create_file(pdata->name, S_IFREG | S_IRUGO, NULL, (void *)id, + &debug_fops); +#endif + return 0; +error_cant_remap: + kfree(pmem[id].bitmap); +err_no_mem_for_metadata: + misc_deregister(&pmem[id].dev); +err_cant_register_device: + return -1; +} + +static int pmem_probe(struct platform_device *pdev) +{ + struct android_pmem_platform_data *pdata; + + if (!pdev || !pdev->dev.platform_data) { + printk(KERN_ALERT "Unable to probe pmem!\n"); + return -1; + } + pdata = pdev->dev.platform_data; + return pmem_setup(pdata, NULL, NULL); +} + + +static int pmem_remove(struct platform_device *pdev) +{ + int id = pdev->id; + __free_page(pfn_to_page(pmem[id].garbage_pfn)); + misc_deregister(&pmem[id].dev); + return 0; +} + +static struct platform_driver pmem_driver = { + .probe = pmem_probe, + .remove = pmem_remove, + .driver = { .name = "android_pmem" } +}; + + +static int __init pmem_init(void) +{ + return platform_driver_register(&pmem_driver); +} + +static void __exit pmem_exit(void) +{ + platform_driver_unregister(&pmem_driver); +} + +module_init(pmem_init); +module_exit(pmem_exit); + diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c new file mode 100644 index 00000000000..6d4d67924f2 --- /dev/null +++ b/drivers/staging/android/ram_console.c @@ -0,0 +1,443 @@ +/* drivers/android/ram_console.c + * + * Copyright (C) 2007-2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/console.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/proc_fs.h> +#include <linux/string.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include "ram_console.h" + +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION +#include <linux/rslib.h> +#endif + +struct ram_console_buffer { + uint32_t sig; + uint32_t start; + uint32_t size; + uint8_t data[0]; +}; + +#define RAM_CONSOLE_SIG (0x43474244) /* DBGC */ + +#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT +static char __initdata + ram_console_old_log_init_buffer[CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE]; +#endif +static char *ram_console_old_log; +static size_t ram_console_old_log_size; + +static struct ram_console_buffer *ram_console_buffer; +static size_t ram_console_buffer_size; +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION +static char *ram_console_par_buffer; +static struct rs_control *ram_console_rs_decoder; +static int ram_console_corrected_bytes; +static int ram_console_bad_blocks; +#define ECC_BLOCK_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE +#define ECC_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE +#define ECC_SYMSIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE +#define ECC_POLY CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL +#endif + +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION +static void ram_console_encode_rs8(uint8_t *data, size_t len, uint8_t *ecc) +{ + int i; + uint16_t par[ECC_SIZE]; + /* Initialize the parity buffer */ + memset(par, 0, sizeof(par)); + encode_rs8(ram_console_rs_decoder, data, len, par, 0); + for (i = 0; i < ECC_SIZE; i++) + ecc[i] = par[i]; +} + +static int ram_console_decode_rs8(void *data, size_t len, uint8_t *ecc) +{ + int i; + uint16_t par[ECC_SIZE]; + for (i = 0; i < ECC_SIZE; i++) + par[i] = ecc[i]; + return decode_rs8(ram_console_rs_decoder, data, par, len, + NULL, 0, NULL, 0, NULL); +} +#endif + +static void ram_console_update(const char *s, unsigned int count) +{ + struct ram_console_buffer *buffer = ram_console_buffer; +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION + uint8_t *buffer_end = buffer->data + ram_console_buffer_size; + uint8_t *block; + uint8_t *par; + int size = ECC_BLOCK_SIZE; +#endif + memcpy(buffer->data + buffer->start, s, count); +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION + block = buffer->data + (buffer->start & ~(ECC_BLOCK_SIZE - 1)); + par = ram_console_par_buffer + + (buffer->start / ECC_BLOCK_SIZE) * ECC_SIZE; + do { + if (block + ECC_BLOCK_SIZE > buffer_end) + size = buffer_end - block; + ram_console_encode_rs8(block, size, par); + block += ECC_BLOCK_SIZE; + par += ECC_SIZE; + } while (block < buffer->data + buffer->start + count); +#endif +} + +static void ram_console_update_header(void) +{ +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION + struct ram_console_buffer *buffer = ram_console_buffer; + uint8_t *par; + par = ram_console_par_buffer + + DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE; + ram_console_encode_rs8((uint8_t *)buffer, sizeof(*buffer), par); +#endif +} + +static void +ram_console_write(struct console *console, const char *s, unsigned int count) +{ + int rem; + struct ram_console_buffer *buffer = ram_console_buffer; + + if (count > ram_console_buffer_size) { + s += count - ram_console_buffer_size; + count = ram_console_buffer_size; + } + rem = ram_console_buffer_size - buffer->start; + if (rem < count) { + ram_console_update(s, rem); + s += rem; + count -= rem; + buffer->start = 0; + buffer->size = ram_console_buffer_size; + } + ram_console_update(s, count); + + buffer->start += count; + if (buffer->size < ram_console_buffer_size) + buffer->size += count; + ram_console_update_header(); +} + +static struct console ram_console = { + .name = "ram", + .write = ram_console_write, + .flags = CON_PRINTBUFFER | CON_ENABLED, + .index = -1, +}; + +void ram_console_enable_console(int enabled) +{ + if (enabled) + ram_console.flags |= CON_ENABLED; + else + ram_console.flags &= ~CON_ENABLED; +} + +static void __init +ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo, + char *dest) +{ + size_t old_log_size = buffer->size; + size_t bootinfo_size = 0; + size_t total_size = old_log_size; + char *ptr; + const char *bootinfo_label = "Boot info:\n"; + +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION + uint8_t *block; + uint8_t *par; + char strbuf[80]; + int strbuf_len = 0; + + block = buffer->data; + par = ram_console_par_buffer; + while (block < buffer->data + buffer->size) { + int numerr; + int size = ECC_BLOCK_SIZE; + if (block + size > buffer->data + ram_console_buffer_size) + size = buffer->data + ram_console_buffer_size - block; + numerr = ram_console_decode_rs8(block, size, par); + if (numerr > 0) { +#if 0 + printk(KERN_INFO "ram_console: error in block %p, %d\n", + block, numerr); +#endif + ram_console_corrected_bytes += numerr; + } else if (numerr < 0) { +#if 0 + printk(KERN_INFO "ram_console: uncorrectable error in " + "block %p\n", block); +#endif + ram_console_bad_blocks++; + } + block += ECC_BLOCK_SIZE; + par += ECC_SIZE; + } + if (ram_console_corrected_bytes || ram_console_bad_blocks) + strbuf_len = snprintf(strbuf, sizeof(strbuf), + "\n%d Corrected bytes, %d unrecoverable blocks\n", + ram_console_corrected_bytes, ram_console_bad_blocks); + else + strbuf_len = snprintf(strbuf, sizeof(strbuf), + "\nNo errors detected\n"); + if (strbuf_len >= sizeof(strbuf)) + strbuf_len = sizeof(strbuf) - 1; + total_size += strbuf_len; +#endif + + if (bootinfo) + bootinfo_size = strlen(bootinfo) + strlen(bootinfo_label); + total_size += bootinfo_size; + + if (dest == NULL) { + dest = kmalloc(total_size, GFP_KERNEL); + if (dest == NULL) { + printk(KERN_ERR + "ram_console: failed to allocate buffer\n"); + return; + } + } + + ram_console_old_log = dest; + ram_console_old_log_size = total_size; + memcpy(ram_console_old_log, + &buffer->data[buffer->start], buffer->size - buffer->start); + memcpy(ram_console_old_log + buffer->size - buffer->start, + &buffer->data[0], buffer->start); + ptr = ram_console_old_log + old_log_size; +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION + memcpy(ptr, strbuf, strbuf_len); + ptr += strbuf_len; +#endif + if (bootinfo) { + memcpy(ptr, bootinfo_label, strlen(bootinfo_label)); + ptr += strlen(bootinfo_label); + memcpy(ptr, bootinfo, bootinfo_size); + ptr += bootinfo_size; + } +} + +static int __init ram_console_init(struct ram_console_buffer *buffer, + size_t buffer_size, const char *bootinfo, + char *old_buf) +{ +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION + int numerr; + uint8_t *par; +#endif + ram_console_buffer = buffer; + ram_console_buffer_size = + buffer_size - sizeof(struct ram_console_buffer); + + if (ram_console_buffer_size > buffer_size) { + pr_err("ram_console: buffer %p, invalid size %zu, " + "datasize %zu\n", buffer, buffer_size, + ram_console_buffer_size); + return 0; + } + +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION + ram_console_buffer_size -= (DIV_ROUND_UP(ram_console_buffer_size, + ECC_BLOCK_SIZE) + 1) * ECC_SIZE; + + if (ram_console_buffer_size > buffer_size) { + pr_err("ram_console: buffer %p, invalid size %zu, " + "non-ecc datasize %zu\n", + buffer, buffer_size, ram_console_buffer_size); + return 0; + } + + ram_console_par_buffer = buffer->data + ram_console_buffer_size; + + + /* first consecutive root is 0 + * primitive element to generate roots = 1 + */ + ram_console_rs_decoder = init_rs(ECC_SYMSIZE, ECC_POLY, 0, 1, ECC_SIZE); + if (ram_console_rs_decoder == NULL) { + printk(KERN_INFO "ram_console: init_rs failed\n"); + return 0; + } + + ram_console_corrected_bytes = 0; + ram_console_bad_blocks = 0; + + par = ram_console_par_buffer + + DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE; + + numerr = ram_console_decode_rs8(buffer, sizeof(*buffer), par); + if (numerr > 0) { + printk(KERN_INFO "ram_console: error in header, %d\n", numerr); + ram_console_corrected_bytes += numerr; + } else if (numerr < 0) { + printk(KERN_INFO + "ram_console: uncorrectable error in header\n"); + ram_console_bad_blocks++; + } +#endif + + if (buffer->sig == RAM_CONSOLE_SIG) { + if (buffer->size > ram_console_buffer_size + || buffer->start > buffer->size) + printk(KERN_INFO "ram_console: found existing invalid " + "buffer, size %d, start %d\n", + buffer->size, buffer->start); + else { + printk(KERN_INFO "ram_console: found existing buffer, " + "size %d, start %d\n", + buffer->size, buffer->start); + ram_console_save_old(buffer, bootinfo, old_buf); + } + } else { + printk(KERN_INFO "ram_console: no valid data in buffer " + "(sig = 0x%08x)\n", buffer->sig); + } + + buffer->sig = RAM_CONSOLE_SIG; + buffer->start = 0; + buffer->size = 0; + + register_console(&ram_console); +#ifdef CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE + console_verbose(); +#endif + return 0; +} + +#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT +static int __init ram_console_early_init(void) +{ + return ram_console_init((struct ram_console_buffer *) + CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR, + CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE, + NULL, + ram_console_old_log_init_buffer); +} +#else +static int ram_console_driver_probe(struct platform_device *pdev) +{ + struct resource *res = pdev->resource; + size_t start; + size_t buffer_size; + void *buffer; + const char *bootinfo = NULL; + struct ram_console_platform_data *pdata = pdev->dev.platform_data; + + if (res == NULL || pdev->num_resources != 1 || + !(res->flags & IORESOURCE_MEM)) { + printk(KERN_ERR "ram_console: invalid resource, %p %d flags " + "%lx\n", res, pdev->num_resources, res ? res->flags : 0); + return -ENXIO; + } + buffer_size = res->end - res->start + 1; + start = res->start; + printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n", + start, buffer_size); + buffer = ioremap(res->start, buffer_size); + if (buffer == NULL) { + printk(KERN_ERR "ram_console: failed to map memory\n"); + return -ENOMEM; + } + + if (pdata) + bootinfo = pdata->bootinfo; + + return ram_console_init(buffer, buffer_size, bootinfo, NULL/* allocate */); +} + +static struct platform_driver ram_console_driver = { + .probe = ram_console_driver_probe, + .driver = { + .name = "ram_console", + }, +}; + +static int __init ram_console_module_init(void) +{ + int err; + err = platform_driver_register(&ram_console_driver); + return err; +} +#endif + +static ssize_t ram_console_read_old(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + loff_t pos = *offset; + ssize_t count; + + if (pos >= ram_console_old_log_size) + return 0; + + count = min(len, (size_t)(ram_console_old_log_size - pos)); + if (copy_to_user(buf, ram_console_old_log + pos, count)) + return -EFAULT; + + *offset += count; + return count; +} + +static const struct file_operations ram_console_file_ops = { + .owner = THIS_MODULE, + .read = ram_console_read_old, +}; + +static int __init ram_console_late_init(void) +{ + struct proc_dir_entry *entry; + + if (ram_console_old_log == NULL) + return 0; +#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT + ram_console_old_log = kmalloc(ram_console_old_log_size, GFP_KERNEL); + if (ram_console_old_log == NULL) { + printk(KERN_ERR + "ram_console: failed to allocate buffer for old log\n"); + ram_console_old_log_size = 0; + return 0; + } + memcpy(ram_console_old_log, + ram_console_old_log_init_buffer, ram_console_old_log_size); +#endif + entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL); + if (!entry) { + printk(KERN_ERR "ram_console: failed to create proc entry\n"); + kfree(ram_console_old_log); + ram_console_old_log = NULL; + return 0; + } + + entry->proc_fops = &ram_console_file_ops; + entry->size = ram_console_old_log_size; + return 0; +} + +#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT +console_initcall(ram_console_early_init); +#else +postcore_initcall(ram_console_module_init); +#endif +late_initcall(ram_console_late_init); + diff --git a/drivers/staging/android/ram_console.h b/drivers/staging/android/ram_console.h new file mode 100644 index 00000000000..9f1125c1106 --- /dev/null +++ b/drivers/staging/android/ram_console.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ +#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ + +struct ram_console_platform_data { + const char *bootinfo; +}; + +#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */ diff --git a/drivers/staging/android/switch/Kconfig b/drivers/staging/android/switch/Kconfig new file mode 100644 index 00000000000..36846f62f4b --- /dev/null +++ b/drivers/staging/android/switch/Kconfig @@ -0,0 +1,11 @@ +menuconfig ANDROID_SWITCH + tristate "Android Switch class support" + help + Say Y here to enable Android switch class support. This allows + monitoring switches by userspace via sysfs and uevent. + +config ANDROID_SWITCH_GPIO + tristate "Android GPIO Switch support" + depends on GENERIC_GPIO && ANDROID_SWITCH + help + Say Y here to enable GPIO based switch support. diff --git a/drivers/staging/android/switch/Makefile b/drivers/staging/android/switch/Makefile new file mode 100644 index 00000000000..d76bfdcedfa --- /dev/null +++ b/drivers/staging/android/switch/Makefile @@ -0,0 +1,4 @@ +# Android Switch Class Driver +obj-$(CONFIG_ANDROID_SWITCH) += switch_class.o +obj-$(CONFIG_ANDROID_SWITCH_GPIO) += switch_gpio.o + diff --git a/drivers/staging/android/switch/switch.h b/drivers/staging/android/switch/switch.h new file mode 100644 index 00000000000..4fcb3109875 --- /dev/null +++ b/drivers/staging/android/switch/switch.h @@ -0,0 +1,53 @@ +/* + * Switch class driver + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * +*/ + +#ifndef __LINUX_SWITCH_H__ +#define __LINUX_SWITCH_H__ + +struct switch_dev { + const char *name; + struct device *dev; + int index; + int state; + + ssize_t (*print_name)(struct switch_dev *sdev, char *buf); + ssize_t (*print_state)(struct switch_dev *sdev, char *buf); +}; + +struct gpio_switch_platform_data { + const char *name; + unsigned gpio; + + /* if NULL, switch_dev.name will be printed */ + const char *name_on; + const char *name_off; + /* if NULL, "0" or "1" will be printed */ + const char *state_on; + const char *state_off; +}; + +extern int switch_dev_register(struct switch_dev *sdev); +extern void switch_dev_unregister(struct switch_dev *sdev); + +static inline int switch_get_state(struct switch_dev *sdev) +{ + return sdev->state; +} + +extern void switch_set_state(struct switch_dev *sdev, int state); + +#endif /* __LINUX_SWITCH_H__ */ diff --git a/drivers/staging/android/switch/switch_class.c b/drivers/staging/android/switch/switch_class.c new file mode 100644 index 00000000000..74680446fc6 --- /dev/null +++ b/drivers/staging/android/switch/switch_class.c @@ -0,0 +1,174 @@ +/* + * switch_class.c + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * +*/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/err.h> +#include "switch.h" + +struct class *switch_class; +static atomic_t device_count; + +static ssize_t state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_dev *sdev = (struct switch_dev *) + dev_get_drvdata(dev); + + if (sdev->print_state) { + int ret = sdev->print_state(sdev, buf); + if (ret >= 0) + return ret; + } + return sprintf(buf, "%d\n", sdev->state); +} + +static ssize_t name_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_dev *sdev = (struct switch_dev *) + dev_get_drvdata(dev); + + if (sdev->print_name) { + int ret = sdev->print_name(sdev, buf); + if (ret >= 0) + return ret; + } + return sprintf(buf, "%s\n", sdev->name); +} + +static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL); +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL); + +void switch_set_state(struct switch_dev *sdev, int state) +{ + char name_buf[120]; + char state_buf[120]; + char *prop_buf; + char *envp[3]; + int env_offset = 0; + int length; + + if (sdev->state != state) { + sdev->state = state; + + prop_buf = (char *)get_zeroed_page(GFP_KERNEL); + if (prop_buf) { + length = name_show(sdev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(name_buf, sizeof(name_buf), + "SWITCH_NAME=%s", prop_buf); + envp[env_offset++] = name_buf; + } + length = state_show(sdev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(state_buf, sizeof(state_buf), + "SWITCH_STATE=%s", prop_buf); + envp[env_offset++] = state_buf; + } + envp[env_offset] = NULL; + kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp); + free_page((unsigned long)prop_buf); + } else { + printk(KERN_ERR "out of memory in switch_set_state\n"); + kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE); + } + } +} +EXPORT_SYMBOL_GPL(switch_set_state); + +static int create_switch_class(void) +{ + if (!switch_class) { + switch_class = class_create(THIS_MODULE, "switch"); + if (IS_ERR(switch_class)) + return PTR_ERR(switch_class); + atomic_set(&device_count, 0); + } + + return 0; +} + +int switch_dev_register(struct switch_dev *sdev) +{ + int ret; + + if (!switch_class) { + ret = create_switch_class(); + if (ret < 0) + return ret; + } + + sdev->index = atomic_inc_return(&device_count); + sdev->dev = device_create(switch_class, NULL, + MKDEV(0, sdev->index), NULL, sdev->name); + if (IS_ERR(sdev->dev)) + return PTR_ERR(sdev->dev); + + ret = device_create_file(sdev->dev, &dev_attr_state); + if (ret < 0) + goto err_create_file_1; + ret = device_create_file(sdev->dev, &dev_attr_name); + if (ret < 0) + goto err_create_file_2; + + dev_set_drvdata(sdev->dev, sdev); + sdev->state = 0; + return 0; + +err_create_file_2: + device_remove_file(sdev->dev, &dev_attr_state); +err_create_file_1: + device_destroy(switch_class, MKDEV(0, sdev->index)); + printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name); + + return ret; +} +EXPORT_SYMBOL_GPL(switch_dev_register); + +void switch_dev_unregister(struct switch_dev *sdev) +{ + device_remove_file(sdev->dev, &dev_attr_name); + device_remove_file(sdev->dev, &dev_attr_state); + device_destroy(switch_class, MKDEV(0, sdev->index)); + dev_set_drvdata(sdev->dev, NULL); +} +EXPORT_SYMBOL_GPL(switch_dev_unregister); + +static int __init switch_class_init(void) +{ + return create_switch_class(); +} + +static void __exit switch_class_exit(void) +{ + class_destroy(switch_class); +} + +module_init(switch_class_init); +module_exit(switch_class_exit); + +MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); +MODULE_DESCRIPTION("Switch class driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/switch/switch_gpio.c b/drivers/staging/android/switch/switch_gpio.c new file mode 100644 index 00000000000..38b2c2f6004 --- /dev/null +++ b/drivers/staging/android/switch/switch_gpio.c @@ -0,0 +1,172 @@ +/* + * switch_gpio.c + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/gpio.h> +#include "switch.h" + +struct gpio_switch_data { + struct switch_dev sdev; + unsigned gpio; + const char *name_on; + const char *name_off; + const char *state_on; + const char *state_off; + int irq; + struct work_struct work; +}; + +static void gpio_switch_work(struct work_struct *work) +{ + int state; + struct gpio_switch_data *data = + container_of(work, struct gpio_switch_data, work); + + state = gpio_get_value(data->gpio); + switch_set_state(&data->sdev, state); +} + +static irqreturn_t gpio_irq_handler(int irq, void *dev_id) +{ + struct gpio_switch_data *switch_data = + (struct gpio_switch_data *)dev_id; + + schedule_work(&switch_data->work); + return IRQ_HANDLED; +} + +static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf) +{ + struct gpio_switch_data *switch_data = + container_of(sdev, struct gpio_switch_data, sdev); + const char *state; + if (switch_get_state(sdev)) + state = switch_data->state_on; + else + state = switch_data->state_off; + + if (state) + return sprintf(buf, "%s\n", state); + return -1; +} + +static int gpio_switch_probe(struct platform_device *pdev) +{ + struct gpio_switch_platform_data *pdata = pdev->dev.platform_data; + struct gpio_switch_data *switch_data; + int ret = 0; + + if (!pdata) + return -EBUSY; + + switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL); + if (!switch_data) + return -ENOMEM; + + switch_data->sdev.name = pdata->name; + switch_data->gpio = pdata->gpio; + switch_data->name_on = pdata->name_on; + switch_data->name_off = pdata->name_off; + switch_data->state_on = pdata->state_on; + switch_data->state_off = pdata->state_off; + switch_data->sdev.print_state = switch_gpio_print_state; + + ret = switch_dev_register(&switch_data->sdev); + if (ret < 0) + goto err_switch_dev_register; + + ret = gpio_request(switch_data->gpio, pdev->name); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(switch_data->gpio); + if (ret < 0) + goto err_set_gpio_input; + + INIT_WORK(&switch_data->work, gpio_switch_work); + + switch_data->irq = gpio_to_irq(switch_data->gpio); + if (switch_data->irq < 0) { + ret = switch_data->irq; + goto err_detect_irq_num_failed; + } + + ret = request_irq(switch_data->irq, gpio_irq_handler, + IRQF_TRIGGER_LOW, pdev->name, switch_data); + if (ret < 0) + goto err_request_irq; + + /* Perform initial detection */ + gpio_switch_work(&switch_data->work); + + return 0; + +err_request_irq: +err_detect_irq_num_failed: +err_set_gpio_input: + gpio_free(switch_data->gpio); +err_request_gpio: + switch_dev_unregister(&switch_data->sdev); +err_switch_dev_register: + kfree(switch_data); + + return ret; +} + +static int __devexit gpio_switch_remove(struct platform_device *pdev) +{ + struct gpio_switch_data *switch_data = platform_get_drvdata(pdev); + + cancel_work_sync(&switch_data->work); + gpio_free(switch_data->gpio); + switch_dev_unregister(&switch_data->sdev); + kfree(switch_data); + + return 0; +} + +static struct platform_driver gpio_switch_driver = { + .probe = gpio_switch_probe, + .remove = __devexit_p(gpio_switch_remove), + .driver = { + .name = "switch-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init gpio_switch_init(void) +{ + return platform_driver_register(&gpio_switch_driver); +} + +static void __exit gpio_switch_exit(void) +{ + platform_driver_unregister(&gpio_switch_driver); +} + +module_init(gpio_switch_init); +module_exit(gpio_switch_exit); + +MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); +MODULE_DESCRIPTION("GPIO Switch driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c new file mode 100644 index 00000000000..a64481c3e86 --- /dev/null +++ b/drivers/staging/android/timed_gpio.c @@ -0,0 +1,176 @@ +/* drivers/misc/timed_gpio.c + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/hrtimer.h> +#include <linux/err.h> +#include <linux/gpio.h> + +#include "timed_output.h" +#include "timed_gpio.h" + + +struct timed_gpio_data { + struct timed_output_dev dev; + struct hrtimer timer; + spinlock_t lock; + unsigned gpio; + int max_timeout; + u8 active_low; +}; + +static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer) +{ + struct timed_gpio_data *data = + container_of(timer, struct timed_gpio_data, timer); + + gpio_direction_output(data->gpio, data->active_low ? 1 : 0); + return HRTIMER_NORESTART; +} + +static int gpio_get_time(struct timed_output_dev *dev) +{ + struct timed_gpio_data *data = + container_of(dev, struct timed_gpio_data, dev); + + if (hrtimer_active(&data->timer)) { + ktime_t r = hrtimer_get_remaining(&data->timer); + struct timeval t = ktime_to_timeval(r); + return t.tv_sec * 1000 + t.tv_usec / 1000; + } else + return 0; +} + +static void gpio_enable(struct timed_output_dev *dev, int value) +{ + struct timed_gpio_data *data = + container_of(dev, struct timed_gpio_data, dev); + unsigned long flags; + + spin_lock_irqsave(&data->lock, flags); + + /* cancel previous timer and set GPIO according to value */ + hrtimer_cancel(&data->timer); + gpio_direction_output(data->gpio, data->active_low ? !value : !!value); + + if (value > 0) { + if (value > data->max_timeout) + value = data->max_timeout; + + hrtimer_start(&data->timer, + ktime_set(value / 1000, (value % 1000) * 1000000), + HRTIMER_MODE_REL); + } + + spin_unlock_irqrestore(&data->lock, flags); +} + +static int timed_gpio_probe(struct platform_device *pdev) +{ + struct timed_gpio_platform_data *pdata = pdev->dev.platform_data; + struct timed_gpio *cur_gpio; + struct timed_gpio_data *gpio_data, *gpio_dat; + int i, j, ret = 0; + + if (!pdata) + return -EBUSY; + + gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios, + GFP_KERNEL); + if (!gpio_data) + return -ENOMEM; + + for (i = 0; i < pdata->num_gpios; i++) { + cur_gpio = &pdata->gpios[i]; + gpio_dat = &gpio_data[i]; + + hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + gpio_dat->timer.function = gpio_timer_func; + spin_lock_init(&gpio_dat->lock); + + gpio_dat->dev.name = cur_gpio->name; + gpio_dat->dev.get_time = gpio_get_time; + gpio_dat->dev.enable = gpio_enable; + ret = gpio_request(cur_gpio->gpio, cur_gpio->name); + if (ret >= 0) { + ret = timed_output_dev_register(&gpio_dat->dev); + if (ret < 0) + gpio_free(cur_gpio->gpio); + } + if (ret < 0) { + for (j = 0; j < i; j++) { + timed_output_dev_unregister(&gpio_data[i].dev); + gpio_free(gpio_data[i].gpio); + } + kfree(gpio_data); + return ret; + } + + gpio_dat->gpio = cur_gpio->gpio; + gpio_dat->max_timeout = cur_gpio->max_timeout; + gpio_dat->active_low = cur_gpio->active_low; + gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low); + } + + platform_set_drvdata(pdev, gpio_data); + + return 0; +} + +static int timed_gpio_remove(struct platform_device *pdev) +{ + struct timed_gpio_platform_data *pdata = pdev->dev.platform_data; + struct timed_gpio_data *gpio_data = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < pdata->num_gpios; i++) { + timed_output_dev_unregister(&gpio_data[i].dev); + gpio_free(gpio_data[i].gpio); + } + + kfree(gpio_data); + + return 0; +} + +static struct platform_driver timed_gpio_driver = { + .probe = timed_gpio_probe, + .remove = timed_gpio_remove, + .driver = { + .name = TIMED_GPIO_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init timed_gpio_init(void) +{ + return platform_driver_register(&timed_gpio_driver); +} + +static void __exit timed_gpio_exit(void) +{ + platform_driver_unregister(&timed_gpio_driver); +} + +module_init(timed_gpio_init); +module_exit(timed_gpio_exit); + +MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); +MODULE_DESCRIPTION("timed gpio driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/timed_gpio.h b/drivers/staging/android/timed_gpio.h new file mode 100644 index 00000000000..a0e15f8be3f --- /dev/null +++ b/drivers/staging/android/timed_gpio.h @@ -0,0 +1,33 @@ +/* include/linux/timed_gpio.h + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * +*/ + +#ifndef _LINUX_TIMED_GPIO_H +#define _LINUX_TIMED_GPIO_H + +#define TIMED_GPIO_NAME "timed-gpio" + +struct timed_gpio { + const char *name; + unsigned gpio; + int max_timeout; + u8 active_low; +}; + +struct timed_gpio_platform_data { + int num_gpios; + struct timed_gpio *gpios; +}; + +#endif diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c new file mode 100644 index 00000000000..f373422308e --- /dev/null +++ b/drivers/staging/android/timed_output.c @@ -0,0 +1,123 @@ +/* drivers/misc/timed_output.c + * + * Copyright (C) 2009 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/err.h> + +#include "timed_output.h" + +static struct class *timed_output_class; +static atomic_t device_count; + +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct timed_output_dev *tdev = dev_get_drvdata(dev); + int remaining = tdev->get_time(tdev); + + return sprintf(buf, "%d\n", remaining); +} + +static ssize_t enable_store( + struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct timed_output_dev *tdev = dev_get_drvdata(dev); + int value; + + if (sscanf(buf, "%d", &value) != 1) + return -EINVAL; + + tdev->enable(tdev, value); + + return size; +} + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); + +static int create_timed_output_class(void) +{ + if (!timed_output_class) { + timed_output_class = class_create(THIS_MODULE, "timed_output"); + if (IS_ERR(timed_output_class)) + return PTR_ERR(timed_output_class); + atomic_set(&device_count, 0); + } + + return 0; +} + +int timed_output_dev_register(struct timed_output_dev *tdev) +{ + int ret; + + if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) + return -EINVAL; + + ret = create_timed_output_class(); + if (ret < 0) + return ret; + + tdev->index = atomic_inc_return(&device_count); + tdev->dev = device_create(timed_output_class, NULL, + MKDEV(0, tdev->index), NULL, tdev->name); + if (IS_ERR(tdev->dev)) + return PTR_ERR(tdev->dev); + + ret = device_create_file(tdev->dev, &dev_attr_enable); + if (ret < 0) + goto err_create_file; + + dev_set_drvdata(tdev->dev, tdev); + tdev->state = 0; + return 0; + +err_create_file: + device_destroy(timed_output_class, MKDEV(0, tdev->index)); + printk(KERN_ERR "timed_output: Failed to register driver %s\n", + tdev->name); + + return ret; +} +EXPORT_SYMBOL_GPL(timed_output_dev_register); + +void timed_output_dev_unregister(struct timed_output_dev *tdev) +{ + device_remove_file(tdev->dev, &dev_attr_enable); + device_destroy(timed_output_class, MKDEV(0, tdev->index)); + dev_set_drvdata(tdev->dev, NULL); +} +EXPORT_SYMBOL_GPL(timed_output_dev_unregister); + +static int __init timed_output_init(void) +{ + return create_timed_output_class(); +} + +static void __exit timed_output_exit(void) +{ + class_destroy(timed_output_class); +} + +module_init(timed_output_init); +module_exit(timed_output_exit); + +MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); +MODULE_DESCRIPTION("timed output class driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/timed_output.h b/drivers/staging/android/timed_output.h new file mode 100644 index 00000000000..ec907ab2ff5 --- /dev/null +++ b/drivers/staging/android/timed_output.h @@ -0,0 +1,37 @@ +/* include/linux/timed_output.h + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * +*/ + +#ifndef _LINUX_TIMED_OUTPUT_H +#define _LINUX_TIMED_OUTPUT_H + +struct timed_output_dev { + const char *name; + + /* enable the output and set the timer */ + void (*enable)(struct timed_output_dev *sdev, int timeout); + + /* returns the current number of milliseconds remaining on the timer */ + int (*get_time)(struct timed_output_dev *sdev); + + /* private data */ + struct device *dev; + int index; + int state; +}; + +extern int timed_output_dev_register(struct timed_output_dev *dev); +extern void timed_output_dev_unregister(struct timed_output_dev *dev); + +#endif diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index 7bb7da7959a..e77e4e0396c 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -201,7 +201,7 @@ static ssize_t set_enabled(struct device *dev, struct device_attribute *attr, struct usb_interface *intf = to_usb_interface(dev); struct asus_oled_dev *odev = usb_get_intfdata(intf); unsigned long value; - if (strict_strtoul(buf, 10, &value)) + if (kstrtoul(buf, 10, &value)) return -EINVAL; enable_oled(odev, value); @@ -217,7 +217,7 @@ static ssize_t class_set_enabled(struct device *device, (struct asus_oled_dev *) dev_get_drvdata(device); unsigned long value; - if (strict_strtoul(buf, 10, &value)) + if (kstrtoul(buf, 10, &value)) return -EINVAL; enable_oled(odev, value); diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index 2fa658eb74d..179707b5e7c 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -161,6 +161,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) INT Status = STATUS_FAILURE; int timeout = 0; IOCTL_BUFFER IoBuffer; + int bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX", cmd, arg); @@ -230,11 +231,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if (!temp_buff) return -ENOMEM; - Status = rdmalt(Adapter, (UINT)sRdmBuffer.Register, + bytes = rdmalt(Adapter, (UINT)sRdmBuffer.Register, (PUINT)temp_buff, Bufflen); - if (Status == STATUS_SUCCESS) { - if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength)) - Status = -EFAULT; + if (bytes > 0) { + Status = STATUS_SUCCESS; + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { + kfree(temp_buff); + return -EFAULT; + } + } else { + Status = bytes; } kfree(temp_buff); @@ -302,7 +308,11 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) return -EFAULT; - /* FIXME: don't trust user supplied length */ + if (IoBuffer.OutputLength > USHRT_MAX || + IoBuffer.OutputLength == 0) { + return -EINVAL; + } + temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL); if (!temp_buff) return STATUS_FAILURE; @@ -318,11 +328,17 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK; - Status = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register, (PUINT)temp_buff, IoBuffer.OutputLength); + bytes = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register, (PUINT)temp_buff, IoBuffer.OutputLength); - if (Status == STATUS_SUCCESS) - if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength)) - Status = -EFAULT; + if (bytes > 0) { + Status = STATUS_SUCCESS; + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { + kfree(temp_buff); + return -EFAULT; + } + } else { + Status = bytes; + } kfree(temp_buff); break; @@ -437,12 +453,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } } - Status = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); - - if (STATUS_SUCCESS != Status) { + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); + if (bytes < 0) { + Status = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "GPIO_MODE_REGISTER read failed"); break; + } else { + Status = STATUS_SUCCESS; } /* Set the gpio mode register to output */ @@ -519,12 +537,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) uiBit = gpio_info.uiGpioNumber; /* Set the gpio output register */ - Status = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, (PUINT)ucRead, sizeof(UINT)); - if (Status != STATUS_SUCCESS) { + if (bytes < 0) { + Status = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM Failed\n"); return Status; + } else { + Status = STATUS_SUCCESS; } } break; @@ -590,11 +611,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) { - Status = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); - if (Status != STATUS_SUCCESS) { + if (bytes < 0) { + Status = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM to GPIO_PIN_STATE_REGISTER Failed."); return Status; + } else { + Status = STATUS_SUCCESS; } pgpio_multi_info[WIMAX_IDX].uiGPIOValue = (*(UINT *)ucResetValue & @@ -605,7 +629,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Failed while copying Content to IOBufer for user space err:%d", Status); - break; + return -EFAULT; } } break; @@ -629,11 +653,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength)) return -EFAULT; - Status = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); - if (STATUS_SUCCESS != Status) { + if (bytes < 0) { + Status = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read of GPIO_MODE_REGISTER failed"); return Status; + } else { + Status = STATUS_SUCCESS; } /* Validating the request */ @@ -678,7 +705,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Failed while copying Content to IOBufer for user space err:%d", Status); - break; + return -EFAULT; } } break; @@ -706,9 +733,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) return -ENOMEM; if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) { - Status = -EFAULT; kfree(pvBuffer); - break; + return -EFAULT; } down(&Adapter->LowPowerModeSync); @@ -733,8 +759,7 @@ cntrlEnd: } case IOCTL_BCM_BUFFER_DOWNLOAD_START: { - INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock); - if (NVMAccess) { + if (down_trylock(&Adapter->NVMRdmWrmLock)) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n"); return -EACCES; @@ -743,157 +768,162 @@ cntrlEnd: BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid); - if (!down_trylock(&Adapter->fw_download_sema)) { - Adapter->bBinDownloaded = FALSE; - Adapter->fw_download_process_pid = current->pid; - Adapter->bCfgDownloaded = FALSE; - Adapter->fw_download_done = FALSE; - netif_carrier_off(Adapter->dev); - netif_stop_queue(Adapter->dev); - Status = reset_card_proc(Adapter); - if (Status) { - pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name); - up(&Adapter->fw_download_sema); - up(&Adapter->NVMRdmWrmLock); - break; - } - mdelay(10); - } else { - Status = -EBUSY; + if (down_trylock(&Adapter->fw_download_sema)) + return -EBUSY; + + Adapter->bBinDownloaded = FALSE; + Adapter->fw_download_process_pid = current->pid; + Adapter->bCfgDownloaded = FALSE; + Adapter->fw_download_done = FALSE; + netif_carrier_off(Adapter->dev); + netif_stop_queue(Adapter->dev); + Status = reset_card_proc(Adapter); + if (Status) { + pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name); + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; } + mdelay(10); up(&Adapter->NVMRdmWrmLock); - break; + return Status; } case IOCTL_BCM_BUFFER_DOWNLOAD: { FIRMWARE_INFO *psFwInfo = NULL; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid); - do { - if (!down_trylock(&Adapter->fw_download_sema)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Invalid way to download buffer. Use Start and then call this!!!\n"); - Status = -EINVAL; - break; - } - - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - return -EFAULT; + if (!down_trylock(&Adapter->fw_download_sema)) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Length for FW DLD is : %lx\n", IoBuffer.InputLength); + "Invalid way to download buffer. Use Start and then call this!!!\n"); + up(&Adapter->fw_download_sema); + Status = -EINVAL; + return Status; + } - if (IoBuffer.InputLength > sizeof(FIRMWARE_INFO)) - return -EINVAL; + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) { + up(&Adapter->fw_download_sema); + return -EFAULT; + } - psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL); - if (!psFwInfo) - return -ENOMEM; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Length for FW DLD is : %lx\n", IoBuffer.InputLength); - if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; + if (IoBuffer.InputLength > sizeof(FIRMWARE_INFO)) { + up(&Adapter->fw_download_sema); + return -EINVAL; + } - if (!psFwInfo->pvMappedFirmwareAddress || - (psFwInfo->u32FirmwareLength == 0)) { + psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL); + if (!psFwInfo) { + up(&Adapter->fw_download_sema); + return -ENOMEM; + } - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Something else is wrong %lu\n", - psFwInfo->u32FirmwareLength); - Status = -EINVAL; - break; - } + if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) { + up(&Adapter->fw_download_sema); + return -EFAULT; + } - Status = bcm_ioctl_fw_download(Adapter, psFwInfo); + if (!psFwInfo->pvMappedFirmwareAddress || + (psFwInfo->u32FirmwareLength == 0)) { - if (Status != STATUS_SUCCESS) { - if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR) - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Configuration File Upload Failed\n"); - else - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Firmware File Upload Failed\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Something else is wrong %lu\n", + psFwInfo->u32FirmwareLength); + up(&Adapter->fw_download_sema); + Status = -EINVAL; + return Status; + } - /* up(&Adapter->fw_download_sema); */ + Status = bcm_ioctl_fw_download(Adapter, psFwInfo); - if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { - Adapter->DriverState = DRIVER_INIT; - Adapter->LEDInfo.bLedInitDone = FALSE; - wake_up(&Adapter->LEDInfo.notify_led_event); - } - } - break; + if (Status != STATUS_SUCCESS) { + if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Configuration File Upload Failed\n"); + else + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Firmware File Upload Failed\n"); + + /* up(&Adapter->fw_download_sema); */ - } while (0); + if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = DRIVER_INIT; + Adapter->LEDInfo.bLedInitDone = FALSE; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + } if (Status != STATUS_SUCCESS) up(&Adapter->fw_download_sema); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "IOCTL: Firmware File Uploaded\n"); kfree(psFwInfo); - break; + return Status; } case IOCTL_BCM_BUFFER_DOWNLOAD_STOP: { - INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock); + if (!down_trylock(&Adapter->fw_download_sema)) { + up(&Adapter->fw_download_sema); + return -EINVAL; + } - if (NVMAccess) { + if (down_trylock(&Adapter->NVMRdmWrmLock)) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "FW download blocked as EEPROM Read/Write is in progress\n"); up(&Adapter->fw_download_sema); return -EACCES; } - if (down_trylock(&Adapter->fw_download_sema)) { - Adapter->bBinDownloaded = TRUE; - Adapter->bCfgDownloaded = TRUE; - atomic_set(&Adapter->CurrNumFreeTxDesc, 0); - Adapter->CurrNumRecvDescs = 0; - Adapter->downloadDDR = 0; - - /* setting the Mips to Run */ - Status = run_card_proc(Adapter); + Adapter->bBinDownloaded = TRUE; + Adapter->bCfgDownloaded = TRUE; + atomic_set(&Adapter->CurrNumFreeTxDesc, 0); + Adapter->CurrNumRecvDescs = 0; + Adapter->downloadDDR = 0; - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Firm Download Failed\n"); - up(&Adapter->fw_download_sema); - up(&Adapter->NVMRdmWrmLock); - break; - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, "Firm Download Over...\n"); - } - - mdelay(10); - - /* Wait for MailBox Interrupt */ - if (StartInterruptUrb((PS_INTERFACE_ADAPTER)Adapter->pvInterfaceAdapter)) - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Unable to send interrupt...\n"); - - timeout = 5*HZ; - Adapter->waiting_to_fw_download_done = FALSE; - wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue, - Adapter->waiting_to_fw_download_done, timeout); - Adapter->fw_download_process_pid = INVALID_PID; - Adapter->fw_download_done = TRUE; - atomic_set(&Adapter->CurrNumFreeTxDesc, 0); - Adapter->CurrNumRecvDescs = 0; - Adapter->PrevNumRecvDescs = 0; - atomic_set(&Adapter->cntrlpktCnt, 0); - Adapter->LinkUpStatus = 0; - Adapter->LinkStatus = 0; + /* setting the Mips to Run */ + Status = run_card_proc(Adapter); - if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { - Adapter->DriverState = FW_DOWNLOAD_DONE; - wake_up(&Adapter->LEDInfo.notify_led_event); - } - - if (!timeout) - Status = -ENODEV; + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Firm Download Failed\n"); + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; } else { - Status = -EINVAL; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "Firm Download Over...\n"); + } + + mdelay(10); + + /* Wait for MailBox Interrupt */ + if (StartInterruptUrb((PS_INTERFACE_ADAPTER)Adapter->pvInterfaceAdapter)) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Unable to send interrupt...\n"); + + timeout = 5*HZ; + Adapter->waiting_to_fw_download_done = FALSE; + wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue, + Adapter->waiting_to_fw_download_done, timeout); + Adapter->fw_download_process_pid = INVALID_PID; + Adapter->fw_download_done = TRUE; + atomic_set(&Adapter->CurrNumFreeTxDesc, 0); + Adapter->CurrNumRecvDescs = 0; + Adapter->PrevNumRecvDescs = 0; + atomic_set(&Adapter->cntrlpktCnt, 0); + Adapter->LinkUpStatus = 0; + Adapter->LinkStatus = 0; + + if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = FW_DOWNLOAD_DONE; + wake_up(&Adapter->LEDInfo.notify_led_event); } + if (!timeout) + Status = -ENODEV; + up(&Adapter->fw_download_sema); up(&Adapter->NVMRdmWrmLock); - break; + return Status; } case IOCTL_BE_BUCKET_SIZE: @@ -969,11 +999,15 @@ cntrlEnd: } case IOCTL_BCM_GET_DRIVER_VERSION: { + ulong len; + /* Copy Ioctl Buffer structure */ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) return -EFAULT; - if (copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, IoBuffer.OutputLength)) + len = min_t(ulong, IoBuffer.OutputLength, strlen(VER_FILEVERSION_STR) + 1); + + if (copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, len)) return -EFAULT; Status = STATUS_SUCCESS; break; @@ -985,8 +1019,7 @@ cntrlEnd: /* Copy Ioctl Buffer structure */ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user failed..\n"); - Status = -EFAULT; - break; + return -EFAULT; } if (IoBuffer.OutputLength != sizeof(link_state)) { @@ -1001,8 +1034,7 @@ cntrlEnd: if (copy_to_user(IoBuffer.OutputBuffer, &link_state, min_t(size_t, sizeof(link_state), IoBuffer.OutputLength))) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n"); - Status = -EFAULT; - break; + return -EFAULT; } Status = STATUS_SUCCESS; break; @@ -1068,8 +1100,10 @@ cntrlEnd: GetDroppedAppCntrlPktMibs(temp_buff, pTarang); if (Status != STATUS_FAILURE) - if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(S_MIBS_HOST_STATS_MIBS))) - Status = -EFAULT; + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(S_MIBS_HOST_STATS_MIBS))) { + kfree(temp_buff); + return -EFAULT; + } kfree(temp_buff); break; @@ -1103,7 +1137,9 @@ cntrlEnd: if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) return -EFAULT; - /* FIXME: restrict length */ + if (IoBuffer.InputLength < sizeof(ULONG) * 2) + return -EINVAL; + pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL); if (!pvBuffer) return -ENOMEM; @@ -1111,8 +1147,7 @@ cntrlEnd: /* Get WrmBuffer structure */ if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) { kfree(pvBuffer); - Status = -EFAULT; - break; + return -EFAULT; } pBulkBuffer = (PBULKWRM_BUFFER)pvBuffer; @@ -1242,8 +1277,7 @@ cntrlEnd: memset(&tv1, 0, sizeof(struct timeval)); if ((Adapter->eNVMType == NVM_FLASH) && (Adapter->uiFlashLayoutMajorVersion == 0)) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "The Flash Control Section is Corrupted. Hence Rejection on NVM Read/Write\n"); - Status = -EFAULT; - break; + return -EFAULT; } if (IsFlash2x(Adapter)) { @@ -1252,7 +1286,7 @@ cntrlEnd: (Adapter->eActiveDSD != DSD2)) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No DSD is active..hence NVM Command is blocked"); - return STATUS_FAILURE ; + return STATUS_FAILURE; } } @@ -1271,8 +1305,7 @@ cntrlEnd: if ((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) > Adapter->uiNVMDSDSize) { /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Can't allow access beyond NVM Size: 0x%x 0x%x\n", stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); */ - Status = STATUS_FAILURE; - break; + return STATUS_FAILURE; } pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL); @@ -1280,9 +1313,8 @@ cntrlEnd: return -ENOMEM; if (copy_from_user(pReadData, stNVMReadWrite.pBuffer, stNVMReadWrite.uiNumBytes)) { - Status = -EFAULT; kfree(pReadData); - break; + return -EFAULT; } do_gettimeofday(&tv0); @@ -1309,7 +1341,7 @@ cntrlEnd: if (copy_to_user(stNVMReadWrite.pBuffer, pReadData, stNVMReadWrite.uiNumBytes)) { kfree(pReadData); - Status = -EFAULT; + return -EFAULT; } } else { down(&Adapter->NVMRdmWrmLock); @@ -1377,9 +1409,8 @@ cntrlEnd: BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " timetaken by Write/read :%ld msec\n", (tv1.tv_sec - tv0.tv_sec)*1000 + (tv1.tv_usec - tv0.tv_usec)/1000); kfree(pReadData); - Status = STATUS_SUCCESS; + return STATUS_SUCCESS; } - break; case IOCTL_BCM_FLASH2X_SECTION_READ: { FLASH2X_READWRITE sFlash2xRead = {0}; @@ -1456,7 +1487,9 @@ cntrlEnd: Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy to use failed with status :%d", Status); - break; + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EFAULT; } NOB = NOB - ReadBytes; if (NOB) { @@ -1548,7 +1581,9 @@ cntrlEnd: Status = copy_from_user(pWriteBuff, InputAddr, WriteBytes); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to user failed with status :%d", Status); - break; + up(&Adapter->NVMRdmWrmLock); + kfree(pWriteBuff); + return -EFAULT; } BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pWriteBuff, WriteBytes); @@ -1608,8 +1643,10 @@ cntrlEnd: BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap); up(&Adapter->NVMRdmWrmLock); - if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP))) - Status = -EFAULT; + if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP))) { + kfree(psFlash2xBitMap); + return -EFAULT; + } kfree(psFlash2xBitMap); } @@ -1627,13 +1664,13 @@ cntrlEnd: Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - return Status; + return -EFAULT; } Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed"); - return Status; + return -EFAULT; } down(&Adapter->NVMRdmWrmLock); @@ -1677,13 +1714,13 @@ cntrlEnd: Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed Status :%d", Status); - return Status; + return -EFAULT; } Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of Copy_Section_Struct failed with Status :%d", Status); - return Status; + return -EFAULT; } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source SEction :%x", sCopySectStrut.SrcSection); @@ -1744,7 +1781,7 @@ cntrlEnd: Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - break; + return -EFAULT; } if (Adapter->eNVMType != NVM_FLASH) { @@ -1783,12 +1820,12 @@ cntrlEnd: Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - return Status; + return -EFAULT; } Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed"); - return Status; + return -EFAULT; } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read Section :%d", eFlash2xSectionVal); @@ -1830,8 +1867,7 @@ cntrlEnd: /* Copy Ioctl Buffer structure */ if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user 1 failed\n"); - Status = -EFAULT; - break; + return -EFAULT; } if (copy_from_user(&stNVMRead, IoBuffer.OutputBuffer, sizeof(NVM_READWRITE))) @@ -1886,7 +1922,9 @@ cntrlEnd: Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to use failed with status :%d", Status); - break; + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EFAULT; } NOB = NOB - ReadBytes; if (NOB) { @@ -1907,8 +1945,7 @@ cntrlEnd: Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of Ioctl buffer is failed from user space"); - Status = -EFAULT; - break; + return -EFAULT; } if (IoBuffer.InputLength != sizeof(unsigned long)) { @@ -1919,8 +1956,7 @@ cntrlEnd: Status = copy_from_user(&RxCntrlMsgBitMask, IoBuffer.InputBuffer, IoBuffer.InputLength); if (Status) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of control bit mask failed from user space"); - Status = -EFAULT; - break; + return -EFAULT; } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\n Got user defined cntrl msg bit mask :%lx", RxCntrlMsgBitMask); pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask; diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c index 2b1e9e17e11..b058e30b2ca 100644 --- a/drivers/staging/bcm/HandleControlPacket.c +++ b/drivers/staging/bcm/HandleControlPacket.c @@ -1,195 +1,208 @@ /** -@file HandleControlPacket.c -This file contains the routines to deal with -sending and receiving of control packets. -*/ + * @file HandleControlPacket.c + * This file contains the routines to deal with + * sending and receiving of control packets. + */ #include "headers.h" /** -When a control packet is received, analyze the -"status" and call appropriate response function. -Enqueue the control packet for Application. -@return None -*/ + * When a control packet is received, analyze the + * "status" and call appropriate response function. + * Enqueue the control packet for Application. + * @return None + */ static VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, struct sk_buff *skb) { - PPER_TARANG_DATA pTarang = NULL; + PPER_TARANG_DATA pTarang = NULL; BOOLEAN HighPriorityMessage = FALSE; - struct sk_buff * newPacket = NULL; + struct sk_buff *newPacket = NULL; CHAR cntrl_msg_mask_bit = 0; - BOOLEAN drop_pkt_flag = TRUE ; + BOOLEAN drop_pkt_flag = TRUE; USHORT usStatus = *(PUSHORT)(skb->data); if (netif_msg_pktdata(Adapter)) print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE, - 16, 1, skb->data, skb->len, 0); - - switch(usStatus) - { - case CM_RESPONSES: // 0xA0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "MAC Version Seems to be Non Multi-Classifier, rejected by Driver"); - HighPriorityMessage = TRUE ; - break; - case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: - HighPriorityMessage = TRUE ; - if(Adapter->LinkStatus==LINKUP_DONE) - { - CmControlResponseMessage(Adapter,(skb->data +sizeof(USHORT))); - } - break; - case LINK_CONTROL_RESP: //0xA2 - case STATUS_RSP: //0xA1 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL,"LINK_CONTROL_RESP"); - HighPriorityMessage = TRUE ; - LinkControlResponseMessage(Adapter,(skb->data + sizeof(USHORT))); - break; - case STATS_POINTER_RESP: //0xA6 - HighPriorityMessage = TRUE ; - StatisticsResponse(Adapter, (skb->data + sizeof(USHORT))); - break; - case IDLE_MODE_STATUS: //0xA3 - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL,"IDLE_MODE_STATUS Type Message Got from F/W"); - InterfaceIdleModeRespond(Adapter, (PUINT)(skb->data + - sizeof(USHORT))); - HighPriorityMessage = TRUE ; - break; - - case AUTH_SS_HOST_MSG: - HighPriorityMessage = TRUE ; - break; - - default: - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL,"Got Default Response"); - /* Let the Application Deal with This Packet */ - break; + 16, 1, skb->data, skb->len, 0); + + switch (usStatus) { + case CM_RESPONSES: /* 0xA0 */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, + "MAC Version Seems to be Non Multi-Classifier, rejected by Driver"); + HighPriorityMessage = TRUE; + break; + case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: + HighPriorityMessage = TRUE; + if (Adapter->LinkStatus == LINKUP_DONE) + CmControlResponseMessage(Adapter, + (skb->data + sizeof(USHORT))); + break; + case LINK_CONTROL_RESP: /* 0xA2 */ + case STATUS_RSP: /* 0xA1 */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, "LINK_CONTROL_RESP"); + HighPriorityMessage = TRUE; + LinkControlResponseMessage(Adapter, + (skb->data + sizeof(USHORT))); + break; + case STATS_POINTER_RESP: /* 0xA6 */ + HighPriorityMessage = TRUE; + StatisticsResponse(Adapter, (skb->data + sizeof(USHORT))); + break; + case IDLE_MODE_STATUS: /* 0xA3 */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, + "IDLE_MODE_STATUS Type Message Got from F/W"); + InterfaceIdleModeRespond(Adapter, (PUINT)(skb->data + + sizeof(USHORT))); + HighPriorityMessage = TRUE; + break; + + case AUTH_SS_HOST_MSG: + HighPriorityMessage = TRUE; + break; + + default: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, "Got Default Response"); + /* Let the Application Deal with This Packet */ + break; } - //Queue The Control Packet to The Application Queues + /* Queue The Control Packet to The Application Queues */ down(&Adapter->RxAppControlQueuelock); - for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) - { - if(Adapter->device_removed) - { + for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) { + if (Adapter->device_removed) break; - } - drop_pkt_flag = TRUE ; + drop_pkt_flag = TRUE; /* - There are cntrl msg from A0 to AC. It has been mapped to 0 to C bit in the cntrl mask. - Also, by default AD to BF has been masked to the rest of the bits... which wil be ON by default. - if mask bit is enable to particular pkt status, send it out to app else stop it. - */ + * There are cntrl msg from A0 to AC. It has been mapped to 0 to + * C bit in the cntrl mask. + * Also, by default AD to BF has been masked to the rest of the + * bits... which wil be ON by default. + * if mask bit is enable to particular pkt status, send it out + * to app else stop it. + */ cntrl_msg_mask_bit = (usStatus & 0x1F); - //printk("\ninew msg mask bit which is disable in mask:%X", cntrl_msg_mask_bit); - if(pTarang->RxCntrlMsgBitMask & (1<<cntrl_msg_mask_bit)) - drop_pkt_flag = FALSE; - - if ((drop_pkt_flag == TRUE) || (pTarang->AppCtrlQueueLen > MAX_APP_QUEUE_LEN) || - ((pTarang->AppCtrlQueueLen > MAX_APP_QUEUE_LEN/2) && (HighPriorityMessage == FALSE))) - { + /* + * printk("\ninew msg mask bit which is disable in mask:%X", + * cntrl_msg_mask_bit); + */ + if (pTarang->RxCntrlMsgBitMask & (1 << cntrl_msg_mask_bit)) + drop_pkt_flag = FALSE; + + if ((drop_pkt_flag == TRUE) || + (pTarang->AppCtrlQueueLen > MAX_APP_QUEUE_LEN) + || ((pTarang->AppCtrlQueueLen > + MAX_APP_QUEUE_LEN / 2) && + (HighPriorityMessage == FALSE))) { /* - Assumption:- - 1. every tarang manages it own dropped pkt statitistics - 2. Total packet dropped per tarang will be equal to the sum of all types of dropped - pkt by that tarang only. - - */ - switch(*(PUSHORT)skb->data) - { - case CM_RESPONSES: - pTarang->stDroppedAppCntrlMsgs.cm_responses++; - break; - case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: - pTarang->stDroppedAppCntrlMsgs.cm_control_newdsx_multiclassifier_resp++; - break; - case LINK_CONTROL_RESP: - pTarang->stDroppedAppCntrlMsgs.link_control_resp++; - break; - case STATUS_RSP: - pTarang->stDroppedAppCntrlMsgs.status_rsp++; - break; - case STATS_POINTER_RESP: - pTarang->stDroppedAppCntrlMsgs.stats_pointer_resp++; - break; - case IDLE_MODE_STATUS: - pTarang->stDroppedAppCntrlMsgs.idle_mode_status++ ; - break; - case AUTH_SS_HOST_MSG: - pTarang->stDroppedAppCntrlMsgs.auth_ss_host_msg++ ; - break; + * Assumption:- + * 1. every tarang manages it own dropped pkt + * statitistics + * 2. Total packet dropped per tarang will be equal to + * the sum of all types of dropped pkt by that + * tarang only. + */ + switch (*(PUSHORT)skb->data) { + case CM_RESPONSES: + pTarang->stDroppedAppCntrlMsgs.cm_responses++; + break; + case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: + pTarang->stDroppedAppCntrlMsgs.cm_control_newdsx_multiclassifier_resp++; + break; + case LINK_CONTROL_RESP: + pTarang->stDroppedAppCntrlMsgs.link_control_resp++; + break; + case STATUS_RSP: + pTarang->stDroppedAppCntrlMsgs.status_rsp++; + break; + case STATS_POINTER_RESP: + pTarang->stDroppedAppCntrlMsgs.stats_pointer_resp++; + break; + case IDLE_MODE_STATUS: + pTarang->stDroppedAppCntrlMsgs.idle_mode_status++; + break; + case AUTH_SS_HOST_MSG: + pTarang->stDroppedAppCntrlMsgs.auth_ss_host_msg++; + break; default: - pTarang->stDroppedAppCntrlMsgs.low_priority_message++ ; - break; + pTarang->stDroppedAppCntrlMsgs.low_priority_message++; + break; } continue; } - newPacket = skb_clone(skb, GFP_KERNEL); - if (!newPacket) - break; - ENQUEUEPACKET(pTarang->RxAppControlHead,pTarang->RxAppControlTail, - newPacket); - pTarang->AppCtrlQueueLen++; - } + newPacket = skb_clone(skb, GFP_KERNEL); + if (!newPacket) + break; + ENQUEUEPACKET(pTarang->RxAppControlHead, + pTarang->RxAppControlTail, newPacket); + pTarang->AppCtrlQueueLen++; + } up(&Adapter->RxAppControlQueuelock); - wake_up(&Adapter->process_read_wait_queue); - dev_kfree_skb(skb); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "After wake_up_interruptible"); + wake_up(&Adapter->process_read_wait_queue); + dev_kfree_skb(skb); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, + "After wake_up_interruptible"); } /** -@ingroup ctrl_pkt_functions -Thread to handle control pkt reception -*/ -int control_packet_handler (PMINI_ADAPTER Adapter /**< pointer to adapter object*/ - ) + * @ingroup ctrl_pkt_functions + * Thread to handle control pkt reception + */ +int control_packet_handler(PMINI_ADAPTER Adapter /* pointer to adapter object*/) { - struct sk_buff *ctrl_packet= NULL; + struct sk_buff *ctrl_packet = NULL; unsigned long flags = 0; - //struct timeval tv ; - //int *puiBuffer = NULL ; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "Entering to make thread wait on control packet event!"); - while(1) - { + /* struct timeval tv; */ + /* int *puiBuffer = NULL; */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, + "Entering to make thread wait on control packet event!"); + while (1) { wait_event_interruptible(Adapter->process_rx_cntrlpkt, - atomic_read(&Adapter->cntrlpktCnt) || - Adapter->bWakeUpDevice || - kthread_should_stop() - ); + atomic_read(&Adapter->cntrlpktCnt) || + Adapter->bWakeUpDevice || + kthread_should_stop()); - if(kthread_should_stop()) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "Exiting \n"); + if (kthread_should_stop()) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, "Exiting\n"); return 0; } - if(TRUE == Adapter->bWakeUpDevice) - { + if (TRUE == Adapter->bWakeUpDevice) { Adapter->bWakeUpDevice = FALSE; - if((FALSE == Adapter->bTriedToWakeUpFromlowPowerMode) && - ((TRUE == Adapter->IdleMode)|| (TRUE == Adapter->bShutStatus))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "Calling InterfaceAbortIdlemode\n"); - // Adapter->bTriedToWakeUpFromlowPowerMode = TRUE; - InterfaceIdleModeWakeup (Adapter); + if ((FALSE == Adapter->bTriedToWakeUpFromlowPowerMode) + && ((TRUE == Adapter->IdleMode) || + (TRUE == Adapter->bShutStatus))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + CP_CTRL_PKT, DBG_LVL_ALL, + "Calling InterfaceAbortIdlemode\n"); + /* + * Adapter->bTriedToWakeUpFromlowPowerMode + * = TRUE; + */ + InterfaceIdleModeWakeup(Adapter); } continue; } - while(atomic_read(&Adapter->cntrlpktCnt)) - { + while (atomic_read(&Adapter->cntrlpktCnt)) { spin_lock_irqsave(&Adapter->control_queue_lock, flags); ctrl_packet = Adapter->RxControlHead; - if(ctrl_packet) - { - DEQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail); -// Adapter->RxControlHead=ctrl_packet->next; + if (ctrl_packet) { + DEQUEUEPACKET(Adapter->RxControlHead, + Adapter->RxControlTail); + /* Adapter->RxControlHead=ctrl_packet->next; */ } - spin_unlock_irqrestore (&Adapter->control_queue_lock, flags); - handle_rx_control_packet(Adapter, ctrl_packet); + spin_unlock_irqrestore(&Adapter->control_queue_lock, + flags); + handle_rx_control_packet(Adapter, ctrl_packet); atomic_dec(&Adapter->cntrlpktCnt); } @@ -201,22 +214,22 @@ int control_packet_handler (PMINI_ADAPTER Adapter /**< pointer to adapter obje INT flushAllAppQ(void) { PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); - PPER_TARANG_DATA pTarang = NULL; + PPER_TARANG_DATA pTarang = NULL; struct sk_buff *PacketToDrop = NULL; - for(pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) - { - while(pTarang->RxAppControlHead != NULL) - { - PacketToDrop=pTarang->RxAppControlHead; - DEQUEUEPACKET(pTarang->RxAppControlHead,pTarang->RxAppControlTail); + for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) { + while (pTarang->RxAppControlHead != NULL) { + PacketToDrop = pTarang->RxAppControlHead; + DEQUEUEPACKET(pTarang->RxAppControlHead, + pTarang->RxAppControlTail); dev_kfree_skb(PacketToDrop); } pTarang->AppCtrlQueueLen = 0; - //dropped contrl packet statistics also should be reset. - memset((PVOID)&pTarang->stDroppedAppCntrlMsgs, 0, sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES)); + /* dropped contrl packet statistics also should be reset. */ + memset((PVOID)&pTarang->stDroppedAppCntrlMsgs, 0, + sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES)); } - return STATUS_SUCCESS ; + return STATUS_SUCCESS; } diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c index bcd86bbef2f..65c352f3568 100644 --- a/drivers/staging/bcm/InterfaceDld.c +++ b/drivers/staging/bcm/InterfaceDld.c @@ -62,6 +62,7 @@ int InterfaceFileReadbackFromChip(PVOID arg, struct file *flp, unsigned int on_c static int fw_down; INT Status = STATUS_SUCCESS; PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)arg; + int bytes; buff = kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA); buff_readback = kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA); @@ -94,8 +95,9 @@ int InterfaceFileReadbackFromChip(PVOID arg, struct file *flp, unsigned int on_c break; } - Status = InterfaceRDM(psIntfAdapter, on_chip_loc, buff_readback, len); - if (Status) { + bytes = InterfaceRDM(psIntfAdapter, on_chip_loc, buff_readback, len); + if (bytes < 0) { + Status = bytes; BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "RDM of len %d Failed! %d", len, reg); goto exit; } @@ -302,6 +304,7 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter, PUCHAR mappedbuffer, UINT u32Fi UINT len = u32FirmwareLength; INT retval = STATUS_SUCCESS; PUCHAR readbackbuff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL); + int bytes; if (NULL == readbackbuff) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "MEMORY ALLOCATION FAILED"); @@ -310,9 +313,10 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter, PUCHAR mappedbuffer, UINT u32Fi while (u32FirmwareLength && !retval) { len = MIN_VAL(u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB); - retval = rdm(Adapter, u32StartingAddress, readbackbuff, len); + bytes = rdm(Adapter, u32StartingAddress, readbackbuff, len); - if (retval) { + if (bytes < 0) { + retval = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "rdm failed with status %d", retval); break; } diff --git a/drivers/staging/bcm/InterfaceIdleMode.c b/drivers/staging/bcm/InterfaceIdleMode.c index 96fa4ead793..faeb03e62c0 100644 --- a/drivers/staging/bcm/InterfaceIdleMode.c +++ b/drivers/staging/bcm/InterfaceIdleMode.c @@ -46,6 +46,7 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer) { int status = STATUS_SUCCESS; unsigned int uiRegRead = 0; + int bytes; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"SubType of Message :0x%X", ntohl(*puiBuffer)); @@ -77,16 +78,16 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer) else if(Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) { //clear on read Register - status = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, &uiRegRead, sizeof(uiRegRead)); - if(status) - { + bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, &uiRegRead, sizeof(uiRegRead)); + if (bytes < 0) { + status = bytes; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort Reg0"); return status; } //clear on read Register - status = rdmalt (Adapter, DEVICE_INT_OUT_EP_REG1, &uiRegRead, sizeof(uiRegRead)); - if(status) - { + bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1, &uiRegRead, sizeof(uiRegRead)); + if (bytes < 0) { + status = bytes; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort Reg1"); return status; } @@ -117,9 +118,9 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer) Adapter->chip_id== BCS220_3) { - status = rdmalt(Adapter, HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead)); - if(status) - { + bytes = rdmalt(Adapter, HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead)); + if (bytes < 0) { + status = bytes; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "rdm failed while Reading HPM_CONFIG_LDO145 Reg 0\n"); return status; } @@ -266,6 +267,8 @@ void InterfaceHandleShutdownModeWakeup(PMINI_ADAPTER Adapter) { unsigned int uiRegVal = 0; INT Status = 0; + int bytes; + if(Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) { // clear idlemode interrupt. @@ -282,16 +285,16 @@ void InterfaceHandleShutdownModeWakeup(PMINI_ADAPTER Adapter) { //clear Interrupt EP registers. - Status = rdmalt(Adapter,DEVICE_INT_OUT_EP_REG0, &uiRegVal, sizeof(uiRegVal)); - if(Status) - { + bytes = rdmalt(Adapter,DEVICE_INT_OUT_EP_REG0, &uiRegVal, sizeof(uiRegVal)); + if (bytes < 0) { + Status = bytes; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"RDM of DEVICE_INT_OUT_EP_REG0 failed with Err :%d", Status); return; } - Status = rdmalt(Adapter,DEVICE_INT_OUT_EP_REG1, &uiRegVal, sizeof(uiRegVal)); - if(Status) - { + bytes = rdmalt(Adapter,DEVICE_INT_OUT_EP_REG1, &uiRegVal, sizeof(uiRegVal)); + if (bytes < 0) { + Status = bytes; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"RDM of DEVICE_INT_OUT_EP_REG1 failed with Err :%d", Status); return; } diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index a09d35108f0..8e3c586a699 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -68,7 +68,7 @@ static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) { unsigned long ulReg = 0; - int ret; + int bytes; /* Program EP2 MAX_PKT_SIZE */ ulReg = ntohl(EP2_MPS_REG); @@ -94,8 +94,8 @@ static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE); /* Program TX EP as interrupt(Alternate Setting) */ - ret = rdmalt(Adapter, 0x0F0110F8, (u32 *)&ulReg, sizeof(u32)); - if (ret) { + bytes = rdmalt(Adapter, 0x0F0110F8, (u32 *)&ulReg, sizeof(u32)); + if (bytes < 0) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reading of Tx EP failed\n"); return; @@ -430,6 +430,7 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) int usedIntOutForBulkTransfer = 0 ; BOOLEAN bBcm16 = FALSE; UINT uiData = 0; + int bytes; /* Store the usb dev into interface adapter */ psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface)); @@ -438,9 +439,10 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) psIntfAdapter->psAdapter->interface_rdm = BcmRDM; psIntfAdapter->psAdapter->interface_wrm = BcmWRM; - retval = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, + bytes = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, (u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32)); - if (retval) { + if (bytes < 0) { + retval = bytes; BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n"); return retval; } diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c index 61f878b4f56..2218faeaf8a 100644 --- a/drivers/staging/bcm/InterfaceMisc.c +++ b/drivers/staging/bcm/InterfaceMisc.c @@ -5,7 +5,7 @@ INT InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter, PVOID buff, INT len) { - int retval = 0; + int bytes; USHORT usRetries = 0; if (psIntfAdapter == NULL) { @@ -30,7 +30,7 @@ INT InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter, psIntfAdapter->psAdapter->DeviceAccess = TRUE; do { - retval = usb_control_msg(psIntfAdapter->udev, + bytes = usb_control_msg(psIntfAdapter->udev, usb_rcvctrlpipe(psIntfAdapter->udev, 0), 0x02, 0xC2, @@ -41,22 +41,20 @@ INT InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter, 5000); usRetries++; - if (-ENODEV == retval) { + if (-ENODEV == bytes) { psIntfAdapter->psAdapter->device_removed = TRUE; break; } - } while ((retval < 0) && (usRetries < MAX_RDM_WRM_RETIRES)); + } while ((bytes < 0) && (usRetries < MAX_RDM_WRM_RETIRES)); - if (retval < 0) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM failed status :%d, retires :%d", retval, usRetries); - psIntfAdapter->psAdapter->DeviceAccess = FALSE; - return retval; - } else { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM sent %d", retval); - psIntfAdapter->psAdapter->DeviceAccess = FALSE; - return STATUS_SUCCESS; - } + if (bytes < 0) + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM failed status :%d, retires :%d", bytes, usRetries); + else + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM sent %d", bytes); + + psIntfAdapter->psAdapter->DeviceAccess = FALSE; + return bytes; } INT InterfaceWRM(PS_INTERFACE_ADAPTER psIntfAdapter, diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index e9f29d59751..c7725e141fd 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -814,6 +814,7 @@ int reset_card_proc(PMINI_ADAPTER ps_adapter) PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); PS_INTERFACE_ADAPTER psIntfAdapter = NULL; unsigned int value = 0, uiResetValue = 0; + int bytes; psIntfAdapter = ((PS_INTERFACE_ADAPTER)(ps_adapter->pvInterfaceAdapter)); ps_adapter->bDDRInitDone = FALSE; @@ -848,8 +849,9 @@ int reset_card_proc(PMINI_ADAPTER ps_adapter) ps_adapter->chip_id == BCS250_BC || ps_adapter->chip_id == BCS220_3) { - retval = rdmalt(ps_adapter, HPM_CONFIG_LDO145, &value, sizeof(value)); - if (retval < 0) { + bytes = rdmalt(ps_adapter, HPM_CONFIG_LDO145, &value, sizeof(value)); + if (bytes < 0) { + retval = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "read failed with status :%d", retval); goto err_exit; } @@ -862,8 +864,9 @@ int reset_card_proc(PMINI_ADAPTER ps_adapter) } } } else { - retval = rdmalt(ps_adapter, 0x0f007018, &value, sizeof(value)); - if (retval < 0) { + bytes = rdmalt(ps_adapter, 0x0f007018, &value, sizeof(value)); + if (bytes < 0) { + retval = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "read failed with status :%d", retval); goto err_exit; } @@ -925,11 +928,16 @@ err_exit: int run_card_proc(PMINI_ADAPTER ps_adapter) { + int status = STATUS_SUCCESS; + int bytes; + unsigned int value = 0; { - if (rdmalt(ps_adapter, CLOCK_RESET_CNTRL_REG_1, &value, sizeof(value)) < 0) { + bytes = rdmalt(ps_adapter, CLOCK_RESET_CNTRL_REG_1, &value, sizeof(value)); + if (bytes < 0) { + status = bytes; BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "%s:%d\n", __func__, __LINE__); - return STATUS_FAILURE; + return status; } if (ps_adapter->bFlashBoot) @@ -942,7 +950,7 @@ int run_card_proc(PMINI_ADAPTER ps_adapter) return STATUS_FAILURE; } } - return STATUS_SUCCESS; + return status; } int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) @@ -1215,6 +1223,7 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress) int status = 0, i = 0; unsigned int temp = 0; unsigned char *pucmacaddr = kmalloc(MAC_ADDRESS_SIZE, GFP_KERNEL); + int bytes; if (!pucmacaddr) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No Buffers to Read the EEPROM Address\n"); @@ -1231,8 +1240,9 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress) } for (i = 0; i < MAC_ADDRESS_SIZE; i++) { - status = rdmalt(Adapter, EEPROM_READ_DATA_Q_REG, &temp, sizeof(temp)); - if (status != STATUS_SUCCESS) { + bytes = rdmalt(Adapter, EEPROM_READ_DATA_Q_REG, &temp, sizeof(temp)); + if (bytes < 0) { + status = bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "rdm Failed..\n"); kfree(pucmacaddr); pucmacaddr = NULL; @@ -1574,11 +1584,13 @@ void update_per_sf_desc_cnts(PMINI_ADAPTER Adapter) { INT iIndex = 0; u32 uibuff[MAX_TARGET_DSX_BUFFERS]; + int bytes; if (!atomic_read(&Adapter->uiMBupdate)) return; - if (rdmaltWithLock(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS) < 0) { + bytes = rdmaltWithLock(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS); + if (bytes < 0) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "rdm failed\n"); return; } diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c index c13ea5c9a2a..101c4e31249 100644 --- a/drivers/staging/bcm/hostmibs.c +++ b/drivers/staging/bcm/hostmibs.c @@ -1,4 +1,3 @@ - /* * File Name: hostmibs.c * @@ -6,73 +5,72 @@ * * Abstract: This file contains the routines to copy the statistics used by * the driver to the Host MIBS structure and giving the same to Application. - * */ + #include "headers.h" -INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMibs) +INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMibs) { - S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL; - S_PHS_RULE *pstPhsRule = NULL; - S_CLASSIFIER_TABLE *pstClassifierTable = NULL; - S_CLASSIFIER_ENTRY *pstClassifierRule = NULL; - PPHS_DEVICE_EXTENSION pDeviceExtension = (PPHS_DEVICE_EXTENSION)&Adapter->stBCMPhsContext; + S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL; + S_PHS_RULE *pstPhsRule = NULL; + S_CLASSIFIER_TABLE *pstClassifierTable = NULL; + S_CLASSIFIER_ENTRY *pstClassifierRule = NULL; + PPHS_DEVICE_EXTENSION pDeviceExtension = (PPHS_DEVICE_EXTENSION) &Adapter->stBCMPhsContext; - UINT nClassifierIndex = 0, nPhsTableIndex = 0,nSfIndex = 0, uiIndex = 0; + UINT nClassifierIndex = 0, nPhsTableIndex = 0, nSfIndex = 0, uiIndex = 0; - if(pDeviceExtension == NULL) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, HOST_MIBS, DBG_LVL_ALL, "Invalid Device Extension\n"); + if (pDeviceExtension == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, HOST_MIBS, DBG_LVL_ALL, "Invalid Device Extension\n"); return STATUS_FAILURE; } - //Copy the classifier Table - for(nClassifierIndex=0; nClassifierIndex < MAX_CLASSIFIERS; - nClassifierIndex++) - { - if(Adapter->astClassifierTable[nClassifierIndex].bUsed == TRUE) - memcpy((PVOID)&pstHostMibs->astClassifierTable[nClassifierIndex], - (PVOID)&Adapter->astClassifierTable[nClassifierIndex], - sizeof(S_MIBS_CLASSIFIER_RULE)); + /* Copy the classifier Table */ + for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS; nClassifierIndex++) { + if (Adapter->astClassifierTable[nClassifierIndex].bUsed == TRUE) + memcpy((PVOID) & pstHostMibs-> + astClassifierTable[nClassifierIndex], + (PVOID) & Adapter-> + astClassifierTable[nClassifierIndex], + sizeof(S_MIBS_CLASSIFIER_RULE)); } - //Copy the SF Table - for(nSfIndex=0; nSfIndex < NO_OF_QUEUES ; nSfIndex++) - { - if(Adapter->PackInfo[nSfIndex].bValid) - { - memcpy((PVOID)&pstHostMibs->astSFtable[nSfIndex],(PVOID)&Adapter->PackInfo[nSfIndex],sizeof(S_MIBS_SERVICEFLOW_TABLE)); - } - else - { - //if index in not valid, don't process this for the PHS table. Go For the next entry. - continue ; - } + /* Copy the SF Table */ + for (nSfIndex = 0; nSfIndex < NO_OF_QUEUES; nSfIndex++) { + if (Adapter->PackInfo[nSfIndex].bValid) { + memcpy((PVOID) & pstHostMibs->astSFtable[nSfIndex], + (PVOID) & Adapter->PackInfo[nSfIndex], + sizeof(S_MIBS_SERVICEFLOW_TABLE)); + } else { + /* If index in not valid, + * don't process this for the PHS table. + * Go For the next entry. + */ + continue; + } - //Retrieve the SFID Entry Index for requested Service Flow - if(PHS_INVALID_TABLE_INDEX == GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, - Adapter->PackInfo[nSfIndex].usVCID_Value ,&pstServiceFlowEntry)) - { + /* Retrieve the SFID Entry Index for requested Service Flow */ + if (PHS_INVALID_TABLE_INDEX == + GetServiceFlowEntry(pDeviceExtension-> + pstServiceFlowPhsRulesTable, + Adapter->PackInfo[nSfIndex]. + usVCID_Value, &pstServiceFlowEntry)) - continue; - } + continue; pstClassifierTable = pstServiceFlowEntry->pstClassifierTable; - - for(uiIndex = 0; uiIndex < MAX_PHSRULE_PER_SF; uiIndex++) - { + for (uiIndex = 0; uiIndex < MAX_PHSRULE_PER_SF; uiIndex++) { pstClassifierRule = &pstClassifierTable->stActivePhsRulesList[uiIndex]; - if(pstClassifierRule->bUsed) - { - pstPhsRule = pstClassifierRule->pstPhsRule; + if (pstClassifierRule->bUsed) { + pstPhsRule = pstClassifierRule->pstPhsRule; - pstHostMibs->astPhsRulesTable[nPhsTableIndex].ulSFID = Adapter->PackInfo[nSfIndex].ulSFID; + pstHostMibs->astPhsRulesTable[nPhsTableIndex]. + ulSFID = Adapter->PackInfo[nSfIndex].ulSFID; - memcpy(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI, - &pstPhsRule->u8PHSI, - sizeof(S_PHS_RULE)); + memcpy(&pstHostMibs-> + astPhsRulesTable[nPhsTableIndex].u8PHSI, + &pstPhsRule->u8PHSI, sizeof(S_PHS_RULE)); nPhsTableIndex++; } @@ -81,65 +79,63 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMi } - - //copy other Host Statistics parameters + /* Copy other Host Statistics parameters */ pstHostMibs->stHostInfo.GoodTransmits = Adapter->dev->stats.tx_packets; pstHostMibs->stHostInfo.GoodReceives = Adapter->dev->stats.rx_packets; - pstHostMibs->stHostInfo.CurrNumFreeDesc = - atomic_read(&Adapter->CurrNumFreeTxDesc); + pstHostMibs->stHostInfo.CurrNumFreeDesc = atomic_read(&Adapter->CurrNumFreeTxDesc); pstHostMibs->stHostInfo.BEBucketSize = Adapter->BEBucketSize; pstHostMibs->stHostInfo.rtPSBucketSize = Adapter->rtPSBucketSize; pstHostMibs->stHostInfo.TimerActive = Adapter->TimerActive; pstHostMibs->stHostInfo.u32TotalDSD = Adapter->u32TotalDSD; - memcpy(pstHostMibs->stHostInfo.aTxPktSizeHist,Adapter->aTxPktSizeHist,sizeof(UINT32)*MIBS_MAX_HIST_ENTRIES); - memcpy(pstHostMibs->stHostInfo.aRxPktSizeHist,Adapter->aRxPktSizeHist,sizeof(UINT32)*MIBS_MAX_HIST_ENTRIES); + memcpy(pstHostMibs->stHostInfo.aTxPktSizeHist, Adapter->aTxPktSizeHist, sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); + memcpy(pstHostMibs->stHostInfo.aRxPktSizeHist, Adapter->aRxPktSizeHist, sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); return STATUS_SUCCESS; } - VOID GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *pstHostMibs, const PPER_TARANG_DATA pTarang) { memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs), - &(pTarang->stDroppedAppCntrlMsgs),sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES)); + &(pTarang->stDroppedAppCntrlMsgs), + sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES)); } - -VOID CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter, - CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex) +VOID CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter, CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex) { - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfSfid = psfLocalSet->u32SFID; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsMaxSustainedRate = psfLocalSet->u32MaxSustainedTrafficRate; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsMaxTrafficBurst = psfLocalSet->u32MaxTrafficBurst; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsMinReservedRate = psfLocalSet->u32MinReservedTrafficRate; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsToleratedJitter = psfLocalSet->u32ToleratedJitter; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsMaxLatency = psfLocalSet->u32MaximumLatency; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsFixedVsVariableSduInd = psfLocalSet->u8FixedLengthVSVariableLengthSDUIndicator; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsFixedVsVariableSduInd = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsFixedVsVariableSduInd); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsSduSize = psfLocalSet->u8SDUSize; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsSduSize = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsSduSize); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsSfSchedulingType = psfLocalSet->u8ServiceFlowSchedulingType; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsSfSchedulingType = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsSfSchedulingType); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqEnable = psfLocalSet->u8ARQEnable; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqEnable = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqEnable); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqWindowSize = ntohs(psfLocalSet->u16ARQWindowSize); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqWindowSize = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqWindowSize); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqBlockLifetime = ntohs(psfLocalSet->u16ARQBlockLifeTime); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqBlockLifetime = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqBlockLifetime); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqSyncLossTimeout = ntohs(psfLocalSet->u16ARQSyncLossTimeOut); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqSyncLossTimeout = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqSyncLossTimeout); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqDeliverInOrder = psfLocalSet->u8ARQDeliverInOrder; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqDeliverInOrder = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqDeliverInOrder); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqRxPurgeTimeout = ntohs(psfLocalSet->u16ARQRxPurgeTimeOut); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqRxPurgeTimeout = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqRxPurgeTimeout); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqBlockSize = ntohs(psfLocalSet->u16ARQBlockSize); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqBlockSize = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsArqBlockSize); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsReqTxPolicy = psfLocalSet->u8RequesttransmissionPolicy; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsReqTxPolicy = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsReqTxPolicy); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnSfCsSpecification = psfLocalSet->u8CSSpecification; - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnSfCsSpecification = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnSfCsSpecification); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsTargetSaid = ntohs(psfLocalSet->u16TargetSAID); - Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsTargetSaid = ntohl(Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable.wmanIfCmnCpsTargetSaid); + S_MIBS_EXTSERVICEFLOW_PARAMETERS *t = &Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable; + + t->wmanIfSfid = psfLocalSet->u32SFID; + t->wmanIfCmnCpsMaxSustainedRate = psfLocalSet->u32MaxSustainedTrafficRate; + t->wmanIfCmnCpsMaxTrafficBurst = psfLocalSet->u32MaxTrafficBurst; + t->wmanIfCmnCpsMinReservedRate = psfLocalSet->u32MinReservedTrafficRate; + t->wmanIfCmnCpsToleratedJitter = psfLocalSet->u32ToleratedJitter; + t->wmanIfCmnCpsMaxLatency = psfLocalSet->u32MaximumLatency; + t->wmanIfCmnCpsFixedVsVariableSduInd = psfLocalSet->u8FixedLengthVSVariableLengthSDUIndicator; + t->wmanIfCmnCpsFixedVsVariableSduInd = ntohl(t->wmanIfCmnCpsFixedVsVariableSduInd); + t->wmanIfCmnCpsSduSize = psfLocalSet->u8SDUSize; + t->wmanIfCmnCpsSduSize = ntohl(t->wmanIfCmnCpsSduSize); + t->wmanIfCmnCpsSfSchedulingType = psfLocalSet->u8ServiceFlowSchedulingType; + t->wmanIfCmnCpsSfSchedulingType = ntohl(t->wmanIfCmnCpsSfSchedulingType); + t->wmanIfCmnCpsArqEnable = psfLocalSet->u8ARQEnable; + t->wmanIfCmnCpsArqEnable = ntohl(t->wmanIfCmnCpsArqEnable); + t->wmanIfCmnCpsArqWindowSize = ntohs(psfLocalSet->u16ARQWindowSize); + t->wmanIfCmnCpsArqWindowSize = ntohl(t->wmanIfCmnCpsArqWindowSize); + t->wmanIfCmnCpsArqBlockLifetime = ntohs(psfLocalSet->u16ARQBlockLifeTime); + t->wmanIfCmnCpsArqBlockLifetime = ntohl(t->wmanIfCmnCpsArqBlockLifetime); + t->wmanIfCmnCpsArqSyncLossTimeout = ntohs(psfLocalSet->u16ARQSyncLossTimeOut); + t->wmanIfCmnCpsArqSyncLossTimeout = ntohl(t->wmanIfCmnCpsArqSyncLossTimeout); + t->wmanIfCmnCpsArqDeliverInOrder = psfLocalSet->u8ARQDeliverInOrder; + t->wmanIfCmnCpsArqDeliverInOrder = ntohl(t->wmanIfCmnCpsArqDeliverInOrder); + t->wmanIfCmnCpsArqRxPurgeTimeout = ntohs(psfLocalSet->u16ARQRxPurgeTimeOut); + t->wmanIfCmnCpsArqRxPurgeTimeout = ntohl(t->wmanIfCmnCpsArqRxPurgeTimeout); + t->wmanIfCmnCpsArqBlockSize = ntohs(psfLocalSet->u16ARQBlockSize); + t->wmanIfCmnCpsArqBlockSize = ntohl(t->wmanIfCmnCpsArqBlockSize); + t->wmanIfCmnCpsReqTxPolicy = psfLocalSet->u8RequesttransmissionPolicy; + t->wmanIfCmnCpsReqTxPolicy = ntohl(t->wmanIfCmnCpsReqTxPolicy); + t->wmanIfCmnSfCsSpecification = psfLocalSet->u8CSSpecification; + t->wmanIfCmnSfCsSpecification = ntohl(t->wmanIfCmnSfCsSpecification); + t->wmanIfCmnCpsTargetSaid = ntohs(psfLocalSet->u16TargetSAID); + t->wmanIfCmnCpsTargetSaid = ntohl(t->wmanIfCmnCpsTargetSaid); } diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c index 16e939fa15d..c7f48862972 100644 --- a/drivers/staging/bcm/led_control.c +++ b/drivers/staging/bcm/led_control.c @@ -5,65 +5,69 @@ static B_UINT16 CFG_CalculateChecksum(B_UINT8 *pu8Buffer, B_UINT32 u32Size) { - B_UINT16 u16CheckSum=0; - while(u32Size--) { + B_UINT16 u16CheckSum = 0; + while (u32Size--) { u16CheckSum += (B_UINT8)~(*pu8Buffer); - pu8Buffer++; + pu8Buffer++; } return u16CheckSum; } + BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios) { - INT Status ; - Status = (Adapter->gpioBitMap & gpios) ^ gpios ; - if(Status) + INT Status; + Status = (Adapter->gpioBitMap & gpios) ^ gpios; + if (Status) return FALSE; else return TRUE; } -static INT LED_Blink(PMINI_ADAPTER Adapter, UINT GPIO_Num, UCHAR uiLedIndex, ULONG timeout, INT num_of_time, LedEventInfo_t currdriverstate) +static INT LED_Blink(PMINI_ADAPTER Adapter, UINT GPIO_Num, UCHAR uiLedIndex, + ULONG timeout, INT num_of_time, LedEventInfo_t currdriverstate) { int Status = STATUS_SUCCESS; BOOLEAN bInfinite = FALSE; - /*Check if num_of_time is -ve. If yes, blink led in infinite loop*/ - if(num_of_time < 0) - { + /* Check if num_of_time is -ve. If yes, blink led in infinite loop */ + if (num_of_time < 0) { bInfinite = TRUE; num_of_time = 1; } - while(num_of_time) - { - - if(currdriverstate == Adapter->DriverState) + while (num_of_time) { + if (currdriverstate == Adapter->DriverState) TURN_ON_LED(GPIO_Num, uiLedIndex); - /*Wait for timeout after setting on the LED*/ - Status = wait_event_interruptible_timeout(Adapter->LEDInfo.notify_led_event, - currdriverstate != Adapter->DriverState || kthread_should_stop(), - msecs_to_jiffies(timeout)); - - if(kthread_should_stop()) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Led thread got signal to exit..hence exiting"); - Adapter->LEDInfo.led_thread_running= BCM_LED_THREAD_DISABLED; + /* Wait for timeout after setting on the LED */ + Status = wait_event_interruptible_timeout( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState || + kthread_should_stop(), + msecs_to_jiffies(timeout)); + + if (kthread_should_stop()) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "Led thread got signal to exit..hence exiting"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; TURN_OFF_LED(GPIO_Num, uiLedIndex); - Status=EVENT_SIGNALED; + Status = EVENT_SIGNALED; break; } - if(Status) - { + if (Status) { TURN_OFF_LED(GPIO_Num, uiLedIndex); - Status=EVENT_SIGNALED; + Status = EVENT_SIGNALED; break; } TURN_OFF_LED(GPIO_Num, uiLedIndex); - Status = wait_event_interruptible_timeout(Adapter->LEDInfo.notify_led_event, - currdriverstate!= Adapter->DriverState || kthread_should_stop(), - msecs_to_jiffies(timeout)); - if(bInfinite == FALSE) + Status = wait_event_interruptible_timeout( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState || + kthread_should_stop(), + msecs_to_jiffies(timeout)); + if (bInfinite == FALSE) num_of_time--; } return Status; @@ -71,19 +75,19 @@ static INT LED_Blink(PMINI_ADAPTER Adapter, UINT GPIO_Num, UCHAR uiLedIndex, ULO static INT ScaleRateofTransfer(ULONG rate) { - if(rate <= 3) + if (rate <= 3) return rate; - else if((rate > 3) && (rate <= 100)) + else if ((rate > 3) && (rate <= 100)) return 5; - else if((rate > 100) && (rate <= 200)) + else if ((rate > 100) && (rate <= 200)) return 6; - else if((rate > 200) && (rate <= 300)) + else if ((rate > 200) && (rate <= 300)) return 7; - else if((rate > 300) && (rate <= 400)) + else if ((rate > 300) && (rate <= 400)) return 8; - else if((rate > 400) && (rate <= 500)) + else if ((rate > 400) && (rate <= 500)) return 9; - else if((rate > 500) && (rate <= 600)) + else if ((rate > 500) && (rate <= 600)) return 10; else return MAX_NUM_OF_BLINKS; @@ -92,215 +96,232 @@ static INT ScaleRateofTransfer(ULONG rate) static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx, - UCHAR uiTxLedIndex, UCHAR GPIO_Num_rx, UCHAR uiRxLedIndex, LedEventInfo_t currdriverstate) + UCHAR uiTxLedIndex, UCHAR GPIO_Num_rx, UCHAR uiRxLedIndex, + LedEventInfo_t currdriverstate) { - /* Initial values of TX and RX packets*/ + /* Initial values of TX and RX packets */ ULONG64 Initial_num_of_packts_tx = 0, Initial_num_of_packts_rx = 0; - /*values of TX and RX packets after 1 sec*/ + /* values of TX and RX packets after 1 sec */ ULONG64 Final_num_of_packts_tx = 0, Final_num_of_packts_rx = 0; - /*Rate of transfer of Tx and Rx in 1 sec*/ + /* Rate of transfer of Tx and Rx in 1 sec */ ULONG64 rate_of_transfer_tx = 0, rate_of_transfer_rx = 0; int Status = STATUS_SUCCESS; INT num_of_time = 0, num_of_time_tx = 0, num_of_time_rx = 0; UINT remDelay = 0; BOOLEAN bBlinkBothLED = TRUE; - //UINT GPIO_num = DISABLE_GPIO_NUM; + /* UINT GPIO_num = DISABLE_GPIO_NUM; */ ulong timeout = 0; - /*Read initial value of packets sent/received */ + /* Read initial value of packets sent/received */ Initial_num_of_packts_tx = Adapter->dev->stats.tx_packets; Initial_num_of_packts_rx = Adapter->dev->stats.rx_packets; - /*Scale the rate of transfer to no of blinks.*/ - num_of_time_tx= ScaleRateofTransfer((ULONG)rate_of_transfer_tx); - num_of_time_rx= ScaleRateofTransfer((ULONG)rate_of_transfer_rx); + /* Scale the rate of transfer to no of blinks. */ + num_of_time_tx = ScaleRateofTransfer((ULONG)rate_of_transfer_tx); + num_of_time_rx = ScaleRateofTransfer((ULONG)rate_of_transfer_rx); - while((Adapter->device_removed == FALSE)) - { + while ((Adapter->device_removed == FALSE)) { timeout = 50; - /*Blink Tx and Rx LED when both Tx and Rx is in normal bandwidth*/ - if(bBlinkBothLED) - { - /*Assign minimum number of blinks of either Tx or Rx.*/ - if(num_of_time_tx > num_of_time_rx) + /* + * Blink Tx and Rx LED when both Tx and Rx is + * in normal bandwidth + */ + if (bBlinkBothLED) { + /* + * Assign minimum number of blinks of + * either Tx or Rx. + */ + if (num_of_time_tx > num_of_time_rx) num_of_time = num_of_time_rx; else num_of_time = num_of_time_tx; - if(num_of_time > 0) - { - /*Blink both Tx and Rx LEDs*/ - if(LED_Blink(Adapter, 1<<GPIO_Num_tx, uiTxLedIndex, timeout, num_of_time,currdriverstate) + if (num_of_time > 0) { + /* Blink both Tx and Rx LEDs */ + if (LED_Blink(Adapter, 1 << GPIO_Num_tx, + uiTxLedIndex, timeout, + num_of_time, currdriverstate) == EVENT_SIGNALED) - { return EVENT_SIGNALED; - } - if(LED_Blink(Adapter, 1<<GPIO_Num_rx, uiRxLedIndex, timeout, num_of_time,currdriverstate) + + if (LED_Blink(Adapter, 1 << GPIO_Num_rx, + uiRxLedIndex, timeout, + num_of_time, currdriverstate) == EVENT_SIGNALED) - { return EVENT_SIGNALED; - } } - if(num_of_time == num_of_time_tx) - { - /*Blink pending rate of Rx*/ - if(LED_Blink(Adapter, (1 << GPIO_Num_rx), uiRxLedIndex, timeout, - num_of_time_rx-num_of_time,currdriverstate) == EVENT_SIGNALED) - { + if (num_of_time == num_of_time_tx) { + /* Blink pending rate of Rx */ + if (LED_Blink(Adapter, (1 << GPIO_Num_rx), + uiRxLedIndex, timeout, + num_of_time_rx-num_of_time, + currdriverstate) + == EVENT_SIGNALED) return EVENT_SIGNALED; - } + num_of_time = num_of_time_rx; - } - else - { - /*Blink pending rate of Tx*/ - if(LED_Blink(Adapter, 1<<GPIO_Num_tx, uiTxLedIndex, timeout, - num_of_time_tx-num_of_time,currdriverstate) == EVENT_SIGNALED) - { + } else { + /* Blink pending rate of Tx */ + if (LED_Blink(Adapter, 1 << GPIO_Num_tx, + uiTxLedIndex, timeout, + num_of_time_tx-num_of_time, + currdriverstate) + == EVENT_SIGNALED) return EVENT_SIGNALED; - } + num_of_time = num_of_time_tx; } - } - else - { - if(num_of_time == num_of_time_tx) - { - /*Blink pending rate of Rx*/ - if(LED_Blink(Adapter, 1<<GPIO_Num_tx, uiTxLedIndex, timeout, num_of_time,currdriverstate) + } else { + if (num_of_time == num_of_time_tx) { + /* Blink pending rate of Rx */ + if (LED_Blink(Adapter, 1 << GPIO_Num_tx, + uiTxLedIndex, timeout, + num_of_time, currdriverstate) == EVENT_SIGNALED) - { return EVENT_SIGNALED; - } - } - else - { - /*Blink pending rate of Tx*/ - if(LED_Blink(Adapter, 1<<GPIO_Num_rx, uiRxLedIndex, timeout, - num_of_time,currdriverstate) == EVENT_SIGNALED) - { + } else { + /* Blink pending rate of Tx */ + if (LED_Blink(Adapter, 1 << GPIO_Num_rx, + uiRxLedIndex, timeout, + num_of_time, currdriverstate) + == EVENT_SIGNALED) return EVENT_SIGNALED; - } } } - /* If Tx/Rx rate is less than maximum blinks per second, - * wait till delay completes to 1 second - */ + + /* + * If Tx/Rx rate is less than maximum blinks per second, + * wait till delay completes to 1 second + */ remDelay = MAX_NUM_OF_BLINKS - num_of_time; - if(remDelay > 0) - { - timeout= 100 * remDelay; - Status = wait_event_interruptible_timeout(Adapter->LEDInfo.notify_led_event, - currdriverstate!= Adapter->DriverState ||kthread_should_stop() , - msecs_to_jiffies (timeout)); - - if(kthread_should_stop()) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Led thread got signal to exit..hence exiting"); - Adapter->LEDInfo.led_thread_running= BCM_LED_THREAD_DISABLED; + if (remDelay > 0) { + timeout = 100 * remDelay; + Status = wait_event_interruptible_timeout( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState + || kthread_should_stop(), + msecs_to_jiffies(timeout)); + + if (kthread_should_stop()) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + LED_DUMP_INFO, DBG_LVL_ALL, + "Led thread got signal to exit..hence exiting"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; return EVENT_SIGNALED; } - if(Status) + if (Status) return EVENT_SIGNALED; } - /*Turn off both Tx and Rx LEDs before next second*/ - TURN_OFF_LED(1<<GPIO_Num_tx, uiTxLedIndex); - TURN_OFF_LED(1<<GPIO_Num_rx, uiTxLedIndex); + /* Turn off both Tx and Rx LEDs before next second */ + TURN_OFF_LED(1 << GPIO_Num_tx, uiTxLedIndex); + TURN_OFF_LED(1 << GPIO_Num_rx, uiTxLedIndex); /* - * Read the Tx & Rx packets transmission after 1 second and - * calculate rate of transfer - */ + * Read the Tx & Rx packets transmission after 1 second and + * calculate rate of transfer + */ Final_num_of_packts_tx = Adapter->dev->stats.tx_packets; Final_num_of_packts_rx = Adapter->dev->stats.rx_packets; - rate_of_transfer_tx = Final_num_of_packts_tx - Initial_num_of_packts_tx; - rate_of_transfer_rx = Final_num_of_packts_rx - Initial_num_of_packts_rx; + rate_of_transfer_tx = Final_num_of_packts_tx - + Initial_num_of_packts_tx; + rate_of_transfer_rx = Final_num_of_packts_rx - + Initial_num_of_packts_rx; - /*Read initial value of packets sent/received */ + /* Read initial value of packets sent/received */ Initial_num_of_packts_tx = Final_num_of_packts_tx; - Initial_num_of_packts_rx = Final_num_of_packts_rx ; + Initial_num_of_packts_rx = Final_num_of_packts_rx; - /*Scale the rate of transfer to no of blinks.*/ - num_of_time_tx= ScaleRateofTransfer((ULONG)rate_of_transfer_tx); - num_of_time_rx= ScaleRateofTransfer((ULONG)rate_of_transfer_rx); + /* Scale the rate of transfer to no of blinks. */ + num_of_time_tx = + ScaleRateofTransfer((ULONG)rate_of_transfer_tx); + num_of_time_rx = + ScaleRateofTransfer((ULONG)rate_of_transfer_rx); } return Status; } - -//----------------------------------------------------------------------------- -// Procedure: ValidateDSDParamsChecksum -// -// Description: Reads DSD Params and validates checkusm. -// -// Arguments: -// Adapter - Pointer to Adapter structure. -// ulParamOffset - Start offset of the DSD parameter to be read and validated. -// usParamLen - Length of the DSD Parameter. -// -// Returns: -// <OSAL_STATUS_CODE> -//----------------------------------------------------------------------------- - -static INT ValidateDSDParamsChecksum( - PMINI_ADAPTER Adapter, - ULONG ulParamOffset, - USHORT usParamLen ) +/* + * ----------------------------------------------------------------------------- + * Procedure: ValidateDSDParamsChecksum + * + * Description: Reads DSD Params and validates checkusm. + * + * Arguments: + * Adapter - Pointer to Adapter structure. + * ulParamOffset - Start offset of the DSD parameter to be read and + * validated. + * usParamLen - Length of the DSD Parameter. + * + * Returns: + * <OSAL_STATUS_CODE> + * ----------------------------------------------------------------------------- + */ +static INT ValidateDSDParamsChecksum(PMINI_ADAPTER Adapter, ULONG ulParamOffset, + USHORT usParamLen) { INT Status = STATUS_SUCCESS; - PUCHAR puBuffer = NULL; - USHORT usChksmOrg = 0; + PUCHAR puBuffer = NULL; + USHORT usChksmOrg = 0; USHORT usChecksumCalculated = 0; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X",ulParamOffset, usParamLen); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X", + ulParamOffset, usParamLen); puBuffer = kmalloc(usParamLen, GFP_KERNEL); - if(!puBuffer) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: ValidateDSDParamsChecksum Allocation failed"); + if (!puBuffer) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum Allocation failed"); return -ENOMEM; } - // - // Read the DSD data from the parameter offset. - // - if(STATUS_SUCCESS != BeceemNVMRead(Adapter,(PUINT)puBuffer,ulParamOffset,usParamLen)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed"); - Status=STATUS_IMAGE_CHECKSUM_MISMATCH; + /* Read the DSD data from the parameter offset. */ + if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)puBuffer, + ulParamOffset, usParamLen)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed"); + Status = STATUS_IMAGE_CHECKSUM_MISMATCH; goto exit; } - // - // Calculate the checksum of the data read from the DSD parameter. - // - usChecksumCalculated = CFG_CalculateChecksum(puBuffer,usParamLen); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: usCheckSumCalculated = 0x%x\n", usChecksumCalculated); - - // - // End of the DSD parameter will have a TWO bytes checksum stored in it. Read it and compare with the calculated - // Checksum. - // - if(STATUS_SUCCESS != BeceemNVMRead(Adapter,(PUINT)&usChksmOrg,ulParamOffset+usParamLen,2)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed"); - Status=STATUS_IMAGE_CHECKSUM_MISMATCH; + /* Calculate the checksum of the data read from the DSD parameter. */ + usChecksumCalculated = CFG_CalculateChecksum(puBuffer, usParamLen); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: usCheckSumCalculated = 0x%x\n", + usChecksumCalculated); + + /* + * End of the DSD parameter will have a TWO bytes checksum stored in it. + * Read it and compare with the calculated Checksum. + */ + if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)&usChksmOrg, + ulParamOffset+usParamLen, 2)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed"); + Status = STATUS_IMAGE_CHECKSUM_MISMATCH; goto exit; } usChksmOrg = ntohs(usChksmOrg); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: usChksmOrg = 0x%x", usChksmOrg); - - // - // Compare the checksum calculated with the checksum read from DSD section - // - if(usChecksumCalculated ^ usChksmOrg) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: ValidateDSDParamsChecksum: Checksums don't match"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: usChksmOrg = 0x%x", usChksmOrg); + + /* + * Compare the checksum calculated with the checksum read + * from DSD section + */ + if (usChecksumCalculated ^ usChksmOrg) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum: Checksums don't match"); Status = STATUS_IMAGE_CHECKSUM_MISMATCH; goto exit; } @@ -311,523 +332,526 @@ exit: } -//----------------------------------------------------------------------------- -// Procedure: ValidateHWParmStructure -// -// Description: Validates HW Parameters. -// -// Arguments: -// Adapter - Pointer to Adapter structure. -// ulHwParamOffset - Start offset of the HW parameter Section to be read and validated. -// -// Returns: -// <OSAL_STATUS_CODE> -//----------------------------------------------------------------------------- - +/* + * ----------------------------------------------------------------------------- + * Procedure: ValidateHWParmStructure + * + * Description: Validates HW Parameters. + * + * Arguments: + * Adapter - Pointer to Adapter structure. + * ulHwParamOffset - Start offset of the HW parameter Section to be read + * and validated. + * + * Returns: + * <OSAL_STATUS_CODE> + * ----------------------------------------------------------------------------- + */ static INT ValidateHWParmStructure(PMINI_ADAPTER Adapter, ULONG ulHwParamOffset) { - INT Status = STATUS_SUCCESS ; + INT Status = STATUS_SUCCESS; USHORT HwParamLen = 0; - // Add DSD start offset to the hwParamOffset to get the actual address. + /* + * Add DSD start offset to the hwParamOffset to get + * the actual address. + */ ulHwParamOffset += DSD_START_OFFSET; - /*Read the Length of HW_PARAM structure*/ - BeceemNVMRead(Adapter,(PUINT)&HwParamLen,ulHwParamOffset,2); + /* Read the Length of HW_PARAM structure */ + BeceemNVMRead(Adapter, (PUINT)&HwParamLen, ulHwParamOffset, 2); HwParamLen = ntohs(HwParamLen); - if(0==HwParamLen || HwParamLen > Adapter->uiNVMDSDSize) - { + if (0 == HwParamLen || HwParamLen > Adapter->uiNVMDSDSize) return STATUS_IMAGE_CHECKSUM_MISMATCH; - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "LED Thread:HwParamLen = 0x%x", HwParamLen); - Status =ValidateDSDParamsChecksum(Adapter,ulHwParamOffset,HwParamLen); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread:HwParamLen = 0x%x", HwParamLen); + Status = ValidateDSDParamsChecksum(Adapter, ulHwParamOffset, + HwParamLen); return Status; } /* ValidateHWParmStructure() */ -static int ReadLEDInformationFromEEPROM(PMINI_ADAPTER Adapter, UCHAR GPIO_Array[]) +static int ReadLEDInformationFromEEPROM(PMINI_ADAPTER Adapter, + UCHAR GPIO_Array[]) { int Status = STATUS_SUCCESS; - ULONG dwReadValue = 0; - USHORT usHwParamData = 0; - USHORT usEEPROMVersion = 0; - UCHAR ucIndex = 0; - UCHAR ucGPIOInfo[32] = {0}; + ULONG dwReadValue = 0; + USHORT usHwParamData = 0; + USHORT usEEPROMVersion = 0; + UCHAR ucIndex = 0; + UCHAR ucGPIOInfo[32] = {0}; - BeceemNVMRead(Adapter,(PUINT)&usEEPROMVersion,EEPROM_VERSION_OFFSET,2); + BeceemNVMRead(Adapter, (PUINT)&usEEPROMVersion, + EEPROM_VERSION_OFFSET, 2); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"usEEPROMVersion: Minor:0x%X Major:0x%x",usEEPROMVersion&0xFF, ((usEEPROMVersion>>8)&0xFF)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "usEEPROMVersion: Minor:0x%X Major:0x%x", + usEEPROMVersion&0xFF, ((usEEPROMVersion>>8)&0xFF)); - if(((usEEPROMVersion>>8)&0xFF) < EEPROM_MAP5_MAJORVERSION) - { - BeceemNVMRead(Adapter,(PUINT)&usHwParamData,EEPROM_HW_PARAM_POINTER_ADDRESS,2); + if (((usEEPROMVersion>>8)&0xFF) < EEPROM_MAP5_MAJORVERSION) { + BeceemNVMRead(Adapter, (PUINT)&usHwParamData, + EEPROM_HW_PARAM_POINTER_ADDRESS, 2); usHwParamData = ntohs(usHwParamData); dwReadValue = usHwParamData; - } - else - { - // - // Validate Compatibility section and then read HW param if compatibility section is valid. - // + } else { + /* + * Validate Compatibility section and then read HW param + * if compatibility section is valid. + */ Status = ValidateDSDParamsChecksum(Adapter, - DSD_START_OFFSET, - COMPATIBILITY_SECTION_LENGTH_MAP5); + DSD_START_OFFSET, + COMPATIBILITY_SECTION_LENGTH_MAP5); - if(Status != STATUS_SUCCESS) - { + if (Status != STATUS_SUCCESS) return Status; - } - BeceemNVMRead(Adapter,(PUINT)&dwReadValue,EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5,4); + + BeceemNVMRead(Adapter, (PUINT)&dwReadValue, + EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5, 4); dwReadValue = ntohl(dwReadValue); } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: Start address of HW_PARAM structure = 0x%lx",dwReadValue); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: Start address of HW_PARAM structure = 0x%lx", + dwReadValue); - // - // Validate if the address read out is within the DSD. - // Adapter->uiNVMDSDSize gives whole DSD size inclusive of Autoinit. - // lower limit should be above DSD_START_OFFSET and - // upper limit should be below (Adapter->uiNVMDSDSize-DSD_START_OFFSET) - // - if(dwReadValue < DSD_START_OFFSET || - dwReadValue > (Adapter->uiNVMDSDSize-DSD_START_OFFSET)) - { + /* + * Validate if the address read out is within the DSD. + * Adapter->uiNVMDSDSize gives whole DSD size inclusive of Autoinit. + * lower limit should be above DSD_START_OFFSET and + * upper limit should be below (Adapter->uiNVMDSDSize-DSD_START_OFFSET) + */ + if (dwReadValue < DSD_START_OFFSET || + dwReadValue > (Adapter->uiNVMDSDSize-DSD_START_OFFSET)) return STATUS_IMAGE_CHECKSUM_MISMATCH; - } Status = ValidateHWParmStructure(Adapter, dwReadValue); - if(Status){ + if (Status) return Status; - } /* - Add DSD_START_OFFSET to the offset read from the EEPROM. - This will give the actual start HW Parameters start address. - To read GPIO section, add GPIO offset further. - */ - - dwReadValue += DSD_START_OFFSET; // = start address of hw param section. - dwReadValue += GPIO_SECTION_START_OFFSET; // = GPIO start offset within HW Param section. - - /* Read the GPIO values for 32 GPIOs from EEPROM and map the function - * number to GPIO pin number to GPIO_Array - */ - BeceemNVMRead(Adapter, (UINT *)ucGPIOInfo,dwReadValue,32); - for(ucIndex = 0; ucIndex < 32; ucIndex++) - { - - switch(ucGPIOInfo[ucIndex]) - { - case RED_LED: - { - GPIO_Array[RED_LED] = ucIndex; - Adapter->gpioBitMap |= (1<<ucIndex); - break; - } - case BLUE_LED: - { - GPIO_Array[BLUE_LED] = ucIndex; - Adapter->gpioBitMap |= (1<<ucIndex); - break; - } - case YELLOW_LED: - { - GPIO_Array[YELLOW_LED] = ucIndex; - Adapter->gpioBitMap |= (1<<ucIndex); - break; - } - case GREEN_LED: - { - GPIO_Array[GREEN_LED] = ucIndex; - Adapter->gpioBitMap |= (1<<ucIndex); - break; - } - default: - break; - } + * Add DSD_START_OFFSET to the offset read from the EEPROM. + * This will give the actual start HW Parameters start address. + * To read GPIO section, add GPIO offset further. + */ + + dwReadValue += + DSD_START_OFFSET; /* = start address of hw param section. */ + dwReadValue += GPIO_SECTION_START_OFFSET; + /* = GPIO start offset within HW Param section. */ + /* + * Read the GPIO values for 32 GPIOs from EEPROM and map the function + * number to GPIO pin number to GPIO_Array + */ + BeceemNVMRead(Adapter, (UINT *)ucGPIOInfo, dwReadValue, 32); + for (ucIndex = 0; ucIndex < 32; ucIndex++) { + + switch (ucGPIOInfo[ucIndex]) { + case RED_LED: + GPIO_Array[RED_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + case BLUE_LED: + GPIO_Array[BLUE_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + case YELLOW_LED: + GPIO_Array[YELLOW_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + case GREEN_LED: + GPIO_Array[GREEN_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + default: + break; } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"GPIO's bit map correspond to LED :0x%X",Adapter->gpioBitMap); - return Status; + + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "GPIO's bit map correspond to LED :0x%X", Adapter->gpioBitMap); + return Status; } -static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread) +static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, + BOOLEAN *bEnableThread) { int Status = STATUS_SUCCESS; - UCHAR GPIO_Array[NUM_OF_LEDS+1]; /*Array to store GPIO numbers from EEPROM*/ + /* Array to store GPIO numbers from EEPROM */ + UCHAR GPIO_Array[NUM_OF_LEDS+1]; UINT uiIndex = 0; UINT uiNum_of_LED_Type = 0; PUCHAR puCFGData = NULL; UCHAR bData = 0; memset(GPIO_Array, DISABLE_GPIO_NUM, NUM_OF_LEDS+1); - if(!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams)) - { - BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Target Params not Avail.\n"); + if (!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams)) { + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "Target Params not Avail.\n"); return -ENOENT; } - /*Populate GPIO_Array with GPIO numbers for LED functions*/ - /*Read the GPIO numbers from EEPROM*/ + /* Populate GPIO_Array with GPIO numbers for LED functions */ + /* Read the GPIO numbers from EEPROM */ Status = ReadLEDInformationFromEEPROM(Adapter, GPIO_Array); - if(Status == STATUS_IMAGE_CHECKSUM_MISMATCH) - { + if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH) { *bEnableThread = FALSE; return STATUS_SUCCESS; - } - else if(Status) - { + } else if (Status) { *bEnableThread = FALSE; return Status; } - /* - * CONFIG file read successfully. Deallocate the memory of - * uiFileNameBufferSize - */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: Config file read successfully\n"); + + /* + * CONFIG file read successfully. Deallocate the memory of + * uiFileNameBufferSize + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: Config file read successfully\n"); puCFGData = (PUCHAR) &Adapter->pstargetparams->HostDrvrConfig1; /* - * Offset for HostDrvConfig1, HostDrvConfig2, HostDrvConfig3 which - * will have the information of LED type, LED on state for different - * driver state and LED blink state. - */ + * Offset for HostDrvConfig1, HostDrvConfig2, HostDrvConfig3 which + * will have the information of LED type, LED on state for different + * driver state and LED blink state. + */ - for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) - { + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { bData = *puCFGData; - /*Check Bit 8 for polarity. If it is set, polarity is reverse polarity*/ - if(bData & 0x80) - { + /* + * Check Bit 8 for polarity. If it is set, + * polarity is reverse polarity + */ + if (bData & 0x80) { Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 0; - /*unset the bit 8*/ + /* unset the bit 8 */ bData = bData & 0x7f; } Adapter->LEDInfo.LEDState[uiIndex].LED_Type = bData; - if(bData <= NUM_OF_LEDS) - Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = GPIO_Array[bData]; + if (bData <= NUM_OF_LEDS) + Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = + GPIO_Array[bData]; else - Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = DISABLE_GPIO_NUM; + Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = + DISABLE_GPIO_NUM; puCFGData++; bData = *puCFGData; Adapter->LEDInfo.LEDState[uiIndex].LED_On_State = bData; puCFGData++; bData = *puCFGData; - Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State= bData; + Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State = bData; puCFGData++; } - /*Check if all the LED settings are disabled. If it is disabled, dont launch the LED control thread.*/ - for(uiIndex = 0; uiIndex<NUM_OF_LEDS; uiIndex++) - { - if((Adapter->LEDInfo.LEDState[uiIndex].LED_Type == DISABLE_GPIO_NUM) || - (Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0x7f) || + /* + * Check if all the LED settings are disabled. If it is disabled, + * dont launch the LED control thread. + */ + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if ((Adapter->LEDInfo.LEDState[uiIndex].LED_Type == DISABLE_GPIO_NUM) || + (Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0x7f) || (Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0)) uiNum_of_LED_Type++; } - if(uiNum_of_LED_Type >= NUM_OF_LEDS) + if (uiNum_of_LED_Type >= NUM_OF_LEDS) *bEnableThread = FALSE; return Status; } -//-------------------------------------------------------------------------- -// Procedure: LedGpioInit -// -// Description: Initializes LED GPIOs. Makes the LED GPIOs to OUTPUT mode and make the -// initial state to be OFF. -// -// Arguments: -// Adapter - Pointer to MINI_ADAPTER structure. -// -// Returns: VOID -// -//----------------------------------------------------------------------------- +/* + * ----------------------------------------------------------------------------- + * Procedure: LedGpioInit + * + * Description: Initializes LED GPIOs. Makes the LED GPIOs to OUTPUT mode + * and make the initial state to be OFF. + * + * Arguments: + * Adapter - Pointer to MINI_ADAPTER structure. + * + * Returns: VOID + * + * ----------------------------------------------------------------------------- + */ static VOID LedGpioInit(PMINI_ADAPTER Adapter) { UINT uiResetValue = 0; UINT uiIndex = 0; /* Set all LED GPIO Mode to output mode */ - if(rdmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue, sizeof(uiResetValue)) <0) - BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: RDM Failed\n"); - for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) - { - if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM) + if (rdmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue, + sizeof(uiResetValue)) < 0) + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "LED Thread: RDM Failed\n"); + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != + DISABLE_GPIO_NUM) uiResetValue |= (1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num); - TURN_OFF_LED(1<<Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num,uiIndex); + TURN_OFF_LED(1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num, + uiIndex); } - if(wrmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue, sizeof(uiResetValue)) < 0) - BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: WRM Failed\n"); + if (wrmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue, + sizeof(uiResetValue)) < 0) + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "LED Thread: WRM Failed\n"); - Adapter->LEDInfo.bIdle_led_off = FALSE; + Adapter->LEDInfo.bIdle_led_off = FALSE; } -//----------------------------------------------------------------------------- -static INT BcmGetGPIOPinInfo(PMINI_ADAPTER Adapter, UCHAR *GPIO_num_tx, UCHAR *GPIO_num_rx ,UCHAR *uiLedTxIndex, UCHAR *uiLedRxIndex,LedEventInfo_t currdriverstate) +static INT BcmGetGPIOPinInfo(PMINI_ADAPTER Adapter, UCHAR *GPIO_num_tx, + UCHAR *GPIO_num_rx, UCHAR *uiLedTxIndex, UCHAR *uiLedRxIndex, + LedEventInfo_t currdriverstate) { UINT uiIndex = 0; *GPIO_num_tx = DISABLE_GPIO_NUM; *GPIO_num_rx = DISABLE_GPIO_NUM; - for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) - { + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { - if((currdriverstate == NORMAL_OPERATION)|| - (currdriverstate == IDLEMODE_EXIT)|| - (currdriverstate == FW_DOWNLOAD)) - { - if(Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State & currdriverstate) - { - if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM) - { - if(*GPIO_num_tx == DISABLE_GPIO_NUM) - { + if ((currdriverstate == NORMAL_OPERATION) || + (currdriverstate == IDLEMODE_EXIT) || + (currdriverstate == FW_DOWNLOAD)) { + if (Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State & + currdriverstate) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) { + if (*GPIO_num_tx == DISABLE_GPIO_NUM) { *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num; *uiLedTxIndex = uiIndex; - } - else - { + } else { *GPIO_num_rx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num; *uiLedRxIndex = uiIndex; } } } - } - else - { - if(Adapter->LEDInfo.LEDState[uiIndex].LED_On_State & currdriverstate) - { - if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM) - { + } else { + if (Adapter->LEDInfo.LEDState[uiIndex].LED_On_State + & currdriverstate) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) { *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num; *uiLedTxIndex = uiIndex; } } } } - return STATUS_SUCCESS ; + return STATUS_SUCCESS; } static VOID LEDControlThread(PMINI_ADAPTER Adapter) { UINT uiIndex = 0; UCHAR GPIO_num = 0; - UCHAR uiLedIndex = 0 ; + UCHAR uiLedIndex = 0; UINT uiResetValue = 0; LedEventInfo_t currdriverstate = 0; ulong timeout = 0; INT Status = 0; - UCHAR dummyGPIONum = 0; - UCHAR dummyIndex = 0; + UCHAR dummyGPIONum = 0; + UCHAR dummyIndex = 0; - //currdriverstate = Adapter->DriverState; + /* currdriverstate = Adapter->DriverState; */ Adapter->LEDInfo.bIdleMode_tx_from_host = FALSE; - /*Wait till event is triggered*/ - //wait_event(Adapter->LEDInfo.notify_led_event, - // currdriverstate!= Adapter->DriverState); + /* + * Wait till event is triggered + * + * wait_event(Adapter->LEDInfo.notify_led_event, + * currdriverstate!= Adapter->DriverState); + */ - GPIO_num = DISABLE_GPIO_NUM ; + GPIO_num = DISABLE_GPIO_NUM; - while(TRUE) - { - /*Wait till event is triggered*/ - if( (GPIO_num == DISABLE_GPIO_NUM) + while (TRUE) { + /* Wait till event is triggered */ + if ((GPIO_num == DISABLE_GPIO_NUM) || - ((currdriverstate != FW_DOWNLOAD) && - (currdriverstate != NORMAL_OPERATION) && - (currdriverstate != LOWPOWER_MODE_ENTER)) - || - (currdriverstate == LED_THREAD_INACTIVE) ) - { - Status = wait_event_interruptible(Adapter->LEDInfo.notify_led_event, - currdriverstate != Adapter->DriverState || kthread_should_stop()); - } - - if(kthread_should_stop() || Adapter->device_removed ) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Led thread got signal to exit..hence exiting"); - Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED; - TURN_OFF_LED(1<<GPIO_num, uiLedIndex); - return ;//STATUS_FAILURE; + ((currdriverstate != FW_DOWNLOAD) && + (currdriverstate != NORMAL_OPERATION) && + (currdriverstate != LOWPOWER_MODE_ENTER)) + || + (currdriverstate == LED_THREAD_INACTIVE)) + Status = wait_event_interruptible( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState + || kthread_should_stop()); + + if (kthread_should_stop() || Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "Led thread got signal to exit..hence exiting"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; + TURN_OFF_LED(1 << GPIO_num, uiLedIndex); + return; /* STATUS_FAILURE; */ } - if(GPIO_num != DISABLE_GPIO_NUM) - { - TURN_OFF_LED(1<<GPIO_num, uiLedIndex); - } + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_OFF_LED(1 << GPIO_num, uiLedIndex); - if(Adapter->LEDInfo.bLedInitDone == FALSE) - { + if (Adapter->LEDInfo.bLedInitDone == FALSE) { LedGpioInit(Adapter); Adapter->LEDInfo.bLedInitDone = TRUE; } - switch(Adapter->DriverState) - { - case DRIVER_INIT: - { - currdriverstate = DRIVER_INIT;//Adapter->DriverState; - BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate); + switch (Adapter->DriverState) { + case DRIVER_INIT: + currdriverstate = DRIVER_INIT; + /* Adapter->DriverState; */ + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyIndex, currdriverstate); + + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_ON_LED(1 << GPIO_num, uiLedIndex); - if(GPIO_num != DISABLE_GPIO_NUM) - { - TURN_ON_LED(1<<GPIO_num, uiLedIndex); - } - } break; - case FW_DOWNLOAD: - { - //BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: FW_DN_DONE called\n"); - currdriverstate = FW_DOWNLOAD; - BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate); - - if(GPIO_num != DISABLE_GPIO_NUM) - { - timeout = 50; - LED_Blink(Adapter, 1<<GPIO_num, uiLedIndex, timeout, -1,currdriverstate); - } + case FW_DOWNLOAD: + /* + * BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + * LED_DUMP_INFO, DBG_LVL_ALL, + * "LED Thread: FW_DN_DONE called\n"); + */ + currdriverstate = FW_DOWNLOAD; + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyIndex, currdriverstate); + + if (GPIO_num != DISABLE_GPIO_NUM) { + timeout = 50; + LED_Blink(Adapter, 1 << GPIO_num, uiLedIndex, + timeout, -1, currdriverstate); } break; - case FW_DOWNLOAD_DONE: - { - currdriverstate = FW_DOWNLOAD_DONE; - BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex,currdriverstate); - if(GPIO_num != DISABLE_GPIO_NUM) - { - TURN_ON_LED(1<<GPIO_num, uiLedIndex); - } - } + case FW_DOWNLOAD_DONE: + currdriverstate = FW_DOWNLOAD_DONE; + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyIndex, currdriverstate); + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_ON_LED(1 << GPIO_num, uiLedIndex); break; - case SHUTDOWN_EXIT: - //no break, continue to NO_NETWORK_ENTRY state as well. - - case NO_NETWORK_ENTRY: - { - currdriverstate = NO_NETWORK_ENTRY; - BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex,&dummyGPIONum,currdriverstate); - if(GPIO_num != DISABLE_GPIO_NUM) - { - TURN_ON_LED(1<<GPIO_num, uiLedIndex); - } - } + case SHUTDOWN_EXIT: + /* + * no break, continue to NO_NETWORK_ENTRY + * state as well. + */ + case NO_NETWORK_ENTRY: + currdriverstate = NO_NETWORK_ENTRY; + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyGPIONum, currdriverstate); + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_ON_LED(1 << GPIO_num, uiLedIndex); break; - case NORMAL_OPERATION: + case NORMAL_OPERATION: { UCHAR GPIO_num_tx = DISABLE_GPIO_NUM; UCHAR GPIO_num_rx = DISABLE_GPIO_NUM; UCHAR uiLEDTx = 0; UCHAR uiLEDRx = 0; currdriverstate = NORMAL_OPERATION; - Adapter->LEDInfo.bIdle_led_off = FALSE; - - BcmGetGPIOPinInfo(Adapter, &GPIO_num_tx, &GPIO_num_rx, &uiLEDTx,&uiLEDRx,currdriverstate); - if((GPIO_num_tx == DISABLE_GPIO_NUM) && (GPIO_num_rx == DISABLE_GPIO_NUM)) - { - GPIO_num = DISABLE_GPIO_NUM ; - } - else - { - /*If single LED is selected, use same for both Tx and Rx*/ - if(GPIO_num_tx == DISABLE_GPIO_NUM) - { + Adapter->LEDInfo.bIdle_led_off = FALSE; + + BcmGetGPIOPinInfo(Adapter, &GPIO_num_tx, + &GPIO_num_rx, &uiLEDTx, &uiLEDRx, + currdriverstate); + if ((GPIO_num_tx == DISABLE_GPIO_NUM) && + (GPIO_num_rx == + DISABLE_GPIO_NUM)) { + GPIO_num = DISABLE_GPIO_NUM; + } else { + /* + * If single LED is selected, use same + * for both Tx and Rx + */ + if (GPIO_num_tx == DISABLE_GPIO_NUM) { GPIO_num_tx = GPIO_num_rx; uiLEDTx = uiLEDRx; - } - else if(GPIO_num_rx == DISABLE_GPIO_NUM) - { + } else if (GPIO_num_rx == + DISABLE_GPIO_NUM) { GPIO_num_rx = GPIO_num_tx; uiLEDRx = uiLEDTx; } - /*Blink the LED in proportionate to Tx and Rx transmissions.*/ - LED_Proportional_Blink(Adapter, GPIO_num_tx, uiLEDTx, GPIO_num_rx, uiLEDRx,currdriverstate); + /* + * Blink the LED in proportionate + * to Tx and Rx transmissions. + */ + LED_Proportional_Blink(Adapter, + GPIO_num_tx, uiLEDTx, + GPIO_num_rx, uiLEDRx, + currdriverstate); } } break; - case LOWPOWER_MODE_ENTER: - { - currdriverstate = LOWPOWER_MODE_ENTER; - if( DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING == Adapter->ulPowerSaveMode) - { - /* Turn OFF all the LED */ - uiResetValue = 0; - for(uiIndex =0; uiIndex < NUM_OF_LEDS; uiIndex++) - { - if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM) - TURN_OFF_LED((1<<Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num),uiIndex); - } - + case LOWPOWER_MODE_ENTER: + currdriverstate = LOWPOWER_MODE_ENTER; + if (DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING == + Adapter->ulPowerSaveMode) { + /* Turn OFF all the LED */ + uiResetValue = 0; + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM) + TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex); } - /* Turn off LED And WAKE-UP for Sendinf IDLE mode ACK */ - Adapter->LEDInfo.bLedInitDone = FALSE; - Adapter->LEDInfo.bIdle_led_off = TRUE; - wake_up(&Adapter->LEDInfo.idleModeSyncEvent); - GPIO_num = DISABLE_GPIO_NUM; - break; - } - case IDLEMODE_CONTINUE: - { - currdriverstate = IDLEMODE_CONTINUE; - GPIO_num = DISABLE_GPIO_NUM; + } + /* Turn off LED And WAKE-UP for Sendinf IDLE mode ACK */ + Adapter->LEDInfo.bLedInitDone = FALSE; + Adapter->LEDInfo.bIdle_led_off = TRUE; + wake_up(&Adapter->LEDInfo.idleModeSyncEvent); + GPIO_num = DISABLE_GPIO_NUM; break; - case IDLEMODE_EXIT: - { - } + case IDLEMODE_CONTINUE: + currdriverstate = IDLEMODE_CONTINUE; + GPIO_num = DISABLE_GPIO_NUM; break; - case DRIVER_HALT: - { - currdriverstate = DRIVER_HALT; - GPIO_num = DISABLE_GPIO_NUM; - for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) - { - if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != - DISABLE_GPIO_NUM) - TURN_OFF_LED((1<<Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num),uiIndex); - } - //Adapter->DriverState = DRIVER_INIT; + case IDLEMODE_EXIT: + break; + case DRIVER_HALT: + currdriverstate = DRIVER_HALT; + GPIO_num = DISABLE_GPIO_NUM; + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) + TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex); } + /* Adapter->DriverState = DRIVER_INIT; */ break; - case LED_THREAD_INACTIVE : - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"InActivating LED thread..."); - currdriverstate = LED_THREAD_INACTIVE; - Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_RUNNING_INACTIVELY ; - Adapter->LEDInfo.bLedInitDone = FALSE ; - //disable ALL LED - for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) - { - if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != - DISABLE_GPIO_NUM) - TURN_OFF_LED((1<<Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num),uiIndex); - } + case LED_THREAD_INACTIVE: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "InActivating LED thread..."); + currdriverstate = LED_THREAD_INACTIVE; + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_RUNNING_INACTIVELY; + Adapter->LEDInfo.bLedInitDone = FALSE; + /* disable ALL LED */ + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) + TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex); } break; - case LED_THREAD_ACTIVE : - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"Activating LED thread again..."); - if(Adapter->LinkUpStatus == FALSE) - Adapter->DriverState = NO_NETWORK_ENTRY; - else - Adapter->DriverState = NORMAL_OPERATION; + case LED_THREAD_ACTIVE: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "Activating LED thread again..."); + if (Adapter->LinkUpStatus == FALSE) + Adapter->DriverState = NO_NETWORK_ENTRY; + else + Adapter->DriverState = NORMAL_OPERATION; - Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_RUNNING_ACTIVELY ; - } + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_RUNNING_ACTIVELY; + break; + /* return; */ + default: break; - //return; - default: - break; } } Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED; @@ -839,49 +863,54 @@ int InitLedSettings(PMINI_ADAPTER Adapter) BOOLEAN bEnableThread = TRUE; UCHAR uiIndex = 0; - /*Initially set BitPolarity to normal polarity. The bit 8 of LED type - * is used to change the polarity of the LED.*/ + /* + * Initially set BitPolarity to normal polarity. The bit 8 of LED type + * is used to change the polarity of the LED. + */ - for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 1; - } - /*Read the LED settings of CONFIG file and map it to GPIO numbers in EEPROM*/ + /* + * Read the LED settings of CONFIG file and map it + * to GPIO numbers in EEPROM + */ Status = ReadConfigFileStructure(Adapter, &bEnableThread); - if(STATUS_SUCCESS != Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: FAILED in ReadConfigFileStructure\n"); + if (STATUS_SUCCESS != Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: FAILED in ReadConfigFileStructure\n"); return Status; } - if(Adapter->LEDInfo.led_thread_running) - { - if(bEnableThread) + if (Adapter->LEDInfo.led_thread_running) { + if (bEnableThread) { ; - else - { + } else { Adapter->DriverState = DRIVER_HALT; wake_up(&Adapter->LEDInfo.notify_led_event); - Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED; + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; } - } - - else if(bEnableThread) - { - /*Create secondary thread to handle the LEDs*/ + } else if (bEnableThread) { + /* Create secondary thread to handle the LEDs */ init_waitqueue_head(&Adapter->LEDInfo.notify_led_event); init_waitqueue_head(&Adapter->LEDInfo.idleModeSyncEvent); - Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_RUNNING_ACTIVELY; - Adapter->LEDInfo.bIdle_led_off = FALSE; - Adapter->LEDInfo.led_cntrl_threadid = kthread_run((int (*)(void *)) - LEDControlThread, Adapter, "led_control_thread"); - if(IS_ERR(Adapter->LEDInfo.led_cntrl_threadid)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Not able to spawn Kernel Thread\n"); - Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED; - return PTR_ERR(Adapter->LEDInfo.led_cntrl_threadid); - } + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_RUNNING_ACTIVELY; + Adapter->LEDInfo.bIdle_led_off = FALSE; + Adapter->LEDInfo.led_cntrl_threadid = + kthread_run((int (*)(void *)) LEDControlThread, + Adapter, "led_control_thread"); + if (IS_ERR(Adapter->LEDInfo.led_cntrl_threadid)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "Not able to spawn Kernel Thread\n"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; + return PTR_ERR(Adapter->LEDInfo.led_cntrl_threadid); + } } return Status; } diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c index 3de0daf5edb..7d703cb3c5e 100644 --- a/drivers/staging/bcm/nvm.c +++ b/drivers/staging/bcm/nvm.c @@ -78,7 +78,7 @@ static UCHAR ReadEEPROMStatusRegister( PMINI_ADAPTER Adapter ) { value=0; uiStatus = 0 ; - rdmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG,&uiStatus, sizeof(uiStatus)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); if(Adapter->device_removed == TRUE) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Modem has got removed hence exiting...."); @@ -93,7 +93,7 @@ static UCHAR ReadEEPROMStatusRegister( PMINI_ADAPTER Adapter ) wrmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); value =0; - rdmalt(Adapter, EEPROM_READ_DATAQ_REG,&value, sizeof(value)); + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); uiData = (UCHAR)value; break; @@ -102,8 +102,8 @@ static UCHAR ReadEEPROMStatusRegister( PMINI_ADAPTER Adapter ) dwRetries-- ; if ( dwRetries == 0 ) { - rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value)); - rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG,&value1, sizeof(value1)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG, &value1, sizeof(value1)); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"0x3004 = %x 0x3008 = %x, retries = %d failed.\n",value,value1, MAX_EEPROM_RETRIES*RETRIES_PER_DELAY); return uiData; } @@ -158,7 +158,7 @@ INT ReadBeceemEEPROMBulk( PMINI_ADAPTER Adapter, { uiStatus = 0; - rdmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); if(Adapter->device_removed == TRUE) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Modem has got Removed.hence exiting from loop..."); @@ -202,8 +202,8 @@ INT ReadBeceemEEPROMBulk( PMINI_ADAPTER Adapter, { value=0; value1=0; - rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value)); - rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG,&value1, sizeof(value1)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG, &value1, sizeof(value1)); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "dwNumWords %d 0x3004 = %x 0x3008 = %x retries = %d failed.\n", dwNumWords, value, value1, MAX_EEPROM_RETRIES*RETRIES_PER_DELAY); return STATUS_FAILURE; } @@ -217,22 +217,22 @@ INT ReadBeceemEEPROMBulk( PMINI_ADAPTER Adapter, pvalue = (PUCHAR)(pdwData + dwIndex); value =0; - rdmalt(Adapter, EEPROM_READ_DATAQ_REG,&value, sizeof(value)); + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); pvalue[0] = value; value = 0; - rdmalt(Adapter, EEPROM_READ_DATAQ_REG,&value, sizeof(value)); + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); pvalue[1] = value; value =0; - rdmalt(Adapter, EEPROM_READ_DATAQ_REG,&value, sizeof(value)); + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); pvalue[2] = value; value = 0; - rdmalt(Adapter, EEPROM_READ_DATAQ_REG,&value, sizeof(value)); + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); pvalue[3] = value; } @@ -445,6 +445,7 @@ static INT BeceemFlashBulkRead( UINT uiBytesToRead = uiNumBytes; INT Status = 0; UINT uiPartOffset = 0; + int bytes; if(Adapter->device_removed ) { @@ -469,9 +470,9 @@ static INT BeceemFlashBulkRead( uiBytesToRead = MAX_RW_SIZE - (uiOffset%MAX_RW_SIZE); uiBytesToRead = MIN(uiNumBytes,uiBytesToRead); - if(rdm(Adapter,uiPartOffset, (PCHAR)pBuffer+uiIndex,uiBytesToRead)) - { - Status = -1; + bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer+uiIndex, uiBytesToRead); + if (bytes < 0) { + Status = bytes; Adapter->SelectedChip = RESET_CHIP_SELECT; return Status; } @@ -488,9 +489,9 @@ static INT BeceemFlashBulkRead( uiBytesToRead = MIN(uiNumBytes,MAX_RW_SIZE); - if(rdm(Adapter,uiPartOffset, (PCHAR)pBuffer+uiIndex,uiBytesToRead)) - { - Status = -1; + bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer+uiIndex, uiBytesToRead); + if (bytes < 0) { + Status = bytes; break; } @@ -613,6 +614,7 @@ static INT FlashSectorErase(PMINI_ADAPTER Adapter, UINT iIndex = 0, iRetries = 0; UINT uiStatus = 0; UINT value; + int bytes; for(iIndex=0;iIndex<numOfSectors;iIndex++) { @@ -632,10 +634,11 @@ static INT FlashSectorErase(PMINI_ADAPTER Adapter, return STATUS_FAILURE; } - if(rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)) < 0 ) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Reading status of FLASH_SPI_READQ_REG fails"); - return STATUS_FAILURE; + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; } iRetries++; //After every try lets make the CPU free for 10 ms. generally time taken by the @@ -679,6 +682,7 @@ static INT flashByteWrite( UINT value; ULONG ulData = *(PUCHAR)pData; + int bytes; // // need not write 0xFF because write requires an erase and erase will @@ -720,10 +724,11 @@ static INT flashByteWrite( return STATUS_FAILURE; } //__udelay(1); - if(rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)) < 0) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Reading status of FLASH_SPI_READQ_REG fails"); - return STATUS_FAILURE; + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; } iRetries--; if( iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0)) @@ -771,6 +776,7 @@ static INT flashWrite( UINT value; UINT uiErasePattern[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + int bytes; // // need not write 0xFFFFFFFF because write requires an erase and erase will // make whole sector 0xFFFFFFFF. @@ -803,10 +809,11 @@ static INT flashWrite( return STATUS_FAILURE; } //__udelay(1); - if(rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)) < 0 ) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Reading status of FLASH_SPI_READQ_REG fails"); - return STATUS_FAILURE; + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; } iRetries--; @@ -849,6 +856,7 @@ static INT flashByteWriteStatus( INT iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; //3 ULONG ulData = *(PUCHAR)pData; UINT value; + int bytes; // // need not write 0xFFFFFFFF because write requires an erase and erase will @@ -891,10 +899,11 @@ static INT flashByteWriteStatus( return STATUS_FAILURE; } //__udelay(1); - if(rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)) < 0) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Reading status of FLASH_SPI_READQ_REG fails"); - return STATUS_FAILURE; + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; } iRetries--; @@ -935,6 +944,7 @@ static INT flashWriteStatus( //UINT uiReadBack = 0; UINT value; UINT uiErasePattern[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + int bytes; // // need not write 0xFFFFFFFF because write requires an erase and erase will @@ -967,10 +977,11 @@ static INT flashWriteStatus( return STATUS_FAILURE; } //__udelay(1); - if(rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)) < 0) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Reading status of FLASH_SPI_READQ_REG fails"); - return STATUS_FAILURE; + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; } iRetries--; //this will ensure that in there will be no changes in the current path. @@ -1841,7 +1852,7 @@ static INT BeceemEEPROMWritePage( PMINI_ADAPTER Adapter, UINT uiData[], UINT uiO * What we are checking if the previous write has completed, and this * may take time. We should wait till the Empty bit is set. */ uiStatus = 0; - rdmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG,&uiStatus, sizeof(uiStatus)) ; + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); while ( ( uiStatus & EEPROM_WRITE_QUEUE_EMPTY ) == 0 ) { uiRetries--; @@ -1855,7 +1866,7 @@ static INT BeceemEEPROMWritePage( PMINI_ADAPTER Adapter, UINT uiData[], UINT uiO msleep(1); uiStatus = 0; - rdmalt( Adapter, EEPROM_SPI_Q_STATUS1_REG,&uiStatus, sizeof(uiStatus)) ; + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); if(Adapter->device_removed == TRUE) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Modem got removed hence exiting from loop...."); @@ -2500,7 +2511,7 @@ static ULONG BcmReadFlashRDID(PMINI_ADAPTER Adapter) // Read SPI READQ REG. The output will be WWXXYYZZ. // The ID is 3Bytes long and is WWXXYY. ZZ needs to be Ignored. // - rdmalt(Adapter, FLASH_SPI_READQ_REG,(PUINT)&ulRDID, sizeof(ulRDID)); + rdmalt(Adapter, FLASH_SPI_READQ_REG, (PUINT)&ulRDID, sizeof(ulRDID)); return (ulRDID >>8); @@ -4735,8 +4746,8 @@ static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset) Adapter->SelectedChip = ChipNum ; //bit[13..12] will select the appropriate chip - rdmalt(Adapter,FLASH_CONFIG_REG, &FlashConfig, 4); - rdmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4); + rdmalt(Adapter, FLASH_CONFIG_REG, &FlashConfig, 4); + rdmalt(Adapter, FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4); { switch(ChipNum) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 5e78c77d5a0..0d18d80bcd2 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1479,10 +1479,10 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) dev_file_info = comedi_get_device_file_info(minor); if (dev_file_info == NULL) - return -ENODEV; + return -ENODEV; dev = dev_file_info->device; if (dev == NULL) - return -ENODEV; + return -ENODEV; mutex_lock(&dev->mutex); if (!dev->attached) { @@ -1556,10 +1556,10 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) dev_file_info = comedi_get_device_file_info(minor); if (dev_file_info == NULL) - return -ENODEV; + return -ENODEV; dev = dev_file_info->device; if (dev == NULL) - return -ENODEV; + return -ENODEV; mutex_lock(&dev->mutex); if (!dev->attached) { @@ -1610,10 +1610,10 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, dev_file_info = comedi_get_device_file_info(minor); if (dev_file_info == NULL) - return -ENODEV; + return -ENODEV; dev = dev_file_info->device; if (dev == NULL) - return -ENODEV; + return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); @@ -1721,10 +1721,10 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, dev_file_info = comedi_get_device_file_info(minor); if (dev_file_info == NULL) - return -ENODEV; + return -ENODEV; dev = dev_file_info->device; if (dev == NULL) - return -ENODEV; + return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); @@ -1931,10 +1931,10 @@ static int comedi_close(struct inode *inode, struct file *file) dev_file_info = comedi_get_device_file_info(minor); if (dev_file_info == NULL) - return -ENODEV; + return -ENODEV; dev = dev_file_info->device; if (dev == NULL) - return -ENODEV; + return -ENODEV; mutex_lock(&dev->mutex); @@ -1973,10 +1973,10 @@ static int comedi_fasync(int fd, struct file *file, int on) dev_file_info = comedi_get_device_file_info(minor); if (dev_file_info == NULL) - return -ENODEV; + return -ENODEV; dev = dev_file_info->device; if (dev == NULL) - return -ENODEV; + return -ENODEV; return fasync_helper(fd, file, on, &dev->async_queue); } @@ -2479,18 +2479,18 @@ static ssize_t store_max_read_buffer_kb(struct device *dev, const char *buf, size_t count) { struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_max_size_kb; - uint64_t new_max_size; + unsigned int new_max_size_kb; + unsigned int new_max_size; + int ret; struct comedi_subdevice *const read_subdevice = comedi_get_read_subdevice(info); - if (strict_strtoul(buf, 10, &new_max_size_kb)) - return -EINVAL; - if (new_max_size_kb != (uint32_t) new_max_size_kb) - return -EINVAL; - new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; - if (new_max_size != (uint32_t) new_max_size) + ret = kstrtouint(buf, 10, &new_max_size_kb); + if (ret) + return ret; + if (new_max_size_kb > (UINT_MAX / bytes_per_kibi)) return -EINVAL; + new_max_size = new_max_size_kb * bytes_per_kibi; mutex_lock(&info->device->mutex); if (read_subdevice == NULL || @@ -2540,19 +2540,19 @@ static ssize_t store_read_buffer_kb(struct device *dev, const char *buf, size_t count) { struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_size_kb; - uint64_t new_size; + unsigned int new_size_kb; + unsigned int new_size; int retval; + int ret; struct comedi_subdevice *const read_subdevice = comedi_get_read_subdevice(info); - if (strict_strtoul(buf, 10, &new_size_kb)) - return -EINVAL; - if (new_size_kb != (uint32_t) new_size_kb) - return -EINVAL; - new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; - if (new_size != (uint32_t) new_size) + ret = kstrtouint(buf, 10, &new_size_kb); + if (ret) + return ret; + if (new_size_kb > (UINT_MAX / bytes_per_kibi)) return -EINVAL; + new_size = new_size_kb * bytes_per_kibi; mutex_lock(&info->device->mutex); if (read_subdevice == NULL || @@ -2606,18 +2606,18 @@ static ssize_t store_max_write_buffer_kb(struct device *dev, const char *buf, size_t count) { struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_max_size_kb; - uint64_t new_max_size; + unsigned int new_max_size_kb; + unsigned int new_max_size; + int ret; struct comedi_subdevice *const write_subdevice = comedi_get_write_subdevice(info); - if (strict_strtoul(buf, 10, &new_max_size_kb)) - return -EINVAL; - if (new_max_size_kb != (uint32_t) new_max_size_kb) - return -EINVAL; - new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; - if (new_max_size != (uint32_t) new_max_size) + ret = kstrtouint(buf, 10, &new_max_size_kb); + if (ret) + return ret; + if (new_max_size_kb > (UINT_MAX / bytes_per_kibi)) return -EINVAL; + new_max_size = new_max_size_kb * bytes_per_kibi; mutex_lock(&info->device->mutex); if (write_subdevice == NULL || @@ -2667,19 +2667,19 @@ static ssize_t store_write_buffer_kb(struct device *dev, const char *buf, size_t count) { struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_size_kb; - uint64_t new_size; + unsigned int new_size_kb; + unsigned int new_size; int retval; + int ret; struct comedi_subdevice *const write_subdevice = comedi_get_write_subdevice(info); - if (strict_strtoul(buf, 10, &new_size_kb)) - return -EINVAL; - if (new_size_kb != (uint32_t) new_size_kb) + ret = kstrtouint(buf, 10, &new_size_kb); + if (ret) + return ret; + if (new_size_kb > (UINT_MAX / bytes_per_kibi)) return -EINVAL; new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; - if (new_size != (uint32_t) new_size) - return -EINVAL; mutex_lock(&info->device->mutex); if (write_subdevice == NULL || diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 6fb7594319c..ca5bd9b8704 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -145,78 +145,77 @@ void fpu_end(void) static DEFINE_PCI_DEVICE_TABLE(addi_apci_tbl) = { #ifdef CONFIG_APCI_3120 - {APCI3120_BOARD_VENDOR_ID, 0x818D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI3120_BOARD_VENDOR_ID, 0x818D)}, #endif #ifdef CONFIG_APCI_1032 - {APCI1032_BOARD_VENDOR_ID, 0x1003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI1032_BOARD_VENDOR_ID, 0x1003)}, #endif #ifdef CONFIG_APCI_1516 - {APCI1516_BOARD_VENDOR_ID, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI1516_BOARD_VENDOR_ID, 0x1001)}, #endif #ifdef CONFIG_APCI_2016 - {APCI2016_BOARD_VENDOR_ID, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI2016_BOARD_VENDOR_ID, 0x1002)}, #endif #ifdef CONFIG_APCI_2032 - {APCI2032_BOARD_VENDOR_ID, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI2032_BOARD_VENDOR_ID, 0x1004)}, #endif #ifdef CONFIG_APCI_2200 - {APCI2200_BOARD_VENDOR_ID, 0x1005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI2200_BOARD_VENDOR_ID, 0x1005)}, #endif #ifdef CONFIG_APCI_1564 - {APCI1564_BOARD_VENDOR_ID, 0x1006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI1564_BOARD_VENDOR_ID, 0x1006)}, #endif #ifdef CONFIG_APCI_1500 - {APCI1500_BOARD_VENDOR_ID, 0x80fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI1500_BOARD_VENDOR_ID, 0x80fc)}, #endif #ifdef CONFIG_APCI_3001 - {APCI3120_BOARD_VENDOR_ID, 0x828D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI3120_BOARD_VENDOR_ID, 0x828D)}, #endif #ifdef CONFIG_APCI_3501 - {APCI3501_BOARD_VENDOR_ID, 0x3001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI3501_BOARD_VENDOR_ID, 0x3001)}, #endif #ifdef CONFIG_APCI_035 - {APCI035_BOARD_VENDOR_ID, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI035_BOARD_VENDOR_ID, 0x0300)}, #endif #ifdef CONFIG_APCI_3200 - {APCI3200_BOARD_VENDOR_ID, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI3200_BOARD_VENDOR_ID, 0x3000)}, #endif #ifdef CONFIG_APCI_3300 - {APCI3200_BOARD_VENDOR_ID, 0x3007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI3200_BOARD_VENDOR_ID, 0x3007)}, #endif #ifdef CONFIG_APCI_1710 - {APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID)}, #endif #ifdef CONFIG_APCI_16XX - {0x15B8, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x100A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1009)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x100A)}, #endif #ifdef CONFIG_APCI_3XXX - {0x15B8, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x300F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x300E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x300B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3010)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x300F)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x300E)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3013)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3014)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3015)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3016)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3017)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3018)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3019)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301A)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301B)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301C)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301D)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301E)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301F)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3020)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3021)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3022)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3023)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x300B)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3002)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3003)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3004)}, + {PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3024)}, #endif {0} }; @@ -1019,7 +1018,7 @@ static const struct addi_board boardtypes[] = { #endif #ifdef CONFIG_APCI_16XX {"apci1648", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x1009, 128, 0, @@ -1075,7 +1074,7 @@ static const struct addi_board boardtypes[] = { i_APCI16XX_InsnBitsWriteTTLIO}, {"apci1696", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x100A, 128, 0, @@ -1132,7 +1131,7 @@ static const struct addi_board boardtypes[] = { #endif #ifdef CONFIG_APCI_3XXX {"apci3000-16", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3010, 256, 256, @@ -1188,7 +1187,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3000-8", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x300F, 256, 256, @@ -1244,7 +1243,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3000-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x300E, 256, 256, @@ -1300,7 +1299,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3006-16", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3013, 256, 256, @@ -1356,7 +1355,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3006-8", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3014, 256, 256, @@ -1412,7 +1411,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3006-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3015, 256, 256, @@ -1468,7 +1467,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3010-16", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3016, 256, 256, @@ -1524,7 +1523,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3010-8", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3017, 256, 256, @@ -1580,7 +1579,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3010-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3018, 256, 256, @@ -1636,7 +1635,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3016-16", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3019, 256, 256, @@ -1692,7 +1691,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3016-8", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x301A, 256, 256, @@ -1748,7 +1747,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3016-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x301B, 256, 256, @@ -1804,7 +1803,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3100-16-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x301C, 256, 256, @@ -1860,7 +1859,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3100-8-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x301D, 256, 256, @@ -1916,7 +1915,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3106-16-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x301E, 256, 256, @@ -1972,7 +1971,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3106-8-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x301F, 256, 256, @@ -2028,7 +2027,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3110-16-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3020, 256, 256, @@ -2084,7 +2083,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3110-8-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3021, 256, 256, @@ -2140,7 +2139,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3116-16-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3022, 256, 256, @@ -2196,7 +2195,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3116-8-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3023, 256, 256, @@ -2252,7 +2251,7 @@ static const struct addi_board boardtypes[] = { i_APCI3XXX_InsnWriteTTLIO}, {"apci3003", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x300B, 256, 256, @@ -2307,7 +2306,7 @@ static const struct addi_board boardtypes[] = { NULL}, {"apci3002-16", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3002, 256, 256, @@ -2362,7 +2361,7 @@ static const struct addi_board boardtypes[] = { NULL}, {"apci3002-8", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3003, 256, 256, @@ -2417,7 +2416,7 @@ static const struct addi_board boardtypes[] = { NULL}, {"apci3002-4", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3004, 256, 256, @@ -2472,7 +2471,7 @@ static const struct addi_board boardtypes[] = { NULL}, {"apci3500", - 0x15B8, + PCI_VENDOR_ID_ADDIDATA, 0x3024, 256, 256, diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c index 72a7258b5b9..20d570554fa 100644 --- a/drivers/staging/comedi/drivers/adl_pci7230.c +++ b/drivers/staging/comedi/drivers/adl_pci7230.c @@ -44,15 +44,7 @@ Configuration Options: #define PCI_DEVICE_ID_PCI7230 0x7230 static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, - PCI_DEVICE_ID_PCI7230, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - 0 - }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) }, {0} }; diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c index f28fe6bec05..9a2320537bd 100644 --- a/drivers/staging/comedi/drivers/adl_pci7296.c +++ b/drivers/staging/comedi/drivers/adl_pci7296.c @@ -49,10 +49,8 @@ Configuration Options: #define PCI_DEVICE_ID_PCI7296 0x7296 static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) }, + {0} }; MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table); diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c index 262da7b29b2..86ee2197604 100644 --- a/drivers/staging/comedi/drivers/adl_pci7432.c +++ b/drivers/staging/comedi/drivers/adl_pci7432.c @@ -44,10 +44,8 @@ Configuration Options: #define PCI_DEVICE_ID_PCI7432 0x7432 static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) }, + {0} }; MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table); diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index 767a594935c..3b83d65bc1b 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -57,10 +57,8 @@ Configuration Options: #define PCI_DEVICE_ID_PCI8164 0x8164 static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) }, + {0} }; MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table); diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index fc48bae42ab..2a9bd88a4ab 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -311,10 +311,8 @@ static const struct comedi_lrange pci9111_hr_ai_range = { }; static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { - { PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 }, - /* { PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, - * 0, 0, 0 }, */ + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, + /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ { 0 } }; diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index da2b75b15d4..8318c82a555 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -1382,16 +1382,14 @@ static int pci1710_attach(struct comedi_device *dev, int i; int board_index; - printk("comedi%d: adv_pci1710: ", dev->minor); + dev_info(dev->hw_dev, "comedi%d: adv_pci1710:\n", dev->minor); opt_bus = it->options[0]; opt_slot = it->options[1]; ret = alloc_private(dev, sizeof(struct pci1710_private)); - if (ret < 0) { - printk(" - Allocation failed!\n"); + if (ret < 0) return -ENOMEM; - } /* Look for matching PCI device */ errstr = "not found!"; @@ -1436,10 +1434,10 @@ static int pci1710_attach(struct comedi_device *dev, if (!pcidev) { if (opt_bus || opt_slot) { - printk(" - Card at b:s %d:%d %s\n", - opt_bus, opt_slot, errstr); + dev_err(dev->hw_dev, "- Card at b:s %d:%d %s\n", + opt_bus, opt_slot, errstr); } else { - printk(" - Card %s\n", errstr); + dev_err(dev->hw_dev, "- Card %s\n", errstr); } return -EIO; } @@ -1450,8 +1448,8 @@ static int pci1710_attach(struct comedi_device *dev, irq = pcidev->irq; iobase = pci_resource_start(pcidev, 2); - printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func, - iobase); + dev_dbg(dev->hw_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n", pci_bus, pci_slot, + pci_func, iobase); dev->iobase = iobase; @@ -1471,10 +1469,8 @@ static int pci1710_attach(struct comedi_device *dev, n_subdevices++; ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) { - printk(" - Allocation failed!\n"); + if (ret < 0) return ret; - } pci1710_reset(dev); @@ -1483,24 +1479,20 @@ static int pci1710_attach(struct comedi_device *dev, if (request_irq(irq, interrupt_service_pci1710, IRQF_SHARED, "Advantech PCI-1710", dev)) { - printk - (", unable to allocate IRQ %d, DISABLING IT", - irq); + dev_dbg(dev->hw_dev, "unable to allocate IRQ %d, DISABLING IT", + irq); irq = 0; /* Can't use IRQ */ } else { - printk(", irq=%u", irq); + dev_dbg(dev->hw_dev, "irq=%u", irq); } } else { - printk(", IRQ disabled"); + dev_dbg(dev->hw_dev, "IRQ disabled"); } } else { irq = 0; } dev->irq = irq; - - printk(".\n"); - subdev = 0; if (this_board->n_aichan) { diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index 69334f6f64e..537e5853427 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -1106,13 +1106,10 @@ static int pci_dio_attach(struct comedi_device *dev, unsigned long iobase; struct pci_dev *pcidev = NULL; - printk("comedi%d: adv_pci_dio: ", dev->minor); ret = alloc_private(dev, sizeof(struct pci_dio_private)); - if (ret < 0) { - printk(", Error: Cann't allocate private memory!\n"); + if (ret < 0) return -ENOMEM; - } for_each_pci_dev(pcidev) { /* loop through cards supported by this driver */ @@ -1140,19 +1137,18 @@ static int pci_dio_attach(struct comedi_device *dev, } if (!dev->board_ptr) { - printk(", Error: Requested type of the card was not found!\n"); + dev_err(dev->hw_dev, "Error: Requested type of the card was not found!\n"); return -EIO; } if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) { - printk - (", Error: Can't enable PCI device and request regions!\n"); + dev_err(dev->hw_dev, "Error: Can't enable PCI device and request regions!\n"); return -EIO; } iobase = pci_resource_start(pcidev, this_board->main_pci_region); - printk(", b:s:f=%d:%d:%d, io=0x%4lx", - pcidev->bus->number, PCI_SLOT(pcidev->devfn), - PCI_FUNC(pcidev->devfn), iobase); + dev_dbg(dev->hw_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n", + pcidev->bus->number, PCI_SLOT(pcidev->devfn), + PCI_FUNC(pcidev->devfn), iobase); dev->iobase = iobase; dev->board_name = this_board->name; @@ -1177,15 +1173,10 @@ static int pci_dio_attach(struct comedi_device *dev, } ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) { - printk(", Error: Cann't allocate subdevice memory!\n"); + if (ret < 0) return ret; - } - - printk(".\n"); subdev = 0; - for (i = 0; i < MAX_DI_SUBDEVS; i++) if (this_board->sdi[i].chans) { s = dev->subdevices + subdev; diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 93bbe4ec318..566cc441145 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -421,12 +421,9 @@ static const struct dio200_layout_struct dio200_layouts[] = { #ifdef CONFIG_COMEDI_PCI static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = { - { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) }, + {0} }; MODULE_DEVICE_TABLE(pci, dio200_pci_table); diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 48246cd50d4..7972cadd403 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -134,10 +134,8 @@ static const struct pc236_board pc236_boards[] = { #ifdef CONFIG_COMEDI_PCI static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = { - { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) }, + {0} }; MODULE_DEVICE_TABLE(pci, pc236_pci_table); diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 8a338807909..191ac0d23ce 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -101,10 +101,8 @@ static const struct pc263_board pc263_boards[] = { #ifdef CONFIG_COMEDI_PCI static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = { - { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) }, + {0} }; MODULE_DEVICE_TABLE(pci, pc263_pci_table); diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 1b5ba1c2725..b278917cec2 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -384,12 +384,9 @@ static const struct pci224_board pci224_boards[] = { */ static DEFINE_PCI_DEVICE_TABLE(pci224_pci_table) = { - { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) }, + {0} }; MODULE_DEVICE_TABLE(pci, pci224_pci_table); diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 7edeb1103dc..538979551c8 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -501,12 +501,9 @@ static const struct pci230_board pci230_boards[] = { }; static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = { - { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) }, + {0} }; MODULE_DEVICE_TABLE(pci, pci230_pci_table); diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index e171c56112d..49404f49f7b 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -99,7 +99,7 @@ static struct comedi_driver driver_das16cs = { .detach = das16cs_detach, }; -static struct pcmcia_device *cur_dev = NULL; +static struct pcmcia_device *cur_dev; static const struct comedi_lrange das16cs_ai_range = { 4, { RANGE(-10, 10), @@ -150,7 +150,7 @@ static const struct das16cs_board *das16cs_probe(struct comedi_device *dev, return das16cs_boards + i; } - printk("unknown board!\n"); + dev_dbg(dev->hw_dev, "unknown board!\n"); return NULL; } @@ -163,20 +163,19 @@ static int das16cs_attach(struct comedi_device *dev, int ret; int i; - printk("comedi%d: cb_das16_cs: ", dev->minor); + dev_dbg(dev->hw_dev, "comedi%d: cb_das16_cs: attached\n", dev->minor); link = cur_dev; /* XXX hack */ if (!link) return -EIO; dev->iobase = link->resource[0]->start; - printk("I/O base=0x%04lx ", dev->iobase); + dev_dbg(dev->hw_dev, "I/O base=0x%04lx\n", dev->iobase); - printk("fingerprint:\n"); + dev_dbg(dev->hw_dev, "fingerprint:\n"); for (i = 0; i < 48; i += 2) - printk("%04x ", inw(dev->iobase + i)); + dev_dbg(dev->hw_dev, "%04x\n", inw(dev->iobase + i)); - printk("\n"); ret = request_irq(link->irq, das16cs_interrupt, IRQF_SHARED, "cb_das16_cs", dev); @@ -185,7 +184,7 @@ static int das16cs_attach(struct comedi_device *dev, dev->irq = link->irq; - printk("irq=%u ", dev->irq); + dev_dbg(dev->hw_dev, "irq=%u\n", dev->irq); dev->board_ptr = das16cs_probe(dev, link); if (!dev->board_ptr) @@ -252,14 +251,13 @@ static int das16cs_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - printk("attached\n"); return 1; } static int das16cs_detach(struct comedi_device *dev) { - printk("comedi%d: das16cs: remove\n", dev->minor); + dev_dbg(dev->hw_dev, "comedi%d: das16cs: remove\n", dev->minor); if (dev->irq) free_irq(dev->irq, dev); @@ -312,7 +310,7 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, break; } if (to == TIMEOUT) { - printk("cb_das16_cs: ai timeout\n"); + dev_dbg(dev->hw_dev, "cb_das16_cs: ai timeout\n"); return -ETIME; } data[i] = (unsigned short)inw(dev->iobase + 0); diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 61968a505f2..7e4ffcfdac6 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -565,8 +565,6 @@ static int cb_pcidas_attach(struct comedi_device *dev, int index; int i; - printk("comedi%d: cb_pcidas: ", dev->minor); - /* * Allocate the private structure area. */ @@ -576,7 +574,6 @@ static int cb_pcidas_attach(struct comedi_device *dev, /* * Probe the device to determine what device in the series it is. */ - printk("\n"); for_each_pci_dev(pcidev) { /* is it not a computer boards card? */ @@ -600,20 +597,20 @@ static int cb_pcidas_attach(struct comedi_device *dev, } } - printk("No supported ComputerBoards/MeasurementComputing card found on " - "requested position\n"); + dev_err(dev->hw_dev, "No supported ComputerBoards/MeasurementComputing card found on requested position\n"); return -EIO; found: - printk("Found %s on bus %i, slot %i\n", cb_pcidas_boards[index].name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); + dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", + cb_pcidas_boards[index].name, pcidev->bus->number, + PCI_SLOT(pcidev->devfn)); /* * Enable PCI device and reserve I/O ports. */ if (comedi_pci_enable(pcidev, "cb_pcidas")) { - printk(" Failed to enable PCI device and request regions\n"); + dev_err(dev->hw_dev, "Failed to enable PCI device and request regions\n"); return -EIO; } /* @@ -639,7 +636,8 @@ found: /* get irq */ if (request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt, IRQF_SHARED, "cb_pcidas", dev)) { - printk(" unable to allocate irq %d\n", devpriv->pci_dev->irq); + dev_dbg(dev->hw_dev, "unable to allocate irq %d\n", + devpriv->pci_dev->irq); return -EINVAL; } dev->irq = devpriv->pci_dev->irq; @@ -768,7 +766,6 @@ found: */ static int cb_pcidas_detach(struct comedi_device *dev) { - printk("comedi%d: cb_pcidas: remove\n", dev->minor); if (devpriv) { if (devpriv->s5933_config) { @@ -776,8 +773,8 @@ static int cb_pcidas_detach(struct comedi_device *dev) outl(INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); #ifdef CB_PCIDAS_DEBUG - printk("detaching, incsr is 0x%x\n", - inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR)); + dev_dbg(dev->hw_dev, "detaching, incsr is 0x%x\n", + inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR)); #endif } } @@ -858,7 +855,8 @@ static int ai_config_calibration_source(struct comedi_device *dev, unsigned int source = data[1]; if (source >= num_calibration_sources) { - printk("invalid calibration source: %i\n", source); + dev_err(dev->hw_dev, "invalid calibration source: %i\n", + source); return -EINVAL; } @@ -1279,7 +1277,7 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, outw(bits, devpriv->control_status + ADCMUX_CONT); #ifdef CB_PCIDAS_DEBUG - printk("comedi: sent 0x%x to adcmux control\n", bits); + dev_dbg(dev->hw_dev, "comedi: sent 0x%x to adcmux control\n", bits); #endif /* load counters */ @@ -1306,7 +1304,8 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, devpriv->adc_fifo_bits |= INT_FHF; /* interrupt fifo half full */ } #ifdef CB_PCIDAS_DEBUG - printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); + dev_dbg(dev->hw_dev, "comedi: adc_fifo_bits are 0x%x\n", + devpriv->adc_fifo_bits); #endif /* enable (and clear) interrupts */ outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL, @@ -1332,7 +1331,7 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, bits |= BURSTE; outw(bits, devpriv->control_status + TRIG_CONTSTAT); #ifdef CB_PCIDAS_DEBUG - printk("comedi: sent 0x%x to trig control\n", bits); + dev_dbg(dev->hw_dev, "comedi: sent 0x%x to trig control\n", bits); #endif return 0; @@ -1549,7 +1548,8 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, spin_lock_irqsave(&dev->spinlock, flags); devpriv->adc_fifo_bits |= DAEMIE | DAHFIE; #ifdef CB_PCIDAS_DEBUG - printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); + dev_dbg(dev->hw_dev, "comedi: adc_fifo_bits are 0x%x\n", + devpriv->adc_fifo_bits); #endif /* enable and clear interrupts */ outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, @@ -1559,7 +1559,8 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY; outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); #ifdef CB_PCIDAS_DEBUG - printk("comedi: sent 0x%x to dac control\n", devpriv->ao_control_bits); + dev_dbg(dev->hw_dev, "comedi: sent 0x%x to dac control\n", + devpriv->ao_control_bits); #endif spin_unlock_irqrestore(&dev->spinlock, flags); @@ -1587,8 +1588,9 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); #ifdef CB_PCIDAS_DEBUG - printk("intcsr 0x%x\n", s5933_status); - printk("mbef 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_MBEF)); + dev_dbg(dev->hw_dev, "intcsr 0x%x\n", s5933_status); + dev_dbg(dev->hw_dev, "mbef 0x%x\n", + inl(devpriv->s5933_config + AMCC_OP_REG_MBEF)); #endif if ((INTCSR_INTR_ASSERTED & s5933_status) == 0) diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 1e324198996..c9e8c478576 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1739,8 +1739,6 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) uint32_t local_range, local_decode; int retval; - printk("comedi%d: cb_pcidas64\n", dev->minor); - /* * Allocate the private structure area. */ @@ -1781,12 +1779,11 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) return -EIO; } - printk("Found %s on bus %i, slot %i\n", board(dev)->name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); + dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", board(dev)->name, + pcidev->bus->number, PCI_SLOT(pcidev->devfn)); if (comedi_pci_enable(pcidev, driver_cb_pcidas.driver_name)) { - printk(KERN_WARNING - " failed to enable PCI device and request regions\n"); + dev_warn(dev->hw_dev, "failed to enable PCI device and request regions\n"); return -EIO; } pci_set_master(pcidev); @@ -1814,7 +1811,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!priv(dev)->plx9080_iobase || !priv(dev)->main_iobase || !priv(dev)->dio_counter_iobase) { - printk(" failed to remap io memory\n"); + dev_warn(dev->hw_dev, "failed to remap io memory\n"); return -ENOMEM; } @@ -1850,17 +1847,19 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) priv(dev)->hw_revision = hw_revision(dev, readw(priv(dev)->main_iobase + HW_STATUS_REG)); - printk(" stc hardware revision %i\n", priv(dev)->hw_revision); + dev_dbg(dev->hw_dev, "stc hardware revision %i\n", + priv(dev)->hw_revision); init_plx9080(dev); init_stc_registers(dev); /* get irq */ if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, "cb_pcidas64", dev)) { - printk(" unable to allocate irq %u\n", pcidev->irq); + dev_dbg(dev->hw_dev, "unable to allocate irq %u\n", + pcidev->irq); return -EINVAL; } dev->irq = pcidev->irq; - printk(" irq %u\n", dev->irq); + dev_dbg(dev->hw_dev, "irq %u\n", dev->irq); retval = setup_subdevices(dev); if (retval < 0) @@ -1882,8 +1881,6 @@ static int detach(struct comedi_device *dev) { unsigned int i; - printk("comedi%d: cb_pcidas: remove\n", dev->minor); - if (dev->irq) free_irq(dev->irq, dev); if (priv(dev)) { @@ -2093,7 +2090,8 @@ static int ai_config_calibration_source(struct comedi_device *dev, else num_calibration_sources = 8; if (source >= num_calibration_sources) { - printk("invalid calibration source: %i\n", source); + dev_dbg(dev->hw_dev, "invalid calibration source: %i\n", + source); return -EINVAL; } @@ -2924,7 +2922,7 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev) } if (num_samples < 0) { - printk(" cb_pcidas64: bug! num_samples < 0\n"); + dev_err(dev->hw_dev, "cb_pcidas64: bug! num_samples < 0\n"); break; } diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 49102b3a6c4..abba220a767 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -282,7 +282,6 @@ static int cb_pcidda_attach(struct comedi_device *dev, struct pci_dev *pcidev = NULL; int index; - printk("comedi%d: cb_pcidda: ", dev->minor); /* * Allocate the private structure area. @@ -293,7 +292,6 @@ static int cb_pcidda_attach(struct comedi_device *dev, /* * Probe the device to determine what device in the series it is. */ - printk("\n"); for_each_pci_dev(pcidev) { if (pcidev->vendor == PCI_VENDOR_ID_CB) { @@ -312,22 +310,21 @@ static int cb_pcidda_attach(struct comedi_device *dev, } } if (!pcidev) { - printk - ("Not a ComputerBoards/MeasurementComputing card on requested position\n"); + dev_err(dev->hw_dev, "Not a ComputerBoards/MeasurementComputing card on requested position\n"); return -EIO; } found: devpriv->pci_dev = pcidev; dev->board_ptr = cb_pcidda_boards + index; /* "thisboard" macro can be used from here. */ - printk("Found %s at requested position\n", thisboard->name); + dev_dbg(dev->hw_dev, "Found %s at requested position\n", + thisboard->name); /* * Enable PCI device and request regions. */ if (comedi_pci_enable(pcidev, thisboard->name)) { - printk - ("cb_pcidda: failed to enable PCI device and request regions\n"); + dev_err(dev->hw_dev, "cb_pcidda: failed to enable PCI device and request regions\n"); return -EIO; } @@ -377,12 +374,11 @@ found: s = dev->subdevices + 2; subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A); - printk(" eeprom:"); + dev_dbg(dev->hw_dev, "eeprom:\n"); for (index = 0; index < EEPROM_SIZE; index++) { devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index); - printk(" %i:0x%x ", index, devpriv->eeprom_data[index]); + dev_dbg(dev->hw_dev, "%i:0x%x\n", index, devpriv->eeprom_data[index]); } - printk("\n"); /* set calibrations dacs */ for (index = 0; index < thisboard->ao_chans; index++) @@ -417,8 +413,6 @@ static int cb_pcidda_detach(struct comedi_device *dev) subdev_8255_cleanup(dev, dev->subdevices + 2); } - printk("comedi%d: cb_pcidda: remove\n", dev->minor); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c index 79477a595ef..8f3215239a1 100644 --- a/drivers/staging/comedi/drivers/cb_pcidio.c +++ b/drivers/staging/comedi/drivers/cb_pcidio.c @@ -184,8 +184,6 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) int index; int i; - printk("comedi%d: cb_pcidio: \n", dev->minor); - /* * Allocate the private structure area. alloc_private() is a * convenient macro defined in comedidev.h. @@ -223,8 +221,7 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) } } - printk("No supported ComputerBoards/MeasurementComputing card found on " - "requested position\n"); + dev_err(dev->hw_dev, "No supported ComputerBoards/MeasurementComputing card found on requested position\n"); return -EIO; found: @@ -236,14 +233,12 @@ found: dev->board_name = thisboard->name; devpriv->pci_dev = pcidev; - printk("Found %s on bus %i, slot %i\n", thisboard->name, - devpriv->pci_dev->bus->number, - PCI_SLOT(devpriv->pci_dev->devfn)); - if (comedi_pci_enable(pcidev, thisboard->name)) { - printk - ("cb_pcidio: failed to enable PCI device and request regions\n"); + dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", thisboard->name, + devpriv->pci_dev->bus->number, + PCI_SLOT(devpriv->pci_dev->devfn)); + if (comedi_pci_enable(pcidev, thisboard->name)) return -EIO; - } + devpriv->dio_reg_base = pci_resource_start(devpriv->pci_dev, @@ -259,11 +254,10 @@ found: for (i = 0; i < thisboard->n_8255; i++) { subdev_8255_init(dev, dev->subdevices + i, NULL, devpriv->dio_reg_base + i * 4); - printk(" subdev %d: base = 0x%lx\n", i, - devpriv->dio_reg_base + i * 4); + dev_dbg(dev->hw_dev, "subdev %d: base = 0x%lx\n", i, + devpriv->dio_reg_base + i * 4); } - printk("attached\n"); return 1; } @@ -277,7 +271,6 @@ found: */ static int pcidio_detach(struct comedi_device *dev) { - printk("comedi%d: cb_pcidio: remove\n", dev->minor); if (devpriv) { if (devpriv->pci_dev) { if (devpriv->dio_reg_base) diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index b1b832b65bc..8ba694263bd 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -212,8 +212,6 @@ static int cb_pcimdas_attach(struct comedi_device *dev, int index; /* int i; */ - printk("comedi%d: cb_pcimdas: ", dev->minor); - /* * Allocate the private structure area. */ @@ -223,7 +221,6 @@ static int cb_pcimdas_attach(struct comedi_device *dev, /* * Probe the device to determine what device in the series it is. */ - printk("\n"); for_each_pci_dev(pcidev) { /* is it not a computer boards card? */ @@ -248,26 +245,26 @@ static int cb_pcimdas_attach(struct comedi_device *dev, } } - printk("No supported ComputerBoards/MeasurementComputing card found on " - "requested position\n"); + dev_err(dev->hw_dev, "No supported ComputerBoards/MeasurementComputing card found on requested position\n"); return -EIO; found: - printk("Found %s on bus %i, slot %i\n", cb_pcimdas_boards[index].name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); + dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", + cb_pcimdas_boards[index].name, pcidev->bus->number, + PCI_SLOT(pcidev->devfn)); /* Warn about non-tested features */ switch (thisboard->device_id) { case 0x56: break; default: - printk("THIS CARD IS UNSUPPORTED.\n" - "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n"); + dev_dbg(dev->hw_dev, "THIS CARD IS UNSUPPORTED.\n" + "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n"); } if (comedi_pci_enable(pcidev, "cb_pcimdas")) { - printk(" Failed to enable PCI device and request regions\n"); + dev_err(dev->hw_dev, "Failed to enable PCI device and request regions\n"); return -EIO; } @@ -277,13 +274,11 @@ found: devpriv->BADR3 = pci_resource_start(devpriv->pci_dev, 3); devpriv->BADR4 = pci_resource_start(devpriv->pci_dev, 4); -#ifdef CBPCIMDAS_DEBUG - printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0); - printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1); - printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2); - printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3); - printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4); -#endif + dev_dbg(dev->hw_dev, "devpriv->BADR0 = 0x%lx\n", devpriv->BADR0); + dev_dbg(dev->hw_dev, "devpriv->BADR1 = 0x%lx\n", devpriv->BADR1); + dev_dbg(dev->hw_dev, "devpriv->BADR2 = 0x%lx\n", devpriv->BADR2); + dev_dbg(dev->hw_dev, "devpriv->BADR3 = 0x%lx\n", devpriv->BADR3); + dev_dbg(dev->hw_dev, "devpriv->BADR4 = 0x%lx\n", devpriv->BADR4); /* Dont support IRQ yet */ /* get irq */ @@ -333,8 +328,6 @@ found: else s->type = COMEDI_SUBD_UNUSED; - printk("attached\n"); - return 1; } @@ -348,16 +341,19 @@ found: */ static int cb_pcimdas_detach(struct comedi_device *dev) { -#ifdef CBPCIMDAS_DEBUG if (devpriv) { - printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0); - printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1); - printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2); - printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3); - printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4); + dev_dbg(dev->hw_dev, "devpriv->BADR0 = 0x%lx\n", + devpriv->BADR0); + dev_dbg(dev->hw_dev, "devpriv->BADR1 = 0x%lx\n", + devpriv->BADR1); + dev_dbg(dev->hw_dev, "devpriv->BADR2 = 0x%lx\n", + devpriv->BADR2); + dev_dbg(dev->hw_dev, "devpriv->BADR3 = 0x%lx\n", + devpriv->BADR3); + dev_dbg(dev->hw_dev, "devpriv->BADR4 = 0x%lx\n", + devpriv->BADR4); } -#endif - printk("comedi%d: cb_pcimdas: remove\n", dev->minor); + if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 8c981a89ab6..40bddfa2222 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -105,7 +105,8 @@ struct board_struct { int ao_bits; int dio_chans; int dio_method; - int dio_offset; /* how many bytes into the BADR are the DIO ports */ + /* how many bytes into the BADR are the DIO ports */ + int dio_offset; int regs_badrindex; /* IO Region for the control, analog output, and DIO registers */ int reg_sz; /* number of bytes of registers in io region */ @@ -144,17 +145,18 @@ static const struct board_struct boards[] = { /* Please add your PCI vendor ID to comedidev.h, and it will be forwarded * upstream. */ static DEFINE_PCI_DEVICE_TABLE(pci_table) = { - { - PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) }, + {0} }; MODULE_DEVICE_TABLE(pci, pci_table); -/* this structure is for data unique to this hardware driver. If - several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device struct. */ +/* + * this structure is for data unique to this hardware driver. If + * several hardware drivers keep similar information in this structure, + * feel free to suggest moving the variable to the struct comedi_device + * struct. + */ struct board_private_struct { unsigned long registers; /* set by probe */ unsigned long dio_registers; @@ -335,7 +337,10 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) if (thisboard->dio_chans) { switch (thisboard->dio_method) { case DIO_8255: - /* this is a straight 8255, so register us with the 8255 driver */ + /* + * this is a straight 8255, so register us with + * the 8255 driver + */ subdev_8255_init(dev, s, NULL, devpriv->dio_registers); devpriv->attached_to_8255 = 1; break; @@ -436,8 +441,11 @@ static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, for (i = 0; i < insn->n; i++) { inw(devpriv->registers + chan * 2); - /* should I set data[i] to the result of the actual read on the register - or the cached unsigned int in devpriv->ao_readback[]? */ + /* + * should I set data[i] to the result of the actual read + * on the register or the cached unsigned int in + * devpriv->ao_readback[]? + */ data[i] = devpriv->ao_readback[chan]; } diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 871f109bcfa..e3659bd6e85 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -57,10 +57,9 @@ static const struct contec_board contec_boards[] = { #define PCI_DEVICE_ID_PIO1616L 0x8172 static DEFINE_PCI_DEVICE_TABLE(contec_pci_table) = { - { - PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, PIO1616L}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L), + .driver_data = PIO1616L }, + {0} }; MODULE_DEVICE_TABLE(pci, contec_pci_table); @@ -197,8 +196,8 @@ static int contec_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - printk("contec_do_insn_bits called\n"); - printk(" data: %d %d\n", data[0], data[1]); + dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n"); + dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]); if (insn->n != 2) return -EINVAL; @@ -206,8 +205,8 @@ static int contec_do_insn_bits(struct comedi_device *dev, if (data[0]) { s->state &= ~data[0]; s->state |= data[0] & data[1]; - printk(" out: %d on %lx\n", s->state, - dev->iobase + thisboard->out_offs); + dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state, + dev->iobase + thisboard->out_offs); outw(s->state, dev->iobase + thisboard->out_offs); } return 2; @@ -218,8 +217,8 @@ static int contec_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - printk("contec_di_insn_bits called\n"); - printk(" data: %d %d\n", data[0], data[1]); + dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n"); + dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]); if (insn->n != 2) return -EINVAL; diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 82be77daa7d..e61c6a8f285 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -325,9 +325,8 @@ static const struct daq200_boardtype boardtypes[] = { #define this_board ((const struct daq200_boardtype *)dev->board_ptr) static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = { - { - 0x1616, 0x0409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(0x1616, 0x0409) }, + {0} }; MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table); @@ -430,16 +429,14 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, /* Enable reading from the scanlist FIFO */ fpga->acqControl = DAQBOARD2000_SeqStartScanList; for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull) { + if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull) break; - } /* udelay(2); */ } fpga->acqControl = DAQBOARD2000_AdcPacerEnable; for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning) { + if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning) break; - } /* udelay(2); */ } for (timeout = 0; timeout < 20; timeout++) { @@ -465,9 +462,8 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev, int i; int chan = CR_CHAN(insn->chanspec); - for (i = 0; i < insn->n; i++) { + for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; - } return i; } @@ -490,9 +486,8 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, /* fpga->dacControl = (chan + 2) * 0x0010 | 0x0001; udelay(1000); */ fpga->dacSetting[chan] = data[i]; for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0) { + if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0) break; - } /* udelay(2); */ } devpriv->ao_readback[chan] = data[i]; @@ -507,7 +502,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, static void daqboard2000_resetLocalBus(struct comedi_device *dev) { - printk("daqboard2000_resetLocalBus\n"); + dev_dbg(dev->hw_dev, "daqboard2000_resetLocalBus\n"); writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c); udelay(10000); writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c); @@ -516,7 +511,7 @@ static void daqboard2000_resetLocalBus(struct comedi_device *dev) static void daqboard2000_reloadPLX(struct comedi_device *dev) { - printk("daqboard2000_reloadPLX\n"); + dev_dbg(dev->hw_dev, "daqboard2000_reloadPLX\n"); writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); udelay(10000); writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c); @@ -527,7 +522,7 @@ static void daqboard2000_reloadPLX(struct comedi_device *dev) static void daqboard2000_pulseProgPin(struct comedi_device *dev) { - printk("daqboard2000_pulseProgPin 1\n"); + dev_dbg(dev->hw_dev, "daqboard2000_pulseProgPin 1\n"); writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c); udelay(10000); writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c); @@ -579,14 +574,14 @@ static int initialize_daqboard2000(struct comedi_device *dev, secr = readl(devpriv->plx + 0x6c); if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) { #ifdef DEBUG_EEPROM - printk("no serial eeprom\n"); + dev_dbg(dev->hw_dev, "no serial eeprom\n"); #endif return -EIO; } for (retry = 0; retry < 3; retry++) { #ifdef DEBUG_EEPROM - printk("Programming EEPROM try %x\n", retry); + dev_dbg(dev->hw_dev, "Programming EEPROM try %x\n", retry); #endif daqboard2000_resetLocalBus(dev); @@ -597,7 +592,8 @@ static int initialize_daqboard2000(struct comedi_device *dev, if (cpld_array[i] == 0xff && cpld_array[i + 1] == 0x20) { #ifdef DEBUG_EEPROM - printk("Preamble found at %d\n", i); + dev_dbg(dev->hw_dev, "Preamble found at %d\n", + i); #endif break; } @@ -605,13 +601,12 @@ static int initialize_daqboard2000(struct comedi_device *dev, for (; i < len; i += 2) { int data = (cpld_array[i] << 8) + cpld_array[i + 1]; - if (!daqboard2000_writeCPLD(dev, data)) { + if (!daqboard2000_writeCPLD(dev, data)) break; - } } if (i >= len) { #ifdef DEBUG_EEPROM - printk("Programmed\n"); + dev_dbg(dev->hw_dev, "Programmed\n"); #endif daqboard2000_resetLocalBus(dev); daqboard2000_reloadPLX(dev); @@ -658,9 +653,8 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) /* Set the + reference dac value in the FPGA */ fpga->refDacs = 0x80 | DAQBOARD2000_PosRefDacSelect; for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) { + if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) break; - } udelay(2); } /* printk("DAQBOARD2000_PosRefDacSelect %d\n", timeout);*/ @@ -668,9 +662,8 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) /* Set the - reference dac value in the FPGA */ fpga->refDacs = 0x80 | DAQBOARD2000_NegRefDacSelect; for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) { + if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) break; - } udelay(2); } /* printk("DAQBOARD2000_NegRefDacSelect %d\n", timeout);*/ @@ -737,15 +730,13 @@ static int daqboard2000_attach(struct comedi_device *dev, unsigned int aux_len; int bus, slot; - printk("comedi%d: daqboard2000:", dev->minor); - bus = it->options[0]; slot = it->options[1]; result = alloc_private(dev, sizeof(struct daqboard2000_private)); - if (result < 0) { + if (result < 0) return -ENOMEM; - } + for (card = pci_get_device(0x1616, 0x0409, NULL); card != NULL; card = pci_get_device(0x1616, 0x0409, card)) { if (bus || slot) { @@ -759,10 +750,10 @@ static int daqboard2000_attach(struct comedi_device *dev, } if (!card) { if (bus || slot) - printk(" no daqboard2000 found at bus/slot: %d/%d\n", - bus, slot); + dev_err(dev->hw_dev, "no daqboard2000 found at bus/slot: %d/%d\n", + bus, slot); else - printk(" no daqboard2000 found\n"); + dev_err(dev->hw_dev, "no daqboard2000 found\n"); return -EIO; } else { u32 id; @@ -772,7 +763,8 @@ static int daqboard2000_attach(struct comedi_device *dev, subsystem_device << 16) | card->subsystem_vendor; for (i = 0; i < n_boardtypes; i++) { if (boardtypes[i].id == id) { - printk(" %s", boardtypes[i].name); + dev_dbg(dev->hw_dev, "%s\n", + boardtypes[i].name); dev->board_ptr = boardtypes + i; } } @@ -786,7 +778,7 @@ static int daqboard2000_attach(struct comedi_device *dev, result = comedi_pci_enable(card, "daqboard2000"); if (result < 0) { - printk(" failed to enable PCI device and request regions\n"); + dev_err(dev->hw_dev, "failed to enable PCI device and request regions\n"); return -EIO; } devpriv->got_regions = 1; @@ -794,9 +786,8 @@ static int daqboard2000_attach(struct comedi_device *dev, ioremap(pci_resource_start(card, 0), DAQBOARD2000_PLX_SIZE); devpriv->daq = ioremap(pci_resource_start(card, 2), DAQBOARD2000_DAQ_SIZE); - if (!devpriv->plx || !devpriv->daq) { + if (!devpriv->plx || !devpriv->daq) return -ENOMEM; - } result = alloc_subdevices(dev, 3); if (result < 0) @@ -817,7 +808,7 @@ static int daqboard2000_attach(struct comedi_device *dev, if (aux_data && aux_len) { result = initialize_daqboard2000(dev, aux_data, aux_len); } else { - printk("no FPGA initialization code, aborting\n"); + dev_dbg(dev->hw_dev, "no FPGA initialization code, aborting\n"); result = -EIO; } if (result < 0) @@ -857,30 +848,26 @@ static int daqboard2000_attach(struct comedi_device *dev, result = subdev_8255_init(dev, s, daqboard2000_8255_cb, (unsigned long)(dev->iobase + 0x40)); - printk("\n"); out: return result; } static int daqboard2000_detach(struct comedi_device *dev) { - printk("comedi%d: daqboard2000: remove\n", dev->minor); - if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 2); - if (dev->irq) { + if (dev->irq) free_irq(dev->irq, dev); - } + if (devpriv) { if (devpriv->daq) iounmap(devpriv->daq); if (devpriv->plx) iounmap(devpriv->plx); if (devpriv->pci_dev) { - if (devpriv->got_regions) { + if (devpriv->got_regions) comedi_pci_disable(devpriv->pci_dev); - } pci_dev_put(devpriv->pci_dev); } } diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 3141dc80fe7..c2dd0ed36a7 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -506,10 +506,8 @@ struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = { #ifdef CONFIG_COMEDI_PCI static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = { - { - PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) }, + {0} }; MODULE_DEVICE_TABLE(pci, das08_pci_table); diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 6d91d302817..4ad398aad72 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -79,22 +79,20 @@ static int das08_cs_attach(struct comedi_device *dev, if (ret < 0) return ret; - printk("comedi%d: das08_cs: ", dev->minor); + dev_info(dev->hw_dev, "comedi%d: das08_cs:\n", dev->minor); /* deal with a pci board */ if (thisboard->bustype == pcmcia) { if (link == NULL) { - printk(" no pcmcia cards found\n"); + dev_err(dev->hw_dev, "no pcmcia cards found\n"); return -EIO; } iobase = link->resource[0]->start; } else { - printk(" bug! board does not have PCMCIA bustype\n"); + dev_err(dev->hw_dev, "bug! board does not have PCMCIA bustype\n"); return -EINVAL; } - printk("\n"); - return das08_common_attach(dev, iobase); } diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index a5ce3b2abe4..5376e718e3d 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -384,20 +384,20 @@ static int das16m1_cmd_exec(struct comedi_device *dev, byte = 0; /* if we are using external start trigger (also board dislikes having * both start and conversion triggers external simultaneously) */ - if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT) { + if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT) byte |= EXT_TRIG_BIT; - } + outb(byte, dev->iobase + DAS16M1_CS); /* clear interrupt bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); /* enable interrupts and internal pacer */ devpriv->control_state &= ~PACER_MASK; - if (cmd->convert_src == TRIG_TIMER) { + if (cmd->convert_src == TRIG_TIMER) devpriv->control_state |= INT_PACER; - } else { + else devpriv->control_state |= EXT_PACER; - } + devpriv->control_state |= INTE; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); @@ -531,9 +531,8 @@ static void munge_sample_array(short *array, unsigned int num_elements) { unsigned int i; - for (i = 0; i < num_elements; i++) { + for (i = 0; i < num_elements; i++) array[i] = munge_sample(array[i]); - } } static void das16m1_handler(struct comedi_device *dev, unsigned int status) @@ -668,25 +667,20 @@ static int das16m1_attach(struct comedi_device *dev, iobase = it->options[0]; - printk("comedi%d: das16m1:", dev->minor); - ret = alloc_private(dev, sizeof(struct das16m1_private_struct)); if (ret < 0) return ret; dev->board_name = thisboard->name; - printk(" io 0x%lx-0x%lx 0x%lx-0x%lx", - iobase, iobase + DAS16M1_SIZE, - iobase + DAS16M1_82C55, iobase + DAS16M1_82C55 + DAS16M1_SIZE2); if (!request_region(iobase, DAS16M1_SIZE, driver_das16m1.driver_name)) { - printk(" I/O port conflict\n"); + comedi_error(dev, "I/O port conflict\n"); return -EIO; } if (!request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2, driver_das16m1.driver_name)) { release_region(iobase, DAS16M1_SIZE); - printk(" I/O port conflict\n"); + comedi_error(dev, "I/O port conflict\n"); return -EIO; } dev->iobase = iobase; @@ -697,17 +691,17 @@ static int das16m1_attach(struct comedi_device *dev, if (das16m1_irq_bits(irq) >= 0) { ret = request_irq(irq, das16m1_interrupt, 0, driver_das16m1.driver_name, dev); - if (ret < 0) { - printk(", irq unavailable\n"); + if (ret < 0) return ret; - } dev->irq = irq; - printk(", irq %u\n", irq); + printk + ("irq %u\n", irq); } else if (irq == 0) { - printk(", no irq\n"); + printk + (", no irq\n"); } else { - printk(", invalid irq\n" - " valid irqs are 2, 3, 5, 7, 10, 11, 12, or 15\n"); + comedi_error(dev, "invalid irq\n" + " valid irqs are 2, 3, 5, 7, 10, 11, 12, or 15\n"); return -EINVAL; } @@ -771,7 +765,6 @@ static int das16m1_attach(struct comedi_device *dev, static int das16m1_detach(struct comedi_device *dev) { - printk("comedi%d: das16m1: remove\n", dev->minor); /* das16m1_reset(dev); */ diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index a6df30b7fd7..99ada5a53b9 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -573,22 +573,23 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, devpriv->dma_bits |= DMA_CH7_CH5; break; default: - printk(" only supports dma channels 5 through 7\n" - " Dual dma only allows the following combinations:\n" - " dma 5,6 / 6,7 / or 7,5\n"); + dev_err(dev->hw_dev, " only supports dma channels 5 through 7\n" + " Dual dma only allows the following combinations:\n" + " dma 5,6 / 6,7 / or 7,5\n"); return -EINVAL; break; } if (request_dma(dma0, driver_das1800.driver_name)) { - printk(" failed to allocate dma channel %i\n", dma0); + dev_err(dev->hw_dev, "failed to allocate dma channel %i\n", + dma0); return -EINVAL; } devpriv->dma0 = dma0; devpriv->dma_current = dma0; if (dma1) { if (request_dma(dma1, driver_das1800.driver_name)) { - printk(" failed to allocate dma channel %i\n", - dma1); + dev_err(dev->hw_dev, "failed to allocate dma channel %i\n", + dma1); return -EINVAL; } devpriv->dma1 = dma1; @@ -631,20 +632,20 @@ static int das1800_attach(struct comedi_device *dev, if (alloc_private(dev, sizeof(struct das1800_private)) < 0) return -ENOMEM; - printk("comedi%d: %s: io 0x%lx", dev->minor, driver_das1800.driver_name, - iobase); + printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor, + driver_das1800.driver_name, iobase); if (irq) { - printk(", irq %u", irq); + printk(KERN_CONT ", irq %u", irq); if (dma0) { - printk(", dma %u", dma0); + printk(KERN_CONT ", dma %u", dma0); if (dma1) - printk(" and %u", dma1); + printk(KERN_CONT " and %u", dma1); } } - printk("\n"); + printk(KERN_CONT "\n"); if (iobase == 0) { - printk(" io base address required\n"); + dev_err(dev->hw_dev, "io base address required\n"); return -EINVAL; } @@ -659,7 +660,7 @@ static int das1800_attach(struct comedi_device *dev, board = das1800_probe(dev); if (board < 0) { - printk(" unable to determine board type\n"); + dev_err(dev->hw_dev, "unable to determine board type\n"); return -ENODEV; } @@ -683,7 +684,8 @@ static int das1800_attach(struct comedi_device *dev, if (irq) { if (request_irq(irq, das1800_interrupt, 0, driver_das1800.driver_name, dev)) { - printk(" unable to allocate irq %u\n", irq); + dev_dbg(dev->hw_dev, "unable to allocate irq %u\n", + irq); return -EINVAL; } } @@ -712,7 +714,7 @@ static int das1800_attach(struct comedi_device *dev, devpriv->irq_dma_bits |= 0x38; break; default: - printk(" irq out of range\n"); + dev_err(dev->hw_dev, "irq out of range\n"); return -EINVAL; break; } @@ -813,8 +815,8 @@ static int das1800_detach(struct comedi_device *dev) kfree(devpriv->ai_buf1); } - printk("comedi%d: %s: remove\n", dev->minor, - driver_das1800.driver_name); + dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor, + driver_das1800.driver_name); return 0; }; @@ -833,8 +835,8 @@ static int das1800_probe(struct comedi_device *dev) case 0x3: if (board == das1801st_da || board == das1802st_da || board == das1701st_da || board == das1702st_da) { - printk(" Board model: %s\n", - das1800_boards[board].name); + dev_dbg(dev->hw_dev, "Board model: %s\n", + das1800_boards[board].name); return board; } printk @@ -843,8 +845,8 @@ static int das1800_probe(struct comedi_device *dev) break; case 0x4: if (board == das1802hr_da || board == das1702hr_da) { - printk(" Board model: %s\n", - das1800_boards[board].name); + dev_dbg(dev->hw_dev, "Board model: %s\n", + das1800_boards[board].name); return board; } printk @@ -854,8 +856,8 @@ static int das1800_probe(struct comedi_device *dev) case 0x5: if (board == das1801ao || board == das1802ao || board == das1701ao || board == das1702ao) { - printk(" Board model: %s\n", - das1800_boards[board].name); + dev_dbg(dev->hw_dev, "Board model: %s\n", + das1800_boards[board].name); return board; } printk @@ -864,18 +866,19 @@ static int das1800_probe(struct comedi_device *dev) break; case 0x6: if (board == das1802hr || board == das1702hr) { - printk(" Board model: %s\n", - das1800_boards[board].name); + dev_dbg(dev->hw_dev, "Board model: %s\n", + das1800_boards[board].name); return board; } - printk(" Board model (probed, not recommended): das-1802hr\n"); + printk + (" Board model (probed, not recommended): das-1802hr\n"); return das1802hr; break; case 0x7: if (board == das1801st || board == das1802st || board == das1701st || board == das1702st) { - printk(" Board model: %s\n", - das1800_boards[board].name); + dev_dbg(dev->hw_dev, "Board model: %s\n", + das1800_boards[board].name); return board; } printk @@ -884,8 +887,8 @@ static int das1800_probe(struct comedi_device *dev) break; case 0x8: if (board == das1801hc || board == das1802hc) { - printk(" Board model: %s\n", - das1800_boards[board].name); + dev_dbg(dev->hw_dev, "Board model: %s\n", + das1800_boards[board].name); return board; } printk diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 6328f5280b6..f25684145e8 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -171,7 +171,7 @@ static irqreturn_t intr_handler(int irq, void *d) struct comedi_subdevice *s = dev->subdevices; if (!dev->attached || devpriv->das6402_ignoreirq) { - printk("das6402: BUG: spurious interrupt\n"); + dev_warn(dev->hw_dev, "BUG: spurious interrupt\n"); return IRQ_HANDLED; } #ifdef DEBUG @@ -228,9 +228,7 @@ static int das6402_ai_cancel(struct comedi_device *dev, */ devpriv->das6402_ignoreirq = 1; -#ifdef DEBUG - printk("das6402: Stopping acquisition\n"); -#endif + dev_dbg(dev->hw_dev, "Stopping acquisition\n"); devpriv->das6402_ignoreirq = 1; outb_p(0x02, dev->iobase + 10); /* disable external trigging */ outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ @@ -246,10 +244,7 @@ static int das6402_ai_mode2(struct comedi_device *dev, struct comedi_subdevice *s, comedi_trig * it) { devpriv->das6402_ignoreirq = 1; - -#ifdef DEBUG - printk("das6402: Starting acquisition\n"); -#endif + dev_dbg(dev->hw_dev, "Starting acquisition\n"); outb_p(0x03, dev->iobase + 10); /* enable external trigging */ outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); @@ -329,10 +324,8 @@ static int das6402_attach(struct comedi_device *dev, if (iobase == 0) iobase = 0x300; - printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase); - if (!request_region(iobase, DAS6402_SIZE, "das6402")) { - printk(" I/O port conflict\n"); + dev_err(dev->hw_dev, "I/O port conflict\n"); return -EIO; } dev->iobase = iobase; @@ -340,14 +333,12 @@ static int das6402_attach(struct comedi_device *dev, /* should do a probe here */ irq = it->options[0]; - printk(" ( irq = %u )", irq); + dev_dbg(dev->hw_dev, "( irq = %u )\n", irq); ret = request_irq(irq, intr_handler, 0, "das6402", dev); - if (ret < 0) { - printk("irq conflict\n"); + if (ret < 0) return ret; - } - dev->irq = irq; + dev->irq = irq; ret = alloc_private(dev, sizeof(struct das6402_private)); if (ret < 0) return ret; diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 96d41ad7695..6e347b40fe6 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -296,47 +296,47 @@ static int das800_probe(struct comedi_device *dev) switch (id_bits) { case 0x0: if (board == das800) { - printk(" Board model: DAS-800\n"); + dev_dbg(dev->hw_dev, "Board model: DAS-800\n"); return board; } if (board == ciodas800) { - printk(" Board model: CIO-DAS800\n"); + dev_dbg(dev->hw_dev, "Board model: CIO-DAS800\n"); return board; } - printk(" Board model (probed): DAS-800\n"); + dev_dbg(dev->hw_dev, "Board model (probed): DAS-800\n"); return das800; break; case 0x2: if (board == das801) { - printk(" Board model: DAS-801\n"); + dev_dbg(dev->hw_dev, "Board model: DAS-801\n"); return board; } if (board == ciodas801) { - printk(" Board model: CIO-DAS801\n"); + dev_dbg(dev->hw_dev, "Board model: CIO-DAS801\n"); return board; } - printk(" Board model (probed): DAS-801\n"); + dev_dbg(dev->hw_dev, "Board model (probed): DAS-801\n"); return das801; break; case 0x3: if (board == das802) { - printk(" Board model: DAS-802\n"); + dev_dbg(dev->hw_dev, "Board model: DAS-802\n"); return board; } if (board == ciodas802) { - printk(" Board model: CIO-DAS802\n"); + dev_dbg(dev->hw_dev, "Board model: CIO-DAS802\n"); return board; } if (board == ciodas80216) { - printk(" Board model: CIO-DAS802/16\n"); + dev_dbg(dev->hw_dev, "Board model: CIO-DAS802/16\n"); return board; } - printk(" Board model (probed): DAS-802\n"); + dev_dbg(dev->hw_dev, "Board model (probed): DAS-802\n"); return das802; break; default: - printk(" Board model: probe returned 0x%x (unknown)\n", - id_bits); + dev_dbg(dev->hw_dev, "Board model: probe returned 0x%x (unknown)\n", + id_bits); return board; break; } @@ -466,42 +466,43 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) unsigned long irq_flags; int board; - printk("comedi%d: das800: io 0x%lx", dev->minor, iobase); + dev_info(dev->hw_dev, "comedi%d: das800: io 0x%lx\n", dev->minor, + iobase); if (irq) - printk(", irq %u", irq); - printk("\n"); + dev_dbg(dev->hw_dev, "irq %u\n", irq); /* allocate and initialize dev->private */ if (alloc_private(dev, sizeof(struct das800_private)) < 0) return -ENOMEM; if (iobase == 0) { - printk("io base address required for das800\n"); + dev_err(dev->hw_dev, "io base address required for das800\n"); return -EINVAL; } /* check if io addresses are available */ if (!request_region(iobase, DAS800_SIZE, "das800")) { - printk("I/O port conflict\n"); + dev_err(dev->hw_dev, "I/O port conflict\n"); return -EIO; } dev->iobase = iobase; board = das800_probe(dev); if (board < 0) { - printk("unable to determine board type\n"); + dev_dbg(dev->hw_dev, "unable to determine board type\n"); return -ENODEV; } dev->board_ptr = das800_boards + board; /* grab our IRQ */ if (irq == 1 || irq > 7) { - printk("irq out of range\n"); + dev_err(dev->hw_dev, "irq out of range\n"); return -EINVAL; } if (irq) { if (request_irq(irq, das800_interrupt, 0, "das800", dev)) { - printk("unable to allocate irq %u\n", irq); + dev_err(dev->hw_dev, "unable to allocate irq %u\n", + irq); return -EINVAL; } } @@ -557,7 +558,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) static int das800_detach(struct comedi_device *dev) { - printk("comedi%d: das800: remove\n", dev->minor); + dev_info(dev->hw_dev, "comedi%d: das800: remove\n", dev->minor); /* only free stuff if it has been allocated by _attach */ if (dev->iobase) diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 6170f7bac46..0a7979e5299 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -352,7 +352,8 @@ static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) return 0; - printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status); + dev_dbg(dev->hw_dev, "dt3k_send_cmd() timeout/error status=0x%04x\n", + status); return -ETIME; } @@ -383,7 +384,7 @@ static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, dt3k_send_cmd(dev, CMD_WRITESINGLE); } -static int debug_n_ints = 0; +static int debug_n_ints; /* FIXME! Assumes shared interrupt is for this card. */ /* What's this debug_n_ints stuff? Obviously needs some work... */ @@ -429,12 +430,12 @@ static char *intr_flags[] = { static void debug_intr_flags(unsigned int flags) { int i; - printk("dt3k: intr_flags:"); + printk(KERN_DEBUG "dt3k: intr_flags:"); for (i = 0; i < 8; i++) { if (flags & (1 << i)) - printk(" %s", intr_flags[i]); + printk(KERN_CONT " %s", intr_flags[i]); } - printk("\n"); + printk(KERN_CONT "\n"); } #endif @@ -452,7 +453,7 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, if (count < 0) count += AI_FIFO_DEPTH; - printk("reading %d samples\n", count); + dev_dbg(dev->hw_dev, "reading %d samples\n", count); rear = devpriv->ai_rear; @@ -640,7 +641,7 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) int ret; unsigned int mode; - printk("dt3k_ai_cmd:\n"); + dev_dbg(dev->hw_dev, "dt3k_ai_cmd:\n"); for (i = 0; i < cmd->chanlist_len; i++) { chan = CR_CHAN(cmd->chanlist[i]); range = CR_RANGE(cmd->chanlist[i]); @@ -651,15 +652,15 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) aref = CR_AREF(cmd->chanlist[0]); writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0)); - printk("param[0]=0x%04x\n", cmd->scan_end_arg); + dev_dbg(dev->hw_dev, "param[0]=0x%04x\n", cmd->scan_end_arg); if (cmd->convert_src == TRIG_TIMER) { divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); writew((divider >> 16), devpriv->io_addr + DPR_Params(1)); - printk("param[1]=0x%04x\n", divider >> 16); + dev_dbg(dev->hw_dev, "param[1]=0x%04x\n", divider >> 16); writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2)); - printk("param[2]=0x%04x\n", divider & 0xffff); + dev_dbg(dev->hw_dev, "param[2]=0x%04x\n", divider & 0xffff); } else { /* not supported */ } @@ -668,21 +669,21 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3)); - printk("param[3]=0x%04x\n", tscandiv >> 16); + dev_dbg(dev->hw_dev, "param[3]=0x%04x\n", tscandiv >> 16); writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4)); - printk("param[4]=0x%04x\n", tscandiv & 0xffff); + dev_dbg(dev->hw_dev, "param[4]=0x%04x\n", tscandiv & 0xffff); } else { /* not supported */ } mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0; writew(mode, devpriv->io_addr + DPR_Params(5)); - printk("param[5]=0x%04x\n", mode); + dev_dbg(dev->hw_dev, "param[5]=0x%04x\n", mode); writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6)); - printk("param[6]=0x%04x\n", aref == AREF_DIFF); + dev_dbg(dev->hw_dev, "param[6]=0x%04x\n", aref == AREF_DIFF); writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7)); - printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2); + dev_dbg(dev->hw_dev, "param[7]=0x%04x\n", AI_FIFO_DEPTH / 2); writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); ret = dt3k_send_cmd(dev, CMD_CONFIG); @@ -848,7 +849,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) int bus, slot; int ret = 0; - printk("dt3000:"); + dev_dbg(dev->hw_dev, "dt3000:\n"); bus = it->options[0]; slot = it->options[1]; @@ -860,7 +861,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret < 0) return ret; if (ret == 0) { - printk(" no DT board found\n"); + dev_warn(dev->hw_dev, "no DT board found\n"); return -ENODEV; } @@ -868,7 +869,8 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED, "dt3000", dev)) { - printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq); + dev_err(dev->hw_dev, "unable to allocate IRQ %u\n", + devpriv->pci_dev->irq); return -EINVAL; } dev->irq = devpriv->pci_dev->irq; diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 8d98cf41270..6a79ba10630 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -71,18 +71,12 @@ static struct comedi_driver driver_jr3_pci = { }; static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = { - { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) }, + {0} }; MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); @@ -378,14 +372,14 @@ static int jr3_pci_open(struct comedi_device *dev) int i; struct jr3_pci_dev_private *devpriv = dev->private; - printk("jr3_pci_open\n"); + dev_dbg(dev->hw_dev, "jr3_pci_open\n"); for (i = 0; i < devpriv->n_channels; i++) { struct jr3_pci_subdev_private *p; p = dev->subdevices[i].private; if (p) { - printk("serial: %p %d (%d)\n", p, p->serial_no, - p->channel_no); + dev_dbg(dev->hw_dev, "serial: %p %d (%d)\n", p, + p->serial_no, p->channel_no); } } return 0; @@ -463,8 +457,8 @@ static int jr3_download_firmware(struct comedi_device *dev, const u8 * data, break; more = more && read_idm_word(data, size, &pos, &addr); - printk("Loading#%d %4.4x bytes at %4.4x\n", i, - count, addr); + dev_dbg(dev->hw_dev, "Loading#%d %4.4x bytes at %4.4x\n", + i, count, addr); while (more && count > 0) { if (addr & 0x4000) { /* 16 bit data, never seen in real life!! */ @@ -599,24 +593,24 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s) min_full_scale = get_min_full_scales(channel); printk("Obtained Min. Full Scales:\n"); - printk("%i ", (min_full_scale).fx); - printk("%i ", (min_full_scale).fy); - printk("%i ", (min_full_scale).fz); - printk("%i ", (min_full_scale).mx); - printk("%i ", (min_full_scale).my); - printk("%i ", (min_full_scale).mz); - printk("\n"); + printk(KERN_DEBUG "%i ", (min_full_scale).fx); + printk(KERN_CONT "%i ", (min_full_scale).fy); + printk(KERN_CONT "%i ", (min_full_scale).fz); + printk(KERN_CONT "%i ", (min_full_scale).mx); + printk(KERN_CONT "%i ", (min_full_scale).my); + printk(KERN_CONT "%i ", (min_full_scale).mz); + printk(KERN_CONT "\n"); max_full_scale = get_max_full_scales(channel); printk("Obtained Max. Full Scales:\n"); - printk("%i ", (max_full_scale).fx); - printk("%i ", (max_full_scale).fy); - printk("%i ", (max_full_scale).fz); - printk("%i ", (max_full_scale).mx); - printk("%i ", (max_full_scale).my); - printk("%i ", (max_full_scale).mz); - printk("\n"); + printk(KERN_DEBUG "%i ", (max_full_scale).fx); + printk(KERN_CONT "%i ", (max_full_scale).fy); + printk(KERN_CONT "%i ", (max_full_scale).fz); + printk(KERN_CONT "%i ", (max_full_scale).mx); + printk(KERN_CONT "%i ", (max_full_scale).my); + printk(KERN_CONT "%i ", (max_full_scale).mz); + printk(KERN_CONT "\n"); set_full_scales(channel, max_full_scale); @@ -779,14 +773,12 @@ static int jr3_pci_attach(struct comedi_device *dev, int opt_bus, opt_slot, i; struct jr3_pci_dev_private *devpriv; - printk("comedi%d: jr3_pci\n", dev->minor); - opt_bus = it->options[0]; opt_slot = it->options[1]; if (sizeof(struct jr3_channel) != 0xc00) { - printk("sizeof(struct jr3_channel) = %x [expected %x]\n", - (unsigned)sizeof(struct jr3_channel), 0xc00); + dev_err(dev->hw_dev, "sizeof(struct jr3_channel) = %x [expected %x]\n", + (unsigned)sizeof(struct jr3_channel), 0xc00); return -EINVAL; } @@ -840,7 +832,7 @@ static int jr3_pci_attach(struct comedi_device *dev, } } if (!card) { - printk(" no jr3_pci found\n"); + dev_err(dev->hw_dev, "no jr3_pci found\n"); return -EIO; } else { devpriv->pci_dev = card; @@ -875,10 +867,10 @@ static int jr3_pci_attach(struct comedi_device *dev, p = dev->subdevices[i].private; p->channel = &devpriv->iobase->channel[i].data; - printk("p->channel %p %p (%tx)\n", - p->channel, devpriv->iobase, - ((char *)(p->channel) - - (char *)(devpriv->iobase))); + dev_dbg(dev->hw_dev, "p->channel %p %p (%tx)\n", + p->channel, devpriv->iobase, + ((char *)(p->channel) - + (char *)(devpriv->iobase))); p->channel_no = i; for (j = 0; j < 8; j++) { int k; @@ -916,7 +908,7 @@ static int jr3_pci_attach(struct comedi_device *dev, devpriv->iobase->channel[0].reset = 0; result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware); - printk("Firmare load %d\n", result); + dev_dbg(dev->hw_dev, "Firmare load %d\n", result); if (result < 0) goto out; @@ -934,9 +926,9 @@ static int jr3_pci_attach(struct comedi_device *dev, */ msleep_interruptible(25); for (i = 0; i < 0x18; i++) { - printk("%c", - get_u16(&devpriv->iobase->channel[0]. - data.copyright[i]) >> 8); + dev_dbg(dev->hw_dev, "%c\n", + get_u16(&devpriv->iobase->channel[0]. + data.copyright[i]) >> 8); } /* Start card timer */ @@ -963,7 +955,6 @@ static int jr3_pci_detach(struct comedi_device *dev) int i; struct jr3_pci_dev_private *devpriv = dev->private; - printk("comedi%d: jr3_pci: remove\n", dev->minor); if (devpriv) { del_timer_sync(&devpriv->timer); diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 286093bca3f..4e9e9a07865 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -52,10 +52,8 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it); static int cnt_detach(struct comedi_device *dev); static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = { - { - PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, + {0} }; MODULE_DEVICE_TABLE(pci, cnt_pci_table); diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index cda4b224b30..8b812e41c52 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -188,12 +188,9 @@ static const struct comedi_lrange me2600_ao_range = { }; static DEFINE_PCI_DEVICE_TABLE(me_pci_table) = { - { - PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) }, + {0} }; MODULE_DEVICE_TABLE(pci, me_pci_table); diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 32e675e3f0b..c25e44c1905 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -731,9 +731,8 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(trigger_bits, dev->iobase + TRIGGER_REG); /* start acquisition for soft trigger */ - if (cmd->start_src == TRIG_NOW) { + if (cmd->start_src == TRIG_NOW) outw(0, dev->iobase + FIFO_START_REG); - } #ifdef A2150_DEBUG ni_dump_regs(dev); #endif @@ -860,11 +859,10 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, case TRIG_ROUND_NEAREST: default: /* if least upper bound is better approximation */ - if (lub - *period < *period - glb) { + if (lub - *period < *period - glb) *period = lub; - } else { + else *period = glb; - } break; case TRIG_ROUND_UP: *period = lub; diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 49b824c7bd2..c0423a8c3e3 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -52,7 +52,7 @@ the PCMCIA interface. #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -static struct pcmcia_device *pcmcia_cur_dev = NULL; +static struct pcmcia_device *pcmcia_cur_dev; #define DIO24_SIZE 4 /* size of io region used by board */ @@ -133,22 +133,19 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) #endif break; default: - printk("bug! couldn't determine board type\n"); + pr_err("bug! couldn't determine board type\n"); return -EINVAL; break; } - printk("comedi%d: ni_daq_dio24: %s, io 0x%lx", dev->minor, - thisboard->name, iobase); + pr_debug("comedi%d: ni_daq_dio24: %s, io 0x%lx", dev->minor, + thisboard->name, iobase); #ifdef incomplete - if (irq) { - printk(", irq %u", irq); - } + if (irq) + pr_debug("irq %u\n", irq); #endif - printk("\n"); - if (iobase == 0) { - printk("io base address is zero!\n"); + pr_err("io base address is zero!\n"); return -EINVAL; } @@ -173,7 +170,7 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) static int dio24_detach(struct comedi_device *dev) { - printk("comedi%d: ni_daq_dio24: remove\n", dev->minor); + dev_info(dev->hw_dev, "comedi%d: ni_daq_dio24: remove\n", dev->minor); if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 0); diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index 832a5178b63..ff3840544dd 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -145,7 +145,7 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) irq = link->irq; break; default: - printk("bug! couldn't determine board type\n"); + pr_err("bug! couldn't determine board type\n"); return -EINVAL; break; } diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 9148abdad07..0f0d995f137 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1470,7 +1470,7 @@ static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, /* FIXME: DIO_Output_Register (16 bit reg) is replaced by M_Offset_Static_Digital_Output (32 bit) and M_Offset_SCXI_Serial_Data_Out (8 bit) */ default: - printk("%s: bug! unhandled register=0x%x in switch.\n", + printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", __func__, reg); BUG(); return; @@ -1505,7 +1505,7 @@ static uint16_t m_series_stc_readw(struct comedi_device *dev, int reg) offset = M_Offset_G01_Status; break; default: - printk("%s: bug! unhandled register=0x%x in switch.\n", + printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", __func__, reg); BUG(); return 0; @@ -1547,7 +1547,7 @@ static void m_series_stc_writel(struct comedi_device *dev, uint32_t data, offset = M_Offset_G1_Load_B; break; default: - printk("%s: bug! unhandled register=0x%x in switch.\n", + printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", __func__, reg); BUG(); return; @@ -1573,7 +1573,7 @@ static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg) offset = M_Offset_G1_Save; break; default: - printk("%s: bug! unhandled register=0x%x in switch.\n", + printk(KERN_WARNING "%s: bug! unhandled register=0x%x in switch.\n", __func__, reg); BUG(); return 0; @@ -1632,9 +1632,8 @@ static void m_series_init_eeprom_buffer(struct comedi_device *dev) } devpriv->serial_number = be32_to_cpu(devpriv->serial_number); - for (i = 0; i < M_SERIES_EEPROM_SIZE; ++i) { + for (i = 0; i < M_SERIES_EEPROM_SIZE; ++i) devpriv->eeprom_buffer[i] = ni_readb(Start_Cal_EEPROM + i); - } writel(old_iodwbsr1_bits, devpriv->mite->mite_io_addr + MITE_IODWBSR_1); writel(old_iodwbsr_bits, devpriv->mite->mite_io_addr + MITE_IODWBSR); @@ -1665,9 +1664,9 @@ static void init_6143(struct comedi_device *dev) static int pcimio_detach(struct comedi_device *dev) { mio_common_detach(dev); - if (dev->irq) { + if (dev->irq) free_irq(dev->irq, dev); - } + if (dev->private) { mite_free_ring(devpriv->ai_mite_ring); mite_free_ring(devpriv->ao_mite_ring); @@ -1685,7 +1684,7 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; - printk("comedi%d: ni_pcimio:", dev->minor); + dev_info(dev->hw_dev, "comedi%d: ni_pcimio:\n", dev->minor); ret = ni_alloc_private(dev); if (ret < 0) @@ -1695,7 +1694,7 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret < 0) return ret; - printk(" %s", boardtype.name); + dev_dbg(dev->hw_dev, "%s\n", boardtype.name); dev->board_name = boardtype.name; if (boardtype.reg_type & ni_reg_m_series_mask) { @@ -1712,7 +1711,7 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) ret = mite_setup(devpriv->mite); if (ret < 0) { - printk(" error setting up mite\n"); + pr_warn("error setting up mite\n"); return ret; } comedi_set_hw_dev(dev, &devpriv->mite->pcidev->dev); @@ -1740,13 +1739,13 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->irq = mite_irq(devpriv->mite); if (dev->irq == 0) { - printk(" unknown irq (bad)\n"); + pr_warn("unknown irq (bad)\n"); } else { - printk(" ( irq = %u )", dev->irq); + pr_debug("( irq = %u )\n", dev->irq); ret = request_irq(dev->irq, ni_E_interrupt, NI_E_IRQ_FLAGS, DRV_NAME, dev); if (ret < 0) { - printk(" irq not available\n"); + pr_warn("irq not available\n"); dev->irq = 0; } } @@ -1787,7 +1786,7 @@ static int pcimio_find_device(struct comedi_device *dev, int bus, int slot) } } } - printk("no device found\n"); + pr_warn("no device found\n"); mite_list_devices(); return -EIO; } diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index 0b9bee36eb5..96cd7ec2ad5 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -155,8 +155,8 @@ static int pcl816_attach(struct comedi_device *dev, static int pcl816_detach(struct comedi_device *dev); #ifdef unused -static int RTC_lock = 0; /* RTC lock */ -static int RTC_timer_lock = 0; /* RTC int lock */ +static int RTC_lock; /* RTC lock */ +static int RTC_timer_lock; /* RTC int lock */ #endif static struct comedi_driver driver_pcl816 = { diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index b45a9bd8b48..7344a53a81c 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -252,8 +252,8 @@ static int pcl818_attach(struct comedi_device *dev, static int pcl818_detach(struct comedi_device *dev); #ifdef unused -static int RTC_lock = 0; /* RTC lock */ -static int RTC_timer_lock = 0; /* RTC int lock */ +static int RTC_lock; /* RTC lock */ +static int RTC_timer_lock; /* RTC int lock */ #endif struct pcl818_board { @@ -463,9 +463,8 @@ static int pcl818_ao_insn_read(struct comedi_device *dev, int n; int chan = CR_CHAN(insn->chanspec); - for (n = 0; n < insn->n; n++) { + for (n = 0; n < insn->n; n++) data[n] = devpriv->ao_readback[chan]; - } return n; } @@ -571,9 +570,9 @@ conv_finish: return IRQ_HANDLED; } devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { + if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) devpriv->act_chanlist_pos = 0; - } + s->async->cur_chan++; if (s->async->cur_chan >= devpriv->ai_n_chan) { /* printk("E"); */ @@ -645,9 +644,9 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { + if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) devpriv->act_chanlist_pos = 0; - } + s->async->cur_chan++; if (s->async->cur_chan >= devpriv->ai_n_chan) { s->async->cur_chan = 0; @@ -805,11 +804,10 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) return IRQ_HANDLED; } - if (lo & 2) { + if (lo & 2) len = 512; - } else { + else len = 0; - } for (i = 0; i < len; i++) { lo = inb(dev->iobase + PCL818_FI_DATALO); @@ -827,9 +825,9 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { + if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) devpriv->act_chanlist_pos = 0; - } + s->async->cur_chan++; if (s->async->cur_chan >= devpriv->ai_n_chan) { s->async->cur_chan = 0; @@ -1009,7 +1007,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, int divisor1 = 0, divisor2 = 0; unsigned int seglen; - printk("pcl818_ai_cmd_mode()\n"); + dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode()\n"); if ((!dev->irq) && (!devpriv->dma_rtc)) { comedi_error(dev, "IRQ not defined!"); return -EINVAL; @@ -1112,7 +1110,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, break; } #endif - printk("pcl818_ai_cmd_mode() end\n"); + dev_dbg(dev->hw_dev, "pcl818_ai_cmd_mode() end\n"); return 0; } @@ -1309,11 +1307,9 @@ static void setup_channel_list(struct comedi_device *dev, */ static int check_single_ended(unsigned int port) { - if (inb(port + PCL818_STATUS) & 0x20) { + if (inb(port + PCL818_STATUS) & 0x20) return 1; - } else { - return 0; - } + return 0; } /* @@ -1352,9 +1348,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (!cmd->stop_src || tmp != cmd->stop_src) err++; - if (err) { + if (err) return 1; - } /* step 2: make sure trigger sources are unique and mutually compatible */ @@ -1377,9 +1372,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) err++; - if (err) { + if (err) return 2; - } /* step 3: make sure arguments are trivially compatible */ @@ -1421,9 +1415,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, } } - if (err) { + if (err) return 3; - } /* step 4: fix up any arguments */ @@ -1438,9 +1431,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, err++; } - if (err) { + if (err) return 4; - } /* step 5: complain about special chanlist considerations */ @@ -1461,7 +1453,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct comedi_cmd *cmd = &s->async->cmd; int retval; - printk("pcl818_ai_cmd()\n"); + dev_dbg(dev->hw_dev, "pcl818_ai_cmd()\n"); devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_chanlist = cmd->chanlist; devpriv->ai_flags = cmd->flags; @@ -1470,17 +1462,16 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_timer1 = 0; devpriv->ai_timer2 = 0; - if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) devpriv->ai_scans = cmd->stop_arg; - } else { + else devpriv->ai_scans = 0; - } if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ devpriv->ai_timer1 = cmd->convert_arg; retval = pcl818_ai_cmd_mode(1, dev, s); - printk("pcl818_ai_cmd() end\n"); + dev_dbg(dev->hw_dev, "pcl818_ai_cmd() end\n"); return retval; } if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ @@ -1499,7 +1490,7 @@ static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { if (devpriv->irq_blocked > 0) { - printk("pcl818_ai_cancel()\n"); + dev_dbg(dev->hw_dev, "pcl818_ai_cancel()\n"); devpriv->irq_was_now_closed = 1; switch (devpriv->ai_mode) { @@ -1549,7 +1540,7 @@ static int pcl818_ai_cancel(struct comedi_device *dev, } end: - printk("pcl818_ai_cancel() end\n"); + dev_dbg(dev->hw_dev, "pcl818_ai_cancel() end\n"); return 0; } @@ -1633,11 +1624,11 @@ static int set_rtc_irq_bit(unsigned char bit) save_flags(flags); cli(); val = CMOS_READ(RTC_CONTROL); - if (bit) { + if (bit) val |= RTC_PIE; - } else { + else val &= ~RTC_PIE; - } + CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); restore_flags(flags); @@ -1754,22 +1745,23 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* claim our I/O space */ iobase = it->options[0]; - printk("comedi%d: pcl818: board=%s, ioport=0x%03lx", - dev->minor, this_board->name, iobase); + printk + ("comedi%d: pcl818: board=%s, ioport=0x%03lx", + dev->minor, this_board->name, iobase); devpriv->io_range = this_board->io_range; if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */ devpriv->io_range = PCLx1xFIFO_RANGE; devpriv->usefifo = 1; } if (!request_region(iobase, devpriv->io_range, "pcl818")) { - printk("I/O port conflict\n"); + comedi_error(dev, "I/O port conflict\n"); return -EIO; } dev->iobase = iobase; if (pcl818_check(iobase)) { - printk(", I can't detect board. FAIL!\n"); + comedi_error(dev, "I can't detect board. FAIL!\n"); return -EIO; } @@ -1793,19 +1785,18 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) irq); irq = 0; /* Can't use IRQ */ } else { - printk(", irq=%u", irq); + printk(KERN_DEBUG "irq=%u", irq); } } } } dev->irq = irq; - if (irq) { - devpriv->irq_free = 1; - } /* 1=we have allocated irq */ - else { + if (irq) + devpriv->irq_free = 1; /* 1=we have allocated irq */ + else devpriv->irq_free = 0; - } + devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ devpriv->ai_mode = 0; /* mode of irq */ @@ -1825,7 +1816,7 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) "pcl818 DMA (RTC)", dev)) { devpriv->dma_rtc = 1; devpriv->rtc_irq = RTC_IRQ; - printk(", dma_irq=%u", devpriv->rtc_irq); + printk(KERN_DEBUG "dma_irq=%u", devpriv->rtc_irq); } else { RTC_lock--; if (RTC_lock == 0) { @@ -1850,34 +1841,26 @@ no_rtc: if (dma < 1) goto no_dma; /* DMA disabled */ if (((1 << dma) & this_board->DMAbits) == 0) { - printk(", DMA is out of allowed range, FAIL!\n"); + printk(KERN_ERR "DMA is out of allowed range, FAIL!\n"); return -EINVAL; /* Bad DMA */ } ret = request_dma(dma, "pcl818"); - if (ret) { - printk(", unable to allocate DMA %u, FAIL!\n", dma); + if (ret) return -EBUSY; /* DMA isn't free */ - } devpriv->dma = dma; - printk(", dma=%u", dma); pages = 2; /* we need 16KB */ devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) { - printk(", unable to allocate DMA buffer, FAIL!\n"); + if (!devpriv->dmabuf[0]) /* maybe experiment with try_to_free_pages() will help .... */ return -EBUSY; /* no buffer :-( */ - } devpriv->dmapages[0] = pages; devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */ devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - printk - (", unable to allocate DMA buffer, FAIL!\n"); + if (!devpriv->dmabuf[1]) return -EBUSY; - } devpriv->dmapages[1] = pages; devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); @@ -2017,11 +2000,10 @@ no_dma: } /* select 1/10MHz oscilator */ - if ((it->options[3] == 0) || (it->options[3] == 10)) { + if ((it->options[3] == 0) || (it->options[3] == 10)) devpriv->i8253_osc_base = 100; - } else { + else devpriv->i8253_osc_base = 1000; - } /* max sampling speed */ devpriv->ns_min = this_board->ns_min; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 3ad04aaa1e3..eddac00e4e2 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -371,15 +371,15 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) iobase = it->options[0]; irq[0] = it->options[1]; - printk(KERN_INFO "comedi%d: %s: io: %lx ", dev->minor, driver.driver_name, - iobase); + printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor, + driver.driver_name, iobase); dev->iobase = iobase; if (!iobase || !request_region(iobase, thisboard->total_iosize, driver.driver_name)) { - printk(KERN_ERR "I/O port conflict\n"); + printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor); return -EIO; } @@ -394,7 +394,8 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) * convenient macro defined in comedidev.h. */ if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) { - printk(KERN_ERR "cannot allocate private data structure\n"); + printk(KERN_ERR "comedi%d: cannot allocate private data structure\n", + dev->minor); return -ENOMEM; } @@ -417,7 +418,8 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), GFP_KERNEL); if (!devpriv->sprivs) { - printk(KERN_ERR "cannot allocate subdevice private data structures\n"); + printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n", + dev->minor); return -ENOMEM; } /* @@ -427,7 +429,8 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO) */ if (alloc_subdevices(dev, n_subdevs) < 0) { - printk(KERN_ERR "cannot allocate subdevice data structures\n"); + printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n", + dev->minor); return -ENOMEM; } @@ -557,14 +560,15 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) */ if (irq[0]) { - printk(KERN_DEBUG "irq: %u ", irq[0]); + printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]); if (thisboard->dio_num_asics == 2 && irq[1]) - printk(KERN_DEBUG "second ASIC irq: %u ", irq[1]); + printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n", + dev->minor, irq[1]); } else { - printk(KERN_INFO "(IRQ mode disabled) "); + printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor); } - printk(KERN_INFO "attached\n"); + printk(KERN_INFO "comedi%d: attached\n", dev->minor); return 1; } @@ -663,7 +667,7 @@ static int pcmmio_dio_insn_bits(struct comedi_device *dev, } #ifdef DAMMIT_ITS_BROKEN /* DEBUG */ - printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte); + printk("data_out_byte %02x\n", (unsigned)byte); #endif /* save the digital input lines for this byte.. */ s->state |= ((unsigned int)byte) << offset; diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index b2c2c8971a3..661ba2e0389 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -295,15 +295,15 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) irq[0] = it->options[1]; irq[1] = it->options[2]; - printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name, - iobase); + dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor, + driver.driver_name, iobase); dev->iobase = iobase; if (!iobase || !request_region(iobase, thisboard->num_asics * ASIC_IOSIZE, driver.driver_name)) { - printk("I/O port conflict\n"); + dev_err(dev->hw_dev, "I/O port conflict\n"); return -EIO; } @@ -318,7 +318,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) * convenient macro defined in comedidev.h. */ if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) { - printk("cannot allocate private data structure\n"); + dev_warn(dev->hw_dev, "cannot allocate private data structure\n"); return -ENOMEM; } @@ -337,7 +337,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private), GFP_KERNEL); if (!devpriv->sprivs) { - printk("cannot allocate subdevice private data structures\n"); + dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n"); return -ENOMEM; } /* @@ -348,7 +348,7 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) * 96-channel version of the board. */ if (alloc_subdevices(dev, n_subdevs) < 0) { - printk("cannot allocate subdevice data structures\n"); + dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n"); return -ENOMEM; } @@ -436,14 +436,13 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) irqs.. */ if (irq[0]) { - printk("irq: %u ", irq[0]); + dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]); if (irq[1] && thisboard->num_asics == 2) - printk("second ASIC irq: %u ", irq[1]); + dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]); } else { - printk("(IRQ mode disabled) "); + dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n"); } - printk("attached\n"); return 1; } @@ -460,7 +459,8 @@ static int pcmuio_detach(struct comedi_device *dev) { int i; - printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name); + dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor, + driver.driver_name); if (dev->iobase) release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics); @@ -501,7 +501,8 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev, #ifdef DAMMIT_ITS_BROKEN /* DEBUG */ - printk("write mask: %08x data: %08x\n", data[0], data[1]); + dev_dbg(dev->hw_dev, "write mask: %08x data: %08x\n", data[0], + data[1]); #endif s->state = 0; @@ -537,7 +538,7 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev, } #ifdef DAMMIT_ITS_BROKEN /* DEBUG */ - printk("data_out_byte %02x\n", (unsigned)byte); + dev_dbg(dev->hw_dev, "data_out_byte %02x\n", (unsigned)byte); #endif /* save the digital input lines for this byte.. */ s->state |= ((unsigned int)byte) << offset; @@ -548,7 +549,8 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev, #ifdef DAMMIT_ITS_BROKEN /* DEBUG */ - printk("s->state %08x data_out %08x\n", s->state, data[1]); + dev_dbg(dev->hw_dev, "s->state %08x data_out %08x\n", s->state, + data[1]); #endif return 2; @@ -951,14 +953,13 @@ pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, spin_lock_irqsave(&subpriv->intr.spinlock, flags); s->async->inttrig = 0; - if (subpriv->intr.active) { + if (subpriv->intr.active) event = pcmuio_start_intr(dev, s); - } + spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); - if (event) { + if (event) comedi_event(dev, s); - } return 1; } @@ -1000,9 +1001,8 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); - if (event) { + if (event) comedi_event(dev, s); - } return 0; } diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index ade2202b623..d880c2f6fbc 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -824,7 +824,7 @@ static int serial2002_attach(struct comedi_device *dev, { struct comedi_subdevice *s; - printk("comedi%d: serial2002: ", dev->minor); + dev_dbg(dev->hw_dev, "comedi%d: attached\n", dev->minor); dev->board_name = thisboard->name; if (alloc_private(dev, sizeof(struct serial2002_private)) < 0) return -ENOMEM; @@ -832,7 +832,8 @@ static int serial2002_attach(struct comedi_device *dev, dev->close = serial_2002_close; devpriv->port = it->options[0]; devpriv->speed = it->options[1]; - printk("/dev/ttyS%d @ %d\n", devpriv->port, devpriv->speed); + dev_dbg(dev->hw_dev, "/dev/ttyS%d @ %d\n", devpriv->port, + devpriv->speed); if (alloc_subdevices(dev, 5) < 0) return -ENOMEM; @@ -891,7 +892,7 @@ static int serial2002_detach(struct comedi_device *dev) struct comedi_subdevice *s; int i; - printk("comedi%d: serial2002: remove\n", dev->minor); + dev_dbg(dev->hw_dev, "comedi%d: remove\n", dev->minor); for (i = 0; i < 5; i++) { s = &dev->subdevices[i]; kfree(s->maxdata_list); diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 6144afb8cba..ca6bcf8b023 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -1524,15 +1524,17 @@ static int usbdux_ao_inttrig(struct comedi_device *dev, return -EFAULT; down(&this_usbduxsub->sem); + if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; + ret = -ENODEV; + goto out; } if (trignum != 0) { dev_err(&this_usbduxsub->interface->dev, "comedi%d: usbdux_ao_inttrig: invalid trignum\n", dev->minor); - return -EINVAL; + ret = -EINVAL; + goto out; } if (!(this_usbduxsub->ao_cmd_running)) { this_usbduxsub->ao_cmd_running = 1; @@ -1542,8 +1544,7 @@ static int usbdux_ao_inttrig(struct comedi_device *dev, "comedi%d: usbdux_ao_inttrig: submitURB: " "err=%d\n", dev->minor, ret); this_usbduxsub->ao_cmd_running = 0; - up(&this_usbduxsub->sem); - return ret; + goto out; } s->async->inttrig = NULL; } else { @@ -1551,8 +1552,10 @@ static int usbdux_ao_inttrig(struct comedi_device *dev, "comedi%d: ao_inttrig but acqu is already running.\n", dev->minor); } + ret = 1; +out: up(&this_usbduxsub->sem); - return 1; + return ret; } static int usbdux_ao_cmdtest(struct comedi_device *dev, @@ -2689,6 +2692,7 @@ static int usbduxsigma_attach(struct comedi_device *dev, if (ret < 0) { dev_err(&udev->interface->dev, "comedi%d: no space for subdev\n", dev->minor); + up(&udev->sem); up(&start_stop_sem); return ret; } diff --git a/drivers/staging/crystalhd/bc_dts_defs.h b/drivers/staging/crystalhd/bc_dts_defs.h index fde5b0627f6..8cd51a7aad8 100644 --- a/drivers/staging/crystalhd/bc_dts_defs.h +++ b/drivers/staging/crystalhd/bc_dts_defs.h @@ -296,43 +296,79 @@ enum { vdecColourPrimariesSMPTE240M, vdecColourPrimariesGenericFilm, }; - +/** + * @vdecRESOLUTION_CUSTOM: custom + * @vdecRESOLUTION_480i: 480i + * @vdecRESOLUTION_1080i: 1080i (1920x1080, 60i) + * @vdecRESOLUTION_NTSC: NTSC (720x483, 60i) + * @vdecRESOLUTION_480p: 480p (720x480, 60p) + * @vdecRESOLUTION_720p: 720p (1280x720, 60p) + * @vdecRESOLUTION_PAL1: PAL_1 (720x576, 50i) + * @vdecRESOLUTION_1080i25: 1080i25 (1920x1080, 50i) + * @vdecRESOLUTION_720p50: 720p50 (1280x720, 50p) + * @vdecRESOLUTION_576p: 576p (720x576, 50p) + * @vdecRESOLUTION_1080i29_97: 1080i (1920x1080, 59.94i) + * @vdecRESOLUTION_720p59_94: 720p (1280x720, 59.94p) + * @vdecRESOLUTION_SD_DVD: SD DVD (720x483, 60i) + * @vdecRESOLUTION_480p656: 480p (720x480, 60p), + * output bus width 8 bit, clock 74.25MHz + * @vdecRESOLUTION_1080p23_976: 1080p23_976 (1920x1080, 23.976p) + * @vdecRESOLUTION_720p23_976: 720p23_976 (1280x720p, 23.976p) + * @vdecRESOLUTION_240p29_97: 240p (1440x240, 29.97p ) + * @vdecRESOLUTION_240p30: 240p (1440x240, 30p) + * @vdecRESOLUTION_288p25: 288p (1440x288p, 25p) + * @vdecRESOLUTION_1080p29_97: 1080p29_97 (1920x1080, 29.97p) + * @vdecRESOLUTION_1080p30: 1080p30 (1920x1080, 30p) + * @vdecRESOLUTION_1080p24: 1080p24 (1920x1080, 24p) + * @vdecRESOLUTION_1080p25: 1080p25 (1920x1080, 25p) + * @vdecRESOLUTION_720p24: 720p24 (1280x720, 25p) + * @vdecRESOLUTION_720p29_97: 720p29.97 (1280x720, 29.97p) + * @vdecRESOLUTION_480p23_976: 480p23.976 (720*480, 23.976) + * @vdecRESOLUTION_480p29_97: 480p29.976 (720*480, 29.97p) + * @vdecRESOLUTION_576p25: 576p25 (720*576, 25p) + * @vdecRESOLUTION_480p0: 480p (720x480, 0p) + * @vdecRESOLUTION_480i0: 480i (720x480, 0i) + * @vdecRESOLUTION_576p0: 576p (720x576, 0p) + * @vdecRESOLUTION_720p0: 720p (1280x720, 0p) + * @vdecRESOLUTION_1080p0: 1080p (1920x1080, 0p) + * @vdecRESOLUTION_1080i0: 1080i (1920x1080, 0i) + */ enum { - vdecRESOLUTION_CUSTOM = 0x00000000, /* custom */ - vdecRESOLUTION_480i = 0x00000001, /* 480i */ - vdecRESOLUTION_1080i = 0x00000002, /* 1080i (1920x1080, 60i) */ - vdecRESOLUTION_NTSC = 0x00000003, /* NTSC (720x483, 60i) */ - vdecRESOLUTION_480p = 0x00000004, /* 480p (720x480, 60p) */ - vdecRESOLUTION_720p = 0x00000005, /* 720p (1280x720, 60p) */ - vdecRESOLUTION_PAL1 = 0x00000006, /* PAL_1 (720x576, 50i) */ - vdecRESOLUTION_1080i25 = 0x00000007, /* 1080i25 (1920x1080, 50i) */ - vdecRESOLUTION_720p50 = 0x00000008, /* 720p50 (1280x720, 50p) */ - vdecRESOLUTION_576p = 0x00000009, /* 576p (720x576, 50p) */ - vdecRESOLUTION_1080i29_97 = 0x0000000A, /* 1080i (1920x1080, 59.94i) */ - vdecRESOLUTION_720p59_94 = 0x0000000B, /* 720p (1280x720, 59.94p) */ - vdecRESOLUTION_SD_DVD = 0x0000000C, /* SD DVD (720x483, 60i) */ - vdecRESOLUTION_480p656 = 0x0000000D, /* 480p (720x480, 60p), output bus width 8 bit, clock 74.25MHz */ - vdecRESOLUTION_1080p23_976 = 0x0000000E, /* 1080p23_976 (1920x1080, 23.976p) */ - vdecRESOLUTION_720p23_976 = 0x0000000F, /* 720p23_976 (1280x720p, 23.976p) */ - vdecRESOLUTION_240p29_97 = 0x00000010, /* 240p (1440x240, 29.97p ) */ - vdecRESOLUTION_240p30 = 0x00000011, /* 240p (1440x240, 30p) */ - vdecRESOLUTION_288p25 = 0x00000012, /* 288p (1440x288p, 25p) */ - vdecRESOLUTION_1080p29_97 = 0x00000013, /* 1080p29_97 (1920x1080, 29.97p) */ - vdecRESOLUTION_1080p30 = 0x00000014, /* 1080p30 (1920x1080, 30p) */ - vdecRESOLUTION_1080p24 = 0x00000015, /* 1080p24 (1920x1080, 24p) */ - vdecRESOLUTION_1080p25 = 0x00000016, /* 1080p25 (1920x1080, 25p) */ - vdecRESOLUTION_720p24 = 0x00000017, /* 720p24 (1280x720, 25p) */ - vdecRESOLUTION_720p29_97 = 0x00000018, /* 720p29.97 (1280x720, 29.97p) */ - vdecRESOLUTION_480p23_976 = 0x00000019, /* 480p23.976 (720*480, 23.976) */ - vdecRESOLUTION_480p29_97 = 0x0000001A, /* 480p29.976 (720*480, 29.97p) */ - vdecRESOLUTION_576p25 = 0x0000001B, /* 576p25 (720*576, 25p) */ + vdecRESOLUTION_CUSTOM = 0x00000000, + vdecRESOLUTION_480i = 0x00000001, + vdecRESOLUTION_1080i = 0x00000002, + vdecRESOLUTION_NTSC = 0x00000003, + vdecRESOLUTION_480p = 0x00000004, + vdecRESOLUTION_720p = 0x00000005, + vdecRESOLUTION_PAL1 = 0x00000006, + vdecRESOLUTION_1080i25 = 0x00000007, + vdecRESOLUTION_720p50 = 0x00000008, + vdecRESOLUTION_576p = 0x00000009, + vdecRESOLUTION_1080i29_97 = 0x0000000A, + vdecRESOLUTION_720p59_94 = 0x0000000B, + vdecRESOLUTION_SD_DVD = 0x0000000C, + vdecRESOLUTION_480p656 = 0x0000000D, + vdecRESOLUTION_1080p23_976 = 0x0000000E, + vdecRESOLUTION_720p23_976 = 0x0000000F, + vdecRESOLUTION_240p29_97 = 0x00000010, + vdecRESOLUTION_240p30 = 0x00000011, + vdecRESOLUTION_288p25 = 0x00000012, + vdecRESOLUTION_1080p29_97 = 0x00000013, + vdecRESOLUTION_1080p30 = 0x00000014, + vdecRESOLUTION_1080p24 = 0x00000015, + vdecRESOLUTION_1080p25 = 0x00000016, + vdecRESOLUTION_720p24 = 0x00000017, + vdecRESOLUTION_720p29_97 = 0x00000018, + vdecRESOLUTION_480p23_976 = 0x00000019, + vdecRESOLUTION_480p29_97 = 0x0000001A, + vdecRESOLUTION_576p25 = 0x0000001B, /* For Zero Frame Rate */ - vdecRESOLUTION_480p0 = 0x0000001C, /* 480p (720x480, 0p) */ - vdecRESOLUTION_480i0 = 0x0000001D, /* 480i (720x480, 0i) */ - vdecRESOLUTION_576p0 = 0x0000001E, /* 576p (720x576, 0p) */ - vdecRESOLUTION_720p0 = 0x0000001F, /* 720p (1280x720, 0p) */ - vdecRESOLUTION_1080p0 = 0x00000020, /* 1080p (1920x1080, 0p) */ - vdecRESOLUTION_1080i0 = 0x00000021, /* 1080i (1920x1080, 0i) */ + vdecRESOLUTION_480p0 = 0x0000001C, + vdecRESOLUTION_480i0 = 0x0000001D, + vdecRESOLUTION_576p0 = 0x0000001E, + vdecRESOLUTION_720p0 = 0x0000001F, + vdecRESOLUTION_1080p0 = 0x00000020, + vdecRESOLUTION_1080i0 = 0x00000021, }; /* Bit definitions for 'flags' field */ @@ -359,14 +395,23 @@ enum _BC_OUTPUT_FORMAT { MODE422_YUY2 = 0x1, MODE422_UYVY = 0x2, }; - +/** + * struct BC_PIC_INFO_BLOCK + * @timeStam;: Timestamp + * @picture_number: Ordinal display number + * @width: pixels + * @height: pixels + * @chroma_format: 0x420, 0x422 or 0x444 + * @n_drop;: number of non-reference frames + * remaining to be dropped + */ struct BC_PIC_INFO_BLOCK { /* Common fields. */ - uint64_t timeStamp; /* Timestamp */ - uint32_t picture_number; /* Ordinal display number */ - uint32_t width; /* pixels */ - uint32_t height; /* pixels */ - uint32_t chroma_format; /* 0x420, 0x422 or 0x444 */ + uint64_t timeStamp; + uint32_t picture_number; + uint32_t width; + uint32_t height; + uint32_t chroma_format; uint32_t pulldown; uint32_t flags; uint32_t frame_rate; @@ -376,7 +421,8 @@ struct BC_PIC_INFO_BLOCK { uint32_t sess_num; uint32_t ycom; uint32_t custom_aspect_ratio_width_height; - uint32_t n_drop; /* number of non-reference frames remaining to be dropped */ + uint32_t n_drop; /* number of non-reference frames + remaining to be dropped */ /* Protocol-specific extensions. */ union { @@ -390,43 +436,71 @@ struct BC_PIC_INFO_BLOCK { /*------------------------------------------------------* * ProcOut Info * *------------------------------------------------------*/ -/* Optional flags for ProcOut Interface.*/ + +/** + * enum POUT_OPTIONAL_IN_FLAGS - Optional flags for ProcOut Interface. + * @BC_POUT_FLAGS_YV12: Copy Data in YV12 format + * @BC_POUT_FLAGS_STRIDE: Stride size is valid. + * @BC_POUT_FLAGS_SIZE: Take size information from Application + * @BC_POUT_FLAGS_INTERLACED: copy only half the bytes + * @BC_POUT_FLAGS_INTERLEAVED: interleaved frame + * @: * @BC_POUT_FLAGS_FMT_CHANGE: Data is not VALID when this flag is set + * @BC_POUT_FLAGS_PIB_VALID: PIB Information valid + * @BC_POUT_FLAGS_ENCRYPTED: Data is encrypted. + * @BC_POUT_FLAGS_FLD_BOT: Bottom Field data + */ enum POUT_OPTIONAL_IN_FLAGS_ { /* Flags from App to Device */ - BC_POUT_FLAGS_YV12 = 0x01, /* Copy Data in YV12 format */ - BC_POUT_FLAGS_STRIDE = 0x02, /* Stride size is valid. */ - BC_POUT_FLAGS_SIZE = 0x04, /* Take size information from Application */ - BC_POUT_FLAGS_INTERLACED = 0x08, /* copy only half the bytes */ - BC_POUT_FLAGS_INTERLEAVED = 0x10, /* interleaved frame */ + BC_POUT_FLAGS_YV12 = 0x01, + BC_POUT_FLAGS_STRIDE = 0x02, + BC_POUT_FLAGS_SIZE = 0x04, + BC_POUT_FLAGS_INTERLACED = 0x08, + BC_POUT_FLAGS_INTERLEAVED = 0x10, /* Flags from Device to APP */ - BC_POUT_FLAGS_FMT_CHANGE = 0x10000, /* Data is not VALID when this flag is set */ - BC_POUT_FLAGS_PIB_VALID = 0x20000, /* PIB Information valid */ - BC_POUT_FLAGS_ENCRYPTED = 0x40000, /* Data is encrypted. */ - BC_POUT_FLAGS_FLD_BOT = 0x80000, /* Bottom Field data */ + BC_POUT_FLAGS_FMT_CHANGE = 0x10000, + BC_POUT_FLAGS_PIB_VALID = 0x20000, + BC_POUT_FLAGS_ENCRYPTED = 0x40000, + BC_POUT_FLAGS_FLD_BOT = 0x80000, }; -typedef enum BC_STATUS(*dts_pout_callback)(void *shnd, uint32_t width, uint32_t height, uint32_t stride, void *pOut); +typedef enum BC_STATUS(*dts_pout_callback)(void *shnd, uint32_t width, + uint32_t height, uint32_t stride, void *pOut); /* Line 21 Closed Caption */ /* User Data */ #define MAX_UD_SIZE 1792 /* 1920 - 128 */ +/** + * struct BC_DTS_PROC_OUT + * @Ybuff: Caller Supplied buffer for Y data + * @YbuffSz: Caller Supplied Y buffer size + * @YBuffDoneSz: Transferred Y datasize + * @*UVbuff: Caller Supplied buffer for UV data + * @UVbuffSz: Caller Supplied UV buffer size + * @UVBuffDoneSz: Transferred UV data size + * @StrideSz: Caller supplied Stride Size + * @PoutFlags: Call IN Flags + * @discCnt: Picture discontinuity count + * @PicInfo: Picture Information Block Data + * @b422Mode: Picture output Mode + * @bPibEnc: PIB encrypted + */ struct BC_DTS_PROC_OUT { - uint8_t *Ybuff; /* Caller Supplied buffer for Y data */ - uint32_t YbuffSz; /* Caller Supplied Y buffer size */ - uint32_t YBuffDoneSz; /* Transferred Y datasize */ + uint8_t *Ybuff; + uint32_t YbuffSz; + uint32_t YBuffDoneSz; - uint8_t *UVbuff; /* Caller Supplied buffer for UV data */ - uint32_t UVbuffSz; /* Caller Supplied UV buffer size */ - uint32_t UVBuffDoneSz; /* Transferred UV data size */ + uint8_t *UVbuff; + uint32_t UVbuffSz; + uint32_t UVBuffDoneSz; - uint32_t StrideSz; /* Caller supplied Stride Size */ - uint32_t PoutFlags; /* Call IN Flags */ + uint32_t StrideSz; + uint32_t PoutFlags; - uint32_t discCnt; /* Picture discontinuity count */ + uint32_t discCnt; - struct BC_PIC_INFO_BLOCK PicInfo; /* Picture Information Block Data */ + struct BC_PIC_INFO_BLOCK PicInfo; /* Line 21 Closed Caption */ /* User Data */ @@ -436,39 +510,47 @@ struct BC_DTS_PROC_OUT { void *hnd; dts_pout_callback AppCallBack; uint8_t DropFrames; - uint8_t b422Mode; /* Picture output Mode */ - uint8_t bPibEnc; /* PIB encrypted */ + uint8_t b422Mode; + uint8_t bPibEnc; uint8_t bRevertScramble; }; - +/** + * struct BC_DTS_STATUS + * @ReadyListCount: Number of frames in ready list (reported by driver) + * @PowerStateChange: Number of active state power + * transitions (reported by driver) + * @FramesDropped: Number of frames dropped. (reported by DIL) + * @FramesCaptured: Number of frames captured. (reported by DIL) + * @FramesRepeated: Number of frames repeated. (reported by DIL) + * @InputCount: Times compressed video has been sent to the HW. + * i.e. Successful DtsProcInput() calls (reported by DIL) + * @InputTotalSize: Amount of compressed video that has been sent to the HW. + * (reported by DIL) + * @InputBusyCount: Times compressed video has attempted to be sent to the HW + * but the input FIFO was full. (reported by DIL) + * @PIBMissCount: Amount of times a PIB is invalid. (reported by DIL) + * @cpbEmptySize: supported only for H.264, specifically changed for + * Adobe. Report size of CPB buffer available. (reported by DIL) + * @NextTimeStamp: TimeStamp of the next picture that will be returned + * by a call to ProcOutput. Added for Adobe. Reported + * back from the driver + */ struct BC_DTS_STATUS { - uint8_t ReadyListCount; /* Number of frames in ready list (reported by driver) */ - uint8_t FreeListCount; /* Number of frame buffers free. (reported by driver) */ - uint8_t PowerStateChange; /* Number of active state power transitions (reported by driver) */ + uint8_t ReadyListCount; + uint8_t FreeListCount; + uint8_t PowerStateChange; uint8_t reserved_[1]; - - uint32_t FramesDropped; /* Number of frames dropped. (reported by DIL) */ - uint32_t FramesCaptured; /* Number of frames captured. (reported by DIL) */ - uint32_t FramesRepeated; /* Number of frames repeated. (reported by DIL) */ - - uint32_t InputCount; /* Times compressed video has been sent to the HW. - * i.e. Successful DtsProcInput() calls (reported by DIL) */ - uint64_t InputTotalSize; /* Amount of compressed video that has been sent to the HW. - * (reported by DIL) */ - uint32_t InputBusyCount; /* Times compressed video has attempted to be sent to the HW - * but the input FIFO was full. (reported by DIL) */ - - uint32_t PIBMissCount; /* Amount of times a PIB is invalid. (reported by DIL) */ - - uint32_t cpbEmptySize; /* supported only for H.264, specifically changed for - * Adobe. Report size of CPB buffer available. - * Reported by DIL */ - uint64_t NextTimeStamp; /* TimeStamp of the next picture that will be returned - * by a call to ProcOutput. Added for Adobe. Reported - * back from the driver */ + uint32_t FramesDropped; + uint32_t FramesCaptured; + uint32_t FramesRepeated; + uint32_t InputCount; + uint64_t InputTotalSize; + uint32_t InputBusyCount; + uint32_t PIBMissCount; + uint32_t cpbEmptySize; + uint64_t NextTimeStamp; uint8_t reserved__[16]; - }; #define BC_SWAP32(_v) \ diff --git a/drivers/staging/cxt1e1/comet.h b/drivers/staging/cxt1e1/comet.h index 5cb3afda011..e06da4a6f6f 100644 --- a/drivers/staging/cxt1e1/comet.h +++ b/drivers/staging/cxt1e1/comet.h @@ -1,7 +1,3 @@ -/* - * $Id: comet.h,v 1.3 2005/09/28 00:10:07 rickd PMCC4_3_1B $ - */ - #ifndef _INC_COMET_H_ #define _INC_COMET_H_ @@ -23,27 +19,9 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.3 $ - * Last changed on $Date: 2005/09/28 00:10:07 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: comet.h,v $ - * Revision 1.3 2005/09/28 00:10:07 rickd - * Add RCS header. Switch to structure usage. - * - * Revision 1.2 2005/04/28 23:43:03 rickd - * Add RCS tracking heading. - * - *----------------------------------------------------------------------------- */ -#if defined(__FreeBSD__) || defined (__NetBSD__) -#include <sys/types.h> -#else #include <linux/types.h> -#endif - #define VINT32 volatile u_int32_t diff --git a/drivers/staging/cxt1e1/comet_tables.c b/drivers/staging/cxt1e1/comet_tables.c index db1293c71a6..84931117da3 100644 --- a/drivers/staging/cxt1e1/comet_tables.c +++ b/drivers/staging/cxt1e1/comet_tables.c @@ -1,7 +1,3 @@ -/* - * $Id: comet_tables.c,v 1.2 2005/10/17 23:55:27 rickd PMCC4_3_1B $ - */ - /*----------------------------------------------------------------------------- * comet_tables.c - waveform tables for the PM4351 'COMET' * @@ -20,28 +16,8 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.2 $ - * Last changed on $Date: 2005/10/17 23:55:27 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: comet_tables.c,v $ - * Revision 1.2 2005/10/17 23:55:27 rickd - * Note that 75 Ohm transmit waveform is not supported on PMCC4. - * - * Revision 1.1 2005/09/28 00:10:05 rickd - * Cosmetic alignment of tables for readability. - * - * Revision 1.0 2005/05/10 22:47:53 rickd - * Initial revision - * - *----------------------------------------------------------------------------- */ -char SBEid_pmcc4_comet_tblc[] = - "@(#)comet_tables.c - $Revision: 1.2 $ (c) Copyright 2004-2005 SBE, Inc."; - - #include <linux/types.h> /***************************************************************************** diff --git a/drivers/staging/cxt1e1/comet_tables.h b/drivers/staging/cxt1e1/comet_tables.h index 80424a26a16..3e2e5badf78 100644 --- a/drivers/staging/cxt1e1/comet_tables.h +++ b/drivers/staging/cxt1e1/comet_tables.h @@ -1,7 +1,3 @@ -/* - * $Id: comet_tables.h,v 1.5 2006/01/02 22:37:31 rickd PMCC4_3_1B $ - */ - #ifndef _INC_COMET_TBLS_H_ #define _INC_COMET_TBLS_H_ @@ -23,26 +19,6 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.5 $ - * Last changed on $Date: 2006/01/02 22:37:31 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: comet_tables.h,v $ - * Revision 1.5 2006/01/02 22:37:31 rickd - * Double indexed arrays need sizings to avoid CC errors under - * gcc 4.0.0 - * - * Revision 1.4 2005/10/17 23:55:28 rickd - * The 75 Ohm transmit waveform is not supported on PMCC4. - * - * Revision 1.3 2005/09/28 00:10:08 rickd - * Add GNU License info. Structures moved to -C- file. - * - * Revision 1.2 2005/04/28 23:43:04 rickd - * Add RCS tracking heading. - * - *----------------------------------------------------------------------------- */ diff --git a/drivers/staging/cxt1e1/libsbew.h b/drivers/staging/cxt1e1/libsbew.h index ae8f06d05be..4254c0426db 100644 --- a/drivers/staging/cxt1e1/libsbew.h +++ b/drivers/staging/cxt1e1/libsbew.h @@ -1,7 +1,3 @@ -/* - * $Id: libsbew.h,v 2.1 2005/10/27 18:54:19 rickd PMCC4_3_1B $ - */ - #ifndef _INC_LIBSBEW_H_ #define _INC_LIBSBEW_H_ @@ -25,32 +21,8 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 2.1 $ - * Last changed on $Date: 2005/10/27 18:54:19 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: libsbew.h,v $ - * Revision 2.1 2005/10/27 18:54:19 rickd - * Add E1PLAIN support. - * - * Revision 2.0 2005/09/28 00:10:08 rickd - * Customized for PMCC4 comet-per-port design. - * - * Revision 1.15 2005/03/29 00:51:31 rickd - * File imported from C1T3 port, Revision 1.15 - *----------------------------------------------------------------------------- */ -#ifndef __KERNEL__ -#include <sys/types.h> -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - /********************************/ /** set driver logging level **/ /********************************/ @@ -574,8 +546,4 @@ struct sbecom_port_param extern int wancfg_set_tsioc (wcfg_t *, struct wanc1t3_ts_param *); #endif -#ifdef __cplusplus -} -#endif - #endif /*** _INC_LIBSBEW_H_ ***/ diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c index 5cc3423a664..90c0f1e30f6 100644 --- a/drivers/staging/cxt1e1/musycc.c +++ b/drivers/staging/cxt1e1/musycc.c @@ -1,7 +1,3 @@ -/* - * $Id: musycc.c,v 2.1 2007/08/15 23:32:17 rickd PMCC4_3_1B $ - */ - unsigned int max_intcnt = 0; unsigned int max_bh = 0; @@ -24,53 +20,8 @@ unsigned int max_bh = 0; * For further information, contact via email: support@onestopsystems.com * One Stop Systems, Inc. Escondido, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 2.1 $ - * Last changed on $Date: 2007/08/15 23:32:17 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: musycc.c,v $ - * Revision 2.1 2007/08/15 23:32:17 rickd - * Use 'if 0' instead of GNU comment delimeter to avoid line wrap induced compiler errors. - * - * Revision 2.0 2007/08/15 22:13:20 rickd - * Update to printf pointer %p usage and correct some UINT to ULONG for - * 64bit comptibility. - * - * Revision 1.7 2006/04/21 00:56:40 rickd - * workqueue files now prefixed with <sbecom> prefix. - * - * Revision 1.6 2005/10/27 18:54:19 rickd - * Clean out old code. Default to HDLC_FCS16, not TRANS. - * - * Revision 1.5 2005/10/17 23:55:28 rickd - * Initial port of NCOMM support patches from original work found - * in pmc_c4t1e1 as updated by NCOMM. Ref: CONFIG_SBE_PMCC4_NCOMM. - * - * Revision 1.4 2005/10/13 20:35:25 rickd - * Cleanup warning for unused <flags> variable. - * - * Revision 1.3 2005/10/13 19:19:22 rickd - * Disable redundant driver removal cleanup code. - * - * Revision 1.2 2005/10/11 18:36:16 rickd - * Clean up warning messages caused by de-implemented some <flags> associated - * with spin_lock() removals. - * - * Revision 1.1 2005/10/05 00:45:28 rickd - * Re-enable xmit on flow-controlled and full channel to fix restart hang. - * Add some temp spin-lock debug code (rld_spin_owner). - * - * Revision 1.0 2005/09/28 00:10:06 rickd - * Initial release for C4T1E1 support. Lots of transparent - * mode updates. - * - *----------------------------------------------------------------------------- */ -char SBEid_pmcc4_musyccc[] = -"@(#)musycc.c - $Revision: 2.1 $ (c) Copyright 2004-2006 SBE, Inc."; - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/types.h> diff --git a/drivers/staging/cxt1e1/musycc.h b/drivers/staging/cxt1e1/musycc.h index 68f3660f447..cf6b54e1568 100644 --- a/drivers/staging/cxt1e1/musycc.h +++ b/drivers/staging/cxt1e1/musycc.h @@ -1,7 +1,3 @@ -/* - * $Id: musycc.h,v 1.3 2005/09/28 00:10:08 rickd PMCC4_3_1B $ - */ - #ifndef _INC_MUSYCC_H_ #define _INC_MUSYCC_H_ @@ -24,36 +20,13 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.3 $ - * Last changed on $Date: 2005/09/28 00:10:08 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: musycc.h,v $ - * Revision 1.3 2005/09/28 00:10:08 rickd - * Add GNU license info. Add PMCC4 PCI/DevIDs. Implement new - * musycc reg&bits namings. Use PORTMAP_0 GCD grouping. - * - * Revision 1.2 2005/04/28 23:43:04 rickd - * Add RCS tracking heading. - * - *----------------------------------------------------------------------------- */ -#if defined (__FreeBSD__) || defined (__NetBSD__) -#include <sys/types.h> -#else #include <linux/types.h> -#endif #define VINT8 volatile u_int8_t #define VINT32 volatile u_int32_t -#ifdef __cplusplus -extern "C" -{ -#endif - #include "pmcc4_defs.h" @@ -448,10 +421,6 @@ extern "C" /* This must be defined on an entire channel group (Port) basis */ #define SUERM_THRESHOLD 0x1f -#ifdef __cplusplus -} -#endif - #undef VINT32 #undef VINT8 diff --git a/drivers/staging/cxt1e1/ossiRelease.c b/drivers/staging/cxt1e1/ossiRelease.c index a56029866c2..f17a902e95e 100644 --- a/drivers/staging/cxt1e1/ossiRelease.c +++ b/drivers/staging/cxt1e1/ossiRelease.c @@ -1,7 +1,3 @@ -/* - * $Id: ossiRelease.c,v 1.2 2008/05/08 20:14:03 rdobbs PMCC4_3_1B $ - */ - /*----------------------------------------------------------------------------- * ossiRelease.c - * @@ -26,14 +22,8 @@ * One Stop Systems, Inc. Escondido, California U.S.A. * *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.2 $ - * Last changed on $Date: 2008/05/08 20:14:03 $ - * Changed by $Author: rdobbs $ - *----------------------------------------------------------------------------- */ - char pmcc4_OSSI_release[] = "$Release: PMCC4_3_1B, Copyright (c) 2008 One Stop Systems$"; /*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.h b/drivers/staging/cxt1e1/pmc93x6_eeprom.h index c3ada87efd2..96c48cb8326 100644 --- a/drivers/staging/cxt1e1/pmc93x6_eeprom.h +++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.h @@ -1,7 +1,3 @@ -/* - * $Id: pmc93x6_eeprom.h,v 1.1 2005/09/28 00:10:08 rickd PMCC4_3_1B $ - */ - #ifndef _INC_PMC93X6_EEPROM_H_ #define _INC_PMC93X6_EEPROM_H_ @@ -23,26 +19,9 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - *----------------------------------------------------------------------------- - * $Log: pmc93x6_eeprom.h,v $ - * Revision 1.1 2005/09/28 00:10:08 rickd - * pmc_verify_cksum return value is char. - * - * Revision 1.0 2005/05/04 17:20:51 rickd - * Initial revision - * - * Revision 1.0 2005/04/22 23:48:48 rickd - * Initial revision - * - *----------------------------------------------------------------------------- */ -#if defined (__FreeBSD__) || defined (__NetBSD__) -#include <sys/types.h> -#else #include <linux/types.h> -#endif #ifdef __KERNEL__ diff --git a/drivers/staging/cxt1e1/pmcc4.h b/drivers/staging/cxt1e1/pmcc4.h index e046b87763a..b0ed4ad1301 100644 --- a/drivers/staging/cxt1e1/pmcc4.h +++ b/drivers/staging/cxt1e1/pmcc4.h @@ -1,7 +1,3 @@ -/* - * $Id: pmcc4.h,v 1.4 2005/11/01 19:24:48 rickd PMCC4_3_1B $ - */ - #ifndef _INC_PMCC4_H_ #define _INC_PMCC4_H_ @@ -23,49 +19,15 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.4 $ - * Last changed on $Date: 2005/11/01 19:24:48 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: pmcc4.h,v $ - * Revision 1.4 2005/11/01 19:24:48 rickd - * Remove de-implement function prototypes. Several <int> to - * <status_t> changes for consistent usage of same. - * - * Revision 1.3 2005/09/28 00:10:08 rickd - * Add GNU license info. Use config params from libsbew.h - * - * Revision 1.2 2005/04/28 23:43:03 rickd - * Add RCS tracking heading. - * - *----------------------------------------------------------------------------- */ - -#if defined(__FreeBSD__) || defined(__NetBSD__) -#include <sys/types.h> -#else -#ifndef __KERNEL__ -#include <sys/types.h> -#else #include <linux/types.h> -#endif -#endif - - typedef int status_t; #define SBE_DRVR_FAIL 0 #define SBE_DRVR_SUCCESS 1 -#ifdef __cplusplus -extern "C" -{ -#endif - - /********************/ /* PMCC4 memory Map */ /********************/ @@ -105,10 +67,6 @@ extern "C" #define sbeE1errSMF 0x02 #define sbeE1CRC 0x01 -#ifdef __cplusplus -} -#endif - #ifdef __KERNEL__ /* diff --git a/drivers/staging/cxt1e1/pmcc4_cpld.h b/drivers/staging/cxt1e1/pmcc4_cpld.h index 6d8f0337aa3..a51209bc527 100644 --- a/drivers/staging/cxt1e1/pmcc4_cpld.h +++ b/drivers/staging/cxt1e1/pmcc4_cpld.h @@ -1,7 +1,3 @@ -/* - * $Id: pmcc4_cpld.h,v 1.0 2005/09/28 00:10:08 rickd PMCC4_3_1B $ - */ - #ifndef _INC_PMCC4_CPLD_H_ #define _INC_PMCC4_CPLD_H_ @@ -23,34 +19,9 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.0 $ - * Last changed on $Date: 2005/09/28 00:10:08 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: pmcc4_cpld.h,v $ - * Revision 1.0 2005/09/28 00:10:08 rickd - * Initial revision - * - *----------------------------------------------------------------------------- */ - -#if defined(__FreeBSD__) || defined(__NetBSD__) -#include <sys/types.h> -#else -#ifndef __KERNEL__ -#include <sys/types.h> -#else #include <linux/types.h> -#endif -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - /********************************/ /* iSPLD control chip registers */ @@ -117,8 +88,4 @@ extern "C" #define PMCC4_CPLD_INTR_CMT_3 0x04 #define PMCC4_CPLD_INTR_CMT_4 0x08 -#ifdef __cplusplus -} -#endif - #endif /* _INC_PMCC4_CPLD_H_ */ diff --git a/drivers/staging/cxt1e1/pmcc4_defs.h b/drivers/staging/cxt1e1/pmcc4_defs.h index a39505f45c2..83ceae4324b 100644 --- a/drivers/staging/cxt1e1/pmcc4_defs.h +++ b/drivers/staging/cxt1e1/pmcc4_defs.h @@ -1,7 +1,3 @@ -/* - * $Id: pmcc4_defs.h,v 1.0 2005/09/28 00:10:09 rickd PMCC4_3_1B $ - */ - #ifndef _INC_PMCC4_DEFS_H_ #define _INC_PMCC4_DEFS_H_ @@ -25,16 +21,6 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.0 $ - * Last changed on $Date: 2005/09/28 00:10:09 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: pmcc4_defs.h,v $ - * Revision 1.0 2005/09/28 00:10:09 rickd - * Initial revision - * - *----------------------------------------------------------------------------- */ diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c index e1f07fabd22..8a7b3a64645 100644 --- a/drivers/staging/cxt1e1/pmcc4_drv.c +++ b/drivers/staging/cxt1e1/pmcc4_drv.c @@ -1,8 +1,3 @@ -/* - * $Id: pmcc4_drv.c,v 3.1 2007/08/15 23:32:17 rickd PMCC4_3_1B $ - */ - - /*----------------------------------------------------------------------------- * pmcc4_drv.c - * @@ -22,74 +17,10 @@ * For further information, contact via email: support@onestopsystems.com * One Stop Systems, Inc. Escondido, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 3.1 $ - * Last changed on $Date: 2007/08/15 23:32:17 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: pmcc4_drv.c,v $ - * Revision 3.1 2007/08/15 23:32:17 rickd - * Use 'if 0' instead of GNU comment delimeter to avoid line wrap induced compiler errors. - * - * Revision 3.0 2007/08/15 22:19:55 rickd - * Correct sizeof() castings and pi->regram to support 64bit compatibility. - * - * Revision 2.10 2006/04/21 00:56:40 rickd - * workqueue files now prefixed with <sbecom> prefix. - * - * Revision 2.9 2005/11/01 19:22:49 rickd - * Add sanity checks against max_port for ioctl functions. - * - * Revision 2.8 2005/10/27 18:59:25 rickd - * Code cleanup. Default channel config to HDLC_FCS16. - * - * Revision 2.7 2005/10/18 18:16:30 rickd - * Further NCOMM code repairs - (1) interrupt matrix usage inconsistent - * for indexing into nciInterrupt[][], code missing double parameters. - * (2) check input of ncomm interrupt registration cardID for correct - * boundary values. - * - * Revision 2.6 2005/10/17 23:55:28 rickd - * Initial port of NCOMM support patches from original work found - * in pmc_c4t1e1 as updated by NCOMM. Ref: CONFIG_SBE_PMCC4_NCOMM. - * Corrected NCOMMs wanpmcC4T1E1_getBaseAddress() to correctly handle - * multiple boards. - * - * Revision 2.5 2005/10/13 23:01:28 rickd - * Correct panic for illegal address reference w/in get_brdinfo on - * first_if/last_if name acquistion under Linux 2.6 - * - * Revision 2.4 2005/10/13 21:20:19 rickd - * Correction of c4_cleanup() wherein next should be acquired before - * ci_t structure is free'd. - * - * Revision 2.3 2005/10/13 19:20:10 rickd - * Correct driver removal cleanup code for multiple boards. - * - * Revision 2.2 2005/10/11 18:34:04 rickd - * New routine added to determine number of ports (comets) on board. - * - * Revision 2.1 2005/10/05 00:48:13 rickd - * Add some RX activation trace code. - * - * Revision 2.0 2005/09/28 00:10:06 rickd - * Implement 2.6 workqueue for TX/RX restart. Correction to - * hardware register boundary checks allows expanded access of MUSYCC. - * Implement new musycc reg&bits namings. - * - *----------------------------------------------------------------------------- */ -char OSSIid_pmcc4_drvc[] = -"@(#)pmcc4_drv.c - $Revision: 3.1 $ (c) Copyright 2002-2007 One Stop Systems, Inc."; - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#if defined (__FreeBSD__) || defined (__NetBSD__) -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/errno.h> -#else #include <linux/types.h> #include "pmcc4_sysdep.h" #include <linux/errno.h> @@ -98,7 +29,6 @@ char OSSIid_pmcc4_drvc[] = #include <linux/timer.h> /* include for timer */ #include <linux/hdlc.h> #include <asm/io.h> -#endif #include "sbecom_inline_linux.h" #include "libsbew.h" diff --git a/drivers/staging/cxt1e1/pmcc4_ioctls.h b/drivers/staging/cxt1e1/pmcc4_ioctls.h index 6b8d65673c7..56a1ee39be1 100644 --- a/drivers/staging/cxt1e1/pmcc4_ioctls.h +++ b/drivers/staging/cxt1e1/pmcc4_ioctls.h @@ -1,6 +1,3 @@ -/* RCSid: $Header: /home/rickd/projects/pmcc4/include/pmcc4_ioctls.h,v 2.0 2005/09/28 00:10:09 rickd PMCC4_3_1B $ - */ - #ifndef _INC_PMCC4_IOCTLS_H_ #define _INC_PMCC4_IOCTLS_H_ @@ -22,19 +19,6 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 2.0 $ - * Last changed on $Date: 2005/09/28 00:10:09 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: pmcc4_ioctls.h,v $ - * Revision 2.0 2005/09/28 00:10:09 rickd - * Add GNU license info. Switch Ioctls to sbe_ioc.h usage. - * - * Revision 1.2 2005/04/28 23:43:03 rickd - * Add RCS tracking heading. - * - *----------------------------------------------------------------------------- */ #include "sbew_ioc.h" diff --git a/drivers/staging/cxt1e1/sbe_bid.h b/drivers/staging/cxt1e1/sbe_bid.h index 1f49b4061fb..abc2e55f62f 100644 --- a/drivers/staging/cxt1e1/sbe_bid.h +++ b/drivers/staging/cxt1e1/sbe_bid.h @@ -1,7 +1,3 @@ -/* - * $Id: sbe_bid.h,v 1.0 2005/09/28 00:10:09 rickd PMCC4_3_1B $ - */ - #ifndef _INC_SBEBID_H_ #define _INC_SBEBID_H_ @@ -24,16 +20,6 @@ * SBE, Inc. San Ramon, California U.S.A. * *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.0 $ - * Last changed on $Date: 2005/09/28 00:10:09 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: sbe_bid.h,v $ - * Revision 1.0 2005/09/28 00:10:09 rickd - * Initial revision - * - *----------------------------------------------------------------------------- */ #define SBE_BID_REG 0x00000000 /* Board ID Register */ diff --git a/drivers/staging/cxt1e1/sbe_promformat.h b/drivers/staging/cxt1e1/sbe_promformat.h index 746f81b15c7..aad411d185f 100644 --- a/drivers/staging/cxt1e1/sbe_promformat.h +++ b/drivers/staging/cxt1e1/sbe_promformat.h @@ -1,7 +1,3 @@ -/* - * $Id: sbe_promformat.h,v 2.2 2005/09/28 00:10:09 rickd PMCC4_3_1B $ - */ - #ifndef _INC_SBE_PROMFORMAT_H_ #define _INC_SBE_PROMFORMAT_H_ @@ -24,19 +20,6 @@ * SBE, Inc. San Ramon, California U.S.A. * *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 2.2 $ - * Last changed on $Date: 2005/09/28 00:10:09 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: sbe_promformat.h,v $ - * Revision 2.2 2005/09/28 00:10:09 rickd - * Add EEPROM sample from C4T1E1 board. - * - * Revision 2.1 2005/05/04 17:18:24 rickd - * Initial CI. - * - *----------------------------------------------------------------------------- */ @@ -85,12 +68,6 @@ * */ -#ifdef __cplusplus -extern "C" -{ -#endif - - #define STRUCT_OFFSET(type, symbol) ((long)&(((type *)0)->symbol)) /*------------------------------------------------------------------------ @@ -150,8 +127,4 @@ extern "C" FLD_TYPE2 fldType2; } PROMFORMAT; -#ifdef __cplusplus -} -#endif - #endif /*** _INC_SBE_PROMFORMAT_H_ ***/ diff --git a/drivers/staging/cxt1e1/sbecom_inline_linux.h b/drivers/staging/cxt1e1/sbecom_inline_linux.h index 9ea2c0c2061..68ed445ab0c 100644 --- a/drivers/staging/cxt1e1/sbecom_inline_linux.h +++ b/drivers/staging/cxt1e1/sbecom_inline_linux.h @@ -1,7 +1,3 @@ -/* - * $Id: sbecom_inline_linux.h,v 1.2 2007/08/15 22:51:35 rickd PMCC4_3_1B $ - */ - #ifndef _INC_SBECOM_INLNX_H_ #define _INC_SBECOM_INLNX_H_ @@ -24,22 +20,6 @@ * For further information, contact via email: support@onestopsystems.com * One Stop Systems, Inc. Escondido, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.2 $ - * Last changed on $Date: 2007/08/15 22:51:35 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: sbecom_inline_linux.h,v $ - * Revision 1.2 2007/08/15 22:51:35 rickd - * Remove duplicate version.h entry. - * - * Revision 1.1 2007/08/15 22:50:29 rickd - * Update linux/config for 2.6.18 and later. - * - * Revision 1.0 2005/09/28 00:10:09 rickd - * Initial revision - * - *----------------------------------------------------------------------------- */ diff --git a/drivers/staging/cxt1e1/sbeproc.h b/drivers/staging/cxt1e1/sbeproc.h index 4aa53f44ec0..e82be6afd1e 100644 --- a/drivers/staging/cxt1e1/sbeproc.h +++ b/drivers/staging/cxt1e1/sbeproc.h @@ -1,7 +1,3 @@ -/* - * $Id: sbeproc.h,v 1.2 2005/10/17 23:55:28 rickd PMCC4_3_1B $ - */ - #ifndef _INC_SBEPROC_H_ #define _INC_SBEPROC_H_ @@ -23,22 +19,6 @@ * For further information, contact via email: support@sbei.com * SBE, Inc. San Ramon, California U.S.A. *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.2 $ - * Last changed on $Date: 2005/10/17 23:55:28 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: sbeproc.h,v $ - * Revision 1.2 2005/10/17 23:55:28 rickd - * sbecom_proc_brd_init() is an declared an __init function. - * - * Revision 1.1 2005/09/28 00:10:09 rickd - * Remove unneeded inclusion of c4_private.h. - * - * Revision 1.0 2005/05/10 22:21:46 rickd - * Initial check-in. - * - *----------------------------------------------------------------------------- */ diff --git a/drivers/staging/cxt1e1/sbew_ioc.h b/drivers/staging/cxt1e1/sbew_ioc.h index 14d371904d1..ce9b15c7189 100644 --- a/drivers/staging/cxt1e1/sbew_ioc.h +++ b/drivers/staging/cxt1e1/sbew_ioc.h @@ -1,7 +1,3 @@ -/* - * $Id: sbew_ioc.h,v 1.0 2005/09/28 00:10:10 rickd PMCC4_3_1B $ - */ - #ifndef _INC_SBEWIOC_H_ #define _INC_SBEWIOC_H_ @@ -24,55 +20,9 @@ * SBE, Inc. San Ramon, California U.S.A. * *----------------------------------------------------------------------------- - * RCS info: - * RCS revision: $Revision: 1.0 $ - * Last changed on $Date: 2005/09/28 00:10:10 $ - * Changed by $Author: rickd $ - *----------------------------------------------------------------------------- - * $Log: sbew_ioc.h,v $ - * Revision 1.0 2005/09/28 00:10:10 rickd - * Initial revision - * - * Revision 1.6 2005/01/11 18:41:01 rickd - * Add BRDADDR_GET Ioctl. - * - * Revision 1.5 2004/09/16 18:55:59 rickd - * Start setting up for generic framer configuration Ioctl by switch - * from tect3_framer_param[] to sbecom_framer_param[]. - * - * Revision 1.4 2004/06/28 17:58:15 rickd - * Rename IOC_TSMAP_[GS] to IOC_TSIOC_[GS] to support need for - * multiple formats of data when setting up TimeSlots. - * - * Revision 1.3 2004/06/22 21:18:13 rickd - * read_vec now() ONLY handles a single common wrt_vec array. - * - * Revision 1.1 2004/06/10 18:11:34 rickd - * Add IID_GET Ioctl reference. - * - * Revision 1.0 2004/06/08 22:59:38 rickd - * Initial revision - * - * Revision 2.0 2004/06/07 17:49:47 rickd - * Initial library release following merge of wanc1t3/wan256 into - * common elements for lib. - * - *----------------------------------------------------------------------------- */ -#ifndef __KERNEL__ -#include <sys/types.h> -#endif -#ifdef SunOS -#include <sys/ioccom.h> -#else #include <linux/ioctl.h> -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif #define SBE_LOCKFILE "/tmp/.sbewan.LCK" @@ -128,9 +78,4 @@ extern "C" #define SBE_IOC_MAXVEC 1 - -#ifdef __cplusplus -} -#endif - #endif /*** _INC_SBEWIOC_H_ ***/ diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c index 0c1c6ca8c37..2c4069fcd98 100644 --- a/drivers/staging/et131x/et131x.c +++ b/drivers/staging/et131x/et131x.c @@ -155,7 +155,6 @@ MODULE_DESCRIPTION("10/100/1000 Base-T Ethernet Driver " #define fMP_ADAPTER_FAIL_SEND_MASK 0x3ff00000 /* Some offsets in PCI config space that are actually used. */ -#define ET1310_PCI_MAX_PYLD 0x4C #define ET1310_PCI_MAC_ADDRESS 0xA4 #define ET1310_PCI_EEPROM_STATUS 0xB2 #define ET1310_PCI_ACK_NACK 0xC0 @@ -178,9 +177,7 @@ MODULE_DESCRIPTION("10/100/1000 Base-T Ethernet Driver " /* RX defines */ #define USE_FBR0 1 - #define FBR_CHUNKS 32 - #define MAX_DESC_PER_RING_RX 1024 /* number of RFDs - default and min */ @@ -195,7 +192,6 @@ MODULE_DESCRIPTION("10/100/1000 Base-T Ethernet Driver " #endif #define NIC_MIN_NUM_RFD 64 - #define NUM_PACKETS_HANDLED 256 #define ALCATEL_MULTICAST_PKT 0x01000000 @@ -303,8 +299,8 @@ struct fbr_lookup { dma_addr_t ring_physaddr; void *mem_virtaddrs[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; dma_addr_t mem_physaddrs[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; - uint64_t real_physaddr; - uint64_t offset; + u64 real_physaddr; + u64 offset; u32 local_full; u32 num_entries; u32 buffsize; @@ -427,7 +423,6 @@ struct tx_ring { int since_irq; }; -/* ADAPTER defines */ /* * Do not change these values: if changed, then change also in respective * TXdma and Rxdma engines @@ -576,8 +571,6 @@ struct et131x_adapter { struct net_device_stats net_stats; }; -/* EEPROM functions */ - static int eeprom_wait_ready(struct pci_dev *pdev, u32 *status) { u32 reg; @@ -795,7 +788,7 @@ static int eeprom_read(struct et131x_adapter *adapter, u32 addr, u8 *pdata) return (status & LBCIF_STATUS_ACK_ERROR) ? -EIO : 0; } -int et131x_init_eeprom(struct et131x_adapter *adapter) +static int et131x_init_eeprom(struct et131x_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; u8 eestatus; @@ -868,7 +861,7 @@ int et131x_init_eeprom(struct et131x_adapter *adapter) * et131x_rx_dma_enable - re-start of Rx_DMA on the ET1310. * @adapter: pointer to our adapter structure */ -void et131x_rx_dma_enable(struct et131x_adapter *adapter) +static void et131x_rx_dma_enable(struct et131x_adapter *adapter) { /* Setup the receive dma configuration register for normal operation */ u32 csr = 0x2000; /* FBR1 enable */ @@ -906,7 +899,7 @@ void et131x_rx_dma_enable(struct et131x_adapter *adapter) * et131x_rx_dma_disable - Stop of Rx_DMA on the ET1310 * @adapter: pointer to our adapter structure */ -void et131x_rx_dma_disable(struct et131x_adapter *adapter) +static void et131x_rx_dma_disable(struct et131x_adapter *adapter) { u32 csr; /* Setup the receive dma configuration register */ @@ -928,7 +921,7 @@ void et131x_rx_dma_disable(struct et131x_adapter *adapter) * * Mainly used after a return to the D0 (full-power) state from a lower state. */ -void et131x_tx_dma_enable(struct et131x_adapter *adapter) +static void et131x_tx_dma_enable(struct et131x_adapter *adapter) { /* Setup the transmit dma configuration register for normal * operation @@ -948,23 +941,10 @@ static inline void add_12bit(u32 *v, int n) } /** - * nic_rx_pkts - Checks the hardware for available packets - * @adapter: pointer to our adapter - * - * Returns rfd, a pointer to our MPRFD. - * - * Checks the hardware for available packets, using completion ring - * If packets are available, it gets an RFD from the recv_list, attaches - * the packet to it, puts the RFD in the RecvPendList, and also returns - * the pointer to the RFD. - */ -/* MAC functions */ - -/** * et1310_config_mac_regs1 - Initialize the first part of MAC regs * @adapter: pointer to our adapter structure */ -void et1310_config_mac_regs1(struct et131x_adapter *adapter) +static void et1310_config_mac_regs1(struct et131x_adapter *adapter) { struct mac_regs __iomem *macregs = &adapter->regs->mac; u32 station1; @@ -1024,7 +1004,7 @@ void et1310_config_mac_regs1(struct et131x_adapter *adapter) * et1310_config_mac_regs2 - Initialize the second part of MAC regs * @adapter: pointer to our adapter structure */ -void et1310_config_mac_regs2(struct et131x_adapter *adapter) +static void et1310_config_mac_regs2(struct et131x_adapter *adapter) { int32_t delay = 0; struct mac_regs __iomem *mac = &adapter->regs->mac; @@ -1105,7 +1085,7 @@ void et1310_config_mac_regs2(struct et131x_adapter *adapter) * * Returns 0 if the device is not in phy coma, 1 if it is in phy coma */ -int et1310_in_phy_coma(struct et131x_adapter *adapter) +static int et1310_in_phy_coma(struct et131x_adapter *adapter) { u32 pmcsr; @@ -1114,15 +1094,13 @@ int et1310_in_phy_coma(struct et131x_adapter *adapter) return ET_PM_PHY_SW_COMA & pmcsr ? 1 : 0; } -void et1310_setup_device_for_multicast(struct et131x_adapter *adapter) +static void et1310_setup_device_for_multicast(struct et131x_adapter *adapter) { struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; - uint32_t nIndex; - uint32_t result; - uint32_t hash1 = 0; - uint32_t hash2 = 0; - uint32_t hash3 = 0; - uint32_t hash4 = 0; + u32 hash1 = 0; + u32 hash2 = 0; + u32 hash3 = 0; + u32 hash4 = 0; u32 pm_csr; /* If ET131X_PACKET_TYPE_MULTICAST is specified, then we provision @@ -1131,10 +1109,13 @@ void et1310_setup_device_for_multicast(struct et131x_adapter *adapter) * driver. */ if (adapter->packet_filter & ET131X_PACKET_TYPE_MULTICAST) { + int i; + /* Loop through our multicast array and set up the device */ - for (nIndex = 0; nIndex < adapter->multicast_addr_count; - nIndex++) { - result = ether_crc(6, adapter->multicast_list[nIndex]); + for (i = 0; i < adapter->multicast_addr_count; i++) { + u32 result; + + result = ether_crc(6, adapter->multicast_list[i]); result = (result & 0x3F800000) >> 23; @@ -1163,7 +1144,7 @@ void et1310_setup_device_for_multicast(struct et131x_adapter *adapter) } } -void et1310_setup_device_for_unicast(struct et131x_adapter *adapter) +static void et1310_setup_device_for_unicast(struct et131x_adapter *adapter) { struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; u32 uni_pf1; @@ -1203,7 +1184,7 @@ void et1310_setup_device_for_unicast(struct et131x_adapter *adapter) } } -void et1310_config_rxmac_regs(struct et131x_adapter *adapter) +static void et1310_config_rxmac_regs(struct et131x_adapter *adapter) { struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; struct phy_device *phydev = adapter->phydev; @@ -1334,7 +1315,7 @@ void et1310_config_rxmac_regs(struct et131x_adapter *adapter) writel(0x9, &rxmac->ctrl); } -void et1310_config_txmac_regs(struct et131x_adapter *adapter) +static void et1310_config_txmac_regs(struct et131x_adapter *adapter) { struct txmac_regs __iomem *txmac = &adapter->regs->txmac; @@ -1348,7 +1329,7 @@ void et1310_config_txmac_regs(struct et131x_adapter *adapter) writel(0x40, &txmac->cf_param); } -void et1310_config_macstat_regs(struct et131x_adapter *adapter) +static void et1310_config_macstat_regs(struct et131x_adapter *adapter) { struct macstat_regs __iomem *macstat = &adapter->regs->macstat; @@ -1422,7 +1403,7 @@ void et1310_config_macstat_regs(struct et131x_adapter *adapter) * * Returns 0 on success, errno on failure (as defined in errno.h) */ -int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr, +static int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr, u8 reg, u16 *value) { struct mac_regs __iomem *mac = &adapter->regs->mac; @@ -1478,7 +1459,7 @@ int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr, return status; } -int et131x_mii_read(struct et131x_adapter *adapter, u8 reg, u16 *value) +static int et131x_mii_read(struct et131x_adapter *adapter, u8 reg, u16 *value) { struct phy_device *phydev = adapter->phydev; @@ -1498,7 +1479,7 @@ int et131x_mii_read(struct et131x_adapter *adapter, u8 reg, u16 *value) * * Return 0 on success, errno on failure (as defined in errno.h) */ -int et131x_mii_write(struct et131x_adapter *adapter, u8 reg, u16 value) +static int et131x_mii_write(struct et131x_adapter *adapter, u8 reg, u16 value) { struct mac_regs __iomem *mac = &adapter->regs->mac; struct phy_device *phydev = adapter->phydev; @@ -1564,8 +1545,9 @@ int et131x_mii_write(struct et131x_adapter *adapter, u8 reg, u16 value) } /* Still used from _mac for BIT_READ */ -void et1310_phy_access_mii_bit(struct et131x_adapter *adapter, u16 action, - u16 regnum, u16 bitnum, u8 *value) +static void et1310_phy_access_mii_bit(struct et131x_adapter *adapter, + u16 action, u16 regnum, u16 bitnum, + u8 *value) { u16 reg; u16 mask = 0x0001 << bitnum; @@ -1591,7 +1573,7 @@ void et1310_phy_access_mii_bit(struct et131x_adapter *adapter, u16 action, } } -void et1310_config_flow_control(struct et131x_adapter *adapter) +static void et1310_config_flow_control(struct et131x_adapter *adapter) { struct phy_device *phydev = adapter->phydev; @@ -1632,7 +1614,7 @@ void et1310_config_flow_control(struct et131x_adapter *adapter) * et1310_update_macstat_host_counters - Update the local copy of the statistics * @adapter: pointer to the adapter structure */ -void et1310_update_macstat_host_counters(struct et131x_adapter *adapter) +static void et1310_update_macstat_host_counters(struct et131x_adapter *adapter) { struct ce_stats *stats = &adapter->stats; struct macstat_regs __iomem *macstat = @@ -1664,7 +1646,7 @@ void et1310_update_macstat_host_counters(struct et131x_adapter *adapter) * the statistics held in the adapter structure, checking the "wrap" * bit for each counter. */ -void et1310_handle_macstat_interrupt(struct et131x_adapter *adapter) +static void et1310_handle_macstat_interrupt(struct et131x_adapter *adapter) { u32 carry_reg1; u32 carry_reg2; @@ -1714,9 +1696,7 @@ void et1310_handle_macstat_interrupt(struct et131x_adapter *adapter) adapter->stats.tx_collisions += COUNTER_WRAP_12_BIT; } -/* PHY functions */ - -int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg) +static int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg) { struct net_device *netdev = bus->priv; struct et131x_adapter *adapter = netdev_priv(netdev); @@ -1731,7 +1711,7 @@ int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg) return value; } -int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 value) +static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 value) { struct net_device *netdev = bus->priv; struct et131x_adapter *adapter = netdev_priv(netdev); @@ -1739,7 +1719,7 @@ int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 value) return et131x_mii_write(adapter, reg, value); } -int et131x_mdio_reset(struct mii_bus *bus) +static int et131x_mdio_reset(struct mii_bus *bus) { struct net_device *netdev = bus->priv; struct et131x_adapter *adapter = netdev_priv(netdev); @@ -1759,7 +1739,7 @@ int et131x_mdio_reset(struct mii_bus *bus) * Can't you see that this code processed * Phy power, phy power.. */ -void et1310_phy_power_down(struct et131x_adapter *adapter, bool down) +static void et1310_phy_power_down(struct et131x_adapter *adapter, bool down) { u16 data; @@ -1775,7 +1755,7 @@ void et1310_phy_power_down(struct et131x_adapter *adapter, bool down) * @adapter: pointer to our private adapter structure * */ -void et131x_xcvr_init(struct et131x_adapter *adapter) +static void et131x_xcvr_init(struct et131x_adapter *adapter) { u16 imr; u16 isr; @@ -1822,7 +1802,7 @@ void et131x_xcvr_init(struct et131x_adapter *adapter) * * Used to configure the global registers on the JAGCore */ -void et131x_configure_global_regs(struct et131x_adapter *adapter) +static void et131x_configure_global_regs(struct et131x_adapter *adapter) { struct global_regs __iomem *regs = &adapter->regs->global; @@ -1863,13 +1843,11 @@ void et131x_configure_global_regs(struct et131x_adapter *adapter) writel(0, ®s->watchdog_timer); } -/* PM functions */ - /** * et131x_config_rx_dma_regs - Start of Rx_DMA init sequence * @adapter: pointer to our adapter structure */ -void et131x_config_rx_dma_regs(struct et131x_adapter *adapter) +static void et131x_config_rx_dma_regs(struct et131x_adapter *adapter) { struct rxdma_regs __iomem *rx_dma = &adapter->regs->rxdma; struct rx_ring *rx_local = &adapter->rx_ring; @@ -1987,7 +1965,7 @@ void et131x_config_rx_dma_regs(struct et131x_adapter *adapter) * Configure the transmit engine with the ring buffers we have created * and prepare it for use. */ -void et131x_config_tx_dma_regs(struct et131x_adapter *adapter) +static void et131x_config_tx_dma_regs(struct et131x_adapter *adapter) { struct txdma_regs __iomem *txdma = &adapter->regs->txdma; @@ -2017,7 +1995,7 @@ void et131x_config_tx_dma_regs(struct et131x_adapter *adapter) * * Returns 0 on success, errno on failure (as defined in errno.h) */ -void et131x_adapter_setup(struct et131x_adapter *adapter) +static void et131x_adapter_setup(struct et131x_adapter *adapter) { /* Configure the JAGCore */ et131x_configure_global_regs(adapter); @@ -2044,7 +2022,7 @@ void et131x_adapter_setup(struct et131x_adapter *adapter) * et131x_soft_reset - Issue a soft reset to the hardware, complete for ET1310 * @adapter: pointer to our private adapter structure */ -void et131x_soft_reset(struct et131x_adapter *adapter) +static void et131x_soft_reset(struct et131x_adapter *adapter) { /* Disable MAC Core */ writel(0xc00f0000, &adapter->regs->mac.cfg1); @@ -2062,7 +2040,7 @@ void et131x_soft_reset(struct et131x_adapter *adapter) * Enable the appropriate interrupts on the ET131x according to our * configuration */ -void et131x_enable_interrupts(struct et131x_adapter *adapter) +static void et131x_enable_interrupts(struct et131x_adapter *adapter) { u32 mask; @@ -2082,7 +2060,7 @@ void et131x_enable_interrupts(struct et131x_adapter *adapter) * * Block all interrupts from the et131x device at the device itself */ -void et131x_disable_interrupts(struct et131x_adapter *adapter) +static void et131x_disable_interrupts(struct et131x_adapter *adapter) { /* Disable all global interrupts */ writel(INT_MASK_DISABLE, &adapter->regs->global.int_mask); @@ -2092,7 +2070,7 @@ void et131x_disable_interrupts(struct et131x_adapter *adapter) * et131x_tx_dma_disable - Stop of Tx_DMA on the ET1310 * @adapter: pointer to our adapter structure */ -void et131x_tx_dma_disable(struct et131x_adapter *adapter) +static void et131x_tx_dma_disable(struct et131x_adapter *adapter) { /* Setup the tramsmit dma configuration register */ writel(ET_TXDMA_CSR_HALT|ET_TXDMA_SNGL_EPKT, @@ -2103,7 +2081,7 @@ void et131x_tx_dma_disable(struct et131x_adapter *adapter) * et131x_enable_txrx - Enable tx/rx queues * @netdev: device to be enabled */ -void et131x_enable_txrx(struct net_device *netdev) +static void et131x_enable_txrx(struct net_device *netdev) { struct et131x_adapter *adapter = netdev_priv(netdev); @@ -2123,7 +2101,7 @@ void et131x_enable_txrx(struct net_device *netdev) * et131x_disable_txrx - Disable tx/rx queues * @netdev: device to be disabled */ -void et131x_disable_txrx(struct net_device *netdev) +static void et131x_disable_txrx(struct net_device *netdev) { struct et131x_adapter *adapter = netdev_priv(netdev); @@ -2142,7 +2120,7 @@ void et131x_disable_txrx(struct net_device *netdev) * et131x_init_send - Initialize send data structures * @adapter: pointer to our private adapter structure */ -void et131x_init_send(struct et131x_adapter *adapter) +static void et131x_init_send(struct et131x_adapter *adapter) { struct tcb *tcb; u32 ct; @@ -2192,7 +2170,7 @@ void et131x_init_send(struct et131x_adapter *adapter) * indicating linkup status, call the MPDisablePhyComa routine to * restore JAGCore and gigE PHY */ -void et1310_enable_phy_coma(struct et131x_adapter *adapter) +static void et1310_enable_phy_coma(struct et131x_adapter *adapter) { unsigned long flags; u32 pmcsr; @@ -2231,7 +2209,7 @@ void et1310_enable_phy_coma(struct et131x_adapter *adapter) * et1310_disable_phy_coma - Disable the Phy Coma Mode * @adapter: pointer to our adapter structure */ -void et1310_disable_phy_coma(struct et131x_adapter *adapter) +static void et1310_disable_phy_coma(struct et131x_adapter *adapter) { u32 pmcsr; @@ -2269,8 +2247,6 @@ void et1310_disable_phy_coma(struct et131x_adapter *adapter) et131x_enable_txrx(adapter->netdev); } -/* RX functions */ - static inline u32 bump_free_buff_ring(u32 *free_buff_ring, u32 limit) { u32 tmp_free_buff_ring = *free_buff_ring; @@ -2296,16 +2272,14 @@ static inline u32 bump_free_buff_ring(u32 *free_buff_ring, u32 limit) * @offset: pointer to the offset variable * @mask: correct mask */ -void et131x_align_allocated_memory(struct et131x_adapter *adapter, - uint64_t *phys_addr, - uint64_t *offset, uint64_t mask) +static void et131x_align_allocated_memory(struct et131x_adapter *adapter, + u64 *phys_addr, u64 *offset, + u64 mask) { - uint64_t new_addr; + u64 new_addr = *phys_addr & ~mask; *offset = 0; - new_addr = *phys_addr & ~mask; - if (new_addr != *phys_addr) { /* Move to next aligned block */ new_addr += mask + 1; @@ -2325,7 +2299,7 @@ void et131x_align_allocated_memory(struct et131x_adapter *adapter, * Allocates Free buffer ring 1 for sure, free buffer ring 0 if required, * and the Packet Status Ring. */ -int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) +static int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) { u32 i, j; u32 bufsize; @@ -2454,8 +2428,8 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) rx_ring->fbr[1]->offset); #endif for (i = 0; i < (rx_ring->fbr[0]->num_entries / FBR_CHUNKS); i++) { - u64 fbr1_offset; u64 fbr1_tmp_physaddr; + u64 fbr1_offset; u32 fbr1_align; /* This code allocates an area of memory big enough for N @@ -2520,8 +2494,8 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) #ifdef USE_FBR0 /* Same for FBR0 (if in use) */ for (i = 0; i < (rx_ring->fbr[1]->num_entries / FBR_CHUNKS); i++) { - u64 fbr0_offset; u64 fbr0_tmp_physaddr; + u64 fbr0_offset; fbr_chunksize = ((FBR_CHUNKS + 1) * rx_ring->fbr[1]->buffsize) - 1; @@ -2629,7 +2603,7 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) * et131x_rx_dma_memory_free - Free all memory allocated within this module. * @adapter: pointer to our private adapter structure */ -void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) +static void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) { u32 index; u32 bufsize; @@ -2774,7 +2748,7 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) * * Returns 0 on success and errno on failure (as defined in errno.h) */ -int et131x_init_recv(struct et131x_adapter *adapter) +static int et131x_init_recv(struct et131x_adapter *adapter) { int status = -ENOMEM; struct rfd *rfd = NULL; @@ -2824,7 +2798,7 @@ int et131x_init_recv(struct et131x_adapter *adapter) * et131x_set_rx_dma_timer - Set the heartbeat timer according to line rate. * @adapter: pointer to our adapter structure */ -void et131x_set_rx_dma_timer(struct et131x_adapter *adapter) +static void et131x_set_rx_dma_timer(struct et131x_adapter *adapter) { struct phy_device *phydev = adapter->phydev; @@ -2918,6 +2892,17 @@ static void nic_return_rfd(struct et131x_adapter *adapter, struct rfd *rfd) WARN_ON(rx_local->num_ready_recv > rx_local->num_rfd); } +/** + * nic_rx_pkts - Checks the hardware for available packets + * @adapter: pointer to our adapter + * + * Returns rfd, a pointer to our MPRFD. + * + * Checks the hardware for available packets, using completion ring + * If packets are available, it gets an RFD from the recv_list, attaches + * the packet to it, puts the RFD in the RecvPendList, and also returns + * the pointer to the RFD. + */ static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter) { struct rx_ring *rx_local = &adapter->rx_ring; @@ -3139,7 +3124,7 @@ static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter) * * Assumption, Rcv spinlock has been acquired. */ -void et131x_handle_recv_interrupt(struct et131x_adapter *adapter) +static void et131x_handle_recv_interrupt(struct et131x_adapter *adapter) { struct rfd *rfd = NULL; u32 count = 0; @@ -3188,8 +3173,6 @@ void et131x_handle_recv_interrupt(struct et131x_adapter *adapter) adapter->rx_ring.unfinished_receives = false; } -/* TX functions */ - /** * et131x_tx_dma_memory_alloc * @adapter: pointer to our private adapter structure @@ -3202,7 +3185,7 @@ void et131x_handle_recv_interrupt(struct et131x_adapter *adapter) * memory. The device will update the "status" in memory each time it xmits a * packet. */ -int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) +static int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) { int desc_size = 0; struct tx_ring *tx_ring = &adapter->tx_ring; @@ -3256,7 +3239,7 @@ int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) * * Returns 0 on success and errno on failure (as defined in errno.h). */ -void et131x_tx_dma_memory_free(struct et131x_adapter *adapter) +static void et131x_tx_dma_memory_free(struct et131x_adapter *adapter) { int desc_size = 0; @@ -3578,7 +3561,7 @@ static int send_packet(struct sk_buff *skb, struct et131x_adapter *adapter) * * Return 0 in almost all cases; non-zero value in extreme hard failure only */ -int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev) +static int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev) { int status = 0; struct et131x_adapter *adapter = netdev_priv(netdev); @@ -3696,7 +3679,7 @@ static inline void free_send_packet(struct et131x_adapter *adapter, * * Assumption - Send spinlock has been acquired */ -void et131x_free_busy_send_packets(struct et131x_adapter *adapter) +static void et131x_free_busy_send_packets(struct et131x_adapter *adapter) { struct tcb *tcb; unsigned long flags; @@ -3743,7 +3726,7 @@ void et131x_free_busy_send_packets(struct et131x_adapter *adapter) * * Assumption - Send spinlock has been acquired */ -void et131x_handle_send_interrupt(struct et131x_adapter *adapter) +static void et131x_handle_send_interrupt(struct et131x_adapter *adapter) { unsigned long flags; u32 serviced; @@ -3798,8 +3781,6 @@ void et131x_handle_send_interrupt(struct et131x_adapter *adapter) spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); } -/* ETHTOOL functions */ - static int et131x_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { @@ -3965,18 +3946,16 @@ static struct ethtool_ops et131x_ethtool_ops = { .get_link = ethtool_op_get_link, }; -void et131x_set_ethtool_ops(struct net_device *netdev) +static void et131x_set_ethtool_ops(struct net_device *netdev) { SET_ETHTOOL_OPS(netdev, &et131x_ethtool_ops); } -/* PCI functions */ - /** * et131x_hwaddr_init - set up the MAC Address on the ET1310 * @adapter: pointer to our private adapter structure */ -void et131x_hwaddr_init(struct et131x_adapter *adapter) +static void et131x_hwaddr_init(struct et131x_adapter *adapter) { /* If have our default mac from init and no mac address from * EEPROM then we need to generate the last octet and set it on the @@ -4022,24 +4001,31 @@ void et131x_hwaddr_init(struct et131x_adapter *adapter) static int et131x_pci_init(struct et131x_adapter *adapter, struct pci_dev *pdev) { - int i; - u8 max_payload; - u8 read_size_reg; + int cap = pci_pcie_cap(pdev); + u16 max_payload; + u16 ctl; + int i, rc; - if (et131x_init_eeprom(adapter) < 0) - return -EIO; + rc = et131x_init_eeprom(adapter); + if (rc < 0) + goto out; + if (!cap) { + dev_err(&pdev->dev, "Missing PCIe capabilities\n"); + goto err_out; + } + /* Let's set up the PORT LOGIC Register. First we need to know what * the max_payload_size is */ - if (pci_read_config_byte(pdev, ET1310_PCI_MAX_PYLD, &max_payload)) { + if (pci_read_config_word(pdev, cap + PCI_EXP_DEVCAP, &max_payload)) { dev_err(&pdev->dev, "Could not read PCI config space for Max Payload Size\n"); - return -EIO; + goto err_out; } /* Program the Ack/Nak latency and replay timers */ - max_payload &= 0x07; /* Only the lower 3 bits are valid */ + max_payload &= 0x07; if (max_payload < 2) { static const u16 acknak[2] = { 0x76, 0xD0 }; @@ -4049,13 +4035,13 @@ static int et131x_pci_init(struct et131x_adapter *adapter, acknak[max_payload])) { dev_err(&pdev->dev, "Could not write PCI config space for ACK/NAK\n"); - return -EIO; + goto err_out; } if (pci_write_config_word(pdev, ET1310_PCI_REPLAY, replay[max_payload])) { dev_err(&pdev->dev, "Could not write PCI config space for Replay Timer\n"); - return -EIO; + goto err_out; } } @@ -4065,23 +4051,22 @@ static int et131x_pci_init(struct et131x_adapter *adapter, if (pci_write_config_byte(pdev, ET1310_PCI_L0L1LATENCY, 0x11)) { dev_err(&pdev->dev, "Could not write PCI config space for Latency Timers\n"); - return -EIO; + goto err_out; } /* Change the max read size to 2k */ - if (pci_read_config_byte(pdev, 0x51, &read_size_reg)) { + if (pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl)) { dev_err(&pdev->dev, "Could not read PCI config space for Max read size\n"); - return -EIO; + goto err_out; } - read_size_reg &= 0x8f; - read_size_reg |= 0x40; + ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | ( 0x04 << 12); - if (pci_write_config_byte(pdev, 0x51, read_size_reg)) { + if (pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl)) { dev_err(&pdev->dev, "Could not write PCI config space for Max read size\n"); - return -EIO; + goto err_out; } /* Get MAC address from config space if an eeprom exists, otherwise @@ -4096,11 +4081,15 @@ static int et131x_pci_init(struct et131x_adapter *adapter, if (pci_read_config_byte(pdev, ET1310_PCI_MAC_ADDRESS + i, adapter->rom_addr + i)) { dev_err(&pdev->dev, "Could not read PCI config space for MAC address\n"); - return -EIO; + goto err_out; } } memcpy(adapter->addr, adapter->rom_addr, ETH_ALEN); - return 0; +out: + return rc; +err_out: + rc = -EIO; + goto out; } /** @@ -4110,7 +4099,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter, * The routine called when the error timer expires, to track the number of * recurring errors. */ -void et131x_error_timer_handler(unsigned long data) +static void et131x_error_timer_handler(unsigned long data) { struct et131x_adapter *adapter = (struct et131x_adapter *) data; struct phy_device *phydev = adapter->phydev; @@ -4153,7 +4142,7 @@ void et131x_error_timer_handler(unsigned long data) * * Allocate all the memory blocks for send, receive and others. */ -int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) +static int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) { int status; @@ -4188,7 +4177,7 @@ int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) * et131x_adapter_memory_free - Free all memory allocated for use by Tx & Rx * @adapter: pointer to our private adapter structure */ -void et131x_adapter_memory_free(struct et131x_adapter *adapter) +static void et131x_adapter_memory_free(struct et131x_adapter *adapter) { /* Free DMA memory */ et131x_tx_dma_memory_free(adapter); @@ -4364,10 +4353,6 @@ static struct et131x_adapter *et131x_adapter_init(struct net_device *netdev, adapter->pdev = pci_dev_get(pdev); adapter->netdev = netdev; - /* Do the same for the netdev struct */ - netdev->irq = pdev->irq; - netdev->base_addr = pci_resource_start(pdev, 0); - /* Initialize spinlocks here */ spin_lock_init(&adapter->lock); spin_lock_init(&adapter->tcb_send_qlock); @@ -4400,6 +4385,7 @@ static void __devexit et131x_pci_remove(struct pci_dev *pdev) struct et131x_adapter *adapter = netdev_priv(netdev); unregister_netdev(netdev); + phy_disconnect(adapter->phydev); mdiobus_unregister(adapter->mii_bus); kfree(adapter->mii_bus->irq); mdiobus_free(adapter->mii_bus); @@ -4417,7 +4403,7 @@ static void __devexit et131x_pci_remove(struct pci_dev *pdev) * et131x_up - Bring up a device for use. * @netdev: device to be opened */ -void et131x_up(struct net_device *netdev) +static void et131x_up(struct net_device *netdev) { struct et131x_adapter *adapter = netdev_priv(netdev); @@ -4429,7 +4415,7 @@ void et131x_up(struct net_device *netdev) * et131x_down - Bring down the device * @netdev: device to be broght down */ -void et131x_down(struct net_device *netdev) +static void et131x_down(struct net_device *netdev) { struct et131x_adapter *adapter = netdev_priv(netdev); @@ -4475,8 +4461,6 @@ static SIMPLE_DEV_PM_OPS(et131x_pm_ops, et131x_suspend, et131x_resume); #define ET131X_PM_OPS NULL #endif -/* ISR functions */ - /** * et131x_isr - The Interrupt Service Routine for the driver. * @irq: the IRQ on which the interrupt was received. @@ -4573,7 +4557,7 @@ out: * scheduled to run in a deferred context by the ISR. This is where the ISR's * work actually gets done. */ -void et131x_isr_handler(struct work_struct *work) +static void et131x_isr_handler(struct work_struct *work) { struct et131x_adapter *adapter = container_of(work, struct et131x_adapter, task); @@ -4774,8 +4758,6 @@ void et131x_isr_handler(struct work_struct *work) et131x_enable_interrupts(adapter); } -/* NETDEV functions */ - /** * et131x_stats - Return the current device statistics. * @netdev: device whose stats are being queried @@ -4829,10 +4811,12 @@ static struct net_device_stats *et131x_stats(struct net_device *netdev) * * Returns 0 on success, errno on failure (as defined in errno.h) */ -int et131x_open(struct net_device *netdev) +static int et131x_open(struct net_device *netdev) { - int result = 0; struct et131x_adapter *adapter = netdev_priv(netdev); + struct pci_dev *pdev = adapter->pdev; + unsigned int irq = pdev->irq; + int result; /* Start the timer to track NIC errors */ init_timer(&adapter->error_timer); @@ -4841,12 +4825,9 @@ int et131x_open(struct net_device *netdev) adapter->error_timer.data = (unsigned long)adapter; add_timer(&adapter->error_timer); - /* Register our IRQ */ - result = request_irq(netdev->irq, et131x_isr, IRQF_SHARED, - netdev->name, netdev); + result = request_irq(irq, et131x_isr, IRQF_SHARED, netdev->name, netdev); if (result) { - dev_err(&adapter->pdev->dev, "could not register IRQ %d\n", - netdev->irq); + dev_err(&pdev->dev, "could not register IRQ %d\n", irq); return result; } @@ -4863,14 +4844,14 @@ int et131x_open(struct net_device *netdev) * * Returns 0 on success, errno on failure (as defined in errno.h) */ -int et131x_close(struct net_device *netdev) +static int et131x_close(struct net_device *netdev) { struct et131x_adapter *adapter = netdev_priv(netdev); et131x_down(netdev); adapter->flags &= ~fMP_ADAPTER_INTERRUPT_IN_USE; - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); /* Stop the error timer */ return del_timer_sync(&adapter->error_timer); @@ -4905,8 +4886,8 @@ static int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, */ static int et131x_set_packet_filter(struct et131x_adapter *adapter) { + int filter = adapter->packet_filter; int status = 0; - uint32_t filter = adapter->packet_filter; u32 ctrl; u32 pf_ctrl; @@ -4968,7 +4949,7 @@ static int et131x_set_packet_filter(struct et131x_adapter *adapter) static void et131x_multicast(struct net_device *netdev) { struct et131x_adapter *adapter = netdev_priv(netdev); - uint32_t packet_filter = 0; + int packet_filter; unsigned long flags; struct netdev_hw_addr *ha; int i; @@ -5249,40 +5230,6 @@ static const struct net_device_ops et131x_netdev_ops = { }; /** - * et131x_device_alloc - * - * Returns pointer to the allocated and initialized net_device struct for - * this device. - * - * Create instances of net_device and wl_private for the new adapter and - * register the device's entry points in the net_device structure. - */ -struct net_device *et131x_device_alloc(void) -{ - struct net_device *netdev; - - /* Alloc net_device and adapter structs */ - netdev = alloc_etherdev(sizeof(struct et131x_adapter)); - - if (!netdev) { - printk(KERN_ERR "et131x: Alloc of net_device struct failed\n"); - return NULL; - } - - /* - * Setup the function registration table (and other data) for a - * net_device - */ - netdev->watchdog_timeo = ET131X_TX_TIMEOUT; - netdev->netdev_ops = &et131x_netdev_ops; - - /* Poll? */ - /* netdev->poll = &et131x_poll; */ - /* netdev->poll_controller = &et131x_poll_controller; */ - return netdev; -} - -/** * et131x_pci_setup - Perform device initialization * @pdev: a pointer to the device's pci_dev structure * @ent: this device's entry in the pci_device_id table @@ -5297,24 +5244,26 @@ struct net_device *et131x_device_alloc(void) static int __devinit et131x_pci_setup(struct pci_dev *pdev, const struct pci_device_id *ent) { - int result; struct net_device *netdev; struct et131x_adapter *adapter; + int rc; int ii; - result = pci_enable_device(pdev); - if (result) { + rc = pci_enable_device(pdev); + if (rc < 0) { dev_err(&pdev->dev, "pci_enable_device() failed\n"); - goto err_out; + goto out; } /* Perform some basic PCI checks */ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "Can't find PCI device's base address\n"); + rc = -ENODEV; goto err_disable; } - if (pci_request_regions(pdev, DRIVER_NAME)) { + rc = pci_request_regions(pdev, DRIVER_NAME); + if (rc < 0) { dev_err(&pdev->dev, "Can't get PCI resources\n"); goto err_disable; } @@ -5323,46 +5272,50 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev, /* Check the DMA addressing support of this device */ if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - result = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - if (result) { + rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); + if (rc < 0) { dev_err(&pdev->dev, "Unable to obtain 64 bit DMA for consistent allocations\n"); goto err_release_res; } } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { - result = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (result) { + rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (rc < 0) { dev_err(&pdev->dev, "Unable to obtain 32 bit DMA for consistent allocations\n"); goto err_release_res; } } else { dev_err(&pdev->dev, "No usable DMA addressing method\n"); - result = -EIO; + rc = -EIO; goto err_release_res; } /* Allocate netdev and private adapter structs */ - netdev = et131x_device_alloc(); + netdev = alloc_etherdev(sizeof(struct et131x_adapter)); if (!netdev) { dev_err(&pdev->dev, "Couldn't alloc netdev struct\n"); - result = -ENOMEM; + rc = -ENOMEM; goto err_release_res; } + netdev->watchdog_timeo = ET131X_TX_TIMEOUT; + netdev->netdev_ops = &et131x_netdev_ops; + SET_NETDEV_DEV(netdev, &pdev->dev); et131x_set_ethtool_ops(netdev); adapter = et131x_adapter_init(netdev, pdev); - /* Initialise the PCI setup for the device */ - et131x_pci_init(adapter, pdev); + rc = et131x_pci_init(adapter, pdev); + if (rc < 0) + goto err_free_dev; /* Map the bus-relative registers to system virtual memory */ adapter->regs = pci_ioremap_bar(pdev, 0); if (!adapter->regs) { dev_err(&pdev->dev, "Cannot map device registers\n"); - result = -ENOMEM; + rc = -ENOMEM; goto err_free_dev; } @@ -5376,8 +5329,8 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev, et131x_disable_interrupts(adapter); /* Allocate DMA memory */ - result = et131x_adapter_memory_alloc(adapter); - if (result) { + rc = et131x_adapter_memory_alloc(adapter); + if (rc < 0) { dev_err(&pdev->dev, "Could not alloc adapater memory (DMA)\n"); goto err_iounmap; } @@ -5395,6 +5348,8 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev, adapter->boot_coma = 0; et1310_disable_phy_coma(adapter); + rc = -ENOMEM; + /* Setup the mii_bus struct */ adapter->mii_bus = mdiobus_alloc(); if (!adapter->mii_bus) { @@ -5418,13 +5373,14 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev, for (ii = 0; ii < PHY_MAX_ADDR; ii++) adapter->mii_bus->irq[ii] = PHY_POLL; - if (mdiobus_register(adapter->mii_bus)) { + rc = mdiobus_register(adapter->mii_bus); + if (rc < 0) { dev_err(&pdev->dev, "failed to register MII bus\n"); - mdiobus_free(adapter->mii_bus); goto err_mdio_free_irq; } - if (et131x_mii_probe(netdev)) { + rc = et131x_mii_probe(netdev); + if (rc < 0) { dev_err(&pdev->dev, "failed to probe MII bus\n"); goto err_mdio_unregister; } @@ -5440,10 +5396,10 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev, */ /* Register the net_device struct with the Linux network layer */ - result = register_netdev(netdev); - if (result != 0) { + rc = register_netdev(netdev); + if (rc < 0) { dev_err(&pdev->dev, "register_netdev() failed\n"); - goto err_mdio_unregister; + goto err_phy_disconnect; } /* Register the net_device struct with the PCI subsystem. Save a copy @@ -5451,10 +5407,11 @@ static int __devinit et131x_pci_setup(struct pci_dev *pdev, * been initialized, just in case it needs to be quickly restored. */ pci_set_drvdata(pdev, netdev); - pci_save_state(adapter->pdev); - - return result; +out: + return rc; +err_phy_disconnect: + phy_disconnect(adapter->phydev); err_mdio_unregister: mdiobus_unregister(adapter->mii_bus); err_mdio_free_irq: @@ -5472,8 +5429,7 @@ err_release_res: pci_release_regions(pdev); err_disable: pci_disable_device(pdev); -err_out: - return result; + goto out; } static DEFINE_PCI_DEVICE_TABLE(et131x_pci_table) = { diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c index c263284ddc0..cf47a5d191f 100644 --- a/drivers/staging/frontier/tranzport.c +++ b/drivers/staging/frontier/tranzport.c @@ -199,7 +199,7 @@ static void usb_tranzport_abort_transfers(struct usb_tranzport *dev) struct usb_interface *intf = to_usb_interface(dev); \ struct usb_tranzport *t = usb_get_intfdata(intf); \ unsigned long temp; \ - if (strict_strtoul(buf, 10, &temp)) \ + if (kstrtoul(buf, 10, &temp)) \ return -EINVAL; \ t->value = temp; \ return count; \ diff --git a/drivers/staging/gma500/Kconfig b/drivers/staging/gma500/Kconfig index bfe2166acda..c7a2b3bc0a1 100644 --- a/drivers/staging/gma500/Kconfig +++ b/drivers/staging/gma500/Kconfig @@ -1,6 +1,6 @@ config DRM_PSB tristate "Intel GMA5/600 KMS Framebuffer" - depends on DRM && PCI && X86 + depends on DRM && PCI && X86 && BROKEN select FB_CFB_COPYAREA select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT diff --git a/drivers/staging/gma500/power.c b/drivers/staging/gma500/power.c index 436fe9733b1..40825703833 100644 --- a/drivers/staging/gma500/power.c +++ b/drivers/staging/gma500/power.c @@ -266,7 +266,7 @@ bool gma_power_begin(struct drm_device *dev, bool force_on) ret = gma_resume_pci(dev->pdev); if (ret == 0) { /* FIXME: we want to defer this for Medfield/Oaktrail */ - gma_resume_display(dev); + gma_resume_display(dev->pdev); psb_irq_preinstall(dev); psb_irq_postinstall(dev); pm_runtime_get(&dev->pdev->dev); diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig index 072185ebe95..60ac479a290 100644 --- a/drivers/staging/hv/Kconfig +++ b/drivers/staging/hv/Kconfig @@ -3,15 +3,3 @@ config HYPERV_STORAGE depends on HYPERV && SCSI help Select this option to enable the Hyper-V virtual storage driver. - -config HYPERV_NET - tristate "Microsoft Hyper-V virtual network driver" - depends on HYPERV && NET - help - Select this option to enable the Hyper-V virtual network driver. - -config HYPERV_MOUSE - tristate "Microsoft Hyper-V mouse driver" - depends on HYPERV && HID - help - Select this option to enable the Hyper-V mouse driver. diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile index 0f55ceee919..af95a6b7e43 100644 --- a/drivers/staging/hv/Makefile +++ b/drivers/staging/hv/Makefile @@ -1,6 +1,3 @@ obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o -obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o -obj-$(CONFIG_HYPERV_MOUSE) += hv_mouse.o hv_storvsc-y := storvsc_drv.o -hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO index ed4d63619df..dea7d92dfdc 100644 --- a/drivers/staging/hv/TODO +++ b/drivers/staging/hv/TODO @@ -1,7 +1,5 @@ TODO: - - audit the network driver - audit the scsi driver Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>, -Hank Janssen <hjanssen@microsoft.com>, Haiyang Zhang <haiyangz@microsoft.com>, -K. Y. Srinivasan <kys@microsoft.com> +Haiyang Zhang <haiyangz@microsoft.com>, and K. Y. Srinivasan <kys@microsoft.com> diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c deleted file mode 100644 index ccd39c70c52..00000000000 --- a/drivers/staging/hv/hv_mouse.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Copyright (c) 2009, Citrix Systems, Inc. - * Copyright (c) 2010, Microsoft Corporation. - * Copyright (c) 2011, Novell Inc. - * - * 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 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. - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/workqueue.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/input.h> -#include <linux/hid.h> -#include <linux/hiddev.h> -#include <linux/hyperv.h> - - -struct hv_input_dev_info { - unsigned int size; - unsigned short vendor; - unsigned short product; - unsigned short version; - unsigned short reserved[11]; -}; - -/* The maximum size of a synthetic input message. */ -#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16 - -/* - * Current version - * - * History: - * Beta, RC < 2008/1/22 1,0 - * RC > 2008/1/22 2,0 - */ -#define SYNTHHID_INPUT_VERSION_MAJOR 2 -#define SYNTHHID_INPUT_VERSION_MINOR 0 -#define SYNTHHID_INPUT_VERSION (SYNTHHID_INPUT_VERSION_MINOR | \ - (SYNTHHID_INPUT_VERSION_MAJOR << 16)) - - -#pragma pack(push, 1) -/* - * Message types in the synthetic input protocol - */ -enum synthhid_msg_type { - SYNTH_HID_PROTOCOL_REQUEST, - SYNTH_HID_PROTOCOL_RESPONSE, - SYNTH_HID_INITIAL_DEVICE_INFO, - SYNTH_HID_INITIAL_DEVICE_INFO_ACK, - SYNTH_HID_INPUT_REPORT, - SYNTH_HID_MAX -}; - -/* - * Basic message structures. - */ -struct synthhid_msg_hdr { - enum synthhid_msg_type type; - u32 size; -}; - -struct synthhid_msg { - struct synthhid_msg_hdr header; - char data[1]; /* Enclosed message */ -}; - -union synthhid_version { - struct { - u16 minor_version; - u16 major_version; - }; - u32 version; -}; - -/* - * Protocol messages - */ -struct synthhid_protocol_request { - struct synthhid_msg_hdr header; - union synthhid_version version_requested; -}; - -struct synthhid_protocol_response { - struct synthhid_msg_hdr header; - union synthhid_version version_requested; - unsigned char approved; -}; - -struct synthhid_device_info { - struct synthhid_msg_hdr header; - struct hv_input_dev_info hid_dev_info; - struct hid_descriptor hid_descriptor; -}; - -struct synthhid_device_info_ack { - struct synthhid_msg_hdr header; - unsigned char reserved; -}; - -struct synthhid_input_report { - struct synthhid_msg_hdr header; - char buffer[1]; -}; - -#pragma pack(pop) - -#define INPUTVSC_SEND_RING_BUFFER_SIZE (10*PAGE_SIZE) -#define INPUTVSC_RECV_RING_BUFFER_SIZE (10*PAGE_SIZE) - -#define NBITS(x) (((x)/BITS_PER_LONG)+1) - -enum pipe_prot_msg_type { - PIPE_MESSAGE_INVALID, - PIPE_MESSAGE_DATA, - PIPE_MESSAGE_MAXIMUM -}; - - -struct pipe_prt_msg { - enum pipe_prot_msg_type type; - u32 size; - char data[1]; -}; - -struct mousevsc_prt_msg { - enum pipe_prot_msg_type type; - u32 size; - union { - struct synthhid_protocol_request request; - struct synthhid_protocol_response response; - struct synthhid_device_info_ack ack; - }; -}; - -/* - * Represents an mousevsc device - */ -struct mousevsc_dev { - struct hv_device *device; - unsigned char init_complete; - struct mousevsc_prt_msg protocol_req; - struct mousevsc_prt_msg protocol_resp; - /* Synchronize the request/response if needed */ - struct completion wait_event; - int dev_info_status; - - struct hid_descriptor *hid_desc; - unsigned char *report_desc; - u32 report_desc_size; - struct hv_input_dev_info hid_dev_info; - int connected; - struct hid_device *hid_device; -}; - - -static struct mousevsc_dev *alloc_input_device(struct hv_device *device) -{ - struct mousevsc_dev *input_dev; - - input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL); - - if (!input_dev) - return NULL; - - input_dev->device = device; - hv_set_drvdata(device, input_dev); - init_completion(&input_dev->wait_event); - - return input_dev; -} - -static void free_input_device(struct mousevsc_dev *device) -{ - kfree(device->hid_desc); - kfree(device->report_desc); - hv_set_drvdata(device->device, NULL); - kfree(device); -} - - -static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, - struct synthhid_device_info *device_info) -{ - int ret = 0; - struct hid_descriptor *desc; - struct mousevsc_prt_msg ack; - - /* Assume success for now */ - input_device->dev_info_status = 0; - - memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info, - sizeof(struct hv_input_dev_info)); - - desc = &device_info->hid_descriptor; - WARN_ON(desc->bLength == 0); - - input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC); - - if (!input_device->hid_desc) - goto cleanup; - - memcpy(input_device->hid_desc, desc, desc->bLength); - - input_device->report_desc_size = desc->desc[0].wDescriptorLength; - if (input_device->report_desc_size == 0) - goto cleanup; - input_device->report_desc = kzalloc(input_device->report_desc_size, - GFP_ATOMIC); - - if (!input_device->report_desc) - goto cleanup; - - memcpy(input_device->report_desc, - ((unsigned char *)desc) + desc->bLength, - desc->desc[0].wDescriptorLength); - - /* Send the ack */ - memset(&ack, 0, sizeof(struct mousevsc_prt_msg)); - - ack.type = PIPE_MESSAGE_DATA; - ack.size = sizeof(struct synthhid_device_info_ack); - - ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK; - ack.ack.header.size = 1; - ack.ack.reserved = 0; - - ret = vmbus_sendpacket(input_device->device->channel, - &ack, - sizeof(struct pipe_prt_msg) - sizeof(unsigned char) + - sizeof(struct synthhid_device_info_ack), - (unsigned long)&ack, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - complete(&input_device->wait_event); - - return; - -cleanup: - kfree(input_device->hid_desc); - input_device->hid_desc = NULL; - - kfree(input_device->report_desc); - input_device->report_desc = NULL; - - input_device->dev_info_status = -1; - complete(&input_device->wait_event); -} - -static void mousevsc_on_receive(struct hv_device *device, - struct vmpacket_descriptor *packet) -{ - struct pipe_prt_msg *pipe_msg; - struct synthhid_msg *hid_msg; - struct mousevsc_dev *input_dev = hv_get_drvdata(device); - struct synthhid_input_report *input_report; - - pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet + - (packet->offset8 << 3)); - - if (pipe_msg->type != PIPE_MESSAGE_DATA) - return; - - hid_msg = (struct synthhid_msg *)&pipe_msg->data[0]; - - switch (hid_msg->header.type) { - case SYNTH_HID_PROTOCOL_RESPONSE: - memcpy(&input_dev->protocol_resp, pipe_msg, - pipe_msg->size + sizeof(struct pipe_prt_msg) - - sizeof(unsigned char)); - complete(&input_dev->wait_event); - break; - - case SYNTH_HID_INITIAL_DEVICE_INFO: - WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info)); - - /* - * Parse out the device info into device attr, - * hid desc and report desc - */ - mousevsc_on_receive_device_info(input_dev, - (struct synthhid_device_info *)&pipe_msg->data[0]); - break; - case SYNTH_HID_INPUT_REPORT: - input_report = - (struct synthhid_input_report *)&pipe_msg->data[0]; - if (!input_dev->init_complete) - break; - hid_input_report(input_dev->hid_device, - HID_INPUT_REPORT, input_report->buffer, - input_report->header.size, 1); - break; - default: - pr_err("unsupported hid msg type - type %d len %d", - hid_msg->header.type, hid_msg->header.size); - break; - } - -} - -static void mousevsc_on_channel_callback(void *context) -{ - const int packetSize = 0x100; - int ret = 0; - struct hv_device *device = (struct hv_device *)context; - - u32 bytes_recvd; - u64 req_id; - unsigned char packet[0x100]; - struct vmpacket_descriptor *desc; - unsigned char *buffer = packet; - int bufferlen = packetSize; - - - do { - ret = vmbus_recvpacket_raw(device->channel, buffer, - bufferlen, &bytes_recvd, &req_id); - - if (ret == 0) { - if (bytes_recvd > 0) { - desc = (struct vmpacket_descriptor *)buffer; - - switch (desc->type) { - case VM_PKT_COMP: - break; - - case VM_PKT_DATA_INBAND: - mousevsc_on_receive( - device, desc); - break; - - default: - pr_err("unhandled packet type %d, tid %llx len %d\n", - desc->type, - req_id, - bytes_recvd); - break; - } - - /* reset */ - if (bufferlen > packetSize) { - kfree(buffer); - - buffer = packet; - bufferlen = packetSize; - } - } else { - if (bufferlen > packetSize) { - kfree(buffer); - - buffer = packet; - bufferlen = packetSize; - } - break; - } - } else if (ret == -ENOBUFS) { - /* Handle large packet */ - bufferlen = bytes_recvd; - buffer = kzalloc(bytes_recvd, GFP_ATOMIC); - - if (buffer == NULL) { - buffer = packet; - bufferlen = packetSize; - break; - } - } - } while (1); - - return; -} - -static int mousevsc_connect_to_vsp(struct hv_device *device) -{ - int ret = 0; - int t; - struct mousevsc_dev *input_dev = hv_get_drvdata(device); - struct mousevsc_prt_msg *request; - struct mousevsc_prt_msg *response; - - - request = &input_dev->protocol_req; - - memset(request, 0, sizeof(struct mousevsc_prt_msg)); - - request->type = PIPE_MESSAGE_DATA; - request->size = sizeof(struct synthhid_protocol_request); - - request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST; - request->request.header.size = sizeof(unsigned int); - request->request.version_requested.version = SYNTHHID_INPUT_VERSION; - - - ret = vmbus_sendpacket(device->channel, request, - sizeof(struct pipe_prt_msg) - - sizeof(unsigned char) + - sizeof(struct synthhid_protocol_request), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - response = &input_dev->protocol_resp; - - if (!response->response.approved) { - pr_err("synthhid protocol request failed (version %d)", - SYNTHHID_INPUT_VERSION); - ret = -ENODEV; - goto cleanup; - } - - t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - /* - * We should have gotten the device attr, hid desc and report - * desc at this point - */ - if (input_dev->dev_info_status) - ret = -ENOMEM; - -cleanup: - - return ret; -} - -static int mousevsc_hid_open(struct hid_device *hid) -{ - return 0; -} - -static void mousevsc_hid_close(struct hid_device *hid) -{ -} - -static struct hid_ll_driver mousevsc_ll_driver = { - .open = mousevsc_hid_open, - .close = mousevsc_hid_close, -}; - -static struct hid_driver mousevsc_hid_driver; - -static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len) -{ - struct hid_device *hid_dev; - struct mousevsc_dev *input_device = hv_get_drvdata(dev); - - hid_dev = hid_allocate_device(); - if (IS_ERR(hid_dev)) - return; - - hid_dev->ll_driver = &mousevsc_ll_driver; - hid_dev->driver = &mousevsc_hid_driver; - - if (hid_parse_report(hid_dev, packet, len)) - return; - - hid_dev->bus = BUS_VIRTUAL; - hid_dev->vendor = input_device->hid_dev_info.vendor; - hid_dev->product = input_device->hid_dev_info.product; - hid_dev->version = input_device->hid_dev_info.version; - - sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse"); - - if (!hidinput_connect(hid_dev, 0)) { - hid_dev->claimed |= HID_CLAIMED_INPUT; - - input_device->connected = 1; - - } - - input_device->hid_device = hid_dev; -} - -static int mousevsc_on_device_add(struct hv_device *device) -{ - int ret = 0; - struct mousevsc_dev *input_dev; - - input_dev = alloc_input_device(device); - - if (!input_dev) - return -ENOMEM; - - input_dev->init_complete = false; - - ret = vmbus_open(device->channel, - INPUTVSC_SEND_RING_BUFFER_SIZE, - INPUTVSC_RECV_RING_BUFFER_SIZE, - NULL, - 0, - mousevsc_on_channel_callback, - device - ); - - if (ret != 0) { - free_input_device(input_dev); - return ret; - } - - - ret = mousevsc_connect_to_vsp(device); - - if (ret != 0) { - vmbus_close(device->channel); - free_input_device(input_dev); - return ret; - } - - - /* workaround SA-167 */ - if (input_dev->report_desc[14] == 0x25) - input_dev->report_desc[14] = 0x29; - - reportdesc_callback(device, input_dev->report_desc, - input_dev->report_desc_size); - - input_dev->init_complete = true; - - return ret; -} - -static int mousevsc_probe(struct hv_device *dev, - const struct hv_vmbus_device_id *dev_id) -{ - - return mousevsc_on_device_add(dev); - -} - -static int mousevsc_remove(struct hv_device *dev) -{ - struct mousevsc_dev *input_dev = hv_get_drvdata(dev); - - vmbus_close(dev->channel); - - if (input_dev->connected) { - hidinput_disconnect(input_dev->hid_device); - input_dev->connected = 0; - hid_destroy_device(input_dev->hid_device); - } - - free_input_device(input_dev); - - return 0; -} - -static const struct hv_vmbus_device_id id_table[] = { - /* Mouse guid */ - { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, - 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) }, - { }, -}; - -MODULE_DEVICE_TABLE(vmbus, id_table); - -static struct hv_driver mousevsc_drv = { - .name = "mousevsc", - .id_table = id_table, - .probe = mousevsc_probe, - .remove = mousevsc_remove, -}; - -static int __init mousevsc_init(void) -{ - return vmbus_driver_register(&mousevsc_drv); -} - -static void __exit mousevsc_exit(void) -{ - vmbus_driver_unregister(&mousevsc_drv); -} - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -module_init(mousevsc_init); -module_exit(mousevsc_exit); diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c index ae8c33e7849..eb853f71089 100644 --- a/drivers/staging/hv/storvsc_drv.c +++ b/drivers/staging/hv/storvsc_drv.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/device.h> #include <linux/hyperv.h> +#include <linux/mempool.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_host.h> @@ -42,6 +43,7 @@ #include <scsi/scsi_dbg.h> +#define STORVSC_MIN_BUF_NR 64 #define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE) static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE; @@ -78,7 +80,7 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)"); /* V1 Beta 0.1 */ /* V1 RC < 2008/1/31 1.0 */ /* V1 RC > 2008/1/31 2.0 */ -#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(2, 0) +#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(4, 2) @@ -104,7 +106,8 @@ enum vstor_packet_operation { VSTOR_OPERATION_END_INITIALIZATION = 8, VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9, VSTOR_OPERATION_QUERY_PROPERTIES = 10, - VSTOR_OPERATION_MAXIMUM = 10 + VSTOR_OPERATION_ENUMERATE_BUS = 11, + VSTOR_OPERATION_MAXIMUM = 11 }; /* @@ -234,8 +237,6 @@ struct vstor_packet { #define STORVSC_MAX_CHANNELS 1 #define STORVSC_MAX_CMD_LEN 16 -struct hv_storvsc_request; - /* Matches Windows-end */ enum storvsc_request_type { WRITE_TYPE, @@ -284,9 +285,13 @@ struct storvsc_device { struct hv_storvsc_request reset_request; }; +struct stor_mem_pools { + struct kmem_cache *request_pool; + mempool_t *request_mempool; +}; + struct hv_host_device { struct hv_device *dev; - struct kmem_cache *request_pool; unsigned int port; unsigned char path; unsigned char target; @@ -302,6 +307,51 @@ struct storvsc_cmd_request { struct hv_storvsc_request request; }; +struct storvsc_scan_work { + struct work_struct work; + struct Scsi_Host *host; + uint lun; +}; + +static void storvsc_bus_scan(struct work_struct *work) +{ + struct storvsc_scan_work *wrk; + int id, order_id; + + wrk = container_of(work, struct storvsc_scan_work, work); + for (id = 0; id < wrk->host->max_id; ++id) { + if (wrk->host->reverse_ordering) + order_id = wrk->host->max_id - id - 1; + else + order_id = id; + + scsi_scan_target(&wrk->host->shost_gendev, 0, + order_id, SCAN_WILD_CARD, 1); + } + kfree(wrk); +} + +static void storvsc_remove_lun(struct work_struct *work) +{ + struct storvsc_scan_work *wrk; + struct scsi_device *sdev; + + wrk = container_of(work, struct storvsc_scan_work, work); + if (!scsi_host_get(wrk->host)) + goto done; + + sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun); + + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } + scsi_host_put(wrk->host); + +done: + kfree(wrk); +} + static inline struct storvsc_device *get_out_stor_device( struct hv_device *device) { @@ -549,11 +599,25 @@ static void storvsc_on_receive(struct hv_device *device, struct vstor_packet *vstor_packet, struct hv_storvsc_request *request) { + struct storvsc_scan_work *work; + struct storvsc_device *stor_device; + switch (vstor_packet->operation) { case VSTOR_OPERATION_COMPLETE_IO: storvsc_on_io_completion(device, vstor_packet, request); break; + case VSTOR_OPERATION_REMOVE_DEVICE: + case VSTOR_OPERATION_ENUMERATE_BUS: + stor_device = get_in_stor_device(device); + work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC); + if (!work) + return; + + INIT_WORK(&work->work, storvsc_bus_scan); + work->host = stor_device->host; + schedule_work(&work->work); + break; default: break; @@ -729,19 +793,48 @@ static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path) static int storvsc_device_alloc(struct scsi_device *sdevice) { - /* - * This enables luns to be located sparsely. Otherwise, we may not - * discovered them. - */ - sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN; + struct stor_mem_pools *memp; + int number = STORVSC_MIN_BUF_NR; + + memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL); + if (!memp) + return -ENOMEM; + + memp->request_pool = + kmem_cache_create(dev_name(&sdevice->sdev_dev), + sizeof(struct storvsc_cmd_request), 0, + SLAB_HWCACHE_ALIGN, NULL); + + if (!memp->request_pool) + goto err0; + + memp->request_mempool = mempool_create(number, mempool_alloc_slab, + mempool_free_slab, + memp->request_pool); + + if (!memp->request_mempool) + goto err1; + + sdevice->hostdata = memp; + return 0; + +err1: + kmem_cache_destroy(memp->request_pool); + +err0: + kfree(memp); + return -ENOMEM; } -static int storvsc_merge_bvec(struct request_queue *q, - struct bvec_merge_data *bmd, struct bio_vec *bvec) +static void storvsc_device_destroy(struct scsi_device *sdevice) { - /* checking done by caller. */ - return bvec->bv_len; + struct stor_mem_pools *memp = sdevice->hostdata; + + mempool_destroy(memp->request_mempool); + kmem_cache_destroy(memp->request_pool); + kfree(memp); + sdevice->hostdata = NULL; } static int storvsc_device_configure(struct scsi_device *sdevice) @@ -751,8 +844,6 @@ static int storvsc_device_configure(struct scsi_device *sdevice) blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); - blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec); - blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY); return 0; @@ -802,12 +893,14 @@ static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count) static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count, - unsigned int len) + unsigned int len, + int write) { int i; int num_pages; struct scatterlist *bounce_sgl; struct page *page_buf; + unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE); num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT; @@ -819,7 +912,7 @@ static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, page_buf = alloc_page(GFP_ATOMIC); if (!page_buf) goto cleanup; - sg_set_page(&bounce_sgl[i], page_buf, 0, 0); + sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0); } return bounce_sgl; @@ -833,7 +926,8 @@ cleanup: /* Assume the original sgl has enough room */ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count) + unsigned int orig_sgl_count, + unsigned int bounce_sgl_count) { int i; int j = 0; @@ -874,6 +968,24 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, kunmap_atomic((void *)bounce_addr, KM_IRQ0); j++; + /* + * It is possible that the number of elements + * in the bounce buffer may not be equal to + * the number of elements in the original + * scatter list. Handle this correctly. + */ + + if (j == bounce_sgl_count) { + /* + * We are done; cleanup and return. + */ + kunmap_atomic((void *)(dest_addr - + orig_sgl[i].offset), + KM_IRQ0); + local_irq_restore(flags); + return total_copied; + } + /* if we need to use another bounce buffer */ if (destlen || i != orig_sgl_count - 1) bounce_addr = @@ -965,18 +1077,13 @@ static int storvsc_remove(struct hv_device *dev) { struct storvsc_device *stor_device = hv_get_drvdata(dev); struct Scsi_Host *host = stor_device->host; - struct hv_host_device *host_dev = - (struct hv_host_device *)host->hostdata; scsi_remove_host(host); scsi_host_put(host); storvsc_dev_remove(dev); - if (host_dev->request_pool) { - kmem_cache_destroy(host_dev->request_pool); - host_dev->request_pool = NULL; - } + return 0; } @@ -1014,7 +1121,7 @@ static int storvsc_host_reset(struct hv_device *device) stor_device = get_out_stor_device(device); if (!stor_device) - return -ENODEV; + return FAILED; request = &stor_device->reset_request; vstor_packet = &request->vstor_packet; @@ -1031,13 +1138,11 @@ static int storvsc_host_reset(struct hv_device *device) VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) - goto cleanup; + return FAILED; t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } + if (t == 0) + return TIMEOUT_ERROR; /* @@ -1045,8 +1150,7 @@ static int storvsc_host_reset(struct hv_device *device) * should have been flushed out and return to us */ -cleanup: - return ret; + return SUCCESS; } @@ -1055,16 +1159,10 @@ cleanup: */ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) { - int ret; - struct hv_host_device *host_dev = - (struct hv_host_device *)scmnd->device->host->hostdata; + struct hv_host_device *host_dev = shost_priv(scmnd->device->host); struct hv_device *dev = host_dev->dev; - ret = storvsc_host_reset(dev); - if (ret != 0) - return ret; - - return ret; + return storvsc_host_reset(dev); } @@ -1076,21 +1174,22 @@ static void storvsc_command_completion(struct hv_storvsc_request *request) struct storvsc_cmd_request *cmd_request = (struct storvsc_cmd_request *)request->context; struct scsi_cmnd *scmnd = cmd_request->cmd; - struct hv_host_device *host_dev = - (struct hv_host_device *)scmnd->device->host->hostdata; + struct hv_host_device *host_dev = shost_priv(scmnd->device->host); void (*scsi_done_fn)(struct scsi_cmnd *); struct scsi_sense_hdr sense_hdr; struct vmscsi_request *vm_srb; + struct storvsc_scan_work *wrk; + struct stor_mem_pools *memp = scmnd->device->hostdata; vm_srb = &request->vstor_packet.vm_srb; if (cmd_request->bounce_sgl_count) { - if (vm_srb->data_in == READ_TYPE) { + if (vm_srb->data_in == READ_TYPE) copy_from_bounce_buffer(scsi_sglist(scmnd), cmd_request->bounce_sgl, - scsi_sg_count(scmnd)); - destroy_bounce_buffer(cmd_request->bounce_sgl, + scsi_sg_count(scmnd), + cmd_request->bounce_sgl_count); + destroy_bounce_buffer(cmd_request->bounce_sgl, cmd_request->bounce_sgl_count); - } } /* @@ -1103,6 +1202,29 @@ static void storvsc_command_completion(struct hv_storvsc_request *request) else scmnd->result = vm_srb->scsi_status; + /* + * If the LUN is invalid; remove the device. + */ + if (vm_srb->srb_status == 0x20) { + struct storvsc_device *stor_dev; + struct hv_device *dev = host_dev->dev; + struct Scsi_Host *host; + + stor_dev = get_in_stor_device(dev); + host = stor_dev->host; + + wrk = kmalloc(sizeof(struct storvsc_scan_work), + GFP_ATOMIC); + if (!wrk) { + scmnd->result = DID_TARGET_FAILURE << 16; + } else { + wrk->host = host; + wrk->lun = vm_srb->lun; + INIT_WORK(&wrk->work, storvsc_remove_lun); + schedule_work(&wrk->work); + } + } + if (scmnd->result) { if (scsi_normalize_sense(scmnd->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr)) @@ -1120,7 +1242,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request) scsi_done_fn(scmnd); - kmem_cache_free(host_dev->request_pool, cmd_request); + mempool_free(cmd_request, memp->request_mempool); } static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd) @@ -1131,7 +1253,7 @@ static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd) switch (scsi_op) { /* smartd sends this command, which will offline the device */ case SET_WINDOW: - scmnd->result = DID_ERROR << 16; + scmnd->result = ILLEGAL_REQUEST << 16; allowed = false; break; default: @@ -1143,12 +1265,10 @@ static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd) /* * storvsc_queuecommand - Initiate command processing */ -static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd, - void (*done)(struct scsi_cmnd *)) +static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) { int ret; - struct hv_host_device *host_dev = - (struct hv_host_device *)scmnd->device->host->hostdata; + struct hv_host_device *host_dev = shost_priv(host); struct hv_device *dev = host_dev->dev; struct hv_storvsc_request *request; struct storvsc_cmd_request *cmd_request; @@ -1157,9 +1277,10 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd, struct scatterlist *sgl; unsigned int sg_count = 0; struct vmscsi_request *vm_srb; + struct stor_mem_pools *memp = scmnd->device->hostdata; if (storvsc_check_scsi_cmd(scmnd) == false) { - done(scmnd); + scmnd->scsi_done(scmnd); return 0; } @@ -1172,16 +1293,14 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd, goto retry_request; } - scmnd->scsi_done = done; - request_size = sizeof(struct storvsc_cmd_request); - cmd_request = kmem_cache_zalloc(host_dev->request_pool, + cmd_request = mempool_alloc(memp->request_mempool, GFP_ATOMIC); - if (!cmd_request) { - scmnd->scsi_done = NULL; + if (!cmd_request) return SCSI_MLQUEUE_DEVICE_BUSY; - } + + memset(cmd_request, 0, sizeof(struct storvsc_cmd_request)); /* Setup the cmd request */ cmd_request->bounce_sgl_count = 0; @@ -1231,12 +1350,12 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd, if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) { cmd_request->bounce_sgl = create_bounce_buffer(sgl, scsi_sg_count(scmnd), - scsi_bufflen(scmnd)); + scsi_bufflen(scmnd), + vm_srb->data_in); if (!cmd_request->bounce_sgl) { - scmnd->scsi_done = NULL; scmnd->host_scribble = NULL; - kmem_cache_free(host_dev->request_pool, - cmd_request); + mempool_free(cmd_request, + memp->request_mempool); return SCSI_MLQUEUE_HOST_BUSY; } @@ -1278,9 +1397,8 @@ retry_request: destroy_bounce_buffer(cmd_request->bounce_sgl, cmd_request->bounce_sgl_count); - kmem_cache_free(host_dev->request_pool, cmd_request); + mempool_free(cmd_request, memp->request_mempool); - scmnd->scsi_done = NULL; scmnd->host_scribble = NULL; ret = SCSI_MLQUEUE_DEVICE_BUSY; @@ -1289,9 +1407,6 @@ retry_request: return ret; } -static DEF_SCSI_QCMD(storvsc_queuecommand) - - /* Scsi driver */ static struct scsi_host_template scsi_driver = { .module = THIS_MODULE, @@ -1300,6 +1415,7 @@ static struct scsi_host_template scsi_driver = { .queuecommand = storvsc_queuecommand, .eh_host_reset_handler = storvsc_host_reset_handler, .slave_alloc = storvsc_device_alloc, + .slave_destroy = storvsc_device_destroy, .slave_configure = storvsc_device_configure, .cmd_per_lun = 1, /* 64 max_queue * 1 target */ @@ -1308,14 +1424,7 @@ static struct scsi_host_template scsi_driver = { /* no use setting to 0 since ll_blk_rw reset it to 1 */ /* currently 32 */ .sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT, - /* - * ENABLE_CLUSTERING allows mutiple physically contig bio_vecs to merge - * into 1 sg element. If set, we must limit the max_segment_size to - * PAGE_SIZE, otherwise we may get 1 sg element that represents - * multiple - */ - /* physically contig pfns (ie sg[x].length > PAGE_SIZE). */ - .use_clustering = ENABLE_CLUSTERING, + .use_clustering = DISABLE_CLUSTERING, /* Make sure we dont get a sg segment crosses a page boundary */ .dma_boundary = PAGE_SIZE-1, }; @@ -1360,27 +1469,17 @@ static int storvsc_probe(struct hv_device *device, if (!host) return -ENOMEM; - host_dev = (struct hv_host_device *)host->hostdata; + host_dev = shost_priv(host); memset(host_dev, 0, sizeof(struct hv_host_device)); host_dev->port = host->host_no; host_dev->dev = device; - host_dev->request_pool = - kmem_cache_create(dev_name(&device->device), - sizeof(struct storvsc_cmd_request), 0, - SLAB_HWCACHE_ALIGN, NULL); - - if (!host_dev->request_pool) { - scsi_host_put(host); - return -ENOMEM; - } stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); if (!stor_device) { - kmem_cache_destroy(host_dev->request_pool); - scsi_host_put(host); - return -ENOMEM; + ret = -ENOMEM; + goto err_out0; } stor_device->destroy = false; @@ -1391,12 +1490,8 @@ static int storvsc_probe(struct hv_device *device, stor_device->port_number = host->host_no; ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size); - if (ret) { - kmem_cache_destroy(host_dev->request_pool); - scsi_host_put(host); - kfree(stor_device); - return ret; - } + if (ret) + goto err_out1; if (dev_is_ide) storvsc_get_ide_info(device, &target, &path); @@ -1416,7 +1511,7 @@ static int storvsc_probe(struct hv_device *device, /* Register the HBA and start the scsi bus scan */ ret = scsi_add_host(host, &device->device); if (ret != 0) - goto err_out; + goto err_out2; if (!dev_is_ide) { scsi_scan_host(host); @@ -1425,21 +1520,32 @@ static int storvsc_probe(struct hv_device *device, ret = scsi_add_device(host, 0, target, 0); if (ret) { scsi_remove_host(host); - goto err_out; + goto err_out2; } return 0; -err_out: +err_out2: + /* + * Once we have connected with the host, we would need to + * to invoke storvsc_dev_remove() to rollback this state and + * this call also frees up the stor_device; hence the jump around + * err_out1 label. + */ storvsc_dev_remove(device); - kmem_cache_destroy(host_dev->request_pool); + goto err_out0; + +err_out1: + kfree(stor_device); + +err_out0: scsi_host_put(host); - return -ENODEV; + return ret; } /* The one and only one */ static struct hv_driver storvsc_drv = { - .name = "storvsc", + .name = KBUILD_MODNAME, .id_table = id_table, .probe = storvsc_probe, .remove = storvsc_remove, diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c index d5809532149..69a05b9456d 100644 --- a/drivers/staging/iio/Documentation/generic_buffer.c +++ b/drivers/staging/iio/Documentation/generic_buffer.c @@ -28,6 +28,7 @@ #include <linux/types.h> #include <string.h> #include <poll.h> +#include <endian.h> #include "iio_utils.h" /** @@ -56,6 +57,13 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels) void print2byte(int input, struct iio_channel_info *info) { + /* First swap if incorrect endian */ + + if (info->be) + input = be16toh((uint_16t)input); + else + input = le16toh((uint_16t)input); + /* shift before conversion to avoid sign extension of left aligned data */ input = input >> info->shift; diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index 75938b2412f..6f3a392297e 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -13,6 +13,7 @@ #include <ctype.h> #include <stdio.h> #include <stdint.h> +#include <dirent.h> #define IIO_MAX_NAME_LENGTH 30 @@ -73,6 +74,7 @@ struct iio_channel_info { unsigned bits_used; unsigned shift; uint64_t mask; + unsigned be; unsigned is_signed; unsigned enabled; unsigned location; @@ -83,6 +85,7 @@ struct iio_channel_info { * @is_signed: output whether channel is signed * @bytes: output how many bytes the channel storage occupies * @mask: output a bit mask for the raw data + * @be: big endian * @device_dir: the iio device directory * @name: the channel name * @generic_name: the channel type name @@ -92,6 +95,7 @@ inline int iioutils_get_type(unsigned *is_signed, unsigned *bits_used, unsigned *shift, uint64_t *mask, + unsigned *be, const char *device_dir, const char *name, const char *generic_name) @@ -100,7 +104,7 @@ inline int iioutils_get_type(unsigned *is_signed, int ret; DIR *dp; char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; - char signchar; + char signchar, endianchar; unsigned padint; const struct dirent *ent; @@ -144,9 +148,18 @@ inline int iioutils_get_type(unsigned *is_signed, ret = -errno; goto error_free_filename; } - fscanf(sysfsfp, - "%c%u/%u>>%u", &signchar, bits_used, - &padint, shift); + + ret = fscanf(sysfsfp, + "%ce:%c%u/%u>>%u", + &endianchar, + &signchar, + bits_used, + &padint, shift); + if (ret < 0) { + printf("failed to pass scan type description\n"); + return ret; + } + *be = (endianchar == 'b'); *bytes = padint / 8; if (*bits_used == 64) *mask = ~0; @@ -156,6 +169,10 @@ inline int iioutils_get_type(unsigned *is_signed, *is_signed = 1; else *is_signed = 0; + fclose(sysfsfp); + free(filename); + + filename = 0; } error_free_filename: if (filename) @@ -386,6 +403,7 @@ inline int build_channel_array(const char *device_dir, ¤t->bits_used, ¤t->shift, ¤t->mask, + ¤t->be, device_dir, current->name, current->generic_name); diff --git a/drivers/staging/iio/Documentation/ring.txt b/drivers/staging/iio/Documentation/ring.txt index 7e99ef2b7bc..e33807761cd 100644 --- a/drivers/staging/iio/Documentation/ring.txt +++ b/drivers/staging/iio/Documentation/ring.txt @@ -23,10 +23,6 @@ The function pointers within here are used to allow the core to handle as much buffer functionality as possible. Note almost all of these are optional. -mark_in_use, unmark_in_use - Basically indicate that not changes should be made to the buffer state that - will effect the form of the data being captures (e.g. scan elements or length) - store_to If possible, push data to the buffer. @@ -39,8 +35,6 @@ rip_first_n The primary buffer reading function. Note that it may well not return as much data as requested. -mark_param_changed - Used to indicate that something has changed. Used in conjunction with request_update If parameters have changed that require reinitialization or configuration of the buffer this will trigger it. @@ -51,7 +45,3 @@ get_bytes_per_datum, set_bytes_per_datum get_length / set_length Get/set the number of complete scans that may be held by the buffer. -is_enabled - Query if ring buffer is in use -enable - Start the ring buffer. diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio index 0d6823d19b6..46a995d6d26 100644 --- a/drivers/staging/iio/Documentation/sysfs-bus-iio +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio @@ -276,6 +276,16 @@ Description: If a discrete set of scale values are available, they are listed in this attribute. +What: /sys/.../in_accel_filter_low_pass_3db_frequency +What: /sys/.../in_magn_filter_low_pass_3db_frequency +What: /sys/.../in_anglvel_filter_low_pass_3db_frequency +KernelVersion: 3.2 +Contact: linux-iio@vger.kernel.org +Description: + If a known or controllable low pass filter is applied + to the underlying data channel, then this parameter + gives the 3dB frequency of the filter in Hz. + What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 4ec9118955f..90162aa8b2d 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -76,7 +76,6 @@ config IIO_DUMMY_EVGEN config IIO_SIMPLE_DUMMY tristate "An example driver with no hardware requirements" - select IIO_SIMPLE_DUMMY_EVGEN if IIO_SIMPLE_DUMMY_EVENTS help Driver intended mainly as documentation for how to write a driver. May also be useful for testing userspace code diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c index 97f747eac64..d439e45d07f 100644 --- a/drivers/staging/iio/accel/adis16201_core.c +++ b/drivers/staging/iio/accel/adis16201_core.c @@ -17,7 +17,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "adis16201.h" @@ -322,8 +322,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: *val = 0; @@ -348,10 +347,10 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, return -EINVAL; } break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = 25; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_ACCEL: bits = 12; @@ -388,7 +387,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, s16 val16; u8 addr; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_ACCEL: bits = 12; @@ -408,36 +407,36 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, static struct iio_chan_spec adis16201_channels[] = { IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_supply, ADIS16201_SCAN_SUPPLY, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, temp, ADIS16201_SCAN_TEMP, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, accel_x, ADIS16201_SCAN_ACC_X, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, accel_y, ADIS16201_SCAN_ACC_Y, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_aux, ADIS16201_SCAN_AUX_ADC, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, incli_x, ADIS16201_SCAN_INCLI_X, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, incli_y, ADIS16201_SCAN_INCLI_Y, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN_SOFT_TIMESTAMP(7) @@ -554,3 +553,4 @@ module_spi_driver(adis16201_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16201 Programmable Digital Vibration Sensor driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16201"); diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c index 0016ed378e3..26c610faee3 100644 --- a/drivers/staging/iio/accel/adis16201_ring.c +++ b/drivers/staging/iio/accel/adis16201_ring.c @@ -74,11 +74,11 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p) return -ENOMEM; } - if (ring->scan_count) - if (adis16201_read_ring_data(indio_dev, st->rx) >= 0) - for (; i < ring->scan_count; i++) - data[i] = be16_to_cpup( - (__be16 *)&(st->rx[i*2])); + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) + && adis16201_read_ring_data(indio_dev, st->rx) >= 0) + for (; i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); i++) + data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (ring->scan_timestamp) @@ -116,11 +116,9 @@ int adis16201_configure_ring(struct iio_dev *indio_dev) } indio_dev->buffer = ring; /* Effectively select the ring buffer implementation */ - ring->bpe = 2; ring->scan_timestamp = true; ring->access = &ring_sw_access_funcs; - ring->setup_ops = &adis16201_ring_setup_ops; - ring->owner = THIS_MODULE; + indio_dev->setup_ops = &adis16201_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &adis16201_trigger_handler, diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c index a6d6d27f3c9..1a5140f9e3f 100644 --- a/drivers/staging/iio/accel/adis16203_core.c +++ b/drivers/staging/iio/accel/adis16203_core.c @@ -17,7 +17,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "adis16203.h" @@ -329,8 +329,7 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: *val = 0; @@ -350,10 +349,10 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = 25; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: bits = 14; mutex_lock(&indio_dev->mlock); addr = adis16203_addresses[chan->address][1]; @@ -374,26 +373,26 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, static struct iio_chan_spec adis16203_channels[] = { IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_supply, ADIS16203_SCAN_SUPPLY, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_aux, ADIS16203_SCAN_AUX_ADC, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, incli_x, ADIS16203_SCAN_INCLI_X, IIO_ST('s', 14, 16, 0), 0), /* Fixme: Not what it appears to be - see data sheet */ IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, incli_y, ADIS16203_SCAN_INCLI_Y, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, temp, ADIS16203_SCAN_TEMP, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN_SOFT_TIMESTAMP(5), @@ -509,3 +508,4 @@ module_spi_driver(adis16203_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable Digital Vibration Sensor driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16203"); diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c index 1fdfe6f6ac6..064640d15e4 100644 --- a/drivers/staging/iio/accel/adis16203_ring.c +++ b/drivers/staging/iio/accel/adis16203_ring.c @@ -74,11 +74,11 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p) return -ENOMEM; } - if (ring->scan_count) - if (adis16203_read_ring_data(&indio_dev->dev, st->rx) >= 0) - for (; i < ring->scan_count; i++) - data[i] = be16_to_cpup( - (__be16 *)&(st->rx[i*2])); + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && + adis16203_read_ring_data(&indio_dev->dev, st->rx) >= 0) + for (; i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); i++) + data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (ring->scan_timestamp) @@ -118,11 +118,9 @@ int adis16203_configure_ring(struct iio_dev *indio_dev) } indio_dev->buffer = ring; /* Effectively select the ring buffer implementation */ - ring->bpe = 2; ring->scan_timestamp = true; ring->access = &ring_sw_access_funcs; - ring->setup_ops = &adis16203_ring_setup_ops; - ring->owner = THIS_MODULE; + indio_dev->setup_ops = &adis16203_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &adis16203_trigger_handler, diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c index 7ac5b4c533d..fa89364b841 100644 --- a/drivers/staging/iio/accel/adis16204_core.c +++ b/drivers/staging/iio/accel/adis16204_core.c @@ -20,7 +20,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "adis16204.h" @@ -366,7 +366,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: *val = 0; @@ -390,12 +390,12 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, return -EINVAL; } break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = 25; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): - case (1 << IIO_CHAN_INFO_PEAK_SEPARATE): - if (mask == (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE)) { + case IIO_CHAN_INFO_CALIBBIAS: + case IIO_CHAN_INFO_PEAK: + if (mask == IIO_CHAN_INFO_CALIBBIAS) { bits = 12; addrind = 1; } else { /* PEAK_SEPARATE */ @@ -428,7 +428,7 @@ static int adis16204_write_raw(struct iio_dev *indio_dev, s16 val16; u8 addr; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_ACCEL: bits = 12; @@ -445,28 +445,28 @@ static int adis16204_write_raw(struct iio_dev *indio_dev, static struct iio_chan_spec adis16204_channels[] = { IIO_CHAN(IIO_VOLTAGE, 0, 0, 0, "supply", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_supply, ADIS16204_SCAN_SUPPLY, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_aux, ADIS16204_SCAN_AUX_ADC, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, temp, ADIS16204_SCAN_TEMP, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_PEAK_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_PEAK_SEPARATE_BIT, accel_x, ADIS16204_SCAN_ACC_X, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_PEAK_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_PEAK_SEPARATE_BIT, accel_y, ADIS16204_SCAN_ACC_Y, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN_SOFT_TIMESTAMP(5), @@ -582,3 +582,4 @@ module_spi_driver(adis16204_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("ADIS16204 High-g Digital Impact Sensor and Recorder"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16204"); diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c index 6fd3d8f51f2..4081179dfa5 100644 --- a/drivers/staging/iio/accel/adis16204_ring.c +++ b/drivers/staging/iio/accel/adis16204_ring.c @@ -71,11 +71,11 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p) return -ENOMEM; } - if (ring->scan_count) - if (adis16204_read_ring_data(&indio_dev->dev, st->rx) >= 0) - for (; i < ring->scan_count; i++) - data[i] = be16_to_cpup( - (__be16 *)&(st->rx[i*2])); + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && + adis16204_read_ring_data(&indio_dev->dev, st->rx) >= 0) + for (; i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); i++) + data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ if (ring->scan_timestamp) @@ -114,10 +114,8 @@ int adis16204_configure_ring(struct iio_dev *indio_dev) indio_dev->buffer = ring; /* Effectively select the ring buffer implementation */ ring->access = &ring_sw_access_funcs; - ring->bpe = 2; ring->scan_timestamp = true; - ring->setup_ops = &adis16204_ring_setup_ops; - ring->owner = THIS_MODULE; + indio_dev->setup_ops = &adis16204_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &adis16204_trigger_handler, diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c index c03afbf5bbd..a98715f6bd6 100644 --- a/drivers/staging/iio/accel/adis16209_core.c +++ b/drivers/staging/iio/accel/adis16209_core.c @@ -18,7 +18,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "adis16209.h" @@ -304,7 +304,7 @@ static int adis16209_write_raw(struct iio_dev *indio_dev, s16 val16; u8 addr; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_ACCEL: case IIO_INCLI: @@ -355,8 +355,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: *val = 0; @@ -381,10 +380,10 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, return -EINVAL; } break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = 25; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_ACCEL: bits = 14; @@ -410,34 +409,34 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, static struct iio_chan_spec adis16209_channels[] = { IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_supply, ADIS16209_SCAN_SUPPLY, IIO_ST('u', 14, 16, 0), 0), IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, temp, ADIS16209_SCAN_TEMP, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, accel_x, ADIS16209_SCAN_ACC_X, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, accel_y, ADIS16209_SCAN_ACC_Y, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_aux, ADIS16209_SCAN_AUX_ADC, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, incli_x, ADIS16209_SCAN_INCLI_X, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, incli_y, ADIS16209_SCAN_INCLI_Y, IIO_ST('s', 14, 16, 0), 0), IIO_CHAN(IIO_ROT, 0, 1, 0, NULL, 0, IIO_MOD_X, @@ -558,3 +557,4 @@ module_spi_driver(adis16209_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16209 Digital Vibration Sensor driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16209"); diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c index d17e39d9545..2a6fd334f5f 100644 --- a/drivers/staging/iio/accel/adis16209_ring.c +++ b/drivers/staging/iio/accel/adis16209_ring.c @@ -72,9 +72,10 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p) return -ENOMEM; } - if (ring->scan_count && + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && adis16209_read_ring_data(&indio_dev->dev, st->rx) >= 0) - for (; i < ring->scan_count; i++) + for (; i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ @@ -114,10 +115,8 @@ int adis16209_configure_ring(struct iio_dev *indio_dev) indio_dev->buffer = ring; /* Effectively select the ring buffer implementation */ ring->access = &ring_sw_access_funcs; - ring->bpe = 2; ring->scan_timestamp = true; - ring->setup_ops = &adis16209_ring_setup_ops; - ring->owner = THIS_MODULE; + indio_dev->setup_ops = &adis16209_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &adis16209_trigger_handler, diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c index 73298e7849e..51a852d4548 100644 --- a/drivers/staging/iio/accel/adis16220_core.c +++ b/drivers/staging/iio/accel/adis16220_core.c @@ -167,9 +167,9 @@ static ssize_t adis16220_write_16bit(struct device *dev, struct iio_dev *indio_dev = dev_get_drvdata(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = adis16220_spi_write_reg_16(indio_dev, this_attr->address, val); @@ -510,17 +510,17 @@ static int adis16220_read_raw(struct iio_dev *indio_dev, case 0: addrind = 0; break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: if (chan->type == IIO_TEMP) { *val = 25; return IIO_VAL_INT; } addrind = 1; break; - case (1 << IIO_CHAN_INFO_PEAK_SEPARATE): + case IIO_CHAN_INFO_PEAK: addrind = 2; break; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: *val = 0; switch (chan->type) { case IIO_TEMP: @@ -575,27 +575,27 @@ static const struct iio_chan_spec adis16220_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, }, { .type = IIO_ACCEL, - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_PEAK_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_PEAK_SEPARATE_BIT, .address = accel, }, { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_1, }, { .type = IIO_VOLTAGE, @@ -713,3 +713,4 @@ module_spi_driver(adis16220_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16220 Digital Vibration Sensor"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16220"); diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index 88881b9919e..17f77fef7f2 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -21,7 +21,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "adis16240.h" @@ -389,8 +389,7 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: *val = 0; @@ -411,14 +410,14 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, return -EINVAL; } break; - case (1 << IIO_CHAN_INFO_PEAK_SCALE_SHARED): + case IIO_CHAN_INFO_PEAK_SCALE: *val = 6; *val2 = 629295; return IIO_VAL_INT_PLUS_MICRO; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = 25; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: bits = 10; mutex_lock(&indio_dev->mlock); addr = adis16240_addresses[chan->address][1]; @@ -432,7 +431,7 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_PEAK_SEPARATE): + case IIO_CHAN_INFO_PEAK: bits = 10; mutex_lock(&indio_dev->mlock); addr = adis16240_addresses[chan->address][2]; @@ -460,7 +459,7 @@ static int adis16240_write_raw(struct iio_dev *indio_dev, s16 val16; u8 addr; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: val16 = val & ((1 << bits) - 1); addr = adis16240_addresses[chan->address][1]; return adis16240_spi_write_reg_16(indio_dev, addr, val16); @@ -470,7 +469,7 @@ static int adis16240_write_raw(struct iio_dev *indio_dev, static struct iio_chan_spec adis16240_channels[] = { IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, in_supply, ADIS16240_SCAN_SUPPLY, IIO_ST('u', 10, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, @@ -478,22 +477,22 @@ static struct iio_chan_spec adis16240_channels[] = { in_aux, ADIS16240_SCAN_AUX_ADC, IIO_ST('u', 10, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, accel_x, ADIS16240_SCAN_ACC_X, IIO_ST('s', 10, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, accel_y, ADIS16240_SCAN_ACC_Y, IIO_ST('s', 10, 16, 0), 0), IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, - (1 << IIO_CHAN_INFO_SCALE_SHARED) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, accel_z, ADIS16240_SCAN_ACC_Z, IIO_ST('s', 10, 16, 0), 0), IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, temp, ADIS16240_SCAN_TEMP, IIO_ST('u', 10, 16, 0), 0), IIO_CHAN_SOFT_TIMESTAMP(6) @@ -611,3 +610,4 @@ module_spi_driver(adis16240_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16240"); diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c index b907ca3f4fd..e23622d96f9 100644 --- a/drivers/staging/iio/accel/adis16240_ring.c +++ b/drivers/staging/iio/accel/adis16240_ring.c @@ -69,9 +69,10 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p) return -ENOMEM; } - if (ring->scan_count && + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && adis16240_read_ring_data(&indio_dev->dev, st->rx) >= 0) - for (; i < ring->scan_count; i++) + for (; i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ @@ -111,10 +112,8 @@ int adis16240_configure_ring(struct iio_dev *indio_dev) indio_dev->buffer = ring; /* Effectively select the ring buffer implementation */ ring->access = &ring_sw_access_funcs; - ring->bpe = 2; ring->scan_timestamp = true; - ring->setup_ops = &adis16240_ring_setup_ops; - ring->owner = THIS_MODULE; + indio_dev->setup_ops = &adis16240_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &adis16240_trigger_handler, diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c index cfce21c2edd..d13d7215ff6 100644 --- a/drivers/staging/iio/accel/kxsd9.c +++ b/drivers/staging/iio/accel/kxsd9.c @@ -140,7 +140,7 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev, { int ret = -EINVAL; - if (mask == (1 << IIO_CHAN_INFO_SCALE_SHARED)) { + if (mask == IIO_CHAN_INFO_SCALE) { /* Check no integer component */ if (val) return -EINVAL; @@ -164,7 +164,7 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, goto error_ret; *val = ret; break; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C)); if (ret) goto error_ret; @@ -181,7 +181,7 @@ error_ret: .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .info_mask = 1 << IIO_CHAN_INFO_SCALE_SHARED, \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = KXSD9_REG_##axis, \ } @@ -268,8 +268,10 @@ static int __devexit kxsd9_remove(struct spi_device *spi) } static const struct spi_device_id kxsd9_id[] = { - {"kxsd9", 0} + {"kxsd9", 0}, + { }, }; +MODULE_DEVICE_TABLE(spi, kxsd9_id); static struct spi_driver kxsd9_driver = { .driver = { diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h index 7237a9ab61a..2db383fc274 100644 --- a/drivers/staging/iio/accel/lis3l02dq.h +++ b/drivers/staging/iio/accel/lis3l02dq.h @@ -181,11 +181,6 @@ int lis3l02dq_disable_all_events(struct iio_dev *indio_dev); void lis3l02dq_remove_trigger(struct iio_dev *indio_dev); int lis3l02dq_probe_trigger(struct iio_dev *indio_dev); -ssize_t lis3l02dq_read_accel_from_buffer(struct iio_buffer *buffer, - int index, - int *val); - - int lis3l02dq_configure_buffer(struct iio_dev *indio_dev); void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev); @@ -212,13 +207,6 @@ static inline int lis3l02dq_probe_trigger(struct iio_dev *indio_dev) { return 0; } -static inline ssize_t -lis3l02dq_read_accel_from_buffer(struct iio_buffer *buffer, - int index, - int *val) -{ - return 0; -} static int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) { diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 6877521ec17..376da513796 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -25,7 +25,8 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../events.h" +#include "../buffer.h" #include "lis3l02dq.h" @@ -226,14 +227,14 @@ static int lis3l02dq_write_raw(struct iio_dev *indio_dev, u8 uval; s8 sval; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: if (val > 255 || val < -256) return -EINVAL; sval = val; reg = lis3l02dq_axis_map[LIS3L02DQ_BIAS][chan->address]; ret = lis3l02dq_spi_write_reg_8(indio_dev, reg, sval); break; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: if (val & ~0xFF) return -EINVAL; uval = val; @@ -259,23 +260,20 @@ static int lis3l02dq_read_raw(struct iio_dev *indio_dev, case 0: /* Take the iio_dev status lock */ mutex_lock(&indio_dev->mlock); - if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) - ret = lis3l02dq_read_accel_from_buffer(indio_dev-> - buffer, - chan->scan_index, - val); - else { + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { + ret = -EBUSY; + } else { reg = lis3l02dq_axis_map [LIS3L02DQ_ACCEL][chan->address]; ret = lis3l02dq_read_reg_s16(indio_dev, reg, val); } mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: *val = 0; *val2 = 9580; return IIO_VAL_INT_PLUS_MICRO; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: reg = lis3l02dq_axis_map[LIS3L02DQ_GAIN][chan->address]; ret = lis3l02dq_spi_read_reg_8(indio_dev, reg, &utemp); if (ret) @@ -284,7 +282,7 @@ static int lis3l02dq_read_raw(struct iio_dev *indio_dev, *val = utemp; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: reg = lis3l02dq_axis_map[LIS3L02DQ_BIAS][chan->address]; ret = lis3l02dq_spi_read_reg_8(indio_dev, reg, (u8 *)&stemp); /* to match with what previous code does */ @@ -331,11 +329,11 @@ static ssize_t lis3l02dq_write_frequency(struct device *dev, size_t len) { struct iio_dev *indio_dev = dev_get_drvdata(dev); - long val; + unsigned long val; int ret; u8 t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) return ret; @@ -515,9 +513,9 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) } #define LIS3L02DQ_INFO_MASK \ - ((1 << IIO_CHAN_INFO_SCALE_SHARED) | \ - (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \ - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE)) + (IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT) #define LIS3L02DQ_EVENT_MASK \ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \ @@ -534,7 +532,7 @@ static struct iio_chan_spec lis3l02dq_channels[] = { }; -static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev, +static int lis3l02dq_read_event_config(struct iio_dev *indio_dev, u64 event_code) { @@ -809,3 +807,4 @@ module_spi_driver(lis3l02dq_driver); MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); MODULE_DESCRIPTION("ST LIS3L02DQ Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:lis3l02dq"); diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 89527af8f4c..98c5c92d345 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -38,38 +38,6 @@ irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private) return IRQ_WAKE_THREAD; } -/** - * lis3l02dq_read_accel_from_buffer() individual acceleration read from buffer - **/ -ssize_t lis3l02dq_read_accel_from_buffer(struct iio_buffer *buffer, - int index, - int *val) -{ - int ret; - s16 *data; - - if (!iio_scan_mask_query(buffer, index)) - return -EINVAL; - - if (!buffer->access->read_last) - return -EBUSY; - - data = kmalloc(buffer->access->get_bytes_per_datum(buffer), - GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - ret = buffer->access->read_last(buffer, (u8 *)data); - if (ret) - goto error_free_data; - *val = data[bitmap_weight(buffer->scan_mask, index)]; -error_free_data: - - kfree(data); - - return ret; -} - static const u8 read_all_tx_array[] = { LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_X_L_ADDR), 0, LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_X_H_ADDR), 0, @@ -87,21 +55,21 @@ static const u8 read_all_tx_array[] = { **/ static int lis3l02dq_read_all(struct iio_dev *indio_dev, u8 *rx_array) { - struct iio_buffer *buffer = indio_dev->buffer; struct lis3l02dq_state *st = iio_priv(indio_dev); struct spi_transfer *xfers; struct spi_message msg; int ret, i, j = 0; - xfers = kzalloc((buffer->scan_count) * 2 - * sizeof(*xfers), GFP_KERNEL); + xfers = kcalloc(bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * 2, + sizeof(*xfers), GFP_KERNEL); if (!xfers) return -ENOMEM; mutex_lock(&st->buf_lock); for (i = 0; i < ARRAY_SIZE(read_all_tx_array)/4; i++) - if (test_bit(i, buffer->scan_mask)) { + if (test_bit(i, indio_dev->active_scan_mask)) { /* lower byte */ xfers[j].tx_buf = st->tx + 2*j; st->tx[2*j] = read_all_tx_array[i*4]; @@ -129,7 +97,8 @@ static int lis3l02dq_read_all(struct iio_dev *indio_dev, u8 *rx_array) * values in alternate bytes */ spi_message_init(&msg); - for (j = 0; j < buffer->scan_count * 2; j++) + for (j = 0; j < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * 2; j++) spi_message_add_tail(&xfers[j], &msg); ret = spi_sync(st->us, &msg); @@ -145,14 +114,16 @@ static int lis3l02dq_get_buffer_element(struct iio_dev *indio_dev, int ret, i; u8 *rx_array ; s16 *data = (s16 *)buf; + int scan_count = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); - rx_array = kzalloc(4 * (indio_dev->buffer->scan_count), GFP_KERNEL); + rx_array = kzalloc(4 * scan_count, GFP_KERNEL); if (rx_array == NULL) return -ENOMEM; ret = lis3l02dq_read_all(indio_dev, rx_array); if (ret < 0) return ret; - for (i = 0; i < indio_dev->buffer->scan_count; i++) + for (i = 0; i < scan_count; i++) data[i] = combine_8_to_16(rx_array[i*4+1], rx_array[i*4+3]); kfree(rx_array); @@ -175,7 +146,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) return -ENOMEM; } - if (buffer->scan_count) + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) len = lis3l02dq_get_buffer_element(indio_dev, data); /* Guaranteed to be aligned with 8 byte boundary */ @@ -363,17 +334,17 @@ static int lis3l02dq_buffer_postenable(struct iio_dev *indio_dev) if (ret) goto error_ret; - if (iio_scan_mask_query(indio_dev->buffer, 0)) { + if (test_bit(0, indio_dev->active_scan_mask)) { t |= LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE; oneenabled = true; } else t &= ~LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE; - if (iio_scan_mask_query(indio_dev->buffer, 1)) { + if (test_bit(1, indio_dev->active_scan_mask)) { t |= LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE; oneenabled = true; } else t &= ~LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE; - if (iio_scan_mask_query(indio_dev->buffer, 2)) { + if (test_bit(2, indio_dev->active_scan_mask)) { t |= LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE; oneenabled = true; } else @@ -437,11 +408,9 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) indio_dev->buffer = buffer; /* Effectively select the buffer implementation */ indio_dev->buffer->access = &lis3l02dq_access_funcs; - buffer->bpe = 2; buffer->scan_timestamp = true; - buffer->setup_ops = &lis3l02dq_buffer_setup_ops; - buffer->owner = THIS_MODULE; + indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops; /* Functions are NULL as we set handler below */ indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 6c359074a06..49764fb7181 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -20,7 +20,8 @@ #include <linux/module.h> #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../events.h" +#include "../buffer.h" #include "sca3000.h" @@ -381,13 +382,17 @@ sca3000_store_measurement_mode(struct device *dev, struct iio_dev *indio_dev = dev_get_drvdata(dev); struct sca3000_state *st = iio_priv(indio_dev); int ret; - int mask = 0x03; - long val; + u8 mask = 0x03; + u8 val; mutex_lock(&st->lock); - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; + if (val > 3) { + ret = -EINVAL; + goto error_ret; + } ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); if (ret) goto error_ret; @@ -424,7 +429,7 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); #define SCA3000_INFO_MASK \ - (1 << IIO_CHAN_INFO_SCALE_SHARED) + IIO_CHAN_INFO_SCALE_SHARED_BIT #define SCA3000_EVENT_MASK \ (IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING)) @@ -474,7 +479,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, (sizeof(*val)*8 - 13); mutex_unlock(&st->lock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: *val = 0; if (chan->type == IIO_ACCEL) *val2 = st->info->scale; @@ -1161,9 +1166,9 @@ static int __devinit sca3000_probe(struct spi_device *spi) if (ret < 0) goto error_unregister_dev; if (indio_dev->buffer) { - iio_scan_mask_set(indio_dev->buffer, 0); - iio_scan_mask_set(indio_dev->buffer, 1); - iio_scan_mask_set(indio_dev->buffer, 2); + iio_scan_mask_set(indio_dev, indio_dev->buffer, 0); + iio_scan_mask_set(indio_dev, indio_dev->buffer, 1); + iio_scan_mask_set(indio_dev, indio_dev->buffer, 2); } if (spi->irq) { @@ -1240,6 +1245,7 @@ static const struct spi_device_id sca3000_id[] = { {"sca3000_e05", e05}, {} }; +MODULE_DEVICE_TABLE(spi, sca3000_id); static struct spi_driver sca3000_driver = { .driver = { diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index 4a9a01dccd0..6b824a11f7f 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -20,7 +20,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_hw.h" #include "sca3000.h" @@ -146,7 +146,6 @@ static int sca3000_ring_get_bytes_per_datum(struct iio_buffer *r) } static IIO_BUFFER_ENABLE_ATTR; -static IIO_BUFFER_BYTES_PER_DATUM_ATTR; static IIO_BUFFER_LENGTH_ATTR; /** @@ -158,8 +157,7 @@ static ssize_t sca3000_query_ring_int(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret, val; - struct iio_buffer *ring = dev_get_drvdata(dev); - struct iio_dev *indio_dev = ring->indio_dev; + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct sca3000_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); @@ -180,8 +178,7 @@ static ssize_t sca3000_set_ring_int(struct device *dev, const char *buf, size_t len) { - struct iio_buffer *ring = dev_get_drvdata(dev); - struct iio_dev *indio_dev = ring->indio_dev; + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct sca3000_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); long val; @@ -222,8 +219,7 @@ static ssize_t sca3000_show_buffer_scale(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_buffer *ring = dev_get_drvdata(dev); - struct iio_dev *indio_dev = ring->indio_dev; + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct sca3000_state *st = iio_priv(indio_dev); return sprintf(buf, "0.%06d\n", 4*st->info->scale); @@ -243,7 +239,6 @@ static IIO_DEVICE_ATTR(in_accel_scale, */ static struct attribute *sca3000_ring_attributes[] = { &dev_attr_length.attr, - &dev_attr_bytes_per_datum.attr, &dev_attr_enable.attr, &iio_dev_attr_50_percent.dev_attr.attr, &iio_dev_attr_75_percent.dev_attr.attr, @@ -269,7 +264,7 @@ static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev) buf = &ring->buf; buf->stufftoread = 0; buf->attrs = &sca3000_ring_attr; - iio_buffer_init(buf, indio_dev); + iio_buffer_init(buf); return buf; } @@ -350,7 +345,7 @@ static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { void sca3000_register_ring_funcs(struct iio_dev *indio_dev) { - indio_dev->buffer->setup_ops = &sca3000_ring_setup_ops; + indio_dev->setup_ops = &sca3000_ring_setup_ops; } /** diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 797e65cd03e..45f4504ed92 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -19,7 +19,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger.h" #include "../trigger_consumer.h" @@ -453,25 +453,6 @@ out: return ret; } -static int ad7192_scan_from_ring(struct ad7192_state *st, unsigned ch, int *val) -{ - struct iio_buffer *ring = iio_priv_to_dev(st)->buffer; - int ret; - s64 dat64[2]; - u32 *dat32 = (u32 *)dat64; - - if (!(test_bit(ch, ring->scan_mask))) - return -EBUSY; - - ret = ring->access->read_last(ring, (u8 *) &dat64); - if (ret) - return ret; - - *val = *dat32; - - return 0; -} - static int ad7192_ring_preenable(struct iio_dev *indio_dev) { struct ad7192_state *st = iio_priv(indio_dev); @@ -479,12 +460,14 @@ static int ad7192_ring_preenable(struct iio_dev *indio_dev) size_t d_size; unsigned channel; - if (!ring->scan_count) + if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; - channel = find_first_bit(ring->scan_mask, indio_dev->masklength); + channel = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); - d_size = ring->scan_count * + d_size = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * indio_dev->channels[0].scan_type.storagebits / 8; if (ring->scan_timestamp) { @@ -544,7 +527,7 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p) s64 dat64[2]; s32 *dat32 = (s32 *)dat64; - if (ring->scan_count) + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) __ad7192_read_reg(st, 1, 1, AD7192_REG_DATA, dat32, indio_dev->channels[0].scan_type.realbits/8); @@ -592,7 +575,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev) } /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad7192_ring_setup_ops; + indio_dev->setup_ops = &ad7192_ring_setup_ops; /* Flag that polled ring buffering is possible */ indio_dev->modes |= INDIO_BUFFER_TRIGGERED; @@ -626,6 +609,10 @@ static irqreturn_t ad7192_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } +static struct iio_trigger_ops ad7192_trigger_ops = { + .owner = THIS_MODULE, +}; + static int ad7192_probe_trigger(struct iio_dev *indio_dev) { struct ad7192_state *st = iio_priv(indio_dev); @@ -638,7 +625,7 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev) ret = -ENOMEM; goto error_ret; } - + st->trig->ops = &ad7192_trigger_ops; ret = request_irq(st->spi->irq, ad7192_data_rdy_trig_poll, IRQF_TRIGGER_LOW, @@ -650,7 +637,6 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev) disable_irq_nosync(st->spi->irq); st->irq_dis = true; st->trig->dev.parent = &st->spi->dev; - st->trig->owner = THIS_MODULE; st->trig->private_data = indio_dev; ret = iio_trigger_register(st->trig); @@ -795,7 +781,7 @@ static ssize_t ad7192_set(struct device *dev, return -EBUSY; } - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD7192_REG_GPOCON: if (val) st->gpocon |= AD7192_GPOCON_BPDSW; @@ -873,8 +859,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, case 0: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) - ret = ad7192_scan_from_ring(st, - chan->scan_index, &smpl); + ret = -EBUSY; else ret = ad7192_read(st, chan->address, chan->scan_type.realbits / 8, &smpl); @@ -901,18 +886,20 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, } return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): - mutex_lock(&indio_dev->mlock); - *val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0]; - *val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1]; - mutex_unlock(&indio_dev->mlock); - - return IIO_VAL_INT_PLUS_NANO; - - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - *val = 1000; - - return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + mutex_lock(&indio_dev->mlock); + *val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0]; + *val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1]; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT_PLUS_NANO; + case IIO_TEMP: + *val = 1000; + return IIO_VAL_INT; + default: + return -EINVAL; + } } return -EINVAL; @@ -935,7 +922,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, } switch (mask) { - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: ret = -EINVAL; for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) if (val2 == st->scale_avail[i][1]) { @@ -992,7 +979,7 @@ static const struct iio_info ad7192_info = { .extend_name = _name, \ .channel = _chan, \ .channel2 = _chan2, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = _address, \ .scan_index = _si, \ .scan_type = IIO_ST('s', 24, 32, 0)} @@ -1001,7 +988,7 @@ static const struct iio_info ad7192_info = { { .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = _chan, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = _address, \ .scan_index = _si, \ .scan_type = IIO_ST('s', 24, 32, 0)} @@ -1010,7 +997,7 @@ static const struct iio_info ad7192_info = { { .type = IIO_TEMP, \ .indexed = 1, \ .channel = _chan, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = _address, \ .scan_index = _si, \ .scan_type = IIO_ST('s', 24, 32, 0)} @@ -1151,6 +1138,7 @@ static const struct spi_device_id ad7192_id[] = { {"ad7195", ID_AD7195}, {} }; +MODULE_DEVICE_TABLE(spi, ad7192_id); static struct spi_driver ad7192_driver = { .driver = { diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index dbaeae81e87..7dbd6812c24 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -18,6 +18,7 @@ #include "../iio.h" #include "../sysfs.h" +#include "../events.h" #include "ad7280a.h" @@ -455,10 +456,10 @@ static ssize_t ad7280_store_balance_timer(struct device *dev, struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7280_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long val; + unsigned long val; int ret; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) return ret; @@ -487,8 +488,8 @@ static int ad7280_channel_init(struct ad7280_state *st) { int dev, ch, cnt; - st->channels = kzalloc(sizeof(*st->channels) * - ((st->slave_num + 1) * 12 + 2), GFP_KERNEL); + st->channels = kcalloc((st->slave_num + 1) * 12 + 2, + sizeof(*st->channels), GFP_KERNEL); if (st->channels == NULL) return -ENOMEM; @@ -507,7 +508,7 @@ static int ad7280_channel_init(struct ad7280_state *st) } st->channels[cnt].indexed = 1; st->channels[cnt].info_mask = - (1 << IIO_CHAN_INFO_SCALE_SHARED); + IIO_CHAN_INFO_SCALE_SHARED_BIT; st->channels[cnt].address = AD7280A_DEVADDR(dev) << 8 | ch; st->channels[cnt].scan_index = cnt; @@ -523,7 +524,7 @@ static int ad7280_channel_init(struct ad7280_state *st) st->channels[cnt].channel2 = dev * 6; st->channels[cnt].address = AD7280A_ALL_CELLS; st->channels[cnt].indexed = 1; - st->channels[cnt].info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED); + st->channels[cnt].info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT; st->channels[cnt].scan_index = cnt; st->channels[cnt].scan_type.sign = 'u'; st->channels[cnt].scan_type.realbits = 32; @@ -600,7 +601,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); unsigned val; - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD7280A_CELL_OVERVOLTAGE: val = 1000 + (st->cell_threshhigh * 1568) / 100; break; @@ -636,7 +637,7 @@ static ssize_t ad7280_write_channel_config(struct device *dev, if (ret) return ret; - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD7280A_CELL_OVERVOLTAGE: case AD7280A_CELL_UNDERVOLTAGE: val = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ @@ -652,7 +653,7 @@ static ssize_t ad7280_write_channel_config(struct device *dev, val = clamp(val, 0L, 0xFFL); mutex_lock(&indio_dev->mlock); - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD7280A_CELL_OVERVOLTAGE: st->cell_threshhigh = val; break; @@ -682,13 +683,13 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) unsigned *channels; int i, ret; - channels = kzalloc(sizeof(*channels) * st->scan_cnt, GFP_KERNEL); + channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL); if (channels == NULL) return IRQ_HANDLED; ret = ad7280_read_all_channels(st, st->scan_cnt, channels); if (ret < 0) - return IRQ_HANDLED; + goto out; for (i = 0; i < st->scan_cnt; i++) { if (((channels[i] >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6) { @@ -731,6 +732,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) } } +out: kfree(channels); return IRQ_HANDLED; @@ -801,7 +803,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6) scale_uv = (4000 * 1000) >> AD7280A_BITS; else @@ -968,11 +970,11 @@ static const struct spi_device_id ad7280_id[] = { {"ad7280a", 0}, {} }; +MODULE_DEVICE_TABLE(spi, ad7280_id); static struct spi_driver ad7280_driver = { .driver = { .name = "ad7280", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7280_probe, diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c index aa44a52a7ad..0a13616e3db 100644 --- a/drivers/staging/iio/adc/ad7291.c +++ b/drivers/staging/iio/adc/ad7291.c @@ -19,6 +19,7 @@ #include "../iio.h" #include "../sysfs.h" +#include "../events.h" /* * Simplified handling @@ -500,7 +501,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case (1 << IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE): + case IIO_CHAN_INFO_AVERAGE_RAW: ret = i2c_smbus_read_word_data(chip->client, AD7291_T_AVERAGE); if (ret < 0) @@ -509,18 +510,24 @@ static int ad7291_read_raw(struct iio_dev *indio_dev, AD7291_VALUE_MASK) << 4) >> 4; *val = signval; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): - scale_uv = (chip->int_vref_mv * 1000) >> AD7291_BITS; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - /* - * One LSB of the ADC corresponds to 0.25 deg C. - * The temperature reading is in 12-bit twos complement format - */ - *val = 250; - return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + scale_uv = (chip->int_vref_mv * 1000) >> AD7291_BITS; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + /* + * One LSB of the ADC corresponds to 0.25 deg C. + * The temperature reading is in 12-bit twos + * complement format + */ + *val = 250; + return IIO_VAL_INT; + default: + return -EINVAL; + } default: return -EINVAL; } @@ -529,7 +536,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev, #define AD7291_VOLTAGE_CHAN(_chan) \ { \ .type = IIO_VOLTAGE, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .indexed = 1, \ .channel = _chan, \ .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\ @@ -547,8 +554,8 @@ static const struct iio_chan_spec ad7291_channels[] = { AD7291_VOLTAGE_CHAN(7), { .type = IIO_TEMP, - .info_mask = (1 << IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .indexed = 1, .channel = 0, .event_mask = diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h index 9ddf5cf0e51..a0e5dea415e 100644 --- a/drivers/staging/iio/adc/ad7298.h +++ b/drivers/staging/iio/adc/ad7298.h @@ -54,14 +54,9 @@ struct ad7298_state { }; #ifdef CONFIG_IIO_BUFFER -int ad7298_scan_from_ring(struct iio_dev *indio_dev, long ch); int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev); void ad7298_ring_cleanup(struct iio_dev *indio_dev); #else /* CONFIG_IIO_BUFFER */ -static inline int ad7298_scan_from_ring(struct iio_dev *indio_dev, long ch) -{ - return 0; -} static inline int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c index a799bd1922d..8dd6aa9cf92 100644 --- a/drivers/staging/iio/adc/ad7298_core.c +++ b/drivers/staging/iio/adc/ad7298_core.c @@ -18,37 +18,37 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "ad7298.h" static struct iio_chan_spec ad7298_channels[] = { IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, 9, AD7298_CH_TEMP, IIO_ST('s', 32, 32, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 1, 1, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 2, 2, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 3, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 3, 3, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 4, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 4, 4, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 5, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 5, 5, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 6, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 6, 6, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 7, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 7, 7, IIO_ST('u', 12, 16, 0), 0), IIO_CHAN_SOFT_TIMESTAMP(8), }; @@ -69,27 +69,28 @@ static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) static int ad7298_scan_temp(struct ad7298_state *st, int *val) { int tmp, ret; + __be16 buf; - tmp = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | + buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | AD7298_TAVG | st->ext_ref); - ret = spi_write(st->spi, (u8 *)&tmp, 2); + ret = spi_write(st->spi, (u8 *)&buf, 2); if (ret) return ret; - tmp = 0; + buf = cpu_to_be16(0); - ret = spi_write(st->spi, (u8 *)&tmp, 2); + ret = spi_write(st->spi, (u8 *)&buf, 2); if (ret) return ret; usleep_range(101, 1000); /* sleep > 100us */ - ret = spi_read(st->spi, (u8 *)&tmp, 2); + ret = spi_read(st->spi, (u8 *)&buf, 2); if (ret) return ret; - tmp = be16_to_cpu(tmp) & RES_MASK(AD7298_BITS); + tmp = be16_to_cpu(buf) & RES_MASK(AD7298_BITS); /* * One LSB of the ADC corresponds to 0.25 deg C. @@ -122,12 +123,8 @@ static int ad7298_read_raw(struct iio_dev *indio_dev, switch (m) { case 0: mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) { - if (chan->address == AD7298_CH_TEMP) - ret = -ENODEV; - else - ret = ad7298_scan_from_ring(indio_dev, - chan->address); + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { + ret = -EBUSY; } else { if (chan->address == AD7298_CH_TEMP) ret = ad7298_scan_temp(st, val); @@ -143,15 +140,20 @@ static int ad7298_read_raw(struct iio_dev *indio_dev, *val = ret & RES_MASK(AD7298_BITS); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): - scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - *val = 1; - *val2 = 0; - return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = 1; + *val2 = 0; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } } return -EINVAL; } @@ -265,11 +267,11 @@ static const struct spi_device_id ad7298_id[] = { {"ad7298", 0}, {} }; +MODULE_DEVICE_TABLE(spi, ad7298_id); static struct spi_driver ad7298_driver = { .driver = { .name = "ad7298", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7298_probe, @@ -281,4 +283,3 @@ module_spi_driver(ad7298_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD7298 ADC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad7298"); diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c index 47630d506a6..d1a12dd015e 100644 --- a/drivers/staging/iio/adc/ad7298_ring.c +++ b/drivers/staging/iio/adc/ad7298_ring.c @@ -12,41 +12,12 @@ #include <linux/spi/spi.h> #include "../iio.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger_consumer.h" #include "ad7298.h" -int ad7298_scan_from_ring(struct iio_dev *indio_dev, long ch) -{ - struct iio_buffer *ring = indio_dev->buffer; - int ret; - u16 *ring_data; - - if (!(test_bit(ch, ring->scan_mask))) { - ret = -EBUSY; - goto error_ret; - } - - ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), - GFP_KERNEL); - if (ring_data == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = ring->access->read_last(ring, (u8 *) ring_data); - if (ret) - goto error_free_ring_data; - - ret = be16_to_cpu(ring_data[ch]); - -error_free_ring_data: - kfree(ring_data); -error_ret: - return ret; -} - /** * ad7298_ring_preenable() setup the parameters of the ring before enabling * @@ -61,8 +32,9 @@ static int ad7298_ring_preenable(struct iio_dev *indio_dev) size_t d_size; int i, m; unsigned short command; - - d_size = ring->scan_count * (AD7298_STORAGE_BITS / 8); + int scan_count = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); + d_size = scan_count * (AD7298_STORAGE_BITS / 8); if (ring->scan_timestamp) { d_size += sizeof(s64); @@ -79,7 +51,7 @@ static int ad7298_ring_preenable(struct iio_dev *indio_dev) command = AD7298_WRITE | st->ext_ref; for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1) - if (test_bit(i, ring->scan_mask)) + if (test_bit(i, indio_dev->active_scan_mask)) command |= m; st->tx_buf[0] = cpu_to_be16(command); @@ -96,7 +68,7 @@ static int ad7298_ring_preenable(struct iio_dev *indio_dev) spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg); - for (i = 0; i < ring->scan_count; i++) { + for (i = 0; i < scan_count; i++) { st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i]; st->ring_xfer[i + 2].len = 2; st->ring_xfer[i + 2].cs_change = 1; @@ -134,7 +106,8 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) &time_ns, sizeof(time_ns)); } - for (i = 0; i < ring->scan_count; i++) + for (i = 0; i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); i++) buf[i] = be16_to_cpu(st->rx_buf[i]); indio_dev->buffer->access->store_to(ring, (u8 *)buf, time_ns); @@ -174,7 +147,7 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) } /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad7298_ring_setup_ops; + indio_dev->setup_ops = &ad7298_ring_setup_ops; indio_dev->buffer->scan_timestamp = true; /* Flag that polled ring buffering is possible */ diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h index 60142926565..27f696c75cc 100644 --- a/drivers/staging/iio/adc/ad7476.h +++ b/drivers/staging/iio/adc/ad7476.h @@ -50,14 +50,9 @@ enum ad7476_supported_device_ids { }; #ifdef CONFIG_IIO_BUFFER -int ad7476_scan_from_ring(struct iio_dev *indio_dev); int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev); void ad7476_ring_cleanup(struct iio_dev *indio_dev); #else /* CONFIG_IIO_BUFFER */ -static inline int ad7476_scan_from_ring(struct iio_dev *indio_dev) -{ - return 0; -} static inline int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c index 0b5852030ab..0c064d1c392 100644 --- a/drivers/staging/iio/adc/ad7476_core.c +++ b/drivers/staging/iio/adc/ad7476_core.c @@ -17,7 +17,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "ad7476.h" @@ -46,7 +46,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, case 0: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) - ret = ad7476_scan_from_ring(indio_dev); + ret = -EBUSY; else ret = ad7476_scan_direct(st); mutex_unlock(&indio_dev->mlock); @@ -56,7 +56,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, *val = (ret >> st->chip_info->channel[0].scan_type.shift) & RES_MASK(st->chip_info->channel[0].scan_type.realbits); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->channel[0].scan_type.realbits; *val = scale_uv/1000; @@ -69,49 +69,49 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { [ID_AD7466] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 12, 16, 0), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7467] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 10, 16, 2), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7468] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1 , 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 8, 16, 4), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7475] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 12, 16, 0), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7476] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 12, 16, 0), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7477] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 10, 16, 2), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7478] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 8, 16, 4), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7495] = { .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('u', 12, 16, 0), 0), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .int_vref_mv = 2500, @@ -237,11 +237,11 @@ static const struct spi_device_id ad7476_id[] = { {"ad7495", ID_AD7495}, {} }; +MODULE_DEVICE_TABLE(spi, ad7476_id); static struct spi_driver ad7476_driver = { .driver = { .name = "ad7476", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7476_probe, @@ -253,4 +253,3 @@ module_spi_driver(ad7476_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad7476"); diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c index e82c1a433f4..4e298b2a05b 100644 --- a/drivers/staging/iio/adc/ad7476_ring.c +++ b/drivers/staging/iio/adc/ad7476_ring.c @@ -14,36 +14,12 @@ #include <linux/spi/spi.h> #include "../iio.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger_consumer.h" #include "ad7476.h" -int ad7476_scan_from_ring(struct iio_dev *indio_dev) -{ - struct iio_buffer *ring = indio_dev->buffer; - int ret; - u8 *ring_data; - - ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), - GFP_KERNEL); - if (ring_data == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = ring->access->read_last(ring, ring_data); - if (ret) - goto error_free_ring_data; - - ret = (ring_data[0] << 8) | ring_data[1]; - -error_free_ring_data: - kfree(ring_data); -error_ret: - return ret; -} - /** * ad7476_ring_preenable() setup the parameters of the ring before enabling * @@ -56,7 +32,8 @@ static int ad7476_ring_preenable(struct iio_dev *indio_dev) struct ad7476_state *st = iio_priv(indio_dev); struct iio_buffer *ring = indio_dev->buffer; - st->d_size = ring->scan_count * + st->d_size = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * st->chip_info->channel[0].scan_type.storagebits / 8; if (ring->scan_timestamp) { @@ -137,7 +114,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) } /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad7476_ring_setup_ops; + indio_dev->setup_ops = &ad7476_ring_setup_ops; indio_dev->buffer->scan_timestamp = true; /* Flag that polled ring buffering is possible */ diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 35018c3f518..10f59896597 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -99,7 +99,6 @@ enum ad7606_supported_device_ids { ID_AD7606_4 }; -int ad7606_scan_from_ring(struct iio_dev *indio_dev, unsigned ch); int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev); void ad7606_ring_cleanup(struct iio_dev *indio_dev); #endif /* IIO_ADC_AD7606_H_ */ diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index e3ecd3d2ef3..ddb7ef92f5c 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -20,7 +20,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "ad7606.h" @@ -91,7 +91,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, case 0: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) - ret = ad7606_scan_from_ring(indio_dev, chan->address); + ret = -EBUSY; else ret = ad7606_scan_direct(indio_dev, chan->address); mutex_unlock(&indio_dev->mlock); @@ -100,7 +100,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, return ret; *val = (short) ret; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: scale_uv = (st->range * 1000 * 2) >> st->chip_info->channels[0].scan_type.realbits; *val = scale_uv / 1000; diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index 688632edd3d..cff97568189 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -189,4 +189,3 @@ module_exit(ad7606_cleanup); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:ad7606_par"); diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index 20927fd5372..e8f94a18a94 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -12,36 +12,12 @@ #include <linux/slab.h> #include "../iio.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger_consumer.h" #include "ad7606.h" -int ad7606_scan_from_ring(struct iio_dev *indio_dev, unsigned ch) -{ - struct iio_buffer *ring = indio_dev->buffer; - int ret; - u16 *ring_data; - - ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), - GFP_KERNEL); - if (ring_data == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = ring->access->read_last(ring, (u8 *) ring_data); - if (ret) - goto error_free_ring_data; - - ret = ring_data[ch]; - -error_free_ring_data: - kfree(ring_data); -error_ret: - return ret; -} - /** * ad7606_trigger_handler_th() th/bh of trigger launched polling to ring buffer * @@ -136,8 +112,6 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ indio_dev->buffer->access = &ring_sw_access_funcs; - indio_dev->buffer->bpe = - st->chip_info->channels[0].scan_type.storagebits / 8; indio_dev->pollfunc = iio_alloc_pollfunc(&ad7606_trigger_handler_th_bh, &ad7606_trigger_handler_th_bh, 0, @@ -152,7 +126,7 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad7606_ring_setup_ops; + indio_dev->setup_ops = &ad7606_ring_setup_ops; indio_dev->buffer->scan_timestamp = true ; INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index b984bd2048b..237f1c44d29 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -97,11 +97,11 @@ static const struct spi_device_id ad7606_id[] = { {"ad7606-4", ID_AD7606_4}, {} }; +MODULE_DEVICE_TABLE(spi, ad7606_id); static struct spi_driver ad7606_driver = { .driver = { .name = "ad7606", - .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = AD7606_SPI_PM_OPS, }, @@ -114,4 +114,3 @@ module_spi_driver(ad7606_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad7606_spi"); diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index ec90261cbc3..a13e58c814e 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -114,7 +114,7 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, *val *= 128; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: scale_uv = (st->int_vref_mv * 100000) >> (channel.scan_type.realbits - 1); *val = scale_uv / 100000; @@ -127,12 +127,12 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { [ID_AD7780] = { .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('s', 24, 32, 8), 0), }, [ID_AD7781] = { .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, 0, 0, IIO_ST('s', 20, 32, 12), 0), }, }; @@ -272,11 +272,11 @@ static const struct spi_device_id ad7780_id[] = { {"ad7781", ID_AD7781}, {} }; +MODULE_DEVICE_TABLE(spi, ad7780_id); static struct spi_driver ad7780_driver = { .driver = { .name = "ad7780", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7780_probe, diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c index 1c5588e88cd..6a058b19c49 100644 --- a/drivers/staging/iio/adc/ad7793.c +++ b/drivers/staging/iio/adc/ad7793.c @@ -20,7 +20,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger.h" #include "../trigger_consumer.h" @@ -316,25 +316,6 @@ out: return ret; } -static int ad7793_scan_from_ring(struct ad7793_state *st, unsigned ch, int *val) -{ - struct iio_buffer *ring = iio_priv_to_dev(st)->buffer; - int ret; - s64 dat64[2]; - u32 *dat32 = (u32 *)dat64; - - if (!(test_bit(ch, ring->scan_mask))) - return -EBUSY; - - ret = ring->access->read_last(ring, (u8 *) &dat64); - if (ret) - return ret; - - *val = *dat32; - - return 0; -} - static int ad7793_ring_preenable(struct iio_dev *indio_dev) { struct ad7793_state *st = iio_priv(indio_dev); @@ -342,14 +323,15 @@ static int ad7793_ring_preenable(struct iio_dev *indio_dev) size_t d_size; unsigned channel; - if (!ring->scan_count) + if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; - channel = find_first_bit(ring->scan_mask, + channel = find_first_bit(indio_dev->active_scan_mask, indio_dev->masklength); - d_size = ring->scan_count * - indio_dev->channels[0].scan_type.storagebits / 8; + d_size = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * + indio_dev->channels[0].scan_type.storagebits / 8; if (ring->scan_timestamp) { d_size += sizeof(s64); @@ -411,7 +393,7 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p) s64 dat64[2]; s32 *dat32 = (s32 *)dat64; - if (ring->scan_count) + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) __ad7793_read_reg(st, 1, 1, AD7793_REG_DATA, dat32, indio_dev->channels[0].scan_type.realbits/8); @@ -459,7 +441,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev) } /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad7793_ring_setup_ops; + indio_dev->setup_ops = &ad7793_ring_setup_ops; /* Flag that polled ring buffering is possible */ indio_dev->modes |= INDIO_BUFFER_TRIGGERED; @@ -493,6 +475,10 @@ static irqreturn_t ad7793_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } +static struct iio_trigger_ops ad7793_trigger_ops = { + .owner = THIS_MODULE, +}; + static int ad7793_probe_trigger(struct iio_dev *indio_dev) { struct ad7793_state *st = iio_priv(indio_dev); @@ -505,6 +491,7 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev) ret = -ENOMEM; goto error_ret; } + st->trig->ops = &ad7793_trigger_ops; ret = request_irq(st->spi->irq, ad7793_data_rdy_trig_poll, @@ -517,7 +504,6 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev) disable_irq_nosync(st->spi->irq); st->irq_dis = true; st->trig->dev.parent = &st->spi->dev; - st->trig->owner = THIS_MODULE; st->trig->private_data = indio_dev; ret = iio_trigger_register(st->trig); @@ -649,8 +635,7 @@ static int ad7793_read_raw(struct iio_dev *indio_dev, case 0: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) - ret = ad7793_scan_from_ring(st, - chan->scan_index, &smpl); + ret = -EBUSY; else ret = ad7793_read(st, chan->address, chan->scan_type.realbits / 8, &smpl); @@ -667,19 +652,21 @@ static int ad7793_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): - *val = st->scale_avail[(st->conf >> 8) & 0x7][0]; - *val2 = st->scale_avail[(st->conf >> 8) & 0x7][1]; - - return IIO_VAL_INT_PLUS_NANO; - - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: - /* 1170mV / 2^23 * 6 */ - scale_uv = (1170ULL * 100000000ULL * 6ULL) - >> (chan->scan_type.realbits - - (unipolar ? 0 : 1)); + if (chan->differential) { + *val = st-> + scale_avail[(st->conf >> 8) & 0x7][0]; + *val2 = st-> + scale_avail[(st->conf >> 8) & 0x7][1]; + return IIO_VAL_INT_PLUS_NANO; + } else { + /* 1170mV / 2^23 * 6 */ + scale_uv = (1170ULL * 100000000ULL * 6ULL) + >> (chan->scan_type.realbits - + (unipolar ? 0 : 1)); + } break; case IIO_TEMP: /* Always uses unity gain and internal ref */ @@ -716,7 +703,7 @@ static int ad7793_write_raw(struct iio_dev *indio_dev, } switch (mask) { - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: ret = -EINVAL; for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) if (val2 == st->scale_avail[i][1]) { @@ -775,7 +762,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 0, .channel2 = 0, .address = AD7793_CH_AIN1P_AIN1M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 0, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -786,7 +773,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 1, .channel2 = 1, .address = AD7793_CH_AIN2P_AIN2M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 1, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -797,7 +784,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN3P_AIN3M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -809,7 +796,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN1M_AIN1M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -818,7 +805,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 0, .address = AD7793_CH_TEMP, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 4, .scan_type = IIO_ST('s', 24, 32, 0), }, @@ -828,7 +815,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 4, .address = AD7793_CH_AVDD_MONITOR, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 5, .scan_type = IIO_ST('s', 24, 32, 0), }, @@ -842,7 +829,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 0, .channel2 = 0, .address = AD7793_CH_AIN1P_AIN1M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 0, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -853,7 +840,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 1, .channel2 = 1, .address = AD7793_CH_AIN2P_AIN2M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 1, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -864,7 +851,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN3P_AIN3M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -876,7 +863,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN1M_AIN1M, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -885,7 +872,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 0, .address = AD7793_CH_TEMP, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 4, .scan_type = IIO_ST('s', 16, 32, 0), }, @@ -895,7 +882,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 4, .address = AD7793_CH_AVDD_MONITOR, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 5, .scan_type = IIO_ST('s', 16, 32, 0), }, @@ -1034,11 +1021,11 @@ static const struct spi_device_id ad7793_id[] = { {"ad7793", ID_AD7793}, {} }; +MODULE_DEVICE_TABLE(spi, ad7793_id); static struct spi_driver ad7793_driver = { .driver = { .name = "ad7793", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7793_probe, diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index acbf9363132..52b720e2b03 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -18,6 +18,7 @@ #include "../iio.h" #include "../sysfs.h" +#include "../events.h" /* * AD7816 config masks @@ -459,7 +460,6 @@ MODULE_DEVICE_TABLE(spi, ad7816_id); static struct spi_driver ad7816_driver = { .driver = { .name = "ad7816", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7816_probe, diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h index 3452d181907..bc53b653212 100644 --- a/drivers/staging/iio/adc/ad7887.h +++ b/drivers/staging/iio/adc/ad7887.h @@ -83,14 +83,9 @@ enum ad7887_supported_device_ids { }; #ifdef CONFIG_IIO_BUFFER -int ad7887_scan_from_ring(struct ad7887_state *st, int channum); int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev); void ad7887_ring_cleanup(struct iio_dev *indio_dev); #else /* CONFIG_IIO_BUFFER */ -static inline int ad7887_scan_from_ring(struct ad7887_state *st, int channum) -{ - return 0; -} static inline int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c index 91b8fb09d92..e9bbc3eed15 100644 --- a/drivers/staging/iio/adc/ad7887_core.c +++ b/drivers/staging/iio/adc/ad7887_core.c @@ -17,7 +17,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "ad7887.h" @@ -45,7 +45,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev, case 0: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) - ret = ad7887_scan_from_ring(st, 1 << chan->address); + ret = -EBUSY; else ret = ad7887_scan_direct(st, chan->address); mutex_unlock(&indio_dev->mlock); @@ -55,7 +55,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev, *val = (ret >> st->chip_info->channel[0].scan_type.shift) & RES_MASK(st->chip_info->channel[0].scan_type.realbits); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->channel[0].scan_type.realbits; *val = scale_uv/1000; @@ -75,7 +75,7 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = 1, .scan_index = 1, .scan_type = IIO_ST('u', 12, 16, 0), @@ -84,7 +84,7 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = 0, .scan_index = 0, .scan_type = IIO_ST('u', 12, 16, 0), @@ -246,11 +246,11 @@ static const struct spi_device_id ad7887_id[] = { {"ad7887", ID_AD7887}, {} }; +MODULE_DEVICE_TABLE(spi, ad7887_id); static struct spi_driver ad7887_driver = { .driver = { .name = "ad7887", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7887_probe, @@ -262,4 +262,3 @@ module_spi_driver(ad7887_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD7887 ADC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad7887"); diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c index cb74cada561..85076cd962e 100644 --- a/drivers/staging/iio/adc/ad7887_ring.c +++ b/drivers/staging/iio/adc/ad7887_ring.c @@ -13,46 +13,12 @@ #include <linux/spi/spi.h> #include "../iio.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger_consumer.h" #include "ad7887.h" -int ad7887_scan_from_ring(struct ad7887_state *st, int channum) -{ - struct iio_buffer *ring = iio_priv_to_dev(st)->buffer; - int count = 0, ret; - u16 *ring_data; - - if (!(test_bit(channum, ring->scan_mask))) { - ret = -EBUSY; - goto error_ret; - } - - ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), - GFP_KERNEL); - if (ring_data == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = ring->access->read_last(ring, (u8 *) ring_data); - if (ret) - goto error_free_ring_data; - - /* for single channel scan the result is stored with zero offset */ - if ((test_bit(1, ring->scan_mask) || test_bit(0, ring->scan_mask)) && - (channum == 1)) - count = 1; - - ret = be16_to_cpu(ring_data[count]); - -error_free_ring_data: - kfree(ring_data); -error_ret: - return ret; -} - /** * ad7887_ring_preenable() setup the parameters of the ring before enabling * @@ -65,7 +31,8 @@ static int ad7887_ring_preenable(struct iio_dev *indio_dev) struct ad7887_state *st = iio_priv(indio_dev); struct iio_buffer *ring = indio_dev->buffer; - st->d_size = ring->scan_count * + st->d_size = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * st->chip_info->channel[0].scan_type.storagebits / 8; if (ring->scan_timestamp) { @@ -80,7 +47,7 @@ static int ad7887_ring_preenable(struct iio_dev *indio_dev) set_bytes_per_datum(indio_dev->buffer, st->d_size); /* We know this is a single long so can 'cheat' */ - switch (*ring->scan_mask) { + switch (*indio_dev->active_scan_mask) { case (1 << 0): st->ring_msg = &st->msg[AD7887_CH0]; break; @@ -121,7 +88,8 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) __u8 *buf; int b_sent; - unsigned int bytes = ring->scan_count * + unsigned int bytes = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * st->chip_info->channel[0].scan_type.storagebits / 8; buf = kzalloc(st->d_size, GFP_KERNEL); @@ -176,7 +144,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) goto error_deallocate_sw_rb; } /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad7887_ring_setup_ops; + indio_dev->setup_ops = &ad7887_ring_setup_ops; /* Flag that polled ring buffering is possible */ indio_dev->modes |= INDIO_BUFFER_TRIGGERED; diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h index eda01d5bab7..356f690a76f 100644 --- a/drivers/staging/iio/adc/ad799x.h +++ b/drivers/staging/iio/adc/ad799x.h @@ -124,15 +124,9 @@ struct ad799x_platform_data { int ad7997_8_set_scan_mode(struct ad799x_state *st, unsigned mask); #ifdef CONFIG_AD799X_RING_BUFFER -int ad799x_single_channel_from_ring(struct iio_dev *indio_dev, int channum); int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev); void ad799x_ring_cleanup(struct iio_dev *indio_dev); #else /* CONFIG_AD799X_RING_BUFFER */ -int ad799x_single_channel_from_ring(struct iio_dev *indio_dev, int channum) -{ - return -EINVAL; -} - static inline int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index c0d2f886ea2..d5b581d8bc2 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -35,7 +35,8 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../events.h" +#include "../buffer.h" #include "ad799x.h" @@ -150,8 +151,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, case 0: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) - ret = ad799x_single_channel_from_ring(indio_dev, - chan->scan_index); + ret = -EBUSY; else ret = ad799x_scan_direct(st, chan->scan_index); mutex_unlock(&indio_dev->mlock); @@ -161,7 +161,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, *val = (ret >> chan->scan_type.shift) & RES_MASK(chan->scan_type.realbits); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: scale_uv = (st->int_vref_mv * 1000) >> chan->scan_type.realbits; *val = scale_uv / 1000; *val2 = (scale_uv % 1000) * 1000; @@ -934,4 +934,3 @@ module_i2c_driver(ad799x_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD799x ADC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("i2c:ad799x"); diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c index e3f4698d781..5dded9e7820 100644 --- a/drivers/staging/iio/adc/ad799x_ring.c +++ b/drivers/staging/iio/adc/ad799x_ring.c @@ -17,42 +17,12 @@ #include <linux/bitops.h> #include "../iio.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger_consumer.h" #include "ad799x.h" -int ad799x_single_channel_from_ring(struct iio_dev *indio_dev, int channum) -{ - struct iio_buffer *ring = indio_dev->buffer; - int count = 0, ret; - u16 *ring_data; - - if (!(test_bit(channum, ring->scan_mask))) { - ret = -EBUSY; - goto error_ret; - } - - ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), - GFP_KERNEL); - if (ring_data == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = ring->access->read_last(ring, (u8 *) ring_data); - if (ret) - goto error_free_ring_data; - /* Need a count of channels prior to this one */ - count = bitmap_weight(ring->scan_mask, channum); - ret = be16_to_cpu(ring_data[count]); - -error_free_ring_data: - kfree(ring_data); -error_ret: - return ret; -} - /** * ad799x_ring_preenable() setup the parameters of the ring before enabling * @@ -71,9 +41,10 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev) */ if (st->id == ad7997 || st->id == ad7998) - ad7997_8_set_scan_mode(st, *ring->scan_mask); + ad7997_8_set_scan_mode(st, *indio_dev->active_scan_mask); - st->d_size = ring->scan_count * 2; + st->d_size = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * 2; if (ring->scan_timestamp) { st->d_size += sizeof(s64); @@ -115,12 +86,13 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) case ad7991: case ad7995: case ad7999: - cmd = st->config | (*ring->scan_mask << AD799X_CHANNEL_SHIFT); + cmd = st->config | + (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); break; case ad7992: case ad7993: case ad7994: - cmd = (*ring->scan_mask << AD799X_CHANNEL_SHIFT) | + cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | AD7998_CONV_RES_REG; break; case ad7997: @@ -132,7 +104,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) } b_sent = i2c_smbus_read_i2c_block_data(st->client, - cmd, ring->scan_count * 2, rxbuf); + cmd, bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * 2, rxbuf); if (b_sent < 0) goto done; @@ -183,7 +156,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) } /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad799x_buf_setup_ops; + indio_dev->setup_ops = &ad799x_buf_setup_ops; indio_dev->buffer->scan_timestamp = true; /* Flag that polled ring buffering is possible */ diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c index bc307f3b024..eec2f325d54 100644 --- a/drivers/staging/iio/adc/adt7310.c +++ b/drivers/staging/iio/adc/adt7310.c @@ -17,7 +17,7 @@ #include "../iio.h" #include "../sysfs.h" - +#include "../events.h" /* * ADT7310 registers definition */ @@ -877,7 +877,6 @@ MODULE_DEVICE_TABLE(spi, adt7310_id); static struct spi_driver adt7310_driver = { .driver = { .name = "adt7310", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = adt7310_probe, diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c index 3481cf6f757..c62248ceb37 100644 --- a/drivers/staging/iio/adc/adt7410.c +++ b/drivers/staging/iio/adc/adt7410.c @@ -17,6 +17,7 @@ #include "../iio.h" #include "../sysfs.h" +#include "../events.h" /* * ADT7410 registers definition diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h index cbcb08a2cb5..2cd0112067b 100644 --- a/drivers/staging/iio/adc/max1363.h +++ b/drivers/staging/iio/adc/max1363.h @@ -146,22 +146,22 @@ struct max1363_state { }; const struct max1363_mode -*max1363_match_mode(unsigned long *mask, const struct max1363_chip_info *ci); +*max1363_match_mode(const unsigned long *mask, + const struct max1363_chip_info *ci); int max1363_set_scan_mode(struct max1363_state *st); #ifdef CONFIG_MAX1363_RING_BUFFER - -int max1363_single_channel_from_ring(const long *mask, - struct max1363_state *st); +int max1363_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask); int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev); void max1363_ring_cleanup(struct iio_dev *indio_dev); #else /* CONFIG_MAX1363_RING_BUFFER */ - -int max1363_single_channel_from_ring(long mask, struct max1363_state *st) +int max1363_update_scan_mode(struct iio_dev *indio_dev, + const long *scan_mask) { - return -EINVAL; + return 0; } static inline int diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 3f28f1ab52a..b92cb4af18c 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -34,7 +34,8 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../events.h" +#include "../buffer.h" #include "max1363.h" @@ -147,7 +148,8 @@ static const struct max1363_mode max1363_mode_table[] = { }; const struct max1363_mode -*max1363_match_mode(unsigned long *mask, const struct max1363_chip_info *ci) +*max1363_match_mode(const unsigned long *mask, +const struct max1363_chip_info *ci) { int i; if (mask) @@ -189,7 +191,6 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, int ret = 0; s32 data; char rxbuf[2]; - const unsigned long *mask; struct max1363_state *st = iio_priv(indio_dev); struct i2c_client *client = st->client; @@ -198,46 +199,38 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, * If monitor mode is enabled, the method for reading a single * channel will have to be rather different and has not yet * been implemented. + * + * Also, cannot read directly if buffered capture enabled. */ - if (st->monitor_on) { + if (st->monitor_on || iio_buffer_enabled(indio_dev)) { ret = -EBUSY; goto error_ret; } - /* If ring buffer capture is occurring, query the buffer */ - if (iio_buffer_enabled(indio_dev)) { - mask = max1363_mode_table[chan->address].modemask; - data = max1363_single_channel_from_ring(mask, st); + /* Check to see if current scan mode is correct */ + if (st->current_mode != &max1363_mode_table[chan->address]) { + /* Update scan mode if needed */ + st->current_mode = &max1363_mode_table[chan->address]; + ret = max1363_set_scan_mode(st); + if (ret < 0) + goto error_ret; + } + if (st->chip_info->bits != 8) { + /* Get reading */ + data = i2c_master_recv(client, rxbuf, 2); if (data < 0) { ret = data; goto error_ret; } + data = (s32)(rxbuf[1]) | ((s32)(rxbuf[0] & 0x0F)) << 8; } else { - /* Check to see if current scan mode is correct */ - if (st->current_mode != &max1363_mode_table[chan->address]) { - /* Update scan mode if needed */ - st->current_mode = &max1363_mode_table[chan->address]; - ret = max1363_set_scan_mode(st); - if (ret < 0) - goto error_ret; - } - if (st->chip_info->bits != 8) { - /* Get reading */ - data = i2c_master_recv(client, rxbuf, 2); - if (data < 0) { - ret = data; - goto error_ret; - } - data = (s32)(rxbuf[1]) | ((s32)(rxbuf[0] & 0x0F)) << 8; - } else { - /* Get reading */ - data = i2c_master_recv(client, rxbuf, 1); - if (data < 0) { - ret = data; - goto error_ret; - } - data = rxbuf[0]; + /* Get reading */ + data = i2c_master_recv(client, rxbuf, 1); + if (data < 0) { + ret = data; + goto error_ret; } + data = rxbuf[0]; } *val = data; error_ret: @@ -260,7 +253,7 @@ static int max1363_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: if ((1 << (st->chip_info->bits + 1)) > st->chip_info->int_vref_mv) { *val = 0; @@ -288,7 +281,7 @@ static const enum max1363_modes max1363_mode_list[] = { #define MAX1363_EV_M \ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \ | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) -#define MAX1363_INFO_MASK (1 << IIO_CHAN_INFO_SCALE_SHARED) +#define MAX1363_INFO_MASK IIO_CHAN_INFO_SCALE_SHARED_BIT #define MAX1363_CHAN_U(num, addr, si, bits, evmask) \ { \ .type = IIO_VOLTAGE, \ @@ -296,7 +289,13 @@ static const enum max1363_modes max1363_mode_list[] = { .channel = num, \ .address = addr, \ .info_mask = MAX1363_INFO_MASK, \ - .scan_type = IIO_ST('u', bits, (bits > 8) ? 16 : 8, 0), \ + .datasheet_name = "AIN"#num, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = bits, \ + .storagebits = (bits > 8) ? 16 : 8, \ + .endianness = IIO_BE, \ + }, \ .scan_index = si, \ .event_mask = evmask, \ } @@ -311,7 +310,13 @@ static const enum max1363_modes max1363_mode_list[] = { .channel2 = num2, \ .address = addr, \ .info_mask = MAX1363_INFO_MASK, \ - .scan_type = IIO_ST('u', bits, (bits > 8) ? 16 : 8, 0), \ + .datasheet_name = "AIN"#num"-AIN"#num2, \ + .scan_type = { \ + .sign = 's', \ + .realbits = bits, \ + .storagebits = (bits > 8) ? 16 : 8, \ + .endianness = IIO_BE, \ + }, \ .scan_index = si, \ .event_mask = evmask, \ } @@ -833,6 +838,7 @@ static const struct iio_info max1363_info = { .read_event_config = &max1363_read_event_config, .write_event_config = &max1363_write_event_config, .read_raw = &max1363_read_raw, + .update_scan_mode = &max1363_update_scan_mode, .driver_module = THIS_MODULE, .event_attrs = &max1363_event_attribute_group, }; diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c index df6893e058c..f730b3fb971 100644 --- a/drivers/staging/iio/adc/max1363_ring.c +++ b/drivers/staging/iio/adc/max1363_ring.c @@ -15,88 +15,25 @@ #include <linux/bitops.h> #include "../iio.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "../trigger_consumer.h" #include "max1363.h" -int max1363_single_channel_from_ring(const long *mask, struct max1363_state *st) -{ - struct iio_buffer *ring = iio_priv_to_dev(st)->buffer; - int count = 0, ret, index; - u8 *ring_data; - index = find_first_bit(mask, MAX1363_MAX_CHANNELS); - - if (!(test_bit(index, st->current_mode->modemask))) { - ret = -EBUSY; - goto error_ret; - } - - ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), - GFP_KERNEL); - if (ring_data == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = ring->access->read_last(ring, ring_data); - if (ret) - goto error_free_ring_data; - /* Need a count of channels prior to this one */ - - count = bitmap_weight(mask, index - 1); - if (st->chip_info->bits != 8) - ret = ((int)(ring_data[count*2 + 0] & 0x0F) << 8) - + (int)(ring_data[count*2 + 1]); - else - ret = ring_data[count]; - -error_free_ring_data: - kfree(ring_data); -error_ret: - return ret; -} - - -/** - * max1363_ring_preenable() - setup the parameters of the ring before enabling - * - * The complex nature of the setting of the nuber of bytes per datum is due - * to this driver currently ensuring that the timestamp is stored at an 8 - * byte boundary. - **/ -static int max1363_ring_preenable(struct iio_dev *indio_dev) +int max1363_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) { struct max1363_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; - size_t d_size = 0; - unsigned long numvals; /* * Need to figure out the current mode based upon the requested * scan mask in iio_dev */ - st->current_mode = max1363_match_mode(ring->scan_mask, - st->chip_info); + st->current_mode = max1363_match_mode(scan_mask, st->chip_info); if (!st->current_mode) return -EINVAL; - max1363_set_scan_mode(st); - - numvals = bitmap_weight(st->current_mode->modemask, - indio_dev->masklength); - if (ring->access->set_bytes_per_datum) { - if (ring->scan_timestamp) - d_size += sizeof(s64); - if (st->chip_info->bits != 8) - d_size += numvals*2; - else - d_size += numvals; - if (ring->scan_timestamp && (d_size % 8)) - d_size += 8 - (d_size % 8); - ring->access->set_bytes_per_datum(ring, d_size); - } - return 0; } @@ -114,12 +51,14 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) /* Ensure the timestamp is 8 byte aligned */ if (st->chip_info->bits != 8) - d_size = numvals*2 + sizeof(s64); + d_size = numvals*2; else - d_size = numvals + sizeof(s64); - if (d_size % sizeof(s64)) - d_size += sizeof(s64) - (d_size % sizeof(s64)); - + d_size = numvals; + if (indio_dev->buffer->scan_timestamp) { + d_size += sizeof(s64); + if (d_size % sizeof(s64)) + d_size += sizeof(s64) - (d_size % sizeof(s64)); + } /* Monitor mode prevents reading. Whilst not currently implemented * might as well have this test in here in the meantime as it does * no harm. @@ -139,9 +78,10 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) time_ns = iio_get_time_ns(); - memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + if (indio_dev->buffer->scan_timestamp) + memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns); - indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns); done: iio_trigger_notify_done(indio_dev->trig); kfree(rxbuf); @@ -151,7 +91,7 @@ done: static const struct iio_buffer_setup_ops max1363_ring_setup_ops = { .postenable = &iio_triggered_buffer_postenable, - .preenable = &max1363_ring_preenable, + .preenable = &iio_sw_buffer_preenable, .predisable = &iio_triggered_buffer_predisable, }; @@ -179,7 +119,7 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ indio_dev->buffer->access = &ring_sw_access_funcs; /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &max1363_ring_setup_ops; + indio_dev->setup_ops = &max1363_ring_setup_ops; /* Flag that polled ring buffering is possible */ indio_dev->modes |= INDIO_BUFFER_TRIGGERED; diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c index 1e93c7b7aed..1ea3cd06299 100644 --- a/drivers/staging/iio/addac/adt7316-spi.c +++ b/drivers/staging/iio/addac/adt7316-spi.c @@ -151,7 +151,6 @@ static int adt7316_spi_resume(struct spi_device *spi_dev) static struct spi_driver adt7316_driver = { .driver = { .name = "adt7316", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = adt7316_spi_probe, diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 8df24704ff2..13c39292d3f 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include "../iio.h" +#include "../events.h" #include "../sysfs.h" #include "adt7316.h" diff --git a/drivers/staging/iio/buffer_generic.h b/drivers/staging/iio/buffer.h index 9e8f0100997..6fb6e64181a 100644 --- a/drivers/staging/iio/buffer_generic.h +++ b/drivers/staging/iio/buffer.h @@ -11,7 +11,6 @@ #define _IIO_BUFFER_GENERIC_H_ #include <linux/sysfs.h> #include "iio.h" -#include "chrdev.h" #ifdef CONFIG_IIO_BUFFER @@ -19,22 +18,14 @@ struct iio_buffer; /** * struct iio_buffer_access_funcs - access functions for buffers. - * @mark_in_use: reference counting, typically to prevent module removal - * @unmark_in_use: reduce reference count when no longer using buffer * @store_to: actually store stuff to the buffer - * @read_last: get the last element stored - * @read_first_n: try to get a specified number of elements (must exist) - * @mark_param_change: notify buffer that some relevant parameter has changed - * Often this means the underlying storage may need to - * change. + * @read_first_n: try to get a specified number of bytes (must exist) * @request_update: if a parameter change has been marked, update underlying * storage. * @get_bytes_per_datum:get current bytes per datum * @set_bytes_per_datum:set number of bytes per datum * @get_length: get number of datums in buffer * @set_length: set number of datums in buffer - * @is_enabled: query if buffer is currently being used - * @enable: enable the buffer * * The purpose of this structure is to make the buffer element * modular as event for a given driver, different usecases may require @@ -45,85 +36,60 @@ struct iio_buffer; * any of them not existing. **/ struct iio_buffer_access_funcs { - void (*mark_in_use)(struct iio_buffer *buffer); - void (*unmark_in_use)(struct iio_buffer *buffer); - int (*store_to)(struct iio_buffer *buffer, u8 *data, s64 timestamp); - int (*read_last)(struct iio_buffer *buffer, u8 *data); int (*read_first_n)(struct iio_buffer *buffer, size_t n, char __user *buf); - int (*mark_param_change)(struct iio_buffer *buffer); int (*request_update)(struct iio_buffer *buffer); int (*get_bytes_per_datum)(struct iio_buffer *buffer); int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd); int (*get_length)(struct iio_buffer *buffer); int (*set_length)(struct iio_buffer *buffer, int length); - - int (*is_enabled)(struct iio_buffer *buffer); - int (*enable)(struct iio_buffer *buffer); -}; - -/** - * struct iio_buffer_setup_ops - buffer setup related callbacks - * @preenable: [DRIVER] function to run prior to marking buffer enabled - * @postenable: [DRIVER] function to run after marking buffer enabled - * @predisable: [DRIVER] function to run prior to marking buffer - * disabled - * @postdisable: [DRIVER] function to run after marking buffer disabled - */ -struct iio_buffer_setup_ops { - int (*preenable)(struct iio_dev *); - int (*postenable)(struct iio_dev *); - int (*predisable)(struct iio_dev *); - int (*postdisable)(struct iio_dev *); }; /** * struct iio_buffer - general buffer structure - * @indio_dev: industrial I/O device structure - * @owner: module that owns the buffer (for ref counting) * @length: [DEVICE] number of datums in buffer * @bytes_per_datum: [DEVICE] size of individual datum including timestamp - * @bpe: [DEVICE] size of individual channel value * @scan_el_attrs: [DRIVER] control of scan elements if that scan mode * control method is used - * @scan_count: [INTERN] the number of elements in the current scan mode * @scan_mask: [INTERN] bitmask used in masking scan mode elements + * @scan_index_timestamp:[INTERN] cache of the index to the timestamp * @scan_timestamp: [INTERN] does the scan mode include a timestamp * @access: [DRIVER] buffer access functions associated with the * implementation. - * @flags: [INTERN] file ops related flags including busy flag. + * @scan_el_dev_attr_list:[INTERN] list of scan element related attributes. + * @scan_el_group: [DRIVER] attribute group for those attributes not + * created from the iio_chan_info array. + * @pollq: [INTERN] wait queue to allow for polling on the buffer. + * @stufftoread: [INTERN] flag to indicate new data. + * @demux_list: [INTERN] list of operations required to demux the scan. + * @demux_bounce: [INTERN] buffer for doing gather from incoming scan. **/ struct iio_buffer { - struct iio_dev *indio_dev; - struct module *owner; int length; int bytes_per_datum; - int bpe; struct attribute_group *scan_el_attrs; - int scan_count; long *scan_mask; bool scan_timestamp; + unsigned scan_index_timestamp; const struct iio_buffer_access_funcs *access; - const struct iio_buffer_setup_ops *setup_ops; struct list_head scan_el_dev_attr_list; struct attribute_group scan_el_group; wait_queue_head_t pollq; bool stufftoread; - unsigned long flags; const struct attribute_group *attrs; + struct list_head demux_list; + unsigned char *demux_bounce; }; /** * iio_buffer_init() - Initialize the buffer structure * @buffer: buffer to be initialized - * @indio_dev: the iio device the buffer is assocated with **/ -void iio_buffer_init(struct iio_buffer *buffer, - struct iio_dev *indio_dev); +void iio_buffer_init(struct iio_buffer *buffer); void iio_buffer_deinit(struct iio_buffer *buffer); @@ -140,17 +106,27 @@ static inline void __iio_update_buffer(struct iio_buffer *buffer, buffer->length = length; } -int iio_scan_mask_query(struct iio_buffer *buffer, int bit); +int iio_scan_mask_query(struct iio_dev *indio_dev, + struct iio_buffer *buffer, int bit); /** * iio_scan_mask_set() - set particular bit in the scan mask * @buffer: the buffer whose scan mask we are interested in * @bit: the bit to be set. **/ -int iio_scan_mask_set(struct iio_buffer *buffer, int bit); +int iio_scan_mask_set(struct iio_dev *indio_dev, + struct iio_buffer *buffer, int bit); -#define to_iio_buffer(d) \ - container_of(d, struct iio_buffer, dev) +/** + * iio_push_to_buffer() - push to a registered buffer. + * @buffer: IIO buffer structure for device + * @scan: Full scan. + * @timestamp: + */ +int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data, + s64 timestamp); + +int iio_update_demux(struct iio_dev *indio_dev); /** * iio_buffer_register() - register the buffer with IIO core @@ -180,12 +156,6 @@ ssize_t iio_buffer_write_length(struct device *dev, const char *buf, size_t len); /** - * iio_buffer_read_bytes_per_datum() - attr for number of bytes in whole datum - **/ -ssize_t iio_buffer_read_bytes_per_datum(struct device *dev, - struct device_attribute *attr, - char *buf); -/** * iio_buffer_store_enable() - attr to turn the buffer on **/ ssize_t iio_buffer_store_enable(struct device *dev, @@ -201,9 +171,6 @@ ssize_t iio_buffer_show_enable(struct device *dev, #define IIO_BUFFER_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR, \ iio_buffer_read_length, \ iio_buffer_write_length) -#define IIO_BUFFER_BYTES_PER_DATUM_ATTR \ - DEVICE_ATTR(bytes_per_datum, S_IRUGO | S_IWUSR, \ - iio_buffer_read_bytes_per_datum, NULL) #define IIO_BUFFER_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, \ iio_buffer_show_enable, \ diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index 47181875e11..b73007dcf4b 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -15,7 +15,7 @@ #include "../iio.h" #include "../sysfs.h" - +#include "../events.h" /* * AD7150 registers definition */ @@ -111,7 +111,7 @@ static int ad7150_read_raw(struct iio_dev *indio_dev, return ret; *val = swab16(ret); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE): + case IIO_CHAN_INFO_AVERAGE_RAW: ret = i2c_smbus_read_word_data(chip->client, ad7150_addresses[chan->channel][1]); if (ret < 0) @@ -429,7 +429,7 @@ static const struct iio_chan_spec ad7150_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE), + .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT, .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) | @@ -441,7 +441,7 @@ static const struct iio_chan_spec ad7150_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE), + .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT, .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) | diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index 152d3be6d97..fdb83c35e6d 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -259,7 +259,7 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: if (val != 1) { ret = -EINVAL; goto out; @@ -276,7 +276,7 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, ret = 0; break; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: if ((val < 0) | (val > 0xFFFF)) { ret = -EINVAL; goto out; @@ -289,7 +289,7 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, ret = 0; break; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: if (val != 0) { ret = -EINVAL; goto out; @@ -372,7 +372,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: ret = i2c_smbus_read_word_data(chip->client, ad7152_addresses[chan->channel][AD7152_GAIN]); @@ -384,7 +384,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT_PLUS_MICRO; break; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: ret = i2c_smbus_read_word_data(chip->client, ad7152_addresses[chan->channel][AD7152_OFFS]); if (ret < 0) @@ -393,7 +393,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: ret = i2c_smbus_read_byte_data(chip->client, ad7152_addresses[chan->channel][AD7152_SETUP]); if (ret < 0) @@ -416,7 +416,7 @@ static int ad7152_write_raw_get_fmt(struct iio_dev *indio_dev, long mask) { switch (mask) { - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: return IIO_VAL_INT_PLUS_NANO; default: return IIO_VAL_INT_PLUS_MICRO; @@ -436,34 +436,34 @@ static const struct iio_chan_spec ad7152_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, }, { .type = IIO_CAPACITANCE, .differential = 1, .indexed = 1, .channel = 0, .channel2 = 2, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, }, { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, }, { .type = IIO_CAPACITANCE, .differential = 1, .indexed = 1, .channel = 1, .channel2 = 3, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, } }; /* diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index 9df590891a6..40b8512cbc3 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -123,7 +123,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_EXT_VIN, }, @@ -132,7 +132,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 1, .extend_name = "supply", - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_VDD_MON, }, @@ -156,10 +156,10 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SHARED) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_CAP_DATA_HIGH << 8, }, [CIN1_DIFF] = { @@ -168,10 +168,10 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 0, .channel2 = 2, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SHARED) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CAPDIFF }, @@ -179,10 +179,10 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SHARED) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CIN2, }, @@ -192,10 +192,10 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 1, .channel2 = 3, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | - (1 << IIO_CHAN_INFO_CALIBBIAS_SHARED) | - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CAPDIFF | AD7746_CAPSETUP_CIN2, } @@ -477,7 +477,7 @@ static int ad7746_write_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: if (val != 1) { ret = -EINVAL; goto out; @@ -503,7 +503,7 @@ static int ad7746_write_raw(struct iio_dev *indio_dev, ret = 0; break; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SHARED): + case IIO_CHAN_INFO_CALIBBIAS: if ((val < 0) | (val > 0xFFFF)) { ret = -EINVAL; goto out; @@ -515,7 +515,7 @@ static int ad7746_write_raw(struct iio_dev *indio_dev, ret = 0; break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: if ((val < 0) | (val > 43008000)) { /* 21pF */ ret = -EINVAL; goto out; @@ -612,7 +612,7 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: switch (chan->type) { case IIO_CAPACITANCE: reg = AD7746_REG_CAP_GAINH; @@ -634,7 +634,7 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT_PLUS_MICRO; break; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SHARED): + case IIO_CHAN_INFO_CALIBBIAS: ret = i2c_smbus_read_word_data(chip->client, AD7746_REG_CAP_OFFH); if (ret < 0) @@ -643,13 +643,13 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = AD7746_CAPDAC_DACP(chip->capdac[chan->channel] [chan->differential]) * 338646; ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_CAPACITANCE: /* 8.192pf / 2^24 */ diff --git a/drivers/staging/iio/chrdev.h b/drivers/staging/iio/chrdev.h deleted file mode 100644 index d8e736f6052..00000000000 --- a/drivers/staging/iio/chrdev.h +++ /dev/null @@ -1,25 +0,0 @@ -/* The industrial I/O core - character device related - * - * Copyright (c) 2008 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _IIO_CHRDEV_H_ -#define _IIO_CHRDEV_H_ - -/** - * struct iio_event_data - The actual event being pushed to userspace - * @id: event identifier - * @timestamp: best estimate of time of event occurrence (often from - * the interrupt handler) - */ -struct iio_event_data { - u64 id; - s64 timestamp; -}; - -#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int) -#endif diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig index fac8549dc8e..13e27979df2 100644 --- a/drivers/staging/iio/dac/Kconfig +++ b/drivers/staging/iio/dac/Kconfig @@ -24,6 +24,29 @@ config AD5360 To compile this driver as module choose M here: the module will be called ad5360. +config AD5380 + tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver" + depends on (SPI_MASTER || I2C) + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER + help + Say yes here to build support for Analog Devices AD5380, AD5381, + AD5382, AD5383, AD5384, AD5390, AD5391, AD5392 multi-channel + Digital to Analog Converters (DAC). + + To compile this driver as module choose M here: the module will be called + ad5380. + +config AD5421 + tristate "Analog Devices AD5421 DAC driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD5421 loop-powered + digital-to-analog convertors (DAC). + + To compile this driver as module choose M here: the module will be called + ad5421. + config AD5624R_SPI tristate "Analog Devices AD5624/44/64R DAC spi driver" depends on SPI @@ -37,7 +60,7 @@ config AD5446 help Say yes here to build support for Analog Devices AD5444, AD5446, AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621, - AD5640, AD5660 DACs. + AD5640, AD5660, AD5662 DACs. To compile this driver as a module, choose M here: the module will be called ad5446. @@ -52,12 +75,22 @@ config AD5504 To compile this driver as a module, choose M here: the module will be called ad5504. +config AD5764 + tristate "Analog Devices AD5764/64R/44/44R DAC driver" + depends on SPI_MASTER + help + Say yes here to build support for Analog Devices AD5764, AD5764R, AD5744, + AD5744R Digital to Analog Converter. + + To compile this driver as a module, choose M here: the + module will be called ad5764. + config AD5791 - tristate "Analog Devices AD5760/AD5780/AD5781/AD5791 DAC SPI driver" + tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver" depends on SPI help Say yes here to build support for Analog Devices AD5760, AD5780, - AD5781, AD5791 High Resolution Voltage Output Digital to + AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to Analog Converter. To compile this driver as a module, choose M here: the diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile index 07b6f5ebdb5..8ab1d264aab 100644 --- a/drivers/staging/iio/dac/Makefile +++ b/drivers/staging/iio/dac/Makefile @@ -3,10 +3,13 @@ # obj-$(CONFIG_AD5360) += ad5360.o +obj-$(CONFIG_AD5380) += ad5380.o +obj-$(CONFIG_AD5421) += ad5421.o obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o obj-$(CONFIG_AD5064) += ad5064.o obj-$(CONFIG_AD5504) += ad5504.o obj-$(CONFIG_AD5446) += ad5446.o +obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_MAX517) += max517.o diff --git a/drivers/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c index 39cfe6cb02a..049a855039c 100644 --- a/drivers/staging/iio/dac/ad5064.c +++ b/drivers/staging/iio/dac/ad5064.c @@ -91,7 +91,7 @@ enum ad5064_type { .indexed = 1, \ .output = 1, \ .channel = (chan), \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = AD5064_ADDR_DAC(chan), \ .scan_type = IIO_ST('u', (bits), 16, 20 - (bits)) \ } @@ -280,14 +280,14 @@ static int ad5064_read_raw(struct iio_dev *indio_dev, long m) { struct ad5064_state *st = iio_priv(indio_dev); - unsigned long scale_uv; unsigned int vref; + int scale_uv; switch (m) { case 0: *val = st->dac_cache[chan->channel]; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: vref = st->chip_info->shared_vref ? 0 : chan->channel; scale_uv = regulator_get_voltage(st->vref_reg[vref].consumer); if (scale_uv < 0) diff --git a/drivers/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c index bc0459e32d0..710b256affc 100644 --- a/drivers/staging/iio/dac/ad5360.c +++ b/drivers/staging/iio/dac/ad5360.c @@ -103,10 +103,10 @@ enum ad5360_type { .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | \ - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | \ - (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \ - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), \ + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ .scan_type = IIO_ST('u', (bits), 16, 16 - (bits)) \ } @@ -326,21 +326,21 @@ static int ad5360_write_raw(struct iio_dev *indio_dev, return ad5360_write(indio_dev, AD5360_CMD_WRITE_DATA, chan->address, val, chan->scan_type.shift); - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: if (val >= max_val || val < 0) return -EINVAL; return ad5360_write(indio_dev, AD5360_CMD_WRITE_OFFSET, chan->address, val, chan->scan_type.shift); - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: if (val >= max_val || val < 0) return -EINVAL; return ad5360_write(indio_dev, AD5360_CMD_WRITE_GAIN, chan->address, val, chan->scan_type.shift); - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: if (val <= -max_val || val > 0) return -EINVAL; @@ -371,8 +371,8 @@ static int ad5360_read_raw(struct iio_dev *indio_dev, long m) { struct ad5360_state *st = iio_priv(indio_dev); - unsigned long scale_uv; unsigned int ofs_index; + int scale_uv; int ret; switch (m) { @@ -383,7 +383,7 @@ static int ad5360_read_raw(struct iio_dev *indio_dev, return ret; *val = ret >> chan->scan_type.shift; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: /* vout = 4 * vref * dac_code */ scale_uv = ad5360_get_channel_vref(st, chan->channel) * 4 * 100; if (scale_uv < 0) @@ -393,21 +393,21 @@ static int ad5360_read_raw(struct iio_dev *indio_dev, *val = scale_uv / 100000; *val2 = (scale_uv % 100000) * 10; return IIO_VAL_INT_PLUS_MICRO; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET, chan->address); if (ret < 0) return ret; *val = ret; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN, chan->address); if (ret < 0) return ret; *val = ret; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: ofs_index = ad5360_get_channel_vref_index(st, chan->channel); ret = ad5360_read(indio_dev, AD5360_READBACK_SF, AD5360_REG_SF_OFS(ofs_index)); diff --git a/drivers/staging/iio/dac/ad5380.c b/drivers/staging/iio/dac/ad5380.c new file mode 100644 index 00000000000..eff97ae05c4 --- /dev/null +++ b/drivers/staging/iio/dac/ad5380.c @@ -0,0 +1,676 @@ +/* + * Analog devices AD5380, AD5381, AD5382, AD5383, AD5390, AD5391, AD5392 + * multi-channel Digital to Analog Converters driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "dac.h" + + +#define AD5380_REG_DATA(x) (((x) << 2) | 3) +#define AD5380_REG_OFFSET(x) (((x) << 2) | 2) +#define AD5380_REG_GAIN(x) (((x) << 2) | 1) +#define AD5380_REG_SF_PWR_DOWN (8 << 2) +#define AD5380_REG_SF_PWR_UP (9 << 2) +#define AD5380_REG_SF_CTRL (12 << 2) + +#define AD5380_CTRL_PWR_DOWN_MODE_OFFSET 13 +#define AD5380_CTRL_INT_VREF_2V5 BIT(12) +#define AD5380_CTRL_INT_VREF_EN BIT(10) + +/** + * struct ad5380_chip_info - chip specific information + * @channel_template: channel specification template + * @num_channels: number of channels + * @int_vref: internal vref in uV +*/ + +struct ad5380_chip_info { + struct iio_chan_spec channel_template; + unsigned int num_channels; + unsigned int int_vref; +}; + +/** + * struct ad5380_state - driver instance specific data + * @regmap: regmap instance used by the device + * @chip_info: chip model specific constants, available modes etc + * @vref_reg: vref supply regulator + * @vref: actual reference voltage used in uA + * @pwr_down: whether the chip is currently in power down mode + */ + +struct ad5380_state { + struct regmap *regmap; + const struct ad5380_chip_info *chip_info; + struct regulator *vref_reg; + int vref; + bool pwr_down; +}; + +enum ad5380_type { + ID_AD5380_3, + ID_AD5380_5, + ID_AD5381_3, + ID_AD5381_5, + ID_AD5382_3, + ID_AD5382_5, + ID_AD5383_3, + ID_AD5383_5, + ID_AD5390_3, + ID_AD5390_5, + ID_AD5391_3, + ID_AD5391_5, + ID_AD5392_3, + ID_AD5392_5, +}; + +#define AD5380_CHANNEL(_bits) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ + .scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)) \ +} + +static const struct ad5380_chip_info ad5380_chip_info_tbl[] = { + [ID_AD5380_3] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 40, + .int_vref = 1250000, + }, + [ID_AD5380_5] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 40, + .int_vref = 2500000, + }, + [ID_AD5381_3] = { + .channel_template = AD5380_CHANNEL(12), + .num_channels = 16, + .int_vref = 1250000, + }, + [ID_AD5381_5] = { + .channel_template = AD5380_CHANNEL(12), + .num_channels = 16, + .int_vref = 2500000, + }, + [ID_AD5382_3] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 32, + .int_vref = 1250000, + }, + [ID_AD5382_5] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 32, + .int_vref = 2500000, + }, + [ID_AD5383_3] = { + .channel_template = AD5380_CHANNEL(12), + .num_channels = 32, + .int_vref = 1250000, + }, + [ID_AD5383_5] = { + .channel_template = AD5380_CHANNEL(12), + .num_channels = 32, + .int_vref = 2500000, + }, + [ID_AD5390_3] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 16, + .int_vref = 1250000, + }, + [ID_AD5390_5] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 16, + .int_vref = 2500000, + }, + [ID_AD5391_3] = { + .channel_template = AD5380_CHANNEL(12), + .num_channels = 16, + .int_vref = 1250000, + }, + [ID_AD5391_5] = { + .channel_template = AD5380_CHANNEL(12), + .num_channels = 16, + .int_vref = 2500000, + }, + [ID_AD5392_3] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 8, + .int_vref = 1250000, + }, + [ID_AD5392_5] = { + .channel_template = AD5380_CHANNEL(14), + .num_channels = 8, + .int_vref = 2500000, + }, +}; + +static ssize_t ad5380_read_dac_powerdown(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5380_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", st->pwr_down); +} + +static ssize_t ad5380_write_dac_powerdown(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5380_state *st = iio_priv(indio_dev); + bool pwr_down; + int ret; + + ret = strtobool(buf, &pwr_down); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + + if (pwr_down) + ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0); + else + ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_UP, 0); + + st->pwr_down = pwr_down; + + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(out_voltage_powerdown, + S_IRUGO | S_IWUSR, + ad5380_read_dac_powerdown, + ad5380_write_dac_powerdown, 0); + +static const char ad5380_powerdown_modes[][15] = { + [0] = "100kohm_to_gnd", + [1] = "three_state", +}; + +static ssize_t ad5380_read_powerdown_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5380_state *st = iio_priv(indio_dev); + unsigned int mode; + int ret; + + ret = regmap_read(st->regmap, AD5380_REG_SF_CTRL, &mode); + if (ret) + return ret; + + mode = (mode >> AD5380_CTRL_PWR_DOWN_MODE_OFFSET) & 1; + + return sprintf(buf, "%s\n", ad5380_powerdown_modes[mode]); +} + +static ssize_t ad5380_write_powerdown_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5380_state *st = iio_priv(indio_dev); + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(ad5380_powerdown_modes); ++i) { + if (sysfs_streq(buf, ad5380_powerdown_modes[i])) + break; + } + + if (i == ARRAY_SIZE(ad5380_powerdown_modes)) + return -EINVAL; + + ret = regmap_update_bits(st->regmap, AD5380_REG_SF_CTRL, + 1 << AD5380_CTRL_PWR_DOWN_MODE_OFFSET, + i << AD5380_CTRL_PWR_DOWN_MODE_OFFSET); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, + S_IRUGO | S_IWUSR, + ad5380_read_powerdown_mode, + ad5380_write_powerdown_mode, 0); + +static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, + "100kohm_to_gnd three_state"); + +static struct attribute *ad5380_attributes[] = { + &iio_dev_attr_out_voltage_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad5380_attribute_group = { + .attrs = ad5380_attributes, +}; + +static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan, + long info) +{ + switch (info) { + case 0: + return AD5380_REG_DATA(chan->address); + case IIO_CHAN_INFO_CALIBBIAS: + return AD5380_REG_OFFSET(chan->address); + case IIO_CHAN_INFO_CALIBSCALE: + return AD5380_REG_GAIN(chan->address); + default: + break; + } + + return 0; +} + +static int ad5380_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long info) +{ + const unsigned int max_val = (1 << chan->scan_type.realbits); + struct ad5380_state *st = iio_priv(indio_dev); + + switch (info) { + case 0: + case IIO_CHAN_INFO_CALIBSCALE: + if (val >= max_val || val < 0) + return -EINVAL; + + return regmap_write(st->regmap, + ad5380_info_to_reg(chan, info), + val << chan->scan_type.shift); + case IIO_CHAN_INFO_CALIBBIAS: + val += (1 << chan->scan_type.realbits) / 2; + if (val >= max_val || val < 0) + return -EINVAL; + + return regmap_write(st->regmap, + AD5380_REG_OFFSET(chan->address), + val << chan->scan_type.shift); + default: + break; + } + return -EINVAL; +} + +static int ad5380_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long info) +{ + struct ad5380_state *st = iio_priv(indio_dev); + unsigned long scale_uv; + int ret; + + switch (info) { + case 0: + case IIO_CHAN_INFO_CALIBSCALE: + ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info), + val); + if (ret) + return ret; + *val >>= chan->scan_type.shift; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + ret = regmap_read(st->regmap, AD5380_REG_OFFSET(chan->address), + val); + if (ret) + return ret; + *val >>= chan->scan_type.shift; + val -= (1 << chan->scan_type.realbits) / 2; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + scale_uv = ((2 * st->vref) >> chan->scan_type.realbits) * 100; + *val = scale_uv / 100000; + *val2 = (scale_uv % 100000) * 10; + return IIO_VAL_INT_PLUS_MICRO; + default: + break; + } + + return -EINVAL; +} + +static const struct iio_info ad5380_info = { + .read_raw = ad5380_read_raw, + .write_raw = ad5380_write_raw, + .attrs = &ad5380_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev) +{ + struct ad5380_state *st = iio_priv(indio_dev); + struct iio_chan_spec *channels; + unsigned int i; + + channels = kcalloc(sizeof(struct iio_chan_spec), + st->chip_info->num_channels, GFP_KERNEL); + + if (!channels) + return -ENOMEM; + + for (i = 0; i < st->chip_info->num_channels; ++i) { + channels[i] = st->chip_info->channel_template; + channels[i].channel = i; + channels[i].address = i; + } + + indio_dev->channels = channels; + + return 0; +} + +static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap, + enum ad5380_type type, const char *name) +{ + struct iio_dev *indio_dev; + struct ad5380_state *st; + unsigned int ctrl = 0; + int ret; + + indio_dev = iio_allocate_device(sizeof(*st)); + if (indio_dev == NULL) { + dev_err(dev, "Failed to allocate iio device\n"); + ret = -ENOMEM; + goto error_regmap_exit; + } + + st = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + + st->chip_info = &ad5380_chip_info_tbl[type]; + st->regmap = regmap; + + indio_dev->dev.parent = dev; + indio_dev->name = name; + indio_dev->info = &ad5380_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->num_channels = st->chip_info->num_channels; + + ret = ad5380_alloc_channels(indio_dev); + if (ret) { + dev_err(dev, "Failed to allocate channel spec: %d\n", ret); + goto error_free; + } + + if (st->chip_info->int_vref == 2500000) + ctrl |= AD5380_CTRL_INT_VREF_2V5; + + st->vref_reg = regulator_get(dev, "vref"); + if (!IS_ERR(st->vref_reg)) { + ret = regulator_enable(st->vref_reg); + if (ret) { + dev_err(dev, "Failed to enable vref regulators: %d\n", + ret); + goto error_free_reg; + } + + st->vref = regulator_get_voltage(st->vref_reg); + } else { + st->vref = st->chip_info->int_vref; + ctrl |= AD5380_CTRL_INT_VREF_EN; + } + + ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl); + if (ret) { + dev_err(dev, "Failed to write to device: %d\n", ret); + goto error_disable_reg; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(dev, "Failed to register iio device: %d\n", ret); + goto error_disable_reg; + } + + return 0; + +error_disable_reg: + if (!IS_ERR(st->vref_reg)) + regulator_disable(st->vref_reg); +error_free_reg: + if (!IS_ERR(st->vref_reg)) + regulator_put(st->vref_reg); + + kfree(indio_dev->channels); +error_free: + iio_free_device(indio_dev); +error_regmap_exit: + regmap_exit(regmap); + + return ret; +} + +static int __devexit ad5380_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5380_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + kfree(indio_dev->channels); + + if (!IS_ERR(st->vref_reg)) { + regulator_disable(st->vref_reg); + regulator_put(st->vref_reg); + } + + regmap_exit(st->regmap); + iio_free_device(indio_dev); + + return 0; +} + +static bool ad5380_reg_false(struct device *dev, unsigned int reg) +{ + return false; +} + +static const struct regmap_config ad5380_regmap_config = { + .reg_bits = 10, + .val_bits = 14, + + .max_register = AD5380_REG_DATA(40), + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = ad5380_reg_false, + .readable_reg = ad5380_reg_false, +}; + +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static int __devinit ad5380_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct regmap *regmap; + + regmap = regmap_init_spi(spi, &ad5380_regmap_config); + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name); +} + +static int __devexit ad5380_spi_remove(struct spi_device *spi) +{ + return ad5380_remove(&spi->dev); +} + +static const struct spi_device_id ad5380_spi_ids[] = { + { "ad5380-3", ID_AD5380_3 }, + { "ad5380-5", ID_AD5380_5 }, + { "ad5381-3", ID_AD5381_3 }, + { "ad5381-5", ID_AD5381_5 }, + { "ad5382-3", ID_AD5382_3 }, + { "ad5382-5", ID_AD5382_5 }, + { "ad5383-3", ID_AD5383_3 }, + { "ad5383-5", ID_AD5383_5 }, + { "ad5384-3", ID_AD5380_3 }, + { "ad5384-5", ID_AD5380_5 }, + { "ad5390-3", ID_AD5390_3 }, + { "ad5390-5", ID_AD5390_5 }, + { "ad5391-3", ID_AD5391_3 }, + { "ad5391-5", ID_AD5391_5 }, + { "ad5392-3", ID_AD5392_3 }, + { "ad5392-5", ID_AD5392_5 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad5380_spi_ids); + +static struct spi_driver ad5380_spi_driver = { + .driver = { + .name = "ad5380", + .owner = THIS_MODULE, + }, + .probe = ad5380_spi_probe, + .remove = __devexit_p(ad5380_spi_remove), + .id_table = ad5380_spi_ids, +}; + +static inline int ad5380_spi_register_driver(void) +{ + return spi_register_driver(&ad5380_spi_driver); +} + +static inline void ad5380_spi_unregister_driver(void) +{ + spi_unregister_driver(&ad5380_spi_driver); +} + +#else + +static inline int ad5380_spi_register_driver(void) +{ + return 0; +} + +static inline void ad5380_spi_unregister_driver(void) +{ +} + +#endif + +#if IS_ENABLED(CONFIG_I2C) + +static int __devinit ad5380_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = regmap_init_i2c(i2c, &ad5380_regmap_config); + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name); +} + +static int __devexit ad5380_i2c_remove(struct i2c_client *i2c) +{ + return ad5380_remove(&i2c->dev); +} + +static const struct i2c_device_id ad5380_i2c_ids[] = { + { "ad5380-3", ID_AD5380_3 }, + { "ad5380-5", ID_AD5380_5 }, + { "ad5381-3", ID_AD5381_3 }, + { "ad5381-5", ID_AD5381_5 }, + { "ad5382-3", ID_AD5382_3 }, + { "ad5382-5", ID_AD5382_5 }, + { "ad5383-3", ID_AD5383_3 }, + { "ad5383-5", ID_AD5383_5 }, + { "ad5384-3", ID_AD5380_3 }, + { "ad5384-5", ID_AD5380_5 }, + { "ad5390-3", ID_AD5390_3 }, + { "ad5390-5", ID_AD5390_5 }, + { "ad5391-3", ID_AD5391_3 }, + { "ad5391-5", ID_AD5391_5 }, + { "ad5392-3", ID_AD5392_3 }, + { "ad5392-5", ID_AD5392_5 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids); + +static struct i2c_driver ad5380_i2c_driver = { + .driver = { + .name = "ad5380", + .owner = THIS_MODULE, + }, + .probe = ad5380_i2c_probe, + .remove = __devexit_p(ad5380_i2c_remove), + .id_table = ad5380_i2c_ids, +}; + +static inline int ad5380_i2c_register_driver(void) +{ + return i2c_add_driver(&ad5380_i2c_driver); +} + +static inline void ad5380_i2c_unregister_driver(void) +{ + i2c_del_driver(&ad5380_i2c_driver); +} + +#else + +static inline int ad5380_i2c_register_driver(void) +{ + return 0; +} + +static inline void ad5380_i2c_unregister_driver(void) +{ +} + +#endif + +static int __init ad5380_spi_init(void) +{ + int ret; + + ret = ad5380_spi_register_driver(); + if (ret) + return ret; + + ret = ad5380_i2c_register_driver(); + if (ret) { + ad5380_spi_unregister_driver(); + return ret; + } + + return 0; +} +module_init(ad5380_spi_init); + +static void __exit ad5380_spi_exit(void) +{ + ad5380_i2c_unregister_driver(); + ad5380_spi_unregister_driver(); + +} +module_exit(ad5380_spi_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c new file mode 100644 index 00000000000..71ee8682476 --- /dev/null +++ b/drivers/staging/iio/dac/ad5421.c @@ -0,0 +1,555 @@ +/* + * AD5421 Digital to analog converters driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/sysfs.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "../events.h" +#include "dac.h" +#include "ad5421.h" + + +#define AD5421_REG_DAC_DATA 0x1 +#define AD5421_REG_CTRL 0x2 +#define AD5421_REG_OFFSET 0x3 +#define AD5421_REG_GAIN 0x4 +/* load dac and fault shared the same register number. Writing to it will cause + * a dac load command, reading from it will return the fault status register */ +#define AD5421_REG_LOAD_DAC 0x5 +#define AD5421_REG_FAULT 0x5 +#define AD5421_REG_FORCE_ALARM_CURRENT 0x6 +#define AD5421_REG_RESET 0x7 +#define AD5421_REG_START_CONVERSION 0x8 +#define AD5421_REG_NOOP 0x9 + +#define AD5421_CTRL_WATCHDOG_DISABLE BIT(12) +#define AD5421_CTRL_AUTO_FAULT_READBACK BIT(11) +#define AD5421_CTRL_MIN_CURRENT BIT(9) +#define AD5421_CTRL_ADC_SOURCE_TEMP BIT(8) +#define AD5421_CTRL_ADC_ENABLE BIT(7) +#define AD5421_CTRL_PWR_DOWN_INT_VREF BIT(6) + +#define AD5421_FAULT_SPI BIT(15) +#define AD5421_FAULT_PEC BIT(14) +#define AD5421_FAULT_OVER_CURRENT BIT(13) +#define AD5421_FAULT_UNDER_CURRENT BIT(12) +#define AD5421_FAULT_TEMP_OVER_140 BIT(11) +#define AD5421_FAULT_TEMP_OVER_100 BIT(10) +#define AD5421_FAULT_UNDER_VOLTAGE_6V BIT(9) +#define AD5421_FAULT_UNDER_VOLTAGE_12V BIT(8) + +/* These bits will cause the fault pin to go high */ +#define AD5421_FAULT_TRIGGER_IRQ \ + (AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \ + AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140) + +/** + * struct ad5421_state - driver instance specific data + * @spi: spi_device + * @ctrl: control register cache + * @current_range: current range which the device is configured for + * @data: spi transfer buffers + * @fault_mask: software masking of events + */ +struct ad5421_state { + struct spi_device *spi; + unsigned int ctrl; + enum ad5421_current_range current_range; + unsigned int fault_mask; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + union { + u32 d32; + u8 d8[4]; + } data[2] ____cacheline_aligned; +}; + +static const struct iio_chan_spec ad5421_channels[] = { + { + .type = IIO_CURRENT, + .indexed = 1, + .output = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .scan_type = IIO_ST('u', 16, 16, 0), + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), + }, + { + .type = IIO_TEMP, + .channel = -1, + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), + }, +}; + +static int ad5421_write_unlocked(struct iio_dev *indio_dev, + unsigned int reg, unsigned int val) +{ + struct ad5421_state *st = iio_priv(indio_dev); + + st->data[0].d32 = cpu_to_be32((reg << 16) | val); + + return spi_write(st->spi, &st->data[0].d8[1], 3); +} + +static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg, + unsigned int val) +{ + int ret; + + mutex_lock(&indio_dev->mlock); + ret = ad5421_write_unlocked(indio_dev, reg, val); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg) +{ + struct ad5421_state *st = iio_priv(indio_dev); + struct spi_message m; + int ret; + struct spi_transfer t[] = { + { + .tx_buf = &st->data[0].d8[1], + .len = 3, + .cs_change = 1, + }, { + .rx_buf = &st->data[1].d8[1], + .len = 3, + }, + }; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + + mutex_lock(&indio_dev->mlock); + + st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); + + ret = spi_sync(st->spi, &m); + if (ret >= 0) + ret = be32_to_cpu(st->data[1].d32) & 0xffff; + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set, + unsigned int clr) +{ + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int ret; + + mutex_lock(&indio_dev->mlock); + + st->ctrl &= ~clr; + st->ctrl |= set; + + ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl); + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static irqreturn_t ad5421_fault_handler(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int fault; + unsigned int old_fault = 0; + unsigned int events; + + fault = ad5421_read(indio_dev, AD5421_REG_FAULT); + if (!fault) + return IRQ_NONE; + + /* If we had a fault, this might mean that the DAC has lost its state + * and has been reset. Make sure that the control register actually + * contains what we expect it to contain. Otherwise the watchdog might + * be enabled and we get watchdog timeout faults, which will render the + * DAC unusable. */ + ad5421_update_ctrl(indio_dev, 0, 0); + + + /* The fault pin stays high as long as a fault condition is present and + * it is not possible to mask fault conditions. For certain fault + * conditions for example like over-temperature it takes some time + * until the fault condition disappears. If we would exit the interrupt + * handler immediately after handling the event it would be entered + * again instantly. Thus we fall back to polling in case we detect that + * a interrupt condition is still present. + */ + do { + /* 0xffff is a invalid value for the register and will only be + * read if there has been a communication error */ + if (fault == 0xffff) + fault = 0; + + /* we are only interested in new events */ + events = (old_fault ^ fault) & fault; + events &= st->fault_mask; + + if (events & AD5421_FAULT_OVER_CURRENT) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } + + if (events & AD5421_FAULT_UNDER_CURRENT) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } + + if (events & AD5421_FAULT_TEMP_OVER_140) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_TEMP, + 0, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } + + old_fault = fault; + fault = ad5421_read(indio_dev, AD5421_REG_FAULT); + + /* still active? go to sleep for some time */ + if (fault & AD5421_FAULT_TRIGGER_IRQ) + msleep(1000); + + } while (fault & AD5421_FAULT_TRIGGER_IRQ); + + + return IRQ_HANDLED; +} + +static void ad5421_get_current_min_max(struct ad5421_state *st, + unsigned int *min, unsigned int *max) +{ + /* The current range is configured using external pins, which are + * usually hard-wired and not run-time switchable. */ + switch (st->current_range) { + case AD5421_CURRENT_RANGE_4mA_20mA: + *min = 4000; + *max = 20000; + break; + case AD5421_CURRENT_RANGE_3mA8_21mA: + *min = 3800; + *max = 21000; + break; + case AD5421_CURRENT_RANGE_3mA2_24mA: + *min = 3200; + *max = 24000; + break; + default: + *min = 0; + *max = 1; + break; + } +} + +static inline unsigned int ad5421_get_offset(struct ad5421_state *st) +{ + unsigned int min, max; + + ad5421_get_current_min_max(st, &min, &max); + return (min * (1 << 16)) / (max - min); +} + +static inline unsigned int ad5421_get_scale(struct ad5421_state *st) +{ + unsigned int min, max; + + ad5421_get_current_min_max(st, &min, &max); + return ((max - min) * 1000) / (1 << 16); +} + +static int ad5421_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long m) +{ + struct ad5421_state *st = iio_priv(indio_dev); + int ret; + + if (chan->type != IIO_CURRENT) + return -EINVAL; + + switch (m) { + case 0: + ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = ad5421_get_scale(st); + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = ad5421_get_offset(st); + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + ret = ad5421_read(indio_dev, AD5421_REG_OFFSET); + if (ret < 0) + return ret; + *val = ret - 32768; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + ret = ad5421_read(indio_dev, AD5421_REG_GAIN); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int ad5421_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + const unsigned int max_val = 1 << 16; + + switch (mask) { + case 0: + if (val >= max_val || val < 0) + return -EINVAL; + + return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val); + case IIO_CHAN_INFO_CALIBBIAS: + val += 32768; + if (val >= max_val || val < 0) + return -EINVAL; + + return ad5421_write(indio_dev, AD5421_REG_OFFSET, val); + case IIO_CHAN_INFO_CALIBSCALE: + if (val >= max_val || val < 0) + return -EINVAL; + + return ad5421_write(indio_dev, AD5421_REG_GAIN, val); + default: + break; + } + + return -EINVAL; +} + +static int ad5421_write_event_config(struct iio_dev *indio_dev, + u64 event_code, int state) +{ + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int mask; + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_CURRENT: + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == + IIO_EV_DIR_RISING) + mask = AD5421_FAULT_OVER_CURRENT; + else + mask = AD5421_FAULT_UNDER_CURRENT; + break; + case IIO_TEMP: + mask = AD5421_FAULT_TEMP_OVER_140; + break; + default: + return -EINVAL; + } + + mutex_lock(&indio_dev->mlock); + if (state) + st->fault_mask |= mask; + else + st->fault_mask &= ~mask; + mutex_unlock(&indio_dev->mlock); + + return 0; +} + +static int ad5421_read_event_config(struct iio_dev *indio_dev, + u64 event_code) +{ + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int mask; + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_CURRENT: + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == + IIO_EV_DIR_RISING) + mask = AD5421_FAULT_OVER_CURRENT; + else + mask = AD5421_FAULT_UNDER_CURRENT; + break; + case IIO_TEMP: + mask = AD5421_FAULT_TEMP_OVER_140; + break; + default: + return -EINVAL; + } + + return (bool)(st->fault_mask & mask); +} + +static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code, + int *val) +{ + int ret; + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_CURRENT: + ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); + if (ret < 0) + return ret; + *val = ret; + break; + case IIO_TEMP: + *val = 140000; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct iio_info ad5421_info = { + .read_raw = ad5421_read_raw, + .write_raw = ad5421_write_raw, + .read_event_config = ad5421_read_event_config, + .write_event_config = ad5421_write_event_config, + .read_event_value = ad5421_read_event_value, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad5421_probe(struct spi_device *spi) +{ + struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev); + struct iio_dev *indio_dev; + struct ad5421_state *st; + int ret; + + indio_dev = iio_allocate_device(sizeof(*st)); + if (indio_dev == NULL) { + dev_err(&spi->dev, "Failed to allocate iio device\n"); + return -ENOMEM; + } + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + + st->spi = spi; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = "ad5421"; + indio_dev->info = &ad5421_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad5421_channels; + indio_dev->num_channels = ARRAY_SIZE(ad5421_channels); + + st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE | + AD5421_CTRL_AUTO_FAULT_READBACK; + + if (pdata) { + st->current_range = pdata->current_range; + if (pdata->external_vref) + st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF; + } else { + st->current_range = AD5421_CURRENT_RANGE_4mA_20mA; + } + + /* write initial ctrl register value */ + ad5421_update_ctrl(indio_dev, 0, 0); + + if (spi->irq) { + ret = request_threaded_irq(spi->irq, + NULL, + ad5421_fault_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "ad5421 fault", + indio_dev); + if (ret) + goto error_free; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); + goto error_free_irq; + } + + return 0; + +error_free_irq: + if (spi->irq) + free_irq(spi->irq, indio_dev); +error_free: + iio_free_device(indio_dev); + + return ret; +} + +static int __devexit ad5421_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + iio_device_unregister(indio_dev); + if (spi->irq) + free_irq(spi->irq, indio_dev); + iio_free_device(indio_dev); + + return 0; +} + +static struct spi_driver ad5421_driver = { + .driver = { + .name = "ad5421", + .owner = THIS_MODULE, + }, + .probe = ad5421_probe, + .remove = __devexit_p(ad5421_remove), +}; + +static __init int ad5421_init(void) +{ + return spi_register_driver(&ad5421_driver); +} +module_init(ad5421_init); + +static __exit void ad5421_exit(void) +{ + spi_unregister_driver(&ad5421_driver); +} +module_exit(ad5421_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD5421 DAC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad5421"); diff --git a/drivers/staging/iio/dac/ad5421.h b/drivers/staging/iio/dac/ad5421.h new file mode 100644 index 00000000000..cd2bb84ff1b --- /dev/null +++ b/drivers/staging/iio/dac/ad5421.h @@ -0,0 +1,32 @@ +#ifndef __IIO_DAC_AD5421_H__ +#define __IIO_DAC_AD5421_H__ + +/* + * TODO: This file needs to go into include/linux/iio + */ + +/** + * enum ad5421_current_range - Current range the AD5421 is configured for. + * @AD5421_CURRENT_RANGE_4mA_20mA: 4 mA to 20 mA (RANGE1,0 pins = 00) + * @AD5421_CURRENT_RANGE_3mA8_21mA: 3.8 mA to 21 mA (RANGE1,0 pins = x1) + * @AD5421_CURRENT_RANGE_3mA2_24mA: 3.2 mA to 24 mA (RANGE1,0 pins = 10) + */ + +enum ad5421_current_range { + AD5421_CURRENT_RANGE_4mA_20mA, + AD5421_CURRENT_RANGE_3mA8_21mA, + AD5421_CURRENT_RANGE_3mA2_24mA, +}; + +/** + * struct ad5421_platform_data - AD5421 DAC driver platform data + * @external_vref: whether an external reference voltage is used or not + * @current_range: Current range the AD5421 is configured for + */ + +struct ad5421_platform_data { + bool external_vref; + enum ad5421_current_range current_range; +}; + +#endif diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c index ec701e939b6..693e7482524 100644 --- a/drivers/staging/iio/dac/ad5446.c +++ b/drivers/staging/iio/dac/ad5446.c @@ -26,19 +26,17 @@ static void ad5446_store_sample(struct ad5446_state *st, unsigned val) { - st->data.d16 = cpu_to_be16(AD5446_LOAD | - (val << st->chip_info->left_shift)); + st->data.d16 = cpu_to_be16(AD5446_LOAD | val); } static void ad5542_store_sample(struct ad5446_state *st, unsigned val) { - st->data.d16 = cpu_to_be16(val << st->chip_info->left_shift); + st->data.d16 = cpu_to_be16(val); } static void ad5620_store_sample(struct ad5446_state *st, unsigned val) { - st->data.d16 = cpu_to_be16(AD5620_LOAD | - (val << st->chip_info->left_shift)); + st->data.d16 = cpu_to_be16(AD5620_LOAD | val); } static void ad5660_store_sample(struct ad5446_state *st, unsigned val) @@ -63,50 +61,6 @@ static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode) st->data.d24[2] = val & 0xFF; } -static ssize_t ad5446_write(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(indio_dev); - int ret; - long val; - - ret = strict_strtol(buf, 10, &val); - if (ret) - goto error_ret; - - if (val > RES_MASK(st->chip_info->bits)) { - ret = -EINVAL; - goto error_ret; - } - - mutex_lock(&indio_dev->mlock); - st->cached_val = val; - st->chip_info->store_sample(st, val); - ret = spi_sync(st->spi, &st->msg); - mutex_unlock(&indio_dev->mlock); - -error_ret: - return ret ? ret : len; -} - -static IIO_DEV_ATTR_OUT_RAW(0, ad5446_write, 0); - -static ssize_t ad5446_show_scale(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(indio_dev); - /* Corresponds to Vref / 2^(bits) */ - unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; - - return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); -} -static IIO_DEVICE_ATTR(out_voltage_scale, S_IRUGO, ad5446_show_scale, NULL, 0); - static ssize_t ad5446_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -189,8 +143,6 @@ static IIO_DEVICE_ATTR(out_voltage0_powerdown, S_IRUGO | S_IWUSR, ad5446_write_dac_powerdown, 0); static struct attribute *ad5446_attributes[] = { - &iio_dev_attr_out_voltage0_raw.dev_attr.attr, - &iio_dev_attr_out_voltage_scale.dev_attr.attr, &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, @@ -223,121 +175,148 @@ static const struct attribute_group ad5446_attribute_group = { .is_visible = ad5446_attr_is_visible, }; +#define AD5446_CHANNEL(bits, storage, shift) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = 0, \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .scan_type = IIO_ST('u', (bits), (storage), (shift)) \ +} + static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { [ID_AD5444] = { - .bits = 12, - .storagebits = 16, - .left_shift = 2, + .channel = AD5446_CHANNEL(12, 16, 2), .store_sample = ad5446_store_sample, }, [ID_AD5446] = { - .bits = 14, - .storagebits = 16, - .left_shift = 0, + .channel = AD5446_CHANNEL(14, 16, 0), .store_sample = ad5446_store_sample, }, [ID_AD5541A] = { - .bits = 16, - .storagebits = 16, - .left_shift = 0, + .channel = AD5446_CHANNEL(16, 16, 0), .store_sample = ad5542_store_sample, }, [ID_AD5542A] = { - .bits = 16, - .storagebits = 16, - .left_shift = 0, + .channel = AD5446_CHANNEL(16, 16, 0), .store_sample = ad5542_store_sample, }, [ID_AD5543] = { - .bits = 16, - .storagebits = 16, - .left_shift = 0, + .channel = AD5446_CHANNEL(16, 16, 0), .store_sample = ad5542_store_sample, }, [ID_AD5512A] = { - .bits = 12, - .storagebits = 16, - .left_shift = 4, + .channel = AD5446_CHANNEL(12, 16, 4), .store_sample = ad5542_store_sample, }, [ID_AD5553] = { - .bits = 14, - .storagebits = 16, - .left_shift = 0, + .channel = AD5446_CHANNEL(14, 16, 0), .store_sample = ad5542_store_sample, }, [ID_AD5601] = { - .bits = 8, - .storagebits = 16, - .left_shift = 6, + .channel = AD5446_CHANNEL(8, 16, 6), .store_sample = ad5542_store_sample, .store_pwr_down = ad5620_store_pwr_down, }, [ID_AD5611] = { - .bits = 10, - .storagebits = 16, - .left_shift = 4, + .channel = AD5446_CHANNEL(10, 16, 4), .store_sample = ad5542_store_sample, .store_pwr_down = ad5620_store_pwr_down, }, [ID_AD5621] = { - .bits = 12, - .storagebits = 16, - .left_shift = 2, + .channel = AD5446_CHANNEL(12, 16, 2), .store_sample = ad5542_store_sample, .store_pwr_down = ad5620_store_pwr_down, }, [ID_AD5620_2500] = { - .bits = 12, - .storagebits = 16, - .left_shift = 2, + .channel = AD5446_CHANNEL(12, 16, 2), .int_vref_mv = 2500, .store_sample = ad5620_store_sample, .store_pwr_down = ad5620_store_pwr_down, }, [ID_AD5620_1250] = { - .bits = 12, - .storagebits = 16, - .left_shift = 2, + .channel = AD5446_CHANNEL(12, 16, 2), .int_vref_mv = 1250, .store_sample = ad5620_store_sample, .store_pwr_down = ad5620_store_pwr_down, }, [ID_AD5640_2500] = { - .bits = 14, - .storagebits = 16, - .left_shift = 0, + .channel = AD5446_CHANNEL(14, 16, 0), .int_vref_mv = 2500, .store_sample = ad5620_store_sample, .store_pwr_down = ad5620_store_pwr_down, }, [ID_AD5640_1250] = { - .bits = 14, - .storagebits = 16, - .left_shift = 0, + .channel = AD5446_CHANNEL(14, 16, 0), .int_vref_mv = 1250, .store_sample = ad5620_store_sample, .store_pwr_down = ad5620_store_pwr_down, }, [ID_AD5660_2500] = { - .bits = 16, - .storagebits = 24, - .left_shift = 0, + .channel = AD5446_CHANNEL(16, 16, 0), .int_vref_mv = 2500, .store_sample = ad5660_store_sample, .store_pwr_down = ad5660_store_pwr_down, }, [ID_AD5660_1250] = { - .bits = 16, - .storagebits = 24, - .left_shift = 0, + .channel = AD5446_CHANNEL(16, 16, 0), .int_vref_mv = 1250, .store_sample = ad5660_store_sample, .store_pwr_down = ad5660_store_pwr_down, }, }; +static int ad5446_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + struct ad5446_state *st = iio_priv(indio_dev); + unsigned long scale_uv; + + switch (m) { + case IIO_CHAN_INFO_SCALE: + scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; + + } + return -EINVAL; +} + +static int ad5446_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ad5446_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case 0: + if (val >= (1 << chan->scan_type.realbits) || val < 0) + return -EINVAL; + + val <<= chan->scan_type.shift; + mutex_lock(&indio_dev->mlock); + st->cached_val = val; + st->chip_info->store_sample(st, val); + ret = spi_sync(st->spi, &st->msg); + mutex_unlock(&indio_dev->mlock); + break; + default: + ret = -EINVAL; + } + + return ret; +} + static const struct iio_info ad5446_info = { + .read_raw = ad5446_read_raw, + .write_raw = ad5446_write_raw, .attrs = &ad5446_attribute_group, .driver_module = THIS_MODULE, }; @@ -376,11 +355,13 @@ static int __devinit ad5446_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad5446_info; indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &st->chip_info->channel; + indio_dev->num_channels = 1; /* Setup default message */ st->xfer.tx_buf = &st->data; - st->xfer.len = st->chip_info->storagebits / 8; + st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8; spi_message_init(&st->msg); spi_message_add_tail(&st->xfer, &st->msg); @@ -454,11 +435,11 @@ static const struct spi_device_id ad5446_id[] = { {"ad5660-1250", ID_AD5660_1250}, {} }; +MODULE_DEVICE_TABLE(spi, ad5446_id); static struct spi_driver ad5446_driver = { .driver = { .name = "ad5446", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad5446_probe, @@ -470,4 +451,3 @@ module_spi_driver(ad5446_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad5446"); diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h index 7118d653ac3..4ea3476fb06 100644 --- a/drivers/staging/iio/dac/ad5446.h +++ b/drivers/staging/iio/dac/ad5446.h @@ -25,8 +25,6 @@ #define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */ #define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */ -#define RES_MASK(bits) ((1 << (bits)) - 1) - #define MODE_PWRDWN_1k 0x1 #define MODE_PWRDWN_100k 0x2 #define MODE_PWRDWN_TRISTATE 0x3 @@ -62,18 +60,14 @@ struct ad5446_state { /** * struct ad5446_chip_info - chip specific information - * @bits: accuracy of the DAC in bits - * @storagebits: number of bits written to the DAC - * @left_shift: number of bits the datum must be shifted + * @channel: channel spec for the DAC * @int_vref_mv: AD5620/40/60: the internal reference voltage * @store_sample: chip specific helper function to store the datum * @store_sample: chip specific helper function to store the powerpown cmd */ struct ad5446_chip_info { - u8 bits; - u8 storagebits; - u8 left_shift; + struct iio_chan_spec channel; u16 int_vref_mv; void (*store_sample) (struct ad5446_state *st, unsigned val); void (*store_pwr_down) (struct ad5446_state *st, unsigned mode); diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c index 57539ce8e6c..bc17205fe72 100644 --- a/drivers/staging/iio/dac/ad5504.c +++ b/drivers/staging/iio/dac/ad5504.c @@ -18,9 +18,27 @@ #include "../iio.h" #include "../sysfs.h" +#include "../events.h" #include "dac.h" #include "ad5504.h" +#define AD5504_CHANNEL(_chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (_chan), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .address = AD5504_ADDR_DAC(_chan), \ + .scan_type = IIO_ST('u', 12, 16, 0), \ +} + +static const struct iio_chan_spec ad5504_channels[] = { + AD5504_CHANNEL(0), + AD5504_CHANNEL(1), + AD5504_CHANNEL(2), + AD5504_CHANNEL(3), +}; + static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val) { u16 tmp = cpu_to_be16(AD5504_CMD_WRITE | @@ -30,13 +48,14 @@ static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val) return spi_write(spi, (u8 *)&tmp, 2); } -static int ad5504_spi_read(struct spi_device *spi, u8 addr, u16 *val) +static int ad5504_spi_read(struct spi_device *spi, u8 addr) { u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); + u16 val; int ret; struct spi_transfer t = { .tx_buf = &tmp, - .rx_buf = val, + .rx_buf = &val, .len = 2, }; struct spi_message m; @@ -45,44 +64,61 @@ static int ad5504_spi_read(struct spi_device *spi, u8 addr, u16 *val) spi_message_add_tail(&t, &m); ret = spi_sync(spi, &m); - *val = be16_to_cpu(*val) & AD5504_RES_MASK; + if (ret < 0) + return ret; - return ret; + return be16_to_cpu(val) & AD5504_RES_MASK; } -static ssize_t ad5504_write_dac(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static int ad5504_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long readin; + unsigned long scale_uv; int ret; - ret = strict_strtol(buf, 10, &readin); - if (ret) - return ret; + switch (m) { + case 0: + ret = ad5504_spi_read(st->spi, chan->address); + if (ret < 0) + return ret; - ret = ad5504_spi_write(st->spi, this_attr->address, readin); - return ret ? ret : len; + *val = ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; + + } + return -EINVAL; } -static ssize_t ad5504_read_dac(struct device *dev, - struct device_attribute *attr, - char *buf) +static int ad5504_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5504_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - u16 val; - ret = ad5504_spi_read(st->spi, this_attr->address, &val); - if (ret) - return ret; + switch (mask) { + case 0: + if (val >= (1 << chan->scan_type.realbits) || val < 0) + return -EINVAL; - return sprintf(buf, "%d\n", val); + return ad5504_spi_write(st->spi, chan->address, val); + default: + ret = -EINVAL; + } + + return -EINVAL; } static ssize_t ad5504_read_powerdown_mode(struct device *dev, @@ -157,32 +193,6 @@ static ssize_t ad5504_write_dac_powerdown(struct device *dev, return ret ? ret : len; } -static ssize_t ad5504_show_scale(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5504_state *st = iio_priv(indio_dev); - /* Corresponds to Vref / 2^(bits) */ - unsigned int scale_uv = (st->vref_mv * 1000) >> AD5505_BITS; - - return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); -} -static IIO_DEVICE_ATTR(out_voltage_scale, S_IRUGO, ad5504_show_scale, NULL, 0); - -#define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr) \ - IIO_DEVICE_ATTR(out_voltage##_num##_raw, \ - S_IRUGO | S_IWUSR, _show, _store, _addr) - -static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5504_read_dac, - ad5504_write_dac, AD5504_ADDR_DAC0); -static IIO_DEV_ATTR_OUT_RW_RAW(1, ad5504_read_dac, - ad5504_write_dac, AD5504_ADDR_DAC1); -static IIO_DEV_ATTR_OUT_RW_RAW(2, ad5504_read_dac, - ad5504_write_dac, AD5504_ADDR_DAC2); -static IIO_DEV_ATTR_OUT_RW_RAW(3, ad5504_read_dac, - ad5504_write_dac, AD5504_ADDR_DAC3); - static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR, ad5504_read_powerdown_mode, ad5504_write_powerdown_mode, 0); @@ -203,17 +213,12 @@ static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5504_read_dac_powerdown, ad5504_write_dac_powerdown, 3); static struct attribute *ad5504_attributes[] = { - &iio_dev_attr_out_voltage0_raw.dev_attr.attr, - &iio_dev_attr_out_voltage1_raw.dev_attr.attr, - &iio_dev_attr_out_voltage2_raw.dev_attr.attr, - &iio_dev_attr_out_voltage3_raw.dev_attr.attr, &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage1_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage2_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage3_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, - &iio_dev_attr_out_voltage_scale.dev_attr.attr, NULL, }; @@ -222,11 +227,9 @@ static const struct attribute_group ad5504_attribute_group = { }; static struct attribute *ad5501_attributes[] = { - &iio_dev_attr_out_voltage0_raw.dev_attr.attr, &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, - &iio_dev_attr_out_voltage_scale.dev_attr.attr, NULL, }; @@ -261,12 +264,16 @@ static irqreturn_t ad5504_event_handler(int irq, void *private) } static const struct iio_info ad5504_info = { + .write_raw = ad5504_write_raw, + .read_raw = ad5504_read_raw, .attrs = &ad5504_attribute_group, .event_attrs = &ad5504_ev_attribute_group, .driver_module = THIS_MODULE, }; static const struct iio_info ad5501_info = { + .write_raw = ad5504_write_raw, + .read_raw = ad5504_read_raw, .attrs = &ad5501_attribute_group, .event_attrs = &ad5504_ev_attribute_group, .driver_module = THIS_MODULE, @@ -307,10 +314,14 @@ static int __devinit ad5504_probe(struct spi_device *spi) st->spi = spi; indio_dev->dev.parent = &spi->dev; indio_dev->name = spi_get_device_id(st->spi)->name; - if (spi_get_device_id(st->spi)->driver_data == ID_AD5501) + if (spi_get_device_id(st->spi)->driver_data == ID_AD5501) { indio_dev->info = &ad5501_info; - else + indio_dev->num_channels = 1; + } else { indio_dev->info = &ad5504_info; + indio_dev->num_channels = 4; + } + indio_dev->channels = ad5504_channels; indio_dev->modes = INDIO_DIRECT_MODE; if (spi->irq) { @@ -367,6 +378,7 @@ static const struct spi_device_id ad5504_id[] = { {"ad5501", ID_AD5501}, {} }; +MODULE_DEVICE_TABLE(spi, ad5504_id); static struct spi_driver ad5504_driver = { .driver = { diff --git a/drivers/staging/iio/dac/ad5504.h b/drivers/staging/iio/dac/ad5504.h index 85beb1dd29b..afe09522f53 100644 --- a/drivers/staging/iio/dac/ad5504.h +++ b/drivers/staging/iio/dac/ad5504.h @@ -18,10 +18,7 @@ /* Registers */ #define AD5504_ADDR_NOOP 0 -#define AD5504_ADDR_DAC0 1 -#define AD5504_ADDR_DAC1 2 -#define AD5504_ADDR_DAC2 3 -#define AD5504_ADDR_DAC3 4 +#define AD5504_ADDR_DAC(x) ((x) + 1) #define AD5504_ADDR_ALL_DAC 5 #define AD5504_ADDR_CTRL 7 diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h index b71c6a03e78..5dca3028cdf 100644 --- a/drivers/staging/iio/dac/ad5624r.h +++ b/drivers/staging/iio/dac/ad5624r.h @@ -32,12 +32,12 @@ /** * struct ad5624r_chip_info - chip specific information - * @bits: accuracy of the DAC in bits + * @channels: channel spec for the DAC * @int_vref_mv: AD5620/40/60: the internal reference voltage */ struct ad5624r_chip_info { - u8 bits; + const struct iio_chan_spec *channels; u16 int_vref_mv; }; diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c index 6e05f0dbae0..10c7484366e 100644 --- a/drivers/staging/iio/dac/ad5624r_spi.c +++ b/drivers/staging/iio/dac/ad5624r_spi.c @@ -21,29 +21,51 @@ #include "dac.h" #include "ad5624r.h" +#define AD5624R_CHANNEL(_chan, _bits) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (_chan), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .address = (_chan), \ + .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \ +} + +#define DECLARE_AD5624R_CHANNELS(_name, _bits) \ + const struct iio_chan_spec _name##_channels[] = { \ + AD5624R_CHANNEL(0, _bits), \ + AD5624R_CHANNEL(1, _bits), \ + AD5624R_CHANNEL(2, _bits), \ + AD5624R_CHANNEL(3, _bits), \ +} + +static DECLARE_AD5624R_CHANNELS(ad5624r, 12); +static DECLARE_AD5624R_CHANNELS(ad5644r, 14); +static DECLARE_AD5624R_CHANNELS(ad5664r, 16); + static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = { [ID_AD5624R3] = { - .bits = 12, - .int_vref_mv = 1250, - }, - [ID_AD5644R3] = { - .bits = 14, - .int_vref_mv = 1250, - }, - [ID_AD5664R3] = { - .bits = 16, + .channels = ad5624r_channels, .int_vref_mv = 1250, }, [ID_AD5624R5] = { - .bits = 12, + .channels = ad5624r_channels, .int_vref_mv = 2500, }, + [ID_AD5644R3] = { + .channels = ad5644r_channels, + .int_vref_mv = 1250, + }, [ID_AD5644R5] = { - .bits = 14, + .channels = ad5644r_channels, .int_vref_mv = 2500, }, + [ID_AD5664R3] = { + .channels = ad5664r_channels, + .int_vref_mv = 1250, + }, [ID_AD5664R5] = { - .bits = 16, + .channels = ad5664r_channels, .int_vref_mv = 2500, }, }; @@ -70,24 +92,49 @@ static int ad5624r_spi_write(struct spi_device *spi, return spi_write(spi, msg, 3); } -static ssize_t ad5624r_write_dac(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static int ad5624r_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) { - long readin; - int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5624r_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + unsigned long scale_uv; - ret = strict_strtol(buf, 10, &readin); - if (ret) - return ret; + switch (m) { + case IIO_CHAN_INFO_SCALE: + scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; - ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, - this_attr->address, readin, - st->chip_info->bits); - return ret ? ret : len; + } + return -EINVAL; +} + +static int ad5624r_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ad5624r_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case 0: + if (val >= (1 << chan->scan_type.realbits) || val < 0) + return -EINVAL; + + return ad5624r_spi_write(st->us, + AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, + chan->address, val, + chan->scan_type.shift); + default: + ret = -EINVAL; + } + + return -EINVAL; } static ssize_t ad5624r_read_powerdown_mode(struct device *dev, @@ -161,24 +208,6 @@ static ssize_t ad5624r_write_dac_powerdown(struct device *dev, return ret ? ret : len; } -static ssize_t ad5624r_show_scale(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5624r_state *st = iio_priv(indio_dev); - /* Corresponds to Vref / 2^(bits) */ - unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; - - return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); -} -static IIO_DEVICE_ATTR(out_voltage_scale, S_IRUGO, ad5624r_show_scale, NULL, 0); - -static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0); -static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1); -static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); -static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); - static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR, ad5624r_read_powerdown_mode, ad5624r_write_powerdown_mode, 0); @@ -200,17 +229,12 @@ static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5624r_read_dac_powerdown, ad5624r_write_dac_powerdown, 3); static struct attribute *ad5624r_attributes[] = { - &iio_dev_attr_out_voltage0_raw.dev_attr.attr, - &iio_dev_attr_out_voltage1_raw.dev_attr.attr, - &iio_dev_attr_out_voltage2_raw.dev_attr.attr, - &iio_dev_attr_out_voltage3_raw.dev_attr.attr, &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage1_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage2_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage3_powerdown.dev_attr.attr, &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, - &iio_dev_attr_out_voltage_scale.dev_attr.attr, NULL, }; @@ -219,6 +243,8 @@ static const struct attribute_group ad5624r_attribute_group = { }; static const struct iio_info ad5624r_info = { + .write_raw = ad5624r_write_raw, + .read_raw = ad5624r_read_raw, .attrs = &ad5624r_attribute_group, .driver_module = THIS_MODULE, }; @@ -259,6 +285,8 @@ static int __devinit ad5624r_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad5624r_info; indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = AD5624R_DAC_CHANNELS; ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, !!voltage_uv, 16); @@ -307,6 +335,7 @@ static const struct spi_device_id ad5624r_id[] = { {"ad5664r5", ID_AD5664R5}, {} }; +MODULE_DEVICE_TABLE(spi, ad5624r_id); static struct spi_driver ad5624r_driver = { .driver = { diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c index e72db2fbfed..ce2d6193dd8 100644 --- a/drivers/staging/iio/dac/ad5686.c +++ b/drivers/staging/iio/dac/ad5686.c @@ -99,7 +99,7 @@ enum ad5686_supported_device_ids { .indexed = 1, \ .output = 1, \ .channel = chan, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = AD5686_ADDR_DAC(chan), \ .scan_type = IIO_ST('u', bits, 16, shift) \ } @@ -306,7 +306,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: scale_uv = (st->vref_mv * 100000) >> (chan->scan_type.realbits); *val = scale_uv / 100000; @@ -437,6 +437,7 @@ static const struct spi_device_id ad5686_id[] = { {"ad5686", ID_AD5686}, {} }; +MODULE_DEVICE_TABLE(spi, ad5686_id); static struct spi_driver ad5686_driver = { .driver = { diff --git a/drivers/staging/iio/dac/ad5764.c b/drivers/staging/iio/dac/ad5764.c new file mode 100644 index 00000000000..ff91480ae65 --- /dev/null +++ b/drivers/staging/iio/dac/ad5764.c @@ -0,0 +1,393 @@ +/* + * Analog devices AD5764, AD5764R, AD5744, AD5744R quad-channel + * Digital to Analog Converters driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/regulator/consumer.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "dac.h" + +#define AD5764_REG_SF_NOP 0x0 +#define AD5764_REG_SF_CONFIG 0x1 +#define AD5764_REG_SF_CLEAR 0x4 +#define AD5764_REG_SF_LOAD 0x5 +#define AD5764_REG_DATA(x) ((2 << 3) | (x)) +#define AD5764_REG_COARSE_GAIN(x) ((3 << 3) | (x)) +#define AD5764_REG_FINE_GAIN(x) ((4 << 3) | (x)) +#define AD5764_REG_OFFSET(x) ((5 << 3) | (x)) + +#define AD5764_NUM_CHANNELS 4 + +/** + * struct ad5764_chip_info - chip specific information + * @int_vref: Value of the internal reference voltage in uV - 0 if external + * reference voltage is used + * @channel channel specification +*/ + +struct ad5764_chip_info { + unsigned long int_vref; + const struct iio_chan_spec *channels; +}; + +/** + * struct ad5764_state - driver instance specific data + * @spi: spi_device + * @chip_info: chip info + * @vref_reg: vref supply regulators + * @data: spi transfer buffers + */ + +struct ad5764_state { + struct spi_device *spi; + const struct ad5764_chip_info *chip_info; + struct regulator_bulk_data vref_reg[2]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + union { + __be32 d32; + u8 d8[4]; + } data[2] ____cacheline_aligned; +}; + +enum ad5764_type { + ID_AD5744, + ID_AD5744R, + ID_AD5764, + ID_AD5764R, +}; + +#define AD5764_CHANNEL(_chan, _bits) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (_chan), \ + .address = (_chan), \ + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ + .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)) \ +} + +#define DECLARE_AD5764_CHANNELS(_name, _bits) \ +const struct iio_chan_spec _name##_channels[] = { \ + AD5764_CHANNEL(0, (_bits)), \ + AD5764_CHANNEL(1, (_bits)), \ + AD5764_CHANNEL(2, (_bits)), \ + AD5764_CHANNEL(3, (_bits)), \ +}; + +static DECLARE_AD5764_CHANNELS(ad5764, 16); +static DECLARE_AD5764_CHANNELS(ad5744, 14); + +static const struct ad5764_chip_info ad5764_chip_infos[] = { + [ID_AD5744] = { + .int_vref = 0, + .channels = ad5744_channels, + }, + [ID_AD5744R] = { + .int_vref = 5000000, + .channels = ad5744_channels, + }, + [ID_AD5764] = { + .int_vref = 0, + .channels = ad5764_channels, + }, + [ID_AD5764R] = { + .int_vref = 5000000, + .channels = ad5764_channels, + }, +}; + +static int ad5764_write(struct iio_dev *indio_dev, unsigned int reg, + unsigned int val) +{ + struct ad5764_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&indio_dev->mlock); + st->data[0].d32 = cpu_to_be32((reg << 16) | val); + + ret = spi_write(st->spi, &st->data[0].d8[1], 3); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg, + unsigned int *val) +{ + struct ad5764_state *st = iio_priv(indio_dev); + struct spi_message m; + int ret; + struct spi_transfer t[] = { + { + .tx_buf = &st->data[0].d8[1], + .len = 3, + .cs_change = 1, + }, { + .rx_buf = &st->data[1].d8[1], + .len = 3, + }, + }; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + + mutex_lock(&indio_dev->mlock); + + st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); + + ret = spi_sync(st->spi, &m); + if (ret >= 0) + *val = be32_to_cpu(st->data[1].d32) & 0xffff; + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5764_chan_info_to_reg(struct iio_chan_spec const *chan, long info) +{ + switch (info) { + case 0: + return AD5764_REG_DATA(chan->address); + case IIO_CHAN_INFO_CALIBBIAS: + return AD5764_REG_OFFSET(chan->address); + case IIO_CHAN_INFO_CALIBSCALE: + return AD5764_REG_FINE_GAIN(chan->address); + default: + break; + } + + return 0; +} + +static int ad5764_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long info) +{ + const int max_val = (1 << chan->scan_type.realbits); + unsigned int reg; + + switch (info) { + case 0: + if (val >= max_val || val < 0) + return -EINVAL; + val <<= chan->scan_type.shift; + break; + case IIO_CHAN_INFO_CALIBBIAS: + if (val >= 128 || val < -128) + return -EINVAL; + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (val >= 32 || val < -32) + return -EINVAL; + break; + default: + return -EINVAL; + } + + reg = ad5764_chan_info_to_reg(chan, info); + return ad5764_write(indio_dev, reg, (u16)val); +} + +static int ad5764_get_channel_vref(struct ad5764_state *st, + unsigned int channel) +{ + if (st->chip_info->int_vref) + return st->chip_info->int_vref; + else + return regulator_get_voltage(st->vref_reg[channel / 2].consumer); +} + +static int ad5764_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long info) +{ + struct ad5764_state *st = iio_priv(indio_dev); + unsigned long scale_uv; + unsigned int reg; + int vref; + int ret; + + switch (info) { + case 0: + reg = AD5764_REG_DATA(chan->address); + ret = ad5764_read(indio_dev, reg, val); + if (ret < 0) + return ret; + *val >>= chan->scan_type.shift; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + reg = AD5764_REG_OFFSET(chan->address); + ret = ad5764_read(indio_dev, reg, val); + if (ret < 0) + return ret; + *val = sign_extend32(*val, 7); + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + reg = AD5764_REG_FINE_GAIN(chan->address); + ret = ad5764_read(indio_dev, reg, val); + if (ret < 0) + return ret; + *val = sign_extend32(*val, 5); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* vout = 4 * vref + ((dac_code / 65535) - 0.5) */ + vref = ad5764_get_channel_vref(st, chan->channel); + if (vref < 0) + return vref; + + scale_uv = (vref * 4 * 100) >> chan->scan_type.realbits; + *val = scale_uv / 100000; + *val2 = (scale_uv % 100000) * 10; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = -(1 << chan->scan_type.realbits) / 2; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static const struct iio_info ad5764_info = { + .read_raw = ad5764_read_raw, + .write_raw = ad5764_write_raw, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad5764_probe(struct spi_device *spi) +{ + enum ad5764_type type = spi_get_device_id(spi)->driver_data; + struct iio_dev *indio_dev; + struct ad5764_state *st; + int ret; + + indio_dev = iio_allocate_device(sizeof(*st)); + if (indio_dev == NULL) { + dev_err(&spi->dev, "Failed to allocate iio device\n"); + return -ENOMEM; + } + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + + st->spi = spi; + st->chip_info = &ad5764_chip_infos[type]; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->info = &ad5764_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->num_channels = AD5764_NUM_CHANNELS; + indio_dev->channels = st->chip_info->channels; + + if (st->chip_info->int_vref == 0) { + st->vref_reg[0].supply = "vrefAB"; + st->vref_reg[1].supply = "vrefCD"; + + ret = regulator_bulk_get(&st->spi->dev, + ARRAY_SIZE(st->vref_reg), st->vref_reg); + if (ret) { + dev_err(&spi->dev, "Failed to request vref regulators: %d\n", + ret); + goto error_free; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg), + st->vref_reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", + ret); + goto error_free_reg; + } + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); + goto error_disable_reg; + } + + return 0; + +error_disable_reg: + if (st->chip_info->int_vref == 0) + regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg); +error_free_reg: + if (st->chip_info->int_vref == 0) + regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg); +error_free: + iio_free_device(indio_dev); + + return ret; +} + +static int __devexit ad5764_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad5764_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + if (st->chip_info->int_vref == 0) { + regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg); + regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg); + } + + iio_free_device(indio_dev); + + return 0; +} + +static const struct spi_device_id ad5764_ids[] = { + { "ad5744", ID_AD5744 }, + { "ad5744r", ID_AD5744R }, + { "ad5764", ID_AD5764 }, + { "ad5764r", ID_AD5764R }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad5764_ids); + +static struct spi_driver ad5764_driver = { + .driver = { + .name = "ad5764", + .owner = THIS_MODULE, + }, + .probe = ad5764_probe, + .remove = __devexit_p(ad5764_remove), + .id_table = ad5764_ids, +}; + +static int __init ad5764_spi_init(void) +{ + return spi_register_driver(&ad5764_driver); +} +module_init(ad5764_spi_init); + +static void __exit ad5764_spi_exit(void) +{ + spi_unregister_driver(&ad5764_driver); +} +module_exit(ad5764_spi_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c index 4a80fd82223..ac45636a8d7 100644 --- a/drivers/staging/iio/dac/ad5791.c +++ b/drivers/staging/iio/dac/ad5791.c @@ -1,5 +1,6 @@ /* - * AD5760, AD5780, AD5781, AD5791 Voltage Output Digital to Analog Converter + * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog + * Converter * * Copyright 2011 Analog Devices Inc. * @@ -77,8 +78,8 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) .indexed = 1, \ .address = AD5791_ADDR_DAC0, \ .channel = 0, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED) | \ - (1 << IIO_CHAN_INFO_OFFSET_SHARED), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ .scan_type = IIO_ST('u', bits, 24, shift) \ } @@ -237,11 +238,11 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, *val &= AD5791_DAC_MASK; *val >>= chan->scan_type.shift; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: *val = 0; *val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits; return IIO_VAL_INT_PLUS_MICRO; - case (1 << IIO_CHAN_INFO_OFFSET_SHARED): + case IIO_CHAN_INFO_OFFSET: val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits); do_div(val64, st->vref_mv); *val = -val64; @@ -397,9 +398,11 @@ static const struct spi_device_id ad5791_id[] = { {"ad5760", ID_AD5760}, {"ad5780", ID_AD5780}, {"ad5781", ID_AD5781}, + {"ad5790", ID_AD5791}, {"ad5791", ID_AD5791}, {} }; +MODULE_DEVICE_TABLE(spi, ad5791_id); static struct spi_driver ad5791_driver = { .driver = { @@ -413,5 +416,5 @@ static struct spi_driver ad5791_driver = { module_spi_driver(ad5791_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5791 DAC"); +MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/dds/ad5930.c index 4a360d044a3..9c32d1beae2 100644 --- a/drivers/staging/iio/dds/ad5930.c +++ b/drivers/staging/iio/dds/ad5930.c @@ -148,3 +148,4 @@ module_spi_driver(ad5930_driver); MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("Analog Devices ad5930 driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c index cc32fd65b8b..2ccf25dd928 100644 --- a/drivers/staging/iio/dds/ad9832.c +++ b/drivers/staging/iio/dds/ad9832.c @@ -88,7 +88,7 @@ static ssize_t ad9832_write(struct device *dev, goto error_ret; mutex_lock(&indio_dev->mlock); - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD9832_FREQ0HM: case AD9832_FREQ1HM: ret = ad9832_write_frequency(st, this_attr->address, val); @@ -344,11 +344,11 @@ static const struct spi_device_id ad9832_id[] = { {"ad9835", 0}, {} }; +MODULE_DEVICE_TABLE(spi, ad9832_id); static struct spi_driver ad9832_driver = { .driver = { .name = "ad9832", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad9832_probe, @@ -360,4 +360,3 @@ module_spi_driver(ad9832_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad9832"); diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/dds/ad9834.c index 51fda6f6981..5e67104fea1 100644 --- a/drivers/staging/iio/dds/ad9834.c +++ b/drivers/staging/iio/dds/ad9834.c @@ -77,7 +77,7 @@ static ssize_t ad9834_write(struct device *dev, goto error_ret; mutex_lock(&indio_dev->mlock); - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD9834_REG_FREQ0: case AD9834_REG_FREQ1: ret = ad9834_write_frequency(st, this_attr->address, val); @@ -153,7 +153,7 @@ static ssize_t ad9834_store_wavetype(struct device *dev, mutex_lock(&indio_dev->mlock); - switch (this_attr->address) { + switch ((u32) this_attr->address) { case 0: if (sysfs_streq(buf, "sine")) { st->control &= ~AD9834_MODE; @@ -435,11 +435,11 @@ static const struct spi_device_id ad9834_id[] = { {"ad9838", ID_AD9838}, {} }; +MODULE_DEVICE_TABLE(spi, ad9834_id); static struct spi_driver ad9834_driver = { .driver = { .name = "ad9834", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad9834_probe, @@ -451,4 +451,3 @@ module_spi_driver(ad9834_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad9834"); diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/dds/ad9850.c index f9c96afcb99..f4f731bb219 100644 --- a/drivers/staging/iio/dds/ad9850.c +++ b/drivers/staging/iio/dds/ad9850.c @@ -134,3 +134,4 @@ module_spi_driver(ad9850_driver); MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("Analog Devices ad9850 driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c index 9fc73fdc9c3..554266c615a 100644 --- a/drivers/staging/iio/dds/ad9852.c +++ b/drivers/staging/iio/dds/ad9852.c @@ -285,3 +285,4 @@ module_spi_driver(ad9852_driver); MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("Analog Devices ad9852 driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c index 57046b03121..3985766d6f8 100644 --- a/drivers/staging/iio/dds/ad9910.c +++ b/drivers/staging/iio/dds/ad9910.c @@ -418,3 +418,4 @@ module_spi_driver(ad9910_driver); MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("Analog Devices ad9910 driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c index d29130e9acd..4d150048002 100644 --- a/drivers/staging/iio/dds/ad9951.c +++ b/drivers/staging/iio/dds/ad9951.c @@ -229,3 +229,4 @@ module_spi_driver(ad9951_driver); MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("Analog Devices ad9951 driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h new file mode 100644 index 00000000000..bfb63400fa6 --- /dev/null +++ b/drivers/staging/iio/events.h @@ -0,0 +1,103 @@ +/* The industrial I/O - event passing to userspace + * + * Copyright (c) 2008-2011 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#ifndef _IIO_EVENTS_H_ +#define _IIO_EVENTS_H_ + +#include <linux/ioctl.h> +#include <linux/types.h> +#include "types.h" + +/** + * struct iio_event_data - The actual event being pushed to userspace + * @id: event identifier + * @timestamp: best estimate of time of event occurrence (often from + * the interrupt handler) + */ +struct iio_event_data { + __u64 id; + __s64 timestamp; +}; + +#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int) + +enum iio_event_type { + IIO_EV_TYPE_THRESH, + IIO_EV_TYPE_MAG, + IIO_EV_TYPE_ROC, + IIO_EV_TYPE_THRESH_ADAPTIVE, + IIO_EV_TYPE_MAG_ADAPTIVE, +}; + +enum iio_event_direction { + IIO_EV_DIR_EITHER, + IIO_EV_DIR_RISING, + IIO_EV_DIR_FALLING, +}; + +/** + * IIO_EVENT_CODE() - create event identifier + * @chan_type: Type of the channel. Should be one of enum iio_chan_type. + * @diff: Whether the event is for an differential channel or not. + * @modifier: Modifier for the channel. Should be one of enum iio_modifier. + * @direction: Direction of the event. One of enum iio_event_direction. + * @type: Type of the event. Should be one enum iio_event_type. + * @chan: Channel number for non-differential channels. + * @chan1: First channel number for differential channels. + * @chan2: Second channel number for differential channels. + */ + +#define IIO_EVENT_CODE(chan_type, diff, modifier, direction, \ + type, chan, chan1, chan2) \ + (((u64)type << 56) | ((u64)diff << 55) | \ + ((u64)direction << 48) | ((u64)modifier << 40) | \ + ((u64)chan_type << 32) | (((u16)chan2) << 16) | ((u16)chan1) | \ + ((u16)chan)) + + +#define IIO_EV_DIR_MAX 4 +#define IIO_EV_BIT(type, direction) \ + (1 << (type*IIO_EV_DIR_MAX + direction)) + +/** + * IIO_MOD_EVENT_CODE() - create event identifier for modified channels + * @chan_type: Type of the channel. Should be one of enum iio_chan_type. + * @number: Channel number. + * @modifier: Modifier for the channel. Should be one of enum iio_modifier. + * @type: Type of the event. Should be one enum iio_event_type. + * @direction: Direction of the event. One of enum iio_event_direction. + */ + +#define IIO_MOD_EVENT_CODE(chan_type, number, modifier, \ + type, direction) \ + IIO_EVENT_CODE(chan_type, 0, modifier, direction, type, number, 0, 0) + +/** + * IIO_UNMOD_EVENT_CODE() - create event identifier for unmodified channels + * @chan_type: Type of the channel. Should be one of enum iio_chan_type. + * @number: Channel number. + * @type: Type of the event. Should be one enum iio_event_type. + * @direction: Direction of the event. One of enum iio_event_direction. + */ + +#define IIO_UNMOD_EVENT_CODE(chan_type, number, type, direction) \ + IIO_EVENT_CODE(chan_type, 0, 0, direction, type, number, 0, 0) + +#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF) + +#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF) + +#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF) + +/* Event code number extraction depends on which type of event we have. + * Perhaps review this function in the future*/ +#define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((__s16)(mask & 0xFFFF)) + +#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF) + +#endif diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index 22aea5b4e61..ea295b25308 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -37,11 +37,11 @@ config ADIS16260 will be called adis16260. config ADXRS450 - tristate "Analog Devices ADXRS450 Digital Output Gyroscope SPI driver" + tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver" depends on SPI help - Say yes here to build support for Analog Devices ADXRS450 programmable - digital output gyroscope. + Say yes here to build support for Analog Devices ADXRS450 and ADXRS453 + programmable digital output gyroscope. This driver can also be built as a module. If so, the module will be called adxrs450. diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c index ff1b5a82b3d..c0ca7093e0e 100644 --- a/drivers/staging/iio/gyro/adis16060_core.c +++ b/drivers/staging/iio/gyro/adis16060_core.c @@ -98,11 +98,11 @@ static int adis16060_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); *val = tval; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = -7; *val2 = 461117; return IIO_VAL_INT_PLUS_MICRO; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: *val = 0; *val2 = 34000; return IIO_VAL_INT_PLUS_MICRO; @@ -136,8 +136,8 @@ static const struct iio_chan_spec adis16060_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = ADIS16060_TEMP_OUT, } }; diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index 9405f2d368e..1815490db8b 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -194,3 +194,4 @@ module_spi_driver(adis16080_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16080"); diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c index c9aaca9631f..947eb86f05d 100644 --- a/drivers/staging/iio/gyro/adis16130_core.c +++ b/drivers/staging/iio/gyro/adis16130_core.c @@ -173,3 +173,4 @@ module_spi_driver(adis16130_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16130"); diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index 886dddf867e..8f6af47e955 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -20,7 +20,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "adis16260.h" @@ -390,9 +390,9 @@ enum adis16260_channel { #define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \ struct iio_chan_spec adis16260_channels_##axis[] = { \ IIO_CHAN(IIO_ANGL_VEL, 1, 0, 0, NULL, 0, mod, \ - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | \ - (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \ - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ gyro, ADIS16260_SCAN_GYRO, \ IIO_ST('s', 14, 16, 0), 0), \ IIO_CHAN(IIO_ANGL, 1, 0, 0, NULL, 0, mod, \ @@ -400,16 +400,16 @@ enum adis16260_channel { angle, ADIS16260_SCAN_ANGL, \ IIO_ST('u', 14, 16, 0), 0), \ IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, \ - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | \ - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ temp, ADIS16260_SCAN_TEMP, \ IIO_ST('u', 12, 16, 0), 0), \ IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, \ - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ in_supply, ADIS16260_SCAN_SUPPLY, \ IIO_ST('u', 12, 16, 0), 0), \ IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, \ - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ in_aux, ADIS16260_SCAN_AUX_ADC, \ IIO_ST('u', 12, 16, 0), 0), \ IIO_CHAN_SOFT_TIMESTAMP(5) \ @@ -464,8 +464,7 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: *val = 0; @@ -489,10 +488,10 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, return -EINVAL; } break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: *val = 25; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_ANGL_VEL: bits = 12; @@ -512,7 +511,7 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: switch (chan->type) { case IIO_ANGL_VEL: bits = 12; @@ -544,11 +543,11 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, s16 val16; u8 addr; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: val16 = val & ((1 << bits) - 1); addr = adis16260_addresses[chan->address][1]; return adis16260_spi_write_reg_16(indio_dev, addr, val16); - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: val16 = val & ((1 << bits) - 1); addr = adis16260_addresses[chan->address][2]; return adis16260_spi_write_reg_16(indio_dev, addr, val16); @@ -633,11 +632,16 @@ static int __devinit adis16260_probe(struct spi_device *spi) } if (indio_dev->buffer) { /* Set default scan mode */ - iio_scan_mask_set(indio_dev->buffer, ADIS16260_SCAN_SUPPLY); - iio_scan_mask_set(indio_dev->buffer, ADIS16260_SCAN_GYRO); - iio_scan_mask_set(indio_dev->buffer, ADIS16260_SCAN_AUX_ADC); - iio_scan_mask_set(indio_dev->buffer, ADIS16260_SCAN_TEMP); - iio_scan_mask_set(indio_dev->buffer, ADIS16260_SCAN_ANGL); + iio_scan_mask_set(indio_dev, indio_dev->buffer, + ADIS16260_SCAN_SUPPLY); + iio_scan_mask_set(indio_dev, indio_dev->buffer, + ADIS16260_SCAN_GYRO); + iio_scan_mask_set(indio_dev, indio_dev->buffer, + ADIS16260_SCAN_AUX_ADC); + iio_scan_mask_set(indio_dev, indio_dev->buffer, + ADIS16260_SCAN_TEMP); + iio_scan_mask_set(indio_dev, indio_dev->buffer, + ADIS16260_SCAN_ANGL); } if (spi->irq) { ret = adis16260_probe_trigger(indio_dev); @@ -701,6 +705,7 @@ static const struct spi_device_id adis16260_id[] = { {"adis16251", 1}, {} }; +MODULE_DEVICE_TABLE(spi, adis16260_id); static struct spi_driver adis16260_driver = { .driver = { diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c index 52a9e784e7c..699a6152c40 100644 --- a/drivers/staging/iio/gyro/adis16260_ring.c +++ b/drivers/staging/iio/gyro/adis16260_ring.c @@ -74,9 +74,10 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p) return -ENOMEM; } - if (ring->scan_count && + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && adis16260_read_ring_data(&indio_dev->dev, st->rx) >= 0) - for (; i < ring->scan_count; i++) + for (; i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ @@ -116,10 +117,8 @@ int adis16260_configure_ring(struct iio_dev *indio_dev) indio_dev->buffer = ring; /* Effectively select the ring buffer implementation */ ring->access = &ring_sw_access_funcs; - ring->bpe = 2; ring->scan_timestamp = true; - ring->setup_ops = &adis16260_ring_setup_ops; - ring->owner = THIS_MODULE; + indio_dev->setup_ops = &adis16260_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &adis16260_trigger_handler, diff --git a/drivers/staging/iio/gyro/adxrs450.h b/drivers/staging/iio/gyro/adxrs450.h index b6b68287640..af0c870100b 100644 --- a/drivers/staging/iio/gyro/adxrs450.h +++ b/drivers/staging/iio/gyro/adxrs450.h @@ -39,6 +39,11 @@ #define ADXRS450_GET_ST(a) ((a >> 26) & 0x3) +enum { + ID_ADXRS450, + ID_ADXRS453, +}; + /** * struct adxrs450_state - device instance specific data * @us: actual spi_device diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/staging/iio/gyro/adxrs450_core.c index 70fd468b685..15e2496f70c 100644 --- a/drivers/staging/iio/gyro/adxrs450_core.c +++ b/drivers/staging/iio/gyro/adxrs450_core.c @@ -1,5 +1,5 @@ /* - * ADXRS450 Digital Output Gyroscope Driver + * ADXRS450/ADXRS453 Digital Output Gyroscope Driver * * Copyright 2011 Analog Devices Inc. * @@ -243,7 +243,7 @@ static int adxrs450_write_raw(struct iio_dev *indio_dev, { int ret; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: ret = adxrs450_spi_write_reg_16(indio_dev, ADXRS450_DNC1, val & 0x3FF); @@ -263,7 +263,7 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev, { int ret; s16 t; - u16 ut; + switch (mask) { case 0: switch (chan->type) { @@ -276,10 +276,10 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev, break; case IIO_TEMP: ret = adxrs450_spi_read_reg_16(indio_dev, - ADXRS450_TEMP1, &ut); + ADXRS450_TEMP1, &t); if (ret) break; - *val = ut; + *val = (t >> 6) + 225; ret = IIO_VAL_INT; break; default: @@ -287,13 +287,34 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev, break; } break; - case (1 << IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE): + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + *val = 0; + *val2 = 218166; + return IIO_VAL_INT_PLUS_NANO; + case IIO_TEMP: + *val = 200; + *val2 = 0; + return IIO_VAL_INT; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW: ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t); if (ret) break; *val = t; ret = IIO_VAL_INT; break; + case IIO_CHAN_INFO_CALIBBIAS: + ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t); + if (ret) + break; + *val = t; + ret = IIO_VAL_INT; + break; default: ret = -EINVAL; break; @@ -302,18 +323,36 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev, return ret; } -static const struct iio_chan_spec adxrs450_channels[] = { - { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE) - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - } +static const struct iio_chan_spec adxrs450_channels[2][2] = { + [ID_ADXRS450] = { + { + .type = IIO_ANGL_VEL, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + }, { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + } + }, + [ID_ADXRS453] = { + { + .type = IIO_ANGL_VEL, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT, + }, { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + } + }, }; static const struct iio_info adxrs450_info = { @@ -343,7 +382,8 @@ static int __devinit adxrs450_probe(struct spi_device *spi) indio_dev->dev.parent = &spi->dev; indio_dev->info = &adxrs450_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = adxrs450_channels; + indio_dev->channels = + adxrs450_channels[spi_get_device_id(spi)->driver_data]; indio_dev->num_channels = ARRAY_SIZE(adxrs450_channels); indio_dev->name = spi->dev.driver->name; @@ -373,6 +413,13 @@ static int adxrs450_remove(struct spi_device *spi) return 0; } +static const struct spi_device_id adxrs450_id[] = { + {"adxrs450", ID_ADXRS450}, + {"adxrs453", ID_ADXRS453}, + {} +}; +MODULE_DEVICE_TABLE(spi, adxrs450_id); + static struct spi_driver adxrs450_driver = { .driver = { .name = "adxrs450", @@ -380,9 +427,10 @@ static struct spi_driver adxrs450_driver = { }, .probe = adxrs450_probe, .remove = __devexit_p(adxrs450_remove), + .id_table = adxrs450_id, }; module_spi_driver(adxrs450_driver); MODULE_AUTHOR("Cliff Cai <cliff.cai@xxxxxxxxxx>"); -MODULE_DESCRIPTION("Analog Devices ADXRS450 Gyroscope SPI driver"); +MODULE_DESCRIPTION("Analog Devices ADXRS450/ADXRS453 Gyroscope SPI driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h index f3d88cd7e8a..be6ced31f65 100644 --- a/drivers/staging/iio/iio.h +++ b/drivers/staging/iio/iio.h @@ -7,13 +7,12 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ - #ifndef _INDUSTRIAL_IO_H_ #define _INDUSTRIAL_IO_H_ #include <linux/device.h> #include <linux/cdev.h> - +#include "types.h" /* IIO TODO LIST */ /* * Provide means of adjusting timer accuracy. @@ -25,62 +24,64 @@ enum iio_data_type { IIO_PROCESSED, }; -enum iio_chan_type { - /* real channel types */ - IIO_VOLTAGE, - IIO_CURRENT, - IIO_POWER, - IIO_ACCEL, - IIO_ANGL_VEL, - IIO_MAGN, - IIO_LIGHT, - IIO_INTENSITY, - IIO_PROXIMITY, - IIO_TEMP, - IIO_INCLI, - IIO_ROT, - IIO_ANGL, - IIO_TIMESTAMP, - IIO_CAPACITANCE, -}; - -enum iio_modifier { - IIO_NO_MOD, - IIO_MOD_X, - IIO_MOD_Y, - IIO_MOD_Z, - IIO_MOD_X_AND_Y, - IIO_MOD_X_ANX_Z, - IIO_MOD_Y_AND_Z, - IIO_MOD_X_AND_Y_AND_Z, - IIO_MOD_X_OR_Y, - IIO_MOD_X_OR_Z, - IIO_MOD_Y_OR_Z, - IIO_MOD_X_OR_Y_OR_Z, - IIO_MOD_LIGHT_BOTH, - IIO_MOD_LIGHT_IR, -}; - /* Could add the raw attributes as well - allowing buffer only devices */ enum iio_chan_info_enum { - IIO_CHAN_INFO_SCALE_SHARED, - IIO_CHAN_INFO_SCALE_SEPARATE, - IIO_CHAN_INFO_OFFSET_SHARED, - IIO_CHAN_INFO_OFFSET_SEPARATE, - IIO_CHAN_INFO_CALIBSCALE_SHARED, - IIO_CHAN_INFO_CALIBSCALE_SEPARATE, - IIO_CHAN_INFO_CALIBBIAS_SHARED, - IIO_CHAN_INFO_CALIBBIAS_SEPARATE, - IIO_CHAN_INFO_PEAK_SHARED, - IIO_CHAN_INFO_PEAK_SEPARATE, - IIO_CHAN_INFO_PEAK_SCALE_SHARED, - IIO_CHAN_INFO_PEAK_SCALE_SEPARATE, - IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED, - IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE, - IIO_CHAN_INFO_AVERAGE_RAW_SHARED, - IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE, + /* 0 is reserverd for raw attributes */ + IIO_CHAN_INFO_SCALE = 1, + IIO_CHAN_INFO_OFFSET, + IIO_CHAN_INFO_CALIBSCALE, + IIO_CHAN_INFO_CALIBBIAS, + IIO_CHAN_INFO_PEAK, + IIO_CHAN_INFO_PEAK_SCALE, + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW, + IIO_CHAN_INFO_AVERAGE_RAW, + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY, }; +#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2) +#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1) + +#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE) +#define IIO_CHAN_INFO_SCALE_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SCALE) +#define IIO_CHAN_INFO_OFFSET_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_OFFSET) +#define IIO_CHAN_INFO_OFFSET_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_OFFSET) +#define IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBSCALE) +#define IIO_CHAN_INFO_CALIBSCALE_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBSCALE) +#define IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBBIAS) +#define IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBBIAS) +#define IIO_CHAN_INFO_PEAK_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAK) +#define IIO_CHAN_INFO_PEAK_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAK) +#define IIO_CHAN_INFO_PEAKSCALE_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAKSCALE) +#define IIO_CHAN_INFO_PEAKSCALE_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAKSCALE) +#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT( \ + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) +#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT( \ + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) +#define IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_AVERAGE_RAW) +#define IIO_CHAN_INFO_AVERAGE_RAW_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_AVERAGE_RAW) +#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT( \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) +#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT( \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) + enum iio_endian { IIO_CPU, IIO_BE, @@ -109,6 +110,10 @@ enum iio_endian { * @extend_name: Allows labeling of channel attributes with an * informative name. Note this has no effect codes etc, * unlike modifiers. + * @datasheet_name: A name used in in kernel mapping of channels. It should + * corrspond to the first name that the channel is referred + * to by in the datasheet (e.g. IND), or the nearest + * possible compound name (e.g. IND-INC). * @processed_val: Flag to specify the data access attribute should be * *_input rather than *_raw. * @modified: Does a modifier apply to this channel. What these are @@ -137,6 +142,7 @@ struct iio_chan_spec { long info_mask; long event_mask; char *extend_name; + const char *datasheet_name; unsigned processed_val:1; unsigned modified:1; unsigned indexed:1; @@ -261,7 +267,23 @@ struct iio_info { int val); int (*validate_trigger)(struct iio_dev *indio_dev, struct iio_trigger *trig); + int (*update_scan_mode)(struct iio_dev *indio_dev, + const unsigned long *scan_mask); +}; +/** + * struct iio_buffer_setup_ops - buffer setup related callbacks + * @preenable: [DRIVER] function to run prior to marking buffer enabled + * @postenable: [DRIVER] function to run after marking buffer enabled + * @predisable: [DRIVER] function to run prior to marking buffer + * disabled + * @postdisable: [DRIVER] function to run after marking buffer disabled + */ +struct iio_buffer_setup_ops { + int (*preenable)(struct iio_dev *); + int (*postenable)(struct iio_dev *); + int (*predisable)(struct iio_dev *); + int (*postdisable)(struct iio_dev *); }; /** @@ -278,6 +300,7 @@ struct iio_info { * @available_scan_masks: [DRIVER] optional array of allowed bitmasks * @masklength: [INTERN] the length of the mask established from * channels + * @active_scan_mask: [INTERN] union of all scan masks requested by buffers * @trig: [INTERN] current device trigger (buffer modes) * @pollfunc: [DRIVER] function run on trigger being received * @channels: [DRIVER] channel specification structure table @@ -290,6 +313,7 @@ struct iio_info { * @chrdev: [INTERN] associated character device * @groups: [INTERN] attribute groups * @groupcounter: [INTERN] index of next attribute group + * @flags: [INTERN] file ops related flags including busy flag. **/ struct iio_dev { int id; @@ -305,6 +329,7 @@ struct iio_dev { unsigned long *available_scan_masks; unsigned masklength; + unsigned long *active_scan_mask; struct iio_trigger *trig; struct iio_poll_func *pollfunc; @@ -315,13 +340,24 @@ struct iio_dev { struct attribute_group chan_attr_group; const char *name; const struct iio_info *info; + const struct iio_buffer_setup_ops *setup_ops; struct cdev chrdev; #define IIO_MAX_GROUPS 6 const struct attribute_group *groups[IIO_MAX_GROUPS + 1]; int groupcounter; + + unsigned long flags; }; /** + * iio_find_channel_from_si() - get channel from its scan index + * @indio_dev: device + * @si: scan index to match + */ +const struct iio_chan_spec +*iio_find_channel_from_si(struct iio_dev *indio_dev, int si); + +/** * iio_device_register() - register a device with the IIO subsystem * @indio_dev: Device structure filled by the device driver **/ diff --git a/drivers/staging/iio/iio_core.h b/drivers/staging/iio/iio_core.h index 36159e0dbfc..107cfb1cbb0 100644 --- a/drivers/staging/iio/iio_core.h +++ b/drivers/staging/iio/iio_core.h @@ -33,9 +33,6 @@ int __iio_add_chan_devattr(const char *postfix, #ifdef CONFIG_IIO_BUFFER struct poll_table_struct; -int iio_chrdev_buffer_open(struct iio_dev *indio_dev); -void iio_chrdev_buffer_release(struct iio_dev *indio_dev); - unsigned int iio_buffer_poll(struct file *filp, struct poll_table_struct *wait); ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, @@ -47,14 +44,6 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, #else -static inline int iio_chrdev_buffer_open(struct iio_dev *indio_dev) -{ - return -EINVAL; -} - -static inline void iio_chrdev_buffer_release(struct iio_dev *indio_dev) -{} - #define iio_buffer_poll_addr NULL #define iio_buffer_read_first_n_outer_addr NULL diff --git a/drivers/staging/iio/iio_core_trigger.h b/drivers/staging/iio/iio_core_trigger.h index 523c288b776..6f7c56fcbe7 100644 --- a/drivers/staging/iio/iio_core_trigger.h +++ b/drivers/staging/iio/iio_core_trigger.h @@ -13,8 +13,7 @@ * iio_device_register_trigger_consumer() - set up an iio_dev to use triggers * @indio_dev: iio_dev associated with the device that will consume the trigger **/ - -int iio_device_register_trigger_consumer(struct iio_dev *indio_dev); +void iio_device_register_trigger_consumer(struct iio_dev *indio_dev); /** * iio_device_unregister_trigger_consumer() - reverse the registration process diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c index da657d10471..cdbf289bfe2 100644 --- a/drivers/staging/iio/iio_dummy_evgen.c +++ b/drivers/staging/iio/iio_dummy_evgen.c @@ -102,6 +102,10 @@ static int iio_dummy_evgen_create(void) int iio_dummy_evgen_get_irq(void) { int i, ret = 0; + + if (iio_evgen == NULL) + return -ENODEV; + mutex_lock(&iio_evgen->lock); for (i = 0; i < IIO_EVENTGEN_NO; i++) if (iio_evgen->inuse[i] == false) { diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index af0c99236d4..e3a94572bb4 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -21,7 +21,8 @@ #include "iio.h" #include "sysfs.h" -#include "buffer_generic.h" +#include "events.h" +#include "buffer.h" #include "iio_simple_dummy.h" /* @@ -76,13 +77,13 @@ static struct iio_chan_spec iio_dummy_channels[] = { * Offset for userspace to apply prior to scale * when converting to standard units (microvolts) */ - (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | /* * in_voltage0_scale * Multipler for userspace to apply post offset * when converting to standard units (microvolts) */ - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, /* The ordering of elements in the buffer via an enum */ .scan_index = voltage0, .scan_type = { /* Description of storage in buffer */ @@ -117,7 +118,7 @@ static struct iio_chan_spec iio_dummy_channels[] = { * Shared version of scale - shared by differential * input channels of type IIO_VOLTAGE. */ - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = diffvoltage1m2, .scan_type = { /* Description of storage in buffer */ .sign = 's', /* signed */ @@ -134,7 +135,7 @@ static struct iio_chan_spec iio_dummy_channels[] = { .channel = 3, .channel2 = 4, .info_mask = - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = diffvoltage3m4, .scan_type = { .sign = 's', @@ -159,7 +160,7 @@ static struct iio_chan_spec iio_dummy_channels[] = { * seeing the readings. Typically part of hardware * calibration. */ - (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, .scan_index = accelx, .scan_type = { /* Description of storage in buffer */ .sign = 's', /* signed */ @@ -228,29 +229,32 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, break; } break; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: /* only single ended adc -> 7 */ *val = 7; ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): - /* only single ended adc -> 0.001333 */ - *val = 0; - *val2 = 1333; - ret = IIO_VAL_INT_PLUS_MICRO; - break; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): - /* all differential adc channels -> 0.000001344 */ - *val = 0; - *val2 = 1344; - ret = IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SCALE: + switch (chan->differential) { + case 0: + /* only single ended adc -> 0.001333 */ + *val = 0; + *val2 = 1333; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + case 1: + /* all differential adc channels -> 0.000001344 */ + *val = 0; + *val2 = 1344; + ret = IIO_VAL_INT_PLUS_NANO; + } break; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: /* only the acceleration axis - read from cache */ *val = st->accel_calibbias; ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: *val = st->accel_calibscale->val; *val2 = st->accel_calibscale->val2; ret = IIO_VAL_INT_PLUS_MICRO; @@ -295,7 +299,7 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, st->dac_val = val; mutex_unlock(&st->lock); return 0; - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: mutex_lock(&st->lock); /* Compare against table - hard matching here */ for (i = 0; i < ARRAY_SIZE(dummy_scales); i++) @@ -514,7 +518,8 @@ static __init int iio_dummy_init(void) return -EINVAL; } /* Fake a bus */ - iio_dummy_devs = kzalloc(sizeof(*iio_dummy_devs)*instances, GFP_KERNEL); + iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs), + GFP_KERNEL); /* Here we have no actual device so call probe */ for (i = 0; i < instances; i++) { ret = iio_dummy_probe(i); diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index edad0e7b4f4..d6a1c0e82a5 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -57,7 +57,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) if (data == NULL) return -ENOMEM; - if (buffer->scan_count) { + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) { /* * Three common options here: * hardware scans: certain combinations of channels make @@ -75,7 +75,10 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) * in the constant table fakedata. */ int i, j; - for (i = 0, j = 0; i < buffer->scan_count; i++) { + for (i = 0, j = 0; + i < bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); + i++) { j = find_next_bit(buffer->scan_mask, indio_dev->masklength, j + 1); /* random access read form the 'device' */ @@ -142,8 +145,6 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) /* Tell the core how to access the buffer */ buffer->access = &kfifo_access_funcs; - /* Number of bytes per element */ - buffer->bpe = 2; /* Enable timestamps by default */ buffer->scan_timestamp = true; @@ -151,8 +152,7 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) * Tell the core what device type specific functions should * be run on either side of buffer capture enable / disable. */ - buffer->setup_ops = &iio_simple_dummy_buffer_setup_ops; - buffer->owner = THIS_MODULE; + indio_dev->setup_ops = &iio_simple_dummy_buffer_setup_ops; /* * Configure a polling function. diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index 9f00cff7ddd..449c7a5ece8 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -14,6 +14,7 @@ #include "iio.h" #include "sysfs.h" +#include "events.h" #include "iio_simple_dummy.h" /* Evgen 'fakes' interrupt events for this example */ diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 454d131455d..9a2ca55625f 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -21,7 +21,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "../ring_sw.h" #include "ad5933.h" @@ -113,10 +113,10 @@ static struct iio_chan_spec ad5933_channels[] = { 0, AD5933_REG_TEMP_DATA, IIO_ST('s', 14, 16, 0), 0), /* Ring Channels */ IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "real_raw", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, AD5933_REG_REAL_DATA, 0, IIO_ST('s', 16, 16, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "imag_raw", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, AD5933_REG_IMAG_DATA, 1, IIO_ST('s', 16, 16, 0), 0), }; @@ -329,7 +329,7 @@ static ssize_t ad5933_show(struct device *dev, int ret = 0, len = 0; mutex_lock(&indio_dev->mlock); - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD5933_OUT_RANGE: len = sprintf(buf, "%d\n", st->range_avail[(st->ctrl_hb >> 1) & 0x3]); @@ -380,7 +380,7 @@ static ssize_t ad5933_store(struct device *dev, } mutex_lock(&indio_dev->mlock); - switch (this_attr->address) { + switch ((u32) this_attr->address) { case AD5933_OUT_RANGE: for (i = 0; i < 4; i++) if (val == st->range_avail[i]) { @@ -537,14 +537,14 @@ static const struct iio_info ad5933_info = { static int ad5933_ring_preenable(struct iio_dev *indio_dev) { struct ad5933_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; size_t d_size; int ret; - if (!ring->scan_count) + if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; - d_size = ring->scan_count * + d_size = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength) * ad5933_channels[1].scan_type.storagebits / 8; if (indio_dev->buffer->access->set_bytes_per_datum) @@ -611,7 +611,7 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->buffer->access = &ring_sw_access_funcs; /* Ring buffer functions - here trigger setup related */ - indio_dev->buffer->setup_ops = &ad5933_ring_setup_ops; + indio_dev->setup_ops = &ad5933_ring_setup_ops; indio_dev->modes |= INDIO_BUFFER_HARDWARE; @@ -640,12 +640,14 @@ static void ad5933_work(struct work_struct *work) ad5933_i2c_read(st->client, AD5933_REG_STATUS, 1, &status); if (status & AD5933_STAT_DATA_VALID) { + int scan_count = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); ad5933_i2c_read(st->client, - test_bit(1, ring->scan_mask) ? + test_bit(1, indio_dev->active_scan_mask) ? AD5933_REG_REAL_DATA : AD5933_REG_IMAG_DATA, - ring->scan_count * 2, (u8 *)buf); + scan_count * 2, (u8 *)buf); - if (ring->scan_count == 2) { + if (scan_count == 2) { buf[0] = be16_to_cpu(buf[0]); buf[1] = be16_to_cpu(buf[1]); } else { @@ -734,8 +736,8 @@ static int __devinit ad5933_probe(struct i2c_client *client, goto error_unreg_ring; /* enable both REAL and IMAG channels by default */ - iio_scan_mask_set(indio_dev->buffer, 0); - iio_scan_mask_set(indio_dev->buffer, 1); + iio_scan_mask_set(indio_dev, indio_dev->buffer, 0); + iio_scan_mask_set(indio_dev, indio_dev->buffer, 1); ret = ad5933_setup(st); if (ret) diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index f3546ee910a..83d133efaac 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -148,12 +148,14 @@ struct adis16400_chip_info { * @tx: transmit buffer * @rx: receive buffer * @buf_lock: mutex to protect tx and rx + * @filt_int: integer part of requested filter frequency **/ struct adis16400_state { struct spi_device *us; struct iio_trigger *trig; struct mutex buf_lock; struct adis16400_chip_info *variant; + int filt_int; u8 tx[ADIS16400_MAX_TX] ____cacheline_aligned; u8 rx[ADIS16400_MAX_RX] ____cacheline_aligned; diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index efc0f652900..e73ad7818d8 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -28,7 +28,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "adis16400.h" enum adis16400_chip_variant { @@ -161,25 +161,65 @@ error_ret: return ret; } +static int adis16400_get_freq(struct iio_dev *indio_dev) +{ + u16 t; + int sps, ret; + + ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t); + if (ret < 0) + return ret; + sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; + sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; + + return sps; +} + static ssize_t adis16400_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); int ret, len = 0; - u16 t; - int sps; - ret = adis16400_spi_read_reg_16(indio_dev, - ADIS16400_SMPL_PRD, - &t); - if (ret) + ret = adis16400_get_freq(indio_dev); + if (ret < 0) return ret; - sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; - sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; - len = sprintf(buf, "%d SPS\n", sps); + len = sprintf(buf, "%d SPS\n", ret); return len; } +static const unsigned adis16400_3db_divisors[] = { + [0] = 2, /* Special case */ + [1] = 5, + [2] = 10, + [3] = 50, + [4] = 200, +}; + +static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) +{ + int i, ret; + u16 val16; + for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 0; i--) + if (sps/adis16400_3db_divisors[i] > val) + break; + if (i == -1) + ret = -EINVAL; + else { + ret = adis16400_spi_read_reg_16(indio_dev, + ADIS16400_SENS_AVG, + &val16); + if (ret < 0) + goto error_ret; + + ret = adis16400_spi_write_reg_16(indio_dev, + ADIS16400_SENS_AVG, + (val16 & ~0x03) | i); + } +error_ret: + return ret; +} + static ssize_t adis16400_write_frequency(struct device *dev, struct device_attribute *attr, const char *buf, @@ -210,6 +250,7 @@ static ssize_t adis16400_write_frequency(struct device *dev, ADIS16400_SMPL_PRD, t); + /* Also update the filter */ mutex_unlock(&indio_dev->mlock); return ret ? ret : len; @@ -455,22 +496,39 @@ static u8 adis16400_addresses[17][2] = { [incli_y] = { ADIS16300_ROLL_OUT } }; + static int adis16400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int ret; + struct adis16400_state *st = iio_priv(indio_dev); + int ret, sps; switch (mask) { - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: mutex_lock(&indio_dev->mlock); ret = adis16400_spi_write_reg_16(indio_dev, adis16400_addresses[chan->address][1], val); mutex_unlock(&indio_dev->mlock); return ret; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + /* Need to cache values so we can update if the frequency + changes */ + mutex_lock(&indio_dev->mlock); + st->filt_int = val; + /* Work out update to current value */ + sps = adis16400_get_freq(indio_dev); + if (sps < 0) { + mutex_unlock(&indio_dev->mlock); + return sps; + } + + ret = adis16400_set_filter(indio_dev, sps, val); + mutex_unlock(&indio_dev->mlock); + return ret; default: return -EINVAL; } @@ -504,8 +562,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val = val16; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_SCALE_SHARED): - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: *val = 0; @@ -533,7 +590,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + case IIO_CHAN_INFO_CALIBBIAS: mutex_lock(&indio_dev->mlock); ret = adis16400_spi_read_reg_16(indio_dev, adis16400_addresses[chan->address][1], @@ -544,11 +601,29 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, val16 = ((val16 & 0xFFF) << 4) >> 4; *val = val16; return IIO_VAL_INT; - case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + case IIO_CHAN_INFO_OFFSET: /* currently only temperature */ *val = 198; *val2 = 160000; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + mutex_lock(&indio_dev->mlock); + /* Need both the number of taps and the sampling frequency */ + ret = adis16400_spi_read_reg_16(indio_dev, + ADIS16400_SENS_AVG, + &val16); + if (ret < 0) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + ret = adis16400_get_freq(indio_dev); + if (ret > 0) + *val = ret/adis16400_3db_divisors[val16 & 0x03]; + *val2 = 0; + mutex_unlock(&indio_dev->mlock); + if (ret < 0) + return ret; + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } @@ -560,7 +635,7 @@ static struct iio_chan_spec adis16400_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 14, 16, 0) @@ -568,8 +643,9 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0) @@ -577,8 +653,9 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_y, .scan_index = ADIS16400_SCAN_GYRO_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -586,8 +663,9 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_z, .scan_index = ADIS16400_SCAN_GYRO_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -595,8 +673,9 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), @@ -604,8 +683,9 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -613,8 +693,9 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -622,7 +703,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = magn_x, .scan_index = ADIS16400_SCAN_MAGN_X, .scan_type = IIO_ST('s', 14, 16, 0), @@ -630,7 +712,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = magn_y, .scan_index = ADIS16400_SCAN_MAGN_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -638,7 +721,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = magn_z, .scan_index = ADIS16400_SCAN_MAGN_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -646,8 +730,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp, .scan_index = ADIS16400_SCAN_TEMP, .scan_type = IIO_ST('s', 12, 16, 0), @@ -655,7 +739,7 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in1, .scan_index = ADIS16400_SCAN_ADC_0, .scan_type = IIO_ST('s', 12, 16, 0), @@ -669,7 +753,7 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 12, 16, 0) @@ -677,8 +761,9 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0) @@ -686,8 +771,9 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_y, .scan_index = ADIS16400_SCAN_GYRO_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -695,8 +781,9 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_z, .scan_index = ADIS16400_SCAN_GYRO_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -704,8 +791,9 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), @@ -713,8 +801,9 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -722,8 +811,9 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -732,8 +822,9 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 0, .extend_name = "x", - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = temp0, .scan_index = ADIS16350_SCAN_TEMP_X, .scan_type = IIO_ST('s', 12, 16, 0), @@ -742,8 +833,9 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 1, .extend_name = "y", - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = temp1, .scan_index = ADIS16350_SCAN_TEMP_Y, .scan_type = IIO_ST('s', 12, 16, 0), @@ -752,8 +844,8 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 2, .extend_name = "z", - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp2, .scan_index = ADIS16350_SCAN_TEMP_Z, .scan_type = IIO_ST('s', 12, 16, 0), @@ -761,7 +853,7 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in1, .scan_index = ADIS16350_SCAN_ADC_0, .scan_type = IIO_ST('s', 12, 16, 0), @@ -775,7 +867,7 @@ static struct iio_chan_spec adis16300_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 12, 16, 0) @@ -783,8 +875,9 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0), @@ -792,8 +885,9 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), @@ -801,8 +895,9 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -810,8 +905,9 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -819,8 +915,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp, .scan_index = ADIS16400_SCAN_TEMP, .scan_type = IIO_ST('s', 12, 16, 0), @@ -828,7 +924,7 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in1, .scan_index = ADIS16350_SCAN_ADC_0, .scan_type = IIO_ST('s', 12, 16, 0), @@ -836,7 +932,7 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_INCLI, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = incli_x, .scan_index = ADIS16300_SCAN_INCLI_X, .scan_type = IIO_ST('s', 13, 16, 0), @@ -844,7 +940,7 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_INCLI, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = incli_y, .scan_index = ADIS16300_SCAN_INCLI_Y, .scan_type = IIO_ST('s', 13, 16, 0), @@ -857,8 +953,9 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0), @@ -866,8 +963,9 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_y, .scan_index = ADIS16400_SCAN_GYRO_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -875,8 +973,9 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_z, .scan_index = ADIS16400_SCAN_GYRO_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -884,8 +983,9 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), @@ -893,8 +993,9 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), @@ -902,8 +1003,9 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -911,8 +1013,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE) | - (1 << IIO_CHAN_INFO_SCALE_SHARED), + .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = accel_z, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), @@ -1118,6 +1220,7 @@ static const struct spi_device_id adis16400_id[] = { {"adis16405", ADIS16400}, {} }; +MODULE_DEVICE_TABLE(spi, adis16400_id); static struct spi_driver adis16400_driver = { .driver = { diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index fd886bf51a6..ac22de573f3 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -79,14 +79,16 @@ static int adis16350_spi_read_all(struct device *dev, u8 *rx) struct spi_message msg; int i, j = 0, ret; struct spi_transfer *xfers; + int scan_count = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); - xfers = kzalloc(sizeof(*xfers)*indio_dev->buffer->scan_count + 1, + xfers = kzalloc(sizeof(*xfers)*(scan_count + 1), GFP_KERNEL); if (xfers == NULL) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(read_all_tx_array); i++) - if (test_bit(i, indio_dev->buffer->scan_mask)) { + if (test_bit(i, indio_dev->active_scan_mask)) { xfers[j].tx_buf = &read_all_tx_array[i]; xfers[j].bits_per_word = 16; xfers[j].len = 2; @@ -97,7 +99,7 @@ static int adis16350_spi_read_all(struct device *dev, u8 *rx) xfers[j].len = 2; spi_message_init(&msg); - for (j = 0; j < indio_dev->buffer->scan_count + 1; j++) + for (j = 0; j < scan_count + 1; j++) spi_message_add_tail(&xfers[j], &msg); ret = spi_sync(st->us, &msg); @@ -119,26 +121,27 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) s16 *data; size_t datasize = ring->access->get_bytes_per_datum(ring); /* Asumption that long is enough for maximum channels */ - unsigned long mask = *ring->scan_mask; - + unsigned long mask = *indio_dev->active_scan_mask; + int scan_count = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; } - if (ring->scan_count) { + if (scan_count) { if (st->variant->flags & ADIS16400_NO_BURST) { ret = adis16350_spi_read_all(&indio_dev->dev, st->rx); if (ret < 0) goto err; - for (; i < ring->scan_count; i++) + for (; i < scan_count; i++) data[i] = *(s16 *)(st->rx + i*2); } else { ret = adis16400_spi_read_burst(&indio_dev->dev, st->rx); if (ret < 0) goto err; - for (; i < indio_dev->buffer->scan_count; i++) { + for (; i < scan_count; i++) { j = __ffs(mask); mask &= ~(1 << j); data[i] = be16_to_cpup( @@ -186,10 +189,8 @@ int adis16400_configure_ring(struct iio_dev *indio_dev) indio_dev->buffer = ring; /* Effectively select the ring buffer implementation */ ring->access = &ring_sw_access_funcs; - ring->bpe = 2; ring->scan_timestamp = true; - ring->setup_ops = &adis16400_ring_setup_ops; - ring->owner = THIS_MODULE; + indio_dev->setup_ops = &adis16400_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &adis16400_trigger_handler, diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c index 9df0ce81dad..d7b1e9e435a 100644 --- a/drivers/staging/iio/industrialio-buffer.c +++ b/drivers/staging/iio/industrialio-buffer.c @@ -24,7 +24,7 @@ #include "iio.h" #include "iio_core.h" #include "sysfs.h" -#include "buffer_generic.h" +#include "buffer.h" static const char * const iio_endian_prefix[] = { [IIO_BE] = "be", @@ -43,7 +43,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; - if (!rb->access->read_first_n) + if (!rb || !rb->access->read_first_n) return -EINVAL; return rb->access->read_first_n(rb, n, buf); } @@ -64,28 +64,9 @@ unsigned int iio_buffer_poll(struct file *filp, return 0; } -int iio_chrdev_buffer_open(struct iio_dev *indio_dev) +void iio_buffer_init(struct iio_buffer *buffer) { - struct iio_buffer *rb = indio_dev->buffer; - if (!rb) - return -EINVAL; - if (rb->access->mark_in_use) - rb->access->mark_in_use(rb); - return 0; -} - -void iio_chrdev_buffer_release(struct iio_dev *indio_dev) -{ - struct iio_buffer *rb = indio_dev->buffer; - - clear_bit(IIO_BUSY_BIT_POS, &rb->flags); - if (rb->access->unmark_in_use) - rb->access->unmark_in_use(rb); -} - -void iio_buffer_init(struct iio_buffer *buffer, struct iio_dev *indio_dev) -{ - buffer->indio_dev = indio_dev; + INIT_LIST_HEAD(&buffer->demux_list); init_waitqueue_head(&buffer->pollq); } EXPORT_SYMBOL(iio_buffer_init); @@ -126,17 +107,15 @@ static ssize_t iio_scan_el_show(struct device *dev, int ret; struct iio_dev *indio_dev = dev_get_drvdata(dev); - ret = iio_scan_mask_query(indio_dev->buffer, - to_iio_dev_attr(attr)->address); - if (ret < 0) - return ret; + ret = test_bit(to_iio_dev_attr(attr)->address, + indio_dev->buffer->scan_mask); + return sprintf(buf, "%d\n", ret); } static int iio_scan_mask_clear(struct iio_buffer *buffer, int bit) { clear_bit(bit, buffer->scan_mask); - buffer->scan_count--; return 0; } @@ -153,11 +132,11 @@ static ssize_t iio_scan_el_store(struct device *dev, state = !(buf[0] == '0'); mutex_lock(&indio_dev->mlock); - if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { + if (iio_buffer_enabled(indio_dev)) { ret = -EBUSY; goto error_ret; } - ret = iio_scan_mask_query(buffer, this_attr->address); + ret = iio_scan_mask_query(indio_dev, buffer, this_attr->address); if (ret < 0) goto error_ret; if (!state && ret) { @@ -165,7 +144,7 @@ static ssize_t iio_scan_el_store(struct device *dev, if (ret) goto error_ret; } else if (state && !ret) { - ret = iio_scan_mask_set(buffer, this_attr->address); + ret = iio_scan_mask_set(indio_dev, buffer, this_attr->address); if (ret) goto error_ret; } @@ -173,7 +152,7 @@ static ssize_t iio_scan_el_store(struct device *dev, error_ret: mutex_unlock(&indio_dev->mlock); - return ret ? ret : len; + return ret < 0 ? ret : len; } @@ -196,7 +175,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev, state = !(buf[0] == '0'); mutex_lock(&indio_dev->mlock); - if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { + if (iio_buffer_enabled(indio_dev)) { ret = -EBUSY; goto error_ret; } @@ -311,12 +290,14 @@ int iio_buffer_register(struct iio_dev *indio_dev, if (ret < 0) goto error_cleanup_dynamic; attrcount += ret; + if (channels[i].type == IIO_TIMESTAMP) + buffer->scan_index_timestamp = + channels[i].scan_index; } if (indio_dev->masklength && buffer->scan_mask == NULL) { - buffer->scan_mask - = kzalloc(sizeof(*buffer->scan_mask)* - BITS_TO_LONGS(indio_dev->masklength), - GFP_KERNEL); + buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), + sizeof(*buffer->scan_mask), + GFP_KERNEL); if (buffer->scan_mask == NULL) { ret = -ENOMEM; goto error_cleanup_dynamic; @@ -326,10 +307,9 @@ int iio_buffer_register(struct iio_dev *indio_dev, buffer->scan_el_group.name = iio_scan_elements_group_name; - buffer->scan_el_group.attrs - = kzalloc(sizeof(buffer->scan_el_group.attrs[0])* - (attrcount + 1), - GFP_KERNEL); + buffer->scan_el_group.attrs = kcalloc(attrcount + 1, + sizeof(buffer->scan_el_group.attrs[0]), + GFP_KERNEL); if (buffer->scan_el_group.attrs == NULL) { ret = -ENOMEM; goto error_free_scan_mask; @@ -395,31 +375,20 @@ ssize_t iio_buffer_write_length(struct device *dev, if (val == buffer->access->get_length(buffer)) return len; - if (buffer->access->set_length) { - buffer->access->set_length(buffer, val); - if (buffer->access->mark_param_change) - buffer->access->mark_param_change(buffer); + mutex_lock(&indio_dev->mlock); + if (iio_buffer_enabled(indio_dev)) { + ret = -EBUSY; + } else { + if (buffer->access->set_length) + buffer->access->set_length(buffer, val); + ret = 0; } + mutex_unlock(&indio_dev->mlock); - return len; + return ret ? ret : len; } EXPORT_SYMBOL(iio_buffer_write_length); -ssize_t iio_buffer_read_bytes_per_datum(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct iio_buffer *buffer = indio_dev->buffer; - - if (buffer->access->get_bytes_per_datum) - return sprintf(buf, "%d\n", - buffer->access->get_bytes_per_datum(buffer)); - - return 0; -} -EXPORT_SYMBOL(iio_buffer_read_bytes_per_datum); - ssize_t iio_buffer_store_enable(struct device *dev, struct device_attribute *attr, const char *buf, @@ -434,14 +403,14 @@ ssize_t iio_buffer_store_enable(struct device *dev, mutex_lock(&indio_dev->mlock); previous_mode = indio_dev->currentmode; requested_state = !(buf[0] == '0'); - current_state = !!(previous_mode & INDIO_ALL_BUFFER_MODES); + current_state = iio_buffer_enabled(indio_dev); if (current_state == requested_state) { printk(KERN_INFO "iio-buffer, current state requested again\n"); goto done; } if (requested_state) { - if (buffer->setup_ops->preenable) { - ret = buffer->setup_ops->preenable(indio_dev); + if (indio_dev->setup_ops->preenable) { + ret = indio_dev->setup_ops->preenable(indio_dev); if (ret) { printk(KERN_ERR "Buffer not started:" @@ -458,16 +427,12 @@ ssize_t iio_buffer_store_enable(struct device *dev, goto error_ret; } } - if (buffer->access->mark_in_use) - buffer->access->mark_in_use(buffer); /* Definitely possible for devices to support both of these.*/ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) { if (!indio_dev->trig) { printk(KERN_INFO "Buffer not started: no trigger\n"); ret = -EINVAL; - if (buffer->access->unmark_in_use) - buffer->access->unmark_in_use(buffer); goto error_ret; } indio_dev->currentmode = INDIO_BUFFER_TRIGGERED; @@ -478,32 +443,28 @@ ssize_t iio_buffer_store_enable(struct device *dev, goto error_ret; } - if (buffer->setup_ops->postenable) { - ret = buffer->setup_ops->postenable(indio_dev); + if (indio_dev->setup_ops->postenable) { + ret = indio_dev->setup_ops->postenable(indio_dev); if (ret) { printk(KERN_INFO "Buffer not started:" "postenable failed\n"); - if (buffer->access->unmark_in_use) - buffer->access->unmark_in_use(buffer); indio_dev->currentmode = previous_mode; - if (buffer->setup_ops->postdisable) - buffer->setup_ops-> + if (indio_dev->setup_ops->postdisable) + indio_dev->setup_ops-> postdisable(indio_dev); goto error_ret; } } } else { - if (buffer->setup_ops->predisable) { - ret = buffer->setup_ops->predisable(indio_dev); + if (indio_dev->setup_ops->predisable) { + ret = indio_dev->setup_ops->predisable(indio_dev); if (ret) goto error_ret; } - if (buffer->access->unmark_in_use) - buffer->access->unmark_in_use(buffer); indio_dev->currentmode = INDIO_DIRECT_MODE; - if (buffer->setup_ops->postdisable) { - ret = buffer->setup_ops->postdisable(indio_dev); + if (indio_dev->setup_ops->postdisable) { + ret = indio_dev->setup_ops->postdisable(indio_dev); if (ret) goto error_ret; } @@ -523,37 +484,10 @@ ssize_t iio_buffer_show_enable(struct device *dev, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", !!(indio_dev->currentmode - & INDIO_ALL_BUFFER_MODES)); + return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev)); } EXPORT_SYMBOL(iio_buffer_show_enable); -int iio_sw_buffer_preenable(struct iio_dev *indio_dev) -{ - struct iio_buffer *buffer = indio_dev->buffer; - size_t size; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - /* Check if there are any scan elements enabled, if not fail*/ - if (!(buffer->scan_count || buffer->scan_timestamp)) - return -EINVAL; - if (buffer->scan_timestamp) - if (buffer->scan_count) - /* Timestamp (aligned to s64) and data */ - size = (((buffer->scan_count * buffer->bpe) - + sizeof(s64) - 1) - & ~(sizeof(s64) - 1)) - + sizeof(s64); - else /* Timestamp only */ - size = sizeof(s64); - else /* Data only */ - size = buffer->scan_count * buffer->bpe; - buffer->access->set_bytes_per_datum(buffer, size); - - return 0; -} -EXPORT_SYMBOL(iio_sw_buffer_preenable); - - /* note NULL used as error indicator as it doesn't make sense. */ static unsigned long *iio_scan_mask_match(unsigned long *av_masks, unsigned int masklength, @@ -569,14 +503,57 @@ static unsigned long *iio_scan_mask_match(unsigned long *av_masks, return NULL; } +int iio_sw_buffer_preenable(struct iio_dev *indio_dev) +{ + struct iio_buffer *buffer = indio_dev->buffer; + const struct iio_chan_spec *ch; + unsigned bytes = 0; + int length, i; + dev_dbg(&indio_dev->dev, "%s\n", __func__); + + /* How much space will the demuxed element take? */ + for_each_set_bit(i, buffer->scan_mask, + indio_dev->masklength) { + ch = iio_find_channel_from_si(indio_dev, i); + length = ch->scan_type.storagebits/8; + bytes = ALIGN(bytes, length); + bytes += length; + } + if (buffer->scan_timestamp) { + ch = iio_find_channel_from_si(indio_dev, + buffer->scan_index_timestamp); + length = ch->scan_type.storagebits/8; + bytes = ALIGN(bytes, length); + bytes += length; + } + buffer->access->set_bytes_per_datum(buffer, bytes); + + /* What scan mask do we actually have ?*/ + if (indio_dev->available_scan_masks) + indio_dev->active_scan_mask = + iio_scan_mask_match(indio_dev->available_scan_masks, + indio_dev->masklength, + buffer->scan_mask); + else + indio_dev->active_scan_mask = buffer->scan_mask; + iio_update_demux(indio_dev); + + if (indio_dev->info->update_scan_mode) + return indio_dev->info + ->update_scan_mode(indio_dev, + indio_dev->active_scan_mask); + return 0; +} +EXPORT_SYMBOL(iio_sw_buffer_preenable); + /** * iio_scan_mask_set() - set particular bit in the scan mask * @buffer: the buffer whose scan mask we are interested in * @bit: the bit to be set. **/ -int iio_scan_mask_set(struct iio_buffer *buffer, int bit) +int iio_scan_mask_set(struct iio_dev *indio_dev, + struct iio_buffer *buffer, int bit) { - struct iio_dev *indio_dev = buffer->indio_dev; unsigned long *mask; unsigned long *trialmask; @@ -604,7 +581,6 @@ int iio_scan_mask_set(struct iio_buffer *buffer, int bit) } } bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength); - buffer->scan_count++; kfree(trialmask); @@ -612,25 +588,147 @@ int iio_scan_mask_set(struct iio_buffer *buffer, int bit) }; EXPORT_SYMBOL_GPL(iio_scan_mask_set); -int iio_scan_mask_query(struct iio_buffer *buffer, int bit) +int iio_scan_mask_query(struct iio_dev *indio_dev, + struct iio_buffer *buffer, int bit) { - struct iio_dev *indio_dev = buffer->indio_dev; - long *mask; - if (bit > indio_dev->masklength) return -EINVAL; if (!buffer->scan_mask) return 0; - if (indio_dev->available_scan_masks) - mask = iio_scan_mask_match(indio_dev->available_scan_masks, - indio_dev->masklength, - buffer->scan_mask); - else - mask = buffer->scan_mask; - if (!mask) - return 0; - return test_bit(bit, mask); + return test_bit(bit, buffer->scan_mask); }; EXPORT_SYMBOL_GPL(iio_scan_mask_query); + +/** + * struct iio_demux_table() - table describing demux memcpy ops + * @from: index to copy from + * @to: index to copy to + * @length: how many bytes to copy + * @l: list head used for management + */ +struct iio_demux_table { + unsigned from; + unsigned to; + unsigned length; + struct list_head l; +}; + +static unsigned char *iio_demux(struct iio_buffer *buffer, + unsigned char *datain) +{ + struct iio_demux_table *t; + + if (list_empty(&buffer->demux_list)) + return datain; + list_for_each_entry(t, &buffer->demux_list, l) + memcpy(buffer->demux_bounce + t->to, + datain + t->from, t->length); + + return buffer->demux_bounce; +} + +int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data, + s64 timestamp) +{ + unsigned char *dataout = iio_demux(buffer, data); + + return buffer->access->store_to(buffer, dataout, timestamp); +} +EXPORT_SYMBOL_GPL(iio_push_to_buffer); + +int iio_update_demux(struct iio_dev *indio_dev) +{ + const struct iio_chan_spec *ch; + struct iio_buffer *buffer = indio_dev->buffer; + int ret, in_ind = -1, out_ind, length; + unsigned in_loc = 0, out_loc = 0; + struct iio_demux_table *p, *q; + + /* Clear out any old demux */ + list_for_each_entry_safe(p, q, &buffer->demux_list, l) { + list_del(&p->l); + kfree(p); + } + kfree(buffer->demux_bounce); + buffer->demux_bounce = NULL; + + /* First work out which scan mode we will actually have */ + if (bitmap_equal(indio_dev->active_scan_mask, + buffer->scan_mask, + indio_dev->masklength)) + return 0; + + /* Now we have the two masks, work from least sig and build up sizes */ + for_each_set_bit(out_ind, + indio_dev->active_scan_mask, + indio_dev->masklength) { + in_ind = find_next_bit(indio_dev->active_scan_mask, + indio_dev->masklength, + in_ind + 1); + while (in_ind != out_ind) { + in_ind = find_next_bit(indio_dev->active_scan_mask, + indio_dev->masklength, + in_ind + 1); + ch = iio_find_channel_from_si(indio_dev, in_ind); + length = ch->scan_type.storagebits/8; + /* Make sure we are aligned */ + in_loc += length; + if (in_loc % length) + in_loc += length - in_loc % length; + } + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + ret = -ENOMEM; + goto error_clear_mux_table; + } + ch = iio_find_channel_from_si(indio_dev, in_ind); + length = ch->scan_type.storagebits/8; + if (out_loc % length) + out_loc += length - out_loc % length; + if (in_loc % length) + in_loc += length - in_loc % length; + p->from = in_loc; + p->to = out_loc; + p->length = length; + list_add_tail(&p->l, &buffer->demux_list); + out_loc += length; + in_loc += length; + } + /* Relies on scan_timestamp being last */ + if (buffer->scan_timestamp) { + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + ret = -ENOMEM; + goto error_clear_mux_table; + } + ch = iio_find_channel_from_si(indio_dev, + buffer->scan_index_timestamp); + length = ch->scan_type.storagebits/8; + if (out_loc % length) + out_loc += length - out_loc % length; + if (in_loc % length) + in_loc += length - in_loc % length; + p->from = in_loc; + p->to = out_loc; + p->length = length; + list_add_tail(&p->l, &buffer->demux_list); + out_loc += length; + in_loc += length; + } + buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL); + if (buffer->demux_bounce == NULL) { + ret = -ENOMEM; + goto error_clear_mux_table; + } + return 0; + +error_clear_mux_table: + list_for_each_entry_safe(p, q, &buffer->demux_list, l) { + list_del(&p->l); + kfree(p); + } + return ret; +} +EXPORT_SYMBOL_GPL(iio_update_demux); diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index aec9311b108..19f897f3c85 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -25,8 +25,8 @@ #include "iio.h" #include "iio_core.h" #include "iio_core_trigger.h" -#include "chrdev.h" #include "sysfs.h" +#include "events.h" /* IDA to assign each registered device a unique id*/ static DEFINE_IDA(iio_ida); @@ -77,17 +77,29 @@ static const char * const iio_modifier_names[] = { /* relies on pairs of these shared then separate */ static const char * const iio_chan_info_postfix[] = { - [IIO_CHAN_INFO_SCALE_SHARED/2] = "scale", - [IIO_CHAN_INFO_OFFSET_SHARED/2] = "offset", - [IIO_CHAN_INFO_CALIBSCALE_SHARED/2] = "calibscale", - [IIO_CHAN_INFO_CALIBBIAS_SHARED/2] = "calibbias", - [IIO_CHAN_INFO_PEAK_SHARED/2] = "peak_raw", - [IIO_CHAN_INFO_PEAK_SCALE_SHARED/2] = "peak_scale", - [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED/2] - = "quadrature_correction_raw", - [IIO_CHAN_INFO_AVERAGE_RAW_SHARED/2] = "mean_raw", + [IIO_CHAN_INFO_SCALE] = "scale", + [IIO_CHAN_INFO_OFFSET] = "offset", + [IIO_CHAN_INFO_CALIBSCALE] = "calibscale", + [IIO_CHAN_INFO_CALIBBIAS] = "calibbias", + [IIO_CHAN_INFO_PEAK] = "peak_raw", + [IIO_CHAN_INFO_PEAK_SCALE] = "peak_scale", + [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW] = "quadrature_correction_raw", + [IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw", + [IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY] + = "filter_low_pass_3db_frequency", }; +const struct iio_chan_spec +*iio_find_channel_from_si(struct iio_dev *indio_dev, int si) +{ + int i; + + for (i = 0; i < indio_dev->num_channels; i++) + if (indio_dev->channels[i].scan_index == si) + return &indio_dev->channels[i]; + return NULL; +} + /** * struct iio_detected_event_list - list element for events that have occurred * @list: linked list header @@ -169,8 +181,11 @@ static ssize_t iio_event_chrdev_read(struct file *filep, { struct iio_event_interface *ev_int = filep->private_data; struct iio_detected_event_list *el; + size_t len = sizeof(el->ev); int ret; - size_t len; + + if (count < len) + return -EINVAL; mutex_lock(&ev_int->event_list_lock); if (list_empty(&ev_int->det_events)) { @@ -192,7 +207,6 @@ static ssize_t iio_event_chrdev_read(struct file *filep, el = list_first_entry(&ev_int->det_events, struct iio_detected_event_list, list); - len = sizeof el->ev; if (copy_to_user(buf, &(el->ev), len)) { ret = -EFAULT; goto error_mutex_unlock; @@ -415,7 +429,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, sysfs_attr_init(&dev_attr->attr); /* Build up postfix of <extend_name>_<modifier>_postfix */ - if (chan->modified) { + if (chan->modified && !generic) { if (chan->extend_name) full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_modifier_names[chan @@ -600,7 +614,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, chan, &iio_read_channel_info, &iio_write_channel_info, - (1 << i), + i/2, !(i%2), &indio_dev->dev, &indio_dev->channel_attr_list); @@ -665,10 +679,9 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) if (indio_dev->name) attrcount++; - indio_dev->chan_attr_group.attrs - = kzalloc(sizeof(indio_dev->chan_attr_group.attrs[0])* - (attrcount + 1), - GFP_KERNEL); + indio_dev->chan_attr_group.attrs = kcalloc(attrcount + 1, + sizeof(indio_dev->chan_attr_group.attrs[0]), + GFP_KERNEL); if (indio_dev->chan_attr_group.attrs == NULL) { ret = -ENOMEM; goto error_clear_attrs; @@ -788,6 +801,9 @@ static ssize_t iio_ev_value_store(struct device *dev, unsigned long val; int ret; + if (!indio_dev->info->write_event_value) + return -EINVAL; + ret = strict_strtoul(buf, 10, &val); if (ret) return ret; @@ -958,10 +974,9 @@ static int iio_device_register_eventset(struct iio_dev *indio_dev) } indio_dev->event_interface->group.name = iio_event_group_name; - indio_dev->event_interface->group.attrs = - kzalloc(sizeof(indio_dev->event_interface->group.attrs[0]) - *(attrcount + 1), - GFP_KERNEL); + indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1, + sizeof(indio_dev->event_interface->group.attrs[0]), + GFP_KERNEL); if (indio_dev->event_interface->group.attrs == NULL) { ret = -ENOMEM; goto error_free_setup_event_lines; @@ -1068,9 +1083,13 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) { struct iio_dev *indio_dev = container_of(inode->i_cdev, struct iio_dev, chrdev); + + if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags)) + return -EBUSY; + filp->private_data = indio_dev; - return iio_chrdev_buffer_open(indio_dev); + return 0; } /** @@ -1078,8 +1097,9 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) **/ static int iio_chrdev_release(struct inode *inode, struct file *filp) { - iio_chrdev_buffer_release(container_of(inode->i_cdev, - struct iio_dev, chrdev)); + struct iio_dev *indio_dev = container_of(inode->i_cdev, + struct iio_dev, chrdev); + clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags); return 0; } diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c index 68a4d4e8c63..47ecadd4818 100644 --- a/drivers/staging/iio/industrialio-trigger.c +++ b/drivers/staging/iio/industrialio-trigger.c @@ -159,13 +159,12 @@ EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll); void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time) { int i; - if (!trig->use_count) { + if (!trig->use_count) for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) if (trig->subirqs[i].enabled) { trig->use_count++; handle_nested_irq(trig->subirq_base + i); } - } } EXPORT_SYMBOL(iio_trigger_poll_chained); @@ -173,10 +172,9 @@ void iio_trigger_notify_done(struct iio_trigger *trig) { trig->use_count--; if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable) - if (trig->ops->try_reenable(trig)) { + if (trig->ops->try_reenable(trig)) /* Missed and interrupt so launch new poll now */ iio_trigger_poll(trig, 0); - } } EXPORT_SYMBOL(iio_trigger_notify_done); @@ -222,8 +220,16 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, ret = request_threaded_irq(pf->irq, pf->h, pf->thread, pf->type, pf->name, pf); - if (trig->ops && trig->ops->set_trigger_state && notinuse) + if (ret < 0) { + module_put(pf->indio_dev->info->driver_module); + return ret; + } + + if (trig->ops && trig->ops->set_trigger_state && notinuse) { ret = trig->ops->set_trigger_state(trig, true); + if (ret < 0) + module_put(pf->indio_dev->info->driver_module); + } return ret; } @@ -336,6 +342,8 @@ static ssize_t iio_trigger_write_current(struct device *dev, mutex_unlock(&indio_dev->mlock); trig = iio_trigger_find_by_name(buf, len); + if (oldtrig == trig) + return len; if (trig && indio_dev->info->validate_trigger) { ret = indio_dev->info->validate_trigger(indio_dev, trig); @@ -473,12 +481,10 @@ void iio_free_trigger(struct iio_trigger *trig) } EXPORT_SYMBOL(iio_free_trigger); -int iio_device_register_trigger_consumer(struct iio_dev *indio_dev) +void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { indio_dev->groups[indio_dev->groupcounter++] = &iio_trigger_consumer_attr_group; - - return 0; } void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev) @@ -490,18 +496,14 @@ void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev) int iio_triggered_buffer_postenable(struct iio_dev *indio_dev) { - return indio_dev->trig - ? iio_trigger_attach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; + return iio_trigger_attach_poll_func(indio_dev->trig, + indio_dev->pollfunc); } EXPORT_SYMBOL(iio_triggered_buffer_postenable); int iio_triggered_buffer_predisable(struct iio_dev *indio_dev) { - return indio_dev->trig - ? iio_trigger_dettach_poll_func(indio_dev->trig, - indio_dev->pollfunc) - : 0; + return iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc); } EXPORT_SYMBOL(iio_triggered_buffer_predisable); diff --git a/drivers/staging/iio/kfifo_buf.c b/drivers/staging/iio/kfifo_buf.c index e8c234bb18f..e1e9c06cde4 100644 --- a/drivers/staging/iio/kfifo_buf.c +++ b/drivers/staging/iio/kfifo_buf.c @@ -11,9 +11,7 @@ struct iio_kfifo { struct iio_buffer buffer; struct kfifo kf; - int use_count; int update_needed; - struct mutex use_lock; }; #define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer) @@ -33,54 +31,25 @@ static int iio_request_update_kfifo(struct iio_buffer *r) int ret = 0; struct iio_kfifo *buf = iio_to_kfifo(r); - mutex_lock(&buf->use_lock); if (!buf->update_needed) goto error_ret; - if (buf->use_count) { - ret = -EAGAIN; - goto error_ret; - } kfifo_free(&buf->kf); ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum, buf->buffer.length); error_ret: - mutex_unlock(&buf->use_lock); return ret; } -static void iio_mark_kfifo_in_use(struct iio_buffer *r) -{ - struct iio_kfifo *buf = iio_to_kfifo(r); - mutex_lock(&buf->use_lock); - buf->use_count++; - mutex_unlock(&buf->use_lock); -} - -static void iio_unmark_kfifo_in_use(struct iio_buffer *r) -{ - struct iio_kfifo *buf = iio_to_kfifo(r); - mutex_lock(&buf->use_lock); - buf->use_count--; - mutex_unlock(&buf->use_lock); -} - static int iio_get_length_kfifo(struct iio_buffer *r) { return r->length; } -static inline void __iio_init_kfifo(struct iio_kfifo *kf) -{ - mutex_init(&kf->use_lock); -} - static IIO_BUFFER_ENABLE_ATTR; -static IIO_BUFFER_BYTES_PER_DATUM_ATTR; static IIO_BUFFER_LENGTH_ATTR; static struct attribute *iio_kfifo_attributes[] = { &dev_attr_length.attr, - &dev_attr_bytes_per_datum.attr, &dev_attr_enable.attr, NULL, }; @@ -98,9 +67,8 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev) if (!kf) return NULL; kf->update_needed = true; - iio_buffer_init(&kf->buffer, indio_dev); + iio_buffer_init(&kf->buffer); kf->buffer.attrs = &iio_kfifo_attribute_group; - __iio_init_kfifo(kf); return &kf->buffer; } @@ -111,20 +79,19 @@ static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r) return r->bytes_per_datum; } -static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) +static int iio_mark_update_needed_kfifo(struct iio_buffer *r) { - if (r->bytes_per_datum != bpd) { - r->bytes_per_datum = bpd; - if (r->access->mark_param_change) - r->access->mark_param_change(r); - } + struct iio_kfifo *kf = iio_to_kfifo(r); + kf->update_needed = true; return 0; } -static int iio_mark_update_needed_kfifo(struct iio_buffer *r) +static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) { - struct iio_kfifo *kf = iio_to_kfifo(r); - kf->update_needed = true; + if (r->bytes_per_datum != bpd) { + r->bytes_per_datum = bpd; + iio_mark_update_needed_kfifo(r); + } return 0; } @@ -132,8 +99,7 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length) { if (r->length != length) { r->length = length; - if (r->access->mark_param_change) - r->access->mark_param_change(r); + iio_mark_update_needed_kfifo(r); } return 0; } @@ -150,16 +116,9 @@ static int iio_store_to_kfifo(struct iio_buffer *r, { int ret; struct iio_kfifo *kf = iio_to_kfifo(r); - u8 *datal = kmalloc(r->bytes_per_datum, GFP_KERNEL); - memcpy(datal, data, r->bytes_per_datum - sizeof(timestamp)); - memcpy(datal + r->bytes_per_datum - sizeof(timestamp), - ×tamp, sizeof(timestamp)); ret = kfifo_in(&kf->kf, data, r->bytes_per_datum); - if (ret != r->bytes_per_datum) { - kfree(datal); + if (ret != r->bytes_per_datum) return -EBUSY; - } - kfree(datal); return 0; } @@ -169,17 +128,18 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, int ret, copied; struct iio_kfifo *kf = iio_to_kfifo(r); - ret = kfifo_to_user(&kf->kf, buf, r->bytes_per_datum*n, &copied); + if (n < r->bytes_per_datum) + return -EINVAL; + + n = rounddown(n, r->bytes_per_datum); + ret = kfifo_to_user(&kf->kf, buf, n, &copied); return copied; } const struct iio_buffer_access_funcs kfifo_access_funcs = { - .mark_in_use = &iio_mark_kfifo_in_use, - .unmark_in_use = &iio_unmark_kfifo_in_use, .store_to = &iio_store_to_kfifo, .read_first_n = &iio_read_first_n_kfifo, - .mark_param_change = &iio_mark_update_needed_kfifo, .request_update = &iio_request_update_kfifo, .get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo, .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo, diff --git a/drivers/staging/iio/kfifo_buf.h b/drivers/staging/iio/kfifo_buf.h index a15598bb9fd..cc2bd9a1ccf 100644 --- a/drivers/staging/iio/kfifo_buf.h +++ b/drivers/staging/iio/kfifo_buf.h @@ -1,7 +1,7 @@ #include <linux/kfifo.h> #include "iio.h" -#include "buffer_generic.h" +#include "buffer.h" extern const struct iio_buffer_access_funcs kfifo_access_funcs; diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 47638362224..849d6a564af 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -362,8 +362,7 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, int ret = -EINVAL; mutex_lock(&chip->lock); - if (mask == (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) && - chan->type == IIO_LIGHT) { + if (mask == IIO_CHAN_INFO_CALIBSCALE && chan->type == IIO_LIGHT) { chip->lux_scale = val; ret = 0; } @@ -402,7 +401,7 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, if (!ret) ret = IIO_VAL_INT; break; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: if (chan->type == IIO_LIGHT) { *val = chip->lux_scale; ret = IIO_VAL_INT; @@ -421,7 +420,7 @@ static const struct iio_chan_spec isl29018_channels[] = { .indexed = 1, .channel = 0, .processed_val = IIO_PROCESSED, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, }, { .type = IIO_INTENSITY, .modified = 1, diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 1942db13b03..ffca85e81ef 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -37,6 +37,7 @@ #include "../iio.h" #include "../sysfs.h" +#include "../events.h" #include "tsl2563.h" /* Use this many bits for fraction part. */ @@ -226,6 +227,8 @@ static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id) if (ret < 0) return ret; + *id = ret; + return 0; } @@ -510,7 +513,7 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev, } break; - case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + case IIO_CHAN_INFO_CALIBSCALE: if (chan->channel == 0) *val = calib_to_sysfs(chip->calib0); else @@ -536,7 +539,7 @@ static const struct iio_chan_spec tsl2563_channels[] = { .type = IIO_INTENSITY, .modified = 1, .channel2 = IIO_MOD_LIGHT_BOTH, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE), + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, .event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | IIO_EV_BIT(IIO_EV_TYPE_THRESH, @@ -544,8 +547,8 @@ static const struct iio_chan_spec tsl2563_channels[] = { }, { .type = IIO_INTENSITY, .modified = 1, - .channel2 = IIO_MOD_LIGHT_BOTH, - .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE), + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, } }; diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index 3836f73a529..5b6455a238d 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -194,6 +194,7 @@ static int taos_get_lux(struct iio_dev *indio_dev) { u16 ch0, ch1; /* separated ch0/ch1 data from device */ u32 lux; /* raw lux calculated from device data */ + u64 lux64; u32 ratio; u8 buf[5]; struct taos_lux *p; @@ -297,9 +298,19 @@ static int taos_get_lux(struct iio_dev *indio_dev) lux = (lux + (chip->als_time_scale >> 1)) / chip->als_time_scale; - /* adjust for active gain scale */ - lux >>= 13; /* tables have factor of 8192 builtin for accuracy */ - lux = (lux * chip->taos_settings.als_gain_trim + 500) / 1000; + /* Adjust for active gain scale. + * The taos_device_lux tables above have a factor of 8192 built in, + * so we need to shift right. + * User-specified gain provides a multiplier. + * Apply user-specified gain before shifting right to retain precision. + * Use 64 bits to avoid overflow on multiplication. + * Then go back to 32 bits before division to avoid using div_u64(). + */ + lux64 = lux; + lux64 = lux64 * chip->taos_settings.als_gain_trim; + lux64 >>= 13; + lux = lux64; + lux = (lux + 500) / 1000; if (lux > TSL258X_LUX_CALC_OVER_FLOW) { /* check for overflow */ return_max: lux = TSL258X_LUX_CALC_OVER_FLOW; diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c index db31d6d0e5b..3158f12cb05 100644 --- a/drivers/staging/iio/magnetometer/ak8975.c +++ b/drivers/staging/iio/magnetometer/ak8975.c @@ -431,7 +431,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev, switch (mask) { case 0: return ak8975_read_axis(indio_dev, chan->address, val); - case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + case IIO_CHAN_INFO_SCALE: *val = data->raw_to_gauss[chan->address]; return IIO_VAL_INT; } @@ -443,7 +443,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev, .type = IIO_MAGN, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = index, \ } diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index 7bb1bc60513..f2e85a9cf19 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -463,7 +463,7 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev, return hmc5843_read_measurement(indio_dev, chan->address, val); - case (1 << IIO_CHAN_INFO_SCALE_SHARED): + case IIO_CHAN_INFO_SCALE: *val = 0; *val2 = hmc5843_regval_to_nanoscale[data->range]; return IIO_VAL_INT_PLUS_NANO; @@ -476,7 +476,7 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev, .type = IIO_MAGN, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = add \ } @@ -605,6 +605,7 @@ static const struct i2c_device_id hmc5843_id[] = { { "hmc5843", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, hmc5843_id); static struct i2c_driver hmc5843_driver = { .driver = { diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 4c7b0cbf49f..57baac6c0d4 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -582,3 +582,4 @@ module_spi_driver(ade7753_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADE7753/6 Single-Phase Multifunction Meter"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ade7753"); diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index 15c98cde76d..8d81c92007e 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -605,3 +605,4 @@ module_spi_driver(ade7754_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad7754"); diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 39338bcb187..dcb20294dfe 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -20,7 +20,7 @@ #include "../iio.h" #include "../sysfs.h" -#include "../buffer_generic.h" +#include "../buffer.h" #include "meter.h" #include "ade7758.h" @@ -663,63 +663,63 @@ static const struct attribute_group ade7758_attribute_group = { static struct iio_chan_spec ade7758_channels[] = { IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE), 0, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT), 1, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR), 2, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR), 3, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR), 4, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE), 5, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT), 6, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR), 7, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR), 8, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR), 9, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE), 10, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT), 11, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR), 12, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR), 13, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), + IIO_CHAN_INFO_SCALE_SHARED_BIT, AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR), 14, IIO_ST('s', 24, 32, 0), 0), IIO_CHAN_SOFT_TIMESTAMP(15), @@ -746,12 +746,12 @@ static int __devinit ade7758_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); /* Allocate the comms buffers */ - st->rx = kzalloc(sizeof(*st->rx)*ADE7758_MAX_RX, GFP_KERNEL); + st->rx = kcalloc(ADE7758_MAX_RX, sizeof(*st->rx), GFP_KERNEL); if (st->rx == NULL) { ret = -ENOMEM; goto error_free_dev; } - st->tx = kzalloc(sizeof(*st->tx)*ADE7758_MAX_TX, GFP_KERNEL); + st->tx = kcalloc(ADE7758_MAX_TX, sizeof(*st->tx), GFP_KERNEL); if (st->tx == NULL) { ret = -ENOMEM; goto error_free_rx; @@ -843,6 +843,7 @@ static const struct spi_device_id ade7758_id[] = { {"ade7758", 0}, {} }; +MODULE_DEVICE_TABLE(spi, ade7758_id); static struct spi_driver ade7758_driver = { .driver = { diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 00fa2ac5c45..f29f2b278fe 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -67,7 +67,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) s64 dat64[2]; u32 *dat32 = (u32 *)dat64; - if (ring->scan_count) + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) if (ade7758_spi_read_burst(&indio_dev->dev) >= 0) *dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF; @@ -96,10 +96,11 @@ static int ade7758_ring_preenable(struct iio_dev *indio_dev) size_t d_size; unsigned channel; - if (!ring->scan_count) + if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; - channel = find_first_bit(ring->scan_mask, indio_dev->masklength); + channel = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); d_size = st->ade7758_ring_channels[channel].scan_type.storagebits / 8; @@ -145,8 +146,7 @@ int ade7758_configure_ring(struct iio_dev *indio_dev) /* Effectively select the ring buffer implementation */ indio_dev->buffer->access = &ring_sw_access_funcs; - indio_dev->buffer->setup_ops = &ade7758_ring_setup_ops; - indio_dev->buffer->owner = THIS_MODULE; + indio_dev->setup_ops = &ade7758_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, &ade7758_trigger_handler, diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index cfa2a5eff12..0beab478dcd 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -526,3 +526,4 @@ module_spi_driver(ade7759_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADE7759 Active Energy Metering IC Driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad7759"); diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index c485a79aeec..81121862c1b 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -343,6 +343,7 @@ static const struct spi_device_id ade7854_id[] = { { "ade7878", 0 }, { } }; +MODULE_DEVICE_TABLE(spi, ade7854_id); static struct spi_driver ade7854_driver = { .driver = { diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c index 1c6a02bfd45..d8ce854c189 100644 --- a/drivers/staging/iio/resolver/ad2s1200.c +++ b/drivers/staging/iio/resolver/ad2s1200.c @@ -160,6 +160,7 @@ static const struct spi_device_id ad2s1200_id[] = { { "ad2s1205" }, {} }; +MODULE_DEVICE_TABLE(spi, ad2s1200_id); static struct spi_driver ad2s1200_driver = { .driver = { diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index ff1b3316d01..c439fcf72be 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -749,6 +749,7 @@ static const struct spi_device_id ad2s1210_id[] = { { "ad2s1210" }, {} }; +MODULE_DEVICE_TABLE(spi, ad2s1210_id); static struct spi_driver ad2s1210_driver = { .driver = { diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c index 6d0794389e7..2a86f582ddf 100644 --- a/drivers/staging/iio/resolver/ad2s90.c +++ b/drivers/staging/iio/resolver/ad2s90.c @@ -109,6 +109,7 @@ static const struct spi_device_id ad2s90_id[] = { { "ad2s90" }, {} }; +MODULE_DEVICE_TABLE(spi, ad2s90_id); static struct spi_driver ad2s90_driver = { .driver = { diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c index 66a34addb75..3e24ec45585 100644 --- a/drivers/staging/iio/ring_sw.c +++ b/drivers/staging/iio/ring_sw.c @@ -23,11 +23,8 @@ * @data: the ring buffer memory * @read_p: read pointer (oldest available) * @write_p: write pointer - * @last_written_p: read pointer (newest available) * @half_p: half buffer length behind write_p (event generation) - * @use_count: reference count to prevent resizing when in use * @update_needed: flag to indicated change in size requested - * @use_lock: lock to prevent change in size when in use * * Note that the first element of all ring buffers must be a * struct iio_buffer. @@ -37,12 +34,9 @@ struct iio_sw_ring_buffer { unsigned char *data; unsigned char *read_p; unsigned char *write_p; - unsigned char *last_written_p; /* used to act as a point at which to signal an event */ unsigned char *half_p; - int use_count; int update_needed; - spinlock_t use_lock; }; #define iio_to_sw_ring(r) container_of(r, struct iio_sw_ring_buffer, buf) @@ -56,38 +50,15 @@ static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring, ring->data = kmalloc(length*ring->buf.bytes_per_datum, GFP_ATOMIC); ring->read_p = NULL; ring->write_p = NULL; - ring->last_written_p = NULL; ring->half_p = NULL; return ring->data ? 0 : -ENOMEM; } -static inline void __iio_init_sw_ring_buffer(struct iio_sw_ring_buffer *ring) -{ - spin_lock_init(&ring->use_lock); -} - static inline void __iio_free_sw_ring_buffer(struct iio_sw_ring_buffer *ring) { kfree(ring->data); } -static void iio_mark_sw_rb_in_use(struct iio_buffer *r) -{ - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - spin_lock(&ring->use_lock); - ring->use_count++; - spin_unlock(&ring->use_lock); -} - -static void iio_unmark_sw_rb_in_use(struct iio_buffer *r) -{ - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - spin_lock(&ring->use_lock); - ring->use_count--; - spin_unlock(&ring->use_lock); -} - - /* Ring buffer related functionality */ /* Store to ring is typically called in the bh of a data ready interrupt handler * in the device driver */ @@ -115,7 +86,6 @@ static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring, * Always valid as either points to latest or second latest value. * Before this runs it is null and read attempts fail with -EAGAIN. */ - ring->last_written_p = ring->write_p; barrier(); /* temp_ptr used to ensure we never have an invalid pointer * it may be slightly lagging, but never invalid @@ -174,6 +144,7 @@ static int iio_read_first_n_sw_rb(struct iio_buffer *r, u8 *initial_read_p, *initial_write_p, *current_read_p, *end_read_p; u8 *data; int ret, max_copied, bytes_to_rip, dead_offset; + size_t data_available, buffer_size; /* A userspace program has probably made an error if it tries to * read something that is not a whole number of bpds. @@ -186,9 +157,11 @@ static int iio_read_first_n_sw_rb(struct iio_buffer *r, n, ring->buf.bytes_per_datum); goto error_ret; } + + buffer_size = ring->buf.bytes_per_datum*ring->buf.length; + /* Limit size to whole of ring buffer */ - bytes_to_rip = min((size_t)(ring->buf.bytes_per_datum*ring->buf.length), - n); + bytes_to_rip = min_t(size_t, buffer_size, n); data = kmalloc(bytes_to_rip, GFP_KERNEL); if (data == NULL) { @@ -217,38 +190,24 @@ static int iio_read_first_n_sw_rb(struct iio_buffer *r, goto error_free_data_cpy; } - if (initial_write_p >= initial_read_p + bytes_to_rip) { - /* write_p is greater than necessary, all is easy */ - max_copied = bytes_to_rip; - memcpy(data, initial_read_p, max_copied); - end_read_p = initial_read_p + max_copied; - } else if (initial_write_p > initial_read_p) { - /*not enough data to cpy */ - max_copied = initial_write_p - initial_read_p; + if (initial_write_p >= initial_read_p) + data_available = initial_write_p - initial_read_p; + else + data_available = buffer_size - (initial_read_p - initial_write_p); + + if (data_available < bytes_to_rip) + bytes_to_rip = data_available; + + if (initial_read_p + bytes_to_rip >= ring->data + buffer_size) { + max_copied = ring->data + buffer_size - initial_read_p; memcpy(data, initial_read_p, max_copied); - end_read_p = initial_write_p; + memcpy(data + max_copied, ring->data, bytes_to_rip - max_copied); + end_read_p = ring->data + bytes_to_rip - max_copied; } else { - /* going through 'end' of ring buffer */ - max_copied = ring->data - + ring->buf.length*ring->buf.bytes_per_datum - initial_read_p; - memcpy(data, initial_read_p, max_copied); - /* possible we are done if we align precisely with end */ - if (max_copied == bytes_to_rip) - end_read_p = ring->data; - else if (initial_write_p - > ring->data + bytes_to_rip - max_copied) { - /* enough data to finish */ - memcpy(data + max_copied, ring->data, - bytes_to_rip - max_copied); - max_copied = bytes_to_rip; - end_read_p = ring->data + (bytes_to_rip - max_copied); - } else { /* not enough data */ - memcpy(data + max_copied, ring->data, - initial_write_p - ring->data); - max_copied += initial_write_p - ring->data; - end_read_p = initial_write_p; - } + memcpy(data, initial_read_p, bytes_to_rip); + end_read_p = initial_read_p + bytes_to_rip; } + /* Now to verify which section was cleanly copied - i.e. how far * read pointer has been pushed */ current_read_p = ring->read_p; @@ -256,15 +215,14 @@ static int iio_read_first_n_sw_rb(struct iio_buffer *r, if (initial_read_p <= current_read_p) dead_offset = current_read_p - initial_read_p; else - dead_offset = ring->buf.length*ring->buf.bytes_per_datum - - (initial_read_p - current_read_p); + dead_offset = buffer_size - (initial_read_p - current_read_p); /* possible issue if the initial write has been lapped or indeed * the point we were reading to has been passed */ /* No valid data read. * In this case the read pointer is already correct having been * pushed further than we would look. */ - if (max_copied - dead_offset < 0) { + if (bytes_to_rip - dead_offset < 0) { ret = 0; goto error_free_data_cpy; } @@ -280,7 +238,7 @@ static int iio_read_first_n_sw_rb(struct iio_buffer *r, while (ring->read_p != end_read_p) ring->read_p = end_read_p; - ret = max_copied - dead_offset; + ret = bytes_to_rip - dead_offset; if (copy_to_user(buf, data + dead_offset, ret)) { ret = -EFAULT; @@ -305,52 +263,18 @@ static int iio_store_to_sw_rb(struct iio_buffer *r, return iio_store_to_sw_ring(ring, data, timestamp); } -static int iio_read_last_from_sw_ring(struct iio_sw_ring_buffer *ring, - unsigned char *data) -{ - unsigned char *last_written_p_copy; - - iio_mark_sw_rb_in_use(&ring->buf); -again: - barrier(); - last_written_p_copy = ring->last_written_p; - barrier(); /*unnessecary? */ - /* Check there is anything here */ - if (last_written_p_copy == NULL) - return -EAGAIN; - memcpy(data, last_written_p_copy, ring->buf.bytes_per_datum); - - if (unlikely(ring->last_written_p != last_written_p_copy)) - goto again; - - iio_unmark_sw_rb_in_use(&ring->buf); - return 0; -} - -static int iio_read_last_from_sw_rb(struct iio_buffer *r, - unsigned char *data) -{ - return iio_read_last_from_sw_ring(iio_to_sw_ring(r), data); -} - static int iio_request_update_sw_rb(struct iio_buffer *r) { int ret = 0; struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); r->stufftoread = false; - spin_lock(&ring->use_lock); if (!ring->update_needed) goto error_ret; - if (ring->use_count) { - ret = -EAGAIN; - goto error_ret; - } __iio_free_sw_ring_buffer(ring); ret = __iio_allocate_sw_ring_buffer(ring, ring->buf.bytes_per_datum, ring->buf.length); error_ret: - spin_unlock(&ring->use_lock); return ret; } @@ -360,12 +284,18 @@ static int iio_get_bytes_per_datum_sw_rb(struct iio_buffer *r) return ring->buf.bytes_per_datum; } +static int iio_mark_update_needed_sw_rb(struct iio_buffer *r) +{ + struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); + ring->update_needed = true; + return 0; +} + static int iio_set_bytes_per_datum_sw_rb(struct iio_buffer *r, size_t bpd) { if (r->bytes_per_datum != bpd) { r->bytes_per_datum = bpd; - if (r->access->mark_param_change) - r->access->mark_param_change(r); + iio_mark_update_needed_sw_rb(r); } return 0; } @@ -379,27 +309,17 @@ static int iio_set_length_sw_rb(struct iio_buffer *r, int length) { if (r->length != length) { r->length = length; - if (r->access->mark_param_change) - r->access->mark_param_change(r); + iio_mark_update_needed_sw_rb(r); } return 0; } -static int iio_mark_update_needed_sw_rb(struct iio_buffer *r) -{ - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - ring->update_needed = true; - return 0; -} - static IIO_BUFFER_ENABLE_ATTR; -static IIO_BUFFER_BYTES_PER_DATUM_ATTR; static IIO_BUFFER_LENGTH_ATTR; /* Standard set of ring buffer attributes */ static struct attribute *iio_ring_attributes[] = { &dev_attr_length.attr, - &dev_attr_bytes_per_datum.attr, &dev_attr_enable.attr, NULL, }; @@ -419,8 +339,7 @@ struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev) return NULL; ring->update_needed = true; buf = &ring->buf; - iio_buffer_init(buf, indio_dev); - __iio_init_sw_ring_buffer(ring); + iio_buffer_init(buf); buf->attrs = &iio_ring_attribute_group; return buf; @@ -434,12 +353,8 @@ void iio_sw_rb_free(struct iio_buffer *r) EXPORT_SYMBOL(iio_sw_rb_free); const struct iio_buffer_access_funcs ring_sw_access_funcs = { - .mark_in_use = &iio_mark_sw_rb_in_use, - .unmark_in_use = &iio_unmark_sw_rb_in_use, .store_to = &iio_store_to_sw_rb, - .read_last = &iio_read_last_from_sw_rb, .read_first_n = &iio_read_first_n_sw_rb, - .mark_param_change = &iio_mark_update_needed_sw_rb, .request_update = &iio_request_update_sw_rb, .get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb, .set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb, diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h index a3e15784c22..e6a6e2c4096 100644 --- a/drivers/staging/iio/ring_sw.h +++ b/drivers/staging/iio/ring_sw.h @@ -23,7 +23,7 @@ #ifndef _IIO_RING_SW_H_ #define _IIO_RING_SW_H_ -#include "buffer_generic.h" +#include "buffer.h" /** * ring_sw_access_funcs - access functions for a software ring buffer diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h index 868952b5ba6..bfedb73b850 100644 --- a/drivers/staging/iio/sysfs.h +++ b/drivers/staging/iio/sysfs.h @@ -114,47 +114,4 @@ struct iio_const_attr { #define IIO_CONST_ATTR_TEMP_SCALE(_string) \ IIO_CONST_ATTR(in_temp_scale, _string) -enum iio_event_type { - IIO_EV_TYPE_THRESH, - IIO_EV_TYPE_MAG, - IIO_EV_TYPE_ROC, - IIO_EV_TYPE_THRESH_ADAPTIVE, - IIO_EV_TYPE_MAG_ADAPTIVE, -}; - -enum iio_event_direction { - IIO_EV_DIR_EITHER, - IIO_EV_DIR_RISING, - IIO_EV_DIR_FALLING, -}; - -#define IIO_EVENT_CODE(chan_type, diff, modifier, direction, \ - type, chan, chan1, chan2) \ - (((u64)type << 56) | ((u64)diff << 55) | \ - ((u64)direction << 48) | ((u64)modifier << 40) | \ - ((u64)chan_type << 32) | (chan2 << 16) | chan1 | chan) - -#define IIO_EV_DIR_MAX 4 -#define IIO_EV_BIT(type, direction) \ - (1 << (type*IIO_EV_DIR_MAX + direction)) - -#define IIO_MOD_EVENT_CODE(channelclass, number, modifier, \ - type, direction) \ - IIO_EVENT_CODE(channelclass, 0, modifier, direction, type, number, 0, 0) - -#define IIO_UNMOD_EVENT_CODE(channelclass, number, type, direction) \ - IIO_EVENT_CODE(channelclass, 0, 0, direction, type, number, 0, 0) - -#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF) - -#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF) - -#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF) - -/* Event code number extraction depends on which type of event we have. - * Perhaps review this function in the future*/ -#define IIO_EVENT_CODE_EXTRACT_NUM(mask) (mask & 0xFFFF) - -#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF) - #endif /* _INDUSTRIAL_IO_SYSFS_H_ */ diff --git a/drivers/staging/iio/trigger.h b/drivers/staging/iio/trigger.h index 5cc42a655c8..1cfca231db8 100644 --- a/drivers/staging/iio/trigger.h +++ b/drivers/staging/iio/trigger.h @@ -46,7 +46,6 @@ struct iio_trigger_ops { * @private_data: [DRIVER] device specific data * @list: [INTERN] used in maintenance of global trigger list * @alloc_list: [DRIVER] used for driver specific trigger list - * @owner: [DRIVER] used to monitor usage count of the trigger. * @use_count: use count for the trigger * @subirq_chip: [INTERN] associate 'virtual' irq chip. * @subirq_base: [INTERN] base number for irqs provided by trigger. @@ -63,7 +62,6 @@ struct iio_trigger { void *private_data; struct list_head list; struct list_head alloc_list; - struct module *owner; int use_count; struct irq_chip subirq_chip; diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index d35d085da94..bd7416b2c56 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -125,7 +125,6 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev) goto error_put_trigger_and_remove_from_list; } trig->private_data = trig_info; - trig->owner = THIS_MODULE; trig->ops = &iio_prtc_trigger_ops; /* RTC access */ trig_info->rtc diff --git a/drivers/staging/iio/types.h b/drivers/staging/iio/types.h new file mode 100644 index 00000000000..b7d26474ad0 --- /dev/null +++ b/drivers/staging/iio/types.h @@ -0,0 +1,49 @@ +/* industrial I/O data types needed both in and out of kernel + * + * Copyright (c) 2008 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _IIO_TYPES_H_ +#define _IIO_TYPES_H_ + +enum iio_chan_type { + /* real channel types */ + IIO_VOLTAGE, + IIO_CURRENT, + IIO_POWER, + IIO_ACCEL, + IIO_ANGL_VEL, + IIO_MAGN, + IIO_LIGHT, + IIO_INTENSITY, + IIO_PROXIMITY, + IIO_TEMP, + IIO_INCLI, + IIO_ROT, + IIO_ANGL, + IIO_TIMESTAMP, + IIO_CAPACITANCE, +}; + +enum iio_modifier { + IIO_NO_MOD, + IIO_MOD_X, + IIO_MOD_Y, + IIO_MOD_Z, + IIO_MOD_X_AND_Y, + IIO_MOD_X_AND_Z, + IIO_MOD_Y_AND_Z, + IIO_MOD_X_AND_Y_AND_Z, + IIO_MOD_X_OR_Y, + IIO_MOD_X_OR_Z, + IIO_MOD_Y_OR_Z, + IIO_MOD_X_OR_Y_OR_Z, + IIO_MOD_LIGHT_BOTH, + IIO_MOD_LIGHT_IR, +}; + +#endif /* _IIO_TYPES_H_ */ diff --git a/drivers/staging/intel_sst/Kconfig b/drivers/staging/intel_sst/Kconfig deleted file mode 100644 index 82391077b38..00000000000 --- a/drivers/staging/intel_sst/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config SND_INTEL_SST - tristate "Intel SST (LPE) Driver" - depends on X86 && INTEL_SCU_IPC - default n - help - Say Y here to include support for the Intel(R) MID SST DSP driver - On other PC platforms if you are unsure answer 'N' - -config SND_INTELMID - tristate "Intel MID sound card driver" - depends on SOUND && SND - select SND_PCM - select SND_SEQUENCER - select SND_JACK - depends on SND_INTEL_SST - default n - help - Say Y here to include support for the Intel(R) MID sound card driver - On other PC platforms if you are unsure answer 'N' diff --git a/drivers/staging/intel_sst/Makefile b/drivers/staging/intel_sst/Makefile deleted file mode 100644 index 9eb7c158bb6..00000000000 --- a/drivers/staging/intel_sst/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for Intel MID Audio drivers -# -snd-intel-sst-y := intel_sst.o intel_sst_ipc.o intel_sst_stream.o intel_sst_drv_interface.o intel_sst_dsp.o intel_sst_pvt.o intel_sst_stream_encoded.o intel_sst_app_interface.o -snd-intelmid-y := intelmid.o intelmid_msic_control.o intelmid_ctrl.o intelmid_pvt.o intelmid_v0_control.o intelmid_v1_control.o intelmid_v2_control.o -obj-$(CONFIG_SND_INTEL_SST) += snd-intel-sst.o -obj-$(CONFIG_SND_INTELMID) += snd-intelmid.o diff --git a/drivers/staging/intel_sst/TODO b/drivers/staging/intel_sst/TODO deleted file mode 100644 index c733d701109..00000000000 --- a/drivers/staging/intel_sst/TODO +++ /dev/null @@ -1,13 +0,0 @@ -TODO ----- - -Get the memrar driver cleaned up and upstream (dependency blocking SST) -Replace long/short press with two virtual buttons -Review the printks and kill off any left over ST_ERR: messages -Review the misc device ioctls for 32/64bit safety and sanity -Review the misc device ioctls for size safety depending on config and decide - if space/unused areas should be left -What the sound folks turn up on full review -Using the ALSA frameworks properly - - diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c deleted file mode 100644 index ff9aaec0557..00000000000 --- a/drivers/staging/intel_sst/intel_sst.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * intel_sst.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This driver exposes the audio engine functionalities to the ALSA - * and middleware. - * - * This file contains all init functions - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/interrupt.h> -#include <linux/firmware.h> -#include <linux/miscdevice.h> -#include <linux/pm_runtime.h> -#include <linux/module.h> -#include <asm/mrst.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - - -MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); -MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); -MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>"); -MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>"); -MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(SST_DRIVER_VERSION); - -struct intel_sst_drv *sst_drv_ctx; -static struct mutex drv_ctx_lock; -struct class *sst_class; - -/* fops Routines */ -static const struct file_operations intel_sst_fops = { - .owner = THIS_MODULE, - .open = intel_sst_open, - .release = intel_sst_release, - .read = intel_sst_read, - .write = intel_sst_write, - .unlocked_ioctl = intel_sst_ioctl, - .mmap = intel_sst_mmap, - .aio_read = intel_sst_aio_read, - .aio_write = intel_sst_aio_write, -}; -static const struct file_operations intel_sst_fops_cntrl = { - .owner = THIS_MODULE, - .open = intel_sst_open_cntrl, - .release = intel_sst_release_cntrl, - .unlocked_ioctl = intel_sst_ioctl, -}; - -static struct miscdevice lpe_dev = { - .minor = MISC_DYNAMIC_MINOR,/* dynamic allocation */ - .name = "intel_sst",/* /dev/intel_sst */ - .fops = &intel_sst_fops -}; - - -static struct miscdevice lpe_ctrl = { - .minor = MISC_DYNAMIC_MINOR,/* dynamic allocation */ - .name = "intel_sst_ctrl",/* /dev/intel_sst_ctrl */ - .fops = &intel_sst_fops_cntrl -}; - -/** -* intel_sst_interrupt - Interrupt service routine for SST -* -* @irq: irq number of interrupt -* @context: pointer to device structre -* -* This function is called by OS when SST device raises -* an interrupt. This will be result of write in IPC register -* Source can be busy or done interrupt -*/ -static irqreturn_t intel_sst_interrupt(int irq, void *context) -{ - union interrupt_reg isr; - union ipc_header header; - union interrupt_reg imr; - struct intel_sst_drv *drv = (struct intel_sst_drv *) context; - unsigned int size = 0, str_id; - struct stream_info *stream ; - - /* Do not handle interrupt in suspended state */ - if (drv->sst_state == SST_SUSPENDED) - return IRQ_NONE; - /* Interrupt arrived, check src */ - isr.full = sst_shim_read(drv->shim, SST_ISRX); - - if (isr.part.busy_interrupt) { - header.full = sst_shim_read(drv->shim, SST_IPCD); - if (header.part.msg_id == IPC_SST_PERIOD_ELAPSED) { - sst_clear_interrupt(); - str_id = header.part.str_id; - stream = &sst_drv_ctx->streams[str_id]; - if (stream->period_elapsed) - stream->period_elapsed(stream->pcm_substream); - return IRQ_HANDLED; - } - if (header.part.large) - size = header.part.data; - if (header.part.msg_id & REPLY_MSG) { - sst_drv_ctx->ipc_process_msg.header = header; - memcpy_fromio(sst_drv_ctx->ipc_process_msg.mailbox, - drv->mailbox + SST_MAILBOX_RCV, size); - queue_work(sst_drv_ctx->process_msg_wq, - &sst_drv_ctx->ipc_process_msg.wq); - } else { - sst_drv_ctx->ipc_process_reply.header = header; - memcpy_fromio(sst_drv_ctx->ipc_process_reply.mailbox, - drv->mailbox + SST_MAILBOX_RCV, size); - queue_work(sst_drv_ctx->process_reply_wq, - &sst_drv_ctx->ipc_process_reply.wq); - } - /* mask busy inetrrupt */ - imr.full = sst_shim_read(drv->shim, SST_IMRX); - imr.part.busy_interrupt = 1; - sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full); - return IRQ_HANDLED; - } else if (isr.part.done_interrupt) { - /* Clear done bit */ - header.full = sst_shim_read(drv->shim, SST_IPCX); - header.part.done = 0; - sst_shim_write(sst_drv_ctx->shim, SST_IPCX, header.full); - /* write 1 to clear status register */; - isr.part.done_interrupt = 1; - /* dummy register for shim workaround */ - sst_shim_write(sst_drv_ctx->shim, SST_ISRX, isr.full); - queue_work(sst_drv_ctx->post_msg_wq, - &sst_drv_ctx->ipc_post_msg.wq); - return IRQ_HANDLED; - } else - return IRQ_NONE; - -} - - -/* -* intel_sst_probe - PCI probe function -* -* @pci: PCI device structure -* @pci_id: PCI device ID structure -* -* This function is called by OS when a device is found -* This enables the device, interrupt etc -*/ -static int __devinit intel_sst_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - int i, ret = 0; - - pr_debug("Probe for DID %x\n", pci->device); - mutex_lock(&drv_ctx_lock); - if (sst_drv_ctx) { - pr_err("Only one sst handle is supported\n"); - mutex_unlock(&drv_ctx_lock); - return -EBUSY; - } - - sst_drv_ctx = kzalloc(sizeof(*sst_drv_ctx), GFP_KERNEL); - if (!sst_drv_ctx) { - pr_err("malloc fail\n"); - mutex_unlock(&drv_ctx_lock); - return -ENOMEM; - } - mutex_unlock(&drv_ctx_lock); - - sst_drv_ctx->pci_id = pci->device; - - mutex_init(&sst_drv_ctx->stream_lock); - mutex_init(&sst_drv_ctx->sst_lock); - sst_drv_ctx->pmic_state = SND_MAD_UN_INIT; - - sst_drv_ctx->stream_cnt = 0; - sst_drv_ctx->encoded_cnt = 0; - sst_drv_ctx->am_cnt = 0; - sst_drv_ctx->pb_streams = 0; - sst_drv_ctx->cp_streams = 0; - sst_drv_ctx->unique_id = 0; - sst_drv_ctx->pmic_port_instance = SST_DEFAULT_PMIC_PORT; - - INIT_LIST_HEAD(&sst_drv_ctx->ipc_dispatch_list); - INIT_WORK(&sst_drv_ctx->ipc_post_msg.wq, sst_post_message); - INIT_WORK(&sst_drv_ctx->ipc_process_msg.wq, sst_process_message); - INIT_WORK(&sst_drv_ctx->ipc_process_reply.wq, sst_process_reply); - INIT_WORK(&sst_drv_ctx->mad_ops.wq, sst_process_mad_ops); - init_waitqueue_head(&sst_drv_ctx->wait_queue); - - sst_drv_ctx->mad_wq = create_workqueue("sst_mad_wq"); - if (!sst_drv_ctx->mad_wq) - goto do_free_drv_ctx; - sst_drv_ctx->post_msg_wq = create_workqueue("sst_post_msg_wq"); - if (!sst_drv_ctx->post_msg_wq) - goto free_mad_wq; - sst_drv_ctx->process_msg_wq = create_workqueue("sst_process_msg_wqq"); - if (!sst_drv_ctx->process_msg_wq) - goto free_post_msg_wq; - sst_drv_ctx->process_reply_wq = create_workqueue("sst_proces_reply_wq"); - if (!sst_drv_ctx->process_reply_wq) - goto free_process_msg_wq; - - for (i = 0; i < MAX_ACTIVE_STREAM; i++) { - sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - sst_drv_ctx->alloc_block[i].ops_block.condition = false; - } - spin_lock_init(&sst_drv_ctx->list_spin_lock); - - sst_drv_ctx->max_streams = pci_id->driver_data; - pr_debug("Got drv data max stream %d\n", - sst_drv_ctx->max_streams); - for (i = 1; i <= sst_drv_ctx->max_streams; i++) { - struct stream_info *stream = &sst_drv_ctx->streams[i]; - INIT_LIST_HEAD(&stream->bufs); - mutex_init(&stream->lock); - spin_lock_init(&stream->pcm_lock); - } - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { - sst_drv_ctx->mmap_mem = NULL; - sst_drv_ctx->mmap_len = SST_MMAP_PAGES * PAGE_SIZE; - while (sst_drv_ctx->mmap_len > 0) { - sst_drv_ctx->mmap_mem = - kzalloc(sst_drv_ctx->mmap_len, GFP_KERNEL); - if (sst_drv_ctx->mmap_mem) { - pr_debug("Got memory %p size 0x%x\n", - sst_drv_ctx->mmap_mem, - sst_drv_ctx->mmap_len); - break; - } - if (sst_drv_ctx->mmap_len < (SST_MMAP_STEP*PAGE_SIZE)) { - pr_err("mem alloc fail...abort!!\n"); - ret = -ENOMEM; - goto free_process_reply_wq; - } - sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE); - pr_debug("mem alloc failed...trying %d\n", - sst_drv_ctx->mmap_len); - } - } - - /* Init the device */ - ret = pci_enable_device(pci); - if (ret) { - pr_err("device can't be enabled\n"); - goto do_free_mem; - } - sst_drv_ctx->pci = pci_dev_get(pci); - ret = pci_request_regions(pci, SST_DRV_NAME); - if (ret) - goto do_disable_device; - /* map registers */ - /* SST Shim */ - sst_drv_ctx->shim_phy_add = pci_resource_start(pci, 1); - sst_drv_ctx->shim = pci_ioremap_bar(pci, 1); - if (!sst_drv_ctx->shim) - goto do_release_regions; - pr_debug("SST Shim Ptr %p\n", sst_drv_ctx->shim); - - /* Shared SRAM */ - sst_drv_ctx->mailbox = pci_ioremap_bar(pci, 2); - if (!sst_drv_ctx->mailbox) - goto do_unmap_shim; - pr_debug("SRAM Ptr %p\n", sst_drv_ctx->mailbox); - - /* IRAM */ - sst_drv_ctx->iram = pci_ioremap_bar(pci, 3); - if (!sst_drv_ctx->iram) - goto do_unmap_sram; - pr_debug("IRAM Ptr %p\n", sst_drv_ctx->iram); - - /* DRAM */ - sst_drv_ctx->dram = pci_ioremap_bar(pci, 4); - if (!sst_drv_ctx->dram) - goto do_unmap_iram; - pr_debug("DRAM Ptr %p\n", sst_drv_ctx->dram); - - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_UN_INIT; - mutex_unlock(&sst_drv_ctx->sst_lock); - /* Register the ISR */ - ret = request_irq(pci->irq, intel_sst_interrupt, - IRQF_SHARED, SST_DRV_NAME, sst_drv_ctx); - if (ret) - goto do_unmap_dram; - pr_debug("Registered IRQ 0x%x\n", pci->irq); - - /*Register LPE Control as misc driver*/ - ret = misc_register(&lpe_ctrl); - if (ret) { - pr_err("couldn't register control device\n"); - goto do_free_irq; - } - - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { - ret = misc_register(&lpe_dev); - if (ret) { - pr_err("couldn't register LPE device\n"); - goto do_free_misc; - } - } else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) { - u32 csr; - - /*allocate mem for fw context save during suspend*/ - sst_drv_ctx->fw_cntx = kzalloc(FW_CONTEXT_MEM, GFP_KERNEL); - if (!sst_drv_ctx->fw_cntx) { - ret = -ENOMEM; - goto do_free_misc; - } - /*setting zero as that is valid mem to restore*/ - sst_drv_ctx->fw_cntx_size = 0; - - /*set lpe start clock and ram size*/ - csr = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr |= 0x30060; /*remove the clock ratio after fw fix*/ - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr); - } - sst_drv_ctx->lpe_stalled = 0; - pci_set_drvdata(pci, sst_drv_ctx); - pm_runtime_allow(&pci->dev); - pm_runtime_put_noidle(&pci->dev); - pr_debug("...successfully done!!!\n"); - return ret; - -do_free_misc: - misc_deregister(&lpe_ctrl); -do_free_irq: - free_irq(pci->irq, sst_drv_ctx); -do_unmap_dram: - iounmap(sst_drv_ctx->dram); -do_unmap_iram: - iounmap(sst_drv_ctx->iram); -do_unmap_sram: - iounmap(sst_drv_ctx->mailbox); -do_unmap_shim: - iounmap(sst_drv_ctx->shim); -do_release_regions: - pci_release_regions(pci); -do_disable_device: - pci_disable_device(pci); -do_free_mem: - kfree(sst_drv_ctx->mmap_mem); -free_process_reply_wq: - destroy_workqueue(sst_drv_ctx->process_reply_wq); -free_process_msg_wq: - destroy_workqueue(sst_drv_ctx->process_msg_wq); -free_post_msg_wq: - destroy_workqueue(sst_drv_ctx->post_msg_wq); -free_mad_wq: - destroy_workqueue(sst_drv_ctx->mad_wq); -do_free_drv_ctx: - kfree(sst_drv_ctx); - sst_drv_ctx = NULL; - pr_err("Probe failed with %d\n", ret); - return ret; -} - -/** -* intel_sst_remove - PCI remove function -* -* @pci: PCI device structure -* -* This function is called by OS when a device is unloaded -* This frees the interrupt etc -*/ -static void __devexit intel_sst_remove(struct pci_dev *pci) -{ - pm_runtime_get_noresume(&pci->dev); - pm_runtime_forbid(&pci->dev); - pci_dev_put(sst_drv_ctx->pci); - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_UN_INIT; - mutex_unlock(&sst_drv_ctx->sst_lock); - misc_deregister(&lpe_ctrl); - free_irq(pci->irq, sst_drv_ctx); - iounmap(sst_drv_ctx->dram); - iounmap(sst_drv_ctx->iram); - iounmap(sst_drv_ctx->mailbox); - iounmap(sst_drv_ctx->shim); - sst_drv_ctx->pmic_state = SND_MAD_UN_INIT; - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { - misc_deregister(&lpe_dev); - kfree(sst_drv_ctx->mmap_mem); - } else - kfree(sst_drv_ctx->fw_cntx); - flush_scheduled_work(); - destroy_workqueue(sst_drv_ctx->process_reply_wq); - destroy_workqueue(sst_drv_ctx->process_msg_wq); - destroy_workqueue(sst_drv_ctx->post_msg_wq); - destroy_workqueue(sst_drv_ctx->mad_wq); - kfree(pci_get_drvdata(pci)); - sst_drv_ctx = NULL; - pci_release_regions(pci); - pci_disable_device(pci); - pci_set_drvdata(pci, NULL); -} - -void sst_save_dsp_context(void) -{ - struct snd_sst_ctxt_params fw_context; - unsigned int pvt_id, i; - struct ipc_post *msg = NULL; - - /*check cpu type*/ - if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID) - return; - /*not supported for rest*/ - if (sst_drv_ctx->sst_state != SST_FW_RUNNING) { - pr_debug("fw not running no context save ...\n"); - return; - } - - /*send msg to fw*/ - if (sst_create_large_msg(&msg)) - return; - pvt_id = sst_assign_pvt_id(sst_drv_ctx); - i = sst_get_block_stream(sst_drv_ctx); - sst_drv_ctx->alloc_block[i].sst_id = pvt_id; - sst_fill_header(&msg->header, IPC_IA_GET_FW_CTXT, 1, pvt_id); - msg->header.part.data = sizeof(fw_context) + sizeof(u32); - fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx); - fw_context.size = FW_CONTEXT_MEM; - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), - &fw_context, sizeof(fw_context)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - /*wait for reply*/ - if (sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i])) - pr_debug("err fw context save timeout ...\n"); - sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - pr_debug("fw context saved ...\n"); - return; -} - -/* Power Management */ -/* -* intel_sst_suspend - PCI suspend function -* -* @pci: PCI device structure -* @state: PM message -* -* This function is called by OS when a power event occurs -*/ -int intel_sst_suspend(struct pci_dev *pci, pm_message_t state) -{ - union config_status_reg csr; - - pr_debug("intel_sst_suspend called\n"); - - if (sst_drv_ctx->stream_cnt) { - pr_err("active streams,not able to suspend\n"); - return -EBUSY; - } - /*save fw context*/ - sst_save_dsp_context(); - /*Assert RESET on LPE Processor*/ - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.full = csr.full | 0x2; - /* Move the SST state to Suspended */ - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_SUSPENDED; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - mutex_unlock(&sst_drv_ctx->sst_lock); - pci_set_drvdata(pci, sst_drv_ctx); - pci_save_state(pci); - pci_disable_device(pci); - pci_set_power_state(pci, PCI_D3hot); - return 0; -} - -/** -* intel_sst_resume - PCI resume function -* -* @pci: PCI device structure -* -* This function is called by OS when a power event occurs -*/ -int intel_sst_resume(struct pci_dev *pci) -{ - int ret = 0; - - pr_debug("intel_sst_resume called\n"); - if (sst_drv_ctx->sst_state != SST_SUSPENDED) { - pr_err("SST is not in suspended state\n"); - return 0; - } - sst_drv_ctx = pci_get_drvdata(pci); - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - ret = pci_enable_device(pci); - if (ret) - pr_err("device can't be enabled\n"); - - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_UN_INIT; - mutex_unlock(&sst_drv_ctx->sst_lock); - return 0; -} - -/* The runtime_suspend/resume is pretty much similar to the legacy - * suspend/resume with the noted exception below: - * The PCI core takes care of taking the system through D3hot and - * restoring it back to D0 and so there is no need to duplicate - * that here. - */ -static int intel_sst_runtime_suspend(struct device *dev) -{ - union config_status_reg csr; - - pr_debug("intel_sst_runtime_suspend called\n"); - if (sst_drv_ctx->stream_cnt) { - pr_err("active streams,not able to suspend\n"); - return -EBUSY; - } - /*save fw context*/ - sst_save_dsp_context(); - /*Assert RESET on LPE Processor*/ - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.full = csr.full | 0x2; - /* Move the SST state to Suspended */ - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_SUSPENDED; - - /* Only needed by Medfield */ - if (sst_drv_ctx->pci_id != SST_MRST_PCI_ID) - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - mutex_unlock(&sst_drv_ctx->sst_lock); - return 0; -} - -static int intel_sst_runtime_resume(struct device *dev) -{ - - pr_debug("intel_sst_runtime_resume called\n"); - if (sst_drv_ctx->sst_state != SST_SUSPENDED) { - pr_err("SST is not in suspended state\n"); - return 0; - } - - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_UN_INIT; - mutex_unlock(&sst_drv_ctx->sst_lock); - return 0; -} - -static int intel_sst_runtime_idle(struct device *dev) -{ - pr_debug("runtime_idle called\n"); - if (sst_drv_ctx->stream_cnt == 0 && sst_drv_ctx->am_cnt == 0) - pm_schedule_suspend(dev, SST_SUSPEND_DELAY); - return -EBUSY; -} - -static const struct dev_pm_ops intel_sst_pm = { - .runtime_suspend = intel_sst_runtime_suspend, - .runtime_resume = intel_sst_runtime_resume, - .runtime_idle = intel_sst_runtime_idle, -}; - -/* PCI Routines */ -static struct pci_device_id intel_sst_ids[] = { - { PCI_VDEVICE(INTEL, SST_MRST_PCI_ID), 3}, - { PCI_VDEVICE(INTEL, SST_MFLD_PCI_ID), 6}, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, intel_sst_ids); - -static struct pci_driver driver = { - .name = SST_DRV_NAME, - .id_table = intel_sst_ids, - .probe = intel_sst_probe, - .remove = __devexit_p(intel_sst_remove), -#ifdef CONFIG_PM - .suspend = intel_sst_suspend, - .resume = intel_sst_resume, - .driver = { - .pm = &intel_sst_pm, - }, -#endif -}; - -/** -* intel_sst_init - Module init function -* -* Registers with PCI -* Registers with /dev -* Init all data strutures -*/ -static int __init intel_sst_init(void) -{ - /* Init all variables, data structure etc....*/ - int ret = 0; - pr_debug("INFO: ******** SST DRIVER loading.. Ver: %s\n", - SST_DRIVER_VERSION); - - mutex_init(&drv_ctx_lock); - /* Register with PCI */ - ret = pci_register_driver(&driver); - if (ret) - pr_err("PCI register failed\n"); - return ret; -} - -/** -* intel_sst_exit - Module exit function -* -* Unregisters with PCI -* Unregisters with /dev -* Frees all data strutures -*/ -static void __exit intel_sst_exit(void) -{ - pci_unregister_driver(&driver); - - pr_debug("driver unloaded\n"); - sst_drv_ctx = NULL; - return; -} - -module_init(intel_sst_init); -module_exit(intel_sst_exit); diff --git a/drivers/staging/intel_sst/intel_sst.h b/drivers/staging/intel_sst/intel_sst.h deleted file mode 100644 index 4ad2829105a..00000000000 --- a/drivers/staging/intel_sst/intel_sst.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef __INTEL_SST_H__ -#define __INTEL_SST_H__ -/* - * intel_sst.h - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corporation - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This driver exposes the audio engine functionalities to the ALSA - * and middleware. - * This file is shared between the SST and MAD drivers - */ -#include "intel_sst_ioctl.h" -#include <sound/jack.h> - -#define SST_CARD_NAMES "intel_mid_card" - -#define MFLD_MAX_HW_CH 4 -/* control list Pmic & Lpe */ -/* Input controls */ -enum port_status { - ACTIVATE = 1, - DEACTIVATE, -}; - -/* Card states */ -enum sst_card_states { - SND_CARD_UN_INIT = 0, - SND_CARD_INIT_DONE, -}; - -enum sst_controls { - SST_SND_ALLOC = 0x1000, - SST_SND_PAUSE = 0x1001, - SST_SND_RESUME = 0x1002, - SST_SND_DROP = 0x1003, - SST_SND_FREE = 0x1004, - SST_SND_BUFFER_POINTER = 0x1005, - SST_SND_STREAM_INIT = 0x1006, - SST_SND_START = 0x1007, - SST_SND_STREAM_PROCESS = 0x1008, - SST_MAX_CONTROLS = 0x1008, - SST_CONTROL_BASE = 0x1000, - SST_ENABLE_RX_TIME_SLOT = 0x1009, -}; - -enum SND_CARDS { - SND_FS = 0, - SND_MX, - SND_NC, - SND_MSIC -}; - -struct pcm_stream_info { - int str_id; - void *mad_substream; - void (*period_elapsed) (void *mad_substream); - unsigned long long buffer_ptr; - int sfreq; -}; - -struct snd_pmic_ops { - int card_status; - int master_mute; - int num_channel; - int input_dev_id; - int mute_status; - struct mutex lock; - int pb_on, pbhs_on; - int cap_on; - int output_dev_id; - int lineout_dev_id, line_out_names_cnt; - int prev_lineout_dev_id; - bool jack_interrupt_status; - int (*set_input_dev) (u8 value); - int (*set_output_dev) (u8 value); - int (*set_lineout_dev) (u8 value); - int (*set_mute) (int dev_id, u8 value); - int (*get_mute) (int dev_id, u8 *value); - - int (*set_vol) (int dev_id, int value); - int (*get_vol) (int dev_id, int *value); - - int (*init_card) (void); - int (*set_pcm_audio_params) - (int sfreq, int word_size , int num_channel); - int (*set_pcm_voice_params) (void); - int (*set_voice_port) (int status); - int (*set_audio_port) (int status); - - int (*power_up_pmic_pb) (unsigned int port); - int (*power_up_pmic_cp) (unsigned int port); - int (*power_down_pmic_pb) (unsigned int device); - int (*power_down_pmic_cp) (unsigned int device); - int (*power_down_pmic) (void); - void (*pmic_irq_cb) (void *cb_data, u8 value); - void (*pmic_irq_enable)(void *data); - int (*pmic_jack_enable) (void); - int (*pmic_get_mic_bias)(void *intelmaddata); - int (*pmic_set_headset_state)(int state); - - unsigned int hw_dmic_map[MFLD_MAX_HW_CH]; - unsigned int available_dmics; - int (*set_hw_dmic_route) (u8 index); - - int gpio_amp; -}; - -extern void sst_mad_send_jack_report(struct snd_jack *jack, - int buttonpressevent, - int status); - - -int intemad_set_headset_state(int state); -int intelmad_get_mic_bias(void); - -struct intel_sst_pcm_control { - int (*open) (struct snd_sst_params *str_param); - int (*device_control) (int cmd, void *arg); - int (*close) (unsigned int str_id); -}; -struct intel_sst_card_ops { - char *module_name; - unsigned int vendor_id; - struct intel_sst_pcm_control *pcm_control; - struct snd_pmic_ops *scard_ops; -}; - -/* modified for generic access */ -struct sc_reg_access { - u16 reg_addr; - u8 value; - u8 mask; -}; -enum sc_reg_access_type { - PMIC_READ = 0, - PMIC_WRITE, - PMIC_READ_MODIFY, -}; - -int register_sst_card(struct intel_sst_card_ops *card); -void unregister_sst_card(struct intel_sst_card_ops *card); -#endif /* __INTEL_SST_H__ */ diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c deleted file mode 100644 index 93b41a284d8..00000000000 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ /dev/null @@ -1,1460 +0,0 @@ -/* - * intel_sst_interface.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This driver exposes the audio engine functionalities to the ALSA - * and middleware. - * Upper layer interfaces (MAD driver, MMF) to SST driver - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/uio.h> -#include <linux/aio.h> -#include <linux/uaccess.h> -#include <linux/firmware.h> -#include <linux/pm_runtime.h> -#include <linux/ioctl.h> -#ifdef CONFIG_MRST_RAR_HANDLER -#include <linux/rar_register.h> -#include "../../../drivers/staging/memrar/memrar.h" -#endif -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - -#define AM_MODULE 1 -#define STREAM_MODULE 0 - - -/** -* intel_sst_check_device - checks SST device -* -* This utility function checks the state of SST device and downlaods FW if -* not done, or resumes the device if suspended -*/ - -static int intel_sst_check_device(void) -{ - int retval = 0; - if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) { - pr_warn("Sound card not available\n"); - return -EIO; - } - if (sst_drv_ctx->sst_state == SST_SUSPENDED) { - pr_debug("Resuming from Suspended state\n"); - retval = intel_sst_resume(sst_drv_ctx->pci); - if (retval) { - pr_debug("Resume Failed= %#x,abort\n", retval); - return retval; - } - } - - if (sst_drv_ctx->sst_state == SST_UN_INIT) { - /* FW is not downloaded */ - retval = sst_download_fw(); - if (retval) - return -ENODEV; - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { - retval = sst_drv_ctx->rx_time_slot_status; - if (retval != RX_TIMESLOT_UNINIT - && sst_drv_ctx->pmic_vendor != SND_NC) - sst_enable_rx_timeslot(retval); - } - } - return 0; -} - -/** - * intel_sst_open - opens a handle to driver - * - * @i_node: inode structure - * @file_ptr:pointer to file - * - * This function is called by OS when a user space component - * tries to get a driver handle. Only one handle at a time - * will be allowed - */ -int intel_sst_open(struct inode *i_node, struct file *file_ptr) -{ - unsigned int retval; - - mutex_lock(&sst_drv_ctx->stream_lock); - pm_runtime_get_sync(&sst_drv_ctx->pci->dev); - retval = intel_sst_check_device(); - if (retval) { - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - return retval; - } - - if (sst_drv_ctx->encoded_cnt < MAX_ENC_STREAM) { - struct ioctl_pvt_data *data = - kzalloc(sizeof(struct ioctl_pvt_data), GFP_KERNEL); - if (!data) { - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - return -ENOMEM; - } - - sst_drv_ctx->encoded_cnt++; - mutex_unlock(&sst_drv_ctx->stream_lock); - data->pvt_id = sst_assign_pvt_id(sst_drv_ctx); - data->str_id = 0; - file_ptr->private_data = (void *)data; - pr_debug("pvt_id handle = %d!\n", data->pvt_id); - } else { - retval = -EUSERS; - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - } - return retval; -} - -/** - * intel_sst_open_cntrl - opens a handle to driver - * - * @i_node: inode structure - * @file_ptr:pointer to file - * - * This function is called by OS when a user space component - * tries to get a driver handle to /dev/intel_sst_control. - * Only one handle at a time will be allowed - * This is for control operations only - */ -int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr) -{ - unsigned int retval; - - /* audio manager open */ - mutex_lock(&sst_drv_ctx->stream_lock); - pm_runtime_get_sync(&sst_drv_ctx->pci->dev); - retval = intel_sst_check_device(); - if (retval) { - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - return retval; - } - - if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) { - sst_drv_ctx->am_cnt++; - pr_debug("AM handle opened...\n"); - file_ptr->private_data = NULL; - } else { - retval = -EACCES; - pm_runtime_put(&sst_drv_ctx->pci->dev); - } - - mutex_unlock(&sst_drv_ctx->stream_lock); - return retval; -} - -/** - * intel_sst_release - releases a handle to driver - * - * @i_node: inode structure - * @file_ptr: pointer to file - * - * This function is called by OS when a user space component - * tries to release a driver handle. - */ -int intel_sst_release(struct inode *i_node, struct file *file_ptr) -{ - struct ioctl_pvt_data *data = file_ptr->private_data; - - pr_debug("Release called, closing app handle\n"); - mutex_lock(&sst_drv_ctx->stream_lock); - sst_drv_ctx->encoded_cnt--; - sst_drv_ctx->stream_cnt--; - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - free_stream_context(data->str_id); - kfree(data); - return 0; -} - -int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr) -{ - /* audio manager close */ - mutex_lock(&sst_drv_ctx->stream_lock); - sst_drv_ctx->am_cnt--; - pm_runtime_put(&sst_drv_ctx->pci->dev); - mutex_unlock(&sst_drv_ctx->stream_lock); - pr_debug("AM handle closed\n"); - return 0; -} - -/** -* intel_sst_mmap - mmaps a kernel buffer to user space for copying data -* -* @vma: vm area structure instance -* @file_ptr: pointer to file -* -* This function is called by OS when a user space component -* tries to get mmap memory from driver -*/ -int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma) -{ - int retval, length; - struct ioctl_pvt_data *data = - (struct ioctl_pvt_data *)file_ptr->private_data; - int str_id = data->str_id; - void *mem_area; - - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - - length = vma->vm_end - vma->vm_start; - pr_debug("called for stream %d length 0x%x\n", str_id, length); - - if (length > sst_drv_ctx->mmap_len) - return -ENOMEM; - if (!sst_drv_ctx->mmap_mem) - return -EIO; - - /* round it up to the page boundary */ - /*mem_area = (void *)((((unsigned long)sst_drv_ctx->mmap_mem) - + PAGE_SIZE - 1) & PAGE_MASK);*/ - mem_area = (void *) PAGE_ALIGN((unsigned int) sst_drv_ctx->mmap_mem); - - /* map the whole physically contiguous area in one piece */ - retval = remap_pfn_range(vma, - vma->vm_start, - virt_to_phys((void *)mem_area) >> PAGE_SHIFT, - length, - vma->vm_page_prot); - if (retval) - sst_drv_ctx->streams[str_id].mmapped = false; - else - sst_drv_ctx->streams[str_id].mmapped = true; - - pr_debug("mmap ret 0x%x\n", retval); - return retval; -} - -/* sets mmap data buffers to play/capture*/ -static int intel_sst_mmap_play_capture(u32 str_id, - struct snd_sst_mmap_buffs *mmap_buf) -{ - struct sst_stream_bufs *bufs; - int retval, i; - struct stream_info *stream; - struct snd_sst_mmap_buff_entry *buf_entry; - struct snd_sst_mmap_buff_entry *tmp_buf; - - pr_debug("called for str_id %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped != true) - return -EIO; - - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) { - return -EBADRQC; - } - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - - tmp_buf = kcalloc(mmap_buf->entries, sizeof(*tmp_buf), GFP_KERNEL); - if (!tmp_buf) - return -ENOMEM; - if (copy_from_user(tmp_buf, (void __user *)mmap_buf->buff, - mmap_buf->entries * sizeof(*tmp_buf))) { - retval = -EFAULT; - goto out_free; - } - - pr_debug("new buffers count %d status %d\n", - mmap_buf->entries, stream->status); - buf_entry = tmp_buf; - for (i = 0; i < mmap_buf->entries; i++) { - bufs = kzalloc(sizeof(*bufs), GFP_KERNEL); - if (!bufs) { - retval = -ENOMEM; - goto out_free; - } - bufs->size = buf_entry->size; - bufs->offset = buf_entry->offset; - bufs->addr = sst_drv_ctx->mmap_mem; - bufs->in_use = false; - buf_entry++; - /* locking here */ - mutex_lock(&stream->lock); - list_add_tail(&bufs->node, &stream->bufs); - mutex_unlock(&stream->lock); - } - - mutex_lock(&stream->lock); - stream->data_blk.condition = false; - stream->data_blk.ret_code = 0; - if (stream->status == STREAM_INIT && - stream->prev != STREAM_UN_INIT && - stream->need_draining != true) { - stream->prev = stream->status; - stream->status = STREAM_RUNNING; - if (stream->ops == STREAM_OPS_PLAYBACK) { - if (sst_play_frame(str_id) < 0) { - pr_warn("play frames fail\n"); - mutex_unlock(&stream->lock); - retval = -EIO; - goto out_free; - } - } else if (stream->ops == STREAM_OPS_CAPTURE) { - if (sst_capture_frame(str_id) < 0) { - pr_warn("capture frame fail\n"); - mutex_unlock(&stream->lock); - retval = -EIO; - goto out_free; - } - } - } - mutex_unlock(&stream->lock); - /* Block the call for reply */ - if (!list_empty(&stream->bufs)) { - stream->data_blk.on = true; - retval = sst_wait_interruptible(sst_drv_ctx, - &stream->data_blk); - } - - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec ioctl bytes = %d!!\n", retval); - -out_free: - kfree(tmp_buf); - return retval; -} - -/*sets user data buffers to play/capture*/ -static int intel_sst_play_capture(struct stream_info *stream, int str_id) -{ - int retval; - - stream->data_blk.ret_code = 0; - stream->data_blk.on = true; - stream->data_blk.condition = false; - - mutex_lock(&stream->lock); - if (stream->status == STREAM_INIT && stream->prev != STREAM_UN_INIT) { - /* stream is started */ - stream->prev = stream->status; - stream->status = STREAM_RUNNING; - } - - if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) { - /* stream is not started yet */ - pr_debug("Stream isn't in started state %d, prev %d\n", - stream->status, stream->prev); - } else if ((stream->status == STREAM_RUNNING || - stream->status == STREAM_PAUSED) && - stream->need_draining != true) { - /* stream is started */ - if (stream->ops == STREAM_OPS_PLAYBACK || - stream->ops == STREAM_OPS_PLAYBACK_DRM) { - if (sst_play_frame(str_id) < 0) { - pr_warn("play frames failed\n"); - mutex_unlock(&stream->lock); - return -EIO; - } - } else if (stream->ops == STREAM_OPS_CAPTURE) { - if (sst_capture_frame(str_id) < 0) { - pr_warn("capture frames failed\n"); - mutex_unlock(&stream->lock); - return -EIO; - } - } - } else { - mutex_unlock(&stream->lock); - return -EIO; - } - mutex_unlock(&stream->lock); - /* Block the call for reply */ - - retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk); - if (retval) { - stream->status = STREAM_INIT; - pr_debug("wait returned error...\n"); - } - return retval; -} - -/* fills kernel list with buffer addresses for SST DSP driver to process*/ -static int snd_sst_fill_kernel_list(struct stream_info *stream, - const struct iovec *iovec, unsigned long nr_segs, - struct list_head *copy_to_list) -{ - struct sst_stream_bufs *stream_bufs; - unsigned long index, mmap_len; - unsigned char __user *bufp; - unsigned long size, copied_size; - int retval = 0, add_to_list = 0; - static int sent_offset; - static unsigned long sent_index; - -#ifdef CONFIG_MRST_RAR_HANDLER - if (stream->ops == STREAM_OPS_PLAYBACK_DRM) { - for (index = stream->sg_index; index < nr_segs; index++) { - __u32 rar_handle; - struct sst_stream_bufs *stream_bufs = - kzalloc(sizeof(*stream_bufs), GFP_KERNEL); - - stream->sg_index = index; - if (!stream_bufs) - return -ENOMEM; - if (copy_from_user((void *) &rar_handle, - iovec[index].iov_base, - sizeof(__u32))) { - kfree(stream_bufs); - return -EFAULT; - } - stream_bufs->addr = (char *)rar_handle; - stream_bufs->in_use = false; - stream_bufs->size = iovec[0].iov_len; - /* locking here */ - mutex_lock(&stream->lock); - list_add_tail(&stream_bufs->node, &stream->bufs); - mutex_unlock(&stream->lock); - } - stream->sg_index = index; - return retval; - } -#endif - stream_bufs = kzalloc(sizeof(*stream_bufs), GFP_KERNEL); - if (!stream_bufs) - return -ENOMEM; - stream_bufs->addr = sst_drv_ctx->mmap_mem; - mmap_len = sst_drv_ctx->mmap_len; - stream_bufs->addr = sst_drv_ctx->mmap_mem; - bufp = stream->cur_ptr; - - copied_size = 0; - - if (!stream->sg_index) - sent_index = sent_offset = 0; - - for (index = stream->sg_index; index < nr_segs; index++) { - stream->sg_index = index; - if (!stream->cur_ptr) - bufp = iovec[index].iov_base; - - size = ((unsigned long)iovec[index].iov_base - + iovec[index].iov_len) - (unsigned long) bufp; - - if ((copied_size + size) > mmap_len) - size = mmap_len - copied_size; - - - if (stream->ops == STREAM_OPS_PLAYBACK) { - if (copy_from_user((void *) - (stream_bufs->addr + copied_size), - bufp, size)) { - /* Clean up the list and return error code */ - retval = -EFAULT; - break; - } - } else if (stream->ops == STREAM_OPS_CAPTURE) { - struct snd_sst_user_cap_list *entry = - kzalloc(sizeof(*entry), GFP_KERNEL); - - if (!entry) { - kfree(stream_bufs); - return -ENOMEM; - } - entry->iov_index = index; - entry->iov_offset = (unsigned long) bufp - - (unsigned long)iovec[index].iov_base; - entry->offset = copied_size; - entry->size = size; - list_add_tail(&entry->node, copy_to_list); - } - - stream->cur_ptr = bufp + size; - - if (((unsigned long)iovec[index].iov_base - + iovec[index].iov_len) < - ((unsigned long)iovec[index].iov_base)) { - pr_debug("Buffer overflows\n"); - kfree(stream_bufs); - return -EINVAL; - } - - if (((unsigned long)iovec[index].iov_base - + iovec[index].iov_len) == - (unsigned long)stream->cur_ptr) { - stream->cur_ptr = NULL; - stream->sg_index++; - } - - copied_size += size; - pr_debug("copied_size - %lx\n", copied_size); - if ((copied_size >= mmap_len) || - (stream->sg_index == nr_segs)) { - add_to_list = 1; - } - - if (add_to_list) { - stream_bufs->in_use = false; - stream_bufs->size = copied_size; - /* locking here */ - mutex_lock(&stream->lock); - list_add_tail(&stream_bufs->node, &stream->bufs); - mutex_unlock(&stream->lock); - break; - } - } - return retval; -} - -/* This function copies the captured data returned from SST DSP engine - * to the user buffers*/ -static int snd_sst_copy_userbuf_capture(struct stream_info *stream, - const struct iovec *iovec, - struct list_head *copy_to_list) -{ - struct snd_sst_user_cap_list *entry, *_entry; - struct sst_stream_bufs *kbufs = NULL, *_kbufs; - int retval = 0; - - /* copy sent buffers */ - pr_debug("capture stream copying to user now...\n"); - list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { - if (kbufs->in_use == true) { - /* copy to user */ - list_for_each_entry_safe(entry, _entry, - copy_to_list, node) { - if (copy_to_user(iovec[entry->iov_index].iov_base + entry->iov_offset, - kbufs->addr + entry->offset, - entry->size)) { - /* Clean up the list and return error */ - retval = -EFAULT; - break; - } - list_del(&entry->node); - kfree(entry); - } - } - } - pr_debug("end of cap copy\n"); - return retval; -} - -/* - * snd_sst_userbufs_play_cap - constructs the list from user buffers - * - * @iovec:pointer to iovec structure - * @nr_segs:number entries in the iovec structure - * @str_id:stream id - * @stream:pointer to stream_info structure - * - * This function will traverse the user list and copy the data to the kernel - * space buffers. - */ -static int snd_sst_userbufs_play_cap(const struct iovec *iovec, - unsigned long nr_segs, unsigned int str_id, - struct stream_info *stream) -{ - int retval; - LIST_HEAD(copy_to_list); - - - retval = snd_sst_fill_kernel_list(stream, iovec, nr_segs, - ©_to_list); - - retval = intel_sst_play_capture(stream, str_id); - if (retval < 0) - return retval; - - if (stream->ops == STREAM_OPS_CAPTURE) { - retval = snd_sst_copy_userbuf_capture(stream, iovec, - ©_to_list); - } - return retval; -} - -/* This function is common function across read/write - for user buffers called from system calls*/ -static int intel_sst_read_write(unsigned int str_id, char __user *buf, - size_t count) -{ - int retval; - struct stream_info *stream; - struct iovec iovec; - unsigned long nr_segs; - - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped == true) { - pr_warn("user write and stream is mapped\n"); - return -EIO; - } - if (!count) - return -EINVAL; - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - /* copy user buf details */ - pr_debug("new buffers %p, copy size %d, status %d\n" , - buf, (int) count, (int) stream->status); - - stream->buf_type = SST_BUF_USER_STATIC; - iovec.iov_base = buf; - iovec.iov_len = count; - nr_segs = 1; - - do { - retval = snd_sst_userbufs_play_cap( - &iovec, nr_segs, str_id, stream); - if (retval < 0) - break; - - } while (stream->sg_index < nr_segs); - - stream->sg_index = 0; - stream->cur_ptr = NULL; - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec bytes = %d!!\n", retval); - return retval; -} - -/*** - * intel_sst_write - This function is called when user tries to play out data - * - * @file_ptr:pointer to file - * @buf:user buffer to be played out - * @count:size of tthe buffer - * @offset:offset to start from - * - * writes the encoded data into DSP - */ -int intel_sst_write(struct file *file_ptr, const char __user *buf, - size_t count, loff_t *offset) -{ - struct ioctl_pvt_data *data = file_ptr->private_data; - int str_id = data->str_id; - struct stream_info *stream = &sst_drv_ctx->streams[str_id]; - - pr_debug("called for %d\n", str_id); - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) { - return -EBADRQC; - } - return intel_sst_read_write(str_id, (char __user *)buf, count); -} - -/* - * intel_sst_aio_write - write buffers - * - * @kiocb:pointer to a structure containing file pointer - * @iov:list of user buffer to be played out - * @nr_segs:number of entries - * @offset:offset to start from - * - * This function is called when user tries to play out multiple data buffers - */ -ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, - unsigned long nr_segs, loff_t offset) -{ - int retval; - struct ioctl_pvt_data *data = kiocb->ki_filp->private_data; - int str_id = data->str_id; - struct stream_info *stream; - - pr_debug("entry - %ld\n", nr_segs); - - if (is_sync_kiocb(kiocb) == false) - return -EINVAL; - - pr_debug("called for str_id %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped == true) - return -EIO; - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) { - return -EBADRQC; - } - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - pr_debug("new segs %ld, offset %d, status %d\n" , - nr_segs, (int) offset, (int) stream->status); - stream->buf_type = SST_BUF_USER_STATIC; - do { - retval = snd_sst_userbufs_play_cap(iov, nr_segs, - str_id, stream); - if (retval < 0) - break; - - } while (stream->sg_index < nr_segs); - - stream->sg_index = 0; - stream->cur_ptr = NULL; - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec bytes = %d!!\n", retval); - return retval; -} - -/* - * intel_sst_read - read the encoded data - * - * @file_ptr: pointer to file - * @buf: user buffer to be filled with captured data - * @count: size of tthe buffer - * @offset: offset to start from - * - * This function is called when user tries to capture data - */ -int intel_sst_read(struct file *file_ptr, char __user *buf, - size_t count, loff_t *offset) -{ - struct ioctl_pvt_data *data = file_ptr->private_data; - int str_id = data->str_id; - struct stream_info *stream = &sst_drv_ctx->streams[str_id]; - - pr_debug("called for %d\n", str_id); - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) - return -EBADRQC; - return intel_sst_read_write(str_id, buf, count); -} - -/* - * intel_sst_aio_read - aio read - * - * @kiocb: pointer to a structure containing file pointer - * @iov: list of user buffer to be filled with captured - * @nr_segs: number of entries - * @offset: offset to start from - * - * This function is called when user tries to capture out multiple data buffers - */ -ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, - unsigned long nr_segs, loff_t offset) -{ - int retval; - struct ioctl_pvt_data *data = kiocb->ki_filp->private_data; - int str_id = data->str_id; - struct stream_info *stream; - - pr_debug("entry - %ld\n", nr_segs); - - if (is_sync_kiocb(kiocb) == false) { - pr_debug("aio_read from user space is not allowed\n"); - return -EINVAL; - } - - pr_debug("called for str_id %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return -EINVAL; - stream = &sst_drv_ctx->streams[str_id]; - if (stream->mmapped == true) - return -EIO; - if (stream->status == STREAM_UN_INIT || - stream->status == STREAM_DECODE) - return -EBADRQC; - stream->curr_bytes = 0; - stream->cumm_bytes = 0; - - pr_debug("new segs %ld, offset %d, status %d\n" , - nr_segs, (int) offset, (int) stream->status); - stream->buf_type = SST_BUF_USER_STATIC; - do { - retval = snd_sst_userbufs_play_cap(iov, nr_segs, - str_id, stream); - if (retval < 0) - break; - - } while (stream->sg_index < nr_segs); - - stream->sg_index = 0; - stream->cur_ptr = NULL; - if (retval >= 0) - retval = stream->cumm_bytes; - pr_debug("end of play/rec bytes = %d!!\n", retval); - return retval; -} - -/* sst_print_stream_params - prints the stream parameters (debug fn)*/ -static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm) -{ - pr_debug("codec params:result = %d\n", - get_prm->codec_params.result); - pr_debug("codec params:stream = %d\n", - get_prm->codec_params.stream_id); - pr_debug("codec params:codec = %d\n", - get_prm->codec_params.codec); - pr_debug("codec params:ops = %d\n", - get_prm->codec_params.ops); - pr_debug("codec params:stream_type = %d\n", - get_prm->codec_params.stream_type); - pr_debug("pcmparams:sfreq = %d\n", - get_prm->pcm_params.sfreq); - pr_debug("pcmparams:num_chan = %d\n", - get_prm->pcm_params.num_chan); - pr_debug("pcmparams:pcm_wd_sz = %d\n", - get_prm->pcm_params.pcm_wd_sz); - return; -} - -/** - * sst_create_algo_ipc - create ipc msg for algorithm parameters - * - * @algo_params: Algorithm parameters - * @msg: post msg pointer - * - * This function is called to create ipc msg - */ -int sst_create_algo_ipc(struct snd_ppp_params *algo_params, - struct ipc_post **msg) -{ - if (sst_create_large_msg(msg)) - return -ENOMEM; - sst_fill_header(&(*msg)->header, - IPC_IA_ALG_PARAMS, 1, algo_params->str_id); - (*msg)->header.part.data = sizeof(u32) + - sizeof(*algo_params) + algo_params->size; - memcpy((*msg)->mailbox_data, &(*msg)->header, sizeof(u32)); - memcpy((*msg)->mailbox_data + sizeof(u32), - algo_params, sizeof(*algo_params)); - return 0; -} - -/** - * sst_send_algo_ipc - send ipc msg for algorithm parameters - * - * @msg: post msg pointer - * - * This function is called to send ipc msg - */ -int sst_send_algo_ipc(struct ipc_post **msg) -{ - sst_drv_ctx->ppp_params_blk.condition = false; - sst_drv_ctx->ppp_params_blk.ret_code = 0; - sst_drv_ctx->ppp_params_blk.on = true; - sst_drv_ctx->ppp_params_blk.data = NULL; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - return sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->ppp_params_blk, SST_BLOCK_TIMEOUT); -} - -/** - * intel_sst_ioctl_dsp - receives the device ioctl's - * - * @cmd:Ioctl cmd - * @arg:data - * - * This function is called when a user space component - * sends a DSP Ioctl to SST driver - */ -long intel_sst_ioctl_dsp(unsigned int cmd, unsigned long arg) -{ - int retval = 0; - struct snd_ppp_params algo_params; - struct snd_ppp_params *algo_params_copied; - struct ipc_post *msg; - - switch (_IOC_NR(cmd)) { - case _IOC_NR(SNDRV_SST_SET_ALGO): - if (copy_from_user(&algo_params, (void __user *)arg, - sizeof(algo_params))) - return -EFAULT; - if (algo_params.size > SST_MAILBOX_SIZE) - return -EMSGSIZE; - - pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", - algo_params.algo_id, algo_params.str_id, - algo_params.enable, algo_params.size); - retval = sst_create_algo_ipc(&algo_params, &msg); - if (retval) - break; - algo_params.reserved = 0; - if (copy_from_user(msg->mailbox_data + sizeof(algo_params), - algo_params.params, algo_params.size)) - return -EFAULT; - - retval = sst_send_algo_ipc(&msg); - if (retval) { - pr_debug("Error in sst_set_algo = %d\n", retval); - retval = -EIO; - } - break; - - case _IOC_NR(SNDRV_SST_GET_ALGO): - if (copy_from_user(&algo_params, (void __user *)arg, - sizeof(algo_params))) - return -EFAULT; - pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", - algo_params.algo_id, algo_params.str_id, - algo_params.enable, algo_params.size); - retval = sst_create_algo_ipc(&algo_params, &msg); - if (retval) - break; - algo_params.reserved = 1; - retval = sst_send_algo_ipc(&msg); - if (retval) { - pr_debug("Error in sst_get_algo = %d\n", retval); - retval = -EIO; - break; - } - algo_params_copied = (struct snd_ppp_params *) - sst_drv_ctx->ppp_params_blk.data; - if (algo_params_copied->size > algo_params.size) { - pr_debug("mem insufficient to copy\n"); - retval = -EMSGSIZE; - goto free_mem; - } else { - char __user *tmp; - - if (copy_to_user(algo_params.params, - algo_params_copied->params, - algo_params_copied->size)) { - retval = -EFAULT; - goto free_mem; - } - tmp = (char __user *)arg + offsetof( - struct snd_ppp_params, size); - if (copy_to_user(tmp, &algo_params_copied->size, - sizeof(__u32))) { - retval = -EFAULT; - goto free_mem; - } - - } -free_mem: - kfree(algo_params_copied->params); - kfree(algo_params_copied); - break; - } - return retval; -} - - -int sst_ioctl_tuning_params(unsigned long arg) -{ - struct snd_sst_tuning_params params; - struct ipc_post *msg; - - if (copy_from_user(¶ms, (void __user *)arg, sizeof(params))) - return -EFAULT; - if (params.size > SST_MAILBOX_SIZE) - return -ENOMEM; - pr_debug("Parameter %d, Stream %d, Size %d\n", params.type, - params.str_id, params.size); - if (sst_create_large_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, IPC_IA_TUNING_PARAMS, 1, params.str_id); - msg->header.part.data = sizeof(u32) + sizeof(params) + params.size; - memcpy(msg->mailbox_data, &msg->header.full, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), ¶ms, sizeof(params)); - if (copy_from_user(msg->mailbox_data + sizeof(params), - (void __user *)(unsigned long)params.addr, - params.size)) { - kfree(msg->mailbox_data); - kfree(msg); - return -EFAULT; - } - return sst_send_algo_ipc(&msg); -} -/** - * intel_sst_ioctl - receives the device ioctl's - * @file_ptr:pointer to file - * @cmd:Ioctl cmd - * @arg:data - * - * This function is called by OS when a user space component - * sends an Ioctl to SST driver - */ -long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) -{ - int retval = 0; - struct ioctl_pvt_data *data = NULL; - int str_id = 0, minor = 0; - - data = file_ptr->private_data; - if (data) { - minor = 0; - str_id = data->str_id; - } else - minor = 1; - - if (sst_drv_ctx->sst_state != SST_FW_RUNNING) - return -EBUSY; - - switch (_IOC_NR(cmd)) { - case _IOC_NR(SNDRV_SST_STREAM_PAUSE): - pr_debug("IOCTL_PAUSE received for %d!\n", str_id); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_pause_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_RESUME): - pr_debug("SNDRV_SST_IOCTL_RESUME received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_resume_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): { - struct snd_sst_params str_param; - - pr_debug("IOCTL_SET_PARAMS received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - - if (copy_from_user(&str_param, (void __user *)arg, - sizeof(str_param))) { - retval = -EFAULT; - break; - } - - if (!str_id) { - - retval = sst_get_stream(&str_param); - if (retval > 0) { - struct stream_info *str_info; - char __user *dest; - - sst_drv_ctx->stream_cnt++; - data->str_id = retval; - str_info = &sst_drv_ctx->streams[retval]; - str_info->src = SST_DRV; - dest = (char __user *)arg + offsetof(struct snd_sst_params, stream_id); - retval = copy_to_user(dest, &retval, sizeof(__u32)); - if (retval) - retval = -EFAULT; - } else { - if (retval == -SST_ERR_INVALID_PARAMS) - retval = -EINVAL; - } - } else { - pr_debug("SET_STREAM_PARAMS received!\n"); - /* allocated set params only */ - retval = sst_set_stream_param(str_id, &str_param); - /* Block the call for reply */ - if (!retval) { - int sfreq = 0, word_size = 0, num_channel = 0; - sfreq = str_param.sparams.uc.pcm_params.sfreq; - word_size = str_param.sparams.uc.pcm_params.pcm_wd_sz; - num_channel = str_param.sparams.uc.pcm_params.num_chan; - if (str_param.ops == STREAM_OPS_CAPTURE) { - sst_drv_ctx->scard_ops->\ - set_pcm_audio_params(sfreq, - word_size, num_channel); - } - } - } - break; - } - case _IOC_NR(SNDRV_SST_SET_VOL): { - struct snd_sst_vol set_vol; - - if (copy_from_user(&set_vol, (void __user *)arg, - sizeof(set_vol))) { - pr_debug("copy failed\n"); - retval = -EFAULT; - break; - } - pr_debug("SET_VOLUME received for %d!\n", - set_vol.stream_id); - if (minor == STREAM_MODULE && set_vol.stream_id == 0) { - pr_debug("invalid operation!\n"); - retval = -EPERM; - break; - } - retval = sst_set_vol(&set_vol); - break; - } - case _IOC_NR(SNDRV_SST_GET_VOL): { - struct snd_sst_vol get_vol; - - if (copy_from_user(&get_vol, (void __user *)arg, - sizeof(get_vol))) { - retval = -EFAULT; - break; - } - pr_debug("IOCTL_GET_VOLUME received for stream = %d!\n", - get_vol.stream_id); - if (minor == STREAM_MODULE && get_vol.stream_id == 0) { - pr_debug("invalid operation!\n"); - retval = -EPERM; - break; - } - retval = sst_get_vol(&get_vol); - if (retval) { - retval = -EIO; - break; - } - pr_debug("id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n", - get_vol.stream_id, get_vol.volume, - get_vol.ramp_duration, get_vol.ramp_type); - if (copy_to_user((struct snd_sst_vol __user *)arg, - &get_vol, sizeof(get_vol))) { - retval = -EFAULT; - break; - } - /*sst_print_get_vol_info(str_id, &get_vol);*/ - break; - } - - case _IOC_NR(SNDRV_SST_MUTE): { - struct snd_sst_mute set_mute; - - if (copy_from_user(&set_mute, (void __user *)arg, - sizeof(set_mute))) { - retval = -EFAULT; - break; - } - pr_debug("SNDRV_SST_SET_VOLUME received for %d!\n", - set_mute.stream_id); - if (minor == STREAM_MODULE && set_mute.stream_id == 0) { - retval = -EPERM; - break; - } - retval = sst_set_mute(&set_mute); - break; - } - case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): { - struct snd_sst_get_stream_params get_params; - - pr_debug("IOCTL_GET_PARAMS received!\n"); - if (minor != 0) { - retval = -EBADRQC; - break; - } - - retval = sst_get_stream_params(str_id, &get_params); - if (retval) { - retval = -EIO; - break; - } - if (copy_to_user((struct snd_sst_get_stream_params __user *)arg, - &get_params, sizeof(get_params))) { - retval = -EFAULT; - break; - } - sst_print_stream_params(&get_params); - break; - } - - case _IOC_NR(SNDRV_SST_MMAP_PLAY): - case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): { - struct snd_sst_mmap_buffs mmap_buf; - - pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - if (copy_from_user(&mmap_buf, (void __user *)arg, - sizeof(mmap_buf))) { - retval = -EFAULT; - break; - } - retval = intel_sst_mmap_play_capture(str_id, &mmap_buf); - break; - } - case _IOC_NR(SNDRV_SST_STREAM_DROP): - pr_debug("SNDRV_SST_IOCTL_DROP received!\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - retval = sst_drop_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): { - struct snd_sst_tstamp tstamp = {0}; - unsigned long long time, freq, mod; - - pr_debug("SNDRV_SST_STREAM_GET_TSTAMP received!\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - memcpy_fromio(&tstamp, - sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp), - sizeof(tstamp)); - time = tstamp.samples_rendered; - freq = (unsigned long long) tstamp.sampling_frequency; - time = time * 1000; /* converting it to ms */ - mod = do_div(time, freq); - if (copy_to_user((void __user *)arg, &time, - sizeof(unsigned long long))) - retval = -EFAULT; - break; - } - - case _IOC_NR(SNDRV_SST_STREAM_START):{ - struct stream_info *stream; - - pr_debug("SNDRV_SST_STREAM_START received!\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - retval = sst_validate_strid(str_id); - if (retval) - break; - stream = &sst_drv_ctx->streams[str_id]; - mutex_lock(&stream->lock); - if (stream->status == STREAM_INIT && - stream->need_draining != true) { - stream->prev = stream->status; - stream->status = STREAM_RUNNING; - if (stream->ops == STREAM_OPS_PLAYBACK || - stream->ops == STREAM_OPS_PLAYBACK_DRM) { - retval = sst_play_frame(str_id); - } else if (stream->ops == STREAM_OPS_CAPTURE) - retval = sst_capture_frame(str_id); - else { - retval = -EINVAL; - mutex_unlock(&stream->lock); - break; - } - if (retval < 0) { - stream->status = STREAM_INIT; - mutex_unlock(&stream->lock); - break; - } - } else { - retval = -EINVAL; - } - mutex_unlock(&stream->lock); - break; - } - - case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): { - struct snd_sst_target_device target_device; - - pr_debug("SET_TARGET_DEVICE received!\n"); - if (copy_from_user(&target_device, (void __user *)arg, - sizeof(target_device))) { - retval = -EFAULT; - break; - } - if (minor != AM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_target_device_select(&target_device); - break; - } - - case _IOC_NR(SNDRV_SST_DRIVER_INFO): { - struct snd_sst_driver_info info; - - pr_debug("SNDRV_SST_DRIVER_INFO received\n"); - info.version = SST_VERSION_NUM; - /* hard coding, shud get sumhow later */ - info.active_pcm_streams = sst_drv_ctx->stream_cnt - - sst_drv_ctx->encoded_cnt; - info.active_enc_streams = sst_drv_ctx->encoded_cnt; - info.max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM; - info.max_enc_streams = MAX_ENC_STREAM; - info.buf_per_stream = sst_drv_ctx->mmap_len; - if (copy_to_user((void __user *)arg, &info, - sizeof(info))) - retval = -EFAULT; - break; - } - - case _IOC_NR(SNDRV_SST_STREAM_DECODE): { - struct snd_sst_dbufs param; - struct snd_sst_dbufs dbufs_local; - struct snd_sst_buffs ibufs, obufs; - struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp; - char __user *dest; - - pr_debug("SNDRV_SST_STREAM_DECODE received\n"); - if (minor != STREAM_MODULE) { - retval = -EBADRQC; - break; - } - if (copy_from_user(¶m, (void __user *)arg, - sizeof(param))) { - retval = -EFAULT; - break; - } - - dbufs_local.input_bytes_consumed = param.input_bytes_consumed; - dbufs_local.output_bytes_produced = - param.output_bytes_produced; - - if (copy_from_user(&ibufs, (void __user *)param.ibufs, sizeof(ibufs))) { - retval = -EFAULT; - break; - } - if (copy_from_user(&obufs, (void __user *)param.obufs, sizeof(obufs))) { - retval = -EFAULT; - break; - } - - ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL); - obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL); - if (!ibuf_tmp || !obuf_tmp) { - retval = -ENOMEM; - goto free_iobufs; - } - - if (copy_from_user(ibuf_tmp, (void __user *)ibufs.buff_entry, - ibufs.entries * sizeof(*ibuf_tmp))) { - retval = -EFAULT; - goto free_iobufs; - } - ibufs.buff_entry = ibuf_tmp; - dbufs_local.ibufs = &ibufs; - - if (copy_from_user(obuf_tmp, (void __user *)obufs.buff_entry, - obufs.entries * sizeof(*obuf_tmp))) { - retval = -EFAULT; - goto free_iobufs; - } - obufs.buff_entry = obuf_tmp; - dbufs_local.obufs = &obufs; - - retval = sst_decode(str_id, &dbufs_local); - if (retval) { - retval = -EAGAIN; - goto free_iobufs; - } - - dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed); - if (copy_to_user(dest, - &dbufs_local.input_bytes_consumed, - sizeof(unsigned long long))) { - retval = -EFAULT; - goto free_iobufs; - } - - dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed); - if (copy_to_user(dest, - &dbufs_local.output_bytes_produced, - sizeof(unsigned long long))) { - retval = -EFAULT; - goto free_iobufs; - } -free_iobufs: - kfree(ibuf_tmp); - kfree(obuf_tmp); - break; - } - - case _IOC_NR(SNDRV_SST_STREAM_DRAIN): - pr_debug("SNDRV_SST_STREAM_DRAIN received\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - retval = sst_drain_stream(str_id); - break; - - case _IOC_NR(SNDRV_SST_STREAM_BYTES_DECODED): { - unsigned long long __user *bytes = (unsigned long long __user *)arg; - struct snd_sst_tstamp tstamp = {0}; - - pr_debug("STREAM_BYTES_DECODED received!\n"); - if (minor != STREAM_MODULE) { - retval = -EINVAL; - break; - } - memcpy_fromio(&tstamp, - sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp), - sizeof(tstamp)); - if (copy_to_user(bytes, &tstamp.bytes_processed, - sizeof(*bytes))) - retval = -EFAULT; - break; - } - case _IOC_NR(SNDRV_SST_FW_INFO): { - struct snd_sst_fw_info *fw_info; - - pr_debug("SNDRV_SST_FW_INFO received\n"); - - fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC); - if (!fw_info) { - retval = -ENOMEM; - break; - } - retval = sst_get_fw_info(fw_info); - if (retval) { - retval = -EIO; - kfree(fw_info); - break; - } - if (copy_to_user((struct snd_sst_dbufs __user *)arg, - fw_info, sizeof(*fw_info))) { - kfree(fw_info); - retval = -EFAULT; - break; - } - /*sst_print_fw_info(fw_info);*/ - kfree(fw_info); - break; - } - case _IOC_NR(SNDRV_SST_GET_ALGO): - case _IOC_NR(SNDRV_SST_SET_ALGO): - if (minor != AM_MODULE) { - retval = -EBADRQC; - break; - } - retval = intel_sst_ioctl_dsp(cmd, arg); - break; - - case _IOC_NR(SNDRV_SST_TUNING_PARAMS): - if (minor != AM_MODULE) { - retval = -EBADRQC; - break; - } - retval = sst_ioctl_tuning_params(arg); - break; - - default: - retval = -EINVAL; - } - pr_debug("intel_sst_ioctl:complete ret code = %d\n", retval); - return retval; -} - diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h deleted file mode 100644 index 870981ba3c9..00000000000 --- a/drivers/staging/intel_sst/intel_sst_common.h +++ /dev/null @@ -1,623 +0,0 @@ -#ifndef __INTEL_SST_COMMON_H__ -#define __INTEL_SST_COMMON_H__ -/* - * intel_sst_common.h - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corporation - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Common private declarations for SST - */ - -#define SST_DRIVER_VERSION "1.2.17" -#define SST_VERSION_NUM 0x1217 - -/* driver names */ -#define SST_DRV_NAME "intel_sst_driver" -#define SST_MRST_PCI_ID 0x080A -#define SST_MFLD_PCI_ID 0x082F -#define PCI_ID_LENGTH 4 -#define SST_SUSPEND_DELAY 2000 -#define FW_CONTEXT_MEM (64*1024) - -enum sst_states { - SST_FW_LOADED = 1, - SST_FW_RUNNING, - SST_UN_INIT, - SST_ERROR, - SST_SUSPENDED -}; - -#define MAX_ACTIVE_STREAM 3 -#define MAX_ENC_STREAM 1 -#define MAX_AM_HANDLES 1 -#define ALLOC_TIMEOUT 5000 -/* SST numbers */ -#define SST_BLOCK_TIMEOUT 5000 -#define TARGET_DEV_BLOCK_TIMEOUT 5000 - -#define BLOCK_UNINIT -1 -#define RX_TIMESLOT_UNINIT -1 - -/* SST register map */ -#define SST_CSR 0x00 -#define SST_PISR 0x08 -#define SST_PIMR 0x10 -#define SST_ISRX 0x18 -#define SST_IMRX 0x28 -#define SST_IPCX 0x38 /* IPC IA-SST */ -#define SST_IPCD 0x40 /* IPC SST-IA */ -#define SST_ISRD 0x20 /* dummy register for shim workaround */ -#define SST_SHIM_SIZE 0X44 - -#define SPI_MODE_ENABLE_BASE_ADDR 0xffae4000 -#define FW_SIGNATURE_SIZE 4 - -/* PMIC and SST hardware states */ -enum sst_mad_states { - SND_MAD_UN_INIT = 0, - SND_MAD_INIT_DONE, -}; - -/* stream states */ -enum sst_stream_states { - STREAM_UN_INIT = 0, /* Freed/Not used stream */ - STREAM_RUNNING = 1, /* Running */ - STREAM_PAUSED = 2, /* Paused stream */ - STREAM_DECODE = 3, /* stream is in decoding only state */ - STREAM_INIT = 4, /* stream init, waiting for data */ -}; - - -enum sst_ram_type { - SST_IRAM = 1, - SST_DRAM = 2, -}; -/* SST shim registers to structure mapping */ -union config_status_reg { - struct { - u32 mfld_strb:1; - u32 sst_reset:1; - u32 hw_rsvd:3; - u32 sst_clk:2; - u32 bypass:3; - u32 run_stall:1; - u32 rsvd1:2; - u32 strb_cntr_rst:1; - u32 rsvd:18; - } part; - u32 full; -}; - -union interrupt_reg { - struct { - u32 done_interrupt:1; - u32 busy_interrupt:1; - u32 rsvd:30; - } part; - u32 full; -}; - -union sst_pisr_reg { - struct { - u32 pssp0:1; - u32 pssp1:1; - u32 rsvd0:3; - u32 dmac:1; - u32 rsvd1:26; - } part; - u32 full; -}; - -union sst_pimr_reg { - struct { - u32 ssp0:1; - u32 ssp1:1; - u32 rsvd0:3; - u32 dmac:1; - u32 rsvd1:10; - u32 ssp0_sc:1; - u32 ssp1_sc:1; - u32 rsvd2:3; - u32 dmac_sc:1; - u32 rsvd3:10; - } part; - u32 full; -}; - - -struct sst_stream_bufs { - struct list_head node; - u32 size; - const char *addr; - u32 data_copied; - bool in_use; - u32 offset; -}; - -struct snd_sst_user_cap_list { - unsigned int iov_index; /* index of iov */ - unsigned long iov_offset; /* offset in iov */ - unsigned long offset; /* offset in kmem */ - unsigned long size; /* size copied */ - struct list_head node; -}; -/* -This structure is used to block a user/fw data call to another -fw/user call -*/ -struct sst_block { - bool condition; /* condition for blocking check */ - int ret_code; /* ret code when block is released */ - void *data; /* data to be appsed for block if any */ - bool on; -}; - -enum snd_sst_buf_type { - SST_BUF_USER_STATIC = 1, - SST_BUF_USER_DYNAMIC, - SST_BUF_MMAP_STATIC, - SST_BUF_MMAP_DYNAMIC, -}; - -enum snd_src { - SST_DRV = 1, - MAD_DRV = 2 -}; - -/** - * struct stream_info - structure that holds the stream information - * - * @status : stream current state - * @prev : stream prev state - * @codec : stream codec - * @sst_id : stream id - * @ops : stream operation pb/cp/drm... - * @bufs: stream buffer list - * @lock : stream mutex for protecting state - * @pcm_lock : spinlock for pcm path only - * @mmapped : is stream mmapped - * @sg_index : current stream user buffer index - * @cur_ptr : stream user buffer pointer - * @buf_entry : current user buffer - * @data_blk : stream block for data operations - * @ctrl_blk : stream block for ctrl operations - * @buf_type : stream user buffer type - * @pcm_substream : PCM substream - * @period_elapsed : PCM period elapsed callback - * @sfreq : stream sampling freq - * @decode_ibuf : Decoded i/p buffers pointer - * @decode_obuf : Decoded o/p buffers pointer - * @decode_isize : Decoded i/p buffers size - * @decode_osize : Decoded o/p buffers size - * @decode_ibuf_type : Decoded i/p buffer type - * @decode_obuf_type : Decoded o/p buffer type - * @idecode_alloc : Decode alloc index - * @need_draining : stream set for drain - * @str_type : stream type - * @curr_bytes : current bytes decoded - * @cumm_bytes : cummulative bytes decoded - * @str_type : stream type - * @src : stream source - * @device : output device type (medfield only) - * @pcm_slot : pcm slot value - */ -struct stream_info { - unsigned int status; - unsigned int prev; - u8 codec; - unsigned int sst_id; - unsigned int ops; - struct list_head bufs; - struct mutex lock; /* mutex */ - spinlock_t pcm_lock; - bool mmapped; - unsigned int sg_index; /* current buf Index */ - unsigned char __user *cur_ptr; /* Current static bufs */ - struct snd_sst_buf_entry __user *buf_entry; - struct sst_block data_blk; /* stream ops block */ - struct sst_block ctrl_blk; /* stream control cmd block */ - enum snd_sst_buf_type buf_type; - void *pcm_substream; - void (*period_elapsed) (void *pcm_substream); - unsigned int sfreq; - void *decode_ibuf, *decode_obuf; - unsigned int decode_isize, decode_osize; - u8 decode_ibuf_type, decode_obuf_type; - unsigned int idecode_alloc; - unsigned int need_draining; - unsigned int str_type; - u32 curr_bytes; - u32 cumm_bytes; - u32 src; - enum snd_sst_audio_device_type device; - u8 pcm_slot; -}; - -/* - * struct stream_alloc_bloc - this structure is used for blocking the user's - * alloc calls to fw's response to alloc calls - * - * @sst_id : session id of blocked stream - * @ops_block : ops block struture - */ -struct stream_alloc_block { - int sst_id; /* session id of blocked stream */ - struct sst_block ops_block; /* ops block struture */ -}; - -#define SST_FW_SIGN "$SST" -#define SST_FW_LIB_SIGN "$LIB" - -/* - * struct fw_header - FW file headers - * - * @signature : FW signature - * @modules : # of modules - * @file_format : version of header format - * @reserved : reserved fields - */ -struct fw_header { - unsigned char signature[FW_SIGNATURE_SIZE]; /* FW signature */ - u32 file_size; /* size of fw minus this header */ - u32 modules; /* # of modules */ - u32 file_format; /* version of header format */ - u32 reserved[4]; -}; - -struct fw_module_header { - unsigned char signature[FW_SIGNATURE_SIZE]; /* module signature */ - u32 mod_size; /* size of module */ - u32 blocks; /* # of blocks */ - u32 type; /* codec type, pp lib */ - u32 entry_point; -}; - -struct dma_block_info { - enum sst_ram_type type; /* IRAM/DRAM */ - u32 size; /* Bytes */ - u32 ram_offset; /* Offset in I/DRAM */ - u32 rsvd; /* Reserved field */ -}; - -struct ioctl_pvt_data { - int str_id; - int pvt_id; -}; - -struct sst_ipc_msg_wq { - union ipc_header header; - char mailbox[SST_MAILBOX_SIZE]; - struct work_struct wq; -}; - -struct mad_ops_wq { - int stream_id; - enum sst_controls control_op; - struct work_struct wq; - -}; - -#define SST_MMAP_PAGES (640*1024 / PAGE_SIZE) -#define SST_MMAP_STEP (40*1024 / PAGE_SIZE) - -/*** - * struct intel_sst_drv - driver ops - * - * @pmic_state : pmic state - * @pmic_vendor : pmic vendor detected - * @sst_state : current sst device state - * @pci_id : PCI device id loaded - * @shim : SST shim pointer - * @mailbox : SST mailbox pointer - * @iram : SST IRAM pointer - * @dram : SST DRAM pointer - * @shim_phy_add : SST shim phy addr - * @ipc_dispatch_list : ipc messages dispatched - * @ipc_post_msg_wq : wq to post IPC messages context - * @ipc_process_msg : wq to process msgs from FW context - * @ipc_process_reply : wq to process reply from FW context - * @ipc_post_msg : wq to post reply from FW context - * @mad_ops : MAD driver operations registered - * @mad_wq : MAD driver wq - * @post_msg_wq : wq to post IPC messages - * @process_msg_wq : wq to process msgs from FW - * @process_reply_wq : wq to process reply from FW - * @streams : sst stream contexts - * @alloc_block : block structure for alloc - * @tgt_dev_blk : block structure for target device - * @fw_info_blk : block structure for fw info block - * @vol_info_blk : block structure for vol info block - * @mute_info_blk : block structure for mute info block - * @hs_info_blk : block structure for hs info block - * @list_lock : sst driver list lock (deprecated) - * @list_spin_lock : sst driver spin lock block - * @scard_ops : sst card ops - * @pci : sst pci device struture - * @active_streams : sst active streams - * @sst_lock : sst device lock - * @stream_lock : sst stream lock - * @unique_id : sst unique id - * @stream_cnt : total sst active stream count - * @pb_streams : total active pb streams - * @cp_streams : total active cp streams - * @lpe_stalled : lpe stall status - * @pmic_port_instance : active pmic port instance - * @rx_time_slot_status : active rx slot - * @lpaudio_start : lpaudio status - * @audio_start : audio status - * @devt_d : pointer to /dev/lpe node - * @devt_c : pointer to /dev/lpe_ctrl node - * @max_streams : max streams allowed - */ -struct intel_sst_drv { - bool pmic_state; - int pmic_vendor; - int sst_state; - unsigned int pci_id; - void __iomem *shim; - void __iomem *mailbox; - void __iomem *iram; - void __iomem *dram; - unsigned int shim_phy_add; - struct list_head ipc_dispatch_list; - struct work_struct ipc_post_msg_wq; - struct sst_ipc_msg_wq ipc_process_msg; - struct sst_ipc_msg_wq ipc_process_reply; - struct sst_ipc_msg_wq ipc_post_msg; - struct mad_ops_wq mad_ops; - wait_queue_head_t wait_queue; - struct workqueue_struct *mad_wq; - struct workqueue_struct *post_msg_wq; - struct workqueue_struct *process_msg_wq; - struct workqueue_struct *process_reply_wq; - - struct stream_info streams[MAX_NUM_STREAMS]; - struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM]; - struct sst_block tgt_dev_blk, fw_info_blk, ppp_params_blk, - vol_info_blk, mute_info_blk, hs_info_blk; - struct mutex list_lock;/* mutex for IPC list locking */ - spinlock_t list_spin_lock; /* mutex for IPC list locking */ - struct snd_pmic_ops *scard_ops; - struct pci_dev *pci; - int active_streams[MAX_NUM_STREAMS]; - void *mmap_mem; - struct mutex sst_lock; - struct mutex stream_lock; - unsigned int mmap_len; - unsigned int unique_id; - unsigned int stream_cnt; /* total streams */ - unsigned int encoded_cnt; /* enocded streams only */ - unsigned int am_cnt; - unsigned int pb_streams; /* pb streams active */ - unsigned int cp_streams; /* cp streams active */ - unsigned int lpe_stalled; /* LPE is stalled or not */ - unsigned int pmic_port_instance; /*pmic port instance*/ - int rx_time_slot_status; - unsigned int lpaudio_start; - /* 1 - LPA stream(MP3 pb) in progress*/ - unsigned int audio_start; - dev_t devt_d, devt_c; - unsigned int max_streams; - unsigned int *fw_cntx; - unsigned int fw_cntx_size; - - unsigned int fw_downloaded; -}; - -extern struct intel_sst_drv *sst_drv_ctx; - -#define CHIP_REV_REG 0xff108000 -#define CHIP_REV_ADDR 0x78 - -/* misc definitions */ -#define FW_DWNL_ID 0xFF -#define LOOP1 0x11111111 -#define LOOP2 0x22222222 -#define LOOP3 0x33333333 -#define LOOP4 0x44444444 - -#define SST_DEFAULT_PMIC_PORT 1 /*audio port*/ -/* NOTE: status will have +ve for good cases and -ve for error ones */ -#define MAX_STREAM_FIELD 255 - -int sst_alloc_stream(char *params, unsigned int stream_ops, u8 codec, - unsigned int session_id); -int sst_alloc_stream_response(unsigned int str_id, - struct snd_sst_alloc_response *response); -int sst_stalled(void); -int sst_pause_stream(int id); -int sst_resume_stream(int id); -int sst_enable_rx_timeslot(int status); -int sst_drop_stream(int id); -int sst_free_stream(int id); -int sst_start_stream(int streamID); -int sst_play_frame(int streamID); -int sst_pcm_play_frame(int str_id, struct sst_stream_bufs *sst_buf); -int sst_capture_frame(int streamID); -int sst_set_stream_param(int streamID, struct snd_sst_params *str_param); -int sst_target_device_select(struct snd_sst_target_device *target_device); -int sst_decode(int str_id, struct snd_sst_dbufs *dbufs); -int sst_get_decoded_bytes(int str_id, unsigned long long *bytes); -int sst_get_fw_info(struct snd_sst_fw_info *info); -int sst_get_stream_params(int str_id, - struct snd_sst_get_stream_params *get_params); -int sst_get_stream(struct snd_sst_params *str_param); -int sst_get_stream_allocated(struct snd_sst_params *str_param, - struct snd_sst_lib_download **lib_dnld); -int sst_drain_stream(int str_id); -int sst_get_vol(struct snd_sst_vol *set_vol); -int sst_set_vol(struct snd_sst_vol *set_vol); -int sst_set_mute(struct snd_sst_mute *set_mute); - - -void sst_post_message(struct work_struct *work); -void sst_process_message(struct work_struct *work); -void sst_process_reply(struct work_struct *work); -void sst_process_mad_ops(struct work_struct *work); -void sst_process_mad_jack_detection(struct work_struct *work); - -long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, - unsigned long arg); -int intel_sst_open(struct inode *i_node, struct file *file_ptr); -int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr); -int intel_sst_release(struct inode *i_node, struct file *file_ptr); -int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr); -int intel_sst_read(struct file *file_ptr, char __user *buf, - size_t count, loff_t *ppos); -int intel_sst_write(struct file *file_ptr, const char __user *buf, - size_t count, loff_t *ppos); -int intel_sst_mmap(struct file *fp, struct vm_area_struct *vma); -ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, - unsigned long nr_segs, loff_t offset); -ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, - unsigned long nr_segs, loff_t offset); - -int sst_load_fw(const struct firmware *fw, void *context); -int sst_load_library(struct snd_sst_lib_download *lib, u8 ops); -int sst_spi_mode_enable(void); -int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx); - -int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block); -int sst_wait_interruptible_timeout(struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block, int timeout); -int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, - struct stream_alloc_block *block); -int sst_create_large_msg(struct ipc_post **arg); -int sst_create_short_msg(struct ipc_post **arg); -void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx, - u8 sst_id, int status, void *data); -void sst_clear_interrupt(void); -int intel_sst_resume(struct pci_dev *pci); -int sst_download_fw(void); -void free_stream_context(unsigned int str_id); -void sst_clean_stream(struct stream_info *stream); - -/* - * sst_fill_header - inline to fill sst header - * - * @header : ipc header - * @msg : IPC message to be sent - * @large : is ipc large msg - * @str_id : stream id - * - * this function is an inline function that sets the headers before - * sending a message - */ -static inline void sst_fill_header(union ipc_header *header, - int msg, int large, int str_id) -{ - header->part.msg_id = msg; - header->part.str_id = str_id; - header->part.large = large; - header->part.done = 0; - header->part.busy = 1; - header->part.data = 0; -} - -/* - * sst_assign_pvt_id - assign a pvt id for stream - * - * @sst_drv_ctx : driver context - * - * this inline function assigns a private id for calls that dont have stream - * context yet, should be called with lock held - */ -static inline unsigned int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx) -{ - sst_drv_ctx->unique_id++; - if (sst_drv_ctx->unique_id >= MAX_NUM_STREAMS) - sst_drv_ctx->unique_id = 1; - return sst_drv_ctx->unique_id; -} - -/* - * sst_init_stream - this function initialzes stream context - * - * @stream : stream struture - * @codec : codec for stream - * @sst_id : stream id - * @ops : stream operation - * @slot : stream pcm slot - * @device : device type - * - * this inline function initialzes stream context for allocated stream - */ -static inline void sst_init_stream(struct stream_info *stream, - int codec, int sst_id, int ops, u8 slot, - enum snd_sst_audio_device_type device) -{ - stream->status = STREAM_INIT; - stream->prev = STREAM_UN_INIT; - stream->codec = codec; - stream->sst_id = sst_id; - stream->str_type = 0; - stream->ops = ops; - stream->data_blk.on = false; - stream->data_blk.condition = false; - stream->data_blk.ret_code = 0; - stream->data_blk.data = NULL; - stream->ctrl_blk.on = false; - stream->ctrl_blk.condition = false; - stream->ctrl_blk.ret_code = 0; - stream->ctrl_blk.data = NULL; - stream->need_draining = false; - stream->decode_ibuf = NULL; - stream->decode_isize = 0; - stream->mmapped = false; - stream->pcm_slot = slot; - stream->device = device; -} - - -/* - * sst_validate_strid - this function validates the stream id - * - * @str_id : stream id to be validated - * - * returns 0 if valid stream - */ -static inline int sst_validate_strid(int str_id) -{ - if (str_id <= 0 || str_id > sst_drv_ctx->max_streams) { - pr_err("SST ERR: invalid stream id : %d MAX_STREAMS:%d\n", - str_id, sst_drv_ctx->max_streams); - return -EINVAL; - } else - return 0; -} - -static inline int sst_shim_write(void __iomem *addr, int offset, int value) -{ - - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) - writel(value, addr + SST_ISRD); /*dummy*/ - writel(value, addr + offset); - return 0; -} - -static inline int sst_shim_read(void __iomem *addr, int offset) -{ - return readl(addr + offset); -} -#endif /* __INTEL_SST_COMMON_H__ */ diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c deleted file mode 100644 index 22bd29c0c43..00000000000 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * intel_sst_interface.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com) - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This driver exposes the audio engine functionalities to the ALSA - * and middleware. - * Upper layer interfaces (MAD driver, MMF) to SST driver - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/firmware.h> -#include <linux/pm_runtime.h> -#include <linux/export.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - - -/* - * sst_download_fw - download the audio firmware to DSP - * - * This function is called when the FW needs to be downloaded to SST DSP engine - */ -int sst_download_fw(void) -{ - int retval; - const struct firmware *fw_sst; - char name[20]; - - if (sst_drv_ctx->sst_state != SST_UN_INIT) - return -EPERM; - - /* Reload firmware is not needed for MRST */ - if ( (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) && sst_drv_ctx->fw_downloaded) { - pr_debug("FW already downloaded, skip for MRST platform\n"); - sst_drv_ctx->sst_state = SST_FW_RUNNING; - return 0; - } - - snprintf(name, sizeof(name), "%s%04x%s", "fw_sst_", - sst_drv_ctx->pci_id, ".bin"); - - pr_debug("Downloading %s FW now...\n", name); - retval = request_firmware(&fw_sst, name, &sst_drv_ctx->pci->dev); - if (retval) { - pr_err("request fw failed %d\n", retval); - return retval; - } - sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID; - sst_drv_ctx->alloc_block[0].ops_block.condition = false; - retval = sst_load_fw(fw_sst, NULL); - if (retval) - goto end_restore; - - retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]); - if (retval) - pr_err("fw download failed %d\n" , retval); - else - sst_drv_ctx->fw_downloaded = 1; - -end_restore: - release_firmware(fw_sst); - sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT; - return retval; -} - - -/* - * sst_stalled - this function checks if the lpe is in stalled state - */ -int sst_stalled(void) -{ - int retry = 1000; - int retval = -1; - - while (retry) { - if (!sst_drv_ctx->lpe_stalled) - return 0; - /*wait for time and re-check*/ - msleep(1); - - retry--; - } - pr_debug("in Stalled State\n"); - return retval; -} - -void free_stream_context(unsigned int str_id) -{ - struct stream_info *stream; - - if (!sst_validate_strid(str_id)) { - /* str_id is valid, so stream is alloacted */ - stream = &sst_drv_ctx->streams[str_id]; - if (sst_free_stream(str_id)) - sst_clean_stream(&sst_drv_ctx->streams[str_id]); - if (stream->ops == STREAM_OPS_PLAYBACK || - stream->ops == STREAM_OPS_PLAYBACK_DRM) { - sst_drv_ctx->pb_streams--; - if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) - sst_drv_ctx->scard_ops->power_down_pmic_pb( - stream->device); - else { - if (sst_drv_ctx->pb_streams == 0) - sst_drv_ctx->scard_ops-> - power_down_pmic_pb(stream->device); - } - } else if (stream->ops == STREAM_OPS_CAPTURE) { - sst_drv_ctx->cp_streams--; - if (sst_drv_ctx->cp_streams == 0) - sst_drv_ctx->scard_ops->power_down_pmic_cp( - stream->device); - } - if (sst_drv_ctx->pb_streams == 0 - && sst_drv_ctx->cp_streams == 0) - sst_drv_ctx->scard_ops->power_down_pmic(); - } -} - -/* - * sst_get_stream_allocated - this function gets a stream allocated with - * the given params - * - * @str_param : stream params - * @lib_dnld : pointer to pointer of lib downlaod struct - * - * This creates new stream id for a stream, in case lib is to be downloaded to - * DSP, it downloads that - */ -int sst_get_stream_allocated(struct snd_sst_params *str_param, - struct snd_sst_lib_download **lib_dnld) -{ - int retval, str_id; - struct stream_info *str_info; - - retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops, - str_param->codec, str_param->device_type); - if (retval < 0) { - pr_err("sst_alloc_stream failed %d\n", retval); - return retval; - } - pr_debug("Stream allocated %d\n", retval); - str_id = retval; - str_info = &sst_drv_ctx->streams[str_id]; - /* Block the call for reply */ - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); - if ((retval != 0) || (str_info->ctrl_blk.ret_code != 0)) { - pr_debug("FW alloc failed retval %d, ret_code %d\n", - retval, str_info->ctrl_blk.ret_code); - str_id = -str_info->ctrl_blk.ret_code; /*return error*/ - *lib_dnld = str_info->ctrl_blk.data; - sst_clean_stream(str_info); - } else - pr_debug("FW Stream allocated success\n"); - return str_id; /*will ret either error (in above if) or correct str id*/ -} - -/* - * sst_get_sfreq - this function returns the frequency of the stream - * - * @str_param : stream params - */ -static int sst_get_sfreq(struct snd_sst_params *str_param) -{ - switch (str_param->codec) { - case SST_CODEC_TYPE_PCM: - return 48000; /*str_param->sparams.uc.pcm_params.sfreq;*/ - case SST_CODEC_TYPE_MP3: - return str_param->sparams.uc.mp3_params.sfreq; - case SST_CODEC_TYPE_AAC: - return str_param->sparams.uc.aac_params.sfreq; - case SST_CODEC_TYPE_WMA9: - return str_param->sparams.uc.wma_params.sfreq; - default: - return 0; - } -} - -/* - * sst_get_stream - this function prepares for stream allocation - * - * @str_param : stream param - */ -int sst_get_stream(struct snd_sst_params *str_param) -{ - int i, retval; - struct stream_info *str_info; - struct snd_sst_lib_download *lib_dnld; - - /* stream is not allocated, we are allocating */ - retval = sst_get_stream_allocated(str_param, &lib_dnld); - if (retval == -(SST_LIB_ERR_LIB_DNLD_REQUIRED)) { - /* codec download is required */ - struct snd_sst_alloc_response *response; - - pr_debug("Codec is required.... trying that\n"); - if (lib_dnld == NULL) { - pr_err("lib download null!!! abort\n"); - return -EIO; - } - i = sst_get_block_stream(sst_drv_ctx); - response = sst_drv_ctx->alloc_block[i].ops_block.data; - pr_debug("alloc block allocated = %d\n", i); - if (i < 0) { - kfree(lib_dnld); - return -ENOMEM; - } - retval = sst_load_library(lib_dnld, str_param->ops); - kfree(lib_dnld); - - sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - if (!retval) { - pr_debug("codec was downloaded successfully\n"); - - retval = sst_get_stream_allocated(str_param, &lib_dnld); - if (retval <= 0) - goto err; - - pr_debug("Alloc done stream id %d\n", retval); - } else { - pr_debug("codec download failed\n"); - retval = -EIO; - goto err; - } - } else if (retval <= 0) - goto err; - /*else - set_port_params(str_param, str_param->ops);*/ - - /* store sampling freq */ - str_info = &sst_drv_ctx->streams[retval]; - str_info->sfreq = sst_get_sfreq(str_param); - - /* power on the analog, if reqd */ - if (str_param->ops == STREAM_OPS_PLAYBACK || - str_param->ops == STREAM_OPS_PLAYBACK_DRM) { - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) - sst_drv_ctx->scard_ops->power_up_pmic_pb( - sst_drv_ctx->pmic_port_instance); - else - sst_drv_ctx->scard_ops->power_up_pmic_pb( - str_info->device); - /*Only if the playback is MP3 - Send a message*/ - sst_drv_ctx->pb_streams++; - } else if (str_param->ops == STREAM_OPS_CAPTURE) { - - sst_drv_ctx->scard_ops->power_up_pmic_cp( - sst_drv_ctx->pmic_port_instance); - /*Send a messageif not sent already*/ - sst_drv_ctx->cp_streams++; - } - -err: - return retval; -} - -void sst_process_mad_ops(struct work_struct *work) -{ - - struct mad_ops_wq *mad_ops = - container_of(work, struct mad_ops_wq, wq); - int retval = 0; - - switch (mad_ops->control_op) { - case SST_SND_PAUSE: - retval = sst_pause_stream(mad_ops->stream_id); - break; - case SST_SND_RESUME: - retval = sst_resume_stream(mad_ops->stream_id); - break; - case SST_SND_DROP: - retval = sst_drop_stream(mad_ops->stream_id); - break; - case SST_SND_START: - pr_debug("SST Debug: start stream\n"); - retval = sst_start_stream(mad_ops->stream_id); - break; - case SST_SND_STREAM_PROCESS: - pr_debug("play/capt frames...\n"); - break; - default: - pr_err(" wrong control_ops reported\n"); - } - return; -} - -void send_intial_rx_timeslot(void) -{ - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID && - sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT - && sst_drv_ctx->pmic_vendor != SND_NC) - sst_enable_rx_timeslot(sst_drv_ctx->rx_time_slot_status); -} - -/* - * sst_open_pcm_stream - Open PCM interface - * - * @str_param: parameters of pcm stream - * - * This function is called by MID sound card driver to open - * a new pcm interface - */ -int sst_open_pcm_stream(struct snd_sst_params *str_param) -{ - struct stream_info *str_info; - int retval; - - pm_runtime_get_sync(&sst_drv_ctx->pci->dev); - - if (sst_drv_ctx->sst_state == SST_SUSPENDED) { - /* LPE is suspended, resume it before proceeding*/ - pr_debug("Resuming from Suspended state\n"); - retval = intel_sst_resume(sst_drv_ctx->pci); - if (retval) { - pr_err("Resume Failed = %#x, abort\n", retval); - pm_runtime_put(&sst_drv_ctx->pci->dev); - return retval; - } - } - if (sst_drv_ctx->sst_state == SST_UN_INIT) { - /* FW is not downloaded */ - pr_debug("DSP Downloading FW now...\n"); - retval = sst_download_fw(); - if (retval) { - pr_err("FW download fail %x, abort\n", retval); - pm_runtime_put(&sst_drv_ctx->pci->dev); - return retval; - } - send_intial_rx_timeslot(); - } - - if (!str_param) { - pm_runtime_put(&sst_drv_ctx->pci->dev); - return -EINVAL; - } - - retval = sst_get_stream(str_param); - if (retval > 0) { - sst_drv_ctx->stream_cnt++; - str_info = &sst_drv_ctx->streams[retval]; - str_info->src = MAD_DRV; - } else - pm_runtime_put(&sst_drv_ctx->pci->dev); - - return retval; -} - -/* - * sst_close_pcm_stream - Close PCM interface - * - * @str_id: stream id to be closed - * - * This function is called by MID sound card driver to close - * an existing pcm interface - */ -int sst_close_pcm_stream(unsigned int str_id) -{ - struct stream_info *stream; - - pr_debug("sst: stream free called\n"); - if (sst_validate_strid(str_id)) - return -EINVAL; - stream = &sst_drv_ctx->streams[str_id]; - free_stream_context(str_id); - stream->pcm_substream = NULL; - stream->status = STREAM_UN_INIT; - stream->period_elapsed = NULL; - sst_drv_ctx->stream_cnt--; - pr_debug("sst: will call runtime put now\n"); - pm_runtime_put(&sst_drv_ctx->pci->dev); - return 0; -} - -/* - * sst_device_control - Set Control params - * - * @cmd: control cmd to be set - * @arg: command argument - * - * This function is called by MID sound card driver to set - * SST/Sound card controls for an opened stream. - * This is registered with MID driver - */ -int sst_device_control(int cmd, void *arg) -{ - int retval = 0, str_id = 0; - - switch (cmd) { - case SST_SND_PAUSE: - case SST_SND_RESUME: - case SST_SND_DROP: - case SST_SND_START: - sst_drv_ctx->mad_ops.control_op = cmd; - sst_drv_ctx->mad_ops.stream_id = *(int *)arg; - queue_work(sst_drv_ctx->mad_wq, &sst_drv_ctx->mad_ops.wq); - break; - - case SST_SND_STREAM_INIT: { - struct pcm_stream_info *str_info; - struct stream_info *stream; - - pr_debug("stream init called\n"); - str_info = (struct pcm_stream_info *)arg; - str_id = str_info->str_id; - retval = sst_validate_strid(str_id); - if (retval) - break; - - stream = &sst_drv_ctx->streams[str_id]; - pr_debug("setting the period ptrs\n"); - stream->pcm_substream = str_info->mad_substream; - stream->period_elapsed = str_info->period_elapsed; - stream->sfreq = str_info->sfreq; - stream->prev = stream->status; - stream->status = STREAM_INIT; - break; - } - - case SST_SND_BUFFER_POINTER: { - struct pcm_stream_info *stream_info; - struct snd_sst_tstamp fw_tstamp = {0,}; - struct stream_info *stream; - - - stream_info = (struct pcm_stream_info *)arg; - str_id = stream_info->str_id; - retval = sst_validate_strid(str_id); - if (retval) - break; - stream = &sst_drv_ctx->streams[str_id]; - - if (!stream->pcm_substream) - break; - memcpy_fromio(&fw_tstamp, - ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP) - +(str_id * sizeof(fw_tstamp))), - sizeof(fw_tstamp)); - - pr_debug("Pointer Query on strid = %d ops %d\n", - str_id, stream->ops); - - if (stream->ops == STREAM_OPS_PLAYBACK) - stream_info->buffer_ptr = fw_tstamp.samples_rendered; - else - stream_info->buffer_ptr = fw_tstamp.samples_processed; - pr_debug("Samples rendered = %llu, buffer ptr %llu\n", - fw_tstamp.samples_rendered, stream_info->buffer_ptr); - break; - } - case SST_ENABLE_RX_TIME_SLOT: { - int status = *(int *)arg; - sst_drv_ctx->rx_time_slot_status = status ; - sst_enable_rx_timeslot(status); - break; - } - default: - /* Illegal case */ - pr_warn("illegal req\n"); - return -EINVAL; - } - - return retval; -} - - -struct intel_sst_pcm_control pcm_ops = { - .open = sst_open_pcm_stream, - .device_control = sst_device_control, - .close = sst_close_pcm_stream, -}; - -struct intel_sst_card_ops sst_pmic_ops = { - .pcm_control = &pcm_ops, -}; - -/* - * register_sst_card - function for sound card to register - * - * @card: pointer to structure of operations - * - * This function is called card driver loads and is ready for registration - */ -int register_sst_card(struct intel_sst_card_ops *card) -{ - if (!sst_drv_ctx) { - pr_err("No SST driver register card reject\n"); - return -ENODEV; - } - - if (!card || !card->module_name) { - pr_err("Null Pointer Passed\n"); - return -EINVAL; - } - if (sst_drv_ctx->pmic_state == SND_MAD_UN_INIT) { - /* register this driver */ - if ((strncmp(SST_CARD_NAMES, card->module_name, - strlen(SST_CARD_NAMES))) == 0) { - sst_drv_ctx->pmic_vendor = card->vendor_id; - sst_drv_ctx->scard_ops = card->scard_ops; - sst_pmic_ops.module_name = card->module_name; - sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE; - sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/ - card->pcm_control = sst_pmic_ops.pcm_control; - return 0; - } else { - pr_err("strcmp fail %s\n", card->module_name); - return -EINVAL; - } - - } else { - /* already registered a driver */ - pr_err("Repeat for registration..denied\n"); - return -EBADRQC; - } - /* The ASoC code doesn't set scard_ops */ - if (sst_drv_ctx->scard_ops) - sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT; - return 0; -} -EXPORT_SYMBOL_GPL(register_sst_card); - -/* - * unregister_sst_card- function for sound card to un-register - * - * @card: pointer to structure of operations - * - * This function is called when card driver unloads - */ -void unregister_sst_card(struct intel_sst_card_ops *card) -{ - if (sst_pmic_ops.pcm_control == card->pcm_control) { - /* unreg */ - sst_pmic_ops.module_name = ""; - sst_drv_ctx->pmic_state = SND_MAD_UN_INIT; - pr_debug("Unregistered %s\n", card->module_name); - } - return; -} -EXPORT_SYMBOL_GPL(unregister_sst_card); diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c deleted file mode 100644 index 426d2b92073..00000000000 --- a/drivers/staging/intel_sst/intel_sst_dsp.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * intel_sst_dsp.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This driver exposes the audio engine functionalities to the ALSA - * and middleware. - * - * This file contains all dsp controlling functions like firmware download, - * setting/resetting dsp cores, etc - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/firmware.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - - -/** - * intel_sst_reset_dsp_mrst - Resetting SST DSP - * - * This resets DSP in case of MRST platfroms - */ -static int intel_sst_reset_dsp_mrst(void) -{ - union config_status_reg csr; - - pr_debug("Resetting the DSP in mrst\n"); - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.full |= 0x382; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.strb_cntr_rst = 0; - csr.part.run_stall = 0x1; - csr.part.bypass = 0x7; - csr.part.sst_reset = 0x1; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - return 0; -} - -/** - * intel_sst_reset_dsp_medfield - Resetting SST DSP - * - * This resets DSP in case of Medfield platfroms - */ -static int intel_sst_reset_dsp_medfield(void) -{ - union config_status_reg csr; - - pr_debug("Resetting the DSP in medfield\n"); - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.full |= 0x382; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - - return 0; -} - -/** - * sst_start_mrst - Start the SST DSP processor - * - * This starts the DSP in MRST platfroms - */ -static int sst_start_mrst(void) -{ - union config_status_reg csr; - - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.bypass = 0; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - csr.part.run_stall = 0; - csr.part.sst_reset = 0; - csr.part.strb_cntr_rst = 1; - pr_debug("Setting SST to execute_mrst 0x%x\n", csr.full); - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - - return 0; -} - -/** - * sst_start_medfield - Start the SST DSP processor - * - * This starts the DSP in Medfield platfroms - */ -static int sst_start_medfield(void) -{ - union config_status_reg csr; - - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.bypass = 0; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.mfld_strb = 1; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.run_stall = 0; - csr.part.sst_reset = 0; - pr_debug("Starting the DSP_medfld %x\n", csr.full); - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - pr_debug("Starting the DSP_medfld\n"); - - return 0; -} - -/** - * sst_parse_module - Parse audio FW modules - * - * @module: FW module header - * - * Parses modules that need to be placed in SST IRAM and DRAM - * returns error or 0 if module sizes are proper - */ -static int sst_parse_module(struct fw_module_header *module) -{ - struct dma_block_info *block; - u32 count; - void __iomem *ram; - - pr_debug("module sign %s size %x blocks %x type %x\n", - module->signature, module->mod_size, - module->blocks, module->type); - pr_debug("module entrypoint 0x%x\n", module->entry_point); - - block = (void *)module + sizeof(*module); - - for (count = 0; count < module->blocks; count++) { - if (block->size <= 0) { - pr_err("block size invalid\n"); - return -EINVAL; - } - switch (block->type) { - case SST_IRAM: - ram = sst_drv_ctx->iram; - break; - case SST_DRAM: - ram = sst_drv_ctx->dram; - break; - default: - pr_err("wrong ram type0x%x in block0x%x\n", - block->type, count); - return -EINVAL; - } - memcpy_toio(ram + block->ram_offset, - (void *)block + sizeof(*block), block->size); - block = (void *)block + sizeof(*block) + block->size; - } - return 0; -} - -/** - * sst_parse_fw_image - parse and load FW - * - * @sst_fw: pointer to audio fw - * - * This function is called to parse and download the FW image - */ -static int sst_parse_fw_image(const struct firmware *sst_fw) -{ - struct fw_header *header; - u32 count; - int ret_val; - struct fw_module_header *module; - - BUG_ON(!sst_fw); - - /* Read the header information from the data pointer */ - header = (struct fw_header *)sst_fw->data; - - /* verify FW */ - if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) || - (sst_fw->size != header->file_size + sizeof(*header))) { - /* Invalid FW signature */ - pr_err("Invalid FW sign/filesize mismatch\n"); - return -EINVAL; - } - pr_debug("header sign=%s size=%x modules=%x fmt=%x size=%x\n", - header->signature, header->file_size, header->modules, - header->file_format, sizeof(*header)); - module = (void *)sst_fw->data + sizeof(*header); - for (count = 0; count < header->modules; count++) { - /* module */ - ret_val = sst_parse_module(module); - if (ret_val) - return ret_val; - module = (void *)module + sizeof(*module) + module->mod_size ; - } - - return 0; -} - -/** - * sst_load_fw - function to load FW into DSP - * - * @fw: Pointer to driver loaded FW - * @context: driver context - * - * This function is called by OS when the FW is loaded into kernel - */ -int sst_load_fw(const struct firmware *fw, void *context) -{ - int ret_val; - - pr_debug("load_fw called\n"); - BUG_ON(!fw); - - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) - ret_val = intel_sst_reset_dsp_mrst(); - else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) - ret_val = intel_sst_reset_dsp_medfield(); - if (ret_val) - return ret_val; - - ret_val = sst_parse_fw_image(fw); - if (ret_val) - return ret_val; - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_FW_LOADED; - mutex_unlock(&sst_drv_ctx->sst_lock); - /* 7. ask scu to reset the bypass bits */ - /* 8.bring sst out of reset */ - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) - ret_val = sst_start_mrst(); - else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) - ret_val = sst_start_medfield(); - if (ret_val) - return ret_val; - - pr_debug("fw loaded successful!!!\n"); - return ret_val; -} - -/*This function is called when any codec/post processing library - needs to be downloaded*/ -static int sst_download_library(const struct firmware *fw_lib, - struct snd_sst_lib_download_info *lib) -{ - /* send IPC message and wait */ - int i; - u8 pvt_id; - struct ipc_post *msg = NULL; - union config_status_reg csr; - struct snd_sst_str_type str_type = {0}; - int retval = 0; - - if (sst_create_large_msg(&msg)) - return -ENOMEM; - - pvt_id = sst_assign_pvt_id(sst_drv_ctx); - i = sst_get_block_stream(sst_drv_ctx); - pr_debug("alloc block allocated = %d, pvt_id %d\n", i, pvt_id); - if (i < 0) { - kfree(msg); - return -ENOMEM; - } - sst_drv_ctx->alloc_block[i].sst_id = pvt_id; - sst_fill_header(&msg->header, IPC_IA_PREP_LIB_DNLD, 1, pvt_id); - msg->header.part.data = sizeof(u32) + sizeof(str_type); - str_type.codec_type = lib->dload_lib.lib_info.lib_type; - /*str_type.pvt_id = pvt_id;*/ - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), &str_type, sizeof(str_type)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]); - if (retval) { - /* error */ - sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - pr_err("Prep codec downloaded failed %d\n", - retval); - return -EIO; - } - pr_debug("FW responded, ready for download now...\n"); - /* downloading on success */ - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_FW_LOADED; - mutex_unlock(&sst_drv_ctx->sst_lock); - csr.full = readl(sst_drv_ctx->shim + SST_CSR); - csr.part.run_stall = 1; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.bypass = 0x7; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - - sst_parse_fw_image(fw_lib); - - /* set the FW to running again */ - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.bypass = 0x0; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - - csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); - csr.part.run_stall = 0; - sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - - /* send download complete and wait */ - if (sst_create_large_msg(&msg)) { - sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - return -ENOMEM; - } - - sst_fill_header(&msg->header, IPC_IA_LIB_DNLD_CMPLT, 1, pvt_id); - sst_drv_ctx->alloc_block[i].sst_id = pvt_id; - msg->header.part.data = sizeof(u32) + sizeof(*lib); - lib->pvt_id = pvt_id; - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), lib, sizeof(*lib)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - pr_debug("Waiting for FW response Download complete\n"); - sst_drv_ctx->alloc_block[i].ops_block.condition = false; - retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]); - if (retval) { - /* error */ - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_UN_INIT; - mutex_unlock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - return -EIO; - } - - pr_debug("FW success on Download complete\n"); - sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_FW_RUNNING; - mutex_unlock(&sst_drv_ctx->sst_lock); - return 0; - -} - -/* This function is called before downloading the codec/postprocessing -library is set for download to SST DSP*/ -static int sst_validate_library(const struct firmware *fw_lib, - struct lib_slot_info *slot, - u32 *entry_point) -{ - struct fw_header *header; - struct fw_module_header *module; - struct dma_block_info *block; - unsigned int n_blk, isize = 0, dsize = 0; - int err = 0; - - header = (struct fw_header *)fw_lib->data; - if (header->modules != 1) { - pr_err("Module no mismatch found\n"); - err = -EINVAL; - goto exit; - } - module = (void *)fw_lib->data + sizeof(*header); - *entry_point = module->entry_point; - pr_debug("Module entry point 0x%x\n", *entry_point); - pr_debug("Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n", - module->signature, module->mod_size, - module->blocks, module->type); - - block = (void *)module + sizeof(*module); - for (n_blk = 0; n_blk < module->blocks; n_blk++) { - switch (block->type) { - case SST_IRAM: - isize += block->size; - break; - case SST_DRAM: - dsize += block->size; - break; - default: - pr_err("Invalid block type for 0x%x\n", n_blk); - err = -EINVAL; - goto exit; - } - block = (void *)block + sizeof(*block) + block->size; - } - if (isize > slot->iram_size || dsize > slot->dram_size) { - pr_err("library exceeds size allocated\n"); - err = -EINVAL; - goto exit; - } else - pr_debug("Library is safe for download...\n"); - - pr_debug("iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n", - isize, dsize, slot->iram_size, slot->dram_size); -exit: - return err; - -} - -/* This function is called when FW requests for a particular library download -This function prepares the library to download*/ -int sst_load_library(struct snd_sst_lib_download *lib, u8 ops) -{ - char buf[20]; - const char *type, *dir; - int len = 0, error = 0; - u32 entry_point; - const struct firmware *fw_lib; - struct snd_sst_lib_download_info dload_info = {{{0},},}; - - memset(buf, 0, sizeof(buf)); - - pr_debug("Lib Type 0x%x, Slot 0x%x, ops 0x%x\n", - lib->lib_info.lib_type, lib->slot_info.slot_num, ops); - pr_debug("Version 0x%x, name %s, caps 0x%x media type 0x%x\n", - lib->lib_info.lib_version, lib->lib_info.lib_name, - lib->lib_info.lib_caps, lib->lib_info.media_type); - - pr_debug("IRAM Size 0x%x, offset 0x%x\n", - lib->slot_info.iram_size, lib->slot_info.iram_offset); - pr_debug("DRAM Size 0x%x, offset 0x%x\n", - lib->slot_info.dram_size, lib->slot_info.dram_offset); - - switch (lib->lib_info.lib_type) { - case SST_CODEC_TYPE_MP3: - type = "mp3_"; - break; - case SST_CODEC_TYPE_AAC: - type = "aac_"; - break; - case SST_CODEC_TYPE_AACP: - type = "aac_v1_"; - break; - case SST_CODEC_TYPE_eAACP: - type = "aac_v2_"; - break; - case SST_CODEC_TYPE_WMA9: - type = "wma9_"; - break; - default: - pr_err("Invalid codec type\n"); - error = -EINVAL; - goto wake; - } - - if (ops == STREAM_OPS_CAPTURE) - dir = "enc_"; - else - dir = "dec_"; - len = strlen(type) + strlen(dir); - strncpy(buf, type, sizeof(buf)-1); - strncpy(buf + strlen(type), dir, sizeof(buf)-strlen(type)-1); - len += snprintf(buf + len, sizeof(buf) - len, "%d", - lib->slot_info.slot_num); - len += snprintf(buf + len, sizeof(buf) - len, ".bin"); - - pr_debug("Requesting %s\n", buf); - - error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev); - if (error) { - pr_err("library load failed %d\n", error); - goto wake; - } - error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point); - if (error) - goto wake_free; - - lib->mod_entry_pt = entry_point; - memcpy(&dload_info.dload_lib, lib, sizeof(*lib)); - error = sst_download_library(fw_lib, &dload_info); - if (error) - goto wake_free; - - /* lib is downloaded and init send alloc again */ - pr_debug("Library is downloaded now...\n"); -wake_free: - /* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */ - release_firmware(fw_lib); -wake: - return error; -} - diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h deleted file mode 100644 index 5d0cc56aaef..00000000000 --- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h +++ /dev/null @@ -1,416 +0,0 @@ -#ifndef __INTEL_SST_FW_IPC_H__ -#define __INTEL_SST_FW_IPC_H__ -/* -* intel_sst_fw_ipc.h - Intel SST Driver for audio engine -* -* Copyright (C) 2008-10 Intel Corporation -* Author: Vinod Koul <vinod.koul@intel.com> -* Harsha Priya <priya.harsha@intel.com> -* Dharageswari R <dharageswari.r@intel.com> -* KP Jeeja <jeeja.kp@intel.com> -* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; version 2 of the License. -* -* 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. -* -* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* -* This driver exposes the audio engine functionalities to the ALSA -* and middleware. -* This file has definitions shared between the firmware and driver -*/ - -#define MAX_NUM_STREAMS_MRST 3 -#define MAX_NUM_STREAMS_MFLD 6 -#define MAX_NUM_STREAMS 6 -#define MAX_DBG_RW_BYTES 80 -#define MAX_NUM_SCATTER_BUFFERS 8 -#define MAX_LOOP_BACK_DWORDS 8 -/* IPC base address and mailbox, timestamp offsets */ -#define SST_MAILBOX_SIZE 0x0400 -#define SST_MAILBOX_SEND 0x0000 -#define SST_MAILBOX_RCV 0x0804 -#define SST_TIME_STAMP 0x1800 -#define SST_RESERVED_OFFSET 0x1A00 -#define SST_CHEKPOINT_OFFSET 0x1C00 -#define REPLY_MSG 0x80 - -/* Message ID's for IPC messages */ -/* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */ - -/* I2L Firmware/Codec Download msgs */ -#define IPC_IA_PREP_LIB_DNLD 0x01 -#define IPC_IA_LIB_DNLD_CMPLT 0x02 - -#define IPC_IA_SET_PMIC_TYPE 0x03 -#define IPC_IA_GET_FW_VERSION 0x04 -#define IPC_IA_GET_FW_BUILD_INF 0x05 -#define IPC_IA_GET_FW_INFO 0x06 -#define IPC_IA_GET_FW_CTXT 0x07 -#define IPC_IA_SET_FW_CTXT 0x08 - -/* I2L Codec Config/control msgs */ -#define IPC_IA_SET_CODEC_PARAMS 0x10 -#define IPC_IA_GET_CODEC_PARAMS 0x11 -#define IPC_IA_SET_PPP_PARAMS 0x12 -#define IPC_IA_GET_PPP_PARAMS 0x13 -#define IPC_IA_PLAY_FRAMES 0x14 -#define IPC_IA_CAPT_FRAMES 0x15 -#define IPC_IA_PLAY_VOICE 0x16 -#define IPC_IA_CAPT_VOICE 0x17 -#define IPC_IA_DECODE_FRAMES 0x18 - -#define IPC_IA_ALG_PARAMS 0x1A -#define IPC_IA_TUNING_PARAMS 0x1B - -/* I2L Stream config/control msgs */ -#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */ -#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */ -#define IPC_IA_SET_STREAM_PARAMS 0x22 -#define IPC_IA_GET_STREAM_PARAMS 0x23 -#define IPC_IA_PAUSE_STREAM 0x24 -#define IPC_IA_RESUME_STREAM 0x25 -#define IPC_IA_DROP_STREAM 0x26 -#define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */ -#define IPC_IA_TARGET_DEV_SELECT 0x28 -#define IPC_IA_CONTROL_ROUTING 0x29 - -#define IPC_IA_SET_STREAM_VOL 0x2A /*Vol for stream, pre mixer */ -#define IPC_IA_GET_STREAM_VOL 0x2B -#define IPC_IA_SET_STREAM_MUTE 0x2C -#define IPC_IA_GET_STREAM_MUTE 0x2D -#define IPC_IA_ENABLE_RX_TIME_SLOT 0x2E /* Enable Rx time slot 0 or 1 */ - -#define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */ - -/* Debug msgs */ -#define IPC_IA_DBG_MEM_READ 0x40 -#define IPC_IA_DBG_MEM_WRITE 0x41 -#define IPC_IA_DBG_LOOP_BACK 0x42 - -/* L2I Firmware/Codec Download msgs */ -#define IPC_IA_FW_INIT_CMPLT 0x81 -#define IPC_IA_LPE_GETTING_STALLED 0x82 -#define IPC_IA_LPE_UNSTALLED 0x83 - -/* L2I Codec Config/control msgs */ -#define IPC_SST_GET_PLAY_FRAMES 0x90 /* Request IA more data */ -#define IPC_SST_GET_CAPT_FRAMES 0x91 /* Request IA more data */ -#define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */ -#define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */ -#define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */ -#define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */ -#define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */ -#define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */ -#define IPC_IA_TARGET_DEV_CHNGD 0x98 /* error in processing a stream */ - -#define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occurred */ -/* L2S messages */ -#define IPC_SC_DDR_LINK_UP 0xC0 -#define IPC_SC_DDR_LINK_DOWN 0xC1 -#define IPC_SC_SET_LPECLK_REQ 0xC2 -#define IPC_SC_SSP_BIT_BANG 0xC3 - -/* L2I Error reporting msgs */ -#define IPC_IA_MEM_ALLOC_FAIL 0xE0 -#define IPC_IA_PROC_ERR 0xE1 /* error in processing a - stream can be used by playback and - capture modules */ - -/* L2I Debug msgs */ -#define IPC_IA_PRINT_STRING 0xF0 - - - -/* Command Response or Acknowledge message to any IPC message will have - * same message ID and stream ID information which is sent. - * There is no specific Ack message ID. The data field is used as response - * meaning. - */ -enum ackData { - IPC_ACK_SUCCESS = 0, - IPC_ACK_FAILURE -}; - - -enum sst_error_codes { - /* Error code,response to msgId: Description */ - /* Common error codes */ - SST_SUCCESS = 0, /* Success */ - SST_ERR_INVALID_STREAM_ID = 1, - SST_ERR_INVALID_MSG_ID = 2, - SST_ERR_INVALID_STREAM_OP = 3, - SST_ERR_INVALID_PARAMS = 4, - SST_ERR_INVALID_CODEC = 5, - SST_ERR_INVALID_MEDIA_TYPE = 6, - SST_ERR_STREAM_ERR = 7, - - /* IPC specific error codes */ - SST_IPC_ERR_CALL_BACK_NOT_REGD = 8, - SST_IPC_ERR_STREAM_NOT_ALLOCATED = 9, - SST_IPC_ERR_STREAM_ALLOC_FAILED = 10, - SST_IPC_ERR_GET_STREAM_FAILED = 11, - SST_ERR_MOD_NOT_AVAIL = 12, - SST_ERR_MOD_DNLD_RQD = 13, - SST_ERR_STREAM_STOPPED = 14, - SST_ERR_STREAM_IN_USE = 15, - - /* Capture specific error codes */ - SST_CAP_ERR_INCMPLTE_CAPTURE_MSG = 16, - SST_CAP_ERR_CAPTURE_FAIL = 17, - SST_CAP_ERR_GET_DDR_NEW_SGLIST = 18, - SST_CAP_ERR_UNDER_RUN = 19, - SST_CAP_ERR_OVERFLOW = 20, - - /* Playback specific error codes*/ - SST_PB_ERR_INCMPLTE_PLAY_MSG = 21, - SST_PB_ERR_PLAY_FAIL = 22, - SST_PB_ERR_GET_DDR_NEW_SGLIST = 23, - - /* Codec manager specific error codes */ - SST_LIB_ERR_LIB_DNLD_REQUIRED = 24, - SST_LIB_ERR_LIB_NOT_SUPPORTED = 25, - - /* Library manager specific error codes */ - SST_SCC_ERR_PREP_DNLD_FAILED = 26, - SST_SCC_ERR_LIB_DNLD_RES_FAILED = 27, - /* Scheduler specific error codes */ - SST_SCH_ERR_FAIL = 28, - - /* DMA specific error codes */ - SST_DMA_ERR_NO_CHNL_AVAILABLE = 29, - SST_DMA_ERR_INVALID_INPUT_PARAMS = 30, - SST_DMA_ERR_CHNL_ALREADY_SUSPENDED = 31, - SST_DMA_ERR_CHNL_ALREADY_STARTED = 32, - SST_DMA_ERR_CHNL_NOT_ENABLED = 33, - SST_DMA_ERR_TRANSFER_FAILED = 34, - - SST_SSP_ERR_ALREADY_ENABLED = 35, - SST_SSP_ERR_ALREADY_DISABLED = 36, - SST_SSP_ERR_NOT_INITIALIZED = 37, - SST_SSP_ERR_SRAM_NO_DMA_DATA = 38, - - /* Other error codes */ - SST_ERR_MOD_INIT_FAIL = 39, - - /* FW init error codes */ - SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED = 40, - SST_RDR_ERR_ROUTE_ALREADY_STARTED = 41, - SST_RDR_ERR_IO_DEV_SEL_FAILED = 42, - SST_RDR_PREP_CODEC_DNLD_FAILED = 43, - - /* Memory debug error codes */ - SST_ERR_DBG_MEM_READ_FAIL = 44, - SST_ERR_DBG_MEM_WRITE_FAIL = 45, - SST_ERR_INSUFFICIENT_INPUT_SG_LIST = 46, - SST_ERR_INSUFFICIENT_OUTPUT_SG_LIST = 47, - - SST_ERR_BUFFER_NOT_AVAILABLE = 48, - SST_ERR_BUFFER_NOT_ALLOCATED = 49, - SST_ERR_INVALID_REGION_TYPE = 50, - SST_ERR_NULL_PTR = 51, - SST_ERR_INVALID_BUFFER_SIZE = 52, - SST_ERR_INVALID_BUFFER_INDEX = 53, - - /*IIPC specific error codes */ - SST_IIPC_QUEUE_FULL = 54, - SST_IIPC_ERR_MSG_SND_FAILED = 55, - SST_PB_ERR_UNDERRUN_OCCURED = 56, - SST_RDR_INSUFFICIENT_MIXER_BUFFER = 57, - SST_INVALID_TIME_SLOTS = 58, -}; - -enum dbg_mem_data_type { - /* Data type of debug read/write */ - DATA_TYPE_U32, - DATA_TYPE_U16, - DATA_TYPE_U8, -}; - -/* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/ - -/* IPC Header */ -union ipc_header { - struct { - u32 msg_id:8; /* Message ID - Max 256 Message Types */ - u32 str_id:5; - u32 large:1; /* Large Message if large = 1 */ - u32 reserved:2; /* Reserved for future use */ - u32 data:14; /* Ack/Info for msg, size of msg in Mailbox */ - u32 done:1; /* bit 30 */ - u32 busy:1; /* bit 31 */ - } part; - u32 full; -} __attribute__ ((packed)); - -/* Firmware build info */ -struct sst_fw_build_info { - unsigned char date[16]; /* Firmware build date */ - unsigned char time[16]; /* Firmware build time */ -} __attribute__ ((packed)); - -struct ipc_header_fw_init { - struct snd_sst_fw_version fw_version;/* Firmware version details */ - struct sst_fw_build_info build_info; - u16 result; /* Fw init result */ - u8 module_id; /* Module ID in case of error */ - u8 debug_info; /* Debug info from Module ID in case of fail */ -} __attribute__ ((packed)); - -/* Address and size info of a frame buffer in DDR */ -struct sst_address_info { - u32 addr; /* Address at IA */ - u32 size; /* Size of the buffer */ -} __attribute__ ((packed)); - -/* Time stamp */ -struct snd_sst_tstamp { - u64 samples_processed;/* capture - data in DDR */ - u64 samples_rendered;/* playback - data rendered */ - u64 bytes_processed;/* bytes decoded or encoded */ - u32 sampling_frequency;/* eg: 48000, 44100 */ - u32 dma_base_address;/* DMA base address */ - u16 dma_channel_no;/* DMA Channel used for the data transfer*/ - u16 reserved;/* 32 bit alignment */ -}; - -/* Frame info to play or capture */ -struct sst_frame_info { - u16 num_entries; /* number of entries to follow */ - u16 rsrvd; - struct sst_address_info addr[MAX_NUM_SCATTER_BUFFERS]; -} __attribute__ ((packed)); - -/* Frames info for decode */ -struct snd_sst_decode_info { - unsigned long long input_bytes_consumed; - unsigned long long output_bytes_produced; - struct sst_frame_info frames_in; - struct sst_frame_info frames_out; -} __attribute__ ((packed)); - -/* SST to IA print debug message*/ -struct ipc_sst_ia_print_params { - u32 string_size;/* Max value is 160 */ - u8 prt_string[160];/* Null terminated Char string */ -} __attribute__ ((packed)); - -/* Voice data message */ -struct snd_sst_voice_data { - u16 num_bytes;/* Number of valid voice data bytes */ - u8 pcm_wd_size;/* 0=8 bit, 1=16 bit 2=32 bit */ - u8 reserved;/* Reserved */ - u8 voice_data_buf[0];/* Voice data buffer in bytes, little endian */ -} __attribute__ ((packed)); - -/* SST to IA memory read debug message */ -struct ipc_sst_ia_dbg_mem_rw { - u16 num_bytes;/* Maximum of MAX_DBG_RW_BYTES */ - u16 data_type;/* enum: dbg_mem_data_type */ - u32 address; /* Memory address of data memory of data_type */ - u8 rw_bytes[MAX_DBG_RW_BYTES];/* Maximum of 64 bytes can be RW */ -} __attribute__ ((packed)); - -struct ipc_sst_ia_dbg_loop_back { - u16 num_dwords; /* Maximum of MAX_DBG_RW_BYTES */ - u16 increment_val;/* Increments dwords by this value, 0- no increment */ - u32 lpbk_dwords[MAX_LOOP_BACK_DWORDS];/* Maximum of 8 dwords loopback */ -} __attribute__ ((packed)); - -/* Stream type params struture for Alloc stream */ -struct snd_sst_str_type { - u8 codec_type; /* Codec type */ - u8 str_type; /* 1 = voice 2 = music */ - u8 operation; /* Playback or Capture */ - u8 protected_str; /* 0=Non DRM, 1=DRM */ - u8 time_slots; - u8 reserved; /* Reserved */ - u16 result; /* Result used for acknowledgment */ -} __attribute__ ((packed)); - -/* Library info structure */ -struct module_info { - u32 lib_version; - u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/ - u32 media_type; - u8 lib_name[12]; - u32 lib_caps; - unsigned char b_date[16]; /* Lib build date */ - unsigned char b_time[16]; /* Lib build time */ -} __attribute__ ((packed)); - -/* Library slot info */ -struct lib_slot_info { - u8 slot_num; /* 1 or 2 */ - u8 reserved1; - u16 reserved2; - u32 iram_size; /* slot size in IRAM */ - u32 dram_size; /* slot size in DRAM */ - u32 iram_offset; /* starting offset of slot in IRAM */ - u32 dram_offset; /* starting offset of slot in DRAM */ -} __attribute__ ((packed)); - -struct snd_sst_lib_download { - struct module_info lib_info; /* library info type, capabilities etc */ - struct lib_slot_info slot_info; /* slot info to be downloaded */ - u32 mod_entry_pt; -}; - -struct snd_sst_lib_download_info { - struct snd_sst_lib_download dload_lib; - u16 result; /* Result used for acknowledgment */ - u8 pvt_id; /* Private ID */ - u8 reserved; /* for alignment */ -}; - -/* Alloc stream params structure */ -struct snd_sst_alloc_params { - struct snd_sst_str_type str_type; - struct snd_sst_stream_params stream_params; -}; - -struct snd_sst_fw_get_stream_params { - struct snd_sst_stream_params codec_params; - struct snd_sst_pmic_config pcm_params; -}; - -/* Alloc stream response message */ -struct snd_sst_alloc_response { - struct snd_sst_str_type str_type; /* Stream type for allocation */ - struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */ -}; - -/* Drop response */ -struct snd_sst_drop_response { - u32 result; - u32 bytes; -}; - -/* CSV Voice call routing structure */ -struct snd_sst_control_routing { - u8 control; /* 0=start, 1=Stop */ - u8 reserved[3]; /* Reserved- for 32 bit alignment */ -}; - - -struct ipc_post { - struct list_head node; - union ipc_header header; /* driver specific */ - char *mailbox_data; -}; - -struct snd_sst_ctxt_params { - u32 address; /* Physical Address in DDR where the context is stored */ - u32 size; /* size of the context */ -}; -#endif /* __INTEL_SST_FW_IPC_H__ */ diff --git a/drivers/staging/intel_sst/intel_sst_ioctl.h b/drivers/staging/intel_sst/intel_sst_ioctl.h deleted file mode 100644 index 5da5ee092c6..00000000000 --- a/drivers/staging/intel_sst/intel_sst_ioctl.h +++ /dev/null @@ -1,440 +0,0 @@ -#ifndef __INTEL_SST_IOCTL_H__ -#define __INTEL_SST_IOCTL_H__ -/* - * intel_sst_ioctl.h - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corporation - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file defines all sst ioctls - */ - -/* codec and post/pre processing related info */ - -#include <linux/types.h> - -enum sst_codec_types { -/* AUDIO/MUSIC CODEC Type Definitions */ - SST_CODEC_TYPE_UNKNOWN = 0, - SST_CODEC_TYPE_PCM, /* Pass through Audio codec */ - SST_CODEC_TYPE_MP3, - SST_CODEC_TYPE_MP24, - SST_CODEC_TYPE_AAC, - SST_CODEC_TYPE_AACP, - SST_CODEC_TYPE_eAACP, - SST_CODEC_TYPE_WMA9, - SST_CODEC_TYPE_WMA10, - SST_CODEC_TYPE_WMA10P, - SST_CODEC_TYPE_RA, - SST_CODEC_TYPE_DDAC3, - SST_CODEC_TYPE_STEREO_TRUE_HD, - SST_CODEC_TYPE_STEREO_HD_PLUS, - - /* VOICE CODEC Type Definitions */ - SST_CODEC_TYPE_VOICE_PCM = 0x21, /* Pass through voice codec */ -}; - -enum sst_algo_types { - SST_CODEC_SRC = 0x64, - SST_CODEC_MIXER = 0x65, - SST_CODEC_DOWN_MIXER = 0x66, - SST_CODEC_VOLUME_CONTROL = 0x67, - SST_CODEC_OEM1 = 0xC8, - SST_CODEC_OEM2 = 0xC9, -}; - -enum snd_sst_stream_ops { - STREAM_OPS_PLAYBACK = 0, /* Decode */ - STREAM_OPS_CAPTURE, /* Encode */ - STREAM_OPS_PLAYBACK_DRM, /* Play Audio/Voice */ - STREAM_OPS_PLAYBACK_ALERT, /* Play Audio/Voice */ - STREAM_OPS_CAPTURE_VOICE_CALL, /* CSV Voice recording */ -}; - -enum stream_mode { - SST_STREAM_MODE_NONE = 0, - SST_STREAM_MODE_DNR = 1, - SST_STREAM_MODE_FNF = 2, - SST_STREAM_MODE_CAPTURE = 3 -}; - -enum stream_type { - SST_STREAM_TYPE_NONE = 0, - SST_STREAM_TYPE_MUSIC = 1, - SST_STREAM_TYPE_NORMAL = 2, - SST_STREAM_TYPE_LONG_PB = 3, - SST_STREAM_TYPE_LOW_LATENCY = 4, -}; - -enum snd_sst_audio_device_type { - SND_SST_DEVICE_HEADSET = 1, - SND_SST_DEVICE_IHF, - SND_SST_DEVICE_VIBRA, - SND_SST_DEVICE_HAPTIC, - SND_SST_DEVICE_CAPTURE, -}; - -/* Firmware Version info */ -struct snd_sst_fw_version { - __u8 build; /* build number*/ - __u8 minor; /* minor number*/ - __u8 major; /* major number*/ - __u8 type; /* build type */ -}; - -/* Port info structure */ -struct snd_sst_port_info { - __u16 port_type; - __u16 reserved; -}; - -/* Mixer info structure */ -struct snd_sst_mix_info { - __u16 max_streams; - __u16 reserved; -}; - -/* PCM Parameters */ -struct snd_pcm_params { - __u16 codec; /* codec type */ - __u8 num_chan; /* 1=Mono, 2=Stereo */ - __u8 pcm_wd_sz; /* 16/24 - bit*/ - __u32 reserved; /* Bitrate in bits per second */ - __u32 sfreq; /* Sampling rate in Hz */ - __u32 ring_buffer_size; - __u32 period_count; /* period elapsed in samples*/ - __u32 ring_buffer_addr; -}; - -/* MP3 Music Parameters Message */ -struct snd_mp3_params { - __u16 codec; - __u8 num_chan; /* 1=Mono, 2=Stereo */ - __u8 pcm_wd_sz; /* 16/24 - bit*/ - __u32 brate; /* Use the hard coded value. */ - __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ - __u8 crc_check; /* crc_check - disable (0) or enable (1) */ - __u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB*/ - __u16 reserved; /* Unused */ -}; - -#define AAC_BIT_STREAM_ADTS 0 -#define AAC_BIT_STREAM_ADIF 1 -#define AAC_BIT_STREAM_RAW 2 - -/* AAC Music Parameters Message */ -struct snd_aac_params { - __u16 codec; - __u8 num_chan; /* 1=Mono, 2=Stereo*/ - __u8 pcm_wd_sz; /* 16/24 - bit*/ - __u32 brate; - __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ - __u32 aac_srate; /* Plain AAC decoder operating sample rate */ - __u8 mpg_id; /* 0=MPEG-2, 1=MPEG-4 */ - __u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */ - __u8 aac_profile; /* 0=Main Profile, 1=LC profile, 3=SSR profile */ - __u8 ext_chl; /* No.of external channels */ - __u8 aot; /* Audio object type. 1=Main , 2=LC , 3=SSR, 4=SBR*/ - __u8 op_align; /* output alignment 0=16 bit , 1=MSB, 2= LSB align */ - __u8 brate_type; /* 0=CBR, 1=VBR */ - __u8 crc_check; /* crc check 0= disable, 1=enable */ - __s8 bit_stream_format[8]; /* input bit stream format adts/adif/raw */ - __u8 jstereo; /* Joint stereo Flag */ - __u8 sbr_present; /* 1 = SBR Present, 0 = SBR absent, for RAW */ - __u8 downsample; /* 1 = Downsampling ON, 0 = Downsampling OFF */ - __u8 num_syntc_elems; /* 1- Mono/stereo, 0 - Dual Mono, 0 - for raw */ - __s8 syntc_id[2]; /* 0 for ID_SCE(Dula Mono), -1 for raw */ - __s8 syntc_tag[2]; /* raw - -1 and 0 -16 for rest of the streams */ - __u8 pce_present; /* Flag. 1- present 0 - not present, for RAW */ - __u8 sbr_type; /* sbr_type: 0-plain aac, 1-aac-v1, 2-aac-v2 */ - __u8 outchmode; /*0- mono, 1-stereo, 2-dual mono 3-Parametric stereo */ - __u8 ps_present; -}; - -/* WMA Music Parameters Message */ -struct snd_wma_params { - __u16 codec; - __u8 num_chan; /* 1=Mono, 2=Stereo */ - __u8 pcm_wd_sz; /* 16/24 - bit*/ - __u32 brate; /* Use the hard coded value. */ - __u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ - __u32 channel_mask; /* Channel Mask */ - __u16 format_tag; /* Format Tag */ - __u16 block_align; /* packet size */ - __u16 wma_encode_opt;/* Encoder option */ - __u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB */ - __u8 pcm_src; /* input pcm bit width */ -}; - -/* Pre processing param structure */ -struct snd_prp_params { - __u32 reserved; /* No pre-processing defined yet */ -}; - -/* Pre and post processing params structure */ -struct snd_ppp_params { - __u8 algo_id;/* Post/Pre processing algorithm ID */ - __u8 str_id; /*Only 5 bits used 0 - 31 are valid*/ - __u8 enable; /* 0= disable, 1= enable*/ - __u8 reserved; - __u32 size; /*Size of parameters for all blocks*/ - void *params; -} __attribute__ ((packed)); - -struct snd_sst_postproc_info { - __u32 src_min; /* Supported SRC Min sampling freq */ - __u32 src_max; /* Supported SRC Max sampling freq */ - __u8 src; /* 0=Not supported, 1=Supported */ - __u8 bass_boost; /* 0=Not Supported, 1=Supported */ - __u8 stereo_widening; /* 0=Not Supported, 1=Supported */ - __u8 volume_control; /* 0=Not Supported, 1=Supported */ - __s16 min_vol; /* Minimum value of Volume in dB */ - __s16 max_vol; /* Maximum value of Volume in dB */ - __u8 mute_control; /* 0=No Mute, 1=Mute */ - __u8 reserved1; - __u16 reserved2; -}; - -/* pre processing Capability info structure */ -struct snd_sst_prp_info { - __s16 min_vol; /* Minimum value of Volume in dB */ - __s16 max_vol; /* Maximum value of Volume in dB */ - __u8 volume_control; /* 0=Not Supported, 1=Supported */ - __u8 reserved1; /* for 32 bit alignment */ - __u16 reserved2; /* for 32 bit alignment */ -} __attribute__ ((packed)); - -/*Pre / Post processing algorithms support*/ -struct snd_sst_ppp_info { - __u32 src:1; /* 0=Not supported, 1=Supported */ - __u32 mixer:1; /* 0=Not supported, 1=Supported */ - __u32 volume_control:1; /* 0=Not Supported, 1=Supported */ - __u32 mute_control:1; /* 0=Not Supported, 1=Supported */ - __u32 anc:1; /* 0=Not Supported, 1=Supported */ - __u32 side_tone:1; /* 0=Not Supported, 1=Supported */ - __u32 dc_removal:1; /* 0=Not Supported, 1=Supported */ - __u32 equalizer:1; /* 0=Not Supported, 1=Supported */ - __u32 spkr_prot:1; /* 0=Not Supported, 1=Supported */ - __u32 bass_boost:1; /* 0=Not Supported, 1=Supported */ - __u32 stereo_widening:1;/* 0=Not Supported, 1=Supported */ - __u32 rsvd1:21; - __u32 rsvd2; -}; - -/* Firmware capabilities info */ -struct snd_sst_fw_info { - struct snd_sst_fw_version fw_version; /* Firmware version */ - __u8 audio_codecs_supported[8]; /* Codecs supported by FW */ - __u32 recommend_min_duration; /* Min duration for Lowpower Playback */ - __u8 max_pcm_streams_supported; /* Max num of PCM streams supported */ - __u8 max_enc_streams_supported; /* Max number of Encoded streams */ - __u16 reserved; /* 32 bit alignment*/ - struct snd_sst_ppp_info ppp_info; /* pre_processing mod cap info */ - struct snd_sst_postproc_info pop_info; /* Post processing cap info*/ - struct snd_sst_port_info port_info[3]; /* Port info */ - struct snd_sst_mix_info mix_info;/* Mixer info */ - __u32 min_input_buf; /* minmum i/p buffer for decode */ -}; - -/* Codec params struture */ -union snd_sst_codec_params { - struct snd_pcm_params pcm_params; - struct snd_mp3_params mp3_params; - struct snd_aac_params aac_params; - struct snd_wma_params wma_params; -}; - - -struct snd_sst_stream_params { - union snd_sst_codec_params uc; -} __attribute__ ((packed)); - -struct snd_sst_params { - __u32 result; - __u32 stream_id; - __u8 codec; - __u8 ops; - __u8 stream_type; - __u8 device_type; - struct snd_sst_stream_params sparams; -}; - -struct snd_sst_vol { - __u32 stream_id; - __s32 volume; - __u32 ramp_duration; - __u32 ramp_type; /* Ramp type, default=0 */ -}; - -struct snd_sst_mute { - __u32 stream_id; - __u32 mute; -}; - -/* ioctl related stuff here */ -struct snd_sst_pmic_config { - __u32 sfreq; /* Sampling rate in Hz */ - __u16 num_chan; /* Mono =1 or Stereo =2 */ - __u16 pcm_wd_sz; /* Number of bits per sample */ -} __attribute__ ((packed)); - -struct snd_sst_get_stream_params { - struct snd_sst_params codec_params; - struct snd_sst_pmic_config pcm_params; -}; - -enum snd_sst_target_type { - SND_SST_TARGET_PMIC = 1, - SND_SST_TARGET_LPE, - SND_SST_TARGET_MODEM, - SND_SST_TARGET_BT, - SND_SST_TARGET_FM, - SND_SST_TARGET_NONE, -}; - -enum snd_sst_device_type { - SND_SST_DEVICE_SSP = 1, - SND_SST_DEVICE_PCM, - SND_SST_DEVICE_OTHER, -}; - -enum snd_sst_device_mode { - - SND_SST_DEV_MODE_PCM_MODE1 = 1, /*(16-bit word, bit-length frame sync)*/ - SND_SST_DEV_MODE_PCM_MODE2, - SND_SST_DEV_MODE_PCM_MODE3, - SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED, - SND_SST_DEV_MODE_PCM_MODE4_LEFT_JUSTIFIED, - SND_SST_DEV_MODE_PCM_MODE4_I2S, /*(I2S mode, 16-bit words)*/ - SND_SST_DEV_MODE_PCM_MODE5, - SND_SST_DEV_MODE_PCM_MODE6, -}; - -enum snd_sst_port_action { - SND_SST_PORT_PREPARE = 1, - SND_SST_PORT_ACTIVATE, -}; - -/* Target selection per device structure */ -struct snd_sst_slot_info { - __u8 mix_enable; /* Mixer enable or disable */ - __u8 device_type; - __u8 device_instance; /* 0, 1, 2 */ - __u8 target_device; - __u16 target_sink; - __u8 slot[2]; - __u8 master; - __u8 action; - __u8 device_mode; - __u8 reserved; - struct snd_sst_pmic_config pcm_params; -} __attribute__ ((packed)); - -#define SST_MAX_TARGET_DEVICES 3 -/* Target device list structure */ -struct snd_sst_target_device { - __u32 device_route; - struct snd_sst_slot_info devices[SST_MAX_TARGET_DEVICES]; -} __attribute__ ((packed)); - -struct snd_sst_driver_info { - __u32 version; /* Version of the driver */ - __u32 active_pcm_streams; - __u32 active_enc_streams; - __u32 max_pcm_streams; - __u32 max_enc_streams; - __u32 buf_per_stream; -}; - -enum snd_sst_buff_type { - SST_BUF_USER = 1, - SST_BUF_MMAP, - SST_BUF_RAR, -}; - -struct snd_sst_mmap_buff_entry { - unsigned int offset; - unsigned int size; -}; - -struct snd_sst_mmap_buffs { - unsigned int entries; - enum snd_sst_buff_type type; - struct snd_sst_mmap_buff_entry *buff; -}; - -struct snd_sst_buff_entry { - void *buffer; - unsigned int size; -}; - -struct snd_sst_buffs { - unsigned int entries; - __u8 type; - struct snd_sst_buff_entry *buff_entry; -}; - -struct snd_sst_dbufs { - unsigned long long input_bytes_consumed; - unsigned long long output_bytes_produced; - struct snd_sst_buffs *ibufs; - struct snd_sst_buffs *obufs; -}; - -struct snd_sst_tuning_params { - __u8 type; - __u8 str_id; - __u8 size; - __u8 rsvd; - __aligned_u64 addr; -} __attribute__ ((packed)); -/*IOCTL defined here */ -/*SST MMF IOCTLS only */ -#define SNDRV_SST_STREAM_SET_PARAMS _IOR('L', 0x00, \ - struct snd_sst_stream_params *) -#define SNDRV_SST_STREAM_GET_PARAMS _IOWR('L', 0x01, \ - struct snd_sst_get_stream_params *) -#define SNDRV_SST_STREAM_GET_TSTAMP _IOWR('L', 0x02, __u64 *) -#define SNDRV_SST_STREAM_DECODE _IOWR('L', 0x03, struct snd_sst_dbufs *) -#define SNDRV_SST_STREAM_BYTES_DECODED _IOWR('L', 0x04, __u64 *) -#define SNDRV_SST_STREAM_START _IO('A', 0x42) -#define SNDRV_SST_STREAM_DROP _IO('A', 0x43) -#define SNDRV_SST_STREAM_DRAIN _IO('A', 0x44) -#define SNDRV_SST_STREAM_PAUSE _IOW('A', 0x45, int) -#define SNDRV_SST_STREAM_RESUME _IO('A', 0x47) -#define SNDRV_SST_MMAP_PLAY _IOW('L', 0x05, struct snd_sst_mmap_buffs *) -#define SNDRV_SST_MMAP_CAPTURE _IOW('L', 0x06, struct snd_sst_mmap_buffs *) -/*SST common ioctls */ -#define SNDRV_SST_DRIVER_INFO _IOR('L', 0x10, struct snd_sst_driver_info *) -#define SNDRV_SST_SET_VOL _IOW('L', 0x11, struct snd_sst_vol *) -#define SNDRV_SST_GET_VOL _IOW('L', 0x12, struct snd_sst_vol *) -#define SNDRV_SST_MUTE _IOW('L', 0x13, struct snd_sst_mute *) -/*AM Ioctly only */ -#define SNDRV_SST_FW_INFO _IOR('L', 0x20, struct snd_sst_fw_info *) -#define SNDRV_SST_SET_TARGET_DEVICE _IOW('L', 0x21, \ - struct snd_sst_target_device *) -/*DSP Ioctls on /dev/intel_sst_ctrl only*/ -#define SNDRV_SST_SET_ALGO _IOW('L', 0x30, struct snd_ppp_params *) -#define SNDRV_SST_GET_ALGO _IOWR('L', 0x31, struct snd_ppp_params *) -#define SNDRV_SST_TUNING_PARAMS _IOW('L', 0x32, struct snd_sst_tuning_params *) - -#endif /* __INTEL_SST_IOCTL_H__ */ diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c deleted file mode 100644 index 5c3444f6ab4..00000000000 --- a/drivers/staging/intel_sst/intel_sst_ipc.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * intel_sst_ipc.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corporation - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file defines all ipc functions - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/firmware.h> -#include <linux/sched.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - -/* - * sst_send_sound_card_type - send sound card type - * - * this function sends the sound card type to sst dsp engine - */ -static void sst_send_sound_card_type(void) -{ - struct ipc_post *msg = NULL; - - if (sst_create_short_msg(&msg)) - return; - - sst_fill_header(&msg->header, IPC_IA_SET_PMIC_TYPE, 0, 0); - msg->header.part.data = sst_drv_ctx->pmic_vendor; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - return; -} - -/** -* sst_post_message - Posts message to SST -* -* @work: Pointer to work structure -* -* This function is called by any component in driver which -* wants to send an IPC message. This will post message only if -* busy bit is free -*/ -void sst_post_message(struct work_struct *work) -{ - struct ipc_post *msg; - union ipc_header header; - union interrupt_reg imr; - int retval = 0; - imr.full = 0; - - /*To check if LPE is in stalled state.*/ - retval = sst_stalled(); - if (retval < 0) { - pr_err("in stalled state\n"); - return; - } - pr_debug("post message called\n"); - spin_lock(&sst_drv_ctx->list_spin_lock); - - /* check list */ - if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) { - /* list is empty, mask imr */ - pr_debug("Empty msg queue... masking\n"); - imr.full = readl(sst_drv_ctx->shim + SST_IMRX); - imr.part.done_interrupt = 1; - /* dummy register for shim workaround */ - sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full); - spin_unlock(&sst_drv_ctx->list_spin_lock); - return; - } - - /* check busy bit */ - header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX); - if (header.part.busy) { - /* busy, unmask */ - pr_debug("Busy not free... unmasking\n"); - imr.full = readl(sst_drv_ctx->shim + SST_IMRX); - imr.part.done_interrupt = 0; - /* dummy register for shim workaround */ - sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full); - spin_unlock(&sst_drv_ctx->list_spin_lock); - return; - } - /* copy msg from list */ - msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next, - struct ipc_post, node); - list_del(&msg->node); - pr_debug("Post message: header = %x\n", msg->header.full); - pr_debug("size: = %x\n", msg->header.part.data); - if (msg->header.part.large) - memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND, - msg->mailbox_data, msg->header.part.data); - /* dummy register for shim workaround */ - - sst_shim_write(sst_drv_ctx->shim, SST_IPCX, msg->header.full); - spin_unlock(&sst_drv_ctx->list_spin_lock); - - kfree(msg->mailbox_data); - kfree(msg); - return; -} - -/* - * sst_clear_interrupt - clear the SST FW interrupt - * - * This function clears the interrupt register after the interrupt - * bottom half is complete allowing next interrupt to arrive - */ -void sst_clear_interrupt(void) -{ - union interrupt_reg isr; - union interrupt_reg imr; - union ipc_header clear_ipc; - - imr.full = sst_shim_read(sst_drv_ctx->shim, SST_IMRX); - isr.full = sst_shim_read(sst_drv_ctx->shim, SST_ISRX); - /* write 1 to clear */; - isr.part.busy_interrupt = 1; - sst_shim_write(sst_drv_ctx->shim, SST_ISRX, isr.full); - /* Set IA done bit */ - clear_ipc.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCD); - clear_ipc.part.busy = 0; - clear_ipc.part.done = 1; - clear_ipc.part.data = IPC_ACK_SUCCESS; - sst_shim_write(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full); - /* un mask busy interrupt */ - imr.part.busy_interrupt = 0; - sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full); -} - -void sst_restore_fw_context(void) -{ - struct snd_sst_ctxt_params fw_context; - struct ipc_post *msg = NULL; - - pr_debug("restore_fw_context\n"); - /*check cpu type*/ - if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID) - return; - /*not supported for rest*/ - if (!sst_drv_ctx->fw_cntx_size) - return; - /*nothing to restore*/ - pr_debug("restoring context......\n"); - /*send msg to fw*/ - if (sst_create_large_msg(&msg)) - return; - - sst_fill_header(&msg->header, IPC_IA_SET_FW_CTXT, 1, 0); - msg->header.part.data = sizeof(fw_context) + sizeof(u32); - fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx); - fw_context.size = sst_drv_ctx->fw_cntx_size; - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), - &fw_context, sizeof(fw_context)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - return; -} -/* - * process_fw_init - process the FW init msg - * - * @msg: IPC message from FW - * - * This function processes the FW init msg from FW - * marks FW state and prints debug info of loaded FW - */ -int process_fw_init(struct sst_ipc_msg_wq *msg) -{ - struct ipc_header_fw_init *init = - (struct ipc_header_fw_init *)msg->mailbox; - int retval = 0; - - pr_debug("*** FW Init msg came***\n"); - if (init->result) { - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_ERROR; - mutex_unlock(&sst_drv_ctx->sst_lock); - pr_debug("FW Init failed, Error %x\n", init->result); - pr_err("FW Init failed, Error %x\n", init->result); - retval = -init->result; - return retval; - } - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) - sst_send_sound_card_type(); - mutex_lock(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = SST_FW_RUNNING; - sst_drv_ctx->lpe_stalled = 0; - mutex_unlock(&sst_drv_ctx->sst_lock); - pr_debug("FW Version %02x.%02x.%02x\n", init->fw_version.major, - init->fw_version.minor, init->fw_version.build); - pr_debug("Build Type %x\n", init->fw_version.type); - pr_debug(" Build date %s Time %s\n", - init->build_info.date, init->build_info.time); - sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL); - sst_restore_fw_context(); - return retval; -} -/** -* sst_process_message - Processes message from SST -* -* @work: Pointer to work structure -* -* This function is scheduled by ISR -* It take a msg from process_queue and does action based on msg -*/ -void sst_process_message(struct work_struct *work) -{ - struct sst_ipc_msg_wq *msg = - container_of(work, struct sst_ipc_msg_wq, wq); - int str_id = msg->header.part.str_id; - - pr_debug("IPC process for %x\n", msg->header.full); - - /* based on msg in list call respective handler */ - switch (msg->header.part.msg_id) { - case IPC_SST_BUF_UNDER_RUN: - case IPC_SST_BUF_OVER_RUN: - if (sst_validate_strid(str_id)) { - pr_err("stream id %d invalid\n", str_id); - break; - } - pr_err("Buffer under/overrun for %d\n", - msg->header.part.str_id); - pr_err("Got Underrun & not to send data...ignore\n"); - break; - - case IPC_SST_GET_PLAY_FRAMES: - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { - struct stream_info *stream ; - - if (sst_validate_strid(str_id)) { - pr_err("strid %d invalid\n", str_id); - break; - } - /* call sst_play_frame */ - stream = &sst_drv_ctx->streams[str_id]; - pr_debug("sst_play_frames for %d\n", - msg->header.part.str_id); - mutex_lock(&sst_drv_ctx->streams[str_id].lock); - sst_play_frame(msg->header.part.str_id); - mutex_unlock(&sst_drv_ctx->streams[str_id].lock); - break; - } else - pr_err("sst_play_frames for Penwell!!\n"); - - case IPC_SST_GET_CAPT_FRAMES: - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { - struct stream_info *stream; - /* call sst_capture_frame */ - if (sst_validate_strid(str_id)) { - pr_err("str id %d invalid\n", str_id); - break; - } - stream = &sst_drv_ctx->streams[str_id]; - pr_debug("sst_capture_frames for %d\n", - msg->header.part.str_id); - mutex_lock(&stream->lock); - if (stream->mmapped == false && - stream->src == SST_DRV) { - pr_debug("waking up block for copy.\n"); - stream->data_blk.ret_code = 0; - stream->data_blk.condition = true; - stream->data_blk.on = false; - wake_up(&sst_drv_ctx->wait_queue); - } else - sst_capture_frame(msg->header.part.str_id); - mutex_unlock(&stream->lock); - } else - pr_err("sst_play_frames for Penwell!!\n"); - break; - - case IPC_IA_PRINT_STRING: - pr_debug("been asked to print something by fw\n"); - /* TBD */ - break; - - case IPC_IA_FW_INIT_CMPLT: { - /* send next data to FW */ - process_fw_init(msg); - break; - } - - case IPC_SST_STREAM_PROCESS_FATAL_ERR: - if (sst_validate_strid(str_id)) { - pr_err("stream id %d invalid\n", str_id); - break; - } - pr_err("codec fatal error %x stream %d...\n", - msg->header.full, msg->header.part.str_id); - pr_err("Dropping the stream\n"); - sst_drop_stream(msg->header.part.str_id); - break; - case IPC_IA_LPE_GETTING_STALLED: - sst_drv_ctx->lpe_stalled = 1; - break; - case IPC_IA_LPE_UNSTALLED: - sst_drv_ctx->lpe_stalled = 0; - break; - default: - /* Illegal case */ - pr_err("Unhandled msg %x header %x\n", - msg->header.part.msg_id, msg->header.full); - } - sst_clear_interrupt(); - return; -} - -/** -* sst_process_reply - Processes reply message from SST -* -* @work: Pointer to work structure -* -* This function is scheduled by ISR -* It take a reply msg from response_queue and -* does action based on msg -*/ -void sst_process_reply(struct work_struct *work) -{ - struct sst_ipc_msg_wq *msg = - container_of(work, struct sst_ipc_msg_wq, wq); - - int str_id = msg->header.part.str_id; - struct stream_info *str_info; - - switch (msg->header.part.msg_id) { - case IPC_IA_TARGET_DEV_SELECT: - if (!msg->header.part.data) { - sst_drv_ctx->tgt_dev_blk.ret_code = 0; - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - sst_drv_ctx->tgt_dev_blk.ret_code = - -msg->header.part.data; - } - - if (sst_drv_ctx->tgt_dev_blk.on == true) { - sst_drv_ctx->tgt_dev_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_ALG_PARAMS: { - pr_debug("sst:IPC_ALG_PARAMS response %x\n", msg->header.full); - pr_debug("sst: data value %x\n", msg->header.part.data); - pr_debug("sst: large value %x\n", msg->header.part.large); - - if (!msg->header.part.large) { - if (!msg->header.part.data) { - pr_debug("sst: alg set success\n"); - sst_drv_ctx->ppp_params_blk.ret_code = 0; - } else { - pr_debug("sst: alg set failed\n"); - sst_drv_ctx->ppp_params_blk.ret_code = - -msg->header.part.data; - } - - } else if (msg->header.part.data) { - struct snd_ppp_params *mailbox_params, *get_params; - char *params; - - pr_debug("sst: alg get success\n"); - mailbox_params = (struct snd_ppp_params *)msg->mailbox; - get_params = kzalloc(sizeof(*get_params), GFP_KERNEL); - if (get_params == NULL) { - pr_err("sst: out of memory for ALG PARAMS"); - break; - } - memcpy_fromio(get_params, mailbox_params, - sizeof(*get_params)); - get_params->params = kzalloc(mailbox_params->size, - GFP_KERNEL); - if (get_params->params == NULL) { - kfree(get_params); - pr_err("sst: out of memory for ALG PARAMS block"); - break; - } - params = msg->mailbox; - params = params + sizeof(*mailbox_params) - sizeof(u32); - memcpy_fromio(get_params->params, params, - get_params->size); - sst_drv_ctx->ppp_params_blk.ret_code = 0; - sst_drv_ctx->ppp_params_blk.data = get_params; - } - - if (sst_drv_ctx->ppp_params_blk.on == true) { - sst_drv_ctx->ppp_params_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - } - - case IPC_IA_TUNING_PARAMS: { - pr_debug("sst:IPC_TUNING_PARAMS resp: %x\n", msg->header.full); - pr_debug("data value %x\n", msg->header.part.data); - if (msg->header.part.large) { - pr_debug("alg set failed\n"); - sst_drv_ctx->ppp_params_blk.ret_code = - -msg->header.part.data; - } else { - pr_debug("alg set success\n"); - sst_drv_ctx->ppp_params_blk.ret_code = 0; - } - if (sst_drv_ctx->ppp_params_blk.on == true) { - sst_drv_ctx->ppp_params_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - } - - case IPC_IA_GET_FW_INFO: { - struct snd_sst_fw_info *fw_info = - (struct snd_sst_fw_info *)msg->mailbox; - if (msg->header.part.large) { - int major = fw_info->fw_version.major; - int minor = fw_info->fw_version.minor; - int build = fw_info->fw_version.build; - pr_debug("Msg succeeded %x\n", - msg->header.part.msg_id); - pr_debug("INFO: ***FW*** = %02d.%02d.%02d\n", - major, minor, build); - memcpy_fromio(sst_drv_ctx->fw_info_blk.data, - ((struct snd_sst_fw_info *)(msg->mailbox)), - sizeof(struct snd_sst_fw_info)); - sst_drv_ctx->fw_info_blk.ret_code = 0; - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - sst_drv_ctx->fw_info_blk.ret_code = - -msg->header.part.data; - } - if (sst_drv_ctx->fw_info_blk.on == true) { - pr_debug("Memcopy succeeded\n"); - sst_drv_ctx->fw_info_blk.on = false; - sst_drv_ctx->fw_info_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - } - case IPC_IA_SET_STREAM_MUTE: - if (!msg->header.part.data) { - pr_debug("Msg succeeded %x\n", - msg->header.part.msg_id); - sst_drv_ctx->mute_info_blk.ret_code = 0; - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - sst_drv_ctx->mute_info_blk.ret_code = - -msg->header.part.data; - - } - if (sst_drv_ctx->mute_info_blk.on == true) { - sst_drv_ctx->mute_info_blk.on = false; - sst_drv_ctx->mute_info_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_SET_STREAM_VOL: - if (!msg->header.part.data) { - pr_debug("Msg succeeded %x\n", - msg->header.part.msg_id); - sst_drv_ctx->vol_info_blk.ret_code = 0; - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, - msg->header.part.data); - sst_drv_ctx->vol_info_blk.ret_code = - -msg->header.part.data; - - } - - if (sst_drv_ctx->vol_info_blk.on == true) { - sst_drv_ctx->vol_info_blk.on = false; - sst_drv_ctx->vol_info_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_GET_STREAM_VOL: - if (msg->header.part.large) { - pr_debug("Large Msg Received Successfully\n"); - pr_debug("Msg succeeded %x\n", - msg->header.part.msg_id); - memcpy_fromio(sst_drv_ctx->vol_info_blk.data, - (void *) msg->mailbox, - sizeof(struct snd_sst_vol)); - sst_drv_ctx->vol_info_blk.ret_code = 0; - } else { - pr_err("Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - sst_drv_ctx->vol_info_blk.ret_code = - -msg->header.part.data; - } - if (sst_drv_ctx->vol_info_blk.on == true) { - sst_drv_ctx->vol_info_blk.on = false; - sst_drv_ctx->vol_info_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - - case IPC_IA_GET_STREAM_PARAMS: - if (sst_validate_strid(str_id)) { - pr_err("stream id %d invalid\n", str_id); - break; - } - str_info = &sst_drv_ctx->streams[str_id]; - if (msg->header.part.large) { - pr_debug("Get stream large success\n"); - memcpy_fromio(str_info->ctrl_blk.data, - ((void *)(msg->mailbox)), - sizeof(struct snd_sst_fw_get_stream_params)); - str_info->ctrl_blk.ret_code = 0; - } else { - pr_err("Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - str_info->ctrl_blk.ret_code = -msg->header.part.data; - } - if (str_info->ctrl_blk.on == true) { - str_info->ctrl_blk.on = false; - str_info->ctrl_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_DECODE_FRAMES: - if (sst_validate_strid(str_id)) { - pr_err("stream id %d invalid\n", str_id); - break; - } - str_info = &sst_drv_ctx->streams[str_id]; - if (msg->header.part.large) { - pr_debug("Msg succeeded %x\n", - msg->header.part.msg_id); - memcpy_fromio(str_info->data_blk.data, - ((void *)(msg->mailbox)), - sizeof(struct snd_sst_decode_info)); - str_info->data_blk.ret_code = 0; - } else { - pr_err("Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - str_info->data_blk.ret_code = -msg->header.part.data; - } - if (str_info->data_blk.on == true) { - str_info->data_blk.on = false; - str_info->data_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_DRAIN_STREAM: - if (sst_validate_strid(str_id)) { - pr_err("stream id %d invalid\n", str_id); - break; - } - str_info = &sst_drv_ctx->streams[str_id]; - if (!msg->header.part.data) { - pr_debug("Msg succeeded %x\n", - msg->header.part.msg_id); - str_info->ctrl_blk.ret_code = 0; - - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - str_info->ctrl_blk.ret_code = -msg->header.part.data; - - } - str_info = &sst_drv_ctx->streams[str_id]; - if (str_info->data_blk.on == true) { - str_info->data_blk.on = false; - str_info->data_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - - case IPC_IA_DROP_STREAM: - if (sst_validate_strid(str_id)) { - pr_err("str id %d invalid\n", str_id); - break; - } - str_info = &sst_drv_ctx->streams[str_id]; - if (msg->header.part.large) { - struct snd_sst_drop_response *drop_resp = - (struct snd_sst_drop_response *)msg->mailbox; - - pr_debug("Drop ret bytes %x\n", drop_resp->bytes); - - str_info->curr_bytes = drop_resp->bytes; - str_info->ctrl_blk.ret_code = 0; - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, msg->header.part.data); - str_info->ctrl_blk.ret_code = -msg->header.part.data; - } - if (str_info->ctrl_blk.on == true) { - str_info->ctrl_blk.on = false; - str_info->ctrl_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_ENABLE_RX_TIME_SLOT: - if (!msg->header.part.data) { - pr_debug("RX_TIME_SLOT success\n"); - sst_drv_ctx->hs_info_blk.ret_code = 0; - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, - msg->header.part.data); - sst_drv_ctx->hs_info_blk.ret_code = - -msg->header.part.data; - } - if (sst_drv_ctx->hs_info_blk.on == true) { - sst_drv_ctx->hs_info_blk.on = false; - sst_drv_ctx->hs_info_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_PAUSE_STREAM: - case IPC_IA_RESUME_STREAM: - case IPC_IA_SET_STREAM_PARAMS: - str_info = &sst_drv_ctx->streams[str_id]; - if (!msg->header.part.data) { - pr_debug("Msg succeeded %x\n", - msg->header.part.msg_id); - str_info->ctrl_blk.ret_code = 0; - } else { - pr_err(" Msg %x reply error %x\n", - msg->header.part.msg_id, - msg->header.part.data); - str_info->ctrl_blk.ret_code = -msg->header.part.data; - } - if (sst_validate_strid(str_id)) { - pr_err(" stream id %d invalid\n", str_id); - break; - } - - if (str_info->ctrl_blk.on == true) { - str_info->ctrl_blk.on = false; - str_info->ctrl_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - - case IPC_IA_FREE_STREAM: - str_info = &sst_drv_ctx->streams[str_id]; - if (!msg->header.part.data) { - pr_debug("Stream %d freed\n", str_id); - } else { - pr_err("Free for %d ret error %x\n", - str_id, msg->header.part.data); - } - if (str_info->ctrl_blk.on == true) { - str_info->ctrl_blk.on = false; - str_info->ctrl_blk.condition = true; - wake_up(&sst_drv_ctx->wait_queue); - } - break; - case IPC_IA_ALLOC_STREAM: { - /* map to stream, call play */ - struct snd_sst_alloc_response *resp = - (struct snd_sst_alloc_response *)msg->mailbox; - if (resp->str_type.result) - pr_err("error alloc stream = %x\n", - resp->str_type.result); - sst_alloc_stream_response(str_id, resp); - break; - } - - case IPC_IA_PLAY_FRAMES: - case IPC_IA_CAPT_FRAMES: - if (sst_validate_strid(str_id)) { - pr_err("stream id %d invalid\n", str_id); - break; - } - pr_debug("Ack for play/capt frames received\n"); - break; - - case IPC_IA_PREP_LIB_DNLD: { - struct snd_sst_str_type *str_type = - (struct snd_sst_str_type *)msg->mailbox; - pr_debug("Prep Lib download %x\n", - msg->header.part.msg_id); - if (str_type->result) - pr_err("Prep lib download %x\n", str_type->result); - else - pr_debug("Can download codec now...\n"); - sst_wake_up_alloc_block(sst_drv_ctx, str_id, - str_type->result, NULL); - break; - } - - case IPC_IA_LIB_DNLD_CMPLT: { - struct snd_sst_lib_download_info *resp = - (struct snd_sst_lib_download_info *)msg->mailbox; - int retval = resp->result; - - pr_debug("Lib downloaded %x\n", msg->header.part.msg_id); - if (resp->result) { - pr_err("err in lib dload %x\n", resp->result); - } else { - pr_debug("Codec download complete...\n"); - pr_debug("codec Type %d Ver %d Built %s: %s\n", - resp->dload_lib.lib_info.lib_type, - resp->dload_lib.lib_info.lib_version, - resp->dload_lib.lib_info.b_date, - resp->dload_lib.lib_info.b_time); - } - sst_wake_up_alloc_block(sst_drv_ctx, str_id, - retval, NULL); - break; - } - - case IPC_IA_GET_FW_VERSION: { - struct ipc_header_fw_init *version = - (struct ipc_header_fw_init *)msg->mailbox; - int major = version->fw_version.major; - int minor = version->fw_version.minor; - int build = version->fw_version.build; - dev_info(&sst_drv_ctx->pci->dev, - "INFO: ***LOADED SST FW VERSION*** = %02d.%02d.%02d\n", - major, minor, build); - break; - } - case IPC_IA_GET_FW_BUILD_INF: { - struct sst_fw_build_info *build = - (struct sst_fw_build_info *)msg->mailbox; - pr_debug("Build date:%sTime:%s", build->date, build->time); - break; - } - case IPC_IA_SET_PMIC_TYPE: - break; - case IPC_IA_START_STREAM: - pr_debug("reply for START STREAM %x\n", msg->header.full); - break; - - case IPC_IA_GET_FW_CTXT: - pr_debug("reply for get fw ctxt %x\n", msg->header.full); - if (msg->header.part.data) - sst_drv_ctx->fw_cntx_size = 0; - else - sst_drv_ctx->fw_cntx_size = *sst_drv_ctx->fw_cntx; - pr_debug("fw copied data %x\n", sst_drv_ctx->fw_cntx_size); - sst_wake_up_alloc_block( - sst_drv_ctx, str_id, msg->header.part.data, NULL); - break; - default: - /* Illegal case */ - pr_err("process reply:default = %x\n", msg->header.full); - } - sst_clear_interrupt(); - return; -} diff --git a/drivers/staging/intel_sst/intel_sst_pvt.c b/drivers/staging/intel_sst/intel_sst_pvt.c deleted file mode 100644 index e034bea56f1..00000000000 --- a/drivers/staging/intel_sst/intel_sst_pvt.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * intel_sst_pvt.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This driver exposes the audio engine functionalities to the ALSA - * and middleware. - * - * This file contains all private functions - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/firmware.h> -#include <linux/sched.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - -/* - * sst_get_block_stream - get a new block stream - * - * @sst_drv_ctx: Driver context structure - * - * This function assigns a block for the calls that dont have stream context yet - * the blocks are used for waiting on Firmware's response for any operation - * Should be called with stream lock held - */ -int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx) -{ - int i; - - for (i = 0; i < MAX_ACTIVE_STREAM; i++) { - if (sst_drv_ctx->alloc_block[i].sst_id == BLOCK_UNINIT) { - sst_drv_ctx->alloc_block[i].ops_block.condition = false; - sst_drv_ctx->alloc_block[i].ops_block.ret_code = 0; - sst_drv_ctx->alloc_block[i].sst_id = 0; - break; - } - } - if (i == MAX_ACTIVE_STREAM) { - pr_err("max alloc_stream reached\n"); - i = -EBUSY; /* active stream limit reached */ - } - return i; -} - -/* - * sst_wait_interruptible - wait on event - * - * @sst_drv_ctx: Driver context - * @block: Driver block to wait on - * - * This function waits without a timeout (and is interruptable) for a - * given block event - */ -int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block) -{ - int retval = 0; - - if (!wait_event_interruptible(sst_drv_ctx->wait_queue, - block->condition)) { - /* event wake */ - if (block->ret_code < 0) { - pr_err("stream failed %d\n", block->ret_code); - retval = -EBUSY; - } else { - pr_debug("event up\n"); - retval = 0; - } - } else { - pr_err("signal interrupted\n"); - retval = -EINTR; - } - return retval; - -} - - -/* - * sst_wait_interruptible_timeout - wait on event interruptable - * - * @sst_drv_ctx: Driver context - * @block: Driver block to wait on - * @timeout: time for wait on - * - * This function waits with a timeout value (and is interruptible) on a - * given block event - */ -int sst_wait_interruptible_timeout( - struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block, int timeout) -{ - int retval = 0; - - pr_debug("sst_wait_interruptible_timeout - waiting....\n"); - if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue, - block->condition, - msecs_to_jiffies(timeout))) { - if (block->ret_code < 0) - pr_err("stream failed %d\n", block->ret_code); - else - pr_debug("event up\n"); - retval = block->ret_code; - } else { - block->on = false; - pr_err("timeout occurred...\n"); - /*setting firmware state as uninit so that the - firmware will get re-downloaded on next request - this is because firmare not responding for 5 sec - is equalant to some unrecoverable error of FW - sst_drv_ctx->sst_state = SST_UN_INIT;*/ - retval = -EBUSY; - } - return retval; - -} - - -/* - * sst_wait_timeout - wait on event for timeout - * - * @sst_drv_ctx: Driver context - * @block: Driver block to wait on - * - * This function waits with a timeout value (and is not interruptible) on a - * given block event - */ -int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, - struct stream_alloc_block *block) -{ - int retval = 0; - - /* NOTE: - Observed that FW processes the alloc msg and replies even - before the alloc thread has finished execution */ - pr_debug("waiting for %x, condition %x\n", - block->sst_id, block->ops_block.condition); - if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue, - block->ops_block.condition, - msecs_to_jiffies(SST_BLOCK_TIMEOUT))) { - /* event wake */ - pr_debug("Event wake %x\n", block->ops_block.condition); - pr_debug("message ret: %d\n", block->ops_block.ret_code); - retval = block->ops_block.ret_code; - } else { - block->ops_block.on = false; - pr_err("Wait timed-out %x\n", block->ops_block.condition); - /* settign firmware state as uninit so that the - firmware will get redownloaded on next request - this is because firmare not responding for 5 sec - is equalant to some unrecoverable error of FW - sst_drv_ctx->sst_state = SST_UN_INIT;*/ - retval = -EBUSY; - } - return retval; - -} - -/* - * sst_create_large_msg - create a large IPC message - * - * @arg: ipc message - * - * this function allocates structures to send a large message to the firmware - */ -int sst_create_large_msg(struct ipc_post **arg) -{ - struct ipc_post *msg; - - msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); - if (!msg) { - pr_err("kzalloc msg failed\n"); - return -ENOMEM; - } - - msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); - if (!msg->mailbox_data) { - kfree(msg); - pr_err("kzalloc mailbox_data failed"); - return -ENOMEM; - } - *arg = msg; - return 0; -} - -/* - * sst_create_short_msg - create a short IPC message - * - * @arg: ipc message - * - * this function allocates structures to send a short message to the firmware - */ -int sst_create_short_msg(struct ipc_post **arg) -{ - struct ipc_post *msg; - - msg = kzalloc(sizeof(*msg), GFP_ATOMIC); - if (!msg) { - pr_err("kzalloc msg failed\n"); - return -ENOMEM; - } - msg->mailbox_data = NULL; - *arg = msg; - return 0; -} - -/* - * sst_clean_stream - clean the stream context - * - * @stream: stream structure - * - * this function resets the stream contexts - * should be called in free - */ -void sst_clean_stream(struct stream_info *stream) -{ - struct sst_stream_bufs *bufs = NULL, *_bufs; - stream->status = STREAM_UN_INIT; - stream->prev = STREAM_UN_INIT; - mutex_lock(&stream->lock); - list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) { - list_del(&bufs->node); - kfree(bufs); - } - mutex_unlock(&stream->lock); - - if (stream->ops != STREAM_OPS_PLAYBACK_DRM) - kfree(stream->decode_ibuf); -} - -/* - * sst_wake_up_alloc_block - wake up waiting block - * - * @sst_drv_ctx: Driver context - * @sst_id: stream id - * @status: status of wakeup - * @data: data pointer of wakeup - * - * This function wakes up a sleeping block event based on the response - */ -void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx, - u8 sst_id, int status, void *data) -{ - int i; - - /* Unblock with retval code */ - for (i = 0; i < MAX_ACTIVE_STREAM; i++) { - if (sst_id == sst_drv_ctx->alloc_block[i].sst_id) { - sst_drv_ctx->alloc_block[i].ops_block.condition = true; - sst_drv_ctx->alloc_block[i].ops_block.ret_code = status; - sst_drv_ctx->alloc_block[i].ops_block.data = data; - wake_up(&sst_drv_ctx->wait_queue); - break; - } - } -} - -/* - * sst_enable_rx_timeslot - Send msg to query for stream parameters - * @status: rx timeslot to be enabled - * - * This function is called when the RX timeslot is required to be enabled - */ -int sst_enable_rx_timeslot(int status) -{ - int retval = 0; - struct ipc_post *msg = NULL; - - if (sst_create_short_msg(&msg)) { - pr_err("mem allocation failed\n"); - return -ENOMEM; - } - pr_debug("ipc message sending: ENABLE_RX_TIME_SLOT\n"); - sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0); - msg->header.part.data = status; - sst_drv_ctx->hs_info_blk.condition = false; - sst_drv_ctx->hs_info_blk.ret_code = 0; - sst_drv_ctx->hs_info_blk.on = true; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, - &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT); - return retval; -} - diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/drivers/staging/intel_sst/intel_sst_stream.c deleted file mode 100644 index be4565e74f8..00000000000 --- a/drivers/staging/intel_sst/intel_sst_stream.c +++ /dev/null @@ -1,583 +0,0 @@ -/* - * intel_sst_stream.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file contains the stream operations of SST driver - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/firmware.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include "intel_sst_ioctl.h" -#include "intel_sst.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" - -/* - * sst_check_device_type - Check the medfield device type - * - * @device: Device to be checked - * @num_ch: Number of channels queried - * @pcm_slot: slot to be enabled for this device - * - * This checks the deivce against the map and calculates pcm_slot value - */ -int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot) -{ - if (device >= MAX_NUM_STREAMS_MFLD) { - pr_debug("device type invalid %d\n", device); - return -EINVAL; - } - if (sst_drv_ctx->streams[device].status == STREAM_UN_INIT) { - if (device == SND_SST_DEVICE_VIBRA && num_chan == 1) - *pcm_slot = 0x10; - else if (device == SND_SST_DEVICE_HAPTIC && num_chan == 1) - *pcm_slot = 0x20; - else if (device == SND_SST_DEVICE_IHF && num_chan == 1) - *pcm_slot = 0x04; - else if (device == SND_SST_DEVICE_IHF && num_chan == 2) - *pcm_slot = 0x0C; - else if (device == SND_SST_DEVICE_HEADSET && num_chan == 1) - *pcm_slot = 0x01; - else if (device == SND_SST_DEVICE_HEADSET && num_chan == 2) - *pcm_slot = 0x03; - else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 1) - *pcm_slot = 0x01; - else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 2) - *pcm_slot = 0x03; - else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 3) - *pcm_slot = 0x07; - else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4) - *pcm_slot = 0x0F; - else if (device == SND_SST_DEVICE_CAPTURE && num_chan > 4) - *pcm_slot = 0x1F; - else { - pr_debug("No condition satisfied.. ret err\n"); - return -EINVAL; - } - } else { - pr_debug("this stream state is not uni-init, is %d\n", - sst_drv_ctx->streams[device].status); - return -EBADRQC; - } - pr_debug("returning slot %x\n", *pcm_slot); - return 0; -} -/** - * get_mrst_stream_id - gets a new stream id for use - * - * This functions searches the current streams and allocated an empty stream - * lock stream_lock required to be held before calling this - */ -static unsigned int get_mrst_stream_id(void) -{ - int i; - - for (i = 1; i <= MAX_NUM_STREAMS_MRST; i++) { - if (sst_drv_ctx->streams[i].status == STREAM_UN_INIT) - return i; - } - pr_debug("Didn't find empty stream for mrst\n"); - return -EBUSY; -} - -/** - * sst_alloc_stream - Send msg for a new stream ID - * - * @params: stream params - * @stream_ops: operation of stream PB/capture - * @codec: codec for stream - * @device: device stream to be allocated for - * - * This function is called by any function which wants to start - * a new stream. This also check if a stream exists which is idle - * it initializes idle stream id to this request - */ -int sst_alloc_stream(char *params, unsigned int stream_ops, - u8 codec, unsigned int device) -{ - struct ipc_post *msg = NULL; - struct snd_sst_alloc_params alloc_param; - unsigned int pcm_slot = 0, num_ch; - int str_id; - struct snd_sst_stream_params *sparams; - struct stream_info *str_info; - - pr_debug("SST DBG:entering sst_alloc_stream\n"); - pr_debug("SST DBG:%d %d %d\n", stream_ops, codec, device); - - BUG_ON(!params); - sparams = (struct snd_sst_stream_params *)params; - num_ch = sparams->uc.pcm_params.num_chan; - /*check the device type*/ - if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) { - if (sst_check_device_type(device, num_ch, &pcm_slot)) - return -EINVAL; - mutex_lock(&sst_drv_ctx->stream_lock); - str_id = device; - mutex_unlock(&sst_drv_ctx->stream_lock); - pr_debug("SST_DBG: slot %x\n", pcm_slot); - } else { - mutex_lock(&sst_drv_ctx->stream_lock); - str_id = get_mrst_stream_id(); - mutex_unlock(&sst_drv_ctx->stream_lock); - if (str_id <= 0) - return -EBUSY; - } - /*allocate device type context*/ - sst_init_stream(&sst_drv_ctx->streams[str_id], codec, - str_id, stream_ops, pcm_slot, device); - /* send msg to FW to allocate a stream */ - if (sst_create_large_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, IPC_IA_ALLOC_STREAM, 1, str_id); - msg->header.part.data = sizeof(alloc_param) + sizeof(u32); - alloc_param.str_type.codec_type = codec; - alloc_param.str_type.str_type = SST_STREAM_TYPE_MUSIC; - alloc_param.str_type.operation = stream_ops; - alloc_param.str_type.protected_str = 0; /* non drm */ - alloc_param.str_type.time_slots = pcm_slot; - alloc_param.str_type.result = alloc_param.str_type.reserved = 0; - memcpy(&alloc_param.stream_params, params, - sizeof(struct snd_sst_stream_params)); - - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), &alloc_param, - sizeof(alloc_param)); - str_info = &sst_drv_ctx->streams[str_id]; - str_info->ctrl_blk.condition = false; - str_info->ctrl_blk.ret_code = 0; - str_info->ctrl_blk.on = true; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - pr_debug("SST DBG:alloc stream done\n"); - return str_id; -} - - -/* - * sst_alloc_stream_response - process alloc reply - * - * @str_id: stream id for which the stream has been allocated - * @resp the stream response from firware - * - * This function is called by firmware as a response to stream allcoation - * request - */ -int sst_alloc_stream_response(unsigned int str_id, - struct snd_sst_alloc_response *resp) -{ - int retval = 0; - struct stream_info *str_info; - struct snd_sst_lib_download *lib_dnld; - - pr_debug("SST DEBUG: stream number given = %d\n", str_id); - str_info = &sst_drv_ctx->streams[str_id]; - if (resp->str_type.result == SST_LIB_ERR_LIB_DNLD_REQUIRED) { - lib_dnld = kzalloc(sizeof(*lib_dnld), GFP_KERNEL); - memcpy(lib_dnld, &resp->lib_dnld, sizeof(*lib_dnld)); - } else - lib_dnld = NULL; - if (str_info->ctrl_blk.on == true) { - str_info->ctrl_blk.on = false; - str_info->ctrl_blk.data = lib_dnld; - str_info->ctrl_blk.condition = true; - str_info->ctrl_blk.ret_code = resp->str_type.result; - pr_debug("SST DEBUG: sst_alloc_stream_response: waking up.\n"); - wake_up(&sst_drv_ctx->wait_queue); - } - return retval; -} - - -/** -* sst_get_fw_info - Send msg to query for firmware configurations -* @info: out param that holds the firmare configurations -* -* This function is called when the firmware configurations are queiried for -*/ -int sst_get_fw_info(struct snd_sst_fw_info *info) -{ - int retval = 0; - struct ipc_post *msg = NULL; - - pr_debug("SST DBG:sst_get_fw_info called\n"); - - if (sst_create_short_msg(&msg)) { - pr_err("SST ERR: message creation failed\n"); - return -ENOMEM; - } - - sst_fill_header(&msg->header, IPC_IA_GET_FW_INFO, 0, 0); - sst_drv_ctx->fw_info_blk.condition = false; - sst_drv_ctx->fw_info_blk.ret_code = 0; - sst_drv_ctx->fw_info_blk.on = true; - sst_drv_ctx->fw_info_blk.data = info; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->fw_info_blk, SST_BLOCK_TIMEOUT); - if (retval) { - pr_err("SST ERR: error in fw_info = %d\n", retval); - retval = -EIO; - } - return retval; -} - - -/** -* sst_pause_stream - Send msg for a pausing stream -* @str_id: stream ID -* -* This function is called by any function which wants to pause -* an already running stream. -*/ -int sst_start_stream(int str_id) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct stream_info *str_info; - - pr_debug("sst_start_stream for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - str_info = &sst_drv_ctx->streams[str_id]; - if (str_info->status != STREAM_INIT) - return -EBADRQC; - if (sst_create_short_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, IPC_IA_START_STREAM, 0, str_id); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - return retval; -} - -/* - * sst_pause_stream - Send msg for a pausing stream - * @str_id: stream ID - * - * This function is called by any function which wants to pause - * an already running stream. - */ -int sst_pause_stream(int str_id) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct stream_info *str_info; - - pr_debug("SST DBG:sst_pause_stream for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - str_info = &sst_drv_ctx->streams[str_id]; - if (str_info->status == STREAM_PAUSED) - return 0; - if (str_info->status == STREAM_RUNNING || - str_info->status == STREAM_INIT) { - if (str_info->prev == STREAM_UN_INIT) - return -EBADRQC; - if (str_info->ctrl_blk.on == true) { - pr_err("SST ERR: control path is in use\n"); - return -EINVAL; - } - if (sst_create_short_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, IPC_IA_PAUSE_STREAM, 0, str_id); - str_info->ctrl_blk.condition = false; - str_info->ctrl_blk.ret_code = 0; - str_info->ctrl_blk.on = true; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, - &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); - if (retval == 0) { - str_info->prev = str_info->status; - str_info->status = STREAM_PAUSED; - } else if (retval == SST_ERR_INVALID_STREAM_ID) { - retval = -EINVAL; - mutex_lock(&sst_drv_ctx->stream_lock); - sst_clean_stream(str_info); - mutex_unlock(&sst_drv_ctx->stream_lock); - } - } else { - retval = -EBADRQC; - pr_err("SST ERR: BADQRC for stream\n"); - } - - return retval; -} - -/** - * sst_resume_stream - Send msg for resuming stream - * @str_id: stream ID - * - * This function is called by any function which wants to resume - * an already paused stream. - */ -int sst_resume_stream(int str_id) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct stream_info *str_info; - - pr_debug("SST DBG:sst_resume_stream for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - str_info = &sst_drv_ctx->streams[str_id]; - if (str_info->status == STREAM_RUNNING) - return 0; - if (str_info->status == STREAM_PAUSED) { - if (str_info->ctrl_blk.on == true) { - pr_err("SST ERR: control path in use\n"); - return -EINVAL; - } - if (sst_create_short_msg(&msg)) { - pr_err("SST ERR: mem allocation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_RESUME_STREAM, 0, str_id); - str_info->ctrl_blk.condition = false; - str_info->ctrl_blk.ret_code = 0; - str_info->ctrl_blk.on = true; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, - &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); - if (!retval) { - if (str_info->prev == STREAM_RUNNING) - str_info->status = STREAM_RUNNING; - else - str_info->status = STREAM_INIT; - str_info->prev = STREAM_PAUSED; - } else if (retval == -SST_ERR_INVALID_STREAM_ID) { - retval = -EINVAL; - mutex_lock(&sst_drv_ctx->stream_lock); - sst_clean_stream(str_info); - mutex_unlock(&sst_drv_ctx->stream_lock); - } - } else { - retval = -EBADRQC; - pr_err("SST ERR: BADQRC for stream\n"); - } - - return retval; -} - - -/** - * sst_drop_stream - Send msg for stopping stream - * @str_id: stream ID - * - * This function is called by any function which wants to stop - * a stream. - */ -int sst_drop_stream(int str_id) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct sst_stream_bufs *bufs = NULL, *_bufs; - struct stream_info *str_info; - - pr_debug("SST DBG:sst_drop_stream for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - str_info = &sst_drv_ctx->streams[str_id]; - - if (str_info->status != STREAM_UN_INIT && - str_info->status != STREAM_DECODE) { - if (str_info->ctrl_blk.on == true) { - pr_err("SST ERR: control path in use\n"); - return -EINVAL; - } - if (sst_create_short_msg(&msg)) { - pr_err("SST ERR: mem allocation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_DROP_STREAM, 0, str_id); - str_info->ctrl_blk.condition = false; - str_info->ctrl_blk.ret_code = 0; - str_info->ctrl_blk.on = true; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, - &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); - if (!retval) { - pr_debug("SST DBG:drop success\n"); - str_info->prev = STREAM_UN_INIT; - str_info->status = STREAM_INIT; - if (str_info->src != MAD_DRV) { - mutex_lock(&str_info->lock); - list_for_each_entry_safe(bufs, _bufs, - &str_info->bufs, node) { - list_del(&bufs->node); - kfree(bufs); - } - mutex_unlock(&str_info->lock); - } - str_info->cumm_bytes += str_info->curr_bytes; - } else if (retval == -SST_ERR_INVALID_STREAM_ID) { - retval = -EINVAL; - mutex_lock(&sst_drv_ctx->stream_lock); - sst_clean_stream(str_info); - mutex_unlock(&sst_drv_ctx->stream_lock); - } - if (str_info->data_blk.on == true) { - str_info->data_blk.condition = true; - str_info->data_blk.ret_code = retval; - wake_up(&sst_drv_ctx->wait_queue); - } - } else { - retval = -EBADRQC; - pr_err("SST ERR: BADQRC for stream\n"); - } - return retval; -} - -/** -* sst_drain_stream - Send msg for draining stream -* @str_id: stream ID -* -* This function is called by any function which wants to drain -* a stream. -*/ -int sst_drain_stream(int str_id) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct stream_info *str_info; - - pr_debug("SST DBG:sst_drain_stream for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - str_info = &sst_drv_ctx->streams[str_id]; - - if (str_info->status != STREAM_RUNNING && - str_info->status != STREAM_INIT && - str_info->status != STREAM_PAUSED) { - pr_err("SST ERR: BADQRC for stream = %d\n", - str_info->status); - return -EBADRQC; - } - - if (str_info->status == STREAM_INIT) { - if (sst_create_short_msg(&msg)) { - pr_err("SST ERR: mem allocation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, 0, str_id); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - } else - str_info->need_draining = true; - str_info->data_blk.condition = false; - str_info->data_blk.ret_code = 0; - str_info->data_blk.on = true; - retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk); - str_info->need_draining = false; - return retval; -} - -/** - * sst_free_stream - Frees a stream - * @str_id: stream ID - * - * This function is called by any function which wants to free - * a stream. - */ -int sst_free_stream(int str_id) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct stream_info *str_info; - - pr_debug("SST DBG:sst_free_stream for %d\n", str_id); - - retval = sst_validate_strid(str_id); - if (retval) - return retval; - str_info = &sst_drv_ctx->streams[str_id]; - - if (str_info->status != STREAM_UN_INIT) { - if (sst_create_short_msg(&msg)) { - pr_err("SST ERR: mem allocation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - str_info->prev = str_info->status; - str_info->status = STREAM_UN_INIT; - if (str_info->data_blk.on == true) { - str_info->data_blk.condition = true; - str_info->data_blk.ret_code = 0; - wake_up(&sst_drv_ctx->wait_queue); - } - str_info->data_blk.on = true; - str_info->data_blk.condition = false; - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); - pr_debug("wait for free returned %d\n", retval); - msleep(100); - mutex_lock(&sst_drv_ctx->stream_lock); - sst_clean_stream(str_info); - mutex_unlock(&sst_drv_ctx->stream_lock); - pr_debug("SST DBG:Stream freed\n"); - } else { - retval = -EBADRQC; - pr_debug("SST DBG:BADQRC for stream\n"); - } - - return retval; -} - - diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c deleted file mode 100644 index 2be58c5cba0..00000000000 --- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c +++ /dev/null @@ -1,1273 +0,0 @@ -/* - * intel_sst_stream.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file contains the stream operations of SST driver - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/syscalls.h> -#include <linux/firmware.h> -#include <linux/sched.h> -#ifdef CONFIG_MRST_RAR_HANDLER -#include <linux/rar_register.h> -#include "../memrar/memrar.h" -#endif -#include "intel_sst_ioctl.h" -#include "intel_sst.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" -/** -* sst_get_stream_params - Send msg to query for stream parameters -* @str_id: stream id for which the parameters are queried for -* @get_params: out parameters to which the parameters are copied to -* -* This function is called when the stream parameters are queiried for -*/ -int sst_get_stream_params(int str_id, - struct snd_sst_get_stream_params *get_params) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct stream_info *str_info; - struct snd_sst_fw_get_stream_params *fw_params; - - pr_debug("get_stream for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - - str_info = &sst_drv_ctx->streams[str_id]; - if (str_info->status != STREAM_UN_INIT) { - if (str_info->ctrl_blk.on == true) { - pr_err("control path in use\n"); - return -EINVAL; - } - if (sst_create_short_msg(&msg)) { - pr_err("message creation failed\n"); - return -ENOMEM; - } - fw_params = kzalloc(sizeof(*fw_params), GFP_ATOMIC); - if (!fw_params) { - pr_err("mem allocation failed\n"); - kfree(msg); - return -ENOMEM; - } - - sst_fill_header(&msg->header, IPC_IA_GET_STREAM_PARAMS, - 0, str_id); - str_info->ctrl_blk.condition = false; - str_info->ctrl_blk.ret_code = 0; - str_info->ctrl_blk.on = true; - str_info->ctrl_blk.data = (void *) fw_params; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); - if (retval) { - get_params->codec_params.result = retval; - kfree(fw_params); - return -EIO; - } - memcpy(&get_params->pcm_params, &fw_params->pcm_params, - sizeof(fw_params->pcm_params)); - memcpy(&get_params->codec_params.sparams, - &fw_params->codec_params, - sizeof(fw_params->codec_params)); - get_params->codec_params.result = 0; - get_params->codec_params.stream_id = str_id; - get_params->codec_params.codec = str_info->codec; - get_params->codec_params.ops = str_info->ops; - get_params->codec_params.stream_type = str_info->str_type; - kfree(fw_params); - } else { - pr_debug("Stream is not in the init state\n"); - } - return retval; -} - -/** - * sst_set_stream_param - Send msg for setting stream parameters - * - * @str_id: stream id - * @str_param: stream params - * - * This function sets stream params during runtime - */ -int sst_set_stream_param(int str_id, struct snd_sst_params *str_param) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct stream_info *str_info; - - BUG_ON(!str_param); - if (sst_drv_ctx->streams[str_id].ops != str_param->ops) { - pr_err("Invalid operation\n"); - return -EINVAL; - } - retval = sst_validate_strid(str_id); - if (retval) - return retval; - pr_debug("set_stream for %d\n", str_id); - str_info = &sst_drv_ctx->streams[str_id]; - if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) { - if (str_info->ctrl_blk.on == true) { - pr_err("control path in use\n"); - return -EAGAIN; - } - if (sst_create_large_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, - IPC_IA_SET_STREAM_PARAMS, 1, str_id); - str_info->ctrl_blk.condition = false; - str_info->ctrl_blk.ret_code = 0; - str_info->ctrl_blk.on = true; - msg->header.part.data = sizeof(u32) + - sizeof(str_param->sparams); - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), &str_param->sparams, - sizeof(str_param->sparams)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); - if (retval < 0) { - retval = -EIO; - sst_clean_stream(str_info); - } - } else { - retval = -EBADRQC; - pr_err("BADQRC for stream\n"); - } - return retval; -} - -/** -* sst_get_vol - This function allows to get the premix gain or gain of a stream -* -* @get_vol: this is an output param through which the volume -* structure is passed back to user -* -* This function is called when the premix gain or stream gain is queried for -*/ -int sst_get_vol(struct snd_sst_vol *get_vol) -{ - int retval = 0; - struct ipc_post *msg = NULL; - struct snd_sst_vol *fw_get_vol; - int str_id = get_vol->stream_id; - - pr_debug("get vol called\n"); - - if (sst_create_short_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, - IPC_IA_GET_STREAM_VOL, 0, str_id); - sst_drv_ctx->vol_info_blk.condition = false; - sst_drv_ctx->vol_info_blk.ret_code = 0; - sst_drv_ctx->vol_info_blk.on = true; - fw_get_vol = kzalloc(sizeof(*fw_get_vol), GFP_ATOMIC); - if (!fw_get_vol) { - pr_err("mem allocation failed\n"); - kfree(msg); - return -ENOMEM; - } - sst_drv_ctx->vol_info_blk.data = (void *)fw_get_vol; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT); - if (retval) - retval = -EIO; - else { - pr_debug("stream id %d\n", fw_get_vol->stream_id); - pr_debug("volume %d\n", fw_get_vol->volume); - pr_debug("ramp duration %d\n", fw_get_vol->ramp_duration); - pr_debug("ramp_type %d\n", fw_get_vol->ramp_type); - memcpy(get_vol, fw_get_vol, sizeof(*fw_get_vol)); - } - return retval; -} - -/** -* sst_set_vol - This function allows to set the premix gain or gain of a stream -* -* @set_vol: this holds the volume structure that needs to be set -* -* This function is called when premix gain or stream gain is requested to be set -*/ -int sst_set_vol(struct snd_sst_vol *set_vol) -{ - - int retval = 0; - struct ipc_post *msg = NULL; - - pr_debug("set vol called\n"); - - if (sst_create_large_msg(&msg)) { - pr_err("message creation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_SET_STREAM_VOL, 1, - set_vol->stream_id); - - msg->header.part.data = sizeof(u32) + sizeof(*set_vol); - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), set_vol, sizeof(*set_vol)); - sst_drv_ctx->vol_info_blk.condition = false; - sst_drv_ctx->vol_info_blk.ret_code = 0; - sst_drv_ctx->vol_info_blk.on = true; - sst_drv_ctx->vol_info_blk.data = set_vol; - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT); - if (retval) { - pr_err("error in set_vol = %d\n", retval); - retval = -EIO; - } - return retval; -} - -/** -* sst_set_mute - This function sets premix mute or soft mute of a stream -* -* @set_mute: this holds the mute structure that needs to be set -* -* This function is called when premix mute or stream mute requested to be set -*/ -int sst_set_mute(struct snd_sst_mute *set_mute) -{ - - int retval = 0; - struct ipc_post *msg = NULL; - - pr_debug("set mute called\n"); - - if (sst_create_large_msg(&msg)) { - pr_err("message creation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_SET_STREAM_MUTE, 1, - set_mute->stream_id); - sst_drv_ctx->mute_info_blk.condition = false; - sst_drv_ctx->mute_info_blk.ret_code = 0; - sst_drv_ctx->mute_info_blk.on = true; - sst_drv_ctx->mute_info_blk.data = set_mute; - - msg->header.part.data = sizeof(u32) + sizeof(*set_mute); - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), set_mute, - sizeof(*set_mute)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->mute_info_blk, SST_BLOCK_TIMEOUT); - if (retval) { - pr_err("error in set_mute = %d\n", retval); - retval = -EIO; - } - return retval; -} - -int sst_prepare_target(struct snd_sst_slot_info *slot) -{ - if (slot->target_device == SND_SST_TARGET_PMIC - && slot->device_instance == 1) { - /*music mode*/ - if (sst_drv_ctx->pmic_port_instance == 0) - sst_drv_ctx->scard_ops->set_voice_port( - DEACTIVATE); - } else if ((slot->target_device == SND_SST_TARGET_PMIC || - slot->target_device == SND_SST_TARGET_MODEM) && - slot->device_instance == 0) { - /*voip mode where pcm0 is active*/ - if (sst_drv_ctx->pmic_port_instance == 1) - sst_drv_ctx->scard_ops->set_audio_port( - DEACTIVATE); - } - return 0; -} - -int sst_activate_target(struct snd_sst_slot_info *slot) -{ - if (slot->target_device == SND_SST_TARGET_PMIC && - slot->device_instance == 1) { - /*music mode*/ - sst_drv_ctx->pmic_port_instance = 1; - sst_drv_ctx->scard_ops->set_audio_port(ACTIVATE); - sst_drv_ctx->scard_ops->set_pcm_audio_params( - slot->pcm_params.sfreq, - slot->pcm_params.pcm_wd_sz, - slot->pcm_params.num_chan); - if (sst_drv_ctx->pb_streams) - sst_drv_ctx->scard_ops->power_up_pmic_pb(1); - if (sst_drv_ctx->cp_streams) - sst_drv_ctx->scard_ops->power_up_pmic_cp(1); - } else if ((slot->target_device == SND_SST_TARGET_PMIC || - slot->target_device == SND_SST_TARGET_MODEM) && - slot->device_instance == 0) { - /*voip mode where pcm0 is active*/ - sst_drv_ctx->pmic_port_instance = 0; - sst_drv_ctx->scard_ops->set_voice_port( - ACTIVATE); - sst_drv_ctx->scard_ops->power_up_pmic_pb(0); - /*sst_drv_ctx->scard_ops->power_up_pmic_cp(0);*/ - } - return 0; -} - -int sst_parse_target(struct snd_sst_slot_info *slot) -{ - int retval = 0; - - if (slot->action == SND_SST_PORT_ACTIVATE && - slot->device_type == SND_SST_DEVICE_PCM) { - retval = sst_activate_target(slot); - if (retval) - pr_err("SST_Activate_target_fail\n"); - else - pr_err("SST_Activate_target_pass\n"); - } else if (slot->action == SND_SST_PORT_PREPARE && - slot->device_type == SND_SST_DEVICE_PCM) { - retval = sst_prepare_target(slot); - if (retval) - pr_err("SST_prepare_target_fail\n"); - else - pr_err("SST_prepare_target_pass\n"); - } else { - pr_err("slot_action : %d, device_type: %d\n", - slot->action, slot->device_type); - } - return retval; -} - -int sst_send_target(struct snd_sst_target_device *target) -{ - int retval; - struct ipc_post *msg; - - if (sst_create_large_msg(&msg)) { - pr_err("message creation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT, 1, 0); - sst_drv_ctx->tgt_dev_blk.condition = false; - sst_drv_ctx->tgt_dev_blk.ret_code = 0; - sst_drv_ctx->tgt_dev_blk.on = true; - - msg->header.part.data = sizeof(u32) + sizeof(*target); - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), target, - sizeof(*target)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - pr_debug("message sent- waiting\n"); - retval = sst_wait_interruptible_timeout(sst_drv_ctx, - &sst_drv_ctx->tgt_dev_blk, TARGET_DEV_BLOCK_TIMEOUT); - if (retval) - pr_err("target device ipc failed = 0x%x\n", retval); - return retval; - -} - -int sst_target_device_validate(struct snd_sst_target_device *target) -{ - int retval = 0; - int i; - - for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) { - if (target->devices[i].device_type == SND_SST_DEVICE_PCM) { - /*pcm device, check params*/ - if (target->devices[i].device_instance == 1) { - if ((target->devices[i].device_mode != - SND_SST_DEV_MODE_PCM_MODE4_I2S) && - (target->devices[i].device_mode != - SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED) - && (target->devices[i].device_mode != - SND_SST_DEV_MODE_PCM_MODE1)) - goto err; - } else if (target->devices[i].device_instance == 0) { - if ((target->devices[i].device_mode != - SND_SST_DEV_MODE_PCM_MODE2) - && (target->devices[i].device_mode != - SND_SST_DEV_MODE_PCM_MODE4_I2S) - && (target->devices[i].device_mode != - SND_SST_DEV_MODE_PCM_MODE1)) - goto err; - if (target->devices[i].pcm_params.sfreq != 8000 - || target->devices[i].pcm_params.num_chan != 1 - || target->devices[i].pcm_params.pcm_wd_sz != - 16) - goto err; - } else { -err: - pr_err("i/p params incorrect\n"); - return -EINVAL; - } - } - } - return retval; -} - -/** - * sst_target_device_select - This function sets the target device configurations - * - * @target: this parameter holds the configurations to be set - * - * This function is called when the user layer wants to change the target - * device's configurations - */ - -int sst_target_device_select(struct snd_sst_target_device *target) -{ - int retval, i, prepare_count = 0; - - pr_debug("Target Device Select\n"); - - if (target->device_route < 0 || target->device_route > 2) { - pr_err("device route is invalid\n"); - return -EINVAL; - } - - if (target->device_route != 0) { - pr_err("Unsupported config\n"); - return -EIO; - } - retval = sst_target_device_validate(target); - if (retval) - return retval; - - retval = sst_send_target(target); - if (retval) - return retval; - for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) { - if (target->devices[i].action == SND_SST_PORT_ACTIVATE) { - pr_debug("activate called in %d\n", i); - retval = sst_parse_target(&target->devices[i]); - if (retval) - return retval; - } else if (target->devices[i].action == SND_SST_PORT_PREPARE) { - pr_debug("PREPARE in %d, Forwarding\n", i); - retval = sst_parse_target(&target->devices[i]); - if (retval) { - pr_err("Parse Target fail %d\n", retval); - return retval; - } - pr_debug("Parse Target successful %d\n", retval); - if (target->devices[i].device_type == - SND_SST_DEVICE_PCM) - prepare_count++; - } - } - if (target->devices[0].action == SND_SST_PORT_PREPARE && - prepare_count == 0) - sst_drv_ctx->scard_ops->power_down_pmic(); - - return retval; -} -#ifdef CONFIG_MRST_RAR_HANDLER -/*This function gets the physical address of the secure memory from the handle*/ -static inline int sst_get_RAR(struct RAR_buffer *buffers, int count) -{ - int retval = 0, rar_status = 0; - - rar_status = rar_handle_to_bus(buffers, count); - - if (count != rar_status) { - pr_err("The rar CALL Failed"); - retval = -EIO; - } - if (buffers->info.type != RAR_TYPE_AUDIO) { - pr_err("Invalid RAR type\n"); - return -EINVAL; - } - return retval; -} - -#endif - -/* This function creates the scatter gather list to be sent to firmware to -capture/playback data*/ -static int sst_create_sg_list(struct stream_info *stream, - struct sst_frame_info *sg_list) -{ - struct sst_stream_bufs *kbufs = NULL; -#ifdef CONFIG_MRST_RAR_HANDLER - struct RAR_buffer rar_buffers; - int retval = 0; -#endif - int i = 0; - list_for_each_entry(kbufs, &stream->bufs, node) { - if (kbufs->in_use == false) { -#ifdef CONFIG_MRST_RAR_HANDLER - if (stream->ops == STREAM_OPS_PLAYBACK_DRM) { - pr_debug("DRM playback handling\n"); - rar_buffers.info.handle = (__u32)kbufs->addr; - rar_buffers.info.size = kbufs->size; - pr_debug("rar handle 0x%x size=0x%x\n", - rar_buffers.info.handle, - rar_buffers.info.size); - retval = sst_get_RAR(&rar_buffers, 1); - - if (retval) - return retval; - sg_list->addr[i].addr = rar_buffers.bus_address; - /* rar_buffers.info.size; */ - sg_list->addr[i].size = (__u32)kbufs->size; - pr_debug("phyaddr[%d] 0x%x Size:0x%x\n" - , i, sg_list->addr[i].addr, - sg_list->addr[i].size); - } -#endif - if (stream->ops != STREAM_OPS_PLAYBACK_DRM) { - sg_list->addr[i].addr = - virt_to_phys((void *) - kbufs->addr + kbufs->offset); - sg_list->addr[i].size = kbufs->size; - pr_debug("phyaddr[%d]:0x%x Size:0x%x\n" - , i , sg_list->addr[i].addr, kbufs->size); - } - stream->curr_bytes += sg_list->addr[i].size; - kbufs->in_use = true; - i++; - } - if (i >= MAX_NUM_SCATTER_BUFFERS) - break; - } - - sg_list->num_entries = i; - pr_debug("sg list entries = %d\n", sg_list->num_entries); - return i; -} - - -/** - * sst_play_frame - Send msg for sending stream frames - * - * @str_id: ID of stream - * - * This function is called to send data to be played out - * to the firmware - */ -int sst_play_frame(int str_id) -{ - int i = 0, retval = 0; - struct ipc_post *msg = NULL; - struct sst_frame_info sg_list = {0}; - struct sst_stream_bufs *kbufs = NULL, *_kbufs; - struct stream_info *stream; - - pr_debug("play frame for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - - stream = &sst_drv_ctx->streams[str_id]; - /* clear prev sent buffers */ - list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { - if (kbufs->in_use == true) { - spin_lock(&stream->pcm_lock); - list_del(&kbufs->node); - spin_unlock(&stream->pcm_lock); - kfree(kbufs); - } - } - /* update bytes sent */ - stream->cumm_bytes += stream->curr_bytes; - stream->curr_bytes = 0; - if (list_empty(&stream->bufs)) { - /* no user buffer available */ - pr_debug("Null buffer stream status %d\n", stream->status); - stream->prev = stream->status; - stream->status = STREAM_INIT; - pr_debug("new stream status = %d\n", stream->status); - if (stream->need_draining == true) { - pr_debug("draining stream\n"); - if (sst_create_short_msg(&msg)) { - pr_err("mem allocation failed\n"); - return -ENOMEM; - } - sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, - 0, str_id); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, - &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - } else if (stream->data_blk.on == true) { - pr_debug("user list empty.. wake\n"); - /* unblock */ - stream->data_blk.ret_code = 0; - stream->data_blk.condition = true; - stream->data_blk.on = false; - wake_up(&sst_drv_ctx->wait_queue); - } - return 0; - } - - /* create list */ - i = sst_create_sg_list(stream, &sg_list); - - /* post msg */ - if (sst_create_large_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, IPC_IA_PLAY_FRAMES, 1, str_id); - msg->header.part.data = sizeof(u32) + sizeof(sg_list); - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - return 0; - -} - -/** - * sst_capture_frame - Send msg for sending stream frames - * - * @str_id: ID of stream - * - * This function is called to capture data from the firmware - */ -int sst_capture_frame(int str_id) -{ - int i = 0, retval = 0; - struct ipc_post *msg = NULL; - struct sst_frame_info sg_list = {0}; - struct sst_stream_bufs *kbufs = NULL, *_kbufs; - struct stream_info *stream; - - - pr_debug("capture frame for %d\n", str_id); - retval = sst_validate_strid(str_id); - if (retval) - return retval; - stream = &sst_drv_ctx->streams[str_id]; - /* clear prev sent buffers */ - list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { - if (kbufs->in_use == true) { - list_del(&kbufs->node); - kfree(kbufs); - pr_debug("del node\n"); - } - } - if (list_empty(&stream->bufs)) { - /* no user buffer available */ - pr_debug("Null buffer!!!!stream status %d\n", - stream->status); - stream->prev = stream->status; - stream->status = STREAM_INIT; - pr_debug("new stream status = %d\n", - stream->status); - if (stream->data_blk.on == true) { - pr_debug("user list empty.. wake\n"); - /* unblock */ - stream->data_blk.ret_code = 0; - stream->data_blk.condition = true; - stream->data_blk.on = false; - wake_up(&sst_drv_ctx->wait_queue); - - } - return 0; - } - /* create new sg list */ - i = sst_create_sg_list(stream, &sg_list); - - /* post msg */ - if (sst_create_large_msg(&msg)) - return -ENOMEM; - - sst_fill_header(&msg->header, IPC_IA_CAPT_FRAMES, 1, str_id); - msg->header.part.data = sizeof(u32) + sizeof(sg_list); - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - - - /*update bytes recevied*/ - stream->cumm_bytes += stream->curr_bytes; - stream->curr_bytes = 0; - - pr_debug("Cum bytes = %d\n", stream->cumm_bytes); - return 0; -} - -/*This function is used to calculate the minimum size of input buffers given*/ -static unsigned int calculate_min_size(struct snd_sst_buffs *bufs) -{ - int i, min_val = bufs->buff_entry[0].size; - for (i = 1 ; i < bufs->entries; i++) { - if (bufs->buff_entry[i].size < min_val) - min_val = bufs->buff_entry[i].size; - } - pr_debug("min_val = %d\n", min_val); - return min_val; -} - -static unsigned int calculate_max_size(struct snd_sst_buffs *bufs) -{ - int i, max_val = bufs->buff_entry[0].size; - for (i = 1 ; i < bufs->entries; i++) { - if (bufs->buff_entry[i].size > max_val) - max_val = bufs->buff_entry[i].size; - } - pr_debug("max_val = %d\n", max_val); - return max_val; -} - -/*This function is used to allocate input and output buffers to be sent to -the firmware that will take encoded data and return decoded data*/ -static int sst_allocate_decode_buf(struct stream_info *str_info, - struct snd_sst_dbufs *dbufs, - unsigned int cum_input_given, - unsigned int cum_output_given) -{ -#ifdef CONFIG_MRST_RAR_HANDLER - if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { - - if (dbufs->ibufs->type == SST_BUF_RAR && - dbufs->obufs->type == SST_BUF_RAR) { - if (dbufs->ibufs->entries == dbufs->obufs->entries) - return 0; - else { - pr_err("RAR entries dont match\n"); - return -EINVAL; - } - } else - str_info->decode_osize = cum_output_given; - return 0; - - } -#endif - if (!str_info->decode_ibuf) { - pr_debug("no i/p buffers, trying full size\n"); - str_info->decode_isize = cum_input_given; - str_info->decode_ibuf = kzalloc(str_info->decode_isize, - GFP_KERNEL); - str_info->idecode_alloc = str_info->decode_isize; - } - if (!str_info->decode_ibuf) { - pr_debug("buff alloc failed, try max size\n"); - str_info->decode_isize = calculate_max_size(dbufs->ibufs); - str_info->decode_ibuf = kzalloc( - str_info->decode_isize, GFP_KERNEL); - str_info->idecode_alloc = str_info->decode_isize; - } - if (!str_info->decode_ibuf) { - pr_debug("buff alloc failed, try min size\n"); - str_info->decode_isize = calculate_min_size(dbufs->ibufs); - str_info->decode_ibuf = kzalloc(str_info->decode_isize, - GFP_KERNEL); - if (!str_info->decode_ibuf) { - pr_err("mem allocation failed\n"); - return -ENOMEM; - } - str_info->idecode_alloc = str_info->decode_isize; - } - str_info->decode_osize = cum_output_given; - if (str_info->decode_osize > sst_drv_ctx->mmap_len) - str_info->decode_osize = sst_drv_ctx->mmap_len; - return 0; -} - -/*This function is used to send the message to firmware to decode the data*/ -static int sst_send_decode_mess(int str_id, struct stream_info *str_info, - struct snd_sst_decode_info *dec_info) -{ - struct ipc_post *msg = NULL; - int retval = 0; - - pr_debug("SST DBG:sst_set_mute:called\n"); - - if (str_info->decode_ibuf_type == SST_BUF_RAR) { -#ifdef CONFIG_MRST_RAR_HANDLER - dec_info->frames_in.addr[0].addr = - (unsigned long)str_info->decode_ibuf; - dec_info->frames_in.addr[0].size = - str_info->decode_isize; -#endif - - } else { - dec_info->frames_in.addr[0].addr = virt_to_phys((void *) - str_info->decode_ibuf); - dec_info->frames_in.addr[0].size = str_info->decode_isize; - } - - - if (str_info->decode_obuf_type == SST_BUF_RAR) { -#ifdef CONFIG_MRST_RAR_HANDLER - dec_info->frames_out.addr[0].addr = - (unsigned long)str_info->decode_obuf; - dec_info->frames_out.addr[0].size = str_info->decode_osize; -#endif - - } else { - dec_info->frames_out.addr[0].addr = virt_to_phys((void *) - str_info->decode_obuf) ; - dec_info->frames_out.addr[0].size = str_info->decode_osize; - } - - dec_info->frames_in.num_entries = 1; - dec_info->frames_out.num_entries = 1; - dec_info->frames_in.rsrvd = 0; - dec_info->frames_out.rsrvd = 0; - dec_info->input_bytes_consumed = 0; - dec_info->output_bytes_produced = 0; - if (sst_create_large_msg(&msg)) { - pr_err("message creation failed\n"); - return -ENOMEM; - } - - sst_fill_header(&msg->header, IPC_IA_DECODE_FRAMES, 1, str_id); - msg->header.part.data = sizeof(u32) + sizeof(*dec_info); - memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); - memcpy(msg->mailbox_data + sizeof(u32), dec_info, - sizeof(*dec_info)); - spin_lock(&sst_drv_ctx->list_spin_lock); - list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); - spin_unlock(&sst_drv_ctx->list_spin_lock); - str_info->data_blk.condition = false; - str_info->data_blk.ret_code = 0; - str_info->data_blk.on = true; - str_info->data_blk.data = dec_info; - sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk); - return retval; -} - -#ifdef CONFIG_MRST_RAR_HANDLER -static int sst_prepare_input_buffers_rar(struct stream_info *str_info, - struct snd_sst_dbufs *dbufs, - int *input_index, int *in_copied, - int *input_index_valid_size, int *new_entry_flag) -{ - int retval = 0, i; - - if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { - struct RAR_buffer rar_buffers; - __u32 info; - retval = copy_from_user((void *) &info, - dbufs->ibufs->buff_entry[i].buffer, - sizeof(__u32)); - if (retval) { - pr_err("cpy from user fail\n"); - return -EAGAIN; - } - rar_buffers.info.type = dbufs->ibufs->type; - rar_buffers.info.size = dbufs->ibufs->buff_entry[i].size; - rar_buffers.info.handle = info; - pr_debug("rar in DnR(input buffer function)=0x%x size=0x%x", - rar_buffers.info.handle, - rar_buffers.info.size); - retval = sst_get_RAR(&rar_buffers, 1); - if (retval) { - pr_debug("SST ERR: RAR API failed\n"); - return retval; - } - str_info->decode_ibuf = - (void *) ((unsigned long) rar_buffers.bus_address); - pr_debug("RAR buf addr in DnR (input buffer function)0x%lu", - (unsigned long) str_info->decode_ibuf); - pr_debug("rar in DnR decode function/output b_add rar =0x%lu", - (unsigned long) rar_buffers.bus_address); - *input_index = i + 1; - str_info->decode_isize = dbufs->ibufs->buff_entry[i].size; - str_info->decode_ibuf_type = dbufs->ibufs->type; - *in_copied = str_info->decode_isize; - } - return retval; -} -#endif -/*This function is used to prepare the kernel input buffers with contents -before sending for decode*/ -static int sst_prepare_input_buffers(struct stream_info *str_info, - struct snd_sst_dbufs *dbufs, - int *input_index, int *in_copied, - int *input_index_valid_size, int *new_entry_flag) -{ - int i, cpy_size, retval = 0; - - pr_debug("input_index = %d, input entries = %d\n", - *input_index, dbufs->ibufs->entries); - for (i = *input_index; i < dbufs->ibufs->entries; i++) { -#ifdef CONFIG_MRST_RAR_HANDLER - retval = sst_prepare_input_buffers_rar(str_info, - dbufs, input_index, in_copied, - input_index_valid_size, new_entry_flag); - if (retval) { - pr_err("In prepare input buffers for RAR\n"); - return -EIO; - } -#endif - *input_index = i; - if (*input_index_valid_size == 0) - *input_index_valid_size = - dbufs->ibufs->buff_entry[i].size; - pr_debug("inout addr = %p, size = %d\n", - dbufs->ibufs->buff_entry[i].buffer, - *input_index_valid_size); - pr_debug("decode_isize = %d, in_copied %d\n", - str_info->decode_isize, *in_copied); - if (*input_index_valid_size <= - (str_info->decode_isize - *in_copied)) - cpy_size = *input_index_valid_size; - else - cpy_size = str_info->decode_isize - *in_copied; - - pr_debug("cpy size = %d\n", cpy_size); - if (!dbufs->ibufs->buff_entry[i].buffer) { - pr_err("i/p buffer is null\n"); - return -EINVAL; - } - pr_debug("Try copy To %p, From %p, size %d\n", - str_info->decode_ibuf + *in_copied, - dbufs->ibufs->buff_entry[i].buffer, cpy_size); - - retval = - copy_from_user((void *)(str_info->decode_ibuf + *in_copied), - (void *) dbufs->ibufs->buff_entry[i].buffer, - cpy_size); - if (retval) { - pr_err("copy from user failed\n"); - return -EIO; - } - *in_copied += cpy_size; - *input_index_valid_size -= cpy_size; - pr_debug("in buff size = %d, in_copied = %d\n", - *input_index_valid_size, *in_copied); - if (*input_index_valid_size != 0) { - pr_debug("more input buffers left\n"); - dbufs->ibufs->buff_entry[i].buffer += cpy_size; - break; - } - if (*in_copied == str_info->decode_isize && - *input_index_valid_size == 0 && - (i+1) <= dbufs->ibufs->entries) { - pr_debug("all input buffers copied\n"); - *new_entry_flag = true; - *input_index = i + 1; - break; - } - } - return retval; -} - -/* This function is used to copy the decoded data from kernel buffers to -the user output buffers with contents after decode*/ -static int sst_prepare_output_buffers(struct stream_info *str_info, - struct snd_sst_dbufs *dbufs, - int *output_index, int output_size, - int *out_copied) - -{ - int i, cpy_size, retval = 0; - pr_debug("output_index = %d, output entries = %d\n", - *output_index, - dbufs->obufs->entries); - for (i = *output_index; i < dbufs->obufs->entries; i++) { - *output_index = i; - pr_debug("output addr = %p, size = %d\n", - dbufs->obufs->buff_entry[i].buffer, - dbufs->obufs->buff_entry[i].size); - pr_debug("output_size = %d, out_copied = %d\n", - output_size, *out_copied); - if (dbufs->obufs->buff_entry[i].size < - (output_size - *out_copied)) - cpy_size = dbufs->obufs->buff_entry[i].size; - else - cpy_size = output_size - *out_copied; - pr_debug("cpy size = %d\n", cpy_size); - pr_debug("Try copy To: %p, From %p, size %d\n", - dbufs->obufs->buff_entry[i].buffer, - sst_drv_ctx->mmap_mem + *out_copied, - cpy_size); - retval = copy_to_user(dbufs->obufs->buff_entry[i].buffer, - sst_drv_ctx->mmap_mem + *out_copied, - cpy_size); - if (retval) { - pr_err("copy to user failed\n"); - return -EIO; - } else - pr_debug("copy to user passed\n"); - *out_copied += cpy_size; - dbufs->obufs->buff_entry[i].size -= cpy_size; - pr_debug("o/p buff size %d, out_copied %d\n", - dbufs->obufs->buff_entry[i].size, *out_copied); - if (dbufs->obufs->buff_entry[i].size != 0) { - *output_index = i; - dbufs->obufs->buff_entry[i].buffer += cpy_size; - break; - } else if (*out_copied == output_size) { - *output_index = i + 1; - break; - } - } - return retval; -} - -/** - * sst_decode - Send msg for decoding frames - * - * @str_id: ID of stream - * @dbufs: param that holds the user input and output buffers and size - * - * This function is called to decode data from the firmware - */ -int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) -{ - int retval = 0, i; - unsigned long long total_input = 0 , total_output = 0; - unsigned int cum_input_given = 0 , cum_output_given = 0; - int copy_in_done = false, copy_out_done = false; - int input_index = 0, output_index = 0; - int input_index_valid_size = 0; - int in_copied, out_copied; - int new_entry_flag; - u64 output_size; - struct stream_info *str_info; - struct snd_sst_decode_info dec_info; - unsigned long long input_bytes, output_bytes; - - sst_drv_ctx->scard_ops->power_down_pmic(); - pr_debug("Powering_down_PMIC...\n"); - - retval = sst_validate_strid(str_id); - if (retval) - return retval; - - str_info = &sst_drv_ctx->streams[str_id]; - if (str_info->status != STREAM_INIT) { - pr_err("invalid stream state = %d\n", - str_info->status); - return -EINVAL; - } - - str_info->prev = str_info->status; - str_info->status = STREAM_DECODE; - - for (i = 0; i < dbufs->ibufs->entries; i++) - cum_input_given += dbufs->ibufs->buff_entry[i].size; - for (i = 0; i < dbufs->obufs->entries; i++) - cum_output_given += dbufs->obufs->buff_entry[i].size; - - /* input and output buffer allocation */ - retval = sst_allocate_decode_buf(str_info, dbufs, - cum_input_given, cum_output_given); - if (retval) { - pr_err("mem allocation failed, abort!!!\n"); - retval = -ENOMEM; - goto finish; - } - - str_info->decode_isize = str_info->idecode_alloc; - str_info->decode_ibuf_type = dbufs->ibufs->type; - str_info->decode_obuf_type = dbufs->obufs->type; - - while ((copy_out_done == false) && (copy_in_done == false)) { - in_copied = 0; - new_entry_flag = false; - retval = sst_prepare_input_buffers(str_info,\ - dbufs, &input_index, &in_copied, - &input_index_valid_size, &new_entry_flag); - if (retval) { - pr_err("prepare in buffers failed\n"); - goto finish; - } - - if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) - str_info->decode_obuf = sst_drv_ctx->mmap_mem; - -#ifdef CONFIG_MRST_RAR_HANDLER - else { - if (dbufs->obufs->type == SST_BUF_RAR) { - struct RAR_buffer rar_buffers; - __u32 info; - - pr_debug("DRM"); - retval = copy_from_user((void *) &info, - dbufs->obufs-> - buff_entry[output_index].buffer, - sizeof(__u32)); - - rar_buffers.info.size = dbufs->obufs-> - buff_entry[output_index].size; - rar_buffers.info.handle = info; - retval = sst_get_RAR(&rar_buffers, 1); - if (retval) - return retval; - - str_info->decode_obuf = (void *)((unsigned long) - rar_buffers.bus_address); - str_info->decode_osize = dbufs->obufs-> - buff_entry[output_index].size; - str_info->decode_obuf_type = dbufs->obufs->type; - pr_debug("DRM handling\n"); - pr_debug("o/p_add=0x%lu Size=0x%x\n", - (unsigned long) str_info->decode_obuf, - str_info->decode_osize); - } else { - str_info->decode_obuf = sst_drv_ctx->mmap_mem; - str_info->decode_osize = dbufs->obufs-> - buff_entry[output_index].size; - - } - } -#endif - if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { - if (str_info->decode_isize > in_copied) { - str_info->decode_isize = in_copied; - pr_debug("i/p size = %d\n", - str_info->decode_isize); - } - } - - - retval = sst_send_decode_mess(str_id, str_info, &dec_info); - if (retval || dec_info.input_bytes_consumed == 0) { - pr_err("SST ERR: mess failed or no input consumed\n"); - goto finish; - } - input_bytes = dec_info.input_bytes_consumed; - output_bytes = dec_info.output_bytes_produced; - - pr_debug("in_copied=%d, con=%lld, prod=%lld\n", - in_copied, input_bytes, output_bytes); - if (dbufs->obufs->type == SST_BUF_RAR) { - output_index += 1; - if (output_index == dbufs->obufs->entries) { - copy_in_done = true; - pr_debug("all i/p cpy done\n"); - } - total_output += output_bytes; - } else { - out_copied = 0; - output_size = output_bytes; - retval = sst_prepare_output_buffers(str_info, dbufs, - &output_index, output_size, &out_copied); - if (retval) { - pr_err("prep out buff fail\n"); - goto finish; - } - if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { - if (in_copied != input_bytes) { - int bytes_left = in_copied - - input_bytes; - pr_debug("bytes %d\n", - bytes_left); - if (new_entry_flag == true) - input_index--; - while (bytes_left) { - struct snd_sst_buffs *ibufs; - struct snd_sst_buff_entry - *buff_entry; - unsigned int size_sent; - - ibufs = dbufs->ibufs; - buff_entry = - &ibufs->buff_entry[input_index]; - size_sent = buff_entry->size -\ - input_index_valid_size; - if (bytes_left == size_sent) { - bytes_left = 0; - } else if (bytes_left < - size_sent) { - buff_entry->buffer += - (size_sent - - bytes_left); - buff_entry->size -= - (size_sent - - bytes_left); - bytes_left = 0; - } else { - bytes_left -= size_sent; - input_index--; - input_index_valid_size = - 0; - } - } - - } - } - - total_output += out_copied; - if (str_info->decode_osize != out_copied) { - str_info->decode_osize -= out_copied; - pr_debug("output size modified = %d\n", - str_info->decode_osize); - } - } - total_input += input_bytes; - - if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { - if (total_input == cum_input_given) - copy_in_done = true; - copy_out_done = true; - - } else { - if (total_output == cum_output_given) { - copy_out_done = true; - pr_debug("all o/p cpy done\n"); - } - - if (total_input == cum_input_given) { - copy_in_done = true; - pr_debug("all i/p cpy done\n"); - } - } - - pr_debug("copy_out = %d, copy_in = %d\n", - copy_out_done, copy_in_done); - } - -finish: - dbufs->input_bytes_consumed = total_input; - dbufs->output_bytes_produced = total_output; - str_info->status = str_info->prev; - str_info->prev = STREAM_DECODE; - kfree(str_info->decode_ibuf); - str_info->decode_ibuf = NULL; - return retval; -} diff --git a/drivers/staging/intel_sst/intelmid.c b/drivers/staging/intel_sst/intelmid.c deleted file mode 100644 index 492b660246b..00000000000 --- a/drivers/staging/intel_sst/intelmid.c +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * intelmid.c - Intel Sound card driver for MID - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Harsha Priya <priya.harsha@intel.com> - * Vinod Koul <vinod.koul@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * ALSA driver for Intel MID sound card chipset - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <linux/firmware.h> -#include <linux/input.h> -#include <sound/control.h> -#include <asm/mrst.h> -#include <sound/pcm.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> -#include <linux/gpio.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intel_sst_fw_ipc.h" -#include "intel_sst_common.h" -#include "intelmid_snd_control.h" -#include "intelmid_adc_control.h" -#include "intelmid.h" - -MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); -MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); -MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>"); -MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>"); -MODULE_DESCRIPTION("Intel MAD Sound card driver"); -MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("{Intel,Intel_MAD}"); - - -static int card_index = SNDRV_DEFAULT_IDX1;/* Index 0-MAX */ -static char *card_id = SNDRV_DEFAULT_STR1; /* ID for this card */ - -module_param(card_index, int, 0444); -MODULE_PARM_DESC(card_index, "Index value for INTELMAD soundcard."); -module_param(card_id, charp, 0444); -MODULE_PARM_DESC(card_id, "ID string for INTELMAD soundcard."); - -int sst_card_vendor_id; -int intelmid_audio_interrupt_enable;/*checkpatch fix*/ -struct snd_intelmad *intelmad_drv; - -#define INFO(_cpu_id, _irq_cache, _size) \ - ((kernel_ulong_t)&(struct snd_intelmad_probe_info) { \ - .cpu_id = (_cpu_id), \ - .irq_cache = (_irq_cache), \ - .size = (_size), \ - }) -/* Data path functionalities */ -static struct snd_pcm_hardware snd_intelmad_stream = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_DOUBLE | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_MMAP| - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_SYNC_START), - .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 | - SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 | - SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32), - .rates = (SNDRV_PCM_RATE_8000| - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000), - .rate_min = MIN_RATE, - - .rate_max = MAX_RATE, - .channels_min = MIN_CHANNEL, - .channels_max = MAX_CHANNEL_AMIC, - .buffer_bytes_max = MAX_BUFFER, - .period_bytes_min = MIN_PERIOD_BYTES, - .period_bytes_max = MAX_PERIOD_BYTES, - .periods_min = MIN_PERIODS, - .periods_max = MAX_PERIODS, - .fifo_size = FIFO_SIZE, -}; - - -/** - * snd_intelmad_pcm_trigger - stream activities are handled here - * - * @substream:substream for which the stream function is called - * @cmd:the stream commamd that requested from upper layer - * - * This function is called whenever an a stream activity is invoked - */ -static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - int ret_val = 0, str_id; - struct snd_intelmad *intelmaddata; - struct mad_stream_pvt *stream; - struct intel_sst_pcm_control *sst_ops; - - WARN_ON(!substream); - - intelmaddata = snd_pcm_substream_chip(substream); - stream = substream->runtime->private_data; - - WARN_ON(!intelmaddata->sstdrv_ops); - WARN_ON(!intelmaddata->sstdrv_ops->scard_ops); - sst_ops = intelmaddata->sstdrv_ops->pcm_control; - str_id = stream->stream_info.str_id; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - pr_debug("Trigger Start\n"); - ret_val = sst_ops->device_control(SST_SND_START, &str_id); - if (ret_val) - return ret_val; - stream->stream_status = RUNNING; - stream->substream = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - pr_debug("in stop\n"); - ret_val = sst_ops->device_control(SST_SND_DROP, &str_id); - if (ret_val) - return ret_val; - stream->stream_status = DROPPED; - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - pr_debug("in pause\n"); - ret_val = sst_ops->device_control(SST_SND_PAUSE, &str_id); - if (ret_val) - return ret_val; - stream->stream_status = PAUSED; - break; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - pr_debug("in pause release\n"); - ret_val = sst_ops->device_control(SST_SND_RESUME, &str_id); - if (ret_val) - return ret_val; - stream->stream_status = RUNNING; - break; - default: - return -EINVAL; - } - return ret_val; -} - -/** -* snd_intelmad_pcm_prepare- internal preparation before starting a stream -* -* @substream: substream for which the function is called -* -* This function is called when a stream is started for internal preparation. -*/ -static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct mad_stream_pvt *stream; - int ret_val = 0; - struct snd_intelmad *intelmaddata; - - pr_debug("pcm_prepare called\n"); - - WARN_ON(!substream); - stream = substream->runtime->private_data; - intelmaddata = snd_pcm_substream_chip(substream); - pr_debug("pb cnt = %d cap cnt = %d\n",\ - intelmaddata->playback_cnt, - intelmaddata->capture_cnt); - - if (stream->stream_info.str_id) { - pr_debug("Prepare called for already set stream\n"); - ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control( - SST_SND_DROP, &stream->stream_info.str_id); - return ret_val; - } - - ret_val = snd_intelmad_alloc_stream(substream); - if (ret_val < 0) - return ret_val; - stream->dbg_cum_bytes = 0; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - intelmaddata->playback_cnt++; - else - intelmaddata->capture_cnt++; - /* return back the stream id */ - snprintf(substream->pcm->id, sizeof(substream->pcm->id), - "%d", stream->stream_info.str_id); - pr_debug("stream id to user = %s\n", - substream->pcm->id); - - ret_val = snd_intelmad_init_stream(substream); - if (ret_val) - return ret_val; - substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER; - return ret_val; -} - -static int snd_intelmad_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - int ret_val; - - pr_debug("snd_intelmad_hw_params called\n"); - ret_val = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - memset(substream->runtime->dma_area, 0, - params_buffer_bytes(hw_params)); - - return ret_val; -} - -static int snd_intelmad_hw_free(struct snd_pcm_substream *substream) -{ - pr_debug("snd_intelmad_hw_free called\n"); - return snd_pcm_lib_free_pages(substream); -} - -/** - * snd_intelmad_pcm_pointer- to send the current buffer pointer processed by hw - * - * @substream: substream for which the function is called - * - * This function is called by ALSA framework to get the current hw buffer ptr - * when a period is elapsed - */ -static snd_pcm_uframes_t snd_intelmad_pcm_pointer - (struct snd_pcm_substream *substream) -{ - /* struct snd_pcm_runtime *runtime = substream->runtime; */ - struct mad_stream_pvt *stream; - struct snd_intelmad *intelmaddata; - int ret_val; - - WARN_ON(!substream); - - intelmaddata = snd_pcm_substream_chip(substream); - stream = substream->runtime->private_data; - if (stream->stream_status == INIT) - return 0; - - ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control( - SST_SND_BUFFER_POINTER, &stream->stream_info); - if (ret_val) { - pr_err("error code = 0x%x\n", ret_val); - return ret_val; - } - pr_debug("samples reported out 0x%llx\n", - stream->stream_info.buffer_ptr); - pr_debug("Frame bits:: %d period_count :: %d\n", - (int)substream->runtime->frame_bits, - (int)substream->runtime->period_size); - - return stream->stream_info.buffer_ptr; - -} - -/** - * snd_intelmad_close- to free parameteres when stream is stopped - * - * @substream: substream for which the function is called - * - * This function is called by ALSA framework when stream is stopped - */ -static int snd_intelmad_close(struct snd_pcm_substream *substream) -{ - struct snd_intelmad *intelmaddata; - struct mad_stream_pvt *stream; - int ret_val = 0, str_id; - - WARN_ON(!substream); - - stream = substream->runtime->private_data; - str_id = stream->stream_info.str_id; - - pr_debug("sst: snd_intelmad_close called for %d\n", str_id); - intelmaddata = snd_pcm_substream_chip(substream); - - pr_debug("str id = %d\n", stream->stream_info.str_id); - if (stream->stream_info.str_id) { - /* SST API to actually stop/free the stream */ - ret_val = intelmaddata->sstdrv_ops->pcm_control->close(str_id); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - intelmaddata->playback_cnt--; - else - intelmaddata->capture_cnt--; - } - pr_debug("snd_intelmad_close : pb cnt = %d cap cnt = %d\n", - intelmaddata->playback_cnt, intelmaddata->capture_cnt); - kfree(substream->runtime->private_data); - return ret_val; -} - -/** - * snd_intelmad_open- to set runtime parameters during stream start - * - * @substream: substream for which the function is called - * @type: audio device type - * - * This function is called by ALSA framework when stream is started - */ -static int snd_intelmad_open(struct snd_pcm_substream *substream, - enum snd_sst_audio_device_type type) -{ - struct snd_intelmad *intelmaddata; - struct snd_pcm_runtime *runtime; - struct mad_stream_pvt *stream; - - WARN_ON(!substream); - - pr_debug("snd_intelmad_open called\n"); - - intelmaddata = snd_pcm_substream_chip(substream); - runtime = substream->runtime; - /* set the runtime hw parameter with local snd_pcm_hardware struct */ - runtime->hw = snd_intelmad_stream; - if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) { - /* - * MRST firmware currently denies stereo recording requests. - */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - runtime->hw.formats = (SNDRV_PCM_FMTBIT_S16 | - SNDRV_PCM_FMTBIT_U16); - runtime->hw.channels_max = 1; - } - } - if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) { - runtime->hw = snd_intelmad_stream; - runtime->hw.rates = SNDRV_PCM_RATE_48000; - runtime->hw.rate_min = MAX_RATE; - runtime->hw.formats = (SNDRV_PCM_FMTBIT_S24 | - SNDRV_PCM_FMTBIT_U24); - if (intelmaddata->sstdrv_ops->scard_ops->input_dev_id == AMIC) - runtime->hw.channels_max = MAX_CHANNEL_AMIC; - else - runtime->hw.channels_max = MAX_CHANNEL_DMIC; - - } - /* setup the internal datastruture stream pointers based on it being - playback or capture stream */ - stream = kzalloc(sizeof(*stream), GFP_KERNEL); - if (!stream) - return -ENOMEM; - stream->stream_info.str_id = 0; - stream->device = type; - stream->stream_status = INIT; - runtime->private_data = stream; - return snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); -} - -static int snd_intelmad_headset_open(struct snd_pcm_substream *substream) -{ - return snd_intelmad_open(substream, SND_SST_DEVICE_HEADSET); -} - -static int snd_intelmad_ihf_open(struct snd_pcm_substream *substream) -{ - return snd_intelmad_open(substream, SND_SST_DEVICE_IHF); -} - -static int snd_intelmad_vibra_open(struct snd_pcm_substream *substream) -{ - return snd_intelmad_open(substream, SND_SST_DEVICE_VIBRA); -} - -static int snd_intelmad_haptic_open(struct snd_pcm_substream *substream) -{ - return snd_intelmad_open(substream, SND_SST_DEVICE_HAPTIC); -} - -static struct snd_pcm_ops snd_intelmad_headset_ops = { - .open = snd_intelmad_headset_open, - .close = snd_intelmad_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelmad_hw_params, - .hw_free = snd_intelmad_hw_free, - .prepare = snd_intelmad_pcm_prepare, - .trigger = snd_intelmad_pcm_trigger, - .pointer = snd_intelmad_pcm_pointer, -}; - -static struct snd_pcm_ops snd_intelmad_ihf_ops = { - .open = snd_intelmad_ihf_open, - .close = snd_intelmad_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelmad_hw_params, - .hw_free = snd_intelmad_hw_free, - .prepare = snd_intelmad_pcm_prepare, - .trigger = snd_intelmad_pcm_trigger, - .pointer = snd_intelmad_pcm_pointer, -}; - -static struct snd_pcm_ops snd_intelmad_vibra_ops = { - .open = snd_intelmad_vibra_open, - .close = snd_intelmad_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelmad_hw_params, - .hw_free = snd_intelmad_hw_free, - .prepare = snd_intelmad_pcm_prepare, - .trigger = snd_intelmad_pcm_trigger, - .pointer = snd_intelmad_pcm_pointer, -}; - -static struct snd_pcm_ops snd_intelmad_haptic_ops = { - .open = snd_intelmad_haptic_open, - .close = snd_intelmad_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelmad_hw_params, - .hw_free = snd_intelmad_hw_free, - .prepare = snd_intelmad_pcm_prepare, - .trigger = snd_intelmad_pcm_trigger, - .pointer = snd_intelmad_pcm_pointer, -}; - -static struct snd_pcm_ops snd_intelmad_capture_ops = { - .open = snd_intelmad_headset_open, - .close = snd_intelmad_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelmad_hw_params, - .hw_free = snd_intelmad_hw_free, - .prepare = snd_intelmad_pcm_prepare, - .trigger = snd_intelmad_pcm_trigger, - .pointer = snd_intelmad_pcm_pointer, -}; - -int intelmad_get_mic_bias(void) -{ - struct snd_pmic_ops *pmic_ops; - - if (!intelmad_drv || !intelmad_drv->sstdrv_ops) - return -ENODEV; - pmic_ops = intelmad_drv->sstdrv_ops->scard_ops; - if (pmic_ops && pmic_ops->pmic_get_mic_bias) - return pmic_ops->pmic_get_mic_bias(intelmad_drv); - else - return -ENODEV; -} -EXPORT_SYMBOL_GPL(intelmad_get_mic_bias); - -int intelmad_set_headset_state(int state) -{ - struct snd_pmic_ops *pmic_ops; - - if (!intelmad_drv || !intelmad_drv->sstdrv_ops) - return -ENODEV; - pmic_ops = intelmad_drv->sstdrv_ops->scard_ops; - if (pmic_ops && pmic_ops->pmic_set_headset_state) - return pmic_ops->pmic_set_headset_state(state); - else - return -ENODEV; -} -EXPORT_SYMBOL_GPL(intelmad_set_headset_state); - -void sst_process_mad_jack_detection(struct work_struct *work) -{ - u8 interrupt_status; - struct mad_jack_msg_wq *mad_jack_detect = - container_of(work, struct mad_jack_msg_wq, wq); - - struct snd_intelmad *intelmaddata = - mad_jack_detect->intelmaddata; - - if (!intelmaddata) - return; - - interrupt_status = mad_jack_detect->intsts; - if (intelmaddata->sstdrv_ops && intelmaddata->sstdrv_ops->scard_ops - && intelmaddata->sstdrv_ops->scard_ops->pmic_irq_cb) { - intelmaddata->sstdrv_ops->scard_ops->pmic_irq_cb( - (void *)intelmaddata, interrupt_status); - intelmaddata->sstdrv_ops->scard_ops->pmic_jack_enable(); - } - kfree(mad_jack_detect); -} -/** - * snd_intelmad_intr_handler- interrupt handler - * - * @irq : irq number of the interrupt received - * @dev: device context - * - * This function is called when an interrupt is raised at the sound card - */ -static irqreturn_t snd_intelmad_intr_handler(int irq, void *dev) -{ - struct snd_intelmad *intelmaddata = - (struct snd_intelmad *)dev; - u8 interrupt_status; - struct mad_jack_msg_wq *mad_jack_msg; - memcpy_fromio(&interrupt_status, - ((void *)(intelmaddata->int_base)), - sizeof(u8)); - - mad_jack_msg = kzalloc(sizeof(*mad_jack_msg), GFP_ATOMIC); - mad_jack_msg->intsts = interrupt_status; - mad_jack_msg->intelmaddata = intelmaddata; - INIT_WORK(&mad_jack_msg->wq, sst_process_mad_jack_detection); - queue_work(intelmaddata->mad_jack_wq, &mad_jack_msg->wq); - - return IRQ_HANDLED; -} - -void sst_mad_send_jack_report(struct snd_jack *jack, - int buttonpressevent , int status) -{ - - if (!jack) { - pr_debug("MAD error jack empty\n"); - - } else { - snd_jack_report(jack, status); - /* button pressed and released */ - if (buttonpressevent) - snd_jack_report(jack, 0); - pr_debug("MAD sending jack report Done !!!\n"); - } -} - -static int __devinit snd_intelmad_register_irq( - struct snd_intelmad *intelmaddata, unsigned int regbase, - unsigned int regsize) -{ - int ret_val; - char *drv_name; - - pr_debug("irq reg regbase 0x%x, regsize 0x%x\n", - regbase, regsize); - intelmaddata->int_base = ioremap_nocache(regbase, regsize); - if (!intelmaddata->int_base) - pr_err("Mapping of cache failed\n"); - pr_debug("irq = 0x%x\n", intelmaddata->irq); - if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) - drv_name = DRIVER_NAME_MFLD; - else - drv_name = DRIVER_NAME_MRST; - ret_val = request_irq(intelmaddata->irq, - snd_intelmad_intr_handler, - IRQF_SHARED, drv_name, - intelmaddata); - if (ret_val) - pr_err("cannot register IRQ\n"); - return ret_val; -} - -static int __devinit snd_intelmad_sst_register( - struct snd_intelmad *intelmaddata) -{ - int ret_val = 0; - struct snd_pmic_ops *intelmad_vendor_ops[MAX_VENDORS] = { - &snd_pmic_ops_fs, - &snd_pmic_ops_mx, - &snd_pmic_ops_nc, - &snd_msic_ops - }; - - struct sc_reg_access vendor_addr = {0x00, 0x00, 0x00}; - - if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) { - ret_val = sst_sc_reg_access(&vendor_addr, PMIC_READ, 1); - if (ret_val) - return ret_val; - sst_card_vendor_id = (vendor_addr.value & (MASK2|MASK1|MASK0)); - pr_debug("original n extrated vendor id = 0x%x %d\n", - vendor_addr.value, sst_card_vendor_id); - if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) { - pr_err("vendor card not supported!!\n"); - return -EIO; - } - } else - sst_card_vendor_id = 0x3; - - intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES; - intelmaddata->sstdrv_ops->vendor_id = sst_card_vendor_id; - BUG_ON(!intelmad_vendor_ops[sst_card_vendor_id]); - intelmaddata->sstdrv_ops->scard_ops = - intelmad_vendor_ops[sst_card_vendor_id]; - - if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) { - intelmaddata->sstdrv_ops->scard_ops->pb_on = 0; - intelmaddata->sstdrv_ops->scard_ops->cap_on = 0; - intelmaddata->sstdrv_ops->scard_ops->input_dev_id = DMIC; - intelmaddata->sstdrv_ops->scard_ops->output_dev_id = - STEREO_HEADPHONE; - intelmaddata->sstdrv_ops->scard_ops->lineout_dev_id = NONE; - } - - /* registering with SST driver to get access to SST APIs to use */ - ret_val = register_sst_card(intelmaddata->sstdrv_ops); - if (ret_val) { - pr_err("sst card registration failed\n"); - return ret_val; - } - sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id; - intelmaddata->pmic_status = PMIC_UNINIT; - return ret_val; -} - -static void snd_intelmad_page_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} -/* Driver Init/exit functionalities */ -/** - * snd_intelmad_pcm_new - to setup pcm for the card - * - * @card: pointer to the sound card structure - * @intelmaddata: pointer to internal context - * @pb: playback count for this card - * @cap: capture count for this card - * @index: device index - * - * This function is called from probe function to set up pcm params - * and functions - */ -static int __devinit snd_intelmad_pcm_new(struct snd_card *card, - struct snd_intelmad *intelmaddata, - unsigned int pb, unsigned int cap, unsigned int index) -{ - int ret_val = 0; - struct snd_pcm *pcm; - char name[32] = INTEL_MAD; - struct snd_pcm_ops *pb_ops = NULL, *cap_ops = NULL; - - pr_debug("called for pb %d, cp %d, idx %d\n", pb, cap, index); - ret_val = snd_pcm_new(card, name, index, pb, cap, &pcm); - if (ret_val) - return ret_val; - /* setup the ops for playback and capture streams */ - switch (index) { - case 0: - pb_ops = &snd_intelmad_headset_ops; - cap_ops = &snd_intelmad_capture_ops; - break; - case 1: - pb_ops = &snd_intelmad_ihf_ops; - cap_ops = &snd_intelmad_capture_ops; - break; - case 2: - pb_ops = &snd_intelmad_vibra_ops; - cap_ops = &snd_intelmad_capture_ops; - break; - case 3: - pb_ops = &snd_intelmad_haptic_ops; - cap_ops = &snd_intelmad_capture_ops; - break; - } - if (pb) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, pb_ops); - if (cap) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, cap_ops); - /* setup private data which can be retrieved when required */ - pcm->private_data = intelmaddata; - pcm->private_free = snd_intelmad_page_free; - pcm->info_flags = 0; - strncpy(pcm->name, card->shortname, strlen(card->shortname)); - /* allocate dma pages for ALSA stream operations */ - snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - MIN_BUFFER, MAX_BUFFER); - return ret_val; -} - -static int __devinit snd_intelmad_pcm(struct snd_card *card, - struct snd_intelmad *intelmaddata) -{ - int ret_val = 0; - - WARN_ON(!card); - WARN_ON(!intelmaddata); - pr_debug("snd_intelmad_pcm called\n"); - ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 1, 0); - if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) - return ret_val; - ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 1); - if (ret_val) - return ret_val; - ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 2); - if (ret_val) - return ret_val; - return snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 3); -} - -/** - * snd_intelmad_jack- to setup jack settings of the card - * - * @intelmaddata: pointer to internal context - * - * This function is called send jack events - */ -static int snd_intelmad_jack(struct snd_intelmad *intelmaddata) -{ - struct snd_jack *jack; - int retval; - - pr_debug("snd_intelmad_jack called\n"); - jack = &intelmaddata->jack[0].jack; - snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PHONE); - retval = snd_jack_new(intelmaddata->card, "Intel(R) MID Audio Jack", - SND_JACK_HEADPHONE | SND_JACK_HEADSET | - SW_JACK_PHYSICAL_INSERT | SND_JACK_BTN_0 - | SND_JACK_BTN_1, &jack); - pr_debug("snd_intelmad_jack called\n"); - if (retval < 0) - return retval; - snd_jack_report(jack, 0); - - jack->private_data = jack; - intelmaddata->jack[0].jack = *jack; - - return retval; -} - -/** - * snd_intelmad_mixer- to setup mixer settings of the card - * - * @intelmaddata: pointer to internal context - * - * This function is called from probe function to set up mixer controls - */ -static int __devinit snd_intelmad_mixer(struct snd_intelmad *intelmaddata) -{ - struct snd_card *card; - unsigned int idx; - int ret_val = 0, max_controls = 0; - char *mixername = "IntelMAD Controls"; - struct snd_kcontrol_new *controls; - - WARN_ON(!intelmaddata); - - card = intelmaddata->card; - strncpy(card->mixername, mixername, sizeof(card->mixername)-1); - /* add all widget controls and expose the same */ - if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) { - max_controls = MAX_CTRL_MFLD; - controls = snd_intelmad_controls_mfld; - } else { - max_controls = MAX_CTRL_MRST; - controls = snd_intelmad_controls_mrst; - } - for (idx = 0; idx < max_controls; idx++) { - ret_val = snd_ctl_add(card, - snd_ctl_new1(&controls[idx], - intelmaddata)); - pr_debug("mixer[idx]=%d added\n", idx); - if (ret_val) { - pr_err("in adding of control index = %d\n", idx); - break; - } - } - return ret_val; -} - -static int snd_intelmad_dev_free(struct snd_device *device) -{ - struct snd_intelmad *intelmaddata; - - WARN_ON(!device); - - intelmaddata = device->device_data; - - pr_debug("snd_intelmad_dev_free called\n"); - unregister_sst_card(intelmaddata->sstdrv_ops); - - /* free allocated memory for internal context */ - destroy_workqueue(intelmaddata->mad_jack_wq); - device->device_data = NULL; - kfree(intelmaddata->sstdrv_ops); - kfree(intelmaddata); - - return 0; -} - -static int __devinit snd_intelmad_create( - struct snd_intelmad *intelmaddata, - struct snd_card *card) -{ - int ret_val; - static struct snd_device_ops ops = { - .dev_free = snd_intelmad_dev_free, - }; - - WARN_ON(!intelmaddata); - WARN_ON(!card); - /* ALSA api to register for the device */ - ret_val = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelmaddata, &ops); - return ret_val; -} - -/** -* snd_intelmad_probe- function registred for init -* @pdev : pointer to the device struture -* This function is called when the device is initialized -*/ -int __devinit snd_intelmad_probe(struct platform_device *pdev) -{ - struct snd_card *card; - int ret_val; - struct snd_intelmad *intelmaddata; - const struct platform_device_id *id = platform_get_device_id(pdev); - struct snd_intelmad_probe_info *info = (void *)id->driver_data; - - pr_debug("probe for %s cpu_id %d\n", pdev->name, info->cpu_id); - pr_debug("rq_chache %x of size %x\n", info->irq_cache, info->size); - if (!strcmp(pdev->name, DRIVER_NAME_MRST)) - pr_debug("detected MRST\n"); - else if (!strcmp(pdev->name, DRIVER_NAME_MFLD)) - pr_debug("detected MFLD\n"); - else { - pr_err("detected unknown device abort!!\n"); - return -EIO; - } - if ((info->cpu_id < CPU_CHIP_LINCROFT) || - (info->cpu_id > CPU_CHIP_PENWELL)) { - pr_err("detected unknown cpu_id abort!!\n"); - return -EIO; - } - /* allocate memory for saving internal context and working */ - intelmaddata = kzalloc(sizeof(*intelmaddata), GFP_KERNEL); - if (!intelmaddata) { - pr_debug("mem alloctn fail\n"); - return -ENOMEM; - } - intelmad_drv = intelmaddata; - - /* allocate memory for LPE API set */ - intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops), - GFP_KERNEL); - if (!intelmaddata->sstdrv_ops) { - pr_err("mem allocation for ops fail\n"); - kfree(intelmaddata); - return -ENOMEM; - } - - intelmaddata->cpu_id = info->cpu_id; - /* create a card instance with ALSA framework */ - ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card); - if (ret_val) { - pr_err("snd_card_create fail\n"); - goto free_allocs; - } - - intelmaddata->pdev = pdev; - intelmaddata->irq = platform_get_irq(pdev, 0); - platform_set_drvdata(pdev, intelmaddata); - intelmaddata->card = card; - intelmaddata->card_id = card_id; - intelmaddata->card_index = card_index; - intelmaddata->master_mute = UNMUTE; - intelmaddata->playback_cnt = intelmaddata->capture_cnt = 0; - strncpy(card->driver, INTEL_MAD, strlen(INTEL_MAD)); - strncpy(card->shortname, INTEL_MAD, strlen(INTEL_MAD)); - - intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES; - /* registering with LPE driver to get access to SST APIs to use */ - ret_val = snd_intelmad_sst_register(intelmaddata); - if (ret_val) { - pr_err("snd_intelmad_sst_register failed\n"); - goto set_null_data; - } - - intelmaddata->pmic_status = PMIC_INIT; - - ret_val = snd_intelmad_pcm(card, intelmaddata); - if (ret_val) { - pr_err("snd_intelmad_pcm failed\n"); - goto free_sst; - } - - ret_val = snd_intelmad_mixer(intelmaddata); - if (ret_val) { - pr_err("snd_intelmad_mixer failed\n"); - goto free_card; - } - - ret_val = snd_intelmad_jack(intelmaddata); - if (ret_val) { - pr_err("snd_intelmad_jack failed\n"); - goto free_card; - } - intelmaddata->adc_address = mid_initialize_adc(); - - /*create work queue for jack interrupt*/ - INIT_WORK(&intelmaddata->mad_jack_msg.wq, - sst_process_mad_jack_detection); - - intelmaddata->mad_jack_wq = create_workqueue("sst_mad_jack_wq"); - if (!intelmaddata->mad_jack_wq) - goto free_card; - - ret_val = snd_intelmad_register_irq(intelmaddata, - info->irq_cache, info->size); - if (ret_val) { - pr_err("snd_intelmad_register_irq fail\n"); - goto free_mad_jack_wq; - } - - /* internal function call to register device with ALSA */ - ret_val = snd_intelmad_create(intelmaddata, card); - if (ret_val) { - pr_err("snd_intelmad_create failed\n"); - goto set_pvt_data; - } - card->private_data = &intelmaddata; - snd_card_set_dev(card, &pdev->dev); - ret_val = snd_card_register(card); - if (ret_val) { - pr_err("snd_card_register failed\n"); - goto set_pvt_data; - } - if (pdev->dev.platform_data) { - int gpio_amp = *(int *)pdev->dev.platform_data; - if (gpio_request_one(gpio_amp, GPIOF_OUT_INIT_LOW, "amp power")) - gpio_amp = 0; - intelmaddata->sstdrv_ops->scard_ops->gpio_amp = gpio_amp; - } - - pr_debug("snd_intelmad_probe complete\n"); - return ret_val; - -set_pvt_data: - card->private_data = NULL; -free_mad_jack_wq: - destroy_workqueue(intelmaddata->mad_jack_wq); -free_card: - snd_card_free(intelmaddata->card); -free_sst: - unregister_sst_card(intelmaddata->sstdrv_ops); -set_null_data: - platform_set_drvdata(pdev, NULL); -free_allocs: - pr_err("probe failed\n"); - snd_card_free(card); - kfree(intelmaddata->sstdrv_ops); - kfree(intelmaddata); - return ret_val; -} - - -static int snd_intelmad_remove(struct platform_device *pdev) -{ - struct snd_intelmad *intelmaddata = platform_get_drvdata(pdev); - - if (intelmaddata) { - if (intelmaddata->sstdrv_ops->scard_ops->gpio_amp) - gpio_free(intelmaddata->sstdrv_ops->scard_ops->gpio_amp); - free_irq(intelmaddata->irq, intelmaddata); - snd_card_free(intelmaddata->card); - } - intelmad_drv = NULL; - platform_set_drvdata(pdev, NULL); - return 0; -} - -/********************************************************************* - * Driver initialization and exit - *********************************************************************/ -static const struct platform_device_id snd_intelmad_ids[] = { - {DRIVER_NAME_MRST, INFO(CPU_CHIP_LINCROFT, AUDINT_BASE, 1)}, - {DRIVER_NAME_MFLD, INFO(CPU_CHIP_PENWELL, 0xFFFF7FCD, 1)}, - {"", 0}, - -}; - -static struct platform_driver snd_intelmad_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "intel_mid_sound_card", - }, - .id_table = snd_intelmad_ids, - .probe = snd_intelmad_probe, - .remove = __devexit_p(snd_intelmad_remove), -}; - -/* - * alsa_card_intelmad_init- driver init function - * - * This function is called when driver module is inserted - */ -static int __init alsa_card_intelmad_init(void) -{ - pr_debug("mad_init called\n"); - return platform_driver_register(&snd_intelmad_driver); -} - -/** - * alsa_card_intelmad_exit- driver exit function - * - * This function is called when driver module is removed - */ -static void __exit alsa_card_intelmad_exit(void) -{ - pr_debug("mad_exit called\n"); - return platform_driver_unregister(&snd_intelmad_driver); -} - -module_init(alsa_card_intelmad_init) -module_exit(alsa_card_intelmad_exit) - diff --git a/drivers/staging/intel_sst/intelmid.h b/drivers/staging/intel_sst/intelmid.h deleted file mode 100644 index 14a7ba078b7..00000000000 --- a/drivers/staging/intel_sst/intelmid.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * intelmid.h - Intel Sound card driver for MID - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Harsha Priya <priya.harsha@intel.com> - * Vinod Koul <vinod.koul@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * ALSA driver header for Intel MAD chipset - */ -#ifndef __INTELMID_H -#define __INTELMID_H - -#include <linux/time.h> -#include <sound/jack.h> - -#define DRIVER_NAME_MFLD "msic_audio" -#define DRIVER_NAME_MRST "pmic_audio" -#define DRIVER_NAME "intelmid_audio" -#define PMIC_SOUND_IRQ_TYPE_MASK (1 << 15) -#define AUDINT_BASE (0xFFFFEFF8 + (6 * sizeof(u8))) -#define REG_IRQ -/* values #defined */ -/* will differ for different hw - to be taken from config */ -#define MAX_DEVICES 1 -#define MIN_RATE 8000 -#define MAX_RATE 48000 -#define MAX_BUFFER (800*1024) /* for PCM */ -#define MIN_BUFFER (800*1024) -#define MAX_PERIODS (1024*2) -#define MIN_PERIODS 2 -#define MAX_PERIOD_BYTES MAX_BUFFER -#define MIN_PERIOD_BYTES 32 -/*#define MIN_PERIOD_BYTES 160*/ -#define MAX_MUTE 1 -#define MIN_MUTE 0 -#define MONO_CNTL 1 -#define STEREO_CNTL 2 -#define MIN_CHANNEL 1 -#define MAX_CHANNEL_AMIC 2 -#define MAX_CHANNEL_DMIC 5 -#define FIFO_SIZE 0 /* fifo not being used */ -#define INTEL_MAD "Intel MAD" -#define MAX_CTRL_MRST 8 -#define MAX_CTRL_MFLD 7 -#define MAX_CTRL 8 -#define MAX_VENDORS 4 -/* TODO +6 db */ -#define MAX_VOL 64 -/* TODO -57 db */ -#define MIN_VOL 0 -#define PLAYBACK_COUNT 1 -#define CAPTURE_COUNT 1 -#define ADC_ONE_LSB_MULTIPLIER 2346 - -#define MID_JACK_HS_LONG_PRESS SND_JACK_BTN_0 -#define MID_JACK_HS_SHORT_PRESS SND_JACK_BTN_1 - -extern int sst_card_vendor_id; - -struct mad_jack { - struct snd_jack jack; - int jack_status; - int jack_dev_state; - struct timeval buttonpressed; - struct timeval buttonreleased; -}; - -struct mad_jack_msg_wq { - u8 intsts; - struct snd_intelmad *intelmaddata; - struct work_struct wq; - -}; - -struct snd_intelmad_probe_info { - unsigned int cpu_id; - unsigned int irq_cache; - unsigned int size; -}; - -/** - * struct snd_intelmad - intelmad driver structure - * - * @card: ptr to the card details - * @card_index: sound card index - * @card_id: sound card id detected - * @sstdrv_ops: ptr to sst driver ops - * @pdev: ptr to platform device - * @irq: interrupt number detected - * @pmic_status: Device status of sound card - * @int_base: ptr to MMIO interrupt region - * @output_sel: device selected as o/p - * @input_sel: device selected as i/p - * @master_mute: master mute status - * @jack: jack status - * @playback_cnt: active pb streams - * @capture_cnt: active cp streams - * @mad_jack_msg: wq struct for jack interrupt processing - * @mad_jack_wq: wq for jack interrupt processing - * @jack_prev_state: Previos state of jack detected - * @cpu_id: current cpu id loaded for - */ -struct snd_intelmad { - struct snd_card *card; /* ptr to the card details */ - int card_index;/* card index */ - char *card_id; /* card id */ - struct intel_sst_card_ops *sstdrv_ops;/* ptr to sst driver ops */ - struct platform_device *pdev; - int irq; - int pmic_status; - void __iomem *int_base; - int output_sel; - int input_sel; - int lineout_sel; - int master_mute; - struct mad_jack jack[4]; - int playback_cnt; - int capture_cnt; - u16 adc_address; - struct mad_jack_msg_wq mad_jack_msg; - struct workqueue_struct *mad_jack_wq; - u8 jack_prev_state; - unsigned int cpu_id; -}; - -struct snd_control_val { - int playback_vol_max; - int playback_vol_min; - int capture_vol_max; - int capture_vol_min; - int master_vol_max; - int master_vol_min; -}; - -struct mad_stream_pvt { - int stream_status; - int stream_ops; - struct snd_pcm_substream *substream; - struct pcm_stream_info stream_info; - ssize_t dbg_cum_bytes; - enum snd_sst_device_type device; -}; - -enum mad_drv_status { - INIT = 1, - STARTED, - RUNNING, - PAUSED, - DROPPED, -}; - -enum mad_pmic_status { - PMIC_UNINIT = 1, - PMIC_INIT, -}; -enum _widget_ctrl { - OUTPUT_SEL = 1, - INPUT_SEL, - PLAYBACK_VOL, - PLAYBACK_MUTE, - CAPTURE_VOL, - CAPTURE_MUTE, - MASTER_VOL, - MASTER_MUTE -}; -enum _widget_ctrl_mfld { - LINEOUT_SEL_MFLD = 3, -}; -enum hw_chs { - HW_CH0 = 0, - HW_CH1, - HW_CH2, - HW_CH3 -}; - -void period_elapsed(void *mad_substream); -int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream); -int snd_intelmad_init_stream(struct snd_pcm_substream *substream); - -int sst_sc_reg_access(struct sc_reg_access *sc_access, - int type, int num_val); -#define CPU_CHIP_LINCROFT 1 /* System running lincroft */ -#define CPU_CHIP_PENWELL 2 /* System running penwell */ - -extern struct snd_control_val intelmad_ctrl_val[]; -extern struct snd_kcontrol_new snd_intelmad_controls_mrst[]; -extern struct snd_kcontrol_new snd_intelmad_controls_mfld[]; -extern struct snd_pmic_ops *intelmad_vendor_ops[]; -void sst_mad_send_jack_report(struct snd_jack *jack, - int buttonpressevent , int status); - -#endif /* __INTELMID_H */ diff --git a/drivers/staging/intel_sst/intelmid_adc_control.h b/drivers/staging/intel_sst/intelmid_adc_control.h deleted file mode 100644 index 65d5c398876..00000000000 --- a/drivers/staging/intel_sst/intelmid_adc_control.h +++ /dev/null @@ -1,193 +0,0 @@ -#ifndef __INTELMID_ADC_CONTROL_H__ -#define __INTELMID_ADC_CONTROL_H_ -/* - * intelmid_adc_control.h - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corporation - * Authors: R Durgadadoss <r.durgadoss@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Common private ADC declarations for SST - */ - - -#define MSIC_ADC1CNTL1 0x1C0 -#define MSIC_ADC_ENBL 0x10 -#define MSIC_ADC_START 0x08 - -#define MSIC_ADC1CNTL3 0x1C2 -#define MSIC_ADCTHERM_ENBL 0x04 -#define MSIC_ADCRRDATA_ENBL 0x05 - -#define MSIC_STOPBIT_MASK 16 -#define MSIC_ADCTHERM_MASK 4 - -#define ADC_CHANLS_MAX 15 /* Number of ADC channels */ -#define ADC_LOOP_MAX (ADC_CHANLS_MAX - 1) - -/* ADC channel code values */ -#define AUDIO_DETECT_CODE 0x06 - -/* ADC base addresses */ -#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ -#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ - - -/** - * configure_adc - enables/disables the ADC for conversion - * @val: zero: disables the ADC non-zero:enables the ADC - * - * Enable/Disable the ADC depending on the argument - * - * Can sleep - */ -static inline int configure_adc(int val) -{ - int ret; - struct sc_reg_access sc_access = {0,}; - - - sc_access.reg_addr = MSIC_ADC1CNTL1; - ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - if (ret) - return ret; - - if (val) - /* Enable and start the ADC */ - sc_access.value |= (MSIC_ADC_ENBL | MSIC_ADC_START); - else - /* Just stop the ADC */ - sc_access.value &= (~MSIC_ADC_START); - sc_access.reg_addr = MSIC_ADC1CNTL1; - return sst_sc_reg_access(&sc_access, PMIC_WRITE, 1); -} - -/** - * reset_stopbit - sets the stop bit to 0 on the given channel - * @addr: address of the channel - * - * Can sleep - */ -static inline int reset_stopbit(uint16_t addr) -{ - int ret; - struct sc_reg_access sc_access = {0,}; - sc_access.reg_addr = addr; - ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - if (ret) - return ret; - /* Set the stop bit to zero */ - sc_access.reg_addr = addr; - sc_access.value = (sc_access.value) & 0xEF; - return sst_sc_reg_access(&sc_access, PMIC_WRITE, 1); -} - -/** - * find_free_channel - finds an empty channel for conversion - * - * If the ADC is not enabled then start using 0th channel - * itself. Otherwise find an empty channel by looking for a - * channel in which the stopbit is set to 1. returns the index - * of the first free channel if succeeds or an error code. - * - * Context: can sleep - * - */ -static inline int find_free_channel(void) -{ - int ret; - int i; - - struct sc_reg_access sc_access = {0,}; - - /* check whether ADC is enabled */ - sc_access.reg_addr = MSIC_ADC1CNTL1; - ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - if (ret) - return ret; - - if ((sc_access.value & MSIC_ADC_ENBL) == 0) - return 0; - - /* ADC is already enabled; Looking for an empty channel */ - for (i = 0; i < ADC_CHANLS_MAX; i++) { - - sc_access.reg_addr = ADC_CHNL_START_ADDR + i; - ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - if (ret) - return ret; - - if (sc_access.value & MSIC_STOPBIT_MASK) { - ret = i; - break; - } - } - return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; -} - -/** - * mid_initialize_adc - initializing the ADC - * @dev: our device structure - * - * Initialize the ADC for reading thermistor values. Can sleep. - */ -static inline int mid_initialize_adc(void) -{ - int base_addr, chnl_addr; - int ret; - static int channel_index; - struct sc_reg_access sc_access = {0,}; - - /* Index of the first channel in which the stop bit is set */ - channel_index = find_free_channel(); - if (channel_index < 0) { - pr_err("No free ADC channels"); - return channel_index; - } - - base_addr = ADC_CHNL_START_ADDR + channel_index; - - if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { - /* Reset stop bit for channels other than 0 and 12 */ - ret = reset_stopbit(base_addr); - if (ret) - return ret; - - /* Index of the first free channel */ - base_addr++; - channel_index++; - } - - /* Since this is the last channel, set the stop bit - to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ - sc_access.reg_addr = base_addr; - sc_access.value = AUDIO_DETECT_CODE | 0x10; - ret = sst_sc_reg_access(&sc_access, PMIC_WRITE, 1); - if (ret) { - pr_err("unable to enable ADC"); - return ret; - } - - chnl_addr = ADC_DATA_START_ADDR + 2 * channel_index; - pr_debug("mid_initialize : %x", chnl_addr); - configure_adc(1); - return chnl_addr; -} -#endif - diff --git a/drivers/staging/intel_sst/intelmid_ctrl.c b/drivers/staging/intel_sst/intelmid_ctrl.c deleted file mode 100644 index 19ec474b362..00000000000 --- a/drivers/staging/intel_sst/intelmid_ctrl.c +++ /dev/null @@ -1,921 +0,0 @@ -/* - * intelmid_ctrl.c - Intel Sound card driver for MID - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Harsha Priya <priya.harsha@intel.com> - * Vinod Koul <vinod.koul@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * ALSA driver handling mixer controls for Intel MAD chipset - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <sound/core.h> -#include <sound/control.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intelmid_snd_control.h" -#include "intelmid.h" - -#define HW_CH_BASE 4 - - -#define HW_CH_0 "Hw1" -#define HW_CH_1 "Hw2" -#define HW_CH_2 "Hw3" -#define HW_CH_3 "Hw4" - -static char *router_dmics[] = { "DMIC1", - "DMIC2", - "DMIC3", - "DMIC4", - "DMIC5", - "DMIC6" - }; - -static char *out_names_mrst[] = {"Headphones", - "Internal speakers"}; -static char *in_names_mrst[] = {"AMIC", - "DMIC", - "HS_MIC"}; -static char *line_out_names_mfld[] = {"Headset", - "IHF ", - "Vibra1 ", - "Vibra2 ", - "NONE "}; -static char *out_names_mfld[] = {"Headset ", - "EarPiece "}; -static char *in_names_mfld[] = {"AMIC", - "DMIC"}; - -struct snd_control_val intelmad_ctrl_val[MAX_VENDORS] = { - { - .playback_vol_max = 63, - .playback_vol_min = 0, - .capture_vol_max = 63, - .capture_vol_min = 0, - }, - { - .playback_vol_max = 0, - .playback_vol_min = -31, - .capture_vol_max = 0, - .capture_vol_min = -20, - }, - { - .playback_vol_max = 0, - .playback_vol_min = -31, - .capture_vol_max = 0, - .capture_vol_min = -31, - .master_vol_max = 0, - .master_vol_min = -126, - }, -}; - -/* control path functionalities */ - -static inline int snd_intelmad_volume_info(struct snd_ctl_elem_info *uinfo, - int control_type, int max, int min) -{ - WARN_ON(!uinfo); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = control_type; - uinfo->value.integer.min = min; - uinfo->value.integer.max = max; - return 0; -} - -/** -* snd_intelmad_mute_info - provides information about the mute controls -* -* @kcontrol: pointer to the control -* @uinfo: pointer to the structure where the control's info need -* to be filled -* -* This function is called when a mixer application requests for control's info -*/ -static int snd_intelmad_mute_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - WARN_ON(!uinfo); - WARN_ON(!kcontrol); - - /* set up the mute as a boolean mono control with min-max values */ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = MONO_CNTL; - uinfo->value.integer.min = MIN_MUTE; - uinfo->value.integer.max = MAX_MUTE; - return 0; -} - -/** -* snd_intelmad_capture_volume_info - provides info about the volume control -* -* @kcontrol: pointer to the control -* @uinfo: pointer to the structure where the control's info need -* to be filled -* -* This function is called when a mixer application requests for control's info -*/ -static int snd_intelmad_capture_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - snd_intelmad_volume_info(uinfo, MONO_CNTL, - intelmad_ctrl_val[sst_card_vendor_id].capture_vol_max, - intelmad_ctrl_val[sst_card_vendor_id].capture_vol_min); - return 0; -} - -/** -* snd_intelmad_playback_volume_info - provides info about the volume control -* -* @kcontrol: pointer to the control -* @uinfo: pointer to the structure where the control's info need -* to be filled -* -* This function is called when a mixer application requests for control's info -*/ -static int snd_intelmad_playback_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - snd_intelmad_volume_info(uinfo, STEREO_CNTL, - intelmad_ctrl_val[sst_card_vendor_id].playback_vol_max, - intelmad_ctrl_val[sst_card_vendor_id].playback_vol_min); - return 0; -} - -static int snd_intelmad_master_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - snd_intelmad_volume_info(uinfo, STEREO_CNTL, - intelmad_ctrl_val[sst_card_vendor_id].master_vol_max, - intelmad_ctrl_val[sst_card_vendor_id].master_vol_min); - return 0; -} - -/** -* snd_intelmad_device_info_mrst - provides information about the devices available -* -* @kcontrol: pointer to the control -* @uinfo: pointer to the structure where the devices's info need -* to be filled -* -* This function is called when a mixer application requests for device's info -*/ -static int snd_intelmad_device_info_mrst(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - - WARN_ON(!kcontrol); - WARN_ON(!uinfo); - - /* setup device select as drop down controls with different values */ - if (kcontrol->id.numid == OUTPUT_SEL) - uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mrst); - else - uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mrst); - uinfo->count = MONO_CNTL; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = 1; - if (kcontrol->id.numid == OUTPUT_SEL) - strncpy(uinfo->value.enumerated.name, - out_names_mrst[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)-1); - else - strncpy(uinfo->value.enumerated.name, - in_names_mrst[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)-1); - return 0; -} - -static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct snd_pmic_ops *scard_ops; - struct snd_intelmad *intelmaddata; - - WARN_ON(!kcontrol); - WARN_ON(!uinfo); - - intelmaddata = kcontrol->private_data; - - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - /* setup device select as drop down controls with different values */ - if (kcontrol->id.numid == OUTPUT_SEL) - uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mfld); - else if (kcontrol->id.numid == INPUT_SEL) - uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mfld); - else if (kcontrol->id.numid == LINEOUT_SEL_MFLD) { - uinfo->value.enumerated.items = ARRAY_SIZE(line_out_names_mfld); - scard_ops->line_out_names_cnt = uinfo->value.enumerated.items; - } else - return -EINVAL; - uinfo->count = MONO_CNTL; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = 1; - if (kcontrol->id.numid == OUTPUT_SEL) - strncpy(uinfo->value.enumerated.name, - out_names_mfld[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)-1); - else if (kcontrol->id.numid == INPUT_SEL) - strncpy(uinfo->value.enumerated.name, - in_names_mfld[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)-1); - else if (kcontrol->id.numid == LINEOUT_SEL_MFLD) - strncpy(uinfo->value.enumerated.name, - line_out_names_mfld[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)-1); - else - return -EINVAL; - return 0; -} - -/** -* snd_intelmad_volume_get - gets the current volume for the control -* -* @kcontrol: pointer to the control -* @uval: pointer to the structure where the control's info need -* to be filled -* -* This function is called when .get function of a control is invoked from app -*/ -static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - int ret_val = 0, cntl_list[2] = {0,}; - int value = 0; - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - - pr_debug("snd_intelmad_volume_get called\n"); - - WARN_ON(!uval); - WARN_ON(!kcontrol); - - intelmaddata = kcontrol->private_data; - - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - - WARN_ON(!scard_ops); - - switch (kcontrol->id.numid) { - case PLAYBACK_VOL: - cntl_list[0] = PMIC_SND_RIGHT_PB_VOL; - cntl_list[1] = PMIC_SND_LEFT_PB_VOL; - break; - - case CAPTURE_VOL: - cntl_list[0] = PMIC_SND_CAPTURE_VOL; - break; - - case MASTER_VOL: - cntl_list[0] = PMIC_SND_RIGHT_MASTER_VOL; - cntl_list[1] = PMIC_SND_LEFT_MASTER_VOL; - break; - default: - return -EINVAL; - } - - ret_val = scard_ops->get_vol(cntl_list[0], &value); - uval->value.integer.value[0] = value; - - if (ret_val) - return ret_val; - - if (kcontrol->id.numid == PLAYBACK_VOL || - kcontrol->id.numid == MASTER_VOL) { - ret_val = scard_ops->get_vol(cntl_list[1], &value); - uval->value.integer.value[1] = value; - } - return ret_val; -} - -/** -* snd_intelmad_mute_get - gets the current mute status for the control -* -* @kcontrol: pointer to the control -* @uval: pointer to the structure where the control's info need -* to be filled -* -* This function is called when .get function of a control is invoked from app -*/ -static int snd_intelmad_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - - int cntl_list = 0, ret_val = 0; - u8 value = 0; - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - - pr_debug("Mute_get called\n"); - - WARN_ON(!uval); - WARN_ON(!kcontrol); - - intelmaddata = kcontrol->private_data; - - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - - WARN_ON(!scard_ops); - - switch (kcontrol->id.numid) { - case PLAYBACK_MUTE: - if (intelmaddata->output_sel == STEREO_HEADPHONE) - cntl_list = PMIC_SND_LEFT_HP_MUTE; - else if ((intelmaddata->output_sel == INTERNAL_SPKR) || - (intelmaddata->output_sel == MONO_EARPIECE)) - cntl_list = PMIC_SND_LEFT_SPEAKER_MUTE; - break; - - case CAPTURE_MUTE: - if (intelmaddata->input_sel == DMIC) - cntl_list = PMIC_SND_DMIC_MUTE; - else if (intelmaddata->input_sel == AMIC) - cntl_list = PMIC_SND_AMIC_MUTE; - else if (intelmaddata->input_sel == HS_MIC) - cntl_list = PMIC_SND_HP_MIC_MUTE; - break; - case MASTER_MUTE: - uval->value.integer.value[0] = intelmaddata->master_mute; - return 0; - default: - return -EINVAL; - } - - ret_val = scard_ops->get_mute(cntl_list, &value); - uval->value.integer.value[0] = value; - return ret_val; -} - -/** -* snd_intelmad_volume_set - sets the volume control's info -* -* @kcontrol: pointer to the control -* @uval: pointer to the structure where the control's info is -* available to be set -* -* This function is called when .set function of a control is invoked from app -*/ -static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - - int ret_val, cntl_list[2] = {0,}; - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - - pr_debug("volume set called:%ld %ld\n", - uval->value.integer.value[0], - uval->value.integer.value[1]); - - WARN_ON(!uval); - WARN_ON(!kcontrol); - - intelmaddata = kcontrol->private_data; - - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - - WARN_ON(!scard_ops); - - switch (kcontrol->id.numid) { - case PLAYBACK_VOL: - cntl_list[0] = PMIC_SND_LEFT_PB_VOL; - cntl_list[1] = PMIC_SND_RIGHT_PB_VOL; - break; - - case CAPTURE_VOL: - cntl_list[0] = PMIC_SND_CAPTURE_VOL; - break; - - case MASTER_VOL: - cntl_list[0] = PMIC_SND_LEFT_MASTER_VOL; - cntl_list[1] = PMIC_SND_RIGHT_MASTER_VOL; - break; - - default: - return -EINVAL; - } - - ret_val = scard_ops->set_vol(cntl_list[0], - uval->value.integer.value[0]); - if (ret_val) - return ret_val; - - if (kcontrol->id.numid == PLAYBACK_VOL || - kcontrol->id.numid == MASTER_VOL) - ret_val = scard_ops->set_vol(cntl_list[1], - uval->value.integer.value[1]); - return ret_val; -} - -/** -* snd_intelmad_mute_set - sets the mute control's info -* -* @kcontrol: pointer to the control -* @uval: pointer to the structure where the control's info is -* available to be set -* -* This function is called when .set function of a control is invoked from app -*/ -static int snd_intelmad_mute_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - int cntl_list[2] = {0,}, ret_val; - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - - pr_debug("snd_intelmad_mute_set called\n"); - - WARN_ON(!uval); - WARN_ON(!kcontrol); - - intelmaddata = kcontrol->private_data; - - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - - WARN_ON(!scard_ops); - - kcontrol->private_value = uval->value.integer.value[0]; - - switch (kcontrol->id.numid) { - case PLAYBACK_MUTE: - if (intelmaddata->output_sel == STEREO_HEADPHONE) { - cntl_list[0] = PMIC_SND_LEFT_HP_MUTE; - cntl_list[1] = PMIC_SND_RIGHT_HP_MUTE; - } else if ((intelmaddata->output_sel == INTERNAL_SPKR) || - (intelmaddata->output_sel == MONO_EARPIECE)) { - cntl_list[0] = PMIC_SND_LEFT_SPEAKER_MUTE; - cntl_list[1] = PMIC_SND_RIGHT_SPEAKER_MUTE; - } - break; - - case CAPTURE_MUTE:/*based on sel device mute the i/p dev*/ - if (intelmaddata->input_sel == DMIC) - cntl_list[0] = PMIC_SND_DMIC_MUTE; - else if (intelmaddata->input_sel == AMIC) - cntl_list[0] = PMIC_SND_AMIC_MUTE; - else if (intelmaddata->input_sel == HS_MIC) - cntl_list[0] = PMIC_SND_HP_MIC_MUTE; - break; - case MASTER_MUTE: - cntl_list[0] = PMIC_SND_MUTE_ALL; - intelmaddata->master_mute = uval->value.integer.value[0]; - break; - default: - return -EINVAL; - } - - ret_val = scard_ops->set_mute(cntl_list[0], - uval->value.integer.value[0]); - if (ret_val) - return ret_val; - - if (kcontrol->id.numid == PLAYBACK_MUTE) - ret_val = scard_ops->set_mute(cntl_list[1], - uval->value.integer.value[0]); - return ret_val; -} - -/** -* snd_intelmad_device_get - get the device select control's info -* -* @kcontrol: pointer to the control -* @uval: pointer to the structure where the control's info is -* to be filled -* -* This function is called when .get function of a control is invoked from app -*/ -static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - pr_debug("device_get called\n"); - - WARN_ON(!uval); - WARN_ON(!kcontrol); - - intelmaddata = kcontrol->private_data; - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) { - if (kcontrol->id.numid == OUTPUT_SEL) - uval->value.enumerated.item[0] = - scard_ops->output_dev_id; - else if (kcontrol->id.numid == INPUT_SEL) - uval->value.enumerated.item[0] = - scard_ops->input_dev_id; - else if (kcontrol->id.numid == LINEOUT_SEL_MFLD) - uval->value.enumerated.item[0] = - scard_ops->lineout_dev_id; - else - return -EINVAL; - } else if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) { - if (kcontrol->id.numid == OUTPUT_SEL) - /* There is a mismatch here. - * ALSA expects 1 for internal speaker. - * But internally, we may give 2 for internal speaker. - */ - if (scard_ops->output_dev_id == MONO_EARPIECE || - scard_ops->output_dev_id == INTERNAL_SPKR) - uval->value.enumerated.item[0] = MONO_EARPIECE; - else if (scard_ops->output_dev_id == STEREO_HEADPHONE) - uval->value.enumerated.item[0] = - STEREO_HEADPHONE; - else - return -EINVAL; - else if (kcontrol->id.numid == INPUT_SEL) - uval->value.enumerated.item[0] = - scard_ops->input_dev_id; - else - return -EINVAL; - } else - uval->value.enumerated.item[0] = kcontrol->private_value; - return 0; -} - -/** -* snd_intelmad_device_set - set the device select control's info -* -* @kcontrol: pointer to the control -* @uval: pointer to the structure where the control's info is -* available to be set -* -* This function is called when .set function of a control is invoked from app -*/ -static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - int ret_val = 0, vendor, status; - struct intel_sst_pcm_control *pcm_control; - - pr_debug("snd_intelmad_device_set called\n"); - - WARN_ON(!uval); - WARN_ON(!kcontrol); - status = -1; - - intelmaddata = kcontrol->private_data; - - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - - WARN_ON(!scard_ops); - - /* store value with driver */ - kcontrol->private_value = uval->value.enumerated.item[0]; - - switch (kcontrol->id.numid) { - case OUTPUT_SEL: - ret_val = scard_ops->set_output_dev( - uval->value.enumerated.item[0]); - intelmaddata->output_sel = uval->value.enumerated.item[0]; - break; - case INPUT_SEL: - vendor = intelmaddata->sstdrv_ops->vendor_id; - if ((vendor == SND_MX) || (vendor == SND_FS)) { - pcm_control = intelmaddata->sstdrv_ops->pcm_control; - if (uval->value.enumerated.item[0] == HS_MIC) - status = 1; - else - status = 0; - pcm_control->device_control( - SST_ENABLE_RX_TIME_SLOT, &status); - } - ret_val = scard_ops->set_input_dev( - uval->value.enumerated.item[0]); - intelmaddata->input_sel = uval->value.enumerated.item[0]; - break; - case LINEOUT_SEL_MFLD: - ret_val = scard_ops->set_lineout_dev( - uval->value.enumerated.item[0]); - intelmaddata->lineout_sel = uval->value.enumerated.item[0]; - break; - default: - return -EINVAL; - } - kcontrol->private_value = uval->value.enumerated.item[0]; - return ret_val; -} - -static int snd_intelmad_device_dmic_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - - WARN_ON(!uval); - WARN_ON(!kcontrol); - - intelmaddata = kcontrol->private_data; - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - - if (scard_ops->input_dev_id != DMIC) { - pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id); - return 0; - } - - if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) - uval->value.enumerated.item[0] = kcontrol->private_value; - else - pr_debug(" CPU id = 0x%xis invalid.\n", - intelmaddata->cpu_id); - return 0; -} - -void msic_set_bit(u8 index, unsigned int *available_dmics) -{ - *available_dmics |= (1 << index); -} - -void msic_clear_bit(u8 index, unsigned int *available_dmics) -{ - *available_dmics &= ~(1 << index); -} - -int msic_is_set_bit(u8 index, unsigned int *available_dmics) -{ - int ret_val; - - ret_val = (*available_dmics & (1 << index)); - return ret_val; -} - -static int snd_intelmad_device_dmic_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uval) -{ - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - int i, dmic_index; - unsigned int available_dmics; - int jump_count; - int max_dmics = ARRAY_SIZE(router_dmics); - - WARN_ON(!uval); - WARN_ON(!kcontrol); - - intelmaddata = kcontrol->private_data; - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - WARN_ON(!scard_ops); - - if (scard_ops->input_dev_id != DMIC) { - pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id); - return 0; - } - - available_dmics = scard_ops->available_dmics; - - if (kcontrol->private_value > uval->value.enumerated.item[0]) { - pr_debug("jump count -1.\n"); - jump_count = -1; - } else { - pr_debug("jump count 1.\n"); - jump_count = 1; - } - - dmic_index = uval->value.enumerated.item[0]; - pr_debug("set function. dmic_index = %d, avl_dmic = 0x%x\n", - dmic_index, available_dmics); - for (i = 0; i < max_dmics; i++) { - pr_debug("set function. loop index = 0x%x. dmic_index = 0x%x\n", - i, dmic_index); - if (!msic_is_set_bit(dmic_index, &available_dmics)) { - msic_clear_bit(kcontrol->private_value, - &available_dmics); - msic_set_bit(dmic_index, &available_dmics); - kcontrol->private_value = dmic_index; - scard_ops->available_dmics = available_dmics; - scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] = - kcontrol->private_value; - scard_ops->set_hw_dmic_route - (kcontrol->id.numid-HW_CH_BASE); - return 0; - } - - dmic_index += jump_count; - - if (dmic_index > (max_dmics - 1) && jump_count == 1) { - pr_debug("Resettingthe dmic index to 0.\n"); - dmic_index = 0; - } else if (dmic_index == -1 && jump_count == -1) { - pr_debug("Resetting the dmic index to 5.\n"); - dmic_index = max_dmics - 1; - } - } - - return -EINVAL; -} - -static int snd_intelmad_device_dmic_info_mfld(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct snd_intelmad *intelmaddata; - struct snd_pmic_ops *scard_ops; - - uinfo->count = MONO_CNTL; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = ARRAY_SIZE(router_dmics); - - intelmaddata = kcontrol->private_data; - WARN_ON(!intelmaddata->sstdrv_ops); - - scard_ops = intelmaddata->sstdrv_ops->scard_ops; - WARN_ON(!scard_ops); - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strncpy(uinfo->value.enumerated.name, - router_dmics[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)-1); - - - msic_set_bit(kcontrol->private_value, &scard_ops->available_dmics); - pr_debug("info function. avl_dmic = 0x%x", - scard_ops->available_dmics); - - scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] = - kcontrol->private_value; - - return 0; -} - -struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = { -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_info_mrst, - .get = snd_intelmad_device_get, - .put = snd_intelmad_device_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_info_mrst, - .get = snd_intelmad_device_get, - .put = snd_intelmad_device_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_playback_volume_info, - .get = snd_intelmad_volume_get, - .put = snd_intelmad_volume_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_mute_info, - .get = snd_intelmad_mute_get, - .put = snd_intelmad_mute_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_capture_volume_info, - .get = snd_intelmad_volume_get, - .put = snd_intelmad_volume_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Capture Switch", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_mute_info, - .get = snd_intelmad_mute_get, - .put = snd_intelmad_mute_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_master_volume_info, - .get = snd_intelmad_volume_get, - .put = snd_intelmad_volume_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_mute_info, - .get = snd_intelmad_mute_get, - .put = snd_intelmad_mute_set, - .private_value = 0, -}, -}; - -struct snd_kcontrol_new -snd_intelmad_controls_mfld[MAX_CTRL_MFLD] __devinitdata = { -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_info_mfld, - .get = snd_intelmad_device_get, - .put = snd_intelmad_device_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_info_mfld, - .get = snd_intelmad_device_get, - .put = snd_intelmad_device_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line out", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_info_mfld, - .get = snd_intelmad_device_get, - .put = snd_intelmad_device_set, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = HW_CH_0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_dmic_info_mfld, - .get = snd_intelmad_device_dmic_get, - .put = snd_intelmad_device_dmic_set, - .private_value = 0 -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = HW_CH_1, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_dmic_info_mfld, - .get = snd_intelmad_device_dmic_get, - .put = snd_intelmad_device_dmic_set, - .private_value = 1 -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = HW_CH_2, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_dmic_info_mfld, - .get = snd_intelmad_device_dmic_get, - .put = snd_intelmad_device_dmic_set, - .private_value = 2 -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = HW_CH_3, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_intelmad_device_dmic_info_mfld, - .get = snd_intelmad_device_dmic_get, - .put = snd_intelmad_device_dmic_set, - .private_value = 3 -} -}; - diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c deleted file mode 100644 index 70cdb169781..00000000000 --- a/drivers/staging/intel_sst/intelmid_msic_control.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * intelmid_vm_control.c - Intel Sound card driver for MID - * - * Copyright (C) 2010 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file contains the control operations of msic vendors - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/file.h> -#include <linux/delay.h> -#include <sound/control.h> -#include "intel_sst.h" -#include <linux/input.h> -#include "intelmid_snd_control.h" -#include "intelmid.h" - -#define AUDIOMUX12 0x24c -#define AUDIOMUX34 0x24d - -static int msic_init_card(void) -{ - struct sc_reg_access sc_access[] = { - /* dmic configuration */ - {0x241, 0x85, 0}, - {0x242, 0x02, 0}, - /* audio paths config */ - {0x24C, 0x10, 0}, - {0x24D, 0x32, 0}, - /* PCM2 interface slots */ - /* preconfigured slots for 0-5 both tx, rx */ - {0x272, 0x10, 0}, - {0x273, 0x32, 0}, - {0x274, 0xFF, 0}, - {0x275, 0x10, 0}, - {0x276, 0x32, 0}, - {0x277, 0x54, 0}, - /*Sinc5 decimator*/ - {0x24E, 0x28, 0}, - /*TI vibra w/a settings*/ - {0x384, 0x80, 0}, - {0x385, 0x80, 0}, - {0x267, 0x00, 0}, - {0x261, 0x00, 0}, - /* pcm port setting */ - {0x278, 0x00, 0}, - {0x27B, 0x01, 0}, - {0x27C, 0x0a, 0}, - /* Set vol HSLRVOLCTRL, IHFVOL */ - {0x259, 0x08, 0}, - {0x25A, 0x08, 0}, - {0x25B, 0x08, 0}, - {0x25C, 0x08, 0}, - /* HSEPRXCTRL Enable the headset left and right FIR filters */ - {0x250, 0x30, 0}, - /* HSMIXER */ - {0x256, 0x11, 0}, - /* amic configuration */ - {0x249, 0x01, 0x0}, - {0x24A, 0x01, 0x0}, - /* unmask ocaudio/accdet interrupts */ - {0x1d, 0x00, 0x00}, - {0x1e, 0x00, 0x00}, - }; - snd_msic_ops.card_status = SND_CARD_INIT_DONE; - sst_sc_reg_access(sc_access, PMIC_WRITE, 28); - snd_msic_ops.pb_on = 0; - snd_msic_ops.pbhs_on = 0; - snd_msic_ops.cap_on = 0; - snd_msic_ops.input_dev_id = DMIC; /*def dev*/ - snd_msic_ops.output_dev_id = STEREO_HEADPHONE; - snd_msic_ops.jack_interrupt_status = false; - pr_debug("msic init complete!!\n"); - return 0; -} -static int msic_line_out_restore(u8 value) -{ - struct sc_reg_access hs_drv_en[] = { - {0x25d, 0x03, 0x03}, - }; - struct sc_reg_access ep_drv_en[] = { - {0x25d, 0x40, 0x40}, - }; - struct sc_reg_access ihf_drv_en[] = { - {0x25d, 0x0c, 0x0c}, - }; - struct sc_reg_access vib1_drv_en[] = { - {0x25d, 0x10, 0x10}, - }; - struct sc_reg_access vib2_drv_en[] = { - {0x25d, 0x20, 0x20}, - }; - struct sc_reg_access pmode_enable[] = { - {0x381, 0x10, 0x10}, - }; - int retval = 0; - - pr_debug("msic_lineout_restore_lineout_dev:%d\n", value); - - switch (value) { - case HEADSET: - pr_debug("Selecting Lineout-HEADSET-restore\n"); - if (snd_msic_ops.output_dev_id == STEREO_HEADPHONE) - retval = sst_sc_reg_access(hs_drv_en, - PMIC_READ_MODIFY, 1); - else - retval = sst_sc_reg_access(ep_drv_en, - PMIC_READ_MODIFY, 1); - break; - case IHF: - pr_debug("Selecting Lineout-IHF-restore\n"); - retval = sst_sc_reg_access(ihf_drv_en, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - retval = sst_sc_reg_access(pmode_enable, PMIC_READ_MODIFY, 1); - break; - case VIBRA1: - pr_debug("Selecting Lineout-Vibra1-restore\n"); - retval = sst_sc_reg_access(vib1_drv_en, PMIC_READ_MODIFY, 1); - break; - case VIBRA2: - pr_debug("Selecting Lineout-VIBRA2-restore\n"); - retval = sst_sc_reg_access(vib2_drv_en, PMIC_READ_MODIFY, 1); - break; - case NONE: - pr_debug("Selecting Lineout-NONE-restore\n"); - break; - default: - return -EINVAL; - } - return retval; -} -static int msic_get_lineout_prvstate(void) -{ - struct sc_reg_access hs_ihf_drv[2] = { - {0x257, 0x0, 0x0}, - {0x25d, 0x0, 0x0}, - }; - struct sc_reg_access vib1drv[2] = { - {0x264, 0x0, 0x0}, - {0x25D, 0x0, 0x0}, - }; - struct sc_reg_access vib2drv[2] = { - {0x26A, 0x0, 0x0}, - {0x25D, 0x0, 0x0}, - }; - int retval = 0, drv_en, dac_en, dev_id, mask; - for (dev_id = 0; dev_id < snd_msic_ops.line_out_names_cnt; dev_id++) { - switch (dev_id) { - case HEADSET: - pr_debug("msic_get_lineout_prvs_state: HEADSET\n"); - sst_sc_reg_access(hs_ihf_drv, PMIC_READ, 2); - - mask = (MASK0|MASK1); - dac_en = (hs_ihf_drv[0].value) & mask; - - mask = ((MASK0|MASK1)|MASK6); - drv_en = (hs_ihf_drv[1].value) & mask; - - if (dac_en && (!drv_en)) { - snd_msic_ops.prev_lineout_dev_id = HEADSET; - return retval; - } - break; - case IHF: - pr_debug("msic_get_lineout_prvstate: IHF\n"); - sst_sc_reg_access(hs_ihf_drv, PMIC_READ, 2); - - mask = (MASK2 | MASK3); - dac_en = (hs_ihf_drv[0].value) & mask; - - mask = (MASK2 | MASK3); - drv_en = (hs_ihf_drv[1].value) & mask; - - if (dac_en && (!drv_en)) { - snd_msic_ops.prev_lineout_dev_id = IHF; - return retval; - } - break; - case VIBRA1: - pr_debug("msic_get_lineout_prvstate: vibra1\n"); - sst_sc_reg_access(vib1drv, PMIC_READ, 2); - - mask = MASK1; - dac_en = (vib1drv[0].value) & mask; - - mask = MASK4; - drv_en = (vib1drv[1].value) & mask; - - if (dac_en && (!drv_en)) { - snd_msic_ops.prev_lineout_dev_id = VIBRA1; - return retval; - } - break; - case VIBRA2: - pr_debug("msic_get_lineout_prvstate: vibra2\n"); - sst_sc_reg_access(vib2drv, PMIC_READ, 2); - - mask = MASK1; - dac_en = (vib2drv[0].value) & mask; - - mask = MASK5; - drv_en = ((vib2drv[1].value) & mask); - - if (dac_en && (!drv_en)) { - snd_msic_ops.prev_lineout_dev_id = VIBRA2; - return retval; - } - break; - case NONE: - pr_debug("msic_get_lineout_prvstate: NONE\n"); - snd_msic_ops.prev_lineout_dev_id = NONE; - return retval; - default: - pr_debug("Invalid device id\n"); - snd_msic_ops.prev_lineout_dev_id = NONE; - return -EINVAL; - } - } - return retval; -} -static int msic_set_selected_lineout_dev(u8 value) -{ - struct sc_reg_access lout_hs[] = { - {0x25e, 0x33, 0xFF}, - {0x25d, 0x0, 0x43}, - }; - struct sc_reg_access lout_ihf[] = { - {0x25e, 0x55, 0xff}, - {0x25d, 0x0, 0x0c}, - }; - struct sc_reg_access lout_vibra1[] = { - - {0x25e, 0x61, 0xff}, - {0x25d, 0x0, 0x10}, - }; - struct sc_reg_access lout_vibra2[] = { - - {0x25e, 0x16, 0xff}, - {0x25d, 0x0, 0x20}, - }; - struct sc_reg_access lout_def[] = { - {0x25e, 0x66, 0x0}, - }; - struct sc_reg_access pmode_disable[] = { - {0x381, 0x00, 0x10}, - }; - struct sc_reg_access pmode_enable[] = { - {0x381, 0x10, 0x10}, - }; - int retval = 0; - - pr_debug("msic_set_selected_lineout_dev:%d\n", value); - msic_get_lineout_prvstate(); - msic_line_out_restore(snd_msic_ops.prev_lineout_dev_id); - snd_msic_ops.lineout_dev_id = value; - - switch (value) { - case HEADSET: - pr_debug("Selecting Lineout-HEADSET\n"); - if (snd_msic_ops.pb_on) - retval = sst_sc_reg_access(lout_hs, - PMIC_READ_MODIFY, 2); - if (retval) - return retval; - retval = sst_sc_reg_access(pmode_disable, - PMIC_READ_MODIFY, 1); - break; - case IHF: - pr_debug("Selecting Lineout-IHF\n"); - if (snd_msic_ops.pb_on) - retval = sst_sc_reg_access(lout_ihf, - PMIC_READ_MODIFY, 2); - if (retval) - return retval; - retval = sst_sc_reg_access(pmode_enable, - PMIC_READ_MODIFY, 1); - break; - case VIBRA1: - pr_debug("Selecting Lineout-Vibra1\n"); - if (snd_msic_ops.pb_on) - retval = sst_sc_reg_access(lout_vibra1, - PMIC_READ_MODIFY, 2); - if (retval) - return retval; - retval = sst_sc_reg_access(pmode_disable, - PMIC_READ_MODIFY, 1); - break; - case VIBRA2: - pr_debug("Selecting Lineout-VIBRA2\n"); - if (snd_msic_ops.pb_on) - retval = sst_sc_reg_access(lout_vibra2, - PMIC_READ_MODIFY, 2); - if (retval) - return retval; - retval = sst_sc_reg_access(pmode_disable, - PMIC_READ_MODIFY, 1); - break; - case NONE: - pr_debug("Selecting Lineout-NONE\n"); - retval = sst_sc_reg_access(lout_def, - PMIC_WRITE, 1); - if (retval) - return retval; - retval = sst_sc_reg_access(pmode_disable, - PMIC_READ_MODIFY, 1); - break; - default: - return -EINVAL; - } - return retval; -} - - -static int msic_power_up_pb(unsigned int device) -{ - struct sc_reg_access vaud[] = { - /* turn on the audio power supplies */ - {0x0DB, 0x07, 0}, - }; - struct sc_reg_access pll[] = { - /* turn on PLL */ - {0x240, 0x20, 0}, - }; - struct sc_reg_access vhs[] = { - /* VHSP */ - {0x0DC, 0x3D, 0}, - /* VHSN */ - {0x0DD, 0x3F, 0}, - }; - struct sc_reg_access hsdac[] = { - {0x382, 0x40, 0x40}, - /* disable driver */ - {0x25D, 0x0, 0x43}, - /* DAC CONFIG ; both HP, LP on */ - {0x257, 0x03, 0x03}, - }; - struct sc_reg_access hs_filter[] = { - /* HSEPRXCTRL Enable the headset left and right FIR filters */ - {0x250, 0x30, 0}, - /* HSMIXER */ - {0x256, 0x11, 0}, - }; - struct sc_reg_access hs_enable[] = { - /* enable driver */ - {0x25D, 0x3, 0x3}, - {0x26C, 0x0, 0x2}, - /* unmute the headset */ - { 0x259, 0x80, 0x80}, - { 0x25A, 0x80, 0x80}, - }; - struct sc_reg_access vihf[] = { - /* VIHF ON */ - {0x0C9, 0x27, 0x00}, - }; - struct sc_reg_access ihf_filter[] = { - /* disable driver */ - {0x25D, 0x00, 0x0C}, - /*Filer DAC enable*/ - {0x251, 0x03, 0x03}, - {0x257, 0x0C, 0x0C}, - }; - struct sc_reg_access ihf_en[] = { - /*enable drv*/ - {0x25D, 0x0C, 0x0c}, - }; - struct sc_reg_access ihf_unmute[] = { - /*unmute headset*/ - {0x25B, 0x80, 0x80}, - {0x25C, 0x80, 0x80}, - }; - struct sc_reg_access epdac[] = { - /* disable driver */ - {0x25D, 0x0, 0x43}, - /* DAC CONFIG ; both HP, LP on */ - {0x257, 0x03, 0x03}, - }; - struct sc_reg_access ep_enable[] = { - /* enable driver */ - {0x25D, 0x40, 0x40}, - /* unmute the headset */ - { 0x259, 0x80, 0x80}, - { 0x25A, 0x80, 0x80}, - }; - struct sc_reg_access vib1_en[] = { - /* enable driver, ADC */ - {0x25D, 0x10, 0x10}, - {0x264, 0x02, 0x82}, - }; - struct sc_reg_access vib2_en[] = { - /* enable driver, ADC */ - {0x25D, 0x20, 0x20}, - {0x26A, 0x02, 0x82}, - }; - struct sc_reg_access pcm2_en[] = { - /* enable pcm 2 */ - {0x27C, 0x1, 0x1}, - }; - int retval = 0; - - if (snd_msic_ops.card_status == SND_CARD_UN_INIT) { - retval = msic_init_card(); - if (retval) - return retval; - } - - pr_debug("powering up pb.... Device %d\n", device); - sst_sc_reg_access(vaud, PMIC_WRITE, 1); - msleep(1); - sst_sc_reg_access(pll, PMIC_WRITE, 1); - msleep(1); - switch (device) { - case SND_SST_DEVICE_HEADSET: - snd_msic_ops.pb_on = 1; - snd_msic_ops.pbhs_on = 1; - if (snd_msic_ops.output_dev_id == STEREO_HEADPHONE) { - sst_sc_reg_access(vhs, PMIC_WRITE, 2); - sst_sc_reg_access(hsdac, PMIC_READ_MODIFY, 3); - sst_sc_reg_access(hs_filter, PMIC_WRITE, 2); - sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 4); - } else { - sst_sc_reg_access(epdac, PMIC_READ_MODIFY, 2); - sst_sc_reg_access(hs_filter, PMIC_WRITE, 2); - sst_sc_reg_access(ep_enable, PMIC_READ_MODIFY, 3); - } - if (snd_msic_ops.lineout_dev_id == HEADSET) - msic_set_selected_lineout_dev(HEADSET); - break; - case SND_SST_DEVICE_IHF: - snd_msic_ops.pb_on = 1; - sst_sc_reg_access(vihf, PMIC_WRITE, 1); - sst_sc_reg_access(ihf_filter, PMIC_READ_MODIFY, 3); - sst_sc_reg_access(ihf_en, PMIC_READ_MODIFY, 1); - sst_sc_reg_access(ihf_unmute, PMIC_READ_MODIFY, 2); - if (snd_msic_ops.lineout_dev_id == IHF) - msic_set_selected_lineout_dev(IHF); - break; - - case SND_SST_DEVICE_VIBRA: - snd_msic_ops.pb_on = 1; - sst_sc_reg_access(vib1_en, PMIC_READ_MODIFY, 2); - if (snd_msic_ops.lineout_dev_id == VIBRA1) - msic_set_selected_lineout_dev(VIBRA1); - break; - - case SND_SST_DEVICE_HAPTIC: - snd_msic_ops.pb_on = 1; - sst_sc_reg_access(vib2_en, PMIC_READ_MODIFY, 2); - if (snd_msic_ops.lineout_dev_id == VIBRA2) - msic_set_selected_lineout_dev(VIBRA2); - break; - - default: - pr_warn("Wrong Device %d, selected %d\n", - device, snd_msic_ops.output_dev_id); - } - return sst_sc_reg_access(pcm2_en, PMIC_READ_MODIFY, 1); -} - -static int msic_power_up_cp(unsigned int device) -{ - struct sc_reg_access vaud[] = { - /* turn on the audio power supplies */ - {0x0DB, 0x07, 0}, - }; - struct sc_reg_access pll[] = { - /* turn on PLL */ - {0x240, 0x20, 0}, - }; - struct sc_reg_access dmic_bias[] = { - /* Turn on AMIC supply */ - {0x247, 0xA0, 0xA0}, - }; - struct sc_reg_access dmic[] = { - /* mic demux enable */ - {0x245, 0x3F, 0x3F}, - {0x246, 0x07, 0x07}, - - }; - struct sc_reg_access amic_bias[] = { - /* Turn on AMIC supply */ - {0x247, 0xFC, 0xFC}, - }; - struct sc_reg_access amic[] = { - /*MIC EN*/ - {0x249, 0x01, 0x01}, - {0x24A, 0x01, 0x01}, - /*ADC EN*/ - {0x248, 0x05, 0x0F}, - - }; - struct sc_reg_access pcm2[] = { - /* enable pcm 2 */ - {0x27C, 0x1, 0x1}, - }; - struct sc_reg_access tx_on[] = { - /*wait for mic to stabalize before turning on audio channels*/ - {0x24F, 0x3C, 0x0}, - }; - int retval = 0; - - if (snd_msic_ops.card_status == SND_CARD_UN_INIT) { - retval = msic_init_card(); - if (retval) - return retval; - } - - pr_debug("powering up cp....%d\n", snd_msic_ops.input_dev_id); - sst_sc_reg_access(vaud, PMIC_WRITE, 1); - msleep(500);/*FIXME need optimzed value here*/ - sst_sc_reg_access(pll, PMIC_WRITE, 1); - msleep(1); - snd_msic_ops.cap_on = 1; - if (snd_msic_ops.input_dev_id == AMIC) { - sst_sc_reg_access(amic_bias, PMIC_READ_MODIFY, 1); - msleep(1); - sst_sc_reg_access(amic, PMIC_READ_MODIFY, 3); - } else { - sst_sc_reg_access(dmic_bias, PMIC_READ_MODIFY, 1); - msleep(1); - sst_sc_reg_access(dmic, PMIC_READ_MODIFY, 2); - } - msleep(1); - sst_sc_reg_access(tx_on, PMIC_WRITE, 1); - return sst_sc_reg_access(pcm2, PMIC_READ_MODIFY, 1); -} - -static int msic_power_down(void) -{ - struct sc_reg_access power_dn[] = { - /* VHSP */ - {0x0DC, 0xC4, 0}, - /* VHSN */ - {0x0DD, 0x04, 0}, - /* VIHF */ - {0x0C9, 0x24, 0}, - }; - struct sc_reg_access pll[] = { - /* turn off PLL*/ - {0x240, 0x00, 0x0}, - }; - struct sc_reg_access vaud[] = { - /* turn off VAUD*/ - {0x0DB, 0x04, 0}, - }; - - pr_debug("powering dn msic\n"); - snd_msic_ops.pbhs_on = 0; - snd_msic_ops.pb_on = 0; - snd_msic_ops.cap_on = 0; - sst_sc_reg_access(power_dn, PMIC_WRITE, 3); - msleep(1); - sst_sc_reg_access(pll, PMIC_WRITE, 1); - msleep(1); - sst_sc_reg_access(vaud, PMIC_WRITE, 1); - return 0; -} - -static int msic_power_down_pb(unsigned int device) -{ - struct sc_reg_access drv_enable[] = { - {0x25D, 0x00, 0x00}, - }; - struct sc_reg_access hs_mute[] = { - {0x259, 0x80, 0x80}, - {0x25A, 0x80, 0x80}, - {0x26C, 0x02, 0x02}, - }; - struct sc_reg_access hs_off[] = { - {0x257, 0x00, 0x03}, - {0x250, 0x00, 0x30}, - {0x382, 0x00, 0x40}, - }; - struct sc_reg_access ihf_mute[] = { - {0x25B, 0x80, 0x80}, - {0x25C, 0x80, 0x80}, - }; - struct sc_reg_access ihf_off[] = { - {0x257, 0x00, 0x0C}, - {0x251, 0x00, 0x03}, - }; - struct sc_reg_access vib1_off[] = { - {0x264, 0x00, 0x82}, - }; - struct sc_reg_access vib2_off[] = { - {0x26A, 0x00, 0x82}, - }; - struct sc_reg_access lout_off[] = { - {0x25e, 0x66, 0x00}, - }; - struct sc_reg_access pmode_disable[] = { - {0x381, 0x00, 0x10}, - }; - - - - pr_debug("powering dn pb for device %d\n", device); - switch (device) { - case SND_SST_DEVICE_HEADSET: - snd_msic_ops.pbhs_on = 0; - sst_sc_reg_access(hs_mute, PMIC_READ_MODIFY, 3); - drv_enable[0].mask = 0x43; - sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1); - sst_sc_reg_access(hs_off, PMIC_READ_MODIFY, 3); - if (snd_msic_ops.lineout_dev_id == HEADSET) - sst_sc_reg_access(lout_off, PMIC_WRITE, 1); - break; - - case SND_SST_DEVICE_IHF: - sst_sc_reg_access(ihf_mute, PMIC_READ_MODIFY, 2); - drv_enable[0].mask = 0x0C; - sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1); - sst_sc_reg_access(ihf_off, PMIC_READ_MODIFY, 2); - if (snd_msic_ops.lineout_dev_id == IHF) { - sst_sc_reg_access(lout_off, PMIC_WRITE, 1); - sst_sc_reg_access(pmode_disable, PMIC_READ_MODIFY, 1); - } - break; - - case SND_SST_DEVICE_VIBRA: - sst_sc_reg_access(vib1_off, PMIC_READ_MODIFY, 1); - drv_enable[0].mask = 0x10; - sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1); - if (snd_msic_ops.lineout_dev_id == VIBRA1) - sst_sc_reg_access(lout_off, PMIC_WRITE, 1); - break; - - case SND_SST_DEVICE_HAPTIC: - sst_sc_reg_access(vib2_off, PMIC_READ_MODIFY, 1); - drv_enable[0].mask = 0x20; - sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1); - if (snd_msic_ops.lineout_dev_id == VIBRA2) - sst_sc_reg_access(lout_off, PMIC_WRITE, 1); - break; - } - return 0; -} - -static int msic_power_down_cp(unsigned int device) -{ - struct sc_reg_access dmic[] = { - {0x247, 0x00, 0xA0}, - {0x245, 0x00, 0x38}, - {0x246, 0x00, 0x07}, - }; - struct sc_reg_access amic[] = { - {0x248, 0x00, 0x05}, - {0x249, 0x00, 0x01}, - {0x24A, 0x00, 0x01}, - {0x247, 0x00, 0xA3}, - }; - struct sc_reg_access tx_off[] = { - {0x24F, 0x00, 0x3C}, - }; - - pr_debug("powering dn cp....\n"); - snd_msic_ops.cap_on = 0; - sst_sc_reg_access(tx_off, PMIC_READ_MODIFY, 1); - if (snd_msic_ops.input_dev_id == DMIC) - sst_sc_reg_access(dmic, PMIC_READ_MODIFY, 3); - else - sst_sc_reg_access(amic, PMIC_READ_MODIFY, 4); - return 0; -} - -static int msic_set_selected_output_dev(u8 value) -{ - int retval = 0; - - pr_debug("msic set selected output:%d\n", value); - snd_msic_ops.output_dev_id = value; - if (snd_msic_ops.pbhs_on) - msic_power_up_pb(SND_SST_DEVICE_HEADSET); - return retval; -} - -static int msic_set_selected_input_dev(u8 value) -{ - - struct sc_reg_access sc_access_dmic[] = { - {0x24C, 0x10, 0x0}, - }; - struct sc_reg_access sc_access_amic[] = { - {0x24C, 0x76, 0x0}, - - }; - int retval = 0; - - pr_debug("msic_set_selected_input_dev:%d\n", value); - snd_msic_ops.input_dev_id = value; - switch (value) { - case AMIC: - pr_debug("Selecting AMIC1\n"); - retval = sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 1); - break; - case DMIC: - pr_debug("Selecting DMIC1\n"); - retval = sst_sc_reg_access(sc_access_dmic, PMIC_WRITE, 1); - break; - default: - return -EINVAL; - - } - if (snd_msic_ops.cap_on) - retval = msic_power_up_cp(SND_SST_DEVICE_CAPTURE); - return retval; -} - -static int msic_set_hw_dmic_route(u8 hw_ch_index) -{ - struct sc_reg_access sc_access_router; - int retval = -EINVAL; - - switch (hw_ch_index) { - case HW_CH0: - sc_access_router.reg_addr = AUDIOMUX12; - sc_access_router.value = snd_msic_ops.hw_dmic_map[0]; - sc_access_router.mask = (MASK2 | MASK1 | MASK0); - pr_debug("hw_ch0. value = 0x%x\n", - sc_access_router.value); - retval = sst_sc_reg_access(&sc_access_router, - PMIC_READ_MODIFY, 1); - break; - - case HW_CH1: - sc_access_router.reg_addr = AUDIOMUX12; - sc_access_router.value = (snd_msic_ops.hw_dmic_map[1]) << 4; - sc_access_router.mask = (MASK6 | MASK5 | MASK4); - pr_debug("### hw_ch1. value = 0x%x\n", - sc_access_router.value); - retval = sst_sc_reg_access(&sc_access_router, - PMIC_READ_MODIFY, 1); - break; - - case HW_CH2: - sc_access_router.reg_addr = AUDIOMUX34; - sc_access_router.value = snd_msic_ops.hw_dmic_map[2]; - sc_access_router.mask = (MASK2 | MASK1 | MASK0); - pr_debug("hw_ch2. value = 0x%x\n", - sc_access_router.value); - retval = sst_sc_reg_access(&sc_access_router, - PMIC_READ_MODIFY, 1); - break; - - case HW_CH3: - sc_access_router.reg_addr = AUDIOMUX34; - sc_access_router.value = (snd_msic_ops.hw_dmic_map[3]) << 4; - sc_access_router.mask = (MASK6 | MASK5 | MASK4); - pr_debug("hw_ch3. value = 0x%x\n", - sc_access_router.value); - retval = sst_sc_reg_access(&sc_access_router, - PMIC_READ_MODIFY, 1); - break; - } - - return retval; -} - - -static int msic_set_pcm_voice_params(void) -{ - return 0; -} - -static int msic_set_pcm_audio_params(int sfreq, int word_size, int num_channel) -{ - return 0; -} - -static int msic_set_audio_port(int status) -{ - return 0; -} - -static int msic_set_voice_port(int status) -{ - return 0; -} - -static int msic_set_mute(int dev_id, u8 value) -{ - return 0; -} - -static int msic_set_vol(int dev_id, int value) -{ - return 0; -} - -static int msic_get_mute(int dev_id, u8 *value) -{ - return 0; -} - -static int msic_get_vol(int dev_id, int *value) -{ - return 0; -} - -static int msic_set_headset_state(int state) -{ - struct sc_reg_access hs_enable[] = { - {0x25D, 0x03, 0x03}, - }; - - if (state) - /*enable*/ - sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 1); - else { - hs_enable[0].value = 0; - sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 1); - } - return 0; -} - -static int msic_enable_mic_bias(void) -{ - struct sc_reg_access jack_interrupt_reg[] = { - {0x0DB, 0x07, 0x00}, - - }; - struct sc_reg_access jack_bias_reg[] = { - {0x247, 0x0C, 0x0C}, - }; - - sst_sc_reg_access(jack_interrupt_reg, PMIC_WRITE, 1); - sst_sc_reg_access(jack_bias_reg, PMIC_READ_MODIFY, 1); - return 0; -} - -static int msic_disable_mic_bias(void) -{ - if (snd_msic_ops.jack_interrupt_status == true) - return 0; - if (!(snd_msic_ops.pb_on || snd_msic_ops.cap_on)) - msic_power_down(); - return 0; -} - -static int msic_disable_jack_btn(void) -{ - struct sc_reg_access btn_disable[] = { - {0x26C, 0x00, 0x01} - }; - - if (!(snd_msic_ops.pb_on || snd_msic_ops.cap_on)) - msic_power_down(); - snd_msic_ops.jack_interrupt_status = false; - return sst_sc_reg_access(btn_disable, PMIC_READ_MODIFY, 1); -} - -static int msic_enable_jack_btn(void) -{ - struct sc_reg_access btn_enable[] = { - {0x26b, 0x77, 0x00}, - {0x26C, 0x01, 0x00}, - }; - return sst_sc_reg_access(btn_enable, PMIC_WRITE, 2); -} -static int msic_convert_adc_to_mvolt(unsigned int mic_bias) -{ - return (ADC_ONE_LSB_MULTIPLIER * mic_bias) / 1000; -} -int msic_get_headset_state(int mic_bias) -{ - struct sc_reg_access msic_hs_toggle[] = { - {0x070, 0x00, 0x01}, - }; - if (mic_bias >= 0 && mic_bias < 400) { - - pr_debug("Detected Headphone!!!\n"); - sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1); - - } else if (mic_bias > 400 && mic_bias < 650) { - - pr_debug("Detected American headset\n"); - msic_hs_toggle[0].value = 0x01; - sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1); - - } else if (mic_bias >= 650 && mic_bias < 2000) { - - pr_debug("Detected Headset!!!\n"); - sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1); - /*power on jack and btn*/ - snd_msic_ops.jack_interrupt_status = true; - msic_enable_jack_btn(); - msic_enable_mic_bias(); - return SND_JACK_HEADSET; - - } else - pr_debug("Detected Open Cable!!!\n"); - - return SND_JACK_HEADPHONE; -} - -static int msic_get_mic_bias(void *arg) -{ - struct snd_intelmad *intelmad_drv = (struct snd_intelmad *)arg; - u16 adc_adr = intelmad_drv->adc_address; - u16 adc_val; - int ret; - struct sc_reg_access adc_ctrl3[2] = { - {0x1C2, 0x05, 0x0}, - }; - - struct sc_reg_access audio_adc_reg1 = {0,}; - struct sc_reg_access audio_adc_reg2 = {0,}; - - msic_enable_mic_bias(); - /* Enable the msic for conversion before reading */ - ret = sst_sc_reg_access(adc_ctrl3, PMIC_WRITE, 1); - if (ret) - return ret; - adc_ctrl3[0].value = 0x04; - /* Re-toggle the RRDATARD bit */ - ret = sst_sc_reg_access(adc_ctrl3, PMIC_WRITE, 1); - if (ret) - return ret; - - audio_adc_reg1.reg_addr = adc_adr; - /* Read the higher bits of data */ - msleep(1000); - ret = sst_sc_reg_access(&audio_adc_reg1, PMIC_READ, 1); - if (ret) - return ret; - pr_debug("adc read value %x", audio_adc_reg1.value); - - /* Shift bits to accomodate the lower two data bits */ - adc_val = (audio_adc_reg1.value << 2); - adc_adr++; - audio_adc_reg2. reg_addr = adc_adr; - ret = sst_sc_reg_access(&audio_adc_reg2, PMIC_READ, 1); - if (ret) - return ret; - pr_debug("adc read value %x", audio_adc_reg2.value); - - /* Adding lower two bits to the higher bits */ - audio_adc_reg2.value &= 03; - adc_val += audio_adc_reg2.value; - - pr_debug("ADC value 0x%x", adc_val); - msic_disable_mic_bias(); - return adc_val; -} - -static void msic_pmic_irq_cb(void *cb_data, u8 intsts) -{ - struct mad_jack *mjack = NULL; - unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; - struct snd_intelmad *intelmaddata = cb_data; - int retval = 0; - - pr_debug("value returned = 0x%x\n", intsts); - - if (snd_msic_ops.card_status == SND_CARD_UN_INIT) { - retval = msic_init_card(); - if (retval) - return; - } - - mjack = &intelmaddata->jack[0]; - if (intsts & 0x1) { - pr_debug("MAD short_push detected\n"); - present = SND_JACK_BTN_0; - jack_event_flag = buttonpressflag = 1; - mjack->jack.type = SND_JACK_BTN_0; - mjack->jack.key[0] = BTN_0 ; - } - - if (intsts & 0x2) { - pr_debug(":MAD long_push detected\n"); - jack_event_flag = buttonpressflag = 1; - mjack->jack.type = present = SND_JACK_BTN_1; - mjack->jack.key[1] = BTN_1; - } - - if (intsts & 0x4) { - unsigned int mic_bias; - jack_event_flag = 1; - buttonpressflag = 0; - mic_bias = msic_get_mic_bias(intelmaddata); - pr_debug("mic_bias = %d\n", mic_bias); - mic_bias = msic_convert_adc_to_mvolt(mic_bias); - pr_debug("mic_bias after conversion = %d mV\n", mic_bias); - mjack->jack_dev_state = msic_get_headset_state(mic_bias); - mjack->jack.type = present = mjack->jack_dev_state; - } - - if (intsts & 0x8) { - mjack->jack.type = mjack->jack_dev_state; - present = 0; - jack_event_flag = 1; - buttonpressflag = 0; - msic_disable_jack_btn(); - msic_disable_mic_bias(); - } - if (jack_event_flag) - sst_mad_send_jack_report(&mjack->jack, - buttonpressflag, present); -} - - - -struct snd_pmic_ops snd_msic_ops = { - .set_input_dev = msic_set_selected_input_dev, - .set_output_dev = msic_set_selected_output_dev, - .set_lineout_dev = msic_set_selected_lineout_dev, - .set_hw_dmic_route = msic_set_hw_dmic_route, - .set_mute = msic_set_mute, - .get_mute = msic_get_mute, - .set_vol = msic_set_vol, - .get_vol = msic_get_vol, - .init_card = msic_init_card, - .set_pcm_audio_params = msic_set_pcm_audio_params, - .set_pcm_voice_params = msic_set_pcm_voice_params, - .set_voice_port = msic_set_voice_port, - .set_audio_port = msic_set_audio_port, - .power_up_pmic_pb = msic_power_up_pb, - .power_up_pmic_cp = msic_power_up_cp, - .power_down_pmic_pb = msic_power_down_pb, - .power_down_pmic_cp = msic_power_down_cp, - .power_down_pmic = msic_power_down, - .pmic_irq_cb = msic_pmic_irq_cb, - .pmic_jack_enable = msic_enable_mic_bias, - .pmic_get_mic_bias = msic_get_mic_bias, - .pmic_set_headset_state = msic_set_headset_state, -}; diff --git a/drivers/staging/intel_sst/intelmid_pvt.c b/drivers/staging/intel_sst/intelmid_pvt.c deleted file mode 100644 index 90e0e64c0ab..00000000000 --- a/drivers/staging/intel_sst/intelmid_pvt.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * intelmid_pvt.h - Intel Sound card driver for MID - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Harsha Priya <priya.harsha@intel.com> - * Vinod Koul <vinod.koul@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * ALSA driver for Intel MID sound card chipset - holding private functions - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/io.h> -#include <asm/intel_scu_ipc.h> -#include <sound/core.h> -#include <sound/control.h> -#include <sound/pcm.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intelmid_snd_control.h" -#include "intelmid.h" - - -void period_elapsed(void *mad_substream) -{ - struct snd_pcm_substream *substream = mad_substream; - struct mad_stream_pvt *stream; - - - - if (!substream || !substream->runtime) - return; - stream = substream->runtime->private_data; - if (!stream) - return; - - if (stream->stream_status != RUNNING) - return; - pr_debug("calling period elapsed\n"); - snd_pcm_period_elapsed(substream); - return; -} - - -int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream) -{ - struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream); - struct mad_stream_pvt *stream = substream->runtime->private_data; - struct snd_sst_stream_params param = {{{0,},},}; - struct snd_sst_params str_params = {0}; - int ret_val; - - /* set codec params and inform SST driver the same */ - - param.uc.pcm_params.codec = SST_CODEC_TYPE_PCM; - param.uc.pcm_params.num_chan = (u8) substream->runtime->channels; - param.uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits; - param.uc.pcm_params.reserved = 0; - param.uc.pcm_params.sfreq = substream->runtime->rate; - param.uc.pcm_params.ring_buffer_size = - snd_pcm_lib_buffer_bytes(substream); - param.uc.pcm_params.period_count = substream->runtime->period_size; - param.uc.pcm_params.ring_buffer_addr = - virt_to_phys(substream->runtime->dma_area); - pr_debug("period_cnt = %d\n", param.uc.pcm_params.period_count); - pr_debug("sfreq= %d, wd_sz = %d\n", - param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz); - - str_params.sparams = param; - str_params.codec = SST_CODEC_TYPE_PCM; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - str_params.ops = STREAM_OPS_PLAYBACK; - pr_debug("Playbck stream,Device %d\n", stream->device); - } else { - str_params.ops = STREAM_OPS_CAPTURE; - stream->device = SND_SST_DEVICE_CAPTURE; - pr_debug("Capture stream,Device %d\n", stream->device); - } - str_params.device_type = stream->device; - ret_val = intelmaddata->sstdrv_ops->pcm_control->open(&str_params); - pr_debug("sst: SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); - if (ret_val < 0) - return ret_val; - - stream->stream_info.str_id = ret_val; - stream->stream_status = INIT; - stream->stream_info.buffer_ptr = 0; - pr_debug("str id : %d\n", stream->stream_info.str_id); - - return ret_val; -} - -int snd_intelmad_init_stream(struct snd_pcm_substream *substream) -{ - struct mad_stream_pvt *stream = substream->runtime->private_data; - struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream); - int ret_val; - - pr_debug("setting buffer ptr param\n"); - stream->stream_info.period_elapsed = period_elapsed; - stream->stream_info.mad_substream = substream; - stream->stream_info.buffer_ptr = 0; - stream->stream_info.sfreq = substream->runtime->rate; - ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control( - SST_SND_STREAM_INIT, &stream->stream_info); - if (ret_val) - pr_err("control_set ret error %d\n", ret_val); - return ret_val; - -} - - -/** - * sst_sc_reg_access - IPC read/write wrapper - * - * @sc_access: array of data, addresses and mask - * @type: operation type - * @num_val: number of reg to opertae on - * - * Reads/writes/read-modify operations on registers accessed through SCU (sound - * card and few SST DSP regsisters that are not accissible to IA) - */ -int sst_sc_reg_access(struct sc_reg_access *sc_access, - int type, int num_val) -{ - int i, retval = 0; - if (type == PMIC_WRITE) { - for (i = 0; i < num_val; i++) { - retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr, - sc_access[i].value); - if (retval) - goto err; - } - } else if (type == PMIC_READ) { - for (i = 0; i < num_val; i++) { - retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr, - &(sc_access[i].value)); - if (retval) - goto err; - } - } else { - for (i = 0; i < num_val; i++) { - retval = intel_scu_ipc_update_register( - sc_access[i].reg_addr, sc_access[i].value, - sc_access[i].mask); - if (retval) - goto err; - } - } - return 0; -err: - pr_err("IPC failed for cmd %d, %d\n", retval, type); - pr_err("reg:0x%2x addr:0x%2x\n", - sc_access[i].reg_addr, sc_access[i].value); - return retval; -} diff --git a/drivers/staging/intel_sst/intelmid_snd_control.h b/drivers/staging/intel_sst/intelmid_snd_control.h deleted file mode 100644 index 06ad3a10099..00000000000 --- a/drivers/staging/intel_sst/intelmid_snd_control.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef __INTELMID_SND_CTRL_H__ -#define __INTELMID_SND_CTRL_H__ -/* - * intelmid_snd_control.h - Intel Sound card driver for MID - * - * Copyright (C) 2008-10 Intel Corporation - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file defines all snd control functions - */ - -/* -Mask bits -*/ -#define MASK0 0x01 /* 0000 0001 */ -#define MASK1 0x02 /* 0000 0010 */ -#define MASK2 0x04 /* 0000 0100 */ -#define MASK3 0x08 /* 0000 1000 */ -#define MASK4 0x10 /* 0001 0000 */ -#define MASK5 0x20 /* 0010 0000 */ -#define MASK6 0x40 /* 0100 0000 */ -#define MASK7 0x80 /* 1000 0000 */ -/* -value bits -*/ -#define VALUE0 0x01 /* 0000 0001 */ -#define VALUE1 0x02 /* 0000 0010 */ -#define VALUE2 0x04 /* 0000 0100 */ -#define VALUE3 0x08 /* 0000 1000 */ -#define VALUE4 0x10 /* 0001 0000 */ -#define VALUE5 0x20 /* 0010 0000 */ -#define VALUE6 0x40 /* 0100 0000 */ -#define VALUE7 0x80 /* 1000 0000 */ - -#define MUTE 0 /* ALSA Passes 0 for mute */ -#define UNMUTE 1 /* ALSA Passes 1 for unmute */ - -#define MAX_VOL_PMIC_VENDOR0 0x3f /* max vol in dB for stereo & voice DAC */ -#define MIN_VOL_PMIC_VENDOR0 0 /* min vol in dB for stereo & voice DAC */ -/* Head phone volume control */ -#define MAX_HP_VOL_PMIC_VENDOR1 6 /* max volume in dB for HP */ -#define MIN_HP_VOL_PMIC_VENDOR1 (-84) /* min volume in dB for HP */ -#define MAX_HP_VOL_INDX_PMIC_VENDOR1 40 /* Number of HP volume control values */ - -/* Mono Earpiece Volume control */ -#define MAX_EP_VOL_PMIC_VENDOR1 0 /* max volume in dB for EP */ -#define MIN_EP_VOL_PMIC_VENDOR1 (-75) /* min volume in dB for EP */ -#define MAX_EP_VOL_INDX_PMIC_VENDOR1 32 /* Number of EP volume control values */ - -int sst_sc_reg_access(struct sc_reg_access *sc_access, - int type, int num_val); -extern struct snd_pmic_ops snd_pmic_ops_fs; -extern struct snd_pmic_ops snd_pmic_ops_mx; -extern struct snd_pmic_ops snd_pmic_ops_nc; -extern struct snd_pmic_ops snd_msic_ops; - -/* device */ -enum SND_INPUT_DEVICE { - AMIC, - DMIC, - HS_MIC, - IN_UNDEFINED -}; -enum SND_LINE_OUT_DEVICE { - HEADSET, - IHF, - VIBRA1, - VIBRA2, - NONE, -}; - -enum SND_OUTPUT_DEVICE { - STEREO_HEADPHONE, - MONO_EARPIECE, - - INTERNAL_SPKR, - RECEIVER, - OUT_UNDEFINED -}; - -enum pmic_controls { - PMIC_SND_HP_MIC_MUTE = 0x0001, - PMIC_SND_AMIC_MUTE = 0x0002, - PMIC_SND_DMIC_MUTE = 0x0003, - PMIC_SND_CAPTURE_VOL = 0x0004, -/* Output controls */ - PMIC_SND_LEFT_PB_VOL = 0x0010, - PMIC_SND_RIGHT_PB_VOL = 0x0011, - PMIC_SND_LEFT_HP_MUTE = 0x0012, - PMIC_SND_RIGHT_HP_MUTE = 0x0013, - PMIC_SND_LEFT_SPEAKER_MUTE = 0x0014, - PMIC_SND_RIGHT_SPEAKER_MUTE = 0x0015, - PMIC_SND_RECEIVER_VOL = 0x0016, - PMIC_SND_RECEIVER_MUTE = 0x0017, - PMIC_SND_LEFT_MASTER_VOL = 0x0018, - PMIC_SND_RIGHT_MASTER_VOL = 0x0019, -/* Other controls */ - PMIC_SND_MUTE_ALL = 0x0020, - PMIC_MAX_CONTROLS = 0x0020, -}; - -#endif /* __INTELMID_SND_CTRL_H__ */ - - diff --git a/drivers/staging/intel_sst/intelmid_v0_control.c b/drivers/staging/intel_sst/intelmid_v0_control.c deleted file mode 100644 index b8dfdb9bc1a..00000000000 --- a/drivers/staging/intel_sst/intelmid_v0_control.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * intel_sst_v0_control.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corporation - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file contains the control operations of vendor 1 - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/file.h> -#include <sound/control.h> -#include "intel_sst.h" -#include "intelmid_snd_control.h" -#include "intelmid.h" - -enum _reg_v1 { - VOICEPORT1 = 0x180, - VOICEPORT2 = 0x181, - AUDIOPORT1 = 0x182, - AUDIOPORT2 = 0x183, - MISCVOICECTRL = 0x184, - MISCAUDCTRL = 0x185, - DMICCTRL1 = 0x186, - AUDIOBIAS = 0x187, - MICCTRL = 0x188, - MICLICTRL1 = 0x189, - MICLICTRL2 = 0x18A, - MICLICTRL3 = 0x18B, - VOICEDACCTRL1 = 0x18C, - STEREOADCCTRL = 0x18D, - AUD15 = 0x18E, - AUD16 = 0x18F, - AUD17 = 0x190, - AUD18 = 0x191, - RMIXOUTSEL = 0x192, - ANALOGLBR = 0x193, - ANALOGLBL = 0x194, - POWERCTRL1 = 0x195, - POWERCTRL2 = 0x196, - HEADSETDETECTINT = 0x197, - HEADSETDETECTINTMASK = 0x198, - TRIMENABLE = 0x199, -}; - -int rev_id = 0x20; -static bool jack_det_enabled; - -/**** - * fs_init_card - initialize the sound card - * - * This initializes the audio paths to know values in case of this sound card - */ -static int fs_init_card(void) -{ - struct sc_reg_access sc_access[] = { - {0x180, 0x00, 0x0}, - {0x181, 0x00, 0x0}, - {0x182, 0xF8, 0x0}, - {0x183, 0x08, 0x0}, - {0x184, 0x00, 0x0}, - {0x185, 0x40, 0x0}, - {0x186, 0x06, 0x0}, - {0x187, 0x80, 0x0}, - {0x188, 0x40, 0x0}, - {0x189, 0x39, 0x0}, - {0x18a, 0x39, 0x0}, - {0x18b, 0x1F, 0x0}, - {0x18c, 0x00, 0x0}, - {0x18d, 0x00, 0x0}, - {0x18e, 0x39, 0x0}, - {0x18f, 0x39, 0x0}, - {0x190, 0x39, 0x0}, - {0x191, 0x11, 0x0}, - {0x192, 0x0E, 0x0}, - {0x193, 0x00, 0x0}, - {0x194, 0x00, 0x0}, - {0x195, 0x00, 0x0}, - {0x196, 0x7C, 0x0}, - {0x197, 0x00, 0x0}, - {0x198, 0x0B, 0x0}, - {0x199, 0x00, 0x0}, - {0x037, 0x3F, 0x0}, - }; - - snd_pmic_ops_fs.card_status = SND_CARD_INIT_DONE; - snd_pmic_ops_fs.master_mute = UNMUTE; - snd_pmic_ops_fs.mute_status = UNMUTE; - snd_pmic_ops_fs.num_channel = 2; - return sst_sc_reg_access(sc_access, PMIC_WRITE, 27); -} - -static int fs_enable_audiodac(int value) -{ - struct sc_reg_access sc_access[3]; - sc_access[0].reg_addr = AUD16; - sc_access[1].reg_addr = AUD17; - sc_access[2].reg_addr = AUD15; - sc_access[0].mask = sc_access[1].mask = sc_access[2].mask = MASK7; - - if (snd_pmic_ops_fs.mute_status == MUTE) - return 0; - if (value == MUTE) { - sc_access[0].value = sc_access[1].value = - sc_access[2].value = 0x80; - - } else { - sc_access[0].value = sc_access[1].value = - sc_access[2].value = 0x0; - } - if (snd_pmic_ops_fs.num_channel == 1) - sc_access[1].value = sc_access[2].value = 0x80; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); - -} - -static int fs_power_up_pb(unsigned int port) -{ - struct sc_reg_access sc_access[] = { - {AUDIOBIAS, 0x00, MASK7}, - {POWERCTRL1, 0xC6, 0xC6}, - {POWERCTRL2, 0x30, 0x30}, - - }; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - retval = fs_enable_audiodac(MUTE); - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); - - if (retval) - return retval; - - pr_debug("in fs power up pb\n"); - return fs_enable_audiodac(UNMUTE); -} - -static int fs_power_down_pb(unsigned int device) -{ - struct sc_reg_access sc_access[] = { - {POWERCTRL1, 0x00, 0xC6}, - {POWERCTRL2, 0x00, 0x30}, - }; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - retval = fs_enable_audiodac(MUTE); - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - - if (retval) - return retval; - - pr_debug("in fsl power down pb\n"); - return fs_enable_audiodac(UNMUTE); -} - -static int fs_power_up_cp(unsigned int port) -{ - struct sc_reg_access sc_access[] = { - {POWERCTRL2, 0x32, 0x32}, /*NOTE power up A ADC only as*/ - {AUDIOBIAS, 0x00, MASK7}, - /*as turning on V ADC causes noise*/ - }; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); -} - -static int fs_power_down_cp(unsigned int device) -{ - struct sc_reg_access sc_access[] = { - {POWERCTRL2, 0x00, 0x03}, - }; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); -} - -static int fs_power_down(void) -{ - int retval = 0; - struct sc_reg_access sc_access[] = { - {AUDIOBIAS, MASK7, MASK7}, - }; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); -} - -static int fs_set_pcm_voice_params(void) -{ - struct sc_reg_access sc_access[] = { - {0x180, 0xA0, 0}, - {0x181, 0x04, 0}, - {0x182, 0x0, 0}, - {0x183, 0x0, 0}, - {0x184, 0x18, 0}, - {0x185, 0x40, 0}, - {0x186, 0x06, 0}, - {0x187, 0x0, 0}, - {0x188, 0x10, 0}, - {0x189, 0x39, 0}, - {0x18a, 0x39, 0}, - {0x18b, 0x02, 0}, - {0x18c, 0x0, 0}, - {0x18d, 0x0, 0}, - {0x18e, 0x39, 0}, - {0x18f, 0x0, 0}, - {0x190, 0x0, 0}, - {0x191, 0x20, 0}, - {0x192, 0x20, 0}, - {0x193, 0x0, 0}, - {0x194, 0x0, 0}, - {0x195, 0x06, 0}, - {0x196, 0x25, 0}, - {0x197, 0x0, 0}, - {0x198, 0xF, 0}, - {0x199, 0x0, 0}, - }; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - return sst_sc_reg_access(sc_access, PMIC_WRITE, 26); -} - -static int fs_set_audio_port(int status) -{ - struct sc_reg_access sc_access[2]; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - if (status == DEACTIVATE) { - /* Deactivate audio port-tristate and power */ - sc_access[0].value = 0x00; - sc_access[0].mask = MASK6|MASK7; - sc_access[0].reg_addr = AUDIOPORT1; - sc_access[1].value = 0x00; - sc_access[1].mask = MASK4|MASK5; - sc_access[1].reg_addr = POWERCTRL2; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - } else if (status == ACTIVATE) { - /* activate audio port */ - sc_access[0].value = 0xC0; - sc_access[0].mask = MASK6|MASK7; - sc_access[0].reg_addr = AUDIOPORT1; - sc_access[1].value = 0x30; - sc_access[1].mask = MASK4|MASK5; - sc_access[1].reg_addr = POWERCTRL2; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - } else - return -EINVAL; -} - -static int fs_set_voice_port(int status) -{ - struct sc_reg_access sc_access[2]; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - if (status == DEACTIVATE) { - /* Deactivate audio port-tristate and power */ - sc_access[0].value = 0x00; - sc_access[0].mask = MASK6|MASK7; - sc_access[0].reg_addr = VOICEPORT1; - sc_access[1].value = 0x00; - sc_access[1].mask = MASK0|MASK1; - sc_access[1].reg_addr = POWERCTRL2; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - } else if (status == ACTIVATE) { - /* activate audio port */ - sc_access[0].value = 0xC0; - sc_access[0].mask = MASK6|MASK7; - sc_access[0].reg_addr = VOICEPORT1; - sc_access[1].value = 0x03; - sc_access[1].mask = MASK0|MASK1; - sc_access[1].reg_addr = POWERCTRL2; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - } else - return -EINVAL; -} - -static int fs_set_pcm_audio_params(int sfreq, int word_size, int num_channel) -{ - u8 config1 = 0; - struct sc_reg_access sc_access[4]; - int retval = 0, num_value = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - switch (sfreq) { - case 8000: - config1 = 0x00; - break; - case 11025: - config1 = 0x01; - break; - case 12000: - config1 = 0x02; - break; - case 16000: - config1 = 0x03; - break; - case 22050: - config1 = 0x04; - break; - case 24000: - config1 = 0x05; - break; - case 26000: - config1 = 0x06; - break; - case 32000: - config1 = 0x07; - break; - case 44100: - config1 = 0x08; - break; - case 48000: - config1 = 0x09; - break; - } - snd_pmic_ops_fs.num_channel = num_channel; - if (snd_pmic_ops_fs.num_channel == 1) { - sc_access[0].reg_addr = AUD17; - sc_access[1].reg_addr = AUD15; - sc_access[0].mask = sc_access[1].mask = MASK7; - sc_access[0].value = sc_access[1].value = 0x80; - sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - - } else { - sc_access[0].reg_addr = AUD17; - sc_access[1].reg_addr = AUD15; - sc_access[0].mask = sc_access[1].mask = MASK7; - sc_access[0].value = sc_access[1].value = 0x00; - sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - - } - pr_debug("sfreq:%d,Register value = %x\n", sfreq, config1); - - if (word_size == 24) { - sc_access[0].reg_addr = AUDIOPORT1; - sc_access[0].mask = MASK0|MASK1|MASK2|MASK3; - sc_access[0].value = 0xFB; - - - sc_access[1].reg_addr = AUDIOPORT2; - sc_access[1].value = config1 | 0x10; - sc_access[1].mask = MASK0 | MASK1 | MASK2 | MASK3 - | MASK4 | MASK5 | MASK6; - - sc_access[2].reg_addr = MISCAUDCTRL; - sc_access[2].value = 0x02; - sc_access[2].mask = 0x02; - - num_value = 3 ; - - } else { - - sc_access[0].reg_addr = AUDIOPORT2; - sc_access[0].value = config1; - sc_access[0].mask = MASK0|MASK1|MASK2|MASK3; - - sc_access[1].reg_addr = MISCAUDCTRL; - sc_access[1].value = 0x00; - sc_access[1].mask = 0x02; - num_value = 2; - } - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_value); - -} - -static int fs_set_selected_input_dev(u8 value) -{ - struct sc_reg_access sc_access_dmic[] = { - {MICCTRL, 0x81, 0xf7}, - {MICLICTRL3, 0x00, 0xE0}, - }; - struct sc_reg_access sc_access_mic[] = { - {MICCTRL, 0x40, MASK2|MASK4|MASK5|MASK6|MASK7}, - {MICLICTRL3, 0x00, 0xE0}, - }; - struct sc_reg_access sc_access_hsmic[] = { - {MICCTRL, 0x10, MASK2|MASK4|MASK5|MASK6|MASK7}, - {MICLICTRL3, 0x00, 0xE0}, - }; - - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - - switch (value) { - case AMIC: - pr_debug("Selecting amic not supported in mono cfg\n"); - return sst_sc_reg_access(sc_access_mic, PMIC_READ_MODIFY, 2); - break; - - case HS_MIC: - pr_debug("Selecting hsmic\n"); - return sst_sc_reg_access(sc_access_hsmic, - PMIC_READ_MODIFY, 2); - break; - - case DMIC: - pr_debug("Selecting dmic\n"); - return sst_sc_reg_access(sc_access_dmic, PMIC_READ_MODIFY, 2); - break; - - default: - return -EINVAL; - - } -} - -static int fs_set_selected_output_dev(u8 value) -{ - struct sc_reg_access sc_access_hp[] = { - {0x191, 0x11, 0x0}, - {0x192, 0x0E, 0x0}, - }; - struct sc_reg_access sc_access_is[] = { - {0x191, 0x17, 0xFF}, - {0x192, 0x08, 0xFF}, - }; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - - switch (value) { - case STEREO_HEADPHONE: - pr_debug("SST DBG:Selecting headphone\n"); - return sst_sc_reg_access(sc_access_hp, PMIC_WRITE, 2); - break; - case MONO_EARPIECE: - case INTERNAL_SPKR: - pr_debug("SST DBG:Selecting internal spkr\n"); - return sst_sc_reg_access(sc_access_is, PMIC_READ_MODIFY, 2); - break; - - default: - return -EINVAL; - - } -} - -static int fs_set_mute(int dev_id, u8 value) -{ - struct sc_reg_access sc_access[6] = {{0,},}; - int reg_num = 0; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - - - pr_debug("dev_id:0x%x value:0x%x\n", dev_id, value); - switch (dev_id) { - case PMIC_SND_DMIC_MUTE: - sc_access[0].reg_addr = MICCTRL; - sc_access[1].reg_addr = MICLICTRL1; - sc_access[2].reg_addr = MICLICTRL2; - sc_access[0].mask = MASK5; - sc_access[1].mask = sc_access[2].mask = MASK6; - if (value == MUTE) { - sc_access[0].value = 0x20; - sc_access[2].value = sc_access[1].value = 0x40; - } else - sc_access[0].value = sc_access[1].value - = sc_access[2].value = 0x0; - reg_num = 3; - break; - case PMIC_SND_HP_MIC_MUTE: - case PMIC_SND_AMIC_MUTE: - sc_access[0].reg_addr = MICLICTRL1; - sc_access[1].reg_addr = MICLICTRL2; - sc_access[0].mask = sc_access[1].mask = MASK6; - if (value == MUTE) - sc_access[0].value = sc_access[1].value = 0x40; - else - sc_access[0].value = sc_access[1].value = 0x0; - reg_num = 2; - break; - case PMIC_SND_LEFT_SPEAKER_MUTE: - case PMIC_SND_LEFT_HP_MUTE: - sc_access[0].reg_addr = AUD16; - sc_access[1].reg_addr = AUD15; - - sc_access[0].mask = sc_access[1].mask = MASK7; - if (value == MUTE) - sc_access[0].value = sc_access[1].value = 0x80; - else - sc_access[0].value = sc_access[1].value = 0x0; - reg_num = 2; - snd_pmic_ops_fs.mute_status = value; - break; - case PMIC_SND_RIGHT_HP_MUTE: - case PMIC_SND_RIGHT_SPEAKER_MUTE: - sc_access[0].reg_addr = AUD17; - sc_access[1].reg_addr = AUD15; - sc_access[0].mask = sc_access[1].mask = MASK7; - if (value == MUTE) - sc_access[0].value = sc_access[1].value = 0x80; - else - sc_access[0].value = sc_access[1].value = 0x0; - snd_pmic_ops_fs.mute_status = value; - if (snd_pmic_ops_fs.num_channel == 1) - sc_access[0].value = sc_access[1].value = 0x80; - reg_num = 2; - break; - case PMIC_SND_MUTE_ALL: - sc_access[0].reg_addr = AUD16; - sc_access[1].reg_addr = AUD17; - sc_access[2].reg_addr = AUD15; - sc_access[3].reg_addr = MICCTRL; - sc_access[4].reg_addr = MICLICTRL1; - sc_access[5].reg_addr = MICLICTRL2; - sc_access[0].mask = sc_access[1].mask = - sc_access[2].mask = MASK7; - sc_access[3].mask = MASK5; - sc_access[4].mask = sc_access[5].mask = MASK6; - - if (value == MUTE) { - sc_access[0].value = - sc_access[1].value = sc_access[2].value = 0x80; - sc_access[3].value = 0x20; - sc_access[4].value = sc_access[5].value = 0x40; - - } else { - sc_access[0].value = sc_access[1].value = - sc_access[2].value = sc_access[3].value = - sc_access[4].value = sc_access[5].value = 0x0; - } - if (snd_pmic_ops_fs.num_channel == 1) - sc_access[1].value = sc_access[2].value = 0x80; - reg_num = 6; - snd_pmic_ops_fs.mute_status = value; - snd_pmic_ops_fs.master_mute = value; - break; - - } - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, reg_num); -} - -static int fs_set_vol(int dev_id, int value) -{ - struct sc_reg_access sc_acces, sc_access[4] = {{0},}; - int reg_num = 0; - int retval = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - - switch (dev_id) { - case PMIC_SND_LEFT_PB_VOL: - pr_debug("PMIC_SND_LEFT_PB_VOL:%d\n", value); - sc_access[0].value = sc_access[1].value = value; - sc_access[0].reg_addr = AUD16; - sc_access[1].reg_addr = AUD15; - sc_access[0].mask = sc_access[1].mask = - (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); - reg_num = 2; - break; - - case PMIC_SND_RIGHT_PB_VOL: - pr_debug("PMIC_SND_RIGHT_PB_VOL:%d\n", value); - sc_access[0].value = sc_access[1].value = value; - sc_access[0].reg_addr = AUD17; - sc_access[1].reg_addr = AUD15; - sc_access[0].mask = sc_access[1].mask = - (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); - if (snd_pmic_ops_fs.num_channel == 1) { - sc_access[0].value = sc_access[1].value = 0x80; - sc_access[0].mask = sc_access[1].mask = MASK7; - } - reg_num = 2; - break; - case PMIC_SND_CAPTURE_VOL: - pr_debug("PMIC_SND_CAPTURE_VOL:%d\n", value); - sc_access[0].reg_addr = MICLICTRL1; - sc_access[1].reg_addr = MICLICTRL2; - sc_access[2].reg_addr = DMICCTRL1; - sc_access[2].value = value; - sc_access[0].value = sc_access[1].value = value; - sc_acces.reg_addr = MICLICTRL3; - sc_acces.value = value; - sc_acces.mask = (MASK0|MASK1|MASK2|MASK3|MASK5|MASK6|MASK7); - retval = sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1); - sc_access[0].mask = sc_access[1].mask = - sc_access[2].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); - reg_num = 3; - break; - - default: - return -EINVAL; - } - - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, reg_num); -} - -static int fs_get_mute(int dev_id, u8 *value) -{ - struct sc_reg_access sc_access[6] = {{0,},}; - - int retval = 0, temp_value = 0, mask = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - - switch (dev_id) { - - case PMIC_SND_AMIC_MUTE: - case PMIC_SND_HP_MIC_MUTE: - sc_access[0].reg_addr = MICLICTRL1; - mask = MASK6; - retval = sst_sc_reg_access(sc_access, PMIC_READ, 1); - if (sc_access[0].value & mask) - *value = MUTE; - else - *value = UNMUTE; - break; - case PMIC_SND_DMIC_MUTE: - sc_access[0].reg_addr = MICCTRL; - mask = MASK5; - retval = sst_sc_reg_access(sc_access, PMIC_READ, 1); - temp_value = (sc_access[0].value & mask); - if (temp_value == 0) - *value = UNMUTE; - else - *value = MUTE; - break; - - case PMIC_SND_LEFT_HP_MUTE: - case PMIC_SND_LEFT_SPEAKER_MUTE: - sc_access[0].reg_addr = AUD16; - mask = MASK7; - retval = sst_sc_reg_access(sc_access, PMIC_READ, 1); - temp_value = sc_access[0].value & mask; - if (temp_value == 0) - *value = UNMUTE; - else - *value = MUTE; - break; - case PMIC_SND_RIGHT_HP_MUTE: - case PMIC_SND_RIGHT_SPEAKER_MUTE: - sc_access[0].reg_addr = AUD17; - mask = MASK7; - retval = sst_sc_reg_access(sc_access, PMIC_READ, 1); - temp_value = sc_access[0].value & mask; - if (temp_value == 0) - *value = UNMUTE; - else - *value = MUTE; - break; - default: - return -EINVAL; - } - - return retval; -} - -static int fs_get_vol(int dev_id, int *value) -{ - struct sc_reg_access sc_access = {0,}; - int retval = 0, mask = 0; - - if (snd_pmic_ops_fs.card_status == SND_CARD_UN_INIT) - retval = fs_init_card(); - if (retval) - return retval; - - switch (dev_id) { - case PMIC_SND_CAPTURE_VOL: - pr_debug("PMIC_SND_CAPTURE_VOL\n"); - sc_access.reg_addr = MICLICTRL1; - mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0); - break; - case PMIC_SND_LEFT_PB_VOL: - pr_debug("PMIC_SND_LEFT_PB_VOL\n"); - sc_access.reg_addr = AUD16; - mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0); - break; - case PMIC_SND_RIGHT_PB_VOL: - pr_debug("PMIC_SND_RT_PB_VOL\n"); - sc_access.reg_addr = AUD17; - mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0); - break; - default: - return -EINVAL; - } - - retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - pr_debug("value read = 0x%x\n", sc_access.value); - *value = (int) (sc_access.value & mask); - pr_debug("value returned = 0x%x\n", *value); - return retval; -} - -static void fs_pmic_irq_enable(void *data) -{ - struct snd_intelmad *intelmaddata = data; - struct sc_reg_access sc_access[] = { - {0x187, 0x00, MASK7}, - {0x188, 0x10, MASK4}, - {0x18b, 0x10, MASK4}, - }; - - struct sc_reg_access sc_access_write[] = { - {0x198, 0x00, 0x0}, - }; - pr_debug("Audio interrupt enable\n"); - sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); - sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1); - - intelmaddata->jack[0].jack_status = 0; - /*intelmaddata->jack[1].jack_status = 0;*/ - - jack_det_enabled = true; - return; -} - -static void fs_pmic_irq_cb(void *cb_data, u8 value) -{ - struct mad_jack *mjack = NULL; - struct snd_intelmad *intelmaddata = cb_data; - unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; - - mjack = &intelmaddata->jack[0]; - - if (value & 0x4) { - if (!jack_det_enabled) - fs_pmic_irq_enable(intelmaddata); - - /* send headphone detect */ - pr_debug(":MAD headphone %d\n", value & 0x4); - present = !(mjack->jack_status); - mjack->jack_status = present; - jack_event_flag = 1; - mjack->jack.type = SND_JACK_HEADPHONE; - } - - if (value & 0x2) { - /* send short push */ - pr_debug(":MAD short push %d\n", value & 0x2); - present = 1; - jack_event_flag = 1; - buttonpressflag = 1; - mjack->jack.type = MID_JACK_HS_SHORT_PRESS; - } - - if (value & 0x1) { - /* send long push */ - pr_debug(":MAD long push %d\n", value & 0x1); - present = 1; - jack_event_flag = 1; - buttonpressflag = 1; - mjack->jack.type = MID_JACK_HS_LONG_PRESS; - } - - if (value & 0x8) { - if (!jack_det_enabled) - fs_pmic_irq_enable(intelmaddata); - /* send headset detect */ - pr_debug(":MAD headset = %d\n", value & 0x8); - present = !(mjack->jack_status); - mjack->jack_status = present; - jack_event_flag = 1; - mjack->jack.type = SND_JACK_HEADSET; - } - - - if (jack_event_flag) - sst_mad_send_jack_report(&mjack->jack, - buttonpressflag, present); - - return; -} -static int fs_jack_enable(void) -{ - return 0; -} - -struct snd_pmic_ops snd_pmic_ops_fs = { - .set_input_dev = fs_set_selected_input_dev, - .set_output_dev = fs_set_selected_output_dev, - .set_mute = fs_set_mute, - .get_mute = fs_get_mute, - .set_vol = fs_set_vol, - .get_vol = fs_get_vol, - .init_card = fs_init_card, - .set_pcm_audio_params = fs_set_pcm_audio_params, - .set_pcm_voice_params = fs_set_pcm_voice_params, - .set_voice_port = fs_set_voice_port, - .set_audio_port = fs_set_audio_port, - .power_up_pmic_pb = fs_power_up_pb, - .power_up_pmic_cp = fs_power_up_cp, - .power_down_pmic_pb = fs_power_down_pb, - .power_down_pmic_cp = fs_power_down_cp, - .power_down_pmic = fs_power_down, - .pmic_irq_cb = fs_pmic_irq_cb, - /* - * Jack detection enabling - * need be delayed till first IRQ happen. - */ - .pmic_irq_enable = NULL, - .pmic_jack_enable = fs_jack_enable, -}; diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c deleted file mode 100644 index 9d00728d8de..00000000000 --- a/drivers/staging/intel_sst/intelmid_v1_control.c +++ /dev/null @@ -1,978 +0,0 @@ -/* intel_sst_v1_control.c - Intel SST Driver for audio engine - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file contains the control operations of vendor 2 - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/file.h> -#include <asm/mrst.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/control.h> -#include <sound/initval.h> -#include "intel_sst.h" -#include "intel_sst_ioctl.h" -#include "intelmid.h" -#include "intelmid_snd_control.h" - -#include <linux/gpio.h> -#define KOSKI_VOICE_CODEC_ENABLE 46 - -enum _reg_v2 { - - MASTER_CLOCK_PRESCALAR = 0x205, - SET_MASTER_AND_LR_CLK1 = 0x20b, - SET_MASTER_AND_LR_CLK2 = 0x20c, - MASTER_MODE_AND_DATA_DELAY = 0x20d, - DIGITAL_INTERFACE_TO_DAI2 = 0x20e, - CLK_AND_FS1 = 0x208, - CLK_AND_FS2 = 0x209, - DAI2_TO_DAC_HP = 0x210, - HP_OP_SINGLE_ENDED = 0x224, - ENABLE_OPDEV_CTRL = 0x226, - ENABLE_DEV_AND_USE_XTAL = 0x227, - - /* Max audio subsystem (PQ49) MAX 8921 */ - AS_IP_MODE_CTL = 0xF9, - AS_LEFT_SPKR_VOL_CTL = 0xFA, /* Mono Earpiece volume control */ - AS_RIGHT_SPKR_VOL_CTL = 0xFB, - AS_LEFT_HP_VOL_CTL = 0xFC, - AS_RIGHT_HP_VOL_CTL = 0xFD, - AS_OP_MIX_CTL = 0xFE, - AS_CONFIG = 0xFF, - - /* Headphone volume control & mute registers */ - VOL_CTRL_LT = 0x21c, - VOL_CTRL_RT = 0x21d, - -}; -/** - * mx_init_card - initialize the sound card - * - * This initializes the audio paths to know values in case of this sound card - */ -static int mx_init_card(void) -{ - struct sc_reg_access sc_access[] = { - {0x200, 0x80, 0x00}, - {0x201, 0xC0, 0x00}, - {0x202, 0x00, 0x00}, - {0x203, 0x00, 0x00}, - {0x204, 0x02, 0x00}, - {0x205, 0x10, 0x00}, - {0x206, 0x60, 0x00}, - {0x207, 0x00, 0x00}, - {0x208, 0x90, 0x00}, - {0x209, 0x51, 0x00}, - {0x20a, 0x00, 0x00}, - {0x20b, 0x10, 0x00}, - {0x20c, 0x00, 0x00}, - {0x20d, 0x00, 0x00}, - {0x20e, 0x21, 0x00}, - {0x20f, 0x00, 0x00}, - {0x210, 0x84, 0x00}, - {0x211, 0xB3, 0x00}, - {0x212, 0x00, 0x00}, - {0x213, 0x00, 0x00}, - {0x214, 0x41, 0x00}, - {0x215, 0x00, 0x00}, - {0x216, 0x00, 0x00}, - {0x217, 0x00, 0x00}, - {0x218, 0x03, 0x00}, - {0x219, 0x03, 0x00}, - {0x21a, 0x00, 0x00}, - {0x21b, 0x00, 0x00}, - {0x21c, 0x00, 0x00}, - {0x21d, 0x00, 0x00}, - {0x21e, 0x00, 0x00}, - {0x21f, 0x00, 0x00}, - {0x220, 0x20, 0x00}, - {0x221, 0x20, 0x00}, - {0x222, 0x51, 0x00}, - {0x223, 0x20, 0x00}, - {0x224, 0x04, 0x00}, - {0x225, 0x80, 0x00}, - {0x226, 0x0F, 0x00}, - {0x227, 0x08, 0x00}, - {0xf9, 0x40, 0x00}, - {0xfa, 0x1f, 0x00}, - {0xfb, 0x1f, 0x00}, - {0xfc, 0x1f, 0x00}, - {0xfd, 0x1f, 0x00}, - {0xfe, 0x00, 0x00}, - {0xff, 0x0c, 0x00}, - }; - snd_pmic_ops_mx.card_status = SND_CARD_INIT_DONE; - snd_pmic_ops_mx.num_channel = 2; - snd_pmic_ops_mx.master_mute = UNMUTE; - snd_pmic_ops_mx.mute_status = UNMUTE; - return sst_sc_reg_access(sc_access, PMIC_WRITE, 47); -} - -static int mx_enable_audiodac(int value) -{ - struct sc_reg_access sc_access[3]; - int mute_val = 0; - int mute_val1 = 0; - int retval = 0; - - sc_access[0].reg_addr = AS_LEFT_HP_VOL_CTL; - sc_access[1].reg_addr = AS_RIGHT_HP_VOL_CTL; - - if (value == UNMUTE) { - mute_val = 0x1F; - mute_val1 = 0x00; - } else { - mute_val = 0x00; - mute_val1 = 0x40; - } - sc_access[0].mask = sc_access[1].mask = MASK0|MASK1|MASK2|MASK3|MASK4; - sc_access[0].value = sc_access[1].value = (u8)mute_val; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - if (retval) - return retval; - pr_debug("mute status = %d\n", snd_pmic_ops_mx.mute_status); - if (snd_pmic_ops_mx.mute_status == MUTE || - snd_pmic_ops_mx.master_mute == MUTE) - return retval; - - sc_access[0].reg_addr = VOL_CTRL_LT; - sc_access[1].reg_addr = VOL_CTRL_RT; - sc_access[0].mask = sc_access[1].mask = MASK6; - sc_access[0].value = sc_access[1].value = mute_val1; - if (snd_pmic_ops_mx.num_channel == 1) - sc_access[1].value = 0x40; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); -} - -static int mx_power_up_pb(unsigned int port) -{ - - int retval = 0; - struct sc_reg_access sc_access[3]; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - retval = mx_enable_audiodac(MUTE); - if (retval) - return retval; - - msleep(10); - - sc_access[0].reg_addr = AS_CONFIG; - sc_access[0].mask = MASK7; - sc_access[0].value = 0x80; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - - sc_access[0].reg_addr = ENABLE_OPDEV_CTRL; - sc_access[0].mask = 0xff; - sc_access[0].value = 0x3C; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - - sc_access[0].reg_addr = ENABLE_DEV_AND_USE_XTAL; - sc_access[0].mask = 0x80; - sc_access[0].value = 0x80; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - - return mx_enable_audiodac(UNMUTE); -} - -static int mx_power_down_pb(unsigned int device) -{ - struct sc_reg_access sc_access[3]; - int retval = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - - retval = mx_enable_audiodac(MUTE); - if (retval) - return retval; - - sc_access[0].reg_addr = ENABLE_OPDEV_CTRL; - sc_access[0].mask = MASK3|MASK2; - sc_access[0].value = 0x00; - - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - - return mx_enable_audiodac(UNMUTE); -} - -static int mx_power_up_cp(unsigned int port) -{ - int retval = 0; - struct sc_reg_access sc_access[] = { - {ENABLE_DEV_AND_USE_XTAL, 0x80, MASK7}, - {ENABLE_OPDEV_CTRL, 0x3, 0x3}, - }; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); -} - -static int mx_power_down_cp(unsigned int device) -{ - struct sc_reg_access sc_access[] = { - {ENABLE_OPDEV_CTRL, 0x00, MASK1|MASK0}, - }; - int retval = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); -} - -static int mx_power_down(void) -{ - int retval = 0; - struct sc_reg_access sc_access[3]; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - - retval = mx_enable_audiodac(MUTE); - if (retval) - return retval; - - sc_access[0].reg_addr = AS_CONFIG; - sc_access[0].mask = MASK7; - sc_access[0].value = 0x00; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - - sc_access[0].reg_addr = ENABLE_DEV_AND_USE_XTAL; - sc_access[0].mask = MASK7; - sc_access[0].value = 0x00; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - - sc_access[0].reg_addr = ENABLE_OPDEV_CTRL; - sc_access[0].mask = MASK3|MASK2; - sc_access[0].value = 0x00; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - if (retval) - return retval; - - return mx_enable_audiodac(UNMUTE); -} - -static int mx_set_pcm_voice_params(void) -{ - int retval = 0; - struct sc_reg_access sc_access[] = { - {0x200, 0x80, 0x00}, - {0x201, 0xC0, 0x00}, - {0x202, 0x00, 0x00}, - {0x203, 0x00, 0x00}, - {0x204, 0x0e, 0x00}, - {0x205, 0x20, 0x00}, - {0x206, 0x8f, 0x00}, - {0x207, 0x21, 0x00}, - {0x208, 0x18, 0x00}, - {0x209, 0x32, 0x00}, - {0x20a, 0x00, 0x00}, - {0x20b, 0x5A, 0x00}, - {0x20c, 0xBE, 0x00},/* 0x00 -> 0xBE Koski */ - {0x20d, 0x00, 0x00}, /* DAI2 'off' */ - {0x20e, 0x40, 0x00}, - {0x20f, 0x00, 0x00}, - {0x210, 0x84, 0x00}, - {0x211, 0x33, 0x00}, /* Voice filter */ - {0x212, 0x00, 0x00}, - {0x213, 0x00, 0x00}, - {0x214, 0x41, 0x00}, - {0x215, 0x00, 0x00}, - {0x216, 0x00, 0x00}, - {0x217, 0x20, 0x00}, - {0x218, 0x00, 0x00}, - {0x219, 0x00, 0x00}, - {0x21a, 0x40, 0x00}, - {0x21b, 0x40, 0x00}, - {0x21c, 0x09, 0x00}, - {0x21d, 0x09, 0x00}, - {0x21e, 0x00, 0x00}, - {0x21f, 0x00, 0x00}, - {0x220, 0x00, 0x00}, /* Microphone configurations */ - {0x221, 0x00, 0x00}, /* Microphone configurations */ - {0x222, 0x50, 0x00}, /* Microphone configurations */ - {0x223, 0x21, 0x00}, /* Microphone configurations */ - {0x224, 0x00, 0x00}, - {0x225, 0x80, 0x00}, - {0xf9, 0x40, 0x00}, - {0xfa, 0x19, 0x00}, - {0xfb, 0x19, 0x00}, - {0xfc, 0x12, 0x00}, - {0xfd, 0x12, 0x00}, - {0xfe, 0x00, 0x00}, - }; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - pr_debug("SST DBG:mx_set_pcm_voice_params called\n"); - return sst_sc_reg_access(sc_access, PMIC_WRITE, 44); -} - -static int mx_set_pcm_audio_params(int sfreq, int word_size, int num_channel) -{ - int retval = 0; - - int config1 = 0, config2 = 0, filter = 0xB3; - struct sc_reg_access sc_access[5]; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - - switch (sfreq) { - case 8000: - config1 = 0x10; - config2 = 0x00; - filter = 0x33; - break; - case 11025: - config1 = 0x16; - config2 = 0x0d; - break; - case 12000: - config1 = 0x18; - config2 = 0x00; - break; - case 16000: - config1 = 0x20; - config2 = 0x00; - break; - case 22050: - config1 = 0x2c; - config2 = 0x1a; - break; - case 24000: - config1 = 0x30; - config2 = 0x00; - break; - case 32000: - config1 = 0x40; - config2 = 0x00; - break; - case 44100: - config1 = 0x58; - config2 = 0x33; - break; - case 48000: - config1 = 0x60; - config2 = 0x00; - break; - } - snd_pmic_ops_mx.num_channel = num_channel; - /*mute the right channel if MONO*/ - if (snd_pmic_ops_mx.num_channel == 1) { - sc_access[0].reg_addr = VOL_CTRL_RT; - sc_access[0].value = 0x40; - sc_access[0].mask = MASK6; - - sc_access[1].reg_addr = 0x224; - sc_access[1].value = 0x05; - sc_access[1].mask = MASK0|MASK1|MASK2; - - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - if (retval) - return retval; - } else { - sc_access[0].reg_addr = VOL_CTRL_RT; - sc_access[0].value = 0x00; - sc_access[0].mask = MASK6; - - sc_access[1].reg_addr = 0x224; - sc_access[1].value = 0x04; - sc_access[1].mask = MASK0|MASK1|MASK2; - - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - if (retval) - return retval; - } - sc_access[0].reg_addr = 0x206; - sc_access[0].value = config1; - sc_access[1].reg_addr = 0x207; - sc_access[1].value = config2; - - if (word_size == 16) { - sc_access[2].value = 0x51; - sc_access[3].value = 0x31; - } else if (word_size == 24) { - sc_access[2].value = 0x52; - sc_access[3].value = 0x92; - } - - sc_access[2].reg_addr = 0x209; - sc_access[3].reg_addr = 0x20e; - - sc_access[4].reg_addr = 0x211; - sc_access[4].value = filter; - - return sst_sc_reg_access(sc_access, PMIC_WRITE, 5); -} - -static int mx_set_selected_output_dev(u8 dev_id) -{ - struct sc_reg_access sc_access[2]; - int num_reg = 0; - int retval = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - - pr_debug("mx_set_selected_output_dev dev_id:0x%x\n", dev_id); - snd_pmic_ops_mx.output_dev_id = dev_id; - switch (dev_id) { - case STEREO_HEADPHONE: - sc_access[0].reg_addr = 0xFF; - sc_access[0].value = 0x8C; - sc_access[0].mask = - MASK2|MASK3|MASK5|MASK6|MASK4; - - num_reg = 1; - break; - case MONO_EARPIECE: - case INTERNAL_SPKR: - sc_access[0].reg_addr = 0xFF; - sc_access[0].value = 0xb0; - sc_access[0].mask = MASK2|MASK3|MASK5|MASK6|MASK4; - - num_reg = 1; - break; - case RECEIVER: - pr_debug("RECEIVER Koski selected\n"); - - /* configuration - AS enable, receiver enable */ - sc_access[0].reg_addr = 0xFF; - sc_access[0].value = 0x81; - sc_access[0].mask = 0xff; - - num_reg = 1; - break; - default: - pr_err("Not a valid output dev\n"); - return 0; - } - return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg); -} - - -static int mx_set_voice_port(int status) -{ - int retval = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - if (status == ACTIVATE) - retval = mx_set_pcm_voice_params(); - - return retval; -} - -static int mx_set_audio_port(int status) -{ - return 0; -} - -static int mx_set_selected_input_dev(u8 dev_id) -{ - struct sc_reg_access sc_access[2]; - int num_reg = 0; - int retval = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - snd_pmic_ops_mx.input_dev_id = dev_id; - pr_debug("mx_set_selected_input_dev dev_id:0x%x\n", dev_id); - - switch (dev_id) { - case AMIC: - sc_access[0].reg_addr = 0x223; - sc_access[0].value = 0x00; - sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0; - sc_access[1].reg_addr = 0x222; - sc_access[1].value = 0x50; - sc_access[1].mask = MASK7|MASK6|MASK5|MASK4; - num_reg = 2; - break; - - case HS_MIC: - sc_access[0].reg_addr = 0x223; - sc_access[0].value = 0x20; - sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0; - sc_access[1].reg_addr = 0x222; - sc_access[1].value = 0x51; - sc_access[1].mask = MASK7|MASK6|MASK5|MASK4; - num_reg = 2; - break; - case DMIC: - sc_access[1].reg_addr = 0x222; - sc_access[1].value = 0x00; - sc_access[1].mask = MASK7|MASK6|MASK5|MASK4|MASK0; - sc_access[0].reg_addr = 0x223; - sc_access[0].value = 0x20; - sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0; - num_reg = 2; - break; - } - return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg); -} - -static int mx_set_mute(int dev_id, u8 value) -{ - struct sc_reg_access sc_access[5]; - int num_reg = 0; - int retval = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - - - pr_debug("set_mute dev_id:0x%x , value:%d\n", dev_id, value); - - switch (dev_id) { - case PMIC_SND_DMIC_MUTE: - case PMIC_SND_AMIC_MUTE: - case PMIC_SND_HP_MIC_MUTE: - sc_access[0].reg_addr = 0x220; - sc_access[1].reg_addr = 0x221; - sc_access[2].reg_addr = 0x223; - if (value == MUTE) { - sc_access[0].value = 0x00; - sc_access[1].value = 0x00; - if (snd_pmic_ops_mx.input_dev_id == DMIC) - sc_access[2].value = 0x00; - else - sc_access[2].value = 0x20; - } else { - sc_access[0].value = 0x20; - sc_access[1].value = 0x20; - if (snd_pmic_ops_mx.input_dev_id == DMIC) - sc_access[2].value = 0x20; - else - sc_access[2].value = 0x00; - } - sc_access[0].mask = MASK5|MASK6; - sc_access[1].mask = MASK5|MASK6; - sc_access[2].mask = MASK5|MASK6; - num_reg = 3; - break; - case PMIC_SND_LEFT_SPEAKER_MUTE: - case PMIC_SND_LEFT_HP_MUTE: - sc_access[0].reg_addr = VOL_CTRL_LT; - if (value == MUTE) - sc_access[0].value = 0x40; - else - sc_access[0].value = 0x00; - sc_access[0].mask = MASK6; - num_reg = 1; - snd_pmic_ops_mx.mute_status = value; - break; - case PMIC_SND_RIGHT_SPEAKER_MUTE: - case PMIC_SND_RIGHT_HP_MUTE: - sc_access[0].reg_addr = VOL_CTRL_RT; - if (snd_pmic_ops_mx.num_channel == 1) - value = MUTE; - if (value == MUTE) - sc_access[0].value = 0x40; - else - sc_access[0].value = 0x00; - sc_access[0].mask = MASK6; - num_reg = 1; - snd_pmic_ops_mx.mute_status = value; - break; - case PMIC_SND_MUTE_ALL: - sc_access[0].reg_addr = VOL_CTRL_RT; - sc_access[1].reg_addr = VOL_CTRL_LT; - sc_access[2].reg_addr = 0x220; - sc_access[3].reg_addr = 0x221; - sc_access[4].reg_addr = 0x223; - snd_pmic_ops_mx.master_mute = value; - if (value == MUTE) { - sc_access[0].value = sc_access[1].value = 0x40; - sc_access[2].value = 0x00; - sc_access[3].value = 0x00; - if (snd_pmic_ops_mx.input_dev_id == DMIC) - sc_access[4].value = 0x00; - else - sc_access[4].value = 0x20; - - } else { - sc_access[0].value = sc_access[1].value = 0x00; - sc_access[2].value = sc_access[3].value = 0x20; - sc_access[4].value = 0x20; - if (snd_pmic_ops_mx.input_dev_id == DMIC) - sc_access[4].value = 0x20; - else - sc_access[4].value = 0x00; - - - } - if (snd_pmic_ops_mx.num_channel == 1) - sc_access[0].value = 0x40; - sc_access[0].mask = sc_access[1].mask = MASK6; - sc_access[2].mask = MASK5|MASK6; - sc_access[3].mask = MASK5|MASK6|MASK2|MASK4; - sc_access[4].mask = MASK5|MASK6|MASK4; - - num_reg = 5; - break; - case PMIC_SND_RECEIVER_MUTE: - sc_access[0].reg_addr = VOL_CTRL_RT; - if (value == MUTE) - sc_access[0].value = 0x40; - else - sc_access[0].value = 0x00; - sc_access[0].mask = MASK6; - num_reg = 1; - break; - } - - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_reg); -} - -static int mx_set_vol(int dev_id, int value) -{ - struct sc_reg_access sc_access[2] = {{0},}; - int num_reg = 0; - int retval = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - pr_debug("set_vol dev_id:0x%x ,value:%d\n", dev_id, value); - switch (dev_id) { - case PMIC_SND_RECEIVER_VOL: - return 0; - break; - case PMIC_SND_CAPTURE_VOL: - sc_access[0].reg_addr = 0x220; - sc_access[1].reg_addr = 0x221; - sc_access[0].value = sc_access[1].value = -value; - sc_access[0].mask = sc_access[1].mask = - (MASK0|MASK1|MASK2|MASK3|MASK4); - num_reg = 2; - break; - case PMIC_SND_LEFT_PB_VOL: - sc_access[0].value = -value; - sc_access[0].reg_addr = VOL_CTRL_LT; - sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); - num_reg = 1; - break; - case PMIC_SND_RIGHT_PB_VOL: - sc_access[0].value = -value; - sc_access[0].reg_addr = VOL_CTRL_RT; - sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); - if (snd_pmic_ops_mx.num_channel == 1) { - sc_access[0].value = 0x40; - sc_access[0].mask = MASK6; - sc_access[0].reg_addr = VOL_CTRL_RT; - } - num_reg = 1; - break; - } - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_reg); -} - -static int mx_get_mute(int dev_id, u8 *value) -{ - struct sc_reg_access sc_access[4] = {{0},}; - int retval = 0, num_reg = 0, mask = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - switch (dev_id) { - case PMIC_SND_DMIC_MUTE: - case PMIC_SND_AMIC_MUTE: - case PMIC_SND_HP_MIC_MUTE: - sc_access[0].reg_addr = 0x220; - mask = MASK5|MASK6; - num_reg = 1; - retval = sst_sc_reg_access(sc_access, PMIC_READ, num_reg); - if (retval) - return retval; - *value = sc_access[0].value & mask; - if (*value) - *value = UNMUTE; - else - *value = MUTE; - return retval; - case PMIC_SND_LEFT_HP_MUTE: - case PMIC_SND_LEFT_SPEAKER_MUTE: - sc_access[0].reg_addr = VOL_CTRL_LT; - num_reg = 1; - mask = MASK6; - break; - case PMIC_SND_RIGHT_HP_MUTE: - case PMIC_SND_RIGHT_SPEAKER_MUTE: - sc_access[0].reg_addr = VOL_CTRL_RT; - num_reg = 1; - mask = MASK6; - break; - } - retval = sst_sc_reg_access(sc_access, PMIC_READ, num_reg); - if (retval) - return retval; - *value = sc_access[0].value & mask; - if (*value) - *value = MUTE; - else - *value = UNMUTE; - return retval; -} - -static int mx_get_vol(int dev_id, int *value) -{ - struct sc_reg_access sc_access = {0,}; - int retval = 0, mask = 0, num_reg = 0; - - if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { - retval = mx_init_card(); - if (retval) - return retval; - } - switch (dev_id) { - case PMIC_SND_CAPTURE_VOL: - sc_access.reg_addr = 0x220; - mask = MASK0|MASK1|MASK2|MASK3|MASK4; - num_reg = 1; - break; - case PMIC_SND_LEFT_PB_VOL: - sc_access.reg_addr = VOL_CTRL_LT; - mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5; - num_reg = 1; - break; - case PMIC_SND_RIGHT_PB_VOL: - sc_access.reg_addr = VOL_CTRL_RT; - mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5; - num_reg = 1; - break; - } - retval = sst_sc_reg_access(&sc_access, PMIC_READ, num_reg); - if (retval) - return retval; - *value = -(sc_access.value & mask); - pr_debug("get volume value extracted %d\n", *value); - return retval; -} - -static u8 mx_get_jack_status(void) -{ - struct sc_reg_access sc_access_read = {0,}; - - sc_access_read.reg_addr = 0x201; - sst_sc_reg_access(&sc_access_read, PMIC_READ, 1); - pr_debug("value returned = 0x%x\n", sc_access_read.value); - return sc_access_read.value; -} - -static void mx_pmic_irq_enable(void *data) -{ - struct snd_intelmad *intelmaddata = data; - - intelmaddata->jack_prev_state = 0xc0; - return; -} - -static void mx_pmic_irq_cb(void *cb_data, u8 intsts) -{ - u8 jack_cur_status, jack_prev_state = 0; - struct mad_jack *mjack = NULL; - unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; - time_t timediff; - struct snd_intelmad *intelmaddata = cb_data; - - mjack = &intelmaddata->jack[0]; - if (intsts & 0x2) { - jack_cur_status = mx_get_jack_status(); - jack_prev_state = intelmaddata->jack_prev_state; - if ((jack_prev_state == 0xc0) && (jack_cur_status == 0x40)) { - /*headset insert detected. */ - pr_debug("MAD headset inserted\n"); - present = 1; - jack_event_flag = 1; - mjack->jack_status = 1; - mjack->jack.type = SND_JACK_HEADSET; - } - - if ((jack_prev_state == 0xc0) && (jack_cur_status == 0x00)) { - /* headphone insert detected. */ - pr_debug("MAD headphone inserted\n"); - present = 1; - jack_event_flag = 1; - mjack->jack.type = SND_JACK_HEADPHONE; - } - - if ((jack_prev_state == 0x40) && (jack_cur_status == 0xc0)) { - /* headset remove detected. */ - pr_debug("MAD headset removed\n"); - - present = 0; - jack_event_flag = 1; - mjack->jack_status = 0; - mjack->jack.type = SND_JACK_HEADSET; - } - - if ((jack_prev_state == 0x00) && (jack_cur_status == 0xc0)) { - /* headphone remove detected. */ - pr_debug("MAD headphone removed\n"); - present = 0; - jack_event_flag = 1; - mjack->jack.type = SND_JACK_HEADPHONE; - } - - if ((jack_prev_state == 0x40) && (jack_cur_status == 0x00)) { - /* button pressed */ - do_gettimeofday(&mjack->buttonpressed); - pr_debug("MAD button press detected\n"); - } - - if ((jack_prev_state == 0x00) && (jack_cur_status == 0x40)) { - if (mjack->jack_status) { - /*button pressed */ - do_gettimeofday( - &mjack->buttonreleased); - /*button pressed */ - pr_debug("MAD Button Released detected\n"); - timediff = mjack->buttonreleased.tv_sec - - mjack->buttonpressed.tv_sec; - buttonpressflag = 1; - - if (timediff > 1) { - pr_debug("MAD long press dtd\n"); - /* send headphone detect/undetect */ - present = 1; - jack_event_flag = 1; - mjack->jack.type = - MID_JACK_HS_LONG_PRESS; - } else { - pr_debug("MAD short press dtd\n"); - /* send headphone detect/undetect */ - present = 1; - jack_event_flag = 1; - mjack->jack.type = - MID_JACK_HS_SHORT_PRESS; - } - } else { - /***workaround for maxim - hw issue,0x00 t 0x40 is not - a valid transiton for Headset insertion */ - /*headset insert detected. */ - pr_debug("MAD headset inserted\n"); - present = 1; - jack_event_flag = 1; - mjack->jack_status = 1; - mjack->jack.type = SND_JACK_HEADSET; - } - } - intelmaddata->jack_prev_state = jack_cur_status; - pr_debug("mx_pmic_irq_cb prv_state= 0x%x\n", - intelmaddata->jack_prev_state); - } - - if (jack_event_flag) - sst_mad_send_jack_report(&mjack->jack, - buttonpressflag, present); -} -static int mx_jack_enable(void) -{ - return 0; -} - -struct snd_pmic_ops snd_pmic_ops_mx = { - .set_input_dev = mx_set_selected_input_dev, - .set_output_dev = mx_set_selected_output_dev, - .set_mute = mx_set_mute, - .get_mute = mx_get_mute, - .set_vol = mx_set_vol, - .get_vol = mx_get_vol, - .init_card = mx_init_card, - .set_pcm_audio_params = mx_set_pcm_audio_params, - .set_pcm_voice_params = mx_set_pcm_voice_params, - .set_voice_port = mx_set_voice_port, - .set_audio_port = mx_set_audio_port, - .power_up_pmic_pb = mx_power_up_pb, - .power_up_pmic_cp = mx_power_up_cp, - .power_down_pmic_pb = mx_power_down_pb, - .power_down_pmic_cp = mx_power_down_cp, - .power_down_pmic = mx_power_down, - .pmic_irq_cb = mx_pmic_irq_cb, - .pmic_irq_enable = mx_pmic_irq_enable, - .pmic_jack_enable = mx_jack_enable, -}; - diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c deleted file mode 100644 index 46ab55eb809..00000000000 --- a/drivers/staging/intel_sst/intelmid_v2_control.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * intelmid_v2_control.c - Intel Sound card driver for MID - * - * Copyright (C) 2008-10 Intel Corp - * Authors: Vinod Koul <vinod.koul@intel.com> - * Harsha Priya <priya.harsha@intel.com> - * KP Jeeja <jeeja.kp@intel.com> - * Dharageswari R <dharageswari.r@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This file contains the control operations of vendor 3 - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/gpio.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/file.h> -#include <sound/control.h> -#include "intel_sst.h" -#include "intelmid_snd_control.h" -#include "intelmid.h" - -enum reg_v3 { - VAUDIOCNT = 0x51, - VOICEPORT1 = 0x100, - VOICEPORT2 = 0x101, - AUDIOPORT1 = 0x102, - AUDIOPORT2 = 0x103, - ADCSAMPLERATE = 0x104, - DMICCTRL1 = 0x105, - DMICCTRL2 = 0x106, - MICCTRL = 0x107, - MICSELVOL = 0x108, - LILSEL = 0x109, - LIRSEL = 0x10a, - VOICEVOL = 0x10b, - AUDIOLVOL = 0x10c, - AUDIORVOL = 0x10d, - LMUTE = 0x10e, - RMUTE = 0x10f, - POWERCTRL1 = 0x110, - POWERCTRL2 = 0x111, - DRVPOWERCTRL = 0x112, - VREFPLL = 0x113, - PCMBUFCTRL = 0x114, - SOFTMUTE = 0x115, - DTMFPATH = 0x116, - DTMFVOL = 0x117, - DTMFFREQ = 0x118, - DTMFHFREQ = 0x119, - DTMFLFREQ = 0x11a, - DTMFCTRL = 0x11b, - DTMFASON = 0x11c, - DTMFASOFF = 0x11d, - DTMFASINUM = 0x11e, - CLASSDVOL = 0x11f, - VOICEDACAVOL = 0x120, - AUDDACAVOL = 0x121, - LOMUTEVOL = 0x122, - HPLVOL = 0x123, - HPRVOL = 0x124, - MONOVOL = 0x125, - LINEOUTMIXVOL = 0x126, - EPMIXVOL = 0x127, - LINEOUTLSEL = 0x128, - LINEOUTRSEL = 0x129, - EPMIXOUTSEL = 0x12a, - HPLMIXSEL = 0x12b, - HPRMIXSEL = 0x12c, - LOANTIPOP = 0x12d, - AUXDBNC = 0x12f, -}; - -static void nc_set_amp_power(int power) -{ - if (snd_pmic_ops_nc.gpio_amp) - gpio_set_value(snd_pmic_ops_nc.gpio_amp, power); -} - -/**** - * nc_init_card - initialize the sound card - * - * This initializes the audio paths to know values in case of this sound card - */ -static int nc_init_card(void) -{ - struct sc_reg_access sc_access[] = { - {VAUDIOCNT, 0x25, 0}, - {VOICEPORT1, 0x00, 0}, - {VOICEPORT2, 0x00, 0}, - {AUDIOPORT1, 0x98, 0}, - {AUDIOPORT2, 0x09, 0}, - {AUDIOLVOL, 0x00, 0}, - {AUDIORVOL, 0x00, 0}, - {LMUTE, 0x03, 0}, - {RMUTE, 0x03, 0}, - {POWERCTRL1, 0x00, 0}, - {POWERCTRL2, 0x00, 0}, - {DRVPOWERCTRL, 0x00, 0}, - {VREFPLL, 0x10, 0}, - {HPLMIXSEL, 0xee, 0}, - {HPRMIXSEL, 0xf6, 0}, - {PCMBUFCTRL, 0x0, 0}, - {VOICEVOL, 0x0e, 0}, - {HPLVOL, 0x06, 0}, - {HPRVOL, 0x06, 0}, - {MICCTRL, 0x51, 0x00}, - {ADCSAMPLERATE, 0x8B, 0x00}, - {MICSELVOL, 0x5B, 0x00}, - {LILSEL, 0x06, 0}, - {LIRSEL, 0x46, 0}, - {LOANTIPOP, 0x00, 0}, - {DMICCTRL1, 0x40, 0}, - {AUXDBNC, 0xff, 0}, - }; - snd_pmic_ops_nc.card_status = SND_CARD_INIT_DONE; - snd_pmic_ops_nc.master_mute = UNMUTE; - snd_pmic_ops_nc.mute_status = UNMUTE; - sst_sc_reg_access(sc_access, PMIC_WRITE, 27); - mutex_init(&snd_pmic_ops_nc.lock); - pr_debug("init complete!!\n"); - return 0; -} - -static int nc_enable_audiodac(int value) -{ - struct sc_reg_access sc_access[3]; - int mute_val = 0; - - if (snd_pmic_ops_nc.mute_status == MUTE) - return 0; - - if (((snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE) || - (snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR)) && - (value == UNMUTE)) - return 0; - if (value == UNMUTE) { - /* unmute the system, set the 7th bit to zero */ - mute_val = 0x00; - } else { - /* MUTE:Set the seventh bit */ - mute_val = 0x04; - - } - sc_access[0].reg_addr = LMUTE; - sc_access[1].reg_addr = RMUTE; - sc_access[0].mask = sc_access[1].mask = MASK2; - sc_access[0].value = sc_access[1].value = mute_val; - - if (snd_pmic_ops_nc.num_channel == 1) - sc_access[1].value = 0x04; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - -} - -static int nc_power_up_pb(unsigned int port) -{ - struct sc_reg_access sc_access[7]; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - if (port == 0xFF) - return 0; - mutex_lock(&snd_pmic_ops_nc.lock); - nc_enable_audiodac(MUTE); - msleep(30); - - pr_debug("powering up pb....\n"); - - sc_access[0].reg_addr = VAUDIOCNT; - sc_access[0].value = 0x27; - sc_access[0].mask = 0x27; - sc_access[1].reg_addr = VREFPLL; - if (port == 0) { - sc_access[1].value = 0x3A; - sc_access[1].mask = 0x3A; - } else if (port == 1) { - sc_access[1].value = 0x35; - sc_access[1].mask = 0x35; - } - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - - - - sc_access[0].reg_addr = POWERCTRL1; - if (port == 0) { - sc_access[0].value = 0x40; - sc_access[0].mask = 0x40; - } else if (port == 1) { - sc_access[0].value = 0x01; - sc_access[0].mask = 0x01; - } - sc_access[1].reg_addr = POWERCTRL2; - sc_access[1].value = 0x0C; - sc_access[1].mask = 0x0C; - - sc_access[2].reg_addr = DRVPOWERCTRL; - sc_access[2].value = 0x86; - sc_access[2].mask = 0x86; - - sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); - - msleep(30); - - snd_pmic_ops_nc.pb_on = 1; - - /* - * There is a mismatch between Playback Sources and the enumerated - * values of output sources. This mismatch causes ALSA upper to send - * Item 1 for Internal Speaker, but the expected enumeration is 2! For - * now, treat MONO_EARPIECE and INTERNAL_SPKR identically and power up - * the needed resources - */ - if (snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE || - snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR) - nc_set_amp_power(1); - nc_enable_audiodac(UNMUTE); - mutex_unlock(&snd_pmic_ops_nc.lock); - return 0; -} - -static int nc_power_up_cp(unsigned int port) -{ - struct sc_reg_access sc_access[5]; - int retval = 0; - - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - - pr_debug("powering up cp....\n"); - - if (port == 0xFF) - return 0; - sc_access[0].reg_addr = VAUDIOCNT; - sc_access[0].value = 0x27; - sc_access[0].mask = 0x27; - sc_access[1].reg_addr = VREFPLL; - if (port == 0) { - sc_access[1].value = 0x3E; - sc_access[1].mask = 0x3E; - } else if (port == 1) { - sc_access[1].value = 0x35; - sc_access[1].mask = 0x35; - } - - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - - - sc_access[0].reg_addr = POWERCTRL1; - if (port == 0) { - sc_access[0].value = 0xB4; - sc_access[0].mask = 0xB4; - } else if (port == 1) { - sc_access[0].value = 0xBF; - sc_access[0].mask = 0xBF; - } - sc_access[1].reg_addr = POWERCTRL2; - if (port == 0) { - sc_access[1].value = 0x0C; - sc_access[1].mask = 0x0C; - } else if (port == 1) { - sc_access[1].value = 0x02; - sc_access[1].mask = 0x02; - } - - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - -} - -static int nc_power_down(void) -{ - int retval = 0; - struct sc_reg_access sc_access[5]; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - nc_enable_audiodac(MUTE); - - - pr_debug("powering dn nc_power_down ....\n"); - - if (snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE || - snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR) - nc_set_amp_power(0); - - msleep(30); - - sc_access[0].reg_addr = DRVPOWERCTRL; - sc_access[0].value = 0x00; - sc_access[0].mask = 0x00; - - sst_sc_reg_access(sc_access, PMIC_WRITE, 1); - - sc_access[0].reg_addr = POWERCTRL1; - sc_access[0].value = 0x00; - sc_access[0].mask = 0x00; - - sc_access[1].reg_addr = POWERCTRL2; - sc_access[1].value = 0x00; - sc_access[1].mask = 0x00; - - - - sst_sc_reg_access(sc_access, PMIC_WRITE, 2); - - msleep(30); - sc_access[0].reg_addr = VREFPLL; - sc_access[0].value = 0x10; - sc_access[0].mask = 0x10; - - sc_access[1].reg_addr = VAUDIOCNT; - sc_access[1].value = 0x25; - sc_access[1].mask = 0x25; - - - retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 2); - - msleep(30); - return nc_enable_audiodac(UNMUTE); -} - -static int nc_power_down_pb(unsigned int device) -{ - - int retval = 0; - struct sc_reg_access sc_access[5]; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - pr_debug("powering dn pb....\n"); - mutex_lock(&snd_pmic_ops_nc.lock); - nc_enable_audiodac(MUTE); - - - msleep(30); - - - sc_access[0].reg_addr = DRVPOWERCTRL; - sc_access[0].value = 0x00; - sc_access[0].mask = 0x00; - - sst_sc_reg_access(sc_access, PMIC_WRITE, 1); - - msleep(30); - - sc_access[0].reg_addr = POWERCTRL1; - sc_access[0].value = 0x00; - sc_access[0].mask = 0x41; - - sc_access[1].reg_addr = POWERCTRL2; - sc_access[1].value = 0x00; - sc_access[1].mask = 0x0C; - - sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); - - msleep(30); - - snd_pmic_ops_nc.pb_on = 0; - - nc_enable_audiodac(UNMUTE); - mutex_unlock(&snd_pmic_ops_nc.lock); - return 0; -} - -static int nc_power_down_cp(unsigned int device) -{ - struct sc_reg_access sc_access[] = { - {POWERCTRL1, 0x00, 0xBE}, - {POWERCTRL2, 0x00, 0x02}, - }; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - pr_debug("powering dn cp....\n"); - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); -} - -static int nc_set_pcm_voice_params(void) -{ - struct sc_reg_access sc_access[] = { - {0x100, 0xD5, 0}, - {0x101, 0x08, 0}, - {0x104, 0x03, 0}, - {0x107, 0x10, 0}, - {0x10B, 0x0E, 0}, - {0x10E, 0x03, 0}, - {0x10F, 0x03, 0}, - {0x114, 0x13, 0}, - {0x115, 0x00, 0}, - {0x128, 0xFE, 0}, - {0x129, 0xFE, 0}, - {0x12A, 0xFE, 0}, - {0x12B, 0xDE, 0}, - {0x12C, 0xDE, 0}, - }; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - sst_sc_reg_access(sc_access, PMIC_WRITE, 14); - pr_debug("Voice parameters set successfully!!\n"); - return 0; -} - - -static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel) -{ - int config2 = 0; - struct sc_reg_access sc_access; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - switch (sfreq) { - case 8000: - config2 = 0x00; - break; - case 11025: - config2 = 0x01; - break; - case 12000: - config2 = 0x02; - break; - case 16000: - config2 = 0x03; - break; - case 22050: - config2 = 0x04; - break; - case 24000: - config2 = 0x05; - break; - case 32000: - config2 = 0x07; - break; - case 44100: - config2 = 0x08; - break; - case 48000: - config2 = 0x09; - break; - } - - snd_pmic_ops_nc.num_channel = num_channel; - if (snd_pmic_ops_nc.num_channel == 1) { - - sc_access.value = 0x07; - sc_access.reg_addr = RMUTE; - pr_debug("RIGHT_HP_MUTE value%d\n", sc_access.value); - sc_access.mask = MASK2; - sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); - } else { - sc_access.value = 0x00; - sc_access.reg_addr = RMUTE; - pr_debug("RIGHT_HP_MUTE value %d\n", sc_access.value); - sc_access.mask = MASK2; - sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); - - - } - - pr_debug("word_size = %d\n", word_size); - - if (word_size == 24) { - sc_access.reg_addr = AUDIOPORT2; - sc_access.value = config2 | 0x10; - sc_access.mask = 0x1F; - } else { - sc_access.value = config2; - sc_access.mask = 0x1F; - sc_access.reg_addr = AUDIOPORT2; - } - sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); - - pr_debug("word_size = %d\n", word_size); - sc_access.reg_addr = AUDIOPORT1; - sc_access.mask = MASK5|MASK4|MASK1|MASK0; - if (word_size == 16) - sc_access.value = 0x98; - else if (word_size == 24) - sc_access.value = 0xAB; - - return sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); - - - -} - -static int nc_set_selected_output_dev(u8 value) -{ - struct sc_reg_access sc_access_HP[] = { - {LMUTE, 0x02, 0x06}, - {RMUTE, 0x02, 0x06}, - {DRVPOWERCTRL, 0x06, 0x06}, - }; - struct sc_reg_access sc_access_IS[] = { - {LMUTE, 0x04, 0x06}, - {RMUTE, 0x04, 0x06}, - {DRVPOWERCTRL, 0x00, 0x06}, - }; - int retval = 0; - - snd_pmic_ops_nc.output_dev_id = value; - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - pr_debug("nc set selected output:%d\n", value); - mutex_lock(&snd_pmic_ops_nc.lock); - switch (value) { - case STEREO_HEADPHONE: - if (snd_pmic_ops_nc.pb_on) - sst_sc_reg_access(sc_access_HP+2, PMIC_WRITE, 1); - retval = sst_sc_reg_access(sc_access_HP, PMIC_WRITE, 2); - nc_set_amp_power(0); - break; - case MONO_EARPIECE: - case INTERNAL_SPKR: - retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 3); - if (snd_pmic_ops_nc.pb_on) - nc_set_amp_power(1); - break; - default: - pr_err("rcvd illegal request: %d\n", value); - mutex_unlock(&snd_pmic_ops_nc.lock); - return -EINVAL; - } - mutex_unlock(&snd_pmic_ops_nc.lock); - return retval; -} - -static int nc_audio_init(void) -{ - struct sc_reg_access sc_acces, sc_access[] = { - {0x100, 0x00, 0}, - {0x101, 0x00, 0}, - {0x104, 0x8B, 0}, - {0x107, 0x11, 0}, - {0x10B, 0x0E, 0}, - {0x114, 0x00, 0}, - {0x115, 0x00, 0}, - {0x128, 0x00, 0}, - {0x129, 0x00, 0}, - {0x12A, 0x00, 0}, - {0x12B, 0xee, 0}, - {0x12C, 0xf6, 0}, - }; - - sst_sc_reg_access(sc_access, PMIC_WRITE, 12); - pr_debug("Audio Init successfully!!\n"); - - /*set output device */ - nc_set_selected_output_dev(snd_pmic_ops_nc.output_dev_id); - - if (snd_pmic_ops_nc.num_channel == 1) { - sc_acces.value = 0x07; - sc_acces.reg_addr = RMUTE; - pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value); - sc_acces.mask = MASK2; - sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1); - } else { - sc_acces.value = 0x00; - sc_acces.reg_addr = RMUTE; - pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value); - sc_acces.mask = MASK2; - sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1); - } - - return 0; -} - -static int nc_set_audio_port(int status) -{ - struct sc_reg_access sc_access[2] = {{0,},}; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - if (status == DEACTIVATE) { - /* Deactivate audio port-tristate and power */ - sc_access[0].value = 0x00; - sc_access[0].mask = MASK4|MASK5; - sc_access[0].reg_addr = AUDIOPORT1; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - } else if (status == ACTIVATE) { - /* activate audio port */ - nc_audio_init(); - sc_access[0].value = 0x10; - sc_access[0].mask = MASK4|MASK5 ; - sc_access[0].reg_addr = AUDIOPORT1; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - } else - return -EINVAL; - -} - -static int nc_set_voice_port(int status) -{ - struct sc_reg_access sc_access[2] = {{0,},}; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - if (status == DEACTIVATE) { - /* Activate Voice port */ - sc_access[0].value = 0x00; - sc_access[0].mask = MASK4; - sc_access[0].reg_addr = VOICEPORT1; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - } else if (status == ACTIVATE) { - /* Deactivate voice port */ - nc_set_pcm_voice_params(); - sc_access[0].value = 0x10; - sc_access[0].mask = MASK4; - sc_access[0].reg_addr = VOICEPORT1; - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - } else - return -EINVAL; -} - -static int nc_set_mute(int dev_id, u8 value) -{ - struct sc_reg_access sc_access[3]; - u8 mute_val, cap_mute; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - pr_debug("set device id::%d, value %d\n", dev_id, value); - - switch (dev_id) { - case PMIC_SND_MUTE_ALL: - pr_debug("PMIC_SND_MUTE_ALL value %d\n", value); - snd_pmic_ops_nc.mute_status = value; - snd_pmic_ops_nc.master_mute = value; - if (value == UNMUTE) { - /* unmute the system, set the 7th bit to zero */ - mute_val = cap_mute = 0x00; - } else { - /* MUTE:Set the seventh bit */ - mute_val = 0x80; - cap_mute = 0x40; - } - sc_access[0].reg_addr = AUDIOLVOL; - sc_access[1].reg_addr = AUDIORVOL; - sc_access[0].mask = sc_access[1].mask = MASK7; - sc_access[0].value = sc_access[1].value = mute_val; - if (snd_pmic_ops_nc.num_channel == 1) - sc_access[1].value = 0x80; - if (!sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2)) { - sc_access[0].reg_addr = 0x109; - sc_access[1].reg_addr = 0x10a; - sc_access[2].reg_addr = 0x105; - sc_access[0].mask = sc_access[1].mask = - sc_access[2].mask = MASK6; - sc_access[0].value = sc_access[1].value = - sc_access[2].value = cap_mute; - - if ((snd_pmic_ops_nc.input_dev_id == AMIC) || - (snd_pmic_ops_nc.input_dev_id == DMIC)) - sc_access[1].value = 0x40; - if (snd_pmic_ops_nc.input_dev_id == HS_MIC) - sc_access[0].value = 0x40; - retval = sst_sc_reg_access(sc_access, - PMIC_READ_MODIFY, 3); - } - break; - case PMIC_SND_HP_MIC_MUTE: - pr_debug("PMIC_SND_HPMIC_MUTE value %d\n", value); - if (value == UNMUTE) { - /* unmute the system, set the 6th bit to one */ - sc_access[0].value = 0x00; - } else { - /* mute the system, reset the 6th bit to zero */ - sc_access[0].value = 0x40; - } - sc_access[0].reg_addr = LIRSEL; - sc_access[0].mask = MASK6; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - break; - case PMIC_SND_AMIC_MUTE: - pr_debug("PMIC_SND_AMIC_MUTE value %d\n", value); - if (value == UNMUTE) { - /* unmute the system, set the 6th bit to one */ - sc_access[0].value = 0x00; - } else { - /* mute the system, reset the 6th bit to zero */ - sc_access[0].value = 0x40; - } - sc_access[0].reg_addr = LILSEL; - sc_access[0].mask = MASK6; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - break; - - case PMIC_SND_DMIC_MUTE: - pr_debug("INPUT_MUTE_DMIC value%d\n", value); - if (value == UNMUTE) { - /* unmute the system, set the 6th bit to one */ - sc_access[1].value = 0x00; - sc_access[0].value = 0x00; - } else { - /* mute the system, reset the 6th bit to zero */ - sc_access[1].value = 0x40; - sc_access[0].value = 0x40; - } - sc_access[0].reg_addr = DMICCTRL1; - sc_access[0].mask = MASK6; - sc_access[1].reg_addr = LILSEL; - sc_access[1].mask = MASK6; - retval = sst_sc_reg_access(sc_access, - PMIC_READ_MODIFY, 2); - break; - - case PMIC_SND_LEFT_HP_MUTE: - case PMIC_SND_RIGHT_HP_MUTE: - snd_pmic_ops_nc.mute_status = value; - if (value == UNMUTE) - sc_access[0].value = 0x0; - else - sc_access[0].value = 0x04; - - if (dev_id == PMIC_SND_LEFT_HP_MUTE) { - sc_access[0].reg_addr = LMUTE; - pr_debug("LEFT_HP_MUTE value %d\n", - sc_access[0].value); - } else { - if (snd_pmic_ops_nc.num_channel == 1) - sc_access[0].value = 0x04; - sc_access[0].reg_addr = RMUTE; - pr_debug("RIGHT_HP_MUTE value %d\n", - sc_access[0].value); - } - sc_access[0].mask = MASK2; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - break; - case PMIC_SND_LEFT_SPEAKER_MUTE: - case PMIC_SND_RIGHT_SPEAKER_MUTE: - if (value == UNMUTE) - sc_access[0].value = 0x00; - else - sc_access[0].value = 0x03; - sc_access[0].reg_addr = LMUTE; - pr_debug("SPEAKER_MUTE %d\n", sc_access[0].value); - sc_access[0].mask = MASK1; - retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); - break; - default: - return -EINVAL; - } - return retval ; - -} - -static int nc_set_vol(int dev_id, int value) -{ - struct sc_reg_access sc_access[3]; - int retval = 0, entries = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - pr_debug("set volume:%d\n", dev_id); - switch (dev_id) { - case PMIC_SND_CAPTURE_VOL: - pr_debug("PMIC_SND_CAPTURE_VOL:value::%d\n", value); - sc_access[0].value = sc_access[1].value = - sc_access[2].value = -value; - sc_access[0].mask = sc_access[1].mask = sc_access[2].mask = - (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); - sc_access[0].reg_addr = 0x10a; - sc_access[1].reg_addr = 0x109; - sc_access[2].reg_addr = 0x105; - entries = 3; - break; - - case PMIC_SND_LEFT_PB_VOL: - pr_debug("PMIC_SND_LEFT_HP_VOL %d\n", value); - sc_access[0].value = -value; - sc_access[0].reg_addr = HPLVOL; - sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4); - entries = 1; - break; - - case PMIC_SND_RIGHT_PB_VOL: - pr_debug("PMIC_SND_RIGHT_HP_VOL value %d\n", value); - if (snd_pmic_ops_nc.num_channel == 1) { - sc_access[0].value = 0x04; - sc_access[0].reg_addr = RMUTE; - sc_access[0].mask = MASK2; - } else { - sc_access[0].value = -value; - sc_access[0].reg_addr = HPRVOL; - sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4); - } - entries = 1; - break; - - case PMIC_SND_LEFT_MASTER_VOL: - pr_debug("PMIC_SND_LEFT_MASTER_VOL value %d\n", value); - sc_access[0].value = -value; - sc_access[0].reg_addr = AUDIOLVOL; - sc_access[0].mask = - (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); - entries = 1; - break; - - case PMIC_SND_RIGHT_MASTER_VOL: - pr_debug("PMIC_SND_RIGHT_MASTER_VOL value %d\n", value); - sc_access[0].value = -value; - sc_access[0].reg_addr = AUDIORVOL; - sc_access[0].mask = - (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); - entries = 1; - break; - - default: - return -EINVAL; - - } - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, entries); -} - -static int nc_set_selected_input_dev(u8 value) -{ - struct sc_reg_access sc_access[6]; - u8 num_val; - int retval = 0; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - snd_pmic_ops_nc.input_dev_id = value; - - pr_debug("nc set selected input:%d\n", value); - - switch (value) { - case AMIC: - pr_debug("Selecting AMIC\n"); - sc_access[0].reg_addr = 0x107; - sc_access[0].value = 0x40; - sc_access[0].mask = MASK6|MASK3|MASK1|MASK0; - sc_access[1].reg_addr = 0x10a; - sc_access[1].value = 0x40; - sc_access[1].mask = MASK6; - sc_access[2].reg_addr = 0x109; - sc_access[2].value = 0x00; - sc_access[2].mask = MASK6; - sc_access[3].reg_addr = 0x105; - sc_access[3].value = 0x40; - sc_access[3].mask = MASK6; - num_val = 4; - break; - - case HS_MIC: - pr_debug("Selecting HS_MIC\n"); - sc_access[0].reg_addr = MICCTRL; - sc_access[0].mask = MASK6|MASK3|MASK1|MASK0; - sc_access[0].value = 0x00; - sc_access[1].reg_addr = 0x109; - sc_access[1].mask = MASK6; - sc_access[1].value = 0x40; - sc_access[2].reg_addr = 0x10a; - sc_access[2].mask = MASK6; - sc_access[2].value = 0x00; - sc_access[3].reg_addr = 0x105; - sc_access[3].value = 0x40; - sc_access[3].mask = MASK6; - sc_access[4].reg_addr = ADCSAMPLERATE; - sc_access[4].mask = MASK7|MASK6|MASK5|MASK4|MASK3; - sc_access[4].value = 0xc8; - num_val = 5; - break; - - case DMIC: - pr_debug("DMIC\n"); - sc_access[0].reg_addr = MICCTRL; - sc_access[0].mask = MASK6|MASK3|MASK1|MASK0; - sc_access[0].value = 0x0B; - sc_access[1].reg_addr = 0x105; - sc_access[1].value = 0x80; - sc_access[1].mask = MASK7|MASK6; - sc_access[2].reg_addr = 0x10a; - sc_access[2].value = 0x40; - sc_access[2].mask = MASK6; - sc_access[3].reg_addr = LILSEL; - sc_access[3].mask = MASK6; - sc_access[3].value = 0x00; - sc_access[4].reg_addr = ADCSAMPLERATE; - sc_access[4].mask = MASK7|MASK6|MASK5|MASK4|MASK3; - sc_access[4].value = 0x33; - num_val = 5; - break; - default: - return -EINVAL; - } - return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_val); -} - -static int nc_get_mute(int dev_id, u8 *value) -{ - int retval = 0, mask = 0; - struct sc_reg_access sc_access = {0,}; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - pr_debug("get mute::%d\n", dev_id); - - switch (dev_id) { - case PMIC_SND_AMIC_MUTE: - pr_debug("PMIC_SND_INPUT_MUTE_MIC1\n"); - sc_access.reg_addr = LILSEL; - mask = MASK6; - break; - case PMIC_SND_HP_MIC_MUTE: - pr_debug("PMIC_SND_INPUT_MUTE_MIC2\n"); - sc_access.reg_addr = LIRSEL; - mask = MASK6; - break; - case PMIC_SND_LEFT_HP_MUTE: - case PMIC_SND_RIGHT_HP_MUTE: - mask = MASK2; - pr_debug("PMIC_SN_LEFT/RIGHT_HP_MUTE\n"); - if (dev_id == PMIC_SND_RIGHT_HP_MUTE) - sc_access.reg_addr = RMUTE; - else - sc_access.reg_addr = LMUTE; - break; - - case PMIC_SND_LEFT_SPEAKER_MUTE: - pr_debug("PMIC_MONO_EARPIECE_MUTE\n"); - sc_access.reg_addr = RMUTE; - mask = MASK1; - break; - case PMIC_SND_DMIC_MUTE: - pr_debug("PMIC_SND_INPUT_MUTE_DMIC\n"); - sc_access.reg_addr = 0x105; - mask = MASK6; - break; - default: - return -EINVAL; - - } - retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - pr_debug("reg value = %d\n", sc_access.value); - if (retval) - return retval; - *value = (sc_access.value) & mask; - pr_debug("masked value = %d\n", *value); - if (*value) - *value = 0; - else - *value = 1; - pr_debug("value returned = 0x%x\n", *value); - return retval; -} - -static int nc_get_vol(int dev_id, int *value) -{ - int retval = 0, mask = 0; - struct sc_reg_access sc_access = {0,}; - - if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT) - retval = nc_init_card(); - if (retval) - return retval; - - switch (dev_id) { - case PMIC_SND_CAPTURE_VOL: - pr_debug("PMIC_SND_INPUT_CAPTURE_VOL\n"); - sc_access.reg_addr = LILSEL; - mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); - break; - - case PMIC_SND_LEFT_MASTER_VOL: - pr_debug("GET_VOLUME_PMIC_LEFT_MASTER_VOL\n"); - sc_access.reg_addr = AUDIOLVOL; - mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); - break; - - case PMIC_SND_RIGHT_MASTER_VOL: - pr_debug("GET_VOLUME_PMIC_RIGHT_MASTER_VOL\n"); - sc_access.reg_addr = AUDIORVOL; - mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); - break; - - case PMIC_SND_RIGHT_PB_VOL: - pr_debug("GET_VOLUME_PMIC_RIGHT_HP_VOL\n"); - sc_access.reg_addr = HPRVOL; - mask = (MASK0|MASK1|MASK2|MASK3|MASK4); - break; - - case PMIC_SND_LEFT_PB_VOL: - pr_debug("GET_VOLUME_PMIC_LEFT_HP_VOL\n"); - sc_access.reg_addr = HPLVOL; - mask = (MASK0|MASK1|MASK2|MASK3|MASK4); - break; - - default: - return -EINVAL; - - } - retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - pr_debug("value read = 0x%x\n", sc_access.value); - *value = -((sc_access.value) & mask); - pr_debug("get vol value returned = %d\n", *value); - return retval; -} - -static void hp_automute(enum snd_jack_types type, int present) -{ - u8 in = DMIC; - u8 out = INTERNAL_SPKR; - if (present) { - if (type == SND_JACK_HEADSET) - in = HS_MIC; - out = STEREO_HEADPHONE; - } - nc_set_selected_input_dev(in); - nc_set_selected_output_dev(out); -} - -static void nc_pmic_irq_cb(void *cb_data, u8 intsts) -{ - u8 value = 0; - struct mad_jack *mjack = NULL; - unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; - struct snd_intelmad *intelmaddata = cb_data; - struct sc_reg_access sc_access_read = {0,}; - - sc_access_read.reg_addr = 0x132; - sst_sc_reg_access(&sc_access_read, PMIC_READ, 1); - value = (sc_access_read.value); - pr_debug("value returned = 0x%x\n", value); - - mjack = &intelmaddata->jack[0]; - if (intsts & 0x1) { - pr_debug("SST DBG:MAD headset detected\n"); - /* send headset detect/undetect */ - present = (value == 0x1) ? 3 : 0; - jack_event_flag = 1; - mjack->jack.type = SND_JACK_HEADSET; - hp_automute(SND_JACK_HEADSET, present); - } - - if (intsts & 0x2) { - pr_debug(":MAD headphone detected\n"); - /* send headphone detect/undetect */ - present = (value == 0x2) ? 1 : 0; - jack_event_flag = 1; - mjack->jack.type = SND_JACK_HEADPHONE; - hp_automute(SND_JACK_HEADPHONE, present); - } - - if (intsts & 0x4) { - pr_debug("MAD short push detected\n"); - /* send short push */ - present = 1; - jack_event_flag = 1; - buttonpressflag = 1; - mjack->jack.type = MID_JACK_HS_SHORT_PRESS; - } - - if (intsts & 0x8) { - pr_debug(":MAD long push detected\n"); - /* send long push */ - present = 1; - jack_event_flag = 1; - buttonpressflag = 1; - mjack->jack.type = MID_JACK_HS_LONG_PRESS; - } - - if (jack_event_flag) - sst_mad_send_jack_report(&mjack->jack, - buttonpressflag, present); -} -static int nc_jack_enable(void) -{ - return 0; -} - -struct snd_pmic_ops snd_pmic_ops_nc = { - .input_dev_id = DMIC, - .output_dev_id = INTERNAL_SPKR, - .set_input_dev = nc_set_selected_input_dev, - .set_output_dev = nc_set_selected_output_dev, - .set_mute = nc_set_mute, - .get_mute = nc_get_mute, - .set_vol = nc_set_vol, - .get_vol = nc_get_vol, - .init_card = nc_init_card, - .set_pcm_audio_params = nc_set_pcm_audio_params, - .set_pcm_voice_params = nc_set_pcm_voice_params, - .set_voice_port = nc_set_voice_port, - .set_audio_port = nc_set_audio_port, - .power_up_pmic_pb = nc_power_up_pb, - .power_up_pmic_cp = nc_power_up_cp, - .power_down_pmic_pb = nc_power_down_pb, - .power_down_pmic_cp = nc_power_down_cp, - .power_down_pmic = nc_power_down, - .pmic_irq_cb = nc_pmic_irq_cb, - .pmic_jack_enable = nc_jack_enable, -}; diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile index de6bd12e973..34a2ddacc7e 100644 --- a/drivers/staging/line6/Makefile +++ b/drivers/staging/line6/Makefile @@ -12,4 +12,5 @@ line6usb-y := \ playback.o \ pod.o \ toneport.o \ - variax.o + variax.o \ + podhd.o diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c index 9647154a492..127f9524774 100644 --- a/drivers/staging/line6/capture.c +++ b/drivers/staging/line6/capture.c @@ -9,6 +9,7 @@ * */ +#include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -192,6 +193,31 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) } } +int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm) +{ + /* We may be invoked multiple times in a row so allocate once only */ + if (line6pcm->buffer_in) + return 0; + + line6pcm->buffer_in = + kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + + if (!line6pcm->buffer_in) { + dev_err(line6pcm->line6->ifcdev, + "cannot malloc capture buffer\n"); + return -ENOMEM; + } + + return 0; +} + +void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) +{ + kfree(line6pcm->buffer_in); + line6pcm->buffer_in = NULL; +} + /* * Callback for completed capture URB. */ @@ -243,11 +269,7 @@ static void audio_in_callback(struct urb *urb) length += fsize; /* the following assumes LINE6_ISO_PACKETS == 1: */ -#if LINE6_BACKUP_MONITOR_SIGNAL - memcpy(line6pcm->prev_fbuf, fbuf, fsize); -#else line6pcm->prev_fbuf = fbuf; -#endif line6pcm->prev_fsize = fsize; #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE @@ -319,6 +341,13 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, } /* -- [FD] end */ + if ((line6pcm->flags & MASK_CAPTURE) == 0) { + ret = line6_alloc_capture_buffer(line6pcm); + + if (ret < 0) + return ret; + } + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) @@ -331,6 +360,13 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, /* hw_free capture callback */ static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) { + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + if ((line6pcm->flags & MASK_CAPTURE) == 0) { + line6_unlink_wait_clear_audio_in_urbs(line6pcm); + line6_free_capture_buffer(line6pcm); + } + return snd_pcm_lib_free_pages(substream); } diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h index a7509fbbb95..366cbaa7c88 100644 --- a/drivers/staging/line6/capture.h +++ b/drivers/staging/line6/capture.h @@ -19,11 +19,13 @@ extern struct snd_pcm_ops snd_line6_capture_ops; +extern int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm); extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize); extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length); extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 851b762319c..6a1959e16e0 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -21,6 +21,7 @@ #include "midi.h" #include "playback.h" #include "pod.h" +#include "podhd.h" #include "revision.h" #include "toneport.h" #include "usbdefs.h" @@ -37,6 +38,8 @@ static const struct usb_device_id line6_id_table[] = { {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)}, + {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)}, + {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)}, @@ -56,23 +59,25 @@ MODULE_DEVICE_TABLE(usb, line6_id_table); /* *INDENT-OFF* */ static struct line6_properties line6_properties_table[] = { - { "BassPODxt", "BassPODxt", LINE6_BIT_BASSPODXT, LINE6_BIT_CONTROL_PCM_HWMON }, - { "BassPODxtLive", "BassPODxt Live", LINE6_BIT_BASSPODXTLIVE, LINE6_BIT_CONTROL_PCM_HWMON }, - { "BassPODxtPro", "BassPODxt Pro", LINE6_BIT_BASSPODXTPRO, LINE6_BIT_CONTROL_PCM_HWMON }, - { "GuitarPort", "GuitarPort", LINE6_BIT_GUITARPORT, LINE6_BIT_PCM }, - { "PocketPOD", "Pocket POD", LINE6_BIT_POCKETPOD, LINE6_BIT_CONTROL }, - { "PODStudioGX", "POD Studio GX", LINE6_BIT_PODSTUDIO_GX, LINE6_BIT_PCM }, - { "PODStudioUX1", "POD Studio UX1", LINE6_BIT_PODSTUDIO_UX1, LINE6_BIT_PCM }, - { "PODStudioUX2", "POD Studio UX2", LINE6_BIT_PODSTUDIO_UX2, LINE6_BIT_PCM }, - { "PODX3", "POD X3", LINE6_BIT_PODX3, LINE6_BIT_PCM }, - { "PODX3Live", "POD X3 Live", LINE6_BIT_PODX3LIVE, LINE6_BIT_PCM }, - { "PODxt", "PODxt", LINE6_BIT_PODXT, LINE6_BIT_CONTROL_PCM_HWMON }, - { "PODxtLive", "PODxt Live", LINE6_BIT_PODXTLIVE, LINE6_BIT_CONTROL_PCM_HWMON }, - { "PODxtPro", "PODxt Pro", LINE6_BIT_PODXTPRO, LINE6_BIT_CONTROL_PCM_HWMON }, - { "TonePortGX", "TonePort GX", LINE6_BIT_TONEPORT_GX, LINE6_BIT_PCM }, - { "TonePortUX1", "TonePort UX1", LINE6_BIT_TONEPORT_UX1, LINE6_BIT_PCM }, - { "TonePortUX2", "TonePort UX2", LINE6_BIT_TONEPORT_UX2, LINE6_BIT_PCM }, - { "Variax", "Variax Workbench", LINE6_BIT_VARIAX, LINE6_BIT_CONTROL } + { LINE6_BIT_BASSPODXT, "BassPODxt", "BassPODxt", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_GUITARPORT, "GuitarPort", "GuitarPort", LINE6_BIT_PCM }, + { LINE6_BIT_POCKETPOD, "PocketPOD", "Pocket POD", LINE6_BIT_CONTROL }, + { LINE6_BIT_PODHD300, "PODHD300", "POD HD300", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODHD500, "PODHD500", "POD HD500", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", LINE6_BIT_PCM }, + { LINE6_BIT_PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", LINE6_BIT_PCM }, + { LINE6_BIT_PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", LINE6_BIT_PCM }, + { LINE6_BIT_PODX3, "PODX3", "POD X3", LINE6_BIT_PCM }, + { LINE6_BIT_PODX3LIVE, "PODX3Live", "POD X3 Live", LINE6_BIT_PCM }, + { LINE6_BIT_PODXT, "PODxt", "PODxt", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODXTLIVE, "PODxtLive", "PODxt Live", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODXTPRO, "PODxtPro", "PODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_TONEPORT_GX, "TonePortGX", "TonePort GX", LINE6_BIT_PCM }, + { LINE6_BIT_TONEPORT_UX1, "TonePortUX1", "TonePort UX1", LINE6_BIT_PCM }, + { LINE6_BIT_TONEPORT_UX2, "TonePortUX2", "TonePort UX2", LINE6_BIT_PCM }, + { LINE6_BIT_VARIAX, "Variax", "Variax Workbench", LINE6_BIT_CONTROL }, }; /* *INDENT-ON* */ @@ -437,6 +442,10 @@ static void line6_data_received(struct urb *urb) line6); break; + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + break; /* let userspace handle MIDI */ + case LINE6_DEVID_PODXTLIVE: switch (line6->interface_number) { case PODXTLIVE_INTERFACE_POD: @@ -720,8 +729,8 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_id *id) { int devtype; - struct usb_device *usbdev = NULL; - struct usb_line6 *line6 = NULL; + struct usb_device *usbdev; + struct usb_line6 *line6; const struct line6_properties *properties; int devnum; int interface_number, alternate = 0; @@ -794,6 +803,7 @@ static int line6_probe(struct usb_interface *interface, } break; + case LINE6_DEVID_PODHD500: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: switch (interface_number) { @@ -812,6 +822,7 @@ static int line6_probe(struct usb_interface *interface, case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: + case LINE6_DEVID_PODHD300: alternate = 5; break; @@ -865,6 +876,18 @@ static int line6_probe(struct usb_interface *interface, ep_write = 0x03; break; + case LINE6_DEVID_PODHD300: + size = sizeof(struct usb_line6_podhd); + ep_read = 0x84; + ep_write = 0x03; + break; + + case LINE6_DEVID_PODHD500: + size = sizeof(struct usb_line6_podhd); + ep_read = 0x81; + ep_write = 0x01; + break; + case LINE6_DEVID_POCKETPOD: size = sizeof(struct usb_line6_pod); ep_read = 0x82; @@ -923,7 +946,7 @@ static int line6_probe(struct usb_interface *interface, } if (size == 0) { - dev_err(line6->ifcdev, + dev_err(&interface->dev, "driver bug: interface data size not set\n"); ret = -ENODEV; goto err_put; @@ -1017,6 +1040,12 @@ static int line6_probe(struct usb_interface *interface, ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); break; + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + ret = line6_podhd_init(interface, + (struct usb_line6_podhd *)line6); + break; + case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: @@ -1139,6 +1168,11 @@ static void line6_disconnect(struct usb_interface *interface) line6_pod_disconnect(interface); break; + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + line6_podhd_disconnect(interface); + break; + case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 553192f4931..117bf994356 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -88,6 +88,11 @@ static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; */ struct line6_properties { /** + Bit identifying this device in the line6usb driver. + */ + int device_bit; + + /** Card id string (maximum 16 characters). This can be used to address the device in ALSA programs as "default:CARD=<id>" @@ -100,11 +105,6 @@ struct line6_properties { const char *name; /** - Bit identifying this device in the line6usb driver. - */ - int device_bit; - - /** Bit vector defining this device's capabilities in the line6usb driver. */ diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c index e554a2da643..13d02939c3c 100644 --- a/drivers/staging/line6/midi.c +++ b/drivers/staging/line6/midi.c @@ -135,7 +135,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, line6_write_hexdump(line6, 'S', data, length); #endif - transfer_buffer = kmalloc(length, GFP_ATOMIC); + transfer_buffer = kmemdup(data, length, GFP_ATOMIC); if (transfer_buffer == NULL) { usb_free_urb(urb); @@ -143,7 +143,6 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, return -ENOMEM; } - memcpy(transfer_buffer, data, length); usb_fill_int_urb(urb, line6->usbdev, usb_sndbulkpipe(line6->usbdev, line6->ep_control_write), @@ -173,6 +172,8 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, break; case LINE6_DEVID_VARIAX: + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: break; default: @@ -307,10 +308,10 @@ static ssize_t midi_set_midi_mask_transmit(struct device *dev, { struct usb_interface *interface = to_usb_interface(dev); struct usb_line6 *line6 = usb_get_intfdata(interface); - unsigned long value; + unsigned short value; int ret; - ret = strict_strtoul(buf, 10, &value); + ret = kstrtou16(buf, 10, &value); if (ret) return ret; @@ -339,10 +340,10 @@ static ssize_t midi_set_midi_mask_receive(struct device *dev, { struct usb_interface *interface = to_usb_interface(dev); struct usb_line6 *line6 = usb_get_intfdata(interface); - unsigned long value; + unsigned short value; int ret; - ret = strict_strtoul(buf, 10, &value); + ret = kstrtou16(buf, 10, &value); if (ret) return ret; @@ -391,16 +392,32 @@ int line6_init_midi(struct usb_line6 *line6) return -ENOMEM; err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); - if (err < 0) + if (err < 0) { + kfree(line6midi); return err; + } err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); - if (err < 0) + if (err < 0) { + kfree(line6midi->midibuf_in.buf); + kfree(line6midi); return err; + } line6midi->line6 = line6; - line6midi->midi_mask_transmit = 1; - line6midi->midi_mask_receive = 4; + + switch(line6->product) { + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + line6midi->midi_mask_transmit = 1; + line6midi->midi_mask_receive = 1; + break; + + default: + line6midi->midi_mask_transmit = 1; + line6midi->midi_mask_receive = 4; + } + line6->line6midi = line6midi; err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, diff --git a/drivers/staging/line6/midi.h b/drivers/staging/line6/midi.h index b73a025d8be..4a9e9f94729 100644 --- a/drivers/staging/line6/midi.h +++ b/drivers/staging/line6/midi.h @@ -57,12 +57,12 @@ struct snd_line6_midi { /** Bit mask for output MIDI channels. */ - int midi_mask_transmit; + unsigned short midi_mask_transmit; /** Bit mask for input MIDI channels. */ - int midi_mask_receive; + unsigned short midi_mask_receive; /** Buffer for incoming MIDI stream. diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 9d4c8a606ee..37675e66da8 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -86,31 +86,22 @@ static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period, #endif +static bool test_flags(unsigned long flags0, unsigned long flags1, + unsigned long mask) +{ + return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); +} + int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) { unsigned long flags_old = __sync_fetch_and_or(&line6pcm->flags, channels); unsigned long flags_new = flags_old | channels; int err = 0; - -#if LINE6_BACKUP_MONITOR_SIGNAL - if (!(line6pcm->line6->properties->capabilities & LINE6_BIT_HWMON)) { - line6pcm->prev_fbuf = - kmalloc(LINE6_ISO_PACKETS * line6pcm->max_packet_size, - GFP_KERNEL); - - if (!line6pcm->prev_fbuf) { - dev_err(line6pcm->line6->ifcdev, - "cannot malloc monitor buffer\n"); - return -ENOMEM; - } - } -#else + line6pcm->prev_fbuf = NULL; -#endif - if (((flags_old & MASK_CAPTURE) == 0) && - ((flags_new & MASK_CAPTURE) != 0)) { + if (test_flags(flags_old, flags_new, MASK_CAPTURE)) { /* Waiting for completion of active URBs in the stop handler is a bug, we therefore report an error if capturing is restarted @@ -119,54 +110,47 @@ int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) return -EBUSY; - line6pcm->buffer_in = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); + if (!(flags_new & MASK_PCM_ALSA_CAPTURE)) { + err = line6_alloc_capture_buffer(line6pcm); - if (!line6pcm->buffer_in) { - dev_err(line6pcm->line6->ifcdev, - "cannot malloc capture buffer\n"); - return -ENOMEM; + if (err < 0) + goto pcm_start_error; } line6pcm->count_in = 0; line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); - if (err < 0) { - __sync_fetch_and_and(&line6pcm->flags, ~channels); - return err; - } + if (err < 0) + goto pcm_start_error; } - if (((flags_old & MASK_PLAYBACK) == 0) && - ((flags_new & MASK_PLAYBACK) != 0)) { + if (test_flags(flags_old, flags_new, MASK_PLAYBACK)) { /* See comment above regarding PCM restart. */ if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) return -EBUSY; - line6pcm->buffer_out = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); + if (!(flags_new & MASK_PCM_ALSA_PLAYBACK)) { + err = line6_alloc_playback_buffer(line6pcm); - if (!line6pcm->buffer_out) { - dev_err(line6pcm->line6->ifcdev, - "cannot malloc playback buffer\n"); - return -ENOMEM; + if (err < 0) + goto pcm_start_error; } line6pcm->count_out = 0; err = line6_submit_audio_out_all_urbs(line6pcm); - if (err < 0) { - __sync_fetch_and_and(&line6pcm->flags, ~channels); - return err; - } + if (err < 0) + goto pcm_start_error; } return 0; + +pcm_start_error: + __sync_fetch_and_and(&line6pcm->flags, ~channels); + return err; } int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels) @@ -175,22 +159,19 @@ int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels) __sync_fetch_and_and(&line6pcm->flags, ~channels); unsigned long flags_new = flags_old & ~channels; - if (((flags_old & MASK_CAPTURE) != 0) && - ((flags_new & MASK_CAPTURE) == 0)) { + if (test_flags(flags_new, flags_old, MASK_CAPTURE)) { line6_unlink_audio_in_urbs(line6pcm); - kfree(line6pcm->buffer_in); - line6pcm->buffer_in = NULL; + + if (!(flags_old & MASK_PCM_ALSA_CAPTURE)) + line6_free_capture_buffer(line6pcm); } - if (((flags_old & MASK_PLAYBACK) != 0) && - ((flags_new & MASK_PLAYBACK) == 0)) { + if (test_flags(flags_new, flags_old, MASK_PLAYBACK)) { line6_unlink_audio_out_urbs(line6pcm); - kfree(line6pcm->buffer_out); - line6pcm->buffer_out = NULL; + + if (!(flags_old & MASK_PCM_ALSA_PLAYBACK)) + line6_free_playback_buffer(line6pcm); } -#if LINE6_BACKUP_MONITOR_SIGNAL - kfree(line6pcm->prev_fbuf); -#endif return 0; } @@ -403,10 +384,12 @@ int line6_init_pcm(struct usb_line6 *line6, case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTLIVE: case LINE6_DEVID_PODXTPRO: + case LINE6_DEVID_PODHD300: ep_read = 0x82; ep_write = 0x01; break; + case LINE6_DEVID_PODHD500: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: ep_read = 0x86; @@ -451,9 +434,14 @@ int line6_init_pcm(struct usb_line6 *line6, line6pcm->line6 = line6; line6pcm->ep_audio_read = ep_read; line6pcm->ep_audio_write = ep_write; - line6pcm->max_packet_size = usb_maxpacket(line6->usbdev, - usb_rcvintpipe(line6->usbdev, - ep_read), 0); + + /* Read and write buffers are sized identically, so choose minimum */ + line6pcm->max_packet_size = min( + usb_maxpacket(line6->usbdev, + usb_rcvisocpipe(line6->usbdev, ep_read), 0), + usb_maxpacket(line6->usbdev, + usb_sndisocpipe(line6->usbdev, ep_write), 1)); + line6pcm->properties = properties; line6->line6pcm = line6pcm; @@ -508,6 +496,23 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) { struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + if ((line6pcm->flags & MASK_PLAYBACK) == 0) + line6_unlink_wait_clear_audio_out_urbs(line6pcm); + + break; + + case SNDRV_PCM_STREAM_CAPTURE: + if ((line6pcm->flags & MASK_CAPTURE) == 0) + line6_unlink_wait_clear_audio_in_urbs(line6pcm); + + break; + + default: + MISSING_CASE; + } + if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) { line6pcm->count_out = 0; line6pcm->pos_out = 0; diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h index 77055b3724a..55d8297dd3d 100644 --- a/drivers/staging/line6/pcm.h +++ b/drivers/staging/line6/pcm.h @@ -39,9 +39,6 @@ #define LINE6_IMPULSE_DEFAULT_PERIOD 100 #endif -#define LINE6_BACKUP_MONITOR_SIGNAL 0 -#define LINE6_REUSE_DMA_AREA_FOR_PLAYBACK 0 - /* Get substream from Line6 PCM data structure */ @@ -149,11 +146,6 @@ struct snd_line6_pcm { unsigned char *buffer_in; /** - Temporary buffer index for playback. - */ - int index_out; - - /** Previously captured frame (for software monitoring). */ unsigned char *prev_fbuf; diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c index 10c54383658..4152db2328b 100644 --- a/drivers/staging/line6/playback.c +++ b/drivers/staging/line6/playback.c @@ -9,6 +9,7 @@ * */ +#include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -191,13 +192,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) urb_frames = urb_size / bytes_per_frame; urb_out->transfer_buffer = line6pcm->buffer_out + - line6pcm->max_packet_size * line6pcm->index_out; + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; urb_out->transfer_buffer_length = urb_size; urb_out->context = line6pcm; - if (++line6pcm->index_out == LINE6_ISO_BUFFERS) - line6pcm->index_out = 0; - if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags) && !test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) { struct snd_pcm_runtime *runtime = @@ -222,18 +220,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) } else dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", len); /* this is somewhat paranoid */ } else { -#if LINE6_REUSE_DMA_AREA_FOR_PLAYBACK - /* set the buffer pointer */ - urb_out->transfer_buffer = - runtime->dma_area + - line6pcm->pos_out * bytes_per_frame; -#else - /* copy data */ memcpy(urb_out->transfer_buffer, runtime->dma_area + line6pcm->pos_out * bytes_per_frame, urb_out->transfer_buffer_length); -#endif } line6pcm->pos_out += urb_frames; @@ -361,6 +351,31 @@ void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) wait_clear_audio_out_urbs(line6pcm); } +int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm) +{ + /* We may be invoked multiple times in a row so allocate once only */ + if (line6pcm->buffer_out) + return 0; + + line6pcm->buffer_out = + kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + + if (!line6pcm->buffer_out) { + dev_err(line6pcm->line6->ifcdev, + "cannot malloc playback buffer\n"); + return -ENOMEM; + } + + return 0; +} + +void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) +{ + kfree(line6pcm->buffer_out); + line6pcm->buffer_out = NULL; +} + /* Callback for completed playback URB. */ @@ -469,6 +484,13 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, } /* -- [FD] end */ + if ((line6pcm->flags & MASK_PLAYBACK) == 0) { + ret = line6_alloc_playback_buffer(line6pcm); + + if (ret < 0) + return ret; + } + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) @@ -481,6 +503,13 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, /* hw_free playback callback */ static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) { + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + if ((line6pcm->flags & MASK_PLAYBACK) == 0) { + line6_unlink_wait_clear_audio_out_urbs(line6pcm); + line6_free_playback_buffer(line6pcm); + } + return snd_pcm_lib_free_pages(substream); } diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h index f2fc8c0526e..02487ff2453 100644 --- a/drivers/staging/line6/playback.h +++ b/drivers/staging/line6/playback.h @@ -29,7 +29,9 @@ extern struct snd_pcm_ops snd_line6_playback_ops; +extern int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm); extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index d9b30212585..4dadc571d96 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -1149,14 +1149,10 @@ static struct snd_kcontrol_new pod_control_monitor = { static void pod_destruct(struct usb_interface *interface) { struct usb_line6_pod *pod = usb_get_intfdata(interface); - struct usb_line6 *line6; if (pod == NULL) return; - line6 = &pod->line6; - if (line6 == NULL) - return; - line6_cleanup_audio(line6); + line6_cleanup_audio(&pod->line6); del_timer(&pod->startup_timer); cancel_work_sync(&pod->startup_work); diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c new file mode 100644 index 00000000000..7ef45437b4f --- /dev/null +++ b/drivers/staging/line6/podhd.c @@ -0,0 +1,154 @@ +/* + * Line6 Pod HD + * + * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <sound/core.h> +#include <sound/pcm.h> + +#include "audio.h" +#include "driver.h" +#include "pcm.h" +#include "podhd.h" + +#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ + +static struct snd_ratden podhd_ratden = { + .num_min = 48000, + .num_max = 48000, + .num_step = 1, + .den = 1, +}; + +static struct line6_pcm_properties podhd_pcm_properties = { + .snd_line6_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | +#ifdef CONFIG_PM + SNDRV_PCM_INFO_RESUME | +#endif + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_rates = { + .nrats = 1, + .rats = &podhd_ratden}, + .bytes_per_frame = PODHD_BYTES_PER_FRAME +}; + +/* + POD HD destructor. +*/ +static void podhd_destruct(struct usb_interface *interface) +{ + struct usb_line6_podhd *podhd = usb_get_intfdata(interface); + + if (podhd == NULL) + return; + line6_cleanup_audio(&podhd->line6); +} + +/* + Try to init POD HD device. +*/ +static int podhd_try_init(struct usb_interface *interface, + struct usb_line6_podhd *podhd) +{ + int err; + struct usb_line6 *line6 = &podhd->line6; + + if ((interface == NULL) || (podhd == NULL)) + return -ENODEV; + + /* initialize audio system: */ + err = line6_init_audio(line6); + if (err < 0) + return err; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(line6); + if (err < 0) + return err; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &podhd_pcm_properties); + if (err < 0) + return err; + + /* register USB audio system: */ + err = line6_register_audio(line6); + return err; +} + +/* + Init POD HD device (and clean up in case of failure). +*/ +int line6_podhd_init(struct usb_interface *interface, + struct usb_line6_podhd *podhd) +{ + int err = podhd_try_init(interface, podhd); + + if (err < 0) + podhd_destruct(interface); + + return err; +} + +/* + POD HD device disconnected. +*/ +void line6_podhd_disconnect(struct usb_interface *interface) +{ + struct usb_line6_podhd *podhd; + + if (interface == NULL) + return; + podhd = usb_get_intfdata(interface); + + if (podhd != NULL) { + struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; + + if (line6pcm != NULL) + line6_pcm_disconnect(line6pcm); + } + + podhd_destruct(interface); +} diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h new file mode 100644 index 00000000000..652f74056bb --- /dev/null +++ b/drivers/staging/line6/podhd.h @@ -0,0 +1,30 @@ +/* + * Line6 Pod HD + * + * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#ifndef PODHD_H +#define PODHD_H + +#include <linux/usb.h> + +#include "driver.h" + +struct usb_line6_podhd { + /** + Generic Line6 USB data. + */ + struct usb_line6 line6; +}; + +extern void line6_podhd_disconnect(struct usb_interface *interface); +extern int line6_podhd_init(struct usb_interface *interface, + struct usb_line6_podhd *podhd); + +#endif /* PODHD_H */ diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h index 350d0dfff8f..b4eee2b7383 100644 --- a/drivers/staging/line6/revision.h +++ b/drivers/staging/line6/revision.h @@ -1,4 +1,4 @@ #ifndef DRIVER_REVISION /* current subversion revision */ -#define DRIVER_REVISION " (revision 690)" +#define DRIVER_REVISION " (904)" #endif diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index 879e6992bbc..f31057830db 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -295,14 +295,10 @@ static struct snd_kcontrol_new toneport_control_source = { static void toneport_destruct(struct usb_interface *interface) { struct usb_line6_toneport *toneport = usb_get_intfdata(interface); - struct usb_line6 *line6; if (toneport == NULL) return; - line6 = &toneport->line6; - if (line6 == NULL) - return; - line6_cleanup_audio(line6); + line6_cleanup_audio(&toneport->line6); } /* diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index c6dffe6bc1a..aff9e5caea4 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -24,6 +24,8 @@ #define LINE6_DEVID_BASSPODXTPRO 0x4252 #define LINE6_DEVID_GUITARPORT 0x4750 #define LINE6_DEVID_POCKETPOD 0x5051 +#define LINE6_DEVID_PODHD300 0x5057 +#define LINE6_DEVID_PODHD500 0x414D #define LINE6_DEVID_PODSTUDIO_GX 0x4153 #define LINE6_DEVID_PODSTUDIO_UX1 0x4150 #define LINE6_DEVID_PODSTUDIO_UX2 0x4151 @@ -37,48 +39,71 @@ #define LINE6_DEVID_TONEPORT_UX2 0x4142 #define LINE6_DEVID_VARIAX 0x534d -#define LINE6_BIT_BASSPODXT (1 << 0) -#define LINE6_BIT_BASSPODXTLIVE (1 << 1) -#define LINE6_BIT_BASSPODXTPRO (1 << 2) -#define LINE6_BIT_GUITARPORT (1 << 3) -#define LINE6_BIT_POCKETPOD (1 << 4) -#define LINE6_BIT_PODSTUDIO_GX (1 << 5) -#define LINE6_BIT_PODSTUDIO_UX1 (1 << 6) -#define LINE6_BIT_PODSTUDIO_UX2 (1 << 7) -#define LINE6_BIT_PODX3 (1 << 8) -#define LINE6_BIT_PODX3LIVE (1 << 9) -#define LINE6_BIT_PODXT (1 << 10) -#define LINE6_BIT_PODXTLIVE (1 << 11) -#define LINE6_BIT_PODXTPRO (1 << 12) -#define LINE6_BIT_TONEPORT_GX (1 << 13) -#define LINE6_BIT_TONEPORT_UX1 (1 << 14) -#define LINE6_BIT_TONEPORT_UX2 (1 << 15) -#define LINE6_BIT_VARIAX (1 << 16) +enum { + LINE6_ID_BASSPODXT, + LINE6_ID_BASSPODXTLIVE, + LINE6_ID_BASSPODXTPRO, + LINE6_ID_GUITARPORT, + LINE6_ID_POCKETPOD, + LINE6_ID_PODHD300, + LINE6_ID_PODHD500, + LINE6_ID_PODSTUDIO_GX, + LINE6_ID_PODSTUDIO_UX1, + LINE6_ID_PODSTUDIO_UX2, + LINE6_ID_PODX3, + LINE6_ID_PODX3LIVE, + LINE6_ID_PODXT, + LINE6_ID_PODXTLIVE, + LINE6_ID_PODXTPRO, + LINE6_ID_TONEPORT_GX, + LINE6_ID_TONEPORT_UX1, + LINE6_ID_TONEPORT_UX2, + LINE6_ID_VARIAX +}; -#define LINE6_BITS_PRO (LINE6_BIT_BASSPODXTPRO | \ - LINE6_BIT_PODXTPRO) -#define LINE6_BITS_LIVE (LINE6_BIT_BASSPODXTLIVE | \ - LINE6_BIT_PODXTLIVE | \ - LINE6_BIT_PODX3LIVE) -#define LINE6_BITS_PODXTALL (LINE6_BIT_PODXT | \ - LINE6_BIT_PODXTLIVE | \ - LINE6_BIT_PODXTPRO) -#define LINE6_BITS_BASSPODXTALL (LINE6_BIT_BASSPODXT | \ - LINE6_BIT_BASSPODXTLIVE | \ - LINE6_BIT_BASSPODXTPRO) +#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_ID_ ## x + +enum { + LINE6_BIT(BASSPODXT), + LINE6_BIT(BASSPODXTLIVE), + LINE6_BIT(BASSPODXTPRO), + LINE6_BIT(GUITARPORT), + LINE6_BIT(POCKETPOD), + LINE6_BIT(PODHD300), + LINE6_BIT(PODHD500), + LINE6_BIT(PODSTUDIO_GX), + LINE6_BIT(PODSTUDIO_UX1), + LINE6_BIT(PODSTUDIO_UX2), + LINE6_BIT(PODX3), + LINE6_BIT(PODX3LIVE), + LINE6_BIT(PODXT), + LINE6_BIT(PODXTLIVE), + LINE6_BIT(PODXTPRO), + LINE6_BIT(TONEPORT_GX), + LINE6_BIT(TONEPORT_UX1), + LINE6_BIT(TONEPORT_UX2), + LINE6_BIT(VARIAX), + + LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO, + LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE | LINE6_BIT_PODX3LIVE, + LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE | LINE6_BIT_PODXTPRO, + LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE, + LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 | LINE6_BIT_PODHD500, + LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT | LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_BASSPODXTPRO +}; /* device supports settings parameter via USB */ -#define LINE6_BIT_CONTROL (1 << 0) +#define LINE6_BIT_CONTROL (1 << 0) /* device supports PCM input/output via USB */ -#define LINE6_BIT_PCM (1 << 1) +#define LINE6_BIT_PCM (1 << 1) /* device support hardware monitoring */ -#define LINE6_BIT_HWMON (1 << 2) +#define LINE6_BIT_HWMON (1 << 2) #define LINE6_BIT_CONTROL_PCM_HWMON (LINE6_BIT_CONTROL | \ LINE6_BIT_PCM | \ LINE6_BIT_HWMON) -#define LINE6_FALLBACK_INTERVAL 10 -#define LINE6_FALLBACK_MAXPACKETSIZE 16 +#define LINE6_FALLBACK_INTERVAL 10 +#define LINE6_FALLBACK_MAXPACKETSIZE 16 #endif diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index 81241cdf1be..d36622228b2 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -572,14 +572,10 @@ static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2); static void variax_destruct(struct usb_interface *interface) { struct usb_line6_variax *variax = usb_get_intfdata(interface); - struct usb_line6 *line6; if (variax == NULL) return; - line6 = &variax->line6; - if (line6 == NULL) - return; - line6_cleanup_audio(line6); + line6_cleanup_audio(&variax->line6); del_timer(&variax->startup_timer1); del_timer(&variax->startup_timer2); diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c index 8bf34794489..4ac3696883c 100644 --- a/drivers/staging/mei/init.c +++ b/drivers/staging/mei/init.c @@ -38,7 +38,6 @@ void mei_io_list_init(struct mei_io_list *list) { /* initialize our queue list */ INIT_LIST_HEAD(&list->mei_cb.cb_list); - list->status = 0; } /** @@ -49,22 +48,15 @@ void mei_io_list_init(struct mei_io_list *list) */ void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) { - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; + struct mei_cl_cb *pos; + struct mei_cl_cb *next; - if (list->status != 0) - return; - - if (list_empty(&list->mei_cb.cb_list)) - return; - - list_for_each_entry_safe(cb_pos, cb_next, - &list->mei_cb.cb_list, cb_list) { - if (cb_pos) { + list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { + if (pos->file_private) { struct mei_cl *cl_tmp; - cl_tmp = (struct mei_cl *)cb_pos->file_private; + cl_tmp = (struct mei_cl *)pos->file_private; if (mei_cl_cmp_id(cl, cl_tmp)) - list_del(&cb_pos->cb_list); + list_del(&pos->cb_list); } } } @@ -338,16 +330,10 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) } } /* remove all waiting requests */ - if (dev->write_list.status == 0 && - !list_empty(&dev->write_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - if (cb_pos) { - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb_pos); - cb_pos = NULL; - } - } + list_for_each_entry_safe(cb_pos, cb_next, + &dev->write_list.mei_cb.cb_list, cb_list) { + list_del(&cb_pos->cb_list); + mei_free_cb_private(cb_pos); } } @@ -380,8 +366,7 @@ void mei_host_start_message(struct mei_device *dev) host_start_req->host_version.major_version = HBM_MAJOR_VERSION; host_start_req->host_version.minor_version = HBM_MINOR_VERSION; dev->recvd_msg = false; - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) (host_start_req), + if (!mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, mei_hdr->length)) { dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); dev->mei_state = MEI_RESETING; @@ -414,8 +399,7 @@ void mei_host_enum_clients_message(struct mei_device *dev) host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD; - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) (host_enum_req), + if (!mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, mei_hdr->length)) { dev->mei_state = MEI_RESETING; dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); @@ -605,15 +589,10 @@ void mei_host_init_iamthif(struct mei_device *dev) return; } - /* Do not render the system unusable when iamthif_mtu is not equal to - the value received from ME. - Assign iamthif_mtu to the value received from ME in order to solve the - hardware macro incompatibility. */ + /* Assign iamthif_mtu to the value received from ME */ - dev_dbg(&dev->pdev->dev, "[DEFAULT] IAMTHIF = %d\n", dev->iamthif_mtu); dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; - dev_dbg(&dev->pdev->dev, - "IAMTHIF = %d\n", + dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", dev->me_clients[i].props.max_msg_length); kfree(dev->iamthif_msg_buf); diff --git a/drivers/staging/mei/interface.c b/drivers/staging/mei/interface.c index a65dacf0021..eb5df7fc226 100644 --- a/drivers/staging/mei/interface.c +++ b/drivers/staging/mei/interface.c @@ -128,9 +128,9 @@ int mei_count_empty_write_slots(struct mei_device *dev) * returns 1 if success, 0 - otherwise. */ int mei_write_message(struct mei_device *dev, - struct mei_msg_hdr *header, - unsigned char *write_buffer, - unsigned long write_length) + struct mei_msg_hdr *header, + unsigned char *write_buffer, + unsigned long write_length) { u32 temp_msg = 0; unsigned long bytes_written = 0; @@ -216,7 +216,7 @@ int mei_count_full_read_slots(struct mei_device *dev) * @buffer_length: message size will be read */ void mei_read_slots(struct mei_device *dev, - unsigned char *buffer, unsigned long buffer_length) + unsigned char *buffer, unsigned long buffer_length) { u32 i = 0; unsigned char temp_buf[sizeof(u32)]; diff --git a/drivers/staging/mei/interface.h b/drivers/staging/mei/interface.h index 7bd38ae2c23..aeae511419c 100644 --- a/drivers/staging/mei/interface.h +++ b/drivers/staging/mei/interface.h @@ -52,6 +52,17 @@ int mei_wd_send(struct mei_device *dev); int mei_wd_stop(struct mei_device *dev, bool preserve); bool mei_wd_host_init(struct mei_device *dev); void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout); +/* + * mei_watchdog_register - Registering watchdog interface + * once we got connection to the WD Client + * @dev - mei device + */ +void mei_watchdog_register(struct mei_device *dev); +/* + * mei_watchdog_unregister - Uegistering watchdog interface + * @dev - mei device + */ +void mei_watchdog_unregister(struct mei_device *dev); int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl); diff --git a/drivers/staging/mei/interrupt.c b/drivers/staging/mei/interrupt.c index 882d106d54e..3544fee34e4 100644 --- a/drivers/staging/mei/interrupt.c +++ b/drivers/staging/mei/interrupt.c @@ -198,8 +198,7 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, unsigned char *buffer = NULL; dev_dbg(&dev->pdev->dev, "start client msg\n"); - if (!(dev->read_list.status == 0 && - !list_empty(&dev->read_list.mei_cb.cb_list))) + if (list_empty(&dev->read_list.mei_cb.cb_list)) goto quit; list_for_each_entry_safe(cb_pos, cb_next, @@ -210,9 +209,6 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, buffer = (unsigned char *) (cb_pos->response_buffer.data + cb_pos->information); - BUG_ON(cb_pos->response_buffer.size < - mei_hdr->length + - cb_pos->information); if (cb_pos->response_buffer.size < mei_hdr->length + cb_pos->information) { @@ -390,24 +386,10 @@ static void mei_client_connect_response(struct mei_device *dev, /* if WD or iamthif client treat specially */ if (is_treat_specially_client(&(dev->wd_cl), rs)) { - dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", - dev->wd_timeout); - - dev->wd_due_counter = (dev->wd_timeout) ? 1 : 0; - dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); + mei_watchdog_register(dev); - /* Registering watchdog interface device once we got connection - to the WD Client - */ - if (watchdog_register_device(&amt_wd_dev)) { - printk(KERN_ERR "mei: unable to register watchdog device.\n"); - dev->wd_interface_reg = false; - } else { - dev_dbg(&dev->pdev->dev, "successfully register watchdog interface.\n"); - dev->wd_interface_reg = true; - } - + /* next step in the state maching */ mei_host_init_iamthif(dev); return; } @@ -416,22 +398,20 @@ static void mei_client_connect_response(struct mei_device *dev, dev->iamthif_state = MEI_IAMTHIF_IDLE; return; } - if (!dev->ctrl_rd_list.status && - !list_empty(&dev->ctrl_rd_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - if (!cl) { + list_for_each_entry_safe(cb_pos, cb_next, + &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { + + cl = (struct mei_cl *)cb_pos->file_private; + if (!cl) { + list_del(&cb_pos->cb_list); + return; + } + if (MEI_IOCTL == cb_pos->major_file_operations) { + if (is_treat_specially_client(cl, rs)) { list_del(&cb_pos->cb_list); - return; - } - if (MEI_IOCTL == cb_pos->major_file_operations) { - if (is_treat_specially_client(cl, rs)) { - list_del(&cb_pos->cb_list); - cl->status = 0; - cl->timer_count = 0; - break; - } + cl->status = 0; + cl->timer_count = 0; + break; } } } @@ -458,29 +438,26 @@ static void mei_client_disconnect_response(struct mei_device *dev, rs->host_addr, rs->status); - if (!dev->ctrl_rd_list.status && - !list_empty(&dev->ctrl_rd_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; + list_for_each_entry_safe(cb_pos, cb_next, + &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { + cl = (struct mei_cl *)cb_pos->file_private; - if (!cl) { - list_del(&cb_pos->cb_list); - return; - } + if (!cl) { + list_del(&cb_pos->cb_list); + return; + } - dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n"); - if (cl->host_client_id == rs->host_addr && - cl->me_client_id == rs->me_addr) { + dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n"); + if (cl->host_client_id == rs->host_addr && + cl->me_client_id == rs->me_addr) { - list_del(&cb_pos->cb_list); - if (!rs->status) - cl->state = MEI_FILE_DISCONNECTED; + list_del(&cb_pos->cb_list); + if (!rs->status) + cl->state = MEI_FILE_DISCONNECTED; - cl->status = 0; - cl->timer_count = 0; - break; - } + cl->status = 0; + cl->timer_count = 0; + break; } } } @@ -718,7 +695,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case CLIENT_DISCONNECT_RES_CMD: disconnect_res = (struct hbm_client_connect_response *) mei_msg; - mei_client_disconnect_response(dev, disconnect_res); + mei_client_disconnect_response(dev, disconnect_res); dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); wake_up(&dev->wait_recvd_msg); break; @@ -736,7 +713,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, mei_reset(dev, 1); return; } - if (dev->me_clients[dev->me_client_presentation_num] + if (dev->me_clients[dev->me_client_presentation_num] .client_id == props_res->address) { dev->me_clients[dev->me_client_presentation_num].props @@ -1228,7 +1205,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, { struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; + struct mei_cl_cb *pos = NULL, *next = NULL; struct mei_io_list *list; int ret; @@ -1241,36 +1218,31 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); list = &dev->write_waiting_list; - if (!list->status && !list_empty(&list->mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &list->mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - if (cl) { - cl->status = 0; - list_del(&cb_pos->cb_list); - if (MEI_WRITING == cl->writing_state && - (cb_pos->major_file_operations == - MEI_WRITE) && - (cl != &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, - "MEI WRITE COMPLETE\n"); - cl->writing_state = - MEI_WRITE_COMPLETE; - list_add_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - } - if (cl == &dev->iamthif_cl) { - dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); - if (dev->iamthif_flow_control_pending) { - ret = - _mei_irq_thread_iamthif_read( - dev, slots); - if (ret) - return ret; - } - } + list_for_each_entry_safe(pos, next, + &list->mei_cb.cb_list, cb_list) { + cl = (struct mei_cl *)pos->file_private; + if (cl == NULL) + continue; + + cl->status = 0; + list_del(&pos->cb_list); + if (MEI_WRITING == cl->writing_state && + (pos->major_file_operations == MEI_WRITE) && + (cl != &dev->iamthif_cl)) { + dev_dbg(&dev->pdev->dev, + "MEI WRITE COMPLETE\n"); + cl->writing_state = MEI_WRITE_COMPLETE; + list_add_tail(&pos->cb_list, + &cmpl_list->mei_cb.cb_list); + } + if (cl == &dev->iamthif_cl) { + dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); + if (dev->iamthif_flow_control_pending) { + ret = _mei_irq_thread_iamthif_read( + dev, slots); + if (ret) + return ret; } - } } @@ -1317,101 +1289,88 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, return ~ENODEV; /* complete control write list CB */ - if (!dev->ctrl_wr_list.status) { - /* complete control write list CB */ - dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); - list_for_each_entry_safe(cb_pos, cb_next, + dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); + list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *) - cb_pos->file_private; - if (!cl) { - list_del(&cb_pos->cb_list); - return -ENODEV; - } - switch (cb_pos->major_file_operations) { - case MEI_CLOSE: - /* send disconnect message */ - ret = _mei_irq_thread_close(dev, slots, - cb_pos, cl, cmpl_list); - if (ret) - return ret; - - break; - case MEI_READ: - /* send flow control message */ - ret = _mei_irq_thread_read(dev, slots, - cb_pos, cl, cmpl_list); - if (ret) - return ret; + cl = (struct mei_cl *) pos->file_private; + if (!cl) { + list_del(&pos->cb_list); + return -ENODEV; + } + switch (pos->major_file_operations) { + case MEI_CLOSE: + /* send disconnect message */ + ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list); + if (ret) + return ret; - break; - case MEI_IOCTL: - /* connect message */ - if (!mei_other_client_is_connecting(dev, - cl)) - continue; - ret = _mei_irq_thread_ioctl(dev, slots, - cb_pos, cl, cmpl_list); - if (ret) - return ret; + break; + case MEI_READ: + /* send flow control message */ + ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list); + if (ret) + return ret; - break; + break; + case MEI_IOCTL: + /* connect message */ + if (mei_other_client_is_connecting(dev, cl)) + continue; + ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list); + if (ret) + return ret; - default: - BUG(); - } + break; + default: + BUG(); } + } /* complete write list CB */ - if (!dev->write_list.status && - !list_empty(&dev->write_list.mei_cb.cb_list)) { - dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - - if (cl) { - if (cl != &dev->iamthif_cl) { - if (!mei_flow_ctrl_creds(dev, - cl)) { - dev_dbg(&dev->pdev->dev, - "No flow control" - " credentials for client" - " %d, not sending.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl(dev, slots, - cb_pos, - cl, cmpl_list); - if (ret) - return ret; - - } else if (cl == &dev->iamthif_cl) { - /* IAMTHIF IOCTL */ - dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n"); - if (!mei_flow_ctrl_creds(dev, - cl)) { - dev_dbg(&dev->pdev->dev, - "No flow control" - " credentials for amthi" - " client %d.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl_iamthif(dev, - slots, - cb_pos, - cl, - cmpl_list); - if (ret) - return ret; - - } + dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); + list_for_each_entry_safe(pos, next, + &dev->write_list.mei_cb.cb_list, cb_list) { + cl = (struct mei_cl *)pos->file_private; + if (cl == NULL) + continue; + + if (cl != &dev->iamthif_cl) { + if (!mei_flow_ctrl_creds(dev, cl)) { + dev_dbg(&dev->pdev->dev, + "No flow control" + " credentials for client" + " %d, not sending.\n", + cl->host_client_id); + continue; + } + ret = _mei_irq_thread_cmpl(dev, slots, + pos, + cl, cmpl_list); + if (ret) + return ret; + + } else if (cl == &dev->iamthif_cl) { + /* IAMTHIF IOCTL */ + dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n"); + if (!mei_flow_ctrl_creds(dev, cl)) { + dev_dbg(&dev->pdev->dev, + "No flow control" + " credentials for amthi" + " client %d.\n", + cl->host_client_id); + continue; } + ret = _mei_irq_thread_cmpl_iamthif(dev, + slots, + pos, + cl, + cmpl_list); + if (ret) + return ret; } + } return 0; } @@ -1502,18 +1461,13 @@ void mei_timer(struct work_struct *work) amthi_complete_list = &dev->amthi_read_complete_list. mei_cb.cb_list; - if (!list_empty(amthi_complete_list)) { - - list_for_each_entry_safe(cb_pos, cb_next, - amthi_complete_list, - cb_list) { + list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) { - cl_pos = cb_pos->file_object->private_data; + cl_pos = cb_pos->file_object->private_data; - /* Finding the AMTHI entry. */ - if (cl_pos == &dev->iamthif_cl) - list_del(&cb_pos->cb_list); - } + /* Finding the AMTHI entry. */ + if (cl_pos == &dev->iamthif_cl) + list_del(&cb_pos->cb_list); } if (dev->iamthif_current_cb) mei_free_cb_private(dev->iamthif_current_cb); @@ -1527,8 +1481,8 @@ void mei_timer(struct work_struct *work) } } out: - schedule_delayed_work(&dev->timer_work, 2 * HZ); - mutex_unlock(&dev->device_lock); + schedule_delayed_work(&dev->timer_work, 2 * HZ); + mutex_unlock(&dev->device_lock); } /** @@ -1624,7 +1578,7 @@ end: wake_up_interruptible(&dev->wait_recvd_msg); bus_message_received = false; } - if (complete_list.status || list_empty(&complete_list.mei_cb.cb_list)) + if (list_empty(&complete_list.mei_cb.cb_list)) return IRQ_HANDLED; diff --git a/drivers/staging/mei/iorw.c b/drivers/staging/mei/iorw.c index 8a61d126651..0752ead4269 100644 --- a/drivers/staging/mei/iorw.c +++ b/drivers/staging/mei/iorw.c @@ -228,18 +228,15 @@ struct mei_cl_cb *find_amthi_read_list_entry( struct file *file) { struct mei_cl *cl_temp; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - - if (!dev->amthi_read_complete_list.status && - !list_empty(&dev->amthi_read_complete_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) { - cl_temp = (struct mei_cl *)cb_pos->file_private; - if (cl_temp && cl_temp == &dev->iamthif_cl && - cb_pos->file_object == file) - return cb_pos; - } + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; + + list_for_each_entry_safe(pos, next, + &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) { + cl_temp = (struct mei_cl *)pos->file_private; + if (cl_temp && cl_temp == &dev->iamthif_cl && + pos->file_object == file) + return pos; } return NULL; } @@ -262,7 +259,7 @@ struct mei_cl_cb *find_amthi_read_list_entry( * negative on failure. */ int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset) + char __user *ubuf, size_t length, loff_t *offset) { int rets; int wait_ret; @@ -334,8 +331,7 @@ int amthi_read(struct mei_device *dev, struct file *file, } } /* if the whole message will fit remove it from the list */ - if (cb->information >= *offset && - length >= (cb->information - *offset)) + if (cb->information >= *offset && length >= (cb->information - *offset)) list_del(&cb->cb_list); else if (cb->information > 0 && cb->information <= *offset) { /* end of the message has been reached */ @@ -356,9 +352,7 @@ int amthi_read(struct mei_device *dev, struct file *file, * the information may be longer */ length = min_t(size_t, length, (cb->information - *offset)); - if (copy_to_user(ubuf, - cb->response_buffer.data + *offset, - length)) + if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) rets = -EFAULT; else { rets = length; @@ -427,7 +421,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; cb->response_buffer.data = - kmalloc(cb->response_buffer.size, GFP_KERNEL); + kmalloc(cb->response_buffer.size, GFP_KERNEL); if (!cb->response_buffer.data) { rets = -ENOMEM; goto unlock; @@ -448,8 +442,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) &dev->read_list.mei_cb.cb_list); } } else { - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list); } return rets; unlock: @@ -482,7 +475,7 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) dev->iamthif_ioctl = true; dev->iamthif_msg_buf_size = cb->request_buffer.size; memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, - cb->request_buffer.size); + cb->request_buffer.size); ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); if (ret < 0) @@ -534,8 +527,7 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) dev_dbg(&dev->pdev->dev, "No flow control credentials, " "so add iamthif cb to write list.\n"); - list_add_tail(&cb->cb_list, - &dev->write_list.mei_cb.cb_list); + list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list); } return 0; } @@ -550,8 +542,8 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) void mei_run_next_iamthif_cmd(struct mei_device *dev) { struct mei_cl *cl_tmp; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; int status; if (!dev) @@ -565,25 +557,22 @@ void mei_run_next_iamthif_cmd(struct mei_device *dev) dev->iamthif_timer = 0; dev->iamthif_file_object = NULL; - if (dev->amthi_cmd_list.status == 0 && - !list_empty(&dev->amthi_cmd_list.mei_cb.cb_list)) { - dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); - - list_for_each_entry_safe(cb_pos, cb_next, - &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) { - list_del(&cb_pos->cb_list); - cl_tmp = (struct mei_cl *)cb_pos->file_private; - - if (cl_tmp && cl_tmp == &dev->iamthif_cl) { - status = amthi_write(dev, cb_pos); - if (status) { - dev_dbg(&dev->pdev->dev, - "amthi write failed status = %d\n", - status); - return; - } - break; + dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); + + list_for_each_entry_safe(pos, next, + &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) { + list_del(&pos->cb_list); + cl_tmp = (struct mei_cl *)pos->file_private; + + if (cl_tmp && cl_tmp == &dev->iamthif_cl) { + status = amthi_write(dev, pos); + if (status) { + dev_dbg(&dev->pdev->dev, + "amthi write failed status = %d\n", + status); + return; } + break; } } } diff --git a/drivers/staging/mei/main.c b/drivers/staging/mei/main.c index eb05c36f45d..1e1a9f996e7 100644 --- a/drivers/staging/mei/main.c +++ b/drivers/staging/mei/main.c @@ -33,6 +33,7 @@ #include <linux/compat.h> #include <linux/jiffies.h> #include <linux/interrupt.h> +#include <linux/miscdevice.h> #include "mei_dev.h" #include "mei.h" @@ -51,18 +52,10 @@ static char mei_driver_name[] = MEI_DRIVER_NAME; static const char mei_driver_string[] = "Intel(R) Management Engine Interface"; static const char mei_driver_version[] = MEI_DRIVER_VERSION; -/* mei char device for registration */ -static struct cdev mei_cdev; - -/* major number for device */ -static int mei_major; /* The device pointer */ /* Currently this driver works as long as there is only a single AMT device. */ struct pci_dev *mei_device; -static struct class *mei_class; - - /* mei_pci_tbl - PCI Device ID Table */ static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)}, @@ -105,173 +98,6 @@ MODULE_DEVICE_TABLE(pci, mei_pci_tbl); static DEFINE_MUTEX(mei_mutex); -/** - * mei_probe - Device Initialization Routine - * - * @pdev: PCI device structure - * @ent: entry in kcs_pci_tbl - * - * returns 0 on success, <0 on failure. - */ -static int __devinit mei_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct mei_device *dev; - int err; - - mutex_lock(&mei_mutex); - if (mei_device) { - err = -EEXIST; - goto end; - } - /* enable pci dev */ - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "mei: Failed to enable pci device.\n"); - goto end; - } - /* set PCI host mastering */ - pci_set_master(pdev); - /* pci request regions for mei driver */ - err = pci_request_regions(pdev, mei_driver_name); - if (err) { - printk(KERN_ERR "mei: Failed to get pci regions.\n"); - goto disable_device; - } - /* allocates and initializes the mei dev structure */ - dev = mei_device_init(pdev); - if (!dev) { - err = -ENOMEM; - goto release_regions; - } - /* mapping IO device memory */ - dev->mem_addr = pci_iomap(pdev, 0, 0); - if (!dev->mem_addr) { - printk(KERN_ERR "mei: mapping I/O device memory failure.\n"); - err = -ENOMEM; - goto free_device; - } - pci_enable_msi(pdev); - - /* request and enable interrupt */ - if (pci_dev_msi_enabled(pdev)) - err = request_threaded_irq(pdev->irq, - NULL, - mei_interrupt_thread_handler, - 0, mei_driver_name, dev); - else - err = request_threaded_irq(pdev->irq, - mei_interrupt_quick_handler, - mei_interrupt_thread_handler, - IRQF_SHARED, mei_driver_name, dev); - - if (err) { - printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n", - pdev->irq); - goto unmap_memory; - } - INIT_DELAYED_WORK(&dev->timer_work, mei_timer); - if (mei_hw_init(dev)) { - printk(KERN_ERR "mei: Init hw failure.\n"); - err = -ENODEV; - goto release_irq; - } - mei_device = pdev; - pci_set_drvdata(pdev, dev); - schedule_delayed_work(&dev->timer_work, HZ); - - mutex_unlock(&mei_mutex); - - pr_debug("mei: Driver initialization successful.\n"); - - return 0; - -release_irq: - /* disable interrupts */ - dev->host_hw_state = mei_hcsr_read(dev); - mei_disable_interrupts(dev); - flush_scheduled_work(); - free_irq(pdev->irq, dev); - pci_disable_msi(pdev); -unmap_memory: - pci_iounmap(pdev, dev->mem_addr); -free_device: - kfree(dev); -release_regions: - pci_release_regions(pdev); -disable_device: - pci_disable_device(pdev); -end: - mutex_unlock(&mei_mutex); - printk(KERN_ERR "mei: Driver initialization failed.\n"); - return err; -} - -/** - * mei_remove - Device Removal Routine - * - * @pdev: PCI device structure - * - * mei_remove is called by the PCI subsystem to alert the driver - * that it should release a PCI device. - */ -static void __devexit mei_remove(struct pci_dev *pdev) -{ - struct mei_device *dev; - - if (mei_device != pdev) - return; - - dev = pci_get_drvdata(pdev); - if (!dev) - return; - - mutex_lock(&dev->device_lock); - - mei_wd_stop(dev, false); - - mei_device = NULL; - - if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { - dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; - mei_disconnect_host_client(dev, &dev->iamthif_cl); - } - if (dev->wd_cl.state == MEI_FILE_CONNECTED) { - dev->wd_cl.state = MEI_FILE_DISCONNECTING; - mei_disconnect_host_client(dev, &dev->wd_cl); - } - - /* Unregistering watchdog device */ - if (dev->wd_interface_reg) - watchdog_unregister_device(&amt_wd_dev); - - /* remove entry if already in list */ - dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); - mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); - - dev->iamthif_current_cb = NULL; - dev->me_clients_num = 0; - - mutex_unlock(&dev->device_lock); - - flush_scheduled_work(); - - /* disable interrupts */ - mei_disable_interrupts(dev); - - free_irq(pdev->irq, dev); - pci_disable_msi(pdev); - pci_set_drvdata(pdev, NULL); - - if (dev->mem_addr) - pci_iounmap(pdev, dev->mem_addr); - - kfree(dev); - - pci_release_regions(pdev); - pci_disable_device(pdev); -} /** * mei_clear_list - removes all callbacks associated with file @@ -372,21 +198,17 @@ static struct mei_cl_cb *find_read_list_entry( struct mei_device *dev, struct mei_cl *cl) { - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - - if (!dev->read_list.status && - !list_empty(&dev->read_list.mei_cb.cb_list)) { + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; - dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->read_list.mei_cb.cb_list, cb_list) { - struct mei_cl *cl_temp; - cl_temp = (struct mei_cl *)cb_pos->file_private; + dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); + list_for_each_entry_safe(pos, next, + &dev->read_list.mei_cb.cb_list, cb_list) { + struct mei_cl *cl_temp; + cl_temp = (struct mei_cl *)pos->file_private; - if (mei_cl_cmp_id(cl, cl_temp)) - return cb_pos; - } + if (mei_cl_cmp_id(cl, cl_temp)) + return pos; } return NULL; } @@ -402,15 +224,16 @@ static struct mei_cl_cb *find_read_list_entry( static int mei_open(struct inode *inode, struct file *file) { struct mei_cl *cl; - int if_num = iminor(inode), err; struct mei_device *dev; + unsigned long cl_id; + int err; err = -ENODEV; if (!mei_device) goto out; dev = pci_get_drvdata(mei_device); - if (if_num != MEI_MINOR_NUMBER || !dev) + if (!dev) goto out; mutex_lock(&dev->device_lock); @@ -429,14 +252,16 @@ static int mei_open(struct inode *inode, struct file *file) if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) goto out_unlock; - cl->host_client_id = find_first_zero_bit(dev->host_clients_map, - MEI_CLIENTS_MAX); - if (cl->host_client_id > MEI_CLIENTS_MAX) + cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX); + if (cl_id >= MEI_CLIENTS_MAX) goto out_unlock; + cl->host_client_id = cl_id; + dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id); dev->open_handle_count++; + list_add_tail(&cl->link, &dev->file_list); set_bit(cl->host_client_id, dev->host_clients_map); @@ -446,7 +271,7 @@ static int mei_open(struct inode *inode, struct file *file) file->private_data = cl; mutex_unlock(&dev->device_lock); - return 0; + return nonseekable_open(inode, file); out_unlock: mutex_unlock(&dev->device_lock); @@ -492,8 +317,7 @@ static int mei_release(struct inode *inode, struct file *file) cl->me_client_id); if (dev->open_handle_count > 0) { - clear_bit(cl->host_client_id, - dev->host_clients_map); + clear_bit(cl->host_client_id, dev->host_clients_map); dev->open_handle_count--; } mei_remove_client_from_file_list(dev, cl->host_client_id); @@ -554,7 +378,7 @@ static int mei_release(struct inode *inode, struct file *file) * returns >=0 data length on success , <0 on error */ static ssize_t mei_read(struct file *file, char __user *ubuf, - size_t length, loff_t *offset) + size_t length, loff_t *offset) { struct mei_cl *cl = file->private_data; struct mei_cl_cb *cb_pos = NULL; @@ -673,9 +497,7 @@ copy_buffer: /* information size may be longer */ length = min_t(size_t, length, (cb->information - *offset)); - if (copy_to_user(ubuf, - cb->response_buffer.data + *offset, - length)) { + if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) { rets = -EFAULT; goto free; } @@ -711,7 +533,7 @@ out: * returns >=0 data length on success , <0 on error */ static ssize_t mei_write(struct file *file, const char __user *ubuf, - size_t length, loff_t *offset) + size_t length, loff_t *offset) { struct mei_cl *cl = file->private_data; struct mei_cl_cb *write_cb = NULL; @@ -762,8 +584,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, cl->read_cb = NULL; cl->read_pending = 0; } - } else if (cl->reading_state == MEI_IDLE && - !cl->read_pending) + } else if (cl->reading_state == MEI_IDLE && !cl->read_pending) *offset = 0; @@ -1034,7 +855,7 @@ out: */ #ifdef CONFIG_COMPAT static long mei_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long data) + unsigned int cmd, unsigned long data) { return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data)); } @@ -1090,6 +911,206 @@ out: return mask; } +/* + * file operations structure will be used for mei char device. + */ +static const struct file_operations mei_fops = { + .owner = THIS_MODULE, + .read = mei_read, + .unlocked_ioctl = mei_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mei_compat_ioctl, +#endif + .open = mei_open, + .release = mei_release, + .write = mei_write, + .poll = mei_poll, + .llseek = no_llseek +}; + + +/* + * Misc Device Struct + */ +static struct miscdevice mei_misc_device = { + .name = MEI_DRIVER_NAME, + .fops = &mei_fops, + .minor = MISC_DYNAMIC_MINOR, +}; + +/** + * mei_probe - Device Initialization Routine + * + * @pdev: PCI device structure + * @ent: entry in kcs_pci_tbl + * + * returns 0 on success, <0 on failure. + */ +static int __devinit mei_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct mei_device *dev; + int err; + + mutex_lock(&mei_mutex); + if (mei_device) { + err = -EEXIST; + goto end; + } + /* enable pci dev */ + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "mei: Failed to enable pci device.\n"); + goto end; + } + /* set PCI host mastering */ + pci_set_master(pdev); + /* pci request regions for mei driver */ + err = pci_request_regions(pdev, mei_driver_name); + if (err) { + printk(KERN_ERR "mei: Failed to get pci regions.\n"); + goto disable_device; + } + /* allocates and initializes the mei dev structure */ + dev = mei_device_init(pdev); + if (!dev) { + err = -ENOMEM; + goto release_regions; + } + /* mapping IO device memory */ + dev->mem_addr = pci_iomap(pdev, 0, 0); + if (!dev->mem_addr) { + printk(KERN_ERR "mei: mapping I/O device memory failure.\n"); + err = -ENOMEM; + goto free_device; + } + pci_enable_msi(pdev); + + /* request and enable interrupt */ + if (pci_dev_msi_enabled(pdev)) + err = request_threaded_irq(pdev->irq, + NULL, + mei_interrupt_thread_handler, + 0, mei_driver_name, dev); + else + err = request_threaded_irq(pdev->irq, + mei_interrupt_quick_handler, + mei_interrupt_thread_handler, + IRQF_SHARED, mei_driver_name, dev); + + if (err) { + printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n", + pdev->irq); + goto unmap_memory; + } + INIT_DELAYED_WORK(&dev->timer_work, mei_timer); + if (mei_hw_init(dev)) { + printk(KERN_ERR "mei: Init hw failure.\n"); + err = -ENODEV; + goto release_irq; + } + + err = misc_register(&mei_misc_device); + if (err) + goto release_irq; + + mei_device = pdev; + pci_set_drvdata(pdev, dev); + + + schedule_delayed_work(&dev->timer_work, HZ); + + mutex_unlock(&mei_mutex); + + pr_debug("mei: Driver initialization successful.\n"); + + return 0; + +release_irq: + /* disable interrupts */ + dev->host_hw_state = mei_hcsr_read(dev); + mei_disable_interrupts(dev); + flush_scheduled_work(); + free_irq(pdev->irq, dev); + pci_disable_msi(pdev); +unmap_memory: + pci_iounmap(pdev, dev->mem_addr); +free_device: + kfree(dev); +release_regions: + pci_release_regions(pdev); +disable_device: + pci_disable_device(pdev); +end: + mutex_unlock(&mei_mutex); + printk(KERN_ERR "mei: Driver initialization failed.\n"); + return err; +} + +/** + * mei_remove - Device Removal Routine + * + * @pdev: PCI device structure + * + * mei_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. + */ +static void __devexit mei_remove(struct pci_dev *pdev) +{ + struct mei_device *dev; + + if (mei_device != pdev) + return; + + dev = pci_get_drvdata(pdev); + if (!dev) + return; + + mutex_lock(&dev->device_lock); + + mei_wd_stop(dev, false); + + mei_device = NULL; + + if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { + dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; + mei_disconnect_host_client(dev, &dev->iamthif_cl); + } + if (dev->wd_cl.state == MEI_FILE_CONNECTED) { + dev->wd_cl.state = MEI_FILE_DISCONNECTING; + mei_disconnect_host_client(dev, &dev->wd_cl); + } + + /* Unregistering watchdog device */ + mei_watchdog_unregister(dev); + + /* remove entry if already in list */ + dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); + mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); + mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); + + dev->iamthif_current_cb = NULL; + dev->me_clients_num = 0; + + mutex_unlock(&dev->device_lock); + + flush_scheduled_work(); + + /* disable interrupts */ + mei_disable_interrupts(dev); + + free_irq(pdev->irq, dev); + pci_disable_msi(pdev); + pci_set_drvdata(pdev, NULL); + + if (dev->mem_addr) + pci_iounmap(pdev, dev->mem_addr); + + kfree(dev); + + pci_release_regions(pdev); + pci_disable_device(pdev); +} #ifdef CONFIG_PM static int mei_pci_suspend(struct device *device) { @@ -1173,131 +1194,6 @@ static struct pci_driver mei_driver = { .driver.pm = MEI_PM_OPS, }; -/* - * file operations structure will be used for mei char device. - */ -static const struct file_operations mei_fops = { - .owner = THIS_MODULE, - .read = mei_read, - .unlocked_ioctl = mei_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mei_compat_ioctl, -#endif - .open = mei_open, - .release = mei_release, - .write = mei_write, - .poll = mei_poll, -}; - -/** - * mei_registration_cdev - sets up the cdev structure for mei device. - * - * @dev: char device struct - * @hminor: minor number for registration char device - * @fops: file operations structure - * - * returns 0 on success, <0 on failure. - */ -static int mei_registration_cdev(struct cdev *dev, int hminor, - const struct file_operations *fops) -{ - int ret, devno = MKDEV(mei_major, hminor); - - cdev_init(dev, fops); - dev->owner = THIS_MODULE; - ret = cdev_add(dev, devno, 1); - /* Fail gracefully if need be */ - if (ret) - printk(KERN_ERR "mei: Error %d registering mei device %d\n", - ret, hminor); - return ret; -} - -/** - * mei_register_cdev - registers mei char device - * - * returns 0 on success, <0 on failure. - */ -static int mei_register_cdev(void) -{ - int ret; - dev_t dev; - - /* registration of char devices */ - ret = alloc_chrdev_region(&dev, MEI_MINORS_BASE, MEI_MINORS_COUNT, - MEI_DRIVER_NAME); - if (ret) { - printk(KERN_ERR "mei: Error allocating char device region.\n"); - return ret; - } - - mei_major = MAJOR(dev); - - ret = mei_registration_cdev(&mei_cdev, MEI_MINOR_NUMBER, - &mei_fops); - if (ret) - unregister_chrdev_region(MKDEV(mei_major, MEI_MINORS_BASE), - MEI_MINORS_COUNT); - - return ret; -} - -/** - * mei_unregister_cdev - unregisters mei char device - */ -static void mei_unregister_cdev(void) -{ - cdev_del(&mei_cdev); - unregister_chrdev_region(MKDEV(mei_major, MEI_MINORS_BASE), - MEI_MINORS_COUNT); -} - -/** - * mei_sysfs_device_create - adds device entry to sysfs - * - * returns 0 on success, <0 on failure. - */ -static int mei_sysfs_device_create(void) -{ - struct class *class; - void *tmphdev; - int err; - - class = class_create(THIS_MODULE, MEI_DRIVER_NAME); - if (IS_ERR(class)) { - err = PTR_ERR(class); - printk(KERN_ERR "mei: Error creating mei class.\n"); - goto err_out; - } - - tmphdev = device_create(class, NULL, mei_cdev.dev, NULL, - MEI_DEV_NAME); - if (IS_ERR(tmphdev)) { - err = PTR_ERR(tmphdev); - goto err_destroy; - } - - mei_class = class; - return 0; - -err_destroy: - class_destroy(class); -err_out: - return err; -} - -/** - * mei_sysfs_device_remove - unregisters the device entry on sysfs - */ -static void mei_sysfs_device_remove(void) -{ - if (IS_ERR_OR_NULL(mei_class)) - return; - - device_destroy(mei_class, mei_cdev.dev); - class_destroy(mei_class); -} - /** * mei_init_module - Driver Registration Routine * @@ -1314,26 +1210,9 @@ static int __init mei_init_module(void) mei_driver_string, mei_driver_version); /* init pci module */ ret = pci_register_driver(&mei_driver); - if (ret < 0) { + if (ret < 0) printk(KERN_ERR "mei: Error registering driver.\n"); - goto end; - } - ret = mei_register_cdev(); - if (ret) - goto unregister_pci; - - ret = mei_sysfs_device_create(); - if (ret) - goto unregister_cdev; - - return ret; - -unregister_cdev: - mei_unregister_cdev(); -unregister_pci: - pci_unregister_driver(&mei_driver); -end: return ret; } @@ -1347,8 +1226,7 @@ module_init(mei_init_module); */ static void __exit mei_exit_module(void) { - mei_sysfs_device_remove(); - mei_unregister_cdev(); + misc_deregister(&mei_misc_device); pci_unregister_driver(&mei_driver); pr_debug("mei: Driver unloaded successfully.\n"); diff --git a/drivers/staging/mei/mei.txt b/drivers/staging/mei/mei.txt index 17302ad2531..516bfe7319a 100644 --- a/drivers/staging/mei/mei.txt +++ b/drivers/staging/mei/mei.txt @@ -1,78 +1,74 @@ -Intel MEI +Intel(R) Management Engine Interface (Intel(R) MEI) ======================= Introduction ======================= -The Intel Management Engine (Intel ME) is an isolated and -protected computing resource (Coprocessor) residing inside -Intel chipsets. The Intel ME provides support for computer/IT -management features. -The Feature set depends on the Intel chipset SKU. +The Intel Management Engine (Intel ME) is an isolated andprotected computing +resource (Co-processor) residing inside certain Intel chipsets. The Intel ME +provides support for computer/IT management features. The feature set +depends on the Intel chipset SKU. -The Intel Management Engine Interface (Intel MEI, previously known -as HECI) is the interface between the Host and Intel ME. -This interface is exposed to the host as a PCI device. -The Intel MEI Driver is in charge of the communication channel -between a host application and the ME feature. +The Intel Management Engine Interface (Intel MEI, previously known as HECI) +is the interface between the Host and Intel ME. This interface is exposed +to the host as a PCI device. The Intel MEI Driver is in charge of the +communication channel between a host application and the Intel ME feature. -Each Intel ME feature (Intel ME Client) is addressed by -GUID/UUID and each feature defines its own protocol. -The protocol is message-based with a header and payload up to -512 bytes. +Each Intel ME feature (Intel ME Client) is addressed by a GUID/UUID and +each client has its own protocol. The protocol is message-based with a +header and payload up to 512 bytes. -[place holder to URL to protocol definitions] - -Prominent usage of the Interface is to communicate with -Intel Active Management Technology (Intel AMT) -implemented in firmware running on the Intel ME. +Prominent usage of the Intel ME Interface is to communicate with Intel(R) +Active Management Technology (Intel AMT)implemented in firmware running on +the Intel ME. Intel AMT provides the ability to manage a host remotely out-of-band (OOB) -even when the host processor has crashed or is in a sleep state. +even when the operating system running on the host processor has crashed or +is in a sleep state. Some examples of Intel AMT usage are: - Monitoring hardware state and platform components - - Remote power off/on (useful for green computing or overnight IT maintenance) + - Remote power off/on (useful for green computing or overnight IT + maintenance) - OS updates - Storage of useful platform information such as software assets - - built-in hardware KVM - - selective network isolation of Ethernet and IP protocol flows based on - policies set by a remote management console + - Built-in hardware KVM + - Selective network isolation of Ethernet and IP protocol flows based + on policies set by a remote management console - IDE device redirection from remote management console Intel AMT (OOB) communication is based on SOAP (deprecated -starting with Release 6.0) over HTTP/HTTPS or WS-Management protocol -over HTTP and HTTPS that are received from a remote -management console application. +starting with Release 6.0) over HTTP/S or WS-Management protocol over +HTTP/S that are received from a remote management console application. For more information about Intel AMT: -http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/aboutintelamt.htm - +http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide -MEI Driver +Intel MEI Driver ======================= -The driver exposes a character device called /dev/mei. +The driver exposes a misc device called /dev/mei. -An application maintains communication with an ME feature while -/dev/mei is open. The binding to a specific features is performed -by calling MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID. -The number of instances of an ME feature that can be opened -at the same time depends on the ME feature, but most of the +An application maintains communication with an Intel ME feature while +/dev/mei is open. The binding to a specific features is performed by calling +MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID. +The number of instances of an Intel ME feature that can be opened +at the same time depends on the Intel ME feature, but most of the features allow only a single instance. - -The Intel AMT Host Interface (AMTHI) feature requires multiple -simultaneous user applications, therefore the MEI driver handles +The Intel AMT Host Interface (Intel AMTHI) feature supports multiple +simultaneous user applications. Therefore, the Intel MEI driver handles this internally by maintaining request queues for the applications. -The driver is oblivious to data that are passed between +The driver is oblivious to data that is passed between firmware feature +and host application. -Because some of the ME features can change the system -configuration, the driver by default allows only privileged +Because some of the Intel ME features can change the system +configuration, the driver by default allows only a privileged user to access it. -A Code snippet for application communicating with AMTHI client: +A code snippet for an application communicating with +Intel AMTHI client: struct mei_connect_client_data data; fd = open(MEI_DEVICE); @@ -80,7 +76,7 @@ A Code snippet for application communicating with AMTHI client: ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data); - printf(“Ver=%d, MaxLen=%ld\n”, + printf("Ver=%d, MaxLen=%ld\n", data.d.in_client_uuid.protocol_version, data.d.in_client_uuid.max_msg_length); @@ -95,76 +91,106 @@ A Code snippet for application communicating with AMTHI client: [...] close(fd); -ME Applications: +IOCTL: +====== +The Intel MEI Driver supports the following IOCTL command: + IOCTL_MEI_CONNECT_CLIENT Connect to firmware Feature (client). + + usage: + struct mei_connect_client_data clientData; + ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &clientData); + + inputs: + mei_connect_client_data struct contain the following + input field: + + in_client_uuid - UUID of the FW Feature that needs + to connect to. + outputs: + out_client_properties - Client Properties: MTU and Protocol Version. + + error returns: + EINVAL Wrong IOCTL Number + ENODEV Device or Connection is not initialized or ready. + (e.g. Wrong UUID) + ENOMEM Unable to allocate memory to client internal data. + EFAULT Fatal Error (e.g. Unable to access user input data) + EBUSY Connection Already Open + + Notes: + max_msg_length (MTU) in client properties describes the maximum + data that can be sent or received. (e.g. if MTU=2K, can send + requests up to bytes 2k and received responses upto 2k bytes). + +Intel ME Applications: ============== 1) Intel Local Management Service (Intel LMS) - Applications running locally on the platform communicate with - Intel AMT Release 2.0 and later releases in the same way - that network applications do via SOAP over HTTP (deprecated - starting with Release 6.0) or with WS-Management over SOAP over - HTTP. which means that some Intel AMT feature can be access - from a local application using same Network interface as for - remote application. - - When a local application sends a message addressed to the local - Intel AMT host name, the Local Manageability Service (LMS), - which listens for traffic directed to the host name, intercepts - the message and routes it to the Intel Management Engine Interface. + + Applications running locally on the platform communicate with Intel AMT Release + 2.0 and later releases in the same way that network applications do via SOAP + over HTTP (deprecated starting with Release 6.0) or with WS-Management over + SOAP over HTTP. This means that some Intel AMT features can be accessed from a + local application using the same network interface as a remote application + communicating with Intel AMT over the network. + + When a local application sends a message addressed to the local Intel AMT host + name, the Intel LMS, which listens for traffic directed to the host name, + intercepts the message and routes it to the Intel MEI. For more information: - http://software.intel.com/sites/manageability/AMT_Implementation_and_ - Reference_Guide/WordDocuments/localaccess1.htm - - The LMS opens a connection using the MEI driver to the LMS - FW feature using a defined UUID and then communicates with the - feature using a protocol - called Intel(R) AMT Port Forwarding Protocol (APF protocol). - The protocol is used to maintain multiple sessions with - Intel AMT from a single application. - See the protocol specification in - the Intel(R) AMT Implementation and Reference Guide - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/HTMLDocuments/MPSDocuments/Intel%20AMT%20Port%20Forwarding%20Protocol%20Reference%20Manual.pdf - - 2) Intel AMT Remote configuration using a Local Agent: + http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide + Under "About Intel AMT" => "Local Access" + + For downloading Intel LMS: + http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/ + + The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS + firmware feature using a defined UUID and then communicates with the feature + using a protocol called Intel AMT Port Forwarding Protocol(Intel APF protocol). + The protocol is used to maintain multiple sessions with Intel AMT from a + single application. + + See the protocol specification in the Intel AMT Software Development Kit(SDK) + http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide + Under "SDK Resources" => "Intel(R) vPro(TM) Gateway(MPS)" + => "Information for Intel(R) vPro(TM) Gateway Developers" + => "Description of the Intel AMT Port Forwarding (APF)Protocol" + + 2) Intel AMT Remote configuration using a Local Agent A Local Agent enables IT personnel to configure Intel AMT out-of-the-box - without requiring installing additional data to enable setup. - The remote configuration process may involve an ISV-developed remote - configuration agent that runs on the host. + without requiring installing additional data to enable setup. The remote + configuration process may involve an ISV-developed remote configuration + agent that runs on the host. For more information: - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/remoteconfigurationwithalocalagent.htm + http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide + Under "Setup and Configuration of Intel AMT" => + "SDK Tools Supporting Setup and Configuration" => + "Using the Local Agent Sample" + + An open source Intel AMT configuration utility, implementing a local agent + that accesses the Intel MEI driver, can be found here: + http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/ - How the Local Agent Works (including Command structs): - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/howthelocalagentsampleworks.htm Intel AMT OS Health Watchdog: ============================= The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog. Whenever the OS hangs or crashes, Intel AMT will send an event -to whoever subscribed to this event. This mechanism means that -IT knows when a platform crashes even when there is a hard failure -on the host. -The AMT Watchdog is composed of two parts: - 1) FW Feature - that receives the heartbeats - and sends an event when the heartbeats stop. - 2) MEI driver – connects to the watchdog (WD) feature, - configures the watchdog and sends the heartbeats. - -The MEI driver configures the Watchdog to expire by default -every 120sec unless set by the user using module parameters. -The Driver then sends heartbeats every 2sec. +to any subsciber to this event. This mechanism means that +IT knows when a platform crashes even when there is a hard failureon the host. -If WD feature does not exist (i.e. the connection failed), -the MEI driver will disable the sending of heartbeats. +The Intel AMT Watchdog is composed of two parts: + 1) Firmware feature - receives the heartbeats + and sends an event when the heartbeats stop. + 2) Intel MEI driver - connects to the watchdog feature, configures the + watchdog and sends the heartbeats. -Module Parameters -================= -watchdog_timeout - the user can use this module parameter -to change the watchdog timeout setting. +The Intel MEI driver uses the kernel watchdog to configure the Intel AMT +Watchdog and to send heartbeats to it. The default timeout of the +watchdog is 120 seconds. -This value sets the Intel AMT watchdog timeout interval in seconds; -the default value is 120sec. -in order to disable the watchdog activites set the value to 0. -Normal values should be between 120 and 65535 +If the Intel AMT Watchdog feature does not exist (i.e. the connection failed), +the Intel MEI driver will disable the sending of heartbeats. Supported Chipsets: ================== diff --git a/drivers/staging/mei/mei_dev.h b/drivers/staging/mei/mei_dev.h index af4b1af9eea..82bacfc624c 100644 --- a/drivers/staging/mei/mei_dev.h +++ b/drivers/staging/mei/mei_dev.h @@ -23,13 +23,6 @@ #include "hw.h" /* - * MEI Char Driver Minors - */ -#define MEI_MINORS_BASE 1 -#define MEI_MINORS_COUNT 1 -#define MEI_MINOR_NUMBER 1 - -/* * watch dog definition */ #define MEI_WATCHDOG_DATA_SIZE 16 @@ -42,11 +35,6 @@ */ extern struct pci_dev *mei_device; -/* - * AMT Watchdog Device - */ -#define INTEL_AMT_WATCHDOG_ID "INTCAMT" -extern struct watchdog_device amt_wd_dev; /* * AMTHI Client UUID @@ -175,7 +163,6 @@ struct mei_cl { struct mei_io_list { struct mei_cl_cb mei_cb; - int status; }; /* MEI private device struct */ diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c index ffca7ca3265..8094941a98f 100644 --- a/drivers/staging/mei/wd.c +++ b/drivers/staging/mei/wd.c @@ -35,12 +35,16 @@ const u8 mei_wd_state_independence_msg[3][4] = { {0x07, 0x02, 0x01, 0x10} }; +/* + * AMT Watchdog Device + */ +#define INTEL_AMT_WATCHDOG_ID "INTCAMT" + /* UUIDs for AMT F/W clients */ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB); - void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) { dev_dbg(&dev->pdev->dev, "timeout=%d.\n", timeout); @@ -331,14 +335,14 @@ static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int t /* * Watchdog Device structs */ -const struct watchdog_ops wd_ops = { +static const struct watchdog_ops wd_ops = { .owner = THIS_MODULE, .start = mei_wd_ops_start, .stop = mei_wd_ops_stop, .ping = mei_wd_ops_ping, .set_timeout = mei_wd_ops_set_timeout, }; -const struct watchdog_info wd_info = { +static const struct watchdog_info wd_info = { .identity = INTEL_AMT_WATCHDOG_ID, .options = WDIOF_KEEPALIVEPING, }; @@ -352,3 +356,25 @@ struct watchdog_device amt_wd_dev = { }; +void mei_watchdog_register(struct mei_device *dev) +{ + dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout); + + dev->wd_due_counter = !!dev->wd_timeout; + + if (watchdog_register_device(&amt_wd_dev)) { + dev_err(&dev->pdev->dev, "unable to register watchdog device.\n"); + dev->wd_interface_reg = false; + } else { + dev_dbg(&dev->pdev->dev, "successfully register watchdog interface.\n"); + dev->wd_interface_reg = true; + } +} + +void mei_watchdog_unregister(struct mei_device *dev) +{ + if (dev->wd_interface_reg) + watchdog_unregister_device(&amt_wd_dev); + dev->wd_interface_reg = false; +} + diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index e06b867d1e0..fafdfa25e13 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -27,6 +27,8 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/list.h> #include <linux/mfd/core.h> #include <linux/mutex.h> @@ -727,8 +729,24 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, nvec); nvec->dev = &pdev->dev; - nvec->gpio = pdata->gpio; - nvec->i2c_addr = pdata->i2c_addr; + + if (pdata) { + nvec->gpio = pdata->gpio; + nvec->i2c_addr = pdata->i2c_addr; + } else if (nvec->dev->of_node) { + nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0); + if (nvec->gpio < 0) { + dev_err(&pdev->dev, "no gpio specified"); + goto failed; + } + if (of_property_read_u32(nvec->dev->of_node, "slave-addr", &nvec->i2c_addr)) { + dev_err(&pdev->dev, "no i2c address specified"); + goto failed; + } + } else { + dev_err(&pdev->dev, "no platform data\n"); + goto failed; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -893,6 +911,13 @@ static int tegra_nvec_resume(struct platform_device *pdev) #define tegra_nvec_resume NULL #endif +/* Match table for of_platform binding */ +static const struct of_device_id nvidia_nvec_of_match[] __devinitconst = { + { .compatible = "nvidia,nvec", }, + {}, +}; +MODULE_DEVICE_TABLE(of, nvidia_nvec_of_match); + static struct platform_driver nvec_device_driver = { .probe = tegra_nvec_probe, .remove = __devexit_p(tegra_nvec_remove), @@ -901,6 +926,7 @@ static struct platform_driver nvec_device_driver = { .driver = { .name = "nvec", .owner = THIS_MODULE, + .of_match_table = nvidia_nvec_of_match, } }; diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index af24ddfb58c..3d9199320d8 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -34,8 +34,8 @@ /* Module definitions */ -static int resumeline = 898; -module_param(resumeline, int, 0444); +static ushort resumeline = 898; +module_param(resumeline, ushort, 0444); /* Default off since it doesn't work on DCON ASIC in B-test OLPC board */ static int useaa = 1; @@ -456,7 +456,7 @@ static ssize_t dcon_mono_store(struct device *dev, unsigned long enable_mono; int rc; - rc = strict_strtoul(buf, 10, &enable_mono); + rc = kstrtoul(buf, 10, &enable_mono); if (rc) return rc; @@ -472,7 +472,7 @@ static ssize_t dcon_freeze_store(struct device *dev, unsigned long output; int ret; - ret = strict_strtoul(buf, 10, &output); + ret = kstrtoul(buf, 10, &output); if (ret) return ret; @@ -498,10 +498,10 @@ static ssize_t dcon_freeze_store(struct device *dev, static ssize_t dcon_resumeline_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long rl; + unsigned short rl; int rc; - rc = strict_strtoul(buf, 10, &rl); + rc = kstrtou16(buf, 10, &rl); if (rc) return rc; @@ -517,7 +517,7 @@ static ssize_t dcon_sleep_store(struct device *dev, unsigned long output; int ret; - ret = strict_strtoul(buf, 10, &output); + ret = kstrtoul(buf, 10, &output); if (ret) return ret; @@ -755,9 +755,9 @@ static int dcon_resume(struct i2c_client *client) irqreturn_t dcon_interrupt(int irq, void *id) { struct dcon_priv *dcon = id; - int status = pdata->read_status(); + u8 status; - if (status == -1) + if (pdata->read_status(&status)) return IRQ_NONE; switch (status & 3) { diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h index 0264c94375a..167a41778be 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.h +++ b/drivers/staging/olpc_dcon/olpc_dcon.h @@ -84,7 +84,7 @@ struct dcon_platform_data { int (*init)(struct dcon_priv *); void (*bus_stabilize_wiggle)(void); void (*set_dconload)(int); - u8 (*read_status)(void); + int (*read_status)(u8 *); }; #include <linux/interrupt.h> diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index 2245213df60..cb6ce0cf92a 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -183,17 +183,15 @@ static void dcon_set_dconload_1(int val) gpio_set_value(OLPC_GPIO_DCON_LOAD, val); } -static u8 dcon_read_status_xo_1(void) +static int dcon_read_status_xo_1(u8 *status) { - u8 status; - - status = gpio_get_value(OLPC_GPIO_DCON_STAT0); - status |= gpio_get_value(OLPC_GPIO_DCON_STAT1) << 1; + *status = gpio_get_value(OLPC_GPIO_DCON_STAT0); + *status |= gpio_get_value(OLPC_GPIO_DCON_STAT1) << 1; /* Clear the negative edge status for GPIO7 */ cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); - return status; + return 0; } struct dcon_platform_data dcon_pdata_xo_1 = { diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c index a6a6cf2adc4..69415eec425 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c @@ -167,20 +167,18 @@ static void dcon_set_dconload_xo_1_5(int val) gpio_set_value(VX855_GPIO(1), val); } -static u8 dcon_read_status_xo_1_5(void) +static int dcon_read_status_xo_1_5(u8 *status) { - u8 status; - if (!dcon_was_irq()) return -1; /* i believe this is the same as "inb(0x44b) & 3" */ - status = gpio_get_value(VX855_GPI(10)); - status |= gpio_get_value(VX855_GPI(11)) << 1; + *status = gpio_get_value(VX855_GPI(10)); + *status |= gpio_get_value(VX855_GPI(11)) << 1; dcon_clear_irq(); - return status; + return 0; } struct dcon_platform_data dcon_pdata_xo_1_5 = { diff --git a/drivers/staging/omapdrm/Kconfig b/drivers/staging/omapdrm/Kconfig new file mode 100644 index 00000000000..81a7cba4a0c --- /dev/null +++ b/drivers/staging/omapdrm/Kconfig @@ -0,0 +1,25 @@ + +config DRM_OMAP + tristate "OMAP DRM" + depends on DRM && !CONFIG_FB_OMAP2 + depends on ARCH_OMAP2PLUS + select DRM_KMS_HELPER + select OMAP2_DSS + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + default n + help + DRM display driver for OMAP2/3/4 based boards. + +config DRM_OMAP_NUM_CRTCS + int "Number of CRTCs" + range 1 10 + default 1 if ARCH_OMAP2 || ARCH_OMAP3 + default 2 if ARCH_OMAP4 + depends on DRM_OMAP + help + Select the number of video overlays which can be used as framebuffers. + The remaining overlays are reserved for video. + diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile new file mode 100644 index 00000000000..592cf69020c --- /dev/null +++ b/drivers/staging/omapdrm/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the drm device driver. This driver provides support for the +# Direct Rendering Infrastructure (DRI) +# + +ccflags-y := -Iinclude/drm -Werror +omapdrm-y := omap_drv.o \ + omap_debugfs.o \ + omap_crtc.o \ + omap_encoder.o \ + omap_connector.o \ + omap_fb.o \ + omap_fbdev.o \ + omap_gem.o \ + omap_dmm_tiler.o \ + tcm-sita.o + +# temporary: +omapdrm-y += omap_gem_helpers.o + +obj-$(CONFIG_DRM_OMAP) += omapdrm.o diff --git a/drivers/staging/omapdrm/TODO b/drivers/staging/omapdrm/TODO new file mode 100644 index 00000000000..55b18377ac4 --- /dev/null +++ b/drivers/staging/omapdrm/TODO @@ -0,0 +1,38 @@ +TODO +. check error handling/cleanup paths +. add drm_plane / overlay support +. add video decode/encode support (via syslink3 + codec-engine) +. still some rough edges with flipping.. event back to userspace should + really come after VSYNC interrupt +. where should we do eviction (detatch_pages())? We aren't necessarily + accessing the pages via a GART, so maybe we need some other threshold + to put a cap on the # of pages that can be pin'd. (It is mostly only + of interest in case you have a swap partition/file.. which a lot of + these devices do not.. but it doesn't hurt for the driver to do the + right thing anyways.) + . Use mm_shrinker to trigger unpinning pages. Need to figure out how + to handle next issue first (I think?) + . Note TTM already has some mm_shrinker stuff.. maybe an argument to + move to TTM? Or maybe something that could be factored out in common? +. GEM/shmem backed pages can have existing mappings (kernel linear map, + etc..), which isn't really ideal. +. Revisit GEM sync object infrastructure.. TTM has some framework for this + already. Possibly this could be refactored out and made more common? + There should be some way to do this with less wheel-reinvention. +. Review DSS vs KMS mismatches. The omap_dss_device is sort of part encoder, + part connector. Which results in a bit of duct tape to fwd calls from + encoder to connector. Possibly this could be done a bit better. +. Solve PM sequencing on resume. DMM/TILER must be reloaded before any + access is made from any component in the system. Which means on suspend + CRTC's should be disabled, and on resume the LUT should be reprogrammed + before CRTC's are re-enabled, to prevent DSS from trying to DMA from a + buffer mapped in DMM/TILER before LUT is reloaded. +. Add debugfs information for DMM/TILER + +Userspace: +. git://github.com/robclark/xf86-video-omap.git + +Currently tested on +. OMAP3530 beagleboard +. OMAP4430 pandaboard +. OMAP4460 pandaboard diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c new file mode 100644 index 00000000000..5e2856c0e0b --- /dev/null +++ b/drivers/staging/omapdrm/omap_connector.c @@ -0,0 +1,371 @@ +/* + * drivers/staging/omapdrm/omap_connector.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "omap_drv.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +/* + * connector funcs + */ + +#define to_omap_connector(x) container_of(x, struct omap_connector, base) + +struct omap_connector { + struct drm_connector base; + struct omap_dss_device *dssdev; +}; + +static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, + struct omap_video_timings *timings) +{ + mode->clock = timings->pixel_clock; + + mode->hdisplay = timings->x_res; + mode->hsync_start = mode->hdisplay + timings->hfp; + mode->hsync_end = mode->hsync_start + timings->hsw; + mode->htotal = mode->hsync_end + timings->hbp; + + mode->vdisplay = timings->y_res; + mode->vsync_start = mode->vdisplay + timings->vfp; + mode->vsync_end = mode->vsync_start + timings->vsw; + mode->vtotal = mode->vsync_end + timings->vbp; + + /* note: whether or not it is interlaced, +/- h/vsync, etc, + * which should be set in the mode flags, is not exposed in + * the omap_video_timings struct.. but hdmi driver tracks + * those separately so all we have to have to set the mode + * is the way to recover these timings values, and the + * omap_dss_driver would do the rest. + */ +} + +static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, + struct drm_display_mode *mode) +{ + timings->pixel_clock = mode->clock; + + timings->x_res = mode->hdisplay; + timings->hfp = mode->hsync_start - mode->hdisplay; + timings->hsw = mode->hsync_end - mode->hsync_start; + timings->hbp = mode->htotal - mode->hsync_end; + + timings->y_res = mode->vdisplay; + timings->vfp = mode->vsync_start - mode->vdisplay; + timings->vsw = mode->vsync_end - mode->vsync_start; + timings->vbp = mode->vtotal - mode->vsync_end; +} + +static void omap_connector_dpms(struct drm_connector *connector, int mode) +{ + struct omap_connector *omap_connector = to_omap_connector(connector); + struct omap_dss_device *dssdev = omap_connector->dssdev; + int old_dpms; + + DBG("%s: %d", dssdev->name, mode); + + old_dpms = connector->dpms; + + /* from off to on, do from crtc to connector */ + if (mode < old_dpms) + drm_helper_connector_dpms(connector, mode); + + if (mode == DRM_MODE_DPMS_ON) { + /* store resume info for suspended displays */ + switch (dssdev->state) { + case OMAP_DSS_DISPLAY_SUSPENDED: + dssdev->activate_after_resume = true; + break; + case OMAP_DSS_DISPLAY_DISABLED: { + int ret = dssdev->driver->enable(dssdev); + if (ret) { + DBG("%s: failed to enable: %d", + dssdev->name, ret); + dssdev->driver->disable(dssdev); + } + break; + } + default: + break; + } + } else { + /* TODO */ + } + + /* from on to off, do from connector to crtc */ + if (mode > old_dpms) + drm_helper_connector_dpms(connector, mode); +} + +enum drm_connector_status omap_connector_detect( + struct drm_connector *connector, bool force) +{ + struct omap_connector *omap_connector = to_omap_connector(connector); + struct omap_dss_device *dssdev = omap_connector->dssdev; + struct omap_dss_driver *dssdrv = dssdev->driver; + enum drm_connector_status ret; + + if (dssdrv->detect) { + if (dssdrv->detect(dssdev)) { + ret = connector_status_connected; + } else { + ret = connector_status_disconnected; + } + } else { + ret = connector_status_unknown; + } + + VERB("%s: %d (force=%d)", omap_connector->dssdev->name, ret, force); + + return ret; +} + +static void omap_connector_destroy(struct drm_connector *connector) +{ + struct omap_connector *omap_connector = to_omap_connector(connector); + struct omap_dss_device *dssdev = omap_connector->dssdev; + + dssdev->driver->disable(dssdev); + + DBG("%s", omap_connector->dssdev->name); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(omap_connector); + + omap_dss_put_device(dssdev); +} + +#define MAX_EDID 512 + +static int omap_connector_get_modes(struct drm_connector *connector) +{ + struct omap_connector *omap_connector = to_omap_connector(connector); + struct omap_dss_device *dssdev = omap_connector->dssdev; + struct omap_dss_driver *dssdrv = dssdev->driver; + struct drm_device *dev = connector->dev; + int n = 0; + + DBG("%s", omap_connector->dssdev->name); + + /* if display exposes EDID, then we parse that in the normal way to + * build table of supported modes.. otherwise (ie. fixed resolution + * LCD panels) we just return a single mode corresponding to the + * currently configured timings: + */ + if (dssdrv->read_edid) { + void *edid = kzalloc(MAX_EDID, GFP_KERNEL); + + if ((dssdrv->read_edid(dssdev, edid, MAX_EDID) > 0) && + drm_edid_is_valid(edid)) { + drm_mode_connector_update_edid_property( + connector, edid); + n = drm_add_edid_modes(connector, edid); + kfree(connector->display_info.raw_edid); + connector->display_info.raw_edid = edid; + } else { + drm_mode_connector_update_edid_property( + connector, NULL); + connector->display_info.raw_edid = NULL; + kfree(edid); + } + } else { + struct drm_display_mode *mode = drm_mode_create(dev); + struct omap_video_timings timings; + + dssdrv->get_timings(dssdev, &timings); + + copy_timings_omap_to_drm(mode, &timings); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + n = 1; + } + + return n; +} + +static int omap_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct omap_connector *omap_connector = to_omap_connector(connector); + struct omap_dss_device *dssdev = omap_connector->dssdev; + struct omap_dss_driver *dssdrv = dssdev->driver; + struct omap_video_timings timings = {0}; + struct drm_device *dev = connector->dev; + struct drm_display_mode *new_mode; + int ret = MODE_BAD; + + copy_timings_drm_to_omap(&timings, mode); + mode->vrefresh = drm_mode_vrefresh(mode); + + if (!dssdrv->check_timings(dssdev, &timings)) { + /* check if vrefresh is still valid */ + new_mode = drm_mode_duplicate(dev, mode); + new_mode->clock = timings.pixel_clock; + new_mode->vrefresh = 0; + if (mode->vrefresh == drm_mode_vrefresh(new_mode)) + ret = MODE_OK; + drm_mode_destroy(dev, new_mode); + } + + DBG("connector: mode %s: " + "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", + (ret == MODE_OK) ? "valid" : "invalid", + mode->base.id, mode->name, mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, mode->type, mode->flags); + + return ret; +} + +struct drm_encoder *omap_connector_attached_encoder( + struct drm_connector *connector) +{ + int i; + struct omap_connector *omap_connector = to_omap_connector(connector); + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + struct drm_mode_object *obj; + + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, + connector->encoder_ids[i], + DRM_MODE_OBJECT_ENCODER); + + if (obj) { + struct drm_encoder *encoder = obj_to_encoder(obj); + struct omap_overlay_manager *mgr = + omap_encoder_get_manager(encoder); + DBG("%s: found %s", omap_connector->dssdev->name, + mgr->name); + return encoder; + } + } + + DBG("%s: no encoder", omap_connector->dssdev->name); + + return NULL; +} + +static const struct drm_connector_funcs omap_connector_funcs = { + .dpms = omap_connector_dpms, + .detect = omap_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = omap_connector_destroy, +}; + +static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { + .get_modes = omap_connector_get_modes, + .mode_valid = omap_connector_mode_valid, + .best_encoder = omap_connector_attached_encoder, +}; + +/* called from encoder when mode is set, to propagate settings to the dssdev */ +void omap_connector_mode_set(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct drm_device *dev = connector->dev; + struct omap_connector *omap_connector = to_omap_connector(connector); + struct omap_dss_device *dssdev = omap_connector->dssdev; + struct omap_dss_driver *dssdrv = dssdev->driver; + struct omap_video_timings timings; + + copy_timings_drm_to_omap(&timings, mode); + + DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", + omap_connector->dssdev->name, + mode->base.id, mode->name, mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, mode->type, mode->flags); + + if (dssdrv->check_timings(dssdev, &timings)) { + dev_err(dev->dev, "could not set timings\n"); + return; + } + + dssdrv->set_timings(dssdev, &timings); +} + +/* flush an area of the framebuffer (in case of manual update display that + * is not automatically flushed) + */ +void omap_connector_flush(struct drm_connector *connector, + int x, int y, int w, int h) +{ + struct omap_connector *omap_connector = to_omap_connector(connector); + + /* TODO: enable when supported in dss */ + VERB("%s: %d,%d, %dx%d", omap_connector->dssdev->name, x, y, w, h); +} + +/* initialize connector */ +struct drm_connector *omap_connector_init(struct drm_device *dev, + int connector_type, struct omap_dss_device *dssdev) +{ + struct drm_connector *connector = NULL; + struct omap_connector *omap_connector; + + DBG("%s", dssdev->name); + + omap_dss_get_device(dssdev); + + omap_connector = kzalloc(sizeof(struct omap_connector), GFP_KERNEL); + if (!omap_connector) { + dev_err(dev->dev, "could not allocate connector\n"); + goto fail; + } + + omap_connector->dssdev = dssdev; + connector = &omap_connector->base; + + drm_connector_init(dev, connector, &omap_connector_funcs, + connector_type); + drm_connector_helper_add(connector, &omap_connector_helper_funcs); + +#if 0 /* enable when dss2 supports hotplug */ + if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_HPD) + connector->polled = 0; + else +#endif + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + + connector->interlace_allowed = 1; + connector->doublescan_allowed = 0; + + drm_sysfs_connector_add(connector); + + return connector; + +fail: + if (connector) { + omap_connector_destroy(connector); + } + + return NULL; +} diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c new file mode 100644 index 00000000000..cffdf5e1239 --- /dev/null +++ b/drivers/staging/omapdrm/omap_crtc.c @@ -0,0 +1,326 @@ +/* + * drivers/staging/omapdrm/omap_crtc.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "omap_drv.h" + +#include "drm_mode.h" +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +#define to_omap_crtc(x) container_of(x, struct omap_crtc, base) + +struct omap_crtc { + struct drm_crtc base; + struct omap_overlay *ovl; + struct omap_overlay_info info; + int id; + + /* if there is a pending flip, this will be non-null: */ + struct drm_pending_vblank_event *event; +}; + +/* push changes down to dss2 */ +static int commit(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct omap_overlay *ovl = omap_crtc->ovl; + struct omap_overlay_info *info = &omap_crtc->info; + int ret; + + DBG("%s", omap_crtc->ovl->name); + DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width, + info->out_height, info->screen_width); + DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr); + + /* NOTE: do we want to do this at all here, or just wait + * for dpms(ON) since other CRTC's may not have their mode + * set yet, so fb dimensions may still change.. + */ + ret = ovl->set_overlay_info(ovl, info); + if (ret) { + dev_err(dev->dev, "could not set overlay info\n"); + return ret; + } + + /* our encoder doesn't necessarily get a commit() after this, in + * particular in the dpms() and mode_set_base() cases, so force the + * manager to update: + * + * could this be in the encoder somehow? + */ + if (ovl->manager) { + ret = ovl->manager->apply(ovl->manager); + if (ret) { + dev_err(dev->dev, "could not apply settings\n"); + return ret; + } + } + + if (info->enabled) { + omap_framebuffer_flush(crtc->fb, crtc->x, crtc->y, + crtc->fb->width, crtc->fb->height); + } + + return 0; +} + +/* update parameters that are dependent on the framebuffer dimensions and + * position within the fb that this crtc scans out from. This is called + * when framebuffer dimensions or x,y base may have changed, either due + * to our mode, or a change in another crtc that is scanning out of the + * same fb. + */ +static void update_scanout(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + dma_addr_t paddr; + unsigned int screen_width; + + omap_framebuffer_get_buffer(crtc->fb, crtc->x, crtc->y, + NULL, &paddr, &screen_width); + + DBG("%s: %d,%d: %08x (%d)", omap_crtc->ovl->name, + crtc->x, crtc->y, (u32)paddr, screen_width); + + omap_crtc->info.paddr = paddr; + omap_crtc->info.screen_width = screen_width; +} + +static void omap_crtc_gamma_set(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + DBG("%s", omap_crtc->ovl->name); +} + +static void omap_crtc_destroy(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + DBG("%s", omap_crtc->ovl->name); + drm_crtc_cleanup(crtc); + kfree(omap_crtc); +} + +static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + DBG("%s: %d", omap_crtc->ovl->name, mode); + + if (mode == DRM_MODE_DPMS_ON) { + update_scanout(crtc); + omap_crtc->info.enabled = true; + } else { + omap_crtc->info.enabled = false; + } + + WARN_ON(commit(crtc)); +} + +static bool omap_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + DBG("%s", omap_crtc->ovl->name); + return true; +} + +static int omap_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + DBG("%s: %d,%d: %dx%d", omap_crtc->ovl->name, x, y, + mode->hdisplay, mode->vdisplay); + + /* just use adjusted mode */ + mode = adjusted_mode; + + omap_crtc->info.width = mode->hdisplay; + omap_crtc->info.height = mode->vdisplay; + omap_crtc->info.out_width = mode->hdisplay; + omap_crtc->info.out_height = mode->vdisplay; + omap_crtc->info.color_mode = OMAP_DSS_COLOR_RGB24U; + omap_crtc->info.rotation_type = OMAP_DSS_ROT_DMA; + omap_crtc->info.rotation = OMAP_DSS_ROT_0; + omap_crtc->info.global_alpha = 0xff; + omap_crtc->info.mirror = 0; + omap_crtc->info.mirror = 0; + omap_crtc->info.pos_x = 0; + omap_crtc->info.pos_y = 0; +#if 0 /* re-enable when these are available in DSS2 driver */ + omap_crtc->info.zorder = 3; /* GUI in the front, video behind */ + omap_crtc->info.min_x_decim = 1; + omap_crtc->info.max_x_decim = 1; + omap_crtc->info.min_y_decim = 1; + omap_crtc->info.max_y_decim = 1; +#endif + + update_scanout(crtc); + + return 0; +} + +static void omap_crtc_prepare(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct omap_overlay *ovl = omap_crtc->ovl; + + DBG("%s", omap_crtc->ovl->name); + + ovl->get_overlay_info(ovl, &omap_crtc->info); + + omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void omap_crtc_commit(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + DBG("%s", omap_crtc->ovl->name); + omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON); +} + +static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + DBG("%s %d,%d: fb=%p", omap_crtc->ovl->name, x, y, old_fb); + + update_scanout(crtc); + + return commit(crtc); +} + +static void omap_crtc_load_lut(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + DBG("%s", omap_crtc->ovl->name); +} + +static void page_flip_cb(void *arg) +{ + struct drm_crtc *crtc = arg; + struct drm_device *dev = crtc->dev; + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct drm_pending_vblank_event *event = omap_crtc->event; + struct timeval now; + unsigned long flags; + + WARN_ON(!event); + + omap_crtc->event = NULL; + + update_scanout(crtc); + WARN_ON(commit(crtc)); + + /* wakeup userspace */ + /* TODO: this should happen *after* flip in vsync IRQ handler */ + if (event) { + spin_lock_irqsave(&dev->event_lock, flags); + event->event.sequence = drm_vblank_count_and_time( + dev, omap_crtc->id, &now); + event->event.tv_sec = now.tv_sec; + event->event.tv_usec = now.tv_usec; + list_add_tail(&event->base.link, + &event->base.file_priv->event_list); + wake_up_interruptible(&event->base.file_priv->event_wait); + spin_unlock_irqrestore(&dev->event_lock, flags); + } +} + +static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct drm_device *dev = crtc->dev; + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id); + + if (omap_crtc->event) { + dev_err(dev->dev, "already a pending flip\n"); + return -EINVAL; + } + + crtc->fb = fb; + omap_crtc->event = event; + + omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ, + page_flip_cb, crtc); + + return 0; +} + +static const struct drm_crtc_funcs omap_crtc_funcs = { + .gamma_set = omap_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = omap_crtc_destroy, + .page_flip = omap_crtc_page_flip_locked, +}; + +static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { + .dpms = omap_crtc_dpms, + .mode_fixup = omap_crtc_mode_fixup, + .mode_set = omap_crtc_mode_set, + .prepare = omap_crtc_prepare, + .commit = omap_crtc_commit, + .mode_set_base = omap_crtc_mode_set_base, + .load_lut = omap_crtc_load_lut, +}; + +struct omap_overlay *omap_crtc_get_overlay(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + return omap_crtc->ovl; +} + +/* initialize crtc */ +struct drm_crtc *omap_crtc_init(struct drm_device *dev, + struct omap_overlay *ovl, int id) +{ + struct drm_crtc *crtc = NULL; + struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); + + DBG("%s", ovl->name); + + if (!omap_crtc) { + dev_err(dev->dev, "could not allocate CRTC\n"); + goto fail; + } + + omap_crtc->ovl = ovl; + omap_crtc->id = id; + crtc = &omap_crtc->base; + drm_crtc_init(dev, crtc, &omap_crtc_funcs); + drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); + + return crtc; + +fail: + if (crtc) { + omap_crtc_destroy(crtc); + } + return NULL; +} diff --git a/drivers/staging/omapdrm/omap_debugfs.c b/drivers/staging/omapdrm/omap_debugfs.c new file mode 100644 index 00000000000..da920dfdc59 --- /dev/null +++ b/drivers/staging/omapdrm/omap_debugfs.c @@ -0,0 +1,42 @@ +/* + * drivers/staging/omapdrm/omap_debugfs.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob.clark@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "omap_drv.h" +#include "omap_dmm_tiler.h" + +#ifdef CONFIG_DEBUG_FS + +static struct drm_info_list omap_debugfs_list[] = { + {"tiler_map", tiler_map_show, 0}, +}; + +int omap_debugfs_init(struct drm_minor *minor) +{ + return drm_debugfs_create_files(omap_debugfs_list, + ARRAY_SIZE(omap_debugfs_list), + minor->debugfs_root, minor); +} + +void omap_debugfs_cleanup(struct drm_minor *minor) +{ + drm_debugfs_remove_files(omap_debugfs_list, + ARRAY_SIZE(omap_debugfs_list), minor); +} + +#endif diff --git a/drivers/staging/omapdrm/omap_dmm_priv.h b/drivers/staging/omapdrm/omap_dmm_priv.h new file mode 100644 index 00000000000..2f529ab4b7c --- /dev/null +++ b/drivers/staging/omapdrm/omap_dmm_priv.h @@ -0,0 +1,187 @@ +/* + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Rob Clark <rob@ti.com> + * Andy Gross <andy.gross@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef OMAP_DMM_PRIV_H +#define OMAP_DMM_PRIV_H + +#define DMM_REVISION 0x000 +#define DMM_HWINFO 0x004 +#define DMM_LISA_HWINFO 0x008 +#define DMM_DMM_SYSCONFIG 0x010 +#define DMM_LISA_LOCK 0x01C +#define DMM_LISA_MAP__0 0x040 +#define DMM_LISA_MAP__1 0x044 +#define DMM_TILER_HWINFO 0x208 +#define DMM_TILER_OR__0 0x220 +#define DMM_TILER_OR__1 0x224 +#define DMM_PAT_HWINFO 0x408 +#define DMM_PAT_GEOMETRY 0x40C +#define DMM_PAT_CONFIG 0x410 +#define DMM_PAT_VIEW__0 0x420 +#define DMM_PAT_VIEW__1 0x424 +#define DMM_PAT_VIEW_MAP__0 0x440 +#define DMM_PAT_VIEW_MAP_BASE 0x460 +#define DMM_PAT_IRQ_EOI 0x478 +#define DMM_PAT_IRQSTATUS_RAW 0x480 +#define DMM_PAT_IRQSTATUS 0x490 +#define DMM_PAT_IRQENABLE_SET 0x4A0 +#define DMM_PAT_IRQENABLE_CLR 0x4B0 +#define DMM_PAT_STATUS__0 0x4C0 +#define DMM_PAT_STATUS__1 0x4C4 +#define DMM_PAT_STATUS__2 0x4C8 +#define DMM_PAT_STATUS__3 0x4CC +#define DMM_PAT_DESCR__0 0x500 +#define DMM_PAT_DESCR__1 0x510 +#define DMM_PAT_DESCR__2 0x520 +#define DMM_PAT_DESCR__3 0x530 +#define DMM_PEG_HWINFO 0x608 +#define DMM_PEG_PRIO 0x620 +#define DMM_PEG_PRIO_PAT 0x640 + +#define DMM_IRQSTAT_DST (1<<0) +#define DMM_IRQSTAT_LST (1<<1) +#define DMM_IRQSTAT_ERR_INV_DSC (1<<2) +#define DMM_IRQSTAT_ERR_INV_DATA (1<<3) +#define DMM_IRQSTAT_ERR_UPD_AREA (1<<4) +#define DMM_IRQSTAT_ERR_UPD_CTRL (1<<5) +#define DMM_IRQSTAT_ERR_UPD_DATA (1<<6) +#define DMM_IRQSTAT_ERR_LUT_MISS (1<<7) + +#define DMM_IRQSTAT_ERR_MASK (DMM_IRQ_STAT_ERR_INV_DSC | \ + DMM_IRQ_STAT_ERR_INV_DATA | \ + DMM_IRQ_STAT_ERR_UPD_AREA | \ + DMM_IRQ_STAT_ERR_UPD_CTRL | \ + DMM_IRQ_STAT_ERR_UPD_DATA | \ + DMM_IRQ_STAT_ERR_LUT_MISS) + +#define DMM_PATSTATUS_READY (1<<0) +#define DMM_PATSTATUS_VALID (1<<1) +#define DMM_PATSTATUS_RUN (1<<2) +#define DMM_PATSTATUS_DONE (1<<3) +#define DMM_PATSTATUS_LINKED (1<<4) +#define DMM_PATSTATUS_BYPASSED (1<<7) +#define DMM_PATSTATUS_ERR_INV_DESCR (1<<10) +#define DMM_PATSTATUS_ERR_INV_DATA (1<<11) +#define DMM_PATSTATUS_ERR_UPD_AREA (1<<12) +#define DMM_PATSTATUS_ERR_UPD_CTRL (1<<13) +#define DMM_PATSTATUS_ERR_UPD_DATA (1<<14) +#define DMM_PATSTATUS_ERR_ACCESS (1<<15) + +/* note: don't treat DMM_PATSTATUS_ERR_ACCESS as an error */ +#define DMM_PATSTATUS_ERR (DMM_PATSTATUS_ERR_INV_DESCR | \ + DMM_PATSTATUS_ERR_INV_DATA | \ + DMM_PATSTATUS_ERR_UPD_AREA | \ + DMM_PATSTATUS_ERR_UPD_CTRL | \ + DMM_PATSTATUS_ERR_UPD_DATA) + + + +enum { + PAT_STATUS, + PAT_DESCR +}; + +struct pat_ctrl { + u32 start:4; + u32 dir:4; + u32 lut_id:8; + u32 sync:12; + u32 ini:4; +}; + +struct pat { + uint32_t next_pa; + struct pat_area area; + struct pat_ctrl ctrl; + uint32_t data_pa; +}; + +#define DMM_FIXED_RETRY_COUNT 1000 + +/* create refill buffer big enough to refill all slots, plus 3 descriptors.. + * 3 descriptors is probably the worst-case for # of 2d-slices in a 1d area, + * but I guess you don't hit that worst case at the same time as full area + * refill + */ +#define DESCR_SIZE 128 +#define REFILL_BUFFER_SIZE ((4 * 128 * 256) + (3 * DESCR_SIZE)) + +struct dmm; + +struct dmm_txn { + void *engine_handle; + struct tcm *tcm; + + uint8_t *current_va; + dma_addr_t current_pa; + + struct pat *last_pat; +}; + +struct refill_engine { + int id; + struct dmm *dmm; + struct tcm *tcm; + + uint8_t *refill_va; + dma_addr_t refill_pa; + + /* only one trans per engine for now */ + struct dmm_txn txn; + + /* offset to lut associated with container */ + u32 *lut_offset; + + wait_queue_head_t wait_for_refill; + + struct list_head idle_node; +}; + +struct dmm { + struct device *dev; + void __iomem *base; + int irq; + + struct page *dummy_page; + dma_addr_t dummy_pa; + + void *refill_va; + dma_addr_t refill_pa; + + /* refill engines */ + struct semaphore engine_sem; + struct list_head idle_head; + struct refill_engine *engines; + int num_engines; + + /* container information */ + int container_width; + int container_height; + int lut_width; + int lut_height; + int num_lut; + + /* array of LUT - TCM containers */ + struct tcm **tcm; + + /* LUT table storage */ + u32 *lut; + + /* allocation list and lock */ + struct list_head alloc_head; + spinlock_t list_lock; +}; + +#endif diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c new file mode 100644 index 00000000000..852d9440f72 --- /dev/null +++ b/drivers/staging/omapdrm/omap_dmm_tiler.c @@ -0,0 +1,830 @@ +/* + * DMM IOMMU driver support functions for TI OMAP processors. + * + * Author: Rob Clark <rob@ti.com> + * Andy Gross <andy.gross@ti.com> + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> /* platform_device() */ +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/time.h> +#include <linux/list.h> +#include <linux/semaphore.h> + +#include "omap_dmm_tiler.h" +#include "omap_dmm_priv.h" + +/* mappings for associating views to luts */ +static struct tcm *containers[TILFMT_NFORMATS]; +static struct dmm *omap_dmm; + +/* Geometry table */ +#define GEOM(xshift, yshift, bytes_per_pixel) { \ + .x_shft = (xshift), \ + .y_shft = (yshift), \ + .cpp = (bytes_per_pixel), \ + .slot_w = 1 << (SLOT_WIDTH_BITS - (xshift)), \ + .slot_h = 1 << (SLOT_HEIGHT_BITS - (yshift)), \ + } + +static const struct { + uint32_t x_shft; /* unused X-bits (as part of bpp) */ + uint32_t y_shft; /* unused Y-bits (as part of bpp) */ + uint32_t cpp; /* bytes/chars per pixel */ + uint32_t slot_w; /* width of each slot (in pixels) */ + uint32_t slot_h; /* height of each slot (in pixels) */ +} geom[TILFMT_NFORMATS] = { + [TILFMT_8BIT] = GEOM(0, 0, 1), + [TILFMT_16BIT] = GEOM(0, 1, 2), + [TILFMT_32BIT] = GEOM(1, 1, 4), + [TILFMT_PAGE] = GEOM(SLOT_WIDTH_BITS, SLOT_HEIGHT_BITS, 1), +}; + + +/* lookup table for registers w/ per-engine instances */ +static const uint32_t reg[][4] = { + [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1, + DMM_PAT_STATUS__2, DMM_PAT_STATUS__3}, + [PAT_DESCR] = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1, + DMM_PAT_DESCR__2, DMM_PAT_DESCR__3}, +}; + +/* simple allocator to grab next 16 byte aligned memory from txn */ +static void *alloc_dma(struct dmm_txn *txn, size_t sz, dma_addr_t *pa) +{ + void *ptr; + struct refill_engine *engine = txn->engine_handle; + + /* dmm programming requires 16 byte aligned addresses */ + txn->current_pa = round_up(txn->current_pa, 16); + txn->current_va = (void *)round_up((long)txn->current_va, 16); + + ptr = txn->current_va; + *pa = txn->current_pa; + + txn->current_pa += sz; + txn->current_va += sz; + + BUG_ON((txn->current_va - engine->refill_va) > REFILL_BUFFER_SIZE); + + return ptr; +} + +/* check status and spin until wait_mask comes true */ +static int wait_status(struct refill_engine *engine, uint32_t wait_mask) +{ + struct dmm *dmm = engine->dmm; + uint32_t r = 0, err, i; + + i = DMM_FIXED_RETRY_COUNT; + while (true) { + r = readl(dmm->base + reg[PAT_STATUS][engine->id]); + err = r & DMM_PATSTATUS_ERR; + if (err) + return -EFAULT; + + if ((r & wait_mask) == wait_mask) + break; + + if (--i == 0) + return -ETIMEDOUT; + + udelay(1); + } + + return 0; +} + +irqreturn_t omap_dmm_irq_handler(int irq, void *arg) +{ + struct dmm *dmm = arg; + uint32_t status = readl(dmm->base + DMM_PAT_IRQSTATUS); + int i; + + /* ack IRQ */ + writel(status, dmm->base + DMM_PAT_IRQSTATUS); + + for (i = 0; i < dmm->num_engines; i++) { + if (status & DMM_IRQSTAT_LST) + wake_up_interruptible(&dmm->engines[i].wait_for_refill); + + status >>= 8; + } + + return IRQ_HANDLED; +} + +/** + * Get a handle for a DMM transaction + */ +static struct dmm_txn *dmm_txn_init(struct dmm *dmm, struct tcm *tcm) +{ + struct dmm_txn *txn = NULL; + struct refill_engine *engine = NULL; + + down(&dmm->engine_sem); + + /* grab an idle engine */ + spin_lock(&dmm->list_lock); + if (!list_empty(&dmm->idle_head)) { + engine = list_entry(dmm->idle_head.next, struct refill_engine, + idle_node); + list_del(&engine->idle_node); + } + spin_unlock(&dmm->list_lock); + + BUG_ON(!engine); + + txn = &engine->txn; + engine->tcm = tcm; + txn->engine_handle = engine; + txn->last_pat = NULL; + txn->current_va = engine->refill_va; + txn->current_pa = engine->refill_pa; + + return txn; +} + +/** + * Add region to DMM transaction. If pages or pages[i] is NULL, then the + * corresponding slot is cleared (ie. dummy_pa is programmed) + */ +static int dmm_txn_append(struct dmm_txn *txn, struct pat_area *area, + struct page **pages, uint32_t npages, uint32_t roll) +{ + dma_addr_t pat_pa = 0; + uint32_t *data; + struct pat *pat; + struct refill_engine *engine = txn->engine_handle; + int columns = (1 + area->x1 - area->x0); + int rows = (1 + area->y1 - area->y0); + int i = columns*rows; + u32 *lut = omap_dmm->lut + (engine->tcm->lut_id * omap_dmm->lut_width * + omap_dmm->lut_height) + + (area->y0 * omap_dmm->lut_width) + area->x0; + + pat = alloc_dma(txn, sizeof(struct pat), &pat_pa); + + if (txn->last_pat) + txn->last_pat->next_pa = (uint32_t)pat_pa; + + pat->area = *area; + pat->ctrl = (struct pat_ctrl){ + .start = 1, + .lut_id = engine->tcm->lut_id, + }; + + data = alloc_dma(txn, 4*i, &pat->data_pa); + + while (i--) { + int n = i + roll; + if (n >= npages) + n -= npages; + data[i] = (pages && pages[n]) ? + page_to_phys(pages[n]) : engine->dmm->dummy_pa; + } + + /* fill in lut with new addresses */ + for (i = 0; i < rows; i++, lut += omap_dmm->lut_width) + memcpy(lut, &data[i*columns], columns * sizeof(u32)); + + txn->last_pat = pat; + + return 0; +} + +/** + * Commit the DMM transaction. + */ +static int dmm_txn_commit(struct dmm_txn *txn, bool wait) +{ + int ret = 0; + struct refill_engine *engine = txn->engine_handle; + struct dmm *dmm = engine->dmm; + + if (!txn->last_pat) { + dev_err(engine->dmm->dev, "need at least one txn\n"); + ret = -EINVAL; + goto cleanup; + } + + txn->last_pat->next_pa = 0; + + /* write to PAT_DESCR to clear out any pending transaction */ + writel(0x0, dmm->base + reg[PAT_DESCR][engine->id]); + + /* wait for engine ready: */ + ret = wait_status(engine, DMM_PATSTATUS_READY); + if (ret) { + ret = -EFAULT; + goto cleanup; + } + + /* kick reload */ + writel(engine->refill_pa, + dmm->base + reg[PAT_DESCR][engine->id]); + + if (wait) { + if (wait_event_interruptible_timeout(engine->wait_for_refill, + wait_status(engine, DMM_PATSTATUS_READY) == 0, + msecs_to_jiffies(1)) <= 0) { + dev_err(dmm->dev, "timed out waiting for done\n"); + ret = -ETIMEDOUT; + } + } + +cleanup: + spin_lock(&dmm->list_lock); + list_add(&engine->idle_node, &dmm->idle_head); + spin_unlock(&dmm->list_lock); + + up(&omap_dmm->engine_sem); + return ret; +} + +/* + * DMM programming + */ +static int fill(struct tcm_area *area, struct page **pages, + uint32_t npages, uint32_t roll, bool wait) +{ + int ret = 0; + struct tcm_area slice, area_s; + struct dmm_txn *txn; + + txn = dmm_txn_init(omap_dmm, area->tcm); + if (IS_ERR_OR_NULL(txn)) + return PTR_ERR(txn); + + tcm_for_each_slice(slice, *area, area_s) { + struct pat_area p_area = { + .x0 = slice.p0.x, .y0 = slice.p0.y, + .x1 = slice.p1.x, .y1 = slice.p1.y, + }; + + ret = dmm_txn_append(txn, &p_area, pages, npages, roll); + if (ret) + goto fail; + + roll += tcm_sizeof(slice); + } + + ret = dmm_txn_commit(txn, wait); + +fail: + return ret; +} + +/* + * Pin/unpin + */ + +/* note: slots for which pages[i] == NULL are filled w/ dummy page + */ +int tiler_pin(struct tiler_block *block, struct page **pages, + uint32_t npages, uint32_t roll, bool wait) +{ + int ret; + + ret = fill(&block->area, pages, npages, roll, wait); + + if (ret) + tiler_unpin(block); + + return ret; +} + +int tiler_unpin(struct tiler_block *block) +{ + return fill(&block->area, NULL, 0, 0, false); +} + +/* + * Reserve/release + */ +struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, + uint16_t h, uint16_t align) +{ + struct tiler_block *block = kzalloc(sizeof(*block), GFP_KERNEL); + u32 min_align = 128; + int ret; + + BUG_ON(!validfmt(fmt)); + + /* convert width/height to slots */ + w = DIV_ROUND_UP(w, geom[fmt].slot_w); + h = DIV_ROUND_UP(h, geom[fmt].slot_h); + + /* convert alignment to slots */ + min_align = max(min_align, (geom[fmt].slot_w * geom[fmt].cpp)); + align = ALIGN(align, min_align); + align /= geom[fmt].slot_w * geom[fmt].cpp; + + block->fmt = fmt; + + ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area); + if (ret) { + kfree(block); + return 0; + } + + /* add to allocation list */ + spin_lock(&omap_dmm->list_lock); + list_add(&block->alloc_node, &omap_dmm->alloc_head); + spin_unlock(&omap_dmm->list_lock); + + return block; +} + +struct tiler_block *tiler_reserve_1d(size_t size) +{ + struct tiler_block *block = kzalloc(sizeof(*block), GFP_KERNEL); + int num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + if (!block) + return 0; + + block->fmt = TILFMT_PAGE; + + if (tcm_reserve_1d(containers[TILFMT_PAGE], num_pages, + &block->area)) { + kfree(block); + return 0; + } + + spin_lock(&omap_dmm->list_lock); + list_add(&block->alloc_node, &omap_dmm->alloc_head); + spin_unlock(&omap_dmm->list_lock); + + return block; +} + +/* note: if you have pin'd pages, you should have already unpin'd first! */ +int tiler_release(struct tiler_block *block) +{ + int ret = tcm_free(&block->area); + + if (block->area.tcm) + dev_err(omap_dmm->dev, "failed to release block\n"); + + spin_lock(&omap_dmm->list_lock); + list_del(&block->alloc_node); + spin_unlock(&omap_dmm->list_lock); + + kfree(block); + return ret; +} + +/* + * Utils + */ + +/* calculate the tiler space address of a pixel in a view orientation */ +static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y) +{ + u32 x_bits, y_bits, tmp, x_mask, y_mask, alignment; + + x_bits = CONT_WIDTH_BITS - geom[fmt].x_shft; + y_bits = CONT_HEIGHT_BITS - geom[fmt].y_shft; + alignment = geom[fmt].x_shft + geom[fmt].y_shft; + + /* validate coordinate */ + x_mask = MASK(x_bits); + y_mask = MASK(y_bits); + + if (x < 0 || x > x_mask || y < 0 || y > y_mask) + return 0; + + /* account for mirroring */ + if (orient & MASK_X_INVERT) + x ^= x_mask; + if (orient & MASK_Y_INVERT) + y ^= y_mask; + + /* get coordinate address */ + if (orient & MASK_XY_FLIP) + tmp = ((x << y_bits) + y); + else + tmp = ((y << x_bits) + x); + + return TIL_ADDR((tmp << alignment), orient, fmt); +} + +dma_addr_t tiler_ssptr(struct tiler_block *block) +{ + BUG_ON(!validfmt(block->fmt)); + + return TILVIEW_8BIT + tiler_get_address(0, block->fmt, + block->area.p0.x * geom[block->fmt].slot_w, + block->area.p0.y * geom[block->fmt].slot_h); +} + +void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h) +{ + BUG_ON(!validfmt(fmt)); + *w = round_up(*w, geom[fmt].slot_w); + *h = round_up(*h, geom[fmt].slot_h); +} + +uint32_t tiler_stride(enum tiler_fmt fmt) +{ + BUG_ON(!validfmt(fmt)); + + return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft); +} + +size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h) +{ + tiler_align(fmt, &w, &h); + return geom[fmt].cpp * w * h; +} + +size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h) +{ + BUG_ON(!validfmt(fmt)); + return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h; +} + +int omap_dmm_remove(void) +{ + struct tiler_block *block, *_block; + int i; + + if (omap_dmm) { + /* free all area regions */ + spin_lock(&omap_dmm->list_lock); + list_for_each_entry_safe(block, _block, &omap_dmm->alloc_head, + alloc_node) { + list_del(&block->alloc_node); + kfree(block); + } + spin_unlock(&omap_dmm->list_lock); + + for (i = 0; i < omap_dmm->num_lut; i++) + if (omap_dmm->tcm && omap_dmm->tcm[i]) + omap_dmm->tcm[i]->deinit(omap_dmm->tcm[i]); + kfree(omap_dmm->tcm); + + kfree(omap_dmm->engines); + if (omap_dmm->refill_va) + dma_free_coherent(omap_dmm->dev, + REFILL_BUFFER_SIZE * omap_dmm->num_engines, + omap_dmm->refill_va, + omap_dmm->refill_pa); + if (omap_dmm->dummy_page) + __free_page(omap_dmm->dummy_page); + + vfree(omap_dmm->lut); + + if (omap_dmm->irq != -1) + free_irq(omap_dmm->irq, omap_dmm); + + kfree(omap_dmm); + } + + return 0; +} + +int omap_dmm_init(struct drm_device *dev) +{ + int ret = -EFAULT, i; + struct tcm_area area = {0}; + u32 hwinfo, pat_geom, lut_table_size; + struct omap_drm_platform_data *pdata = dev->dev->platform_data; + + if (!pdata || !pdata->dmm_pdata) { + dev_err(dev->dev, "dmm platform data not present, skipping\n"); + return ret; + } + + omap_dmm = kzalloc(sizeof(*omap_dmm), GFP_KERNEL); + if (!omap_dmm) { + dev_err(dev->dev, "failed to allocate driver data section\n"); + goto fail; + } + + /* lookup hwmod data - base address and irq */ + omap_dmm->base = pdata->dmm_pdata->base; + omap_dmm->irq = pdata->dmm_pdata->irq; + omap_dmm->dev = dev->dev; + + if (!omap_dmm->base) { + dev_err(dev->dev, "failed to get dmm base address\n"); + goto fail; + } + + hwinfo = readl(omap_dmm->base + DMM_PAT_HWINFO); + omap_dmm->num_engines = (hwinfo >> 24) & 0x1F; + omap_dmm->num_lut = (hwinfo >> 16) & 0x1F; + omap_dmm->container_width = 256; + omap_dmm->container_height = 128; + + /* read out actual LUT width and height */ + pat_geom = readl(omap_dmm->base + DMM_PAT_GEOMETRY); + omap_dmm->lut_width = ((pat_geom >> 16) & 0xF) << 5; + omap_dmm->lut_height = ((pat_geom >> 24) & 0xF) << 5; + + /* initialize DMM registers */ + writel(0x88888888, omap_dmm->base + DMM_PAT_VIEW__0); + writel(0x88888888, omap_dmm->base + DMM_PAT_VIEW__1); + writel(0x80808080, omap_dmm->base + DMM_PAT_VIEW_MAP__0); + writel(0x80000000, omap_dmm->base + DMM_PAT_VIEW_MAP_BASE); + writel(0x88888888, omap_dmm->base + DMM_TILER_OR__0); + writel(0x88888888, omap_dmm->base + DMM_TILER_OR__1); + + ret = request_irq(omap_dmm->irq, omap_dmm_irq_handler, IRQF_SHARED, + "omap_dmm_irq_handler", omap_dmm); + + if (ret) { + dev_err(dev->dev, "couldn't register IRQ %d, error %d\n", + omap_dmm->irq, ret); + omap_dmm->irq = -1; + goto fail; + } + + /* Enable all interrupts for each refill engine except + * ERR_LUT_MISS<n> (which is just advisory, and we don't care + * about because we want to be able to refill live scanout + * buffers for accelerated pan/scroll) and FILL_DSC<n> which + * we just generally don't care about. + */ + writel(0x7e7e7e7e, omap_dmm->base + DMM_PAT_IRQENABLE_SET); + + lut_table_size = omap_dmm->lut_width * omap_dmm->lut_height * + omap_dmm->num_lut; + + omap_dmm->lut = vmalloc(lut_table_size * sizeof(*omap_dmm->lut)); + if (!omap_dmm->lut) { + dev_err(dev->dev, "could not allocate lut table\n"); + ret = -ENOMEM; + goto fail; + } + + omap_dmm->dummy_page = alloc_page(GFP_KERNEL | __GFP_DMA32); + if (!omap_dmm->dummy_page) { + dev_err(dev->dev, "could not allocate dummy page\n"); + ret = -ENOMEM; + goto fail; + } + omap_dmm->dummy_pa = page_to_phys(omap_dmm->dummy_page); + + /* alloc refill memory */ + omap_dmm->refill_va = dma_alloc_coherent(dev->dev, + REFILL_BUFFER_SIZE * omap_dmm->num_engines, + &omap_dmm->refill_pa, GFP_KERNEL); + if (!omap_dmm->refill_va) { + dev_err(dev->dev, "could not allocate refill memory\n"); + goto fail; + } + + /* alloc engines */ + omap_dmm->engines = kzalloc( + omap_dmm->num_engines * sizeof(struct refill_engine), + GFP_KERNEL); + if (!omap_dmm->engines) { + dev_err(dev->dev, "could not allocate engines\n"); + ret = -ENOMEM; + goto fail; + } + + sema_init(&omap_dmm->engine_sem, omap_dmm->num_engines); + INIT_LIST_HEAD(&omap_dmm->idle_head); + for (i = 0; i < omap_dmm->num_engines; i++) { + omap_dmm->engines[i].id = i; + omap_dmm->engines[i].dmm = omap_dmm; + omap_dmm->engines[i].refill_va = omap_dmm->refill_va + + (REFILL_BUFFER_SIZE * i); + omap_dmm->engines[i].refill_pa = omap_dmm->refill_pa + + (REFILL_BUFFER_SIZE * i); + init_waitqueue_head(&omap_dmm->engines[i].wait_for_refill); + + list_add(&omap_dmm->engines[i].idle_node, &omap_dmm->idle_head); + } + + omap_dmm->tcm = kzalloc(omap_dmm->num_lut * sizeof(*omap_dmm->tcm), + GFP_KERNEL); + if (!omap_dmm->tcm) { + dev_err(dev->dev, "failed to allocate lut ptrs\n"); + ret = -ENOMEM; + goto fail; + } + + /* init containers */ + for (i = 0; i < omap_dmm->num_lut; i++) { + omap_dmm->tcm[i] = sita_init(omap_dmm->container_width, + omap_dmm->container_height, + NULL); + + if (!omap_dmm->tcm[i]) { + dev_err(dev->dev, "failed to allocate container\n"); + ret = -ENOMEM; + goto fail; + } + + omap_dmm->tcm[i]->lut_id = i; + } + + /* assign access mode containers to applicable tcm container */ + /* OMAP 4 has 1 container for all 4 views */ + containers[TILFMT_8BIT] = omap_dmm->tcm[0]; + containers[TILFMT_16BIT] = omap_dmm->tcm[0]; + containers[TILFMT_32BIT] = omap_dmm->tcm[0]; + containers[TILFMT_PAGE] = omap_dmm->tcm[0]; + + INIT_LIST_HEAD(&omap_dmm->alloc_head); + spin_lock_init(&omap_dmm->list_lock); + + area = (struct tcm_area) { + .is2d = true, + .tcm = NULL, + .p1.x = omap_dmm->container_width - 1, + .p1.y = omap_dmm->container_height - 1, + }; + + for (i = 0; i < lut_table_size; i++) + omap_dmm->lut[i] = omap_dmm->dummy_pa; + + /* initialize all LUTs to dummy page entries */ + for (i = 0; i < omap_dmm->num_lut; i++) { + area.tcm = omap_dmm->tcm[i]; + if (fill(&area, NULL, 0, 0, true)) + dev_err(omap_dmm->dev, "refill failed"); + } + + dev_info(omap_dmm->dev, "initialized all PAT entries\n"); + + return 0; + +fail: + omap_dmm_remove(); + return ret; +} + +/* + * debugfs support + */ + +#ifdef CONFIG_DEBUG_FS + +static const char *alphabet = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +static const char *special = ".,:;'\"`~!^-+"; + +static void fill_map(char **map, int xdiv, int ydiv, struct tcm_area *a, + char c, bool ovw) +{ + int x, y; + for (y = a->p0.y / ydiv; y <= a->p1.y / ydiv; y++) + for (x = a->p0.x / xdiv; x <= a->p1.x / xdiv; x++) + if (map[y][x] == ' ' || ovw) + map[y][x] = c; +} + +static void fill_map_pt(char **map, int xdiv, int ydiv, struct tcm_pt *p, + char c) +{ + map[p->y / ydiv][p->x / xdiv] = c; +} + +static char read_map_pt(char **map, int xdiv, int ydiv, struct tcm_pt *p) +{ + return map[p->y / ydiv][p->x / xdiv]; +} + +static int map_width(int xdiv, int x0, int x1) +{ + return (x1 / xdiv) - (x0 / xdiv) + 1; +} + +static void text_map(char **map, int xdiv, char *nice, int yd, int x0, int x1) +{ + char *p = map[yd] + (x0 / xdiv); + int w = (map_width(xdiv, x0, x1) - strlen(nice)) / 2; + if (w >= 0) { + p += w; + while (*nice) + *p++ = *nice++; + } +} + +static void map_1d_info(char **map, int xdiv, int ydiv, char *nice, + struct tcm_area *a) +{ + sprintf(nice, "%dK", tcm_sizeof(*a) * 4); + if (a->p0.y + 1 < a->p1.y) { + text_map(map, xdiv, nice, (a->p0.y + a->p1.y) / 2 / ydiv, 0, + 256 - 1); + } else if (a->p0.y < a->p1.y) { + if (strlen(nice) < map_width(xdiv, a->p0.x, 256 - 1)) + text_map(map, xdiv, nice, a->p0.y / ydiv, + a->p0.x + xdiv, 256 - 1); + else if (strlen(nice) < map_width(xdiv, 0, a->p1.x)) + text_map(map, xdiv, nice, a->p1.y / ydiv, + 0, a->p1.y - xdiv); + } else if (strlen(nice) + 1 < map_width(xdiv, a->p0.x, a->p1.x)) { + text_map(map, xdiv, nice, a->p0.y / ydiv, a->p0.x, a->p1.x); + } +} + +static void map_2d_info(char **map, int xdiv, int ydiv, char *nice, + struct tcm_area *a) +{ + sprintf(nice, "(%d*%d)", tcm_awidth(*a), tcm_aheight(*a)); + if (strlen(nice) + 1 < map_width(xdiv, a->p0.x, a->p1.x)) + text_map(map, xdiv, nice, (a->p0.y + a->p1.y) / 2 / ydiv, + a->p0.x, a->p1.x); +} + +int tiler_map_show(struct seq_file *s, void *arg) +{ + int xdiv = 2, ydiv = 1; + char **map = NULL, *global_map; + struct tiler_block *block; + struct tcm_area a, p; + int i; + const char *m2d = alphabet; + const char *a2d = special; + const char *m2dp = m2d, *a2dp = a2d; + char nice[128]; + int h_adj = omap_dmm->lut_height / ydiv; + int w_adj = omap_dmm->lut_width / xdiv; + unsigned long flags; + + map = kzalloc(h_adj * sizeof(*map), GFP_KERNEL); + global_map = kzalloc((w_adj + 1) * h_adj, GFP_KERNEL); + + if (!map || !global_map) + goto error; + + memset(global_map, ' ', (w_adj + 1) * h_adj); + for (i = 0; i < omap_dmm->lut_height; i++) { + map[i] = global_map + i * (w_adj + 1); + map[i][w_adj] = 0; + } + spin_lock_irqsave(&omap_dmm->list_lock, flags); + + list_for_each_entry(block, &omap_dmm->alloc_head, alloc_node) { + if (block->fmt != TILFMT_PAGE) { + fill_map(map, xdiv, ydiv, &block->area, *m2dp, true); + if (!*++a2dp) + a2dp = a2d; + if (!*++m2dp) + m2dp = m2d; + map_2d_info(map, xdiv, ydiv, nice, &block->area); + } else { + bool start = read_map_pt(map, xdiv, ydiv, + &block->area.p0) + == ' '; + bool end = read_map_pt(map, xdiv, ydiv, &block->area.p1) + == ' '; + tcm_for_each_slice(a, block->area, p) + fill_map(map, xdiv, ydiv, &a, '=', true); + fill_map_pt(map, xdiv, ydiv, &block->area.p0, + start ? '<' : 'X'); + fill_map_pt(map, xdiv, ydiv, &block->area.p1, + end ? '>' : 'X'); + map_1d_info(map, xdiv, ydiv, nice, &block->area); + } + } + + spin_unlock_irqrestore(&omap_dmm->list_lock, flags); + + if (s) { + seq_printf(s, "BEGIN DMM TILER MAP\n"); + for (i = 0; i < 128; i++) + seq_printf(s, "%03d:%s\n", i, map[i]); + seq_printf(s, "END TILER MAP\n"); + } else { + dev_dbg(omap_dmm->dev, "BEGIN DMM TILER MAP\n"); + for (i = 0; i < 128; i++) + dev_dbg(omap_dmm->dev, "%03d:%s\n", i, map[i]); + dev_dbg(omap_dmm->dev, "END TILER MAP\n"); + } + +error: + kfree(map); + kfree(global_map); + + return 0; +} +#endif diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.h b/drivers/staging/omapdrm/omap_dmm_tiler.h new file mode 100644 index 00000000000..f87cb657d68 --- /dev/null +++ b/drivers/staging/omapdrm/omap_dmm_tiler.h @@ -0,0 +1,135 @@ +/* + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Rob Clark <rob@ti.com> + * Andy Gross <andy.gross@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef OMAP_DMM_TILER_H +#define OMAP_DMM_TILER_H + +#include "omap_drv.h" +#include "tcm.h" + +enum tiler_fmt { + TILFMT_8BIT = 0, + TILFMT_16BIT, + TILFMT_32BIT, + TILFMT_PAGE, + TILFMT_NFORMATS +}; + +struct pat_area { + u32 x0:8; + u32 y0:8; + u32 x1:8; + u32 y1:8; +}; + +struct tiler_block { + struct list_head alloc_node; /* node for global block list */ + struct tcm_area area; /* area */ + enum tiler_fmt fmt; /* format */ +}; + +/* bits representing the same slot in DMM-TILER hw-block */ +#define SLOT_WIDTH_BITS 6 +#define SLOT_HEIGHT_BITS 6 + +/* bits reserved to describe coordinates in DMM-TILER hw-block */ +#define CONT_WIDTH_BITS 14 +#define CONT_HEIGHT_BITS 13 + +/* calculated constants */ +#define TILER_PAGE (1 << (SLOT_WIDTH_BITS + SLOT_HEIGHT_BITS)) +#define TILER_WIDTH (1 << (CONT_WIDTH_BITS - SLOT_WIDTH_BITS)) +#define TILER_HEIGHT (1 << (CONT_HEIGHT_BITS - SLOT_HEIGHT_BITS)) + +/* tiler space addressing bitfields */ +#define MASK_XY_FLIP (1 << 31) +#define MASK_Y_INVERT (1 << 30) +#define MASK_X_INVERT (1 << 29) +#define SHIFT_ACC_MODE 27 +#define MASK_ACC_MODE 3 + +#define MASK(bits) ((1 << (bits)) - 1) + +#define TILVIEW_8BIT 0x60000000u +#define TILVIEW_16BIT (TILVIEW_8BIT + VIEW_SIZE) +#define TILVIEW_32BIT (TILVIEW_16BIT + VIEW_SIZE) +#define TILVIEW_PAGE (TILVIEW_32BIT + VIEW_SIZE) +#define TILVIEW_END (TILVIEW_PAGE + VIEW_SIZE) + +/* create tsptr by adding view orientation and access mode */ +#define TIL_ADDR(x, orient, a)\ + ((u32) (x) | (orient) | ((a) << SHIFT_ACC_MODE)) + +/* externally accessible functions */ +int omap_dmm_init(struct drm_device *dev); +int omap_dmm_remove(void); + +#ifdef CONFIG_DEBUG_FS +int tiler_map_show(struct seq_file *s, void *arg); +#endif + +/* pin/unpin */ +int tiler_pin(struct tiler_block *block, struct page **pages, + uint32_t npages, uint32_t roll, bool wait); +int tiler_unpin(struct tiler_block *block); + +/* reserve/release */ +struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, uint16_t h, + uint16_t align); +struct tiler_block *tiler_reserve_1d(size_t size); +int tiler_release(struct tiler_block *block); + +/* utilities */ +dma_addr_t tiler_ssptr(struct tiler_block *block); +uint32_t tiler_stride(enum tiler_fmt fmt); +size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h); +size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h); +void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h); + + +/* GEM bo flags -> tiler fmt */ +static inline enum tiler_fmt gem2fmt(uint32_t flags) +{ + switch (flags & OMAP_BO_TILED) { + case OMAP_BO_TILED_8: + return TILFMT_8BIT; + case OMAP_BO_TILED_16: + return TILFMT_16BIT; + case OMAP_BO_TILED_32: + return TILFMT_32BIT; + default: + return TILFMT_PAGE; + } +} + +static inline bool validfmt(enum tiler_fmt fmt) +{ + switch (fmt) { + case TILFMT_8BIT: + case TILFMT_16BIT: + case TILFMT_32BIT: + case TILFMT_PAGE: + return true; + default: + return false; + } +} + +struct omap_dmm_platform_data { + void __iomem *base; + int irq; +}; + +#endif diff --git a/drivers/staging/omapdrm/omap_drm.h b/drivers/staging/omapdrm/omap_drm.h new file mode 100644 index 00000000000..f0ac34a8973 --- /dev/null +++ b/drivers/staging/omapdrm/omap_drm.h @@ -0,0 +1,123 @@ +/* + * include/drm/omap_drm.h + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __OMAP_DRM_H__ +#define __OMAP_DRM_H__ + +#include <drm/drm.h> + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +#define OMAP_PARAM_CHIPSET_ID 1 /* ie. 0x3430, 0x4430, etc */ + +struct drm_omap_param { + uint64_t param; /* in */ + uint64_t value; /* in (set_param), out (get_param) */ +}; + +#define OMAP_BO_SCANOUT 0x00000001 /* scanout capable (phys contiguous) */ +#define OMAP_BO_CACHE_MASK 0x00000006 /* cache type mask, see cache modes */ +#define OMAP_BO_TILED_MASK 0x00000f00 /* tiled mapping mask, see tiled modes */ + +/* cache modes */ +#define OMAP_BO_CACHED 0x00000000 /* default */ +#define OMAP_BO_WC 0x00000002 /* write-combine */ +#define OMAP_BO_UNCACHED 0x00000004 /* strongly-ordered (uncached) */ + +/* tiled modes */ +#define OMAP_BO_TILED_8 0x00000100 +#define OMAP_BO_TILED_16 0x00000200 +#define OMAP_BO_TILED_32 0x00000300 +#define OMAP_BO_TILED (OMAP_BO_TILED_8 | OMAP_BO_TILED_16 | OMAP_BO_TILED_32) + +union omap_gem_size { + uint32_t bytes; /* (for non-tiled formats) */ + struct { + uint16_t width; + uint16_t height; + } tiled; /* (for tiled formats) */ +}; + +struct drm_omap_gem_new { + union omap_gem_size size; /* in */ + uint32_t flags; /* in */ + uint32_t handle; /* out */ + uint32_t __pad; +}; + +/* mask of operations: */ +enum omap_gem_op { + OMAP_GEM_READ = 0x01, + OMAP_GEM_WRITE = 0x02, +}; + +struct drm_omap_gem_cpu_prep { + uint32_t handle; /* buffer handle (in) */ + uint32_t op; /* mask of omap_gem_op (in) */ +}; + +struct drm_omap_gem_cpu_fini { + uint32_t handle; /* buffer handle (in) */ + uint32_t op; /* mask of omap_gem_op (in) */ + /* TODO maybe here we pass down info about what regions are touched + * by sw so we can be clever about cache ops? For now a placeholder, + * set to zero and we just do full buffer flush.. + */ + uint32_t nregions; + uint32_t __pad; +}; + +struct drm_omap_gem_info { + uint32_t handle; /* buffer handle (in) */ + uint32_t pad; + uint64_t offset; /* mmap offset (out) */ + /* note: in case of tiled buffers, the user virtual size can be + * different from the physical size (ie. how many pages are needed + * to back the object) which is returned in DRM_IOCTL_GEM_OPEN.. + * This size here is the one that should be used if you want to + * mmap() the buffer: + */ + uint32_t size; /* virtual size for mmap'ing (out) */ + uint32_t __pad; +}; + +#define DRM_OMAP_GET_PARAM 0x00 +#define DRM_OMAP_SET_PARAM 0x01 +/* placeholder for plugin-api +#define DRM_OMAP_GET_BASE 0x02 +*/ +#define DRM_OMAP_GEM_NEW 0x03 +#define DRM_OMAP_GEM_CPU_PREP 0x04 +#define DRM_OMAP_GEM_CPU_FINI 0x05 +#define DRM_OMAP_GEM_INFO 0x06 +#define DRM_OMAP_NUM_IOCTLS 0x07 + +#define DRM_IOCTL_OMAP_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_PARAM, struct drm_omap_param) +#define DRM_IOCTL_OMAP_SET_PARAM DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_SET_PARAM, struct drm_omap_param) +/* placeholder for plugin-api +#define DRM_IOCTL_OMAP_GET_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_BASE, struct drm_omap_get_base) +*/ +#define DRM_IOCTL_OMAP_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GEM_NEW, struct drm_omap_gem_new) +#define DRM_IOCTL_OMAP_GEM_CPU_PREP DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_PREP, struct drm_omap_gem_cpu_prep) +#define DRM_IOCTL_OMAP_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_FINI, struct drm_omap_gem_cpu_fini) +#define DRM_IOCTL_OMAP_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GEM_INFO, struct drm_omap_gem_info) + +#endif /* __OMAP_DRM_H__ */ diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c new file mode 100644 index 00000000000..602aa2dd49c --- /dev/null +++ b/drivers/staging/omapdrm/omap_drv.c @@ -0,0 +1,821 @@ +/* + * drivers/staging/omapdrm/omap_drv.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "omap_drv.h" + +#include "drm_crtc_helper.h" +#include "drm_fb_helper.h" + +#define DRIVER_NAME MODULE_NAME +#define DRIVER_DESC "OMAP DRM" +#define DRIVER_DATE "20110917" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +struct drm_device *drm_device; + +static int num_crtc = CONFIG_DRM_OMAP_NUM_CRTCS; + +MODULE_PARM_DESC(num_crtc, "Number of overlays to use as CRTCs"); +module_param(num_crtc, int, 0600); + +/* + * mode config funcs + */ + +/* Notes about mapping DSS and DRM entities: + * CRTC: overlay + * encoder: manager.. with some extension to allow one primary CRTC + * and zero or more video CRTC's to be mapped to one encoder? + * connector: dssdev.. manager can be attached/detached from different + * devices + */ + +static void omap_fb_output_poll_changed(struct drm_device *dev) +{ + struct omap_drm_private *priv = dev->dev_private; + DBG("dev=%p", dev); + if (priv->fbdev) { + drm_fb_helper_hotplug_event(priv->fbdev); + } +} + +static struct drm_mode_config_funcs omap_mode_config_funcs = { + .fb_create = omap_framebuffer_create, + .output_poll_changed = omap_fb_output_poll_changed, +}; + +static int get_connector_type(struct omap_dss_device *dssdev) +{ + switch (dssdev->type) { + case OMAP_DISPLAY_TYPE_HDMI: + return DRM_MODE_CONNECTOR_HDMIA; + case OMAP_DISPLAY_TYPE_DPI: + if (!strcmp(dssdev->name, "dvi")) + return DRM_MODE_CONNECTOR_DVID; + /* fallthrough */ + default: + return DRM_MODE_CONNECTOR_Unknown; + } +} + +#if 0 /* enable when dss2 supports hotplug */ +static int omap_drm_notifier(struct notifier_block *nb, + unsigned long evt, void *arg) +{ + switch (evt) { + case OMAP_DSS_SIZE_CHANGE: + case OMAP_DSS_HOTPLUG_CONNECT: + case OMAP_DSS_HOTPLUG_DISCONNECT: { + struct drm_device *dev = drm_device; + DBG("hotplug event: evt=%d, dev=%p", evt, dev); + if (dev) { + drm_sysfs_hotplug_event(dev); + } + return NOTIFY_OK; + } + default: /* don't care about other events for now */ + return NOTIFY_DONE; + } +} +#endif + +static void dump_video_chains(void) +{ + int i; + + DBG("dumping video chains: "); + for (i = 0; i < omap_dss_get_num_overlays(); i++) { + struct omap_overlay *ovl = omap_dss_get_overlay(i); + struct omap_overlay_manager *mgr = ovl->manager; + struct omap_dss_device *dssdev = mgr ? mgr->device : NULL; + if (dssdev) { + DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name, + dssdev->name); + } else if (mgr) { + DBG("%d: %s -> %s", i, ovl->name, mgr->name); + } else { + DBG("%d: %s", i, ovl->name); + } + } +} + +/* create encoders for each manager */ +static int create_encoder(struct drm_device *dev, + struct omap_overlay_manager *mgr) +{ + struct omap_drm_private *priv = dev->dev_private; + struct drm_encoder *encoder = omap_encoder_init(dev, mgr); + + if (!encoder) { + dev_err(dev->dev, "could not create encoder: %s\n", + mgr->name); + return -ENOMEM; + } + + BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); + + priv->encoders[priv->num_encoders++] = encoder; + + return 0; +} + +/* create connectors for each display device */ +static int create_connector(struct drm_device *dev, + struct omap_dss_device *dssdev) +{ + struct omap_drm_private *priv = dev->dev_private; + static struct notifier_block *notifier; + struct drm_connector *connector; + int j; + + if (!dssdev->driver) { + dev_warn(dev->dev, "%s has no driver.. skipping it\n", + dssdev->name); + return 0; + } + + if (!(dssdev->driver->get_timings || + dssdev->driver->read_edid)) { + dev_warn(dev->dev, "%s driver does not support " + "get_timings or read_edid.. skipping it!\n", + dssdev->name); + return 0; + } + + connector = omap_connector_init(dev, + get_connector_type(dssdev), dssdev); + + if (!connector) { + dev_err(dev->dev, "could not create connector: %s\n", + dssdev->name); + return -ENOMEM; + } + + BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); + + priv->connectors[priv->num_connectors++] = connector; + +#if 0 /* enable when dss2 supports hotplug */ + notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); + notifier->notifier_call = omap_drm_notifier; + omap_dss_add_notify(dssdev, notifier); +#else + notifier = NULL; +#endif + + for (j = 0; j < priv->num_encoders; j++) { + struct omap_overlay_manager *mgr = + omap_encoder_get_manager(priv->encoders[j]); + if (mgr->device == dssdev) { + drm_mode_connector_attach_encoder(connector, + priv->encoders[j]); + } + } + + return 0; +} + +/* create up to max_overlays CRTCs mapping to overlays.. by default, + * connect the overlays to different managers/encoders, giving priority + * to encoders connected to connectors with a detected connection + */ +static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl, + int *j, unsigned int connected_connectors) +{ + struct omap_drm_private *priv = dev->dev_private; + struct omap_overlay_manager *mgr = NULL; + struct drm_crtc *crtc; + + if (ovl->manager) { + DBG("disconnecting %s from %s", ovl->name, + ovl->manager->name); + ovl->unset_manager(ovl); + } + + /* find next best connector, ones with detected connection first + */ + while (*j < priv->num_connectors && !mgr) { + if (connected_connectors & (1 << *j)) { + struct drm_encoder *encoder = + omap_connector_attached_encoder( + priv->connectors[*j]); + if (encoder) { + mgr = omap_encoder_get_manager(encoder); + } + } + (*j)++; + } + + /* if we couldn't find another connected connector, lets start + * looking at the unconnected connectors: + * + * note: it might not be immediately apparent, but thanks to + * the !mgr check in both this loop and the one above, the only + * way to enter this loop is with *j == priv->num_connectors, + * so idx can never go negative. + */ + while (*j < 2 * priv->num_connectors && !mgr) { + int idx = *j - priv->num_connectors; + if (!(connected_connectors & (1 << idx))) { + struct drm_encoder *encoder = + omap_connector_attached_encoder( + priv->connectors[idx]); + if (encoder) { + mgr = omap_encoder_get_manager(encoder); + } + } + (*j)++; + } + + if (mgr) { + DBG("connecting %s to %s", ovl->name, mgr->name); + ovl->set_manager(ovl, mgr); + } + + crtc = omap_crtc_init(dev, ovl, priv->num_crtcs); + + if (!crtc) { + dev_err(dev->dev, "could not create CRTC: %s\n", + ovl->name); + return -ENOMEM; + } + + BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); + + priv->crtcs[priv->num_crtcs++] = crtc; + + return 0; +} + +static int match_dev_name(struct omap_dss_device *dssdev, void *data) +{ + return !strcmp(dssdev->name, data); +} + +static unsigned int detect_connectors(struct drm_device *dev) +{ + struct omap_drm_private *priv = dev->dev_private; + unsigned int connected_connectors = 0; + int i; + + for (i = 0; i < priv->num_connectors; i++) { + struct drm_connector *connector = priv->connectors[i]; + if (omap_connector_detect(connector, true) == + connector_status_connected) { + connected_connectors |= (1 << i); + } + } + + return connected_connectors; +} + +static int omap_modeset_init(struct drm_device *dev) +{ + const struct omap_drm_platform_data *pdata = dev->dev->platform_data; + struct omap_kms_platform_data *kms_pdata = NULL; + struct omap_drm_private *priv = dev->dev_private; + struct omap_dss_device *dssdev = NULL; + int i, j; + unsigned int connected_connectors = 0; + + drm_mode_config_init(dev); + + if (pdata && pdata->kms_pdata) { + kms_pdata = pdata->kms_pdata; + + /* if platform data is provided by the board file, use it to + * control which overlays, managers, and devices we own. + */ + for (i = 0; i < kms_pdata->mgr_cnt; i++) { + struct omap_overlay_manager *mgr = + omap_dss_get_overlay_manager( + kms_pdata->mgr_ids[i]); + create_encoder(dev, mgr); + } + + for (i = 0; i < kms_pdata->dev_cnt; i++) { + struct omap_dss_device *dssdev = + omap_dss_find_device( + (void *)kms_pdata->dev_names[i], + match_dev_name); + if (!dssdev) { + dev_warn(dev->dev, "no such dssdev: %s\n", + kms_pdata->dev_names[i]); + continue; + } + create_connector(dev, dssdev); + } + + connected_connectors = detect_connectors(dev); + + j = 0; + for (i = 0; i < kms_pdata->ovl_cnt; i++) { + struct omap_overlay *ovl = + omap_dss_get_overlay(kms_pdata->ovl_ids[i]); + create_crtc(dev, ovl, &j, connected_connectors); + } + } else { + /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try + * to make educated guesses about everything else + */ + int max_overlays = min(omap_dss_get_num_overlays(), num_crtc); + + for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { + create_encoder(dev, omap_dss_get_overlay_manager(i)); + } + + for_each_dss_dev(dssdev) { + create_connector(dev, dssdev); + } + + connected_connectors = detect_connectors(dev); + + j = 0; + for (i = 0; i < max_overlays; i++) { + create_crtc(dev, omap_dss_get_overlay(i), + &j, connected_connectors); + } + } + + /* for now keep the mapping of CRTCs and encoders static.. */ + for (i = 0; i < priv->num_encoders; i++) { + struct drm_encoder *encoder = priv->encoders[i]; + struct omap_overlay_manager *mgr = + omap_encoder_get_manager(encoder); + + encoder->possible_crtcs = 0; + + for (j = 0; j < priv->num_crtcs; j++) { + struct omap_overlay *ovl = + omap_crtc_get_overlay(priv->crtcs[j]); + if (ovl->manager == mgr) { + encoder->possible_crtcs |= (1 << j); + } + } + + DBG("%s: possible_crtcs=%08x", mgr->name, + encoder->possible_crtcs); + } + + dump_video_chains(); + + dev->mode_config.min_width = 256; + dev->mode_config.min_height = 256; + + /* note: eventually will need some cpu_is_omapXYZ() type stuff here + * to fill in these limits properly on different OMAP generations.. + */ + dev->mode_config.max_width = 2048; + dev->mode_config.max_height = 2048; + + dev->mode_config.funcs = &omap_mode_config_funcs; + + return 0; +} + +static void omap_modeset_free(struct drm_device *dev) +{ + drm_mode_config_cleanup(dev); +} + +/* + * drm ioctl funcs + */ + + +static int ioctl_get_param(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_omap_param *args = data; + + DBG("%p: param=%llu", dev, args->param); + + switch (args->param) { + case OMAP_PARAM_CHIPSET_ID: + args->value = GET_OMAP_TYPE; + break; + default: + DBG("unknown parameter %lld", args->param); + return -EINVAL; + } + + return 0; +} + +static int ioctl_set_param(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_omap_param *args = data; + + switch (args->param) { + default: + DBG("unknown parameter %lld", args->param); + return -EINVAL; + } + + return 0; +} + +static int ioctl_gem_new(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_omap_gem_new *args = data; + DBG("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, + args->size.bytes, args->flags); + return omap_gem_new_handle(dev, file_priv, args->size, + args->flags, &args->handle); +} + +static int ioctl_gem_cpu_prep(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_omap_gem_cpu_prep *args = data; + struct drm_gem_object *obj; + int ret; + + VERB("%p:%p: handle=%d, op=%x", dev, file_priv, args->handle, args->op); + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (!obj) { + return -ENOENT; + } + + ret = omap_gem_op_sync(obj, args->op); + + if (!ret) { + ret = omap_gem_op_start(obj, args->op); + } + + drm_gem_object_unreference_unlocked(obj); + + return ret; +} + +static int ioctl_gem_cpu_fini(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_omap_gem_cpu_fini *args = data; + struct drm_gem_object *obj; + int ret; + + VERB("%p:%p: handle=%d", dev, file_priv, args->handle); + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (!obj) { + return -ENOENT; + } + + /* XXX flushy, flushy */ + ret = 0; + + if (!ret) { + ret = omap_gem_op_finish(obj, args->op); + } + + drm_gem_object_unreference_unlocked(obj); + + return ret; +} + +static int ioctl_gem_info(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_omap_gem_info *args = data; + struct drm_gem_object *obj; + int ret = 0; + + DBG("%p:%p: handle=%d", dev, file_priv, args->handle); + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (!obj) { + return -ENOENT; + } + + args->size = omap_gem_mmap_size(obj); + args->offset = omap_gem_mmap_offset(obj); + + drm_gem_object_unreference_unlocked(obj); + + return ret; +} + +struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { + DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_PREP, ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_FINI, ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(OMAP_GEM_INFO, ioctl_gem_info, DRM_UNLOCKED|DRM_AUTH), +}; + +/* + * drm driver funcs + */ + +/** + * load - setup chip and create an initial config + * @dev: DRM device + * @flags: startup flags + * + * The driver load routine has to do several things: + * - initialize the memory manager + * - allocate initial config memory + * - setup the DRM framebuffer with the allocated memory + */ +static int dev_load(struct drm_device *dev, unsigned long flags) +{ + struct omap_drm_private *priv; + int ret; + + DBG("load: dev=%p", dev); + + drm_device = dev; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(dev->dev, "could not allocate priv\n"); + return -ENOMEM; + } + + dev->dev_private = priv; + + omap_gem_init(dev); + + ret = omap_modeset_init(dev); + if (ret) { + dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); + dev->dev_private = NULL; + kfree(priv); + return ret; + } + + priv->fbdev = omap_fbdev_init(dev); + if (!priv->fbdev) { + dev_warn(dev->dev, "omap_fbdev_init failed\n"); + /* well, limp along without an fbdev.. maybe X11 will work? */ + } + + drm_kms_helper_poll_init(dev); + + ret = drm_vblank_init(dev, priv->num_crtcs); + if (ret) { + dev_warn(dev->dev, "could not init vblank\n"); + } + + return 0; +} + +static int dev_unload(struct drm_device *dev) +{ + DBG("unload: dev=%p", dev); + + drm_vblank_cleanup(dev); + drm_kms_helper_poll_fini(dev); + + omap_fbdev_free(dev); + omap_modeset_free(dev); + omap_gem_deinit(dev); + + kfree(dev->dev_private); + dev->dev_private = NULL; + + return 0; +} + +static int dev_open(struct drm_device *dev, struct drm_file *file) +{ + file->driver_priv = NULL; + + DBG("open: dev=%p, file=%p", dev, file); + + return 0; +} + +static int dev_firstopen(struct drm_device *dev) +{ + DBG("firstopen: dev=%p", dev); + return 0; +} + +/** + * lastclose - clean up after all DRM clients have exited + * @dev: DRM device + * + * Take care of cleaning up after all DRM clients have exited. In the + * mode setting case, we want to restore the kernel's initial mode (just + * in case the last client left us in a bad state). + */ +static void dev_lastclose(struct drm_device *dev) +{ + /* we don't support vga-switcheroo.. so just make sure the fbdev + * mode is active + */ + struct omap_drm_private *priv = dev->dev_private; + int ret; + + DBG("lastclose: dev=%p", dev); + + ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); + if (ret) + DBG("failed to restore crtc mode"); +} + +static void dev_preclose(struct drm_device *dev, struct drm_file *file) +{ + DBG("preclose: dev=%p", dev); +} + +static void dev_postclose(struct drm_device *dev, struct drm_file *file) +{ + DBG("postclose: dev=%p, file=%p", dev, file); +} + +/** + * enable_vblank - enable vblank interrupt events + * @dev: DRM device + * @crtc: which irq to enable + * + * Enable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, this routine should be a no-op, since + * interrupts will have to stay on to keep the count accurate. + * + * RETURNS + * Zero on success, appropriate errno if the given @crtc's vblank + * interrupt cannot be enabled. + */ +static int dev_enable_vblank(struct drm_device *dev, int crtc) +{ + DBG("enable_vblank: dev=%p, crtc=%d", dev, crtc); + return 0; +} + +/** + * disable_vblank - disable vblank interrupt events + * @dev: DRM device + * @crtc: which irq to enable + * + * Disable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, this routine should be a no-op, since + * interrupts will have to stay on to keep the count accurate. + */ +static void dev_disable_vblank(struct drm_device *dev, int crtc) +{ + DBG("disable_vblank: dev=%p, crtc=%d", dev, crtc); +} + +static irqreturn_t dev_irq_handler(DRM_IRQ_ARGS) +{ + return IRQ_HANDLED; +} + +static void dev_irq_preinstall(struct drm_device *dev) +{ + DBG("irq_preinstall: dev=%p", dev); +} + +static int dev_irq_postinstall(struct drm_device *dev) +{ + DBG("irq_postinstall: dev=%p", dev); + return 0; +} + +static void dev_irq_uninstall(struct drm_device *dev) +{ + DBG("irq_uninstall: dev=%p", dev); +} + +static struct vm_operations_struct omap_gem_vm_ops = { + .fault = omap_gem_fault, + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + +static struct drm_driver omap_drm_driver = { + .driver_features = + DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM, + .load = dev_load, + .unload = dev_unload, + .open = dev_open, + .firstopen = dev_firstopen, + .lastclose = dev_lastclose, + .preclose = dev_preclose, + .postclose = dev_postclose, + .get_vblank_counter = drm_vblank_count, + .enable_vblank = dev_enable_vblank, + .disable_vblank = dev_disable_vblank, + .irq_preinstall = dev_irq_preinstall, + .irq_postinstall = dev_irq_postinstall, + .irq_uninstall = dev_irq_uninstall, + .irq_handler = dev_irq_handler, + .reclaim_buffers = drm_core_reclaim_buffers, +#ifdef CONFIG_DEBUG_FS + .debugfs_init = omap_debugfs_init, + .debugfs_cleanup = omap_debugfs_cleanup, +#endif + .gem_init_object = omap_gem_init_object, + .gem_free_object = omap_gem_free_object, + .gem_vm_ops = &omap_gem_vm_ops, + .dumb_create = omap_gem_dumb_create, + .dumb_map_offset = omap_gem_dumb_map_offset, + .dumb_destroy = omap_gem_dumb_destroy, + .ioctls = ioctls, + .num_ioctls = DRM_OMAP_NUM_IOCTLS, + .fops = { + .owner = THIS_MODULE, + .open = drm_open, + .unlocked_ioctl = drm_ioctl, + .release = drm_release, + .mmap = omap_gem_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + .read = drm_read, + .llseek = noop_llseek, + }, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; + +static int pdev_suspend(struct platform_device *pDevice, pm_message_t state) +{ + DBG(""); + return 0; +} + +static int pdev_resume(struct platform_device *device) +{ + DBG(""); + return 0; +} + +static void pdev_shutdown(struct platform_device *device) +{ + DBG(""); +} + +static int pdev_probe(struct platform_device *device) +{ + DBG("%s", device->name); + return drm_platform_init(&omap_drm_driver, device); +} + +static int pdev_remove(struct platform_device *device) +{ + DBG(""); + drm_platform_exit(&omap_drm_driver, device); + return 0; +} + +struct platform_driver pdev = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = pdev_probe, + .remove = pdev_remove, + .suspend = pdev_suspend, + .resume = pdev_resume, + .shutdown = pdev_shutdown, +}; + +static int __init omap_drm_init(void) +{ + DBG("init"); + return platform_driver_register(&pdev); +} + +static void __exit omap_drm_fini(void) +{ + DBG("fini"); + platform_driver_unregister(&pdev); +} + +/* need late_initcall() so we load after dss_driver's are loaded */ +late_initcall(omap_drm_init); +module_exit(omap_drm_fini); + +MODULE_AUTHOR("Rob Clark <rob@ti.com>"); +MODULE_DESCRIPTION("OMAP DRM Display Driver"); +MODULE_ALIAS("platform:" DRIVER_NAME); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h new file mode 100644 index 00000000000..76c42515ecc --- /dev/null +++ b/drivers/staging/omapdrm/omap_drv.h @@ -0,0 +1,135 @@ +/* + * drivers/staging/omapdrm/omap_drv.h + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __OMAP_DRV_H__ +#define __OMAP_DRV_H__ + +#include <video/omapdss.h> +#include <linux/module.h> +#include <linux/types.h> +#include <drm/drmP.h> +#include "omap_drm.h" +#include "omap_priv.h" + +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) +#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ + +#define MODULE_NAME "omapdrm" + +/* max # of mapper-id's that can be assigned.. todo, come up with a better + * (but still inexpensive) way to store/access per-buffer mapper private + * data.. + */ +#define MAX_MAPPERS 2 + +struct omap_drm_private { + unsigned int num_crtcs; + struct drm_crtc *crtcs[8]; + unsigned int num_encoders; + struct drm_encoder *encoders[8]; + unsigned int num_connectors; + struct drm_connector *connectors[8]; + + struct drm_fb_helper *fbdev; + + bool has_dmm; +}; + +#ifdef CONFIG_DEBUG_FS +int omap_debugfs_init(struct drm_minor *minor); +void omap_debugfs_cleanup(struct drm_minor *minor); +#endif + +struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); +void omap_fbdev_free(struct drm_device *dev); + +struct drm_crtc *omap_crtc_init(struct drm_device *dev, + struct omap_overlay *ovl, int id); +struct omap_overlay *omap_crtc_get_overlay(struct drm_crtc *crtc); + +struct drm_encoder *omap_encoder_init(struct drm_device *dev, + struct omap_overlay_manager *mgr); +struct omap_overlay_manager *omap_encoder_get_manager( + struct drm_encoder *encoder); +struct drm_encoder *omap_connector_attached_encoder( + struct drm_connector *connector); +enum drm_connector_status omap_connector_detect( + struct drm_connector *connector, bool force); + +struct drm_connector *omap_connector_init(struct drm_device *dev, + int connector_type, struct omap_dss_device *dssdev); +void omap_connector_mode_set(struct drm_connector *connector, + struct drm_display_mode *mode); +void omap_connector_flush(struct drm_connector *connector, + int x, int y, int w, int h); + +struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, + struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd); +struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo); +struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb); +int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y, + void **vaddr, dma_addr_t *paddr, unsigned int *screen_width); +struct drm_connector *omap_framebuffer_get_next_connector( + struct drm_framebuffer *fb, struct drm_connector *from); +void omap_framebuffer_flush(struct drm_framebuffer *fb, + int x, int y, int w, int h); + +void omap_gem_init(struct drm_device *dev); +void omap_gem_deinit(struct drm_device *dev); + +struct drm_gem_object *omap_gem_new(struct drm_device *dev, + union omap_gem_size gsize, uint32_t flags); +int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, + union omap_gem_size gsize, uint32_t flags, uint32_t *handle); +void omap_gem_free_object(struct drm_gem_object *obj); +int omap_gem_init_object(struct drm_gem_object *obj); +void *omap_gem_vaddr(struct drm_gem_object *obj); +int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset); +int omap_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, + uint32_t handle); +int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); +int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma); +int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); +int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op); +int omap_gem_op_finish(struct drm_gem_object *obj, enum omap_gem_op op); +int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op); +int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op, + void (*fxn)(void *arg), void *arg); +int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll); +int omap_gem_get_paddr(struct drm_gem_object *obj, + dma_addr_t *paddr, bool remap); +int omap_gem_put_paddr(struct drm_gem_object *obj); +uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj); +size_t omap_gem_mmap_size(struct drm_gem_object *obj); + +static inline int align_pitch(int pitch, int width, int bpp) +{ + int bytespp = (bpp + 7) / 8; + /* in case someone tries to feed us a completely bogus stride: */ + pitch = max(pitch, width * bytespp); + /* PVR needs alignment to 8 pixels.. right now that is the most + * restrictive stride requirement.. + */ + return ALIGN(pitch, 8 * bytespp); +} + +#endif /* __OMAP_DRV_H__ */ diff --git a/drivers/staging/omapdrm/omap_encoder.c b/drivers/staging/omapdrm/omap_encoder.c new file mode 100644 index 00000000000..06c52cb62d2 --- /dev/null +++ b/drivers/staging/omapdrm/omap_encoder.c @@ -0,0 +1,171 @@ +/* + * drivers/staging/omapdrm/omap_encoder.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "omap_drv.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +/* + * encoder funcs + */ + +#define to_omap_encoder(x) container_of(x, struct omap_encoder, base) + +struct omap_encoder { + struct drm_encoder base; + struct omap_overlay_manager *mgr; +}; + +static void omap_encoder_destroy(struct drm_encoder *encoder) +{ + struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + DBG("%s", omap_encoder->mgr->name); + drm_encoder_cleanup(encoder); + kfree(omap_encoder); +} + +static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + DBG("%s: %d", omap_encoder->mgr->name, mode); +} + +static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + DBG("%s", omap_encoder->mgr->name); + return true; +} + +static void omap_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct omap_drm_private *priv = dev->dev_private; + int i; + + mode = adjusted_mode; + + DBG("%s: set mode: %dx%d", omap_encoder->mgr->name, + mode->hdisplay, mode->vdisplay); + + for (i = 0; i < priv->num_connectors; i++) { + struct drm_connector *connector = priv->connectors[i]; + if (connector->encoder == encoder) { + omap_connector_mode_set(connector, mode); + } + } +} + +static void omap_encoder_prepare(struct drm_encoder *encoder) +{ + struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + struct drm_encoder_helper_funcs *encoder_funcs = + encoder->helper_private; + DBG("%s", omap_encoder->mgr->name); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void omap_encoder_commit(struct drm_encoder *encoder) +{ + struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + struct drm_encoder_helper_funcs *encoder_funcs = + encoder->helper_private; + DBG("%s", omap_encoder->mgr->name); + omap_encoder->mgr->apply(omap_encoder->mgr); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); +} + +static const struct drm_encoder_funcs omap_encoder_funcs = { + .destroy = omap_encoder_destroy, +}; + +static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { + .dpms = omap_encoder_dpms, + .mode_fixup = omap_encoder_mode_fixup, + .mode_set = omap_encoder_mode_set, + .prepare = omap_encoder_prepare, + .commit = omap_encoder_commit, +}; + +struct omap_overlay_manager *omap_encoder_get_manager( + struct drm_encoder *encoder) +{ + struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + return omap_encoder->mgr; +} + +/* initialize encoder */ +struct drm_encoder *omap_encoder_init(struct drm_device *dev, + struct omap_overlay_manager *mgr) +{ + struct drm_encoder *encoder = NULL; + struct omap_encoder *omap_encoder; + struct omap_overlay_manager_info info; + int ret; + + DBG("%s", mgr->name); + + omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); + if (!omap_encoder) { + dev_err(dev->dev, "could not allocate encoder\n"); + goto fail; + } + + omap_encoder->mgr = mgr; + encoder = &omap_encoder->base; + + drm_encoder_init(dev, encoder, &omap_encoder_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); + + mgr->get_manager_info(mgr, &info); + + /* TODO: fix hard-coded setup.. */ + info.default_color = 0x00000000; + info.trans_key = 0x00000000; + info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; + info.trans_enabled = false; + + ret = mgr->set_manager_info(mgr, &info); + if (ret) { + dev_err(dev->dev, "could not set manager info\n"); + goto fail; + } + + ret = mgr->apply(mgr); + if (ret) { + dev_err(dev->dev, "could not apply\n"); + goto fail; + } + + return encoder; + +fail: + if (encoder) { + omap_encoder_destroy(encoder); + } + + return NULL; +} diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c new file mode 100644 index 00000000000..0b50c5b3b56 --- /dev/null +++ b/drivers/staging/omapdrm/omap_fb.c @@ -0,0 +1,243 @@ +/* + * drivers/staging/omapdrm/omap_fb.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "omap_drv.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + + +/* + * framebuffer funcs + */ + +#define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base) + +struct omap_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *bo; + int size; + dma_addr_t paddr; +}; + +static int omap_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + return drm_gem_handle_create(file_priv, omap_fb->bo, handle); +} + +static void omap_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + + DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); + + drm_framebuffer_cleanup(fb); + + if (omap_fb->bo) { + if (omap_fb->paddr && omap_gem_put_paddr(omap_fb->bo)) + dev_err(dev->dev, "could not unmap!\n"); + drm_gem_object_unreference_unlocked(omap_fb->bo); + } + + kfree(omap_fb); +} + +static int omap_framebuffer_dirty(struct drm_framebuffer *fb, + struct drm_file *file_priv, unsigned flags, unsigned color, + struct drm_clip_rect *clips, unsigned num_clips) +{ + int i; + + for (i = 0; i < num_clips; i++) { + omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1, + clips[i].x2 - clips[i].x1, + clips[i].y2 - clips[i].y1); + } + + return 0; +} + +static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { + .create_handle = omap_framebuffer_create_handle, + .destroy = omap_framebuffer_destroy, + .dirty = omap_framebuffer_dirty, +}; + +/* returns the buffer size */ +int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y, + void **vaddr, dma_addr_t *paddr, unsigned int *screen_width) +{ + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + int bpp = fb->bits_per_pixel / 8; + unsigned long offset; + + offset = (x * bpp) + (y * fb->pitch); + + if (vaddr) { + void *bo_vaddr = omap_gem_vaddr(omap_fb->bo); + /* note: we can only count on having a vaddr for buffers that + * are allocated physically contiguously to begin with (ie. + * dma_alloc_coherent()). But this should be ok because it + * is only used by legacy fbdev + */ + BUG_ON(IS_ERR_OR_NULL(bo_vaddr)); + *vaddr = bo_vaddr + offset; + } + + *paddr = omap_fb->paddr + offset; + *screen_width = fb->pitch / bpp; + + return omap_fb->size - offset; +} + +struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb) +{ + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + return omap_fb->bo; +} + +/* iterate thru all the connectors, returning ones that are attached + * to the same fb.. + */ +struct drm_connector *omap_framebuffer_get_next_connector( + struct drm_framebuffer *fb, struct drm_connector *from) +{ + struct drm_device *dev = fb->dev; + struct list_head *connector_list = &dev->mode_config.connector_list; + struct drm_connector *connector = from; + + if (!from) { + return list_first_entry(connector_list, typeof(*from), head); + } + + list_for_each_entry_from(connector, connector_list, head) { + if (connector != from) { + struct drm_encoder *encoder = connector->encoder; + struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; + if (crtc && crtc->fb == fb) { + return connector; + } + } + } + + return NULL; +} + +/* flush an area of the framebuffer (in case of manual update display that + * is not automatically flushed) + */ +void omap_framebuffer_flush(struct drm_framebuffer *fb, + int x, int y, int w, int h) +{ + struct drm_connector *connector = NULL; + + VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb); + + while ((connector = omap_framebuffer_get_next_connector(fb, connector))) { + /* only consider connectors that are part of a chain */ + if (connector->encoder && connector->encoder->crtc) { + /* TODO: maybe this should propagate thru the crtc who + * could do the coordinate translation.. + */ + struct drm_crtc *crtc = connector->encoder->crtc; + int cx = max(0, x - crtc->x); + int cy = max(0, y - crtc->y); + int cw = w + (x - crtc->x) - cx; + int ch = h + (y - crtc->y) - cy; + + omap_connector_flush(connector, cx, cy, cw, ch); + } + } +} + +struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, + struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd) +{ + struct drm_gem_object *bo; + struct drm_framebuffer *fb; + bo = drm_gem_object_lookup(dev, file, mode_cmd->handle); + if (!bo) { + return ERR_PTR(-ENOENT); + } + fb = omap_framebuffer_init(dev, mode_cmd, bo); + if (!fb) { + return ERR_PTR(-ENOMEM); + } + return fb; +} + +struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo) +{ + struct omap_framebuffer *omap_fb; + struct drm_framebuffer *fb = NULL; + int size, ret; + + DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%d)", + dev, mode_cmd, mode_cmd->width, mode_cmd->height, + mode_cmd->bpp); + + /* in case someone tries to feed us a completely bogus stride: */ + mode_cmd->pitch = align_pitch(mode_cmd->pitch, + mode_cmd->width, mode_cmd->bpp); + + omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL); + if (!omap_fb) { + dev_err(dev->dev, "could not allocate fb\n"); + goto fail; + } + + fb = &omap_fb->base; + ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs); + if (ret) { + dev_err(dev->dev, "framebuffer init failed: %d\n", ret); + goto fail; + } + + DBG("create: FB ID: %d (%p)", fb->base.id, fb); + + size = PAGE_ALIGN(mode_cmd->pitch * mode_cmd->height); + + if (size > bo->size) { + dev_err(dev->dev, "provided buffer object is too small!\n"); + goto fail; + } + + omap_fb->bo = bo; + omap_fb->size = size; + + if (omap_gem_get_paddr(bo, &omap_fb->paddr, true)) { + dev_err(dev->dev, "could not map (paddr)!\n"); + goto fail; + } + + drm_helper_mode_fill_fb_struct(fb, mode_cmd); + + return fb; + +fail: + if (fb) { + omap_framebuffer_destroy(fb); + } + return NULL; +} diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c new file mode 100644 index 00000000000..093ae2f87b2 --- /dev/null +++ b/drivers/staging/omapdrm/omap_fbdev.c @@ -0,0 +1,372 @@ +/* + * drivers/staging/omapdrm/omap_fbdev.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "omap_drv.h" + +#include "drm_crtc.h" +#include "drm_fb_helper.h" + +MODULE_PARM_DESC(ywrap, "Enable ywrap scrolling (omap44xx and later, default 'y')"); +static bool ywrap_enabled = true; +module_param_named(ywrap, ywrap_enabled, bool, 0644); + +/* + * fbdev funcs, to implement legacy fbdev interface on top of drm driver + */ + +#define to_omap_fbdev(x) container_of(x, struct omap_fbdev, base) + +struct omap_fbdev { + struct drm_fb_helper base; + struct drm_framebuffer *fb; + struct drm_gem_object *bo; + bool ywrap_enabled; +}; + +static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h); +static struct drm_fb_helper *get_fb(struct fb_info *fbi); + +static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t res; + + res = fb_sys_write(fbi, buf, count, ppos); + omap_fbdev_flush(fbi, 0, 0, fbi->var.xres, fbi->var.yres); + + return res; +} + +static void omap_fbdev_fillrect(struct fb_info *fbi, + const struct fb_fillrect *rect) +{ + sys_fillrect(fbi, rect); + omap_fbdev_flush(fbi, rect->dx, rect->dy, rect->width, rect->height); +} + +static void omap_fbdev_copyarea(struct fb_info *fbi, + const struct fb_copyarea *area) +{ + sys_copyarea(fbi, area); + omap_fbdev_flush(fbi, area->dx, area->dy, area->width, area->height); +} + +static void omap_fbdev_imageblit(struct fb_info *fbi, + const struct fb_image *image) +{ + sys_imageblit(fbi, image); + omap_fbdev_flush(fbi, image->dx, image->dy, + image->width, image->height); +} + +static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + struct drm_fb_helper *helper = get_fb(fbi); + struct omap_fbdev *fbdev = to_omap_fbdev(helper); + int npages; + + if (!helper) + goto fallback; + + if (!fbdev->ywrap_enabled) + goto fallback; + + /* DMM roll shifts in 4K pages: */ + npages = fbi->fix.line_length >> PAGE_SHIFT; + omap_gem_roll(fbdev->bo, var->yoffset * npages); + + return 0; + +fallback: + return drm_fb_helper_pan_display(var, fbi); +} + +static struct fb_ops omap_fb_ops = { + .owner = THIS_MODULE, + + /* Note: to properly handle manual update displays, we wrap the + * basic fbdev ops which write to the framebuffer + */ + .fb_read = fb_sys_read, + .fb_write = omap_fbdev_write, + .fb_fillrect = omap_fbdev_fillrect, + .fb_copyarea = omap_fbdev_copyarea, + .fb_imageblit = omap_fbdev_imageblit, + + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_pan_display = omap_fbdev_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, + + .fb_debug_enter = drm_fb_helper_debug_enter, + .fb_debug_leave = drm_fb_helper_debug_leave, +}; + +static int omap_fbdev_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct omap_fbdev *fbdev = to_omap_fbdev(helper); + struct drm_device *dev = helper->dev; + struct omap_drm_private *priv = dev->dev_private; + struct drm_framebuffer *fb = NULL; + union omap_gem_size gsize; + struct fb_info *fbi = NULL; + struct drm_mode_fb_cmd mode_cmd = {0}; + dma_addr_t paddr; + void __iomem *vaddr; + int size, screen_width; + int ret; + + /* only doing ARGB32 since this is what is needed to alpha-blend + * with video overlays: + */ + sizes->surface_bpp = 32; + sizes->surface_depth = 32; + + DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width, + sizes->surface_height, sizes->surface_bpp, + sizes->fb_width, sizes->fb_height); + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + + mode_cmd.bpp = sizes->surface_bpp; + mode_cmd.depth = sizes->surface_depth; + + mode_cmd.pitch = align_pitch( + mode_cmd.width * ((mode_cmd.bpp + 7) / 8), + mode_cmd.width, mode_cmd.bpp); + + fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled; + if (fbdev->ywrap_enabled) { + /* need to align pitch to page size if using DMM scrolling */ + mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE); + } + + /* allocate backing bo */ + gsize = (union omap_gem_size){ + .bytes = PAGE_ALIGN(mode_cmd.pitch * mode_cmd.height), + }; + DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index); + fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); + if (!fbdev->bo) { + dev_err(dev->dev, "failed to allocate buffer object\n"); + goto fail; + } + + fb = omap_framebuffer_init(dev, &mode_cmd, fbdev->bo); + if (!fb) { + dev_err(dev->dev, "failed to allocate fb\n"); + ret = -ENOMEM; + goto fail; + } + + mutex_lock(&dev->struct_mutex); + + fbi = framebuffer_alloc(0, dev->dev); + if (!fbi) { + dev_err(dev->dev, "failed to allocate fb info\n"); + ret = -ENOMEM; + goto fail_unlock; + } + + DBG("fbi=%p, dev=%p", fbi, dev); + + fbdev->fb = fb; + helper->fb = fb; + helper->fbdev = fbi; + + fbi->par = helper; + fbi->flags = FBINFO_DEFAULT; + fbi->fbops = &omap_fb_ops; + + strcpy(fbi->fix.id, MODULE_NAME); + + ret = fb_alloc_cmap(&fbi->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto fail_unlock; + } + + drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth); + drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); + + size = omap_framebuffer_get_buffer(fb, 0, 0, + &vaddr, &paddr, &screen_width); + + dev->mode_config.fb_base = paddr; + + fbi->screen_base = vaddr; + fbi->screen_size = size; + fbi->fix.smem_start = paddr; + fbi->fix.smem_len = size; + + /* if we have DMM, then we can use it for scrolling by just + * shuffling pages around in DMM rather than doing sw blit. + */ + if (fbdev->ywrap_enabled) { + DRM_INFO("Enabling DMM ywrap scrolling\n"); + fbi->flags |= FBINFO_HWACCEL_YWRAP | FBINFO_READS_FAST; + fbi->fix.ywrapstep = 1; + } + + + DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); + DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); + + mutex_unlock(&dev->struct_mutex); + + return 0; + +fail_unlock: + mutex_unlock(&dev->struct_mutex); +fail: + + if (ret) { + if (fbi) + framebuffer_release(fbi); + if (fb) + fb->funcs->destroy(fb); + } + + return ret; +} + +static void omap_crtc_fb_gamma_set(struct drm_crtc *crtc, + u16 red, u16 green, u16 blue, int regno) +{ + DBG("fbdev: set gamma"); +} + +static void omap_crtc_fb_gamma_get(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, int regno) +{ + DBG("fbdev: get gamma"); +} + +static int omap_fbdev_probe(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + int new_fb = 0; + int ret; + + if (!helper->fb) { + ret = omap_fbdev_create(helper, sizes); + if (ret) + return ret; + new_fb = 1; + } + return new_fb; +} + +static struct drm_fb_helper_funcs omap_fb_helper_funcs = { + .gamma_set = omap_crtc_fb_gamma_set, + .gamma_get = omap_crtc_fb_gamma_get, + .fb_probe = omap_fbdev_probe, +}; + +static struct drm_fb_helper *get_fb(struct fb_info *fbi) +{ + if (!fbi || strcmp(fbi->fix.id, MODULE_NAME)) { + /* these are not the fb's you're looking for */ + return NULL; + } + return fbi->par; +} + +/* flush an area of the framebuffer (in case of manual update display that + * is not automatically flushed) + */ +static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h) +{ + struct drm_fb_helper *helper = get_fb(fbi); + + if (!helper) + return; + + VERB("flush fbdev: %d,%d %dx%d, fbi=%p", x, y, w, h, fbi); + + omap_framebuffer_flush(helper->fb, x, y, w, h); +} + +/* initialize fbdev helper */ +struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) +{ + struct omap_drm_private *priv = dev->dev_private; + struct omap_fbdev *fbdev = NULL; + struct drm_fb_helper *helper; + int ret = 0; + + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); + if (!fbdev) { + dev_err(dev->dev, "could not allocate fbdev\n"); + goto fail; + } + + helper = &fbdev->base; + + helper->funcs = &omap_fb_helper_funcs; + + ret = drm_fb_helper_init(dev, helper, + priv->num_crtcs, priv->num_connectors); + if (ret) { + dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret); + goto fail; + } + + drm_fb_helper_single_add_all_connectors(helper); + drm_fb_helper_initial_config(helper, 32); + + priv->fbdev = helper; + + return helper; + +fail: + kfree(fbdev); + return NULL; +} + +void omap_fbdev_free(struct drm_device *dev) +{ + struct omap_drm_private *priv = dev->dev_private; + struct drm_fb_helper *helper = priv->fbdev; + struct omap_fbdev *fbdev; + struct fb_info *fbi; + + DBG(); + + fbi = helper->fbdev; + + unregister_framebuffer(fbi); + framebuffer_release(fbi); + + drm_fb_helper_fini(helper); + + fbdev = to_omap_fbdev(priv->fbdev); + + kfree(fbdev); + + /* this will free the backing object */ + if (fbdev->fb) + fbdev->fb->funcs->destroy(fbdev->fb); + + priv->fbdev = NULL; +} diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c new file mode 100644 index 00000000000..e0ebd1d139f --- /dev/null +++ b/drivers/staging/omapdrm/omap_gem.c @@ -0,0 +1,1231 @@ +/* + * drivers/staging/omapdrm/omap_gem.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob.clark@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <linux/spinlock.h> +#include <linux/shmem_fs.h> + +#include "omap_drv.h" +#include "omap_dmm_tiler.h" + +/* remove these once drm core helpers are merged */ +struct page ** _drm_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); +void _drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, + bool dirty, bool accessed); +int _drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size); + +/* + * GEM buffer object implementation. + */ + +#define to_omap_bo(x) container_of(x, struct omap_gem_object, base) + +/* note: we use upper 8 bits of flags for driver-internal flags: */ +#define OMAP_BO_DMA 0x01000000 /* actually is physically contiguous */ +#define OMAP_BO_EXT_SYNC 0x02000000 /* externally allocated sync object */ +#define OMAP_BO_EXT_MEM 0x04000000 /* externally allocated memory */ + + +struct omap_gem_object { + struct drm_gem_object base; + + uint32_t flags; + + /** width/height for tiled formats (rounded up to slot boundaries) */ + uint16_t width, height; + + /** roll applied when mapping to DMM */ + uint32_t roll; + + /** + * If buffer is allocated physically contiguous, the OMAP_BO_DMA flag + * is set and the paddr is valid. Also if the buffer is remapped in + * TILER and paddr_cnt > 0, then paddr is valid. But if you are using + * the physical address and OMAP_BO_DMA is not set, then you should + * be going thru omap_gem_{get,put}_paddr() to ensure the mapping is + * not removed from under your feet. + * + * Note that OMAP_BO_SCANOUT is a hint from userspace that DMA capable + * buffer is requested, but doesn't mean that it is. Use the + * OMAP_BO_DMA flag to determine if the buffer has a DMA capable + * physical address. + */ + dma_addr_t paddr; + + /** + * # of users of paddr + */ + uint32_t paddr_cnt; + + /** + * tiler block used when buffer is remapped in DMM/TILER. + */ + struct tiler_block *block; + + /** + * Array of backing pages, if allocated. Note that pages are never + * allocated for buffers originally allocated from contiguous memory + */ + struct page **pages; + + /** addresses corresponding to pages in above array */ + dma_addr_t *addrs; + + /** + * Virtual address, if mapped. + */ + void *vaddr; + + /** + * sync-object allocated on demand (if needed) + * + * Per-buffer sync-object for tracking pending and completed hw/dma + * read and write operations. The layout in memory is dictated by + * the SGX firmware, which uses this information to stall the command + * stream if a surface is not ready yet. + * + * Note that when buffer is used by SGX, the sync-object needs to be + * allocated from a special heap of sync-objects. This way many sync + * objects can be packed in a page, and not waste GPU virtual address + * space. Because of this we have to have a omap_gem_set_sync_object() + * API to allow replacement of the syncobj after it has (potentially) + * already been allocated. A bit ugly but I haven't thought of a + * better alternative. + */ + struct { + uint32_t write_pending; + uint32_t write_complete; + uint32_t read_pending; + uint32_t read_complete; + } *sync; +}; + +/* To deal with userspace mmap'ings of 2d tiled buffers, which (a) are + * not necessarily pinned in TILER all the time, and (b) when they are + * they are not necessarily page aligned, we reserve one or more small + * regions in each of the 2d containers to use as a user-GART where we + * can create a second page-aligned mapping of parts of the buffer + * being accessed from userspace. + * + * Note that we could optimize slightly when we know that multiple + * tiler containers are backed by the same PAT.. but I'll leave that + * for later.. + */ +#define NUM_USERGART_ENTRIES 2 +struct usergart_entry { + struct tiler_block *block; /* the reserved tiler block */ + dma_addr_t paddr; + struct drm_gem_object *obj; /* the current pinned obj */ + pgoff_t obj_pgoff; /* page offset of obj currently + mapped in */ +}; +static struct { + struct usergart_entry entry[NUM_USERGART_ENTRIES]; + int height; /* height in rows */ + int height_shift; /* ilog2(height in rows) */ + int slot_shift; /* ilog2(width per slot) */ + int stride_pfn; /* stride in pages */ + int last; /* index of last used entry */ +} *usergart; + +static void evict_entry(struct drm_gem_object *obj, + enum tiler_fmt fmt, struct usergart_entry *entry) +{ + if (obj->dev->dev_mapping) { + size_t size = PAGE_SIZE * usergart[fmt].height; + loff_t off = omap_gem_mmap_offset(obj) + + (entry->obj_pgoff << PAGE_SHIFT); + unmap_mapping_range(obj->dev->dev_mapping, off, size, 1); + } + + entry->obj = NULL; +} + +/* Evict a buffer from usergart, if it is mapped there */ +static void evict(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + + if (omap_obj->flags & OMAP_BO_TILED) { + enum tiler_fmt fmt = gem2fmt(omap_obj->flags); + int i; + + if (!usergart) + return; + + for (i = 0; i < NUM_USERGART_ENTRIES; i++) { + struct usergart_entry *entry = &usergart[fmt].entry[i]; + if (entry->obj == obj) + evict_entry(obj, fmt, entry); + } + } +} + +/* GEM objects can either be allocated from contiguous memory (in which + * case obj->filp==NULL), or w/ shmem backing (obj->filp!=NULL). But non + * contiguous buffers can be remapped in TILER/DMM if they need to be + * contiguous... but we don't do this all the time to reduce pressure + * on TILER/DMM space when we know at allocation time that the buffer + * will need to be scanned out. + */ +static inline bool is_shmem(struct drm_gem_object *obj) +{ + return obj->filp != NULL; +} + +static int get_pages(struct drm_gem_object *obj, struct page ***pages); + +static DEFINE_SPINLOCK(sync_lock); + +/** ensure backing pages are allocated */ +static int omap_gem_attach_pages(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + struct page **pages; + + WARN_ON(omap_obj->pages); + + /* TODO: __GFP_DMA32 .. but somehow GFP_HIGHMEM is coming from the + * mapping_gfp_mask(mapping) which conflicts w/ GFP_DMA32.. probably + * we actually want CMA memory for it all anyways.. + */ + pages = _drm_gem_get_pages(obj, GFP_KERNEL); + if (IS_ERR(pages)) { + dev_err(obj->dev->dev, "could not get pages: %ld\n", PTR_ERR(pages)); + return PTR_ERR(pages); + } + + /* for non-cached buffers, ensure the new pages are clean because + * DSS, GPU, etc. are not cache coherent: + */ + if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) { + int i, npages = obj->size >> PAGE_SHIFT; + dma_addr_t *addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL); + for (i = 0; i < npages; i++) { + addrs[i] = dma_map_page(obj->dev->dev, pages[i], + 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + } + omap_obj->addrs = addrs; + } + + omap_obj->pages = pages; + return 0; +} + +/** release backing pages */ +static void omap_gem_detach_pages(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + + /* for non-cached buffers, ensure the new pages are clean because + * DSS, GPU, etc. are not cache coherent: + */ + if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) { + int i, npages = obj->size >> PAGE_SHIFT; + for (i = 0; i < npages; i++) { + dma_unmap_page(obj->dev->dev, omap_obj->addrs[i], + PAGE_SIZE, DMA_BIDIRECTIONAL); + } + kfree(omap_obj->addrs); + omap_obj->addrs = NULL; + } + + _drm_gem_put_pages(obj, omap_obj->pages, true, false); + omap_obj->pages = NULL; +} + +/** get mmap offset */ +uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj) +{ + if (!obj->map_list.map) { + /* Make it mmapable */ + size_t size = omap_gem_mmap_size(obj); + int ret = _drm_gem_create_mmap_offset_size(obj, size); + + if (ret) { + dev_err(obj->dev->dev, "could not allocate mmap offset"); + return 0; + } + } + + return (uint64_t)obj->map_list.hash.key << PAGE_SHIFT; +} + +/** get mmap size */ +size_t omap_gem_mmap_size(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + size_t size = obj->size; + + if (omap_obj->flags & OMAP_BO_TILED) { + /* for tiled buffers, the virtual size has stride rounded up + * to 4kb.. (to hide the fact that row n+1 might start 16kb or + * 32kb later!). But we don't back the entire buffer with + * pages, only the valid picture part.. so need to adjust for + * this in the size used to mmap and generate mmap offset + */ + size = tiler_vsize(gem2fmt(omap_obj->flags), + omap_obj->width, omap_obj->height); + } + + return size; +} + + +/* Normal handling for the case of faulting in non-tiled buffers */ +static int fault_1d(struct drm_gem_object *obj, + struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + unsigned long pfn; + pgoff_t pgoff; + + /* We don't use vmf->pgoff since that has the fake offset: */ + pgoff = ((unsigned long)vmf->virtual_address - + vma->vm_start) >> PAGE_SHIFT; + + if (omap_obj->pages) { + pfn = page_to_pfn(omap_obj->pages[pgoff]); + } else { + BUG_ON(!(omap_obj->flags & OMAP_BO_DMA)); + pfn = (omap_obj->paddr >> PAGE_SHIFT) + pgoff; + } + + VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + pfn, pfn << PAGE_SHIFT); + + return vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); +} + +/* Special handling for the case of faulting in 2d tiled buffers */ +static int fault_2d(struct drm_gem_object *obj, + struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + struct usergart_entry *entry; + enum tiler_fmt fmt = gem2fmt(omap_obj->flags); + struct page *pages[64]; /* XXX is this too much to have on stack? */ + unsigned long pfn; + pgoff_t pgoff, base_pgoff; + void __user *vaddr; + int i, ret, slots; + + if (!usergart) + return -EFAULT; + + /* TODO: this fxn might need a bit tweaking to deal w/ tiled buffers + * that are wider than 4kb + */ + + /* We don't use vmf->pgoff since that has the fake offset: */ + pgoff = ((unsigned long)vmf->virtual_address - + vma->vm_start) >> PAGE_SHIFT; + + /* actual address we start mapping at is rounded down to previous slot + * boundary in the y direction: + */ + base_pgoff = round_down(pgoff, usergart[fmt].height); + vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT); + entry = &usergart[fmt].entry[usergart[fmt].last]; + + slots = omap_obj->width >> usergart[fmt].slot_shift; + + /* evict previous buffer using this usergart entry, if any: */ + if (entry->obj) + evict_entry(entry->obj, fmt, entry); + + entry->obj = obj; + entry->obj_pgoff = base_pgoff; + + /* now convert base_pgoff to phys offset from virt offset: + */ + base_pgoff = (base_pgoff >> usergart[fmt].height_shift) * slots; + + /* map in pages. Note the height of the slot is also equal to the + * number of pages that need to be mapped in to fill 4kb wide CPU page. + * If the height is 64, then 64 pages fill a 4kb wide by 64 row region. + * Beyond the valid pixel part of the buffer, we set pages[i] to NULL to + * get a dummy page mapped in.. if someone reads/writes it they will get + * random/undefined content, but at least it won't be corrupting + * whatever other random page used to be mapped in, or other undefined + * behavior. + */ + memcpy(pages, &omap_obj->pages[base_pgoff], + sizeof(struct page *) * slots); + memset(pages + slots, 0, + sizeof(struct page *) * (usergart[fmt].height - slots)); + + ret = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true); + if (ret) { + dev_err(obj->dev->dev, "failed to pin: %d\n", ret); + return ret; + } + + i = usergart[fmt].height; + pfn = entry->paddr >> PAGE_SHIFT; + + VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + pfn, pfn << PAGE_SHIFT); + + while (i--) { + vm_insert_mixed(vma, (unsigned long)vaddr, pfn); + pfn += usergart[fmt].stride_pfn; + vaddr += PAGE_SIZE; + } + + /* simple round-robin: */ + usergart[fmt].last = (usergart[fmt].last + 1) % NUM_USERGART_ENTRIES; + + return 0; +} + +/** + * omap_gem_fault - pagefault handler for GEM objects + * @vma: the VMA of the GEM object + * @vmf: fault detail + * + * Invoked when a fault occurs on an mmap of a GEM managed area. GEM + * does most of the work for us including the actual map/unmap calls + * but we need to do the actual page work. + * + * The VMA was set up by GEM. In doing so it also ensured that the + * vma->vm_private_data points to the GEM object that is backing this + * mapping. + */ +int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct drm_gem_object *obj = vma->vm_private_data; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + struct drm_device *dev = obj->dev; + struct page **pages; + int ret; + + /* Make sure we don't parallel update on a fault, nor move or remove + * something from beneath our feet + */ + mutex_lock(&dev->struct_mutex); + + /* if a shmem backed object, make sure we have pages attached now */ + ret = get_pages(obj, &pages); + if (ret) { + goto fail; + } + + /* where should we do corresponding put_pages().. we are mapping + * the original page, rather than thru a GART, so we can't rely + * on eviction to trigger this. But munmap() or all mappings should + * probably trigger put_pages()? + */ + + if (omap_obj->flags & OMAP_BO_TILED) + ret = fault_2d(obj, vma, vmf); + else + ret = fault_1d(obj, vma, vmf); + + +fail: + mutex_unlock(&dev->struct_mutex); + switch (ret) { + case 0: + case -ERESTARTSYS: + case -EINTR: + return VM_FAULT_NOPAGE; + case -ENOMEM: + return VM_FAULT_OOM; + default: + return VM_FAULT_SIGBUS; + } +} + +/** We override mainly to fix up some of the vm mapping flags.. */ +int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct omap_gem_object *omap_obj; + int ret; + + ret = drm_gem_mmap(filp, vma); + if (ret) { + DBG("mmap failed: %d", ret); + return ret; + } + + /* after drm_gem_mmap(), it is safe to access the obj */ + omap_obj = to_omap_bo(vma->vm_private_data); + + vma->vm_flags &= ~VM_PFNMAP; + vma->vm_flags |= VM_MIXEDMAP; + + if (omap_obj->flags & OMAP_BO_WC) { + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + } else if (omap_obj->flags & OMAP_BO_UNCACHED) { + vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags)); + } else { + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + } + + return ret; +} + +/** + * omap_gem_dumb_create - create a dumb buffer + * @drm_file: our client file + * @dev: our device + * @args: the requested arguments copied from userspace + * + * Allocate a buffer suitable for use for a frame buffer of the + * form described by user space. Give userspace a handle by which + * to reference it. + */ +int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + union omap_gem_size gsize; + + /* in case someone tries to feed us a completely bogus stride: */ + args->pitch = align_pitch(args->pitch, args->width, args->bpp); + args->size = PAGE_ALIGN(args->pitch * args->height); + + gsize = (union omap_gem_size){ + .bytes = args->size, + }; + + return omap_gem_new_handle(dev, file, gsize, + OMAP_BO_SCANOUT | OMAP_BO_WC, &args->handle); +} + +/** + * omap_gem_dumb_destroy - destroy a dumb buffer + * @file: client file + * @dev: our DRM device + * @handle: the object handle + * + * Destroy a handle that was created via omap_gem_dumb_create. + */ +int omap_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, + uint32_t handle) +{ + /* No special work needed, drop the reference and see what falls out */ + return drm_gem_handle_delete(file, handle); +} + +/** + * omap_gem_dumb_map - buffer mapping for dumb interface + * @file: our drm client file + * @dev: drm device + * @handle: GEM handle to the object (from dumb_create) + * + * Do the necessary setup to allow the mapping of the frame buffer + * into user memory. We don't have to do much here at the moment. + */ +int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset) +{ + struct drm_gem_object *obj; + int ret = 0; + + /* GEM does all our handle to object mapping */ + obj = drm_gem_object_lookup(dev, file, handle); + if (obj == NULL) { + ret = -ENOENT; + goto fail; + } + + *offset = omap_gem_mmap_offset(obj); + + drm_gem_object_unreference_unlocked(obj); + +fail: + return ret; +} + +/* Set scrolling position. This allows us to implement fast scrolling + * for console. + */ +int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + uint32_t npages = obj->size >> PAGE_SHIFT; + int ret = 0; + + if (roll > npages) { + dev_err(obj->dev->dev, "invalid roll: %d\n", roll); + return -EINVAL; + } + + omap_obj->roll = roll; + + if (in_atomic() || mutex_is_locked(&obj->dev->struct_mutex)) { + /* this can get called from fbcon in atomic context.. so + * just ignore it and wait for next time called from + * interruptible context to update the PAT.. the result + * may be that user sees wrap-around instead of scrolling + * momentarily on the screen. If we wanted to be fancier + * we could perhaps schedule some workqueue work at this + * point. + */ + return 0; + } + + mutex_lock(&obj->dev->struct_mutex); + + /* if we aren't mapped yet, we don't need to do anything */ + if (omap_obj->block) { + struct page **pages; + ret = get_pages(obj, &pages); + if (ret) + goto fail; + ret = tiler_pin(omap_obj->block, pages, npages, roll, true); + if (ret) + dev_err(obj->dev->dev, "could not repin: %d\n", ret); + } + +fail: + mutex_unlock(&obj->dev->struct_mutex); + + return ret; +} + +/* Get physical address for DMA.. if 'remap' is true, and the buffer is not + * already contiguous, remap it to pin in physically contiguous memory.. (ie. + * map in TILER) + */ +int omap_gem_get_paddr(struct drm_gem_object *obj, + dma_addr_t *paddr, bool remap) +{ + struct omap_drm_private *priv = obj->dev->dev_private; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = 0; + + mutex_lock(&obj->dev->struct_mutex); + + if (remap && is_shmem(obj) && priv->has_dmm) { + if (omap_obj->paddr_cnt == 0) { + struct page **pages; + uint32_t npages = obj->size >> PAGE_SHIFT; + enum tiler_fmt fmt = gem2fmt(omap_obj->flags); + struct tiler_block *block; + + BUG_ON(omap_obj->block); + + ret = get_pages(obj, &pages); + if (ret) + goto fail; + + if (omap_obj->flags & OMAP_BO_TILED) { + block = tiler_reserve_2d(fmt, + omap_obj->width, + omap_obj->height, 0); + } else { + block = tiler_reserve_1d(obj->size); + } + + if (IS_ERR(block)) { + ret = PTR_ERR(block); + dev_err(obj->dev->dev, + "could not remap: %d (%d)\n", ret, fmt); + goto fail; + } + + /* TODO: enable async refill.. */ + ret = tiler_pin(block, pages, npages, + omap_obj->roll, true); + if (ret) { + tiler_release(block); + dev_err(obj->dev->dev, + "could not pin: %d\n", ret); + goto fail; + } + + omap_obj->paddr = tiler_ssptr(block); + omap_obj->block = block; + + DBG("got paddr: %08x", omap_obj->paddr); + } + + omap_obj->paddr_cnt++; + + *paddr = omap_obj->paddr; + } else if (omap_obj->flags & OMAP_BO_DMA) { + *paddr = omap_obj->paddr; + } else { + ret = -EINVAL; + } + +fail: + mutex_unlock(&obj->dev->struct_mutex); + + return ret; +} + +/* Release physical address, when DMA is no longer being performed.. this + * could potentially unpin and unmap buffers from TILER + */ +int omap_gem_put_paddr(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = 0; + + mutex_lock(&obj->dev->struct_mutex); + if (omap_obj->paddr_cnt > 0) { + omap_obj->paddr_cnt--; + if (omap_obj->paddr_cnt == 0) { + ret = tiler_unpin(omap_obj->block); + if (ret) { + dev_err(obj->dev->dev, + "could not unpin pages: %d\n", ret); + goto fail; + } + ret = tiler_release(omap_obj->block); + if (ret) { + dev_err(obj->dev->dev, + "could not release unmap: %d\n", ret); + } + omap_obj->block = NULL; + } + } +fail: + mutex_unlock(&obj->dev->struct_mutex); + return ret; +} + +/* acquire pages when needed (for example, for DMA where physically + * contiguous buffer is not required + */ +static int get_pages(struct drm_gem_object *obj, struct page ***pages) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = 0; + + if (is_shmem(obj) && !omap_obj->pages) { + ret = omap_gem_attach_pages(obj); + if (ret) { + dev_err(obj->dev->dev, "could not attach pages\n"); + return ret; + } + } + + /* TODO: even phys-contig.. we should have a list of pages? */ + *pages = omap_obj->pages; + + return 0; +} + +int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages) +{ + int ret; + mutex_lock(&obj->dev->struct_mutex); + ret = get_pages(obj, pages); + mutex_unlock(&obj->dev->struct_mutex); + return ret; +} + +/* release pages when DMA no longer being performed */ +int omap_gem_put_pages(struct drm_gem_object *obj) +{ + /* do something here if we dynamically attach/detach pages.. at + * least they would no longer need to be pinned if everyone has + * released the pages.. + */ + return 0; +} + +/* Get kernel virtual address for CPU access.. this more or less only + * exists for omap_fbdev. This should be called with struct_mutex + * held. + */ +void *omap_gem_vaddr(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + WARN_ON(! mutex_is_locked(&obj->dev->struct_mutex)); + if (!omap_obj->vaddr) { + struct page **pages; + int ret = get_pages(obj, &pages); + if (ret) + return ERR_PTR(ret); + omap_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, + VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + } + return omap_obj->vaddr; +} + +/* Buffer Synchronization: + */ + +struct omap_gem_sync_waiter { + struct list_head list; + struct omap_gem_object *omap_obj; + enum omap_gem_op op; + uint32_t read_target, write_target; + /* notify called w/ sync_lock held */ + void (*notify)(void *arg); + void *arg; +}; + +/* list of omap_gem_sync_waiter.. the notify fxn gets called back when + * the read and/or write target count is achieved which can call a user + * callback (ex. to kick 3d and/or 2d), wakeup blocked task (prep for + * cpu access), etc. + */ +static LIST_HEAD(waiters); + +static inline bool is_waiting(struct omap_gem_sync_waiter *waiter) +{ + struct omap_gem_object *omap_obj = waiter->omap_obj; + if ((waiter->op & OMAP_GEM_READ) && + (omap_obj->sync->read_complete < waiter->read_target)) + return true; + if ((waiter->op & OMAP_GEM_WRITE) && + (omap_obj->sync->write_complete < waiter->write_target)) + return true; + return false; +} + +/* macro for sync debug.. */ +#define SYNCDBG 0 +#define SYNC(fmt, ...) do { if (SYNCDBG) \ + printk(KERN_ERR "%s:%d: "fmt"\n", \ + __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) + + +static void sync_op_update(void) +{ + struct omap_gem_sync_waiter *waiter, *n; + list_for_each_entry_safe(waiter, n, &waiters, list) { + if (!is_waiting(waiter)) { + list_del(&waiter->list); + SYNC("notify: %p", waiter); + waiter->notify(waiter->arg); + kfree(waiter); + } + } +} + +static inline int sync_op(struct drm_gem_object *obj, + enum omap_gem_op op, bool start) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = 0; + + spin_lock(&sync_lock); + + if (!omap_obj->sync) { + omap_obj->sync = kzalloc(sizeof(*omap_obj->sync), GFP_ATOMIC); + if (!omap_obj->sync) { + ret = -ENOMEM; + goto unlock; + } + } + + if (start) { + if (op & OMAP_GEM_READ) + omap_obj->sync->read_pending++; + if (op & OMAP_GEM_WRITE) + omap_obj->sync->write_pending++; + } else { + if (op & OMAP_GEM_READ) + omap_obj->sync->read_complete++; + if (op & OMAP_GEM_WRITE) + omap_obj->sync->write_complete++; + sync_op_update(); + } + +unlock: + spin_unlock(&sync_lock); + + return ret; +} + +/* it is a bit lame to handle updates in this sort of polling way, but + * in case of PVR, the GPU can directly update read/write complete + * values, and not really tell us which ones it updated.. this also + * means that sync_lock is not quite sufficient. So we'll need to + * do something a bit better when it comes time to add support for + * separate 2d hw.. + */ +void omap_gem_op_update(void) +{ + spin_lock(&sync_lock); + sync_op_update(); + spin_unlock(&sync_lock); +} + +/* mark the start of read and/or write operation */ +int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op) +{ + return sync_op(obj, op, true); +} + +int omap_gem_op_finish(struct drm_gem_object *obj, enum omap_gem_op op) +{ + return sync_op(obj, op, false); +} + +static DECLARE_WAIT_QUEUE_HEAD(sync_event); + +static void sync_notify(void *arg) +{ + struct task_struct **waiter_task = arg; + *waiter_task = NULL; + wake_up_all(&sync_event); +} + +int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = 0; + if (omap_obj->sync) { + struct task_struct *waiter_task = current; + struct omap_gem_sync_waiter *waiter = + kzalloc(sizeof(*waiter), GFP_KERNEL); + + if (!waiter) { + return -ENOMEM; + } + + waiter->omap_obj = omap_obj; + waiter->op = op; + waiter->read_target = omap_obj->sync->read_pending; + waiter->write_target = omap_obj->sync->write_pending; + waiter->notify = sync_notify; + waiter->arg = &waiter_task; + + spin_lock(&sync_lock); + if (is_waiting(waiter)) { + SYNC("waited: %p", waiter); + list_add_tail(&waiter->list, &waiters); + spin_unlock(&sync_lock); + ret = wait_event_interruptible(sync_event, + (waiter_task == NULL)); + spin_lock(&sync_lock); + if (waiter_task) { + SYNC("interrupted: %p", waiter); + /* we were interrupted */ + list_del(&waiter->list); + waiter_task = NULL; + } else { + /* freed in sync_op_update() */ + waiter = NULL; + } + } + spin_unlock(&sync_lock); + + if (waiter) { + kfree(waiter); + } + } + return ret; +} + +/* call fxn(arg), either synchronously or asynchronously if the op + * is currently blocked.. fxn() can be called from any context + * + * (TODO for now fxn is called back from whichever context calls + * omap_gem_op_update().. but this could be better defined later + * if needed) + * + * TODO more code in common w/ _sync().. + */ +int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op, + void (*fxn)(void *arg), void *arg) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + if (omap_obj->sync) { + struct omap_gem_sync_waiter *waiter = + kzalloc(sizeof(*waiter), GFP_ATOMIC); + + if (!waiter) { + return -ENOMEM; + } + + waiter->omap_obj = omap_obj; + waiter->op = op; + waiter->read_target = omap_obj->sync->read_pending; + waiter->write_target = omap_obj->sync->write_pending; + waiter->notify = fxn; + waiter->arg = arg; + + spin_lock(&sync_lock); + if (is_waiting(waiter)) { + SYNC("waited: %p", waiter); + list_add_tail(&waiter->list, &waiters); + spin_unlock(&sync_lock); + return 0; + } + + spin_unlock(&sync_lock); + } + + /* no waiting.. */ + fxn(arg); + + return 0; +} + +/* special API so PVR can update the buffer to use a sync-object allocated + * from it's sync-obj heap. Only used for a newly allocated (from PVR's + * perspective) sync-object, so we overwrite the new syncobj w/ values + * from the already allocated syncobj (if there is one) + */ +int omap_gem_set_sync_object(struct drm_gem_object *obj, void *syncobj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = 0; + + spin_lock(&sync_lock); + + if ((omap_obj->flags & OMAP_BO_EXT_SYNC) && !syncobj) { + /* clearing a previously set syncobj */ + syncobj = kzalloc(sizeof(*omap_obj->sync), GFP_ATOMIC); + if (!syncobj) { + ret = -ENOMEM; + goto unlock; + } + memcpy(syncobj, omap_obj->sync, sizeof(*omap_obj->sync)); + omap_obj->flags &= ~OMAP_BO_EXT_SYNC; + omap_obj->sync = syncobj; + } else if (syncobj && !(omap_obj->flags & OMAP_BO_EXT_SYNC)) { + /* replacing an existing syncobj */ + if (omap_obj->sync) { + memcpy(syncobj, omap_obj->sync, sizeof(*omap_obj->sync)); + kfree(omap_obj->sync); + } + omap_obj->flags |= OMAP_BO_EXT_SYNC; + omap_obj->sync = syncobj; + } + +unlock: + spin_unlock(&sync_lock); + return ret; +} + +int omap_gem_init_object(struct drm_gem_object *obj) +{ + return -EINVAL; /* unused */ +} + +/* don't call directly.. called from GEM core when it is time to actually + * free the object.. + */ +void omap_gem_free_object(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + + evict(obj); + + if (obj->map_list.map) { + drm_gem_free_mmap_offset(obj); + } + + /* don't free externally allocated backing memory */ + if (!(omap_obj->flags & OMAP_BO_EXT_MEM)) { + if (omap_obj->pages) { + omap_gem_detach_pages(obj); + } + if (!is_shmem(obj)) { + dma_free_writecombine(dev->dev, obj->size, + omap_obj->vaddr, omap_obj->paddr); + } else if (omap_obj->vaddr) { + vunmap(omap_obj->vaddr); + } + } + + /* don't free externally allocated syncobj */ + if (!(omap_obj->flags & OMAP_BO_EXT_SYNC)) { + kfree(omap_obj->sync); + } + + drm_gem_object_release(obj); + + kfree(obj); +} + +/* convenience method to construct a GEM buffer object, and userspace handle */ +int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, + union omap_gem_size gsize, uint32_t flags, uint32_t *handle) +{ + struct drm_gem_object *obj; + int ret; + + obj = omap_gem_new(dev, gsize, flags); + if (!obj) + return -ENOMEM; + + ret = drm_gem_handle_create(file, obj, handle); + if (ret) { + drm_gem_object_release(obj); + kfree(obj); /* TODO isn't there a dtor to call? just copying i915 */ + return ret; + } + + /* drop reference from allocate - handle holds it now */ + drm_gem_object_unreference_unlocked(obj); + + return 0; +} + +/* GEM buffer object constructor */ +struct drm_gem_object *omap_gem_new(struct drm_device *dev, + union omap_gem_size gsize, uint32_t flags) +{ + struct omap_drm_private *priv = dev->dev_private; + struct omap_gem_object *omap_obj; + struct drm_gem_object *obj = NULL; + size_t size; + int ret; + + if (flags & OMAP_BO_TILED) { + if (!usergart) { + dev_err(dev->dev, "Tiled buffers require DMM\n"); + goto fail; + } + + /* tiled buffers are always shmem paged backed.. when they are + * scanned out, they are remapped into DMM/TILER + */ + flags &= ~OMAP_BO_SCANOUT; + + /* currently don't allow cached buffers.. there is some caching + * stuff that needs to be handled better + */ + flags &= ~(OMAP_BO_CACHED|OMAP_BO_UNCACHED); + flags |= OMAP_BO_WC; + + /* align dimensions to slot boundaries... */ + tiler_align(gem2fmt(flags), + &gsize.tiled.width, &gsize.tiled.height); + + /* ...and calculate size based on aligned dimensions */ + size = tiler_size(gem2fmt(flags), + gsize.tiled.width, gsize.tiled.height); + } else { + size = PAGE_ALIGN(gsize.bytes); + } + + omap_obj = kzalloc(sizeof(*omap_obj), GFP_KERNEL); + if (!omap_obj) { + dev_err(dev->dev, "could not allocate GEM object\n"); + goto fail; + } + + obj = &omap_obj->base; + + if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) { + /* attempt to allocate contiguous memory if we don't + * have DMM for remappign discontiguous buffers + */ + omap_obj->vaddr = dma_alloc_writecombine(dev->dev, size, + &omap_obj->paddr, GFP_KERNEL); + if (omap_obj->vaddr) { + flags |= OMAP_BO_DMA; + } + } + + omap_obj->flags = flags; + + if (flags & OMAP_BO_TILED) { + omap_obj->width = gsize.tiled.width; + omap_obj->height = gsize.tiled.height; + } + + if (flags & (OMAP_BO_DMA|OMAP_BO_EXT_MEM)) { + ret = drm_gem_private_object_init(dev, obj, size); + } else { + ret = drm_gem_object_init(dev, obj, size); + } + + if (ret) { + goto fail; + } + + return obj; + +fail: + if (obj) { + omap_gem_free_object(obj); + } + return NULL; +} + +/* init/cleanup.. if DMM is used, we need to set some stuff up.. */ +void omap_gem_init(struct drm_device *dev) +{ + struct omap_drm_private *priv = dev->dev_private; + const enum tiler_fmt fmts[] = { + TILFMT_8BIT, TILFMT_16BIT, TILFMT_32BIT + }; + int i, j, ret; + + ret = omap_dmm_init(dev); + if (ret) { + /* DMM only supported on OMAP4 and later, so this isn't fatal */ + dev_warn(dev->dev, "omap_dmm_init failed, disabling DMM\n"); + return; + } + + usergart = kzalloc(3 * sizeof(*usergart), GFP_KERNEL); + if (!usergart) { + dev_warn(dev->dev, "could not allocate usergart\n"); + return; + } + + /* reserve 4k aligned/wide regions for userspace mappings: */ + for (i = 0; i < ARRAY_SIZE(fmts); i++) { + uint16_t h = 1, w = PAGE_SIZE >> i; + tiler_align(fmts[i], &w, &h); + /* note: since each region is 1 4kb page wide, and minimum + * number of rows, the height ends up being the same as the + * # of pages in the region + */ + usergart[i].height = h; + usergart[i].height_shift = ilog2(h); + usergart[i].stride_pfn = tiler_stride(fmts[i]) >> PAGE_SHIFT; + usergart[i].slot_shift = ilog2((PAGE_SIZE / h) >> i); + for (j = 0; j < NUM_USERGART_ENTRIES; j++) { + struct usergart_entry *entry = &usergart[i].entry[j]; + struct tiler_block *block = + tiler_reserve_2d(fmts[i], w, h, + PAGE_SIZE); + if (IS_ERR(block)) { + dev_err(dev->dev, + "reserve failed: %d, %d, %ld\n", + i, j, PTR_ERR(block)); + return; + } + entry->paddr = tiler_ssptr(block); + entry->block = block; + + DBG("%d:%d: %dx%d: paddr=%08x stride=%d", i, j, w, h, + entry->paddr, + usergart[i].stride_pfn << PAGE_SHIFT); + } + } + + priv->has_dmm = true; +} + +void omap_gem_deinit(struct drm_device *dev) +{ + /* I believe we can rely on there being no more outstanding GEM + * objects which could depend on usergart/dmm at this point. + */ + omap_dmm_remove(); + kfree(usergart); +} diff --git a/drivers/staging/omapdrm/omap_gem_helpers.c b/drivers/staging/omapdrm/omap_gem_helpers.c new file mode 100644 index 00000000000..29275c7209e --- /dev/null +++ b/drivers/staging/omapdrm/omap_gem_helpers.c @@ -0,0 +1,169 @@ +/* + * drivers/staging/omapdrm/omap_gem_helpers.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob.clark@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* temporary copy of drm_gem_{get,put}_pages() until the + * "drm/gem: add functions to get/put pages" patch is merged.. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/shmem_fs.h> + +#include <drm/drmP.h> + +/** + * drm_gem_get_pages - helper to allocate backing pages for a GEM object + * @obj: obj in question + * @gfpmask: gfp mask of requested pages + */ +struct page ** _drm_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask) +{ + struct inode *inode; + struct address_space *mapping; + struct page *p, **pages; + int i, npages; + + /* This is the shared memory object that backs the GEM resource */ + inode = obj->filp->f_path.dentry->d_inode; + mapping = inode->i_mapping; + + npages = obj->size >> PAGE_SHIFT; + + pages = drm_malloc_ab(npages, sizeof(struct page *)); + if (pages == NULL) + return ERR_PTR(-ENOMEM); + + gfpmask |= mapping_gfp_mask(mapping); + + for (i = 0; i < npages; i++) { + p = shmem_read_mapping_page_gfp(mapping, i, gfpmask); + if (IS_ERR(p)) + goto fail; + pages[i] = p; + + /* There is a hypothetical issue w/ drivers that require + * buffer memory in the low 4GB.. if the pages are un- + * pinned, and swapped out, they can end up swapped back + * in above 4GB. If pages are already in memory, then + * shmem_read_mapping_page_gfp will ignore the gfpmask, + * even if the already in-memory page disobeys the mask. + * + * It is only a theoretical issue today, because none of + * the devices with this limitation can be populated with + * enough memory to trigger the issue. But this BUG_ON() + * is here as a reminder in case the problem with + * shmem_read_mapping_page_gfp() isn't solved by the time + * it does become a real issue. + * + * See this thread: http://lkml.org/lkml/2011/7/11/238 + */ + BUG_ON((gfpmask & __GFP_DMA32) && + (page_to_pfn(p) >= 0x00100000UL)); + } + + return pages; + +fail: + while (i--) { + page_cache_release(pages[i]); + } + drm_free_large(pages); + return ERR_PTR(PTR_ERR(p)); +} + +/** + * drm_gem_put_pages - helper to free backing pages for a GEM object + * @obj: obj in question + * @pages: pages to free + */ +void _drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, + bool dirty, bool accessed) +{ + int i, npages; + + npages = obj->size >> PAGE_SHIFT; + + for (i = 0; i < npages; i++) { + if (dirty) + set_page_dirty(pages[i]); + + if (accessed) + mark_page_accessed(pages[i]); + + /* Undo the reference we took when populating the table */ + page_cache_release(pages[i]); + } + + drm_free_large(pages); +} + +int +_drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size) +{ + struct drm_device *dev = obj->dev; + struct drm_gem_mm *mm = dev->mm_private; + struct drm_map_list *list; + struct drm_local_map *map; + int ret = 0; + + /* Set the object up for mmap'ing */ + list = &obj->map_list; + list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); + if (!list->map) + return -ENOMEM; + + map = list->map; + map->type = _DRM_GEM; + map->size = size; + map->handle = obj; + + /* Get a DRM GEM mmap offset allocated... */ + list->file_offset_node = drm_mm_search_free(&mm->offset_manager, + size / PAGE_SIZE, 0, 0); + + if (!list->file_offset_node) { + DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); + ret = -ENOSPC; + goto out_free_list; + } + + list->file_offset_node = drm_mm_get_block(list->file_offset_node, + size / PAGE_SIZE, 0); + if (!list->file_offset_node) { + ret = -ENOMEM; + goto out_free_list; + } + + list->hash.key = list->file_offset_node->start; + ret = drm_ht_insert_item(&mm->offset_hash, &list->hash); + if (ret) { + DRM_ERROR("failed to add to map hash\n"); + goto out_free_mm; + } + + return 0; + +out_free_mm: + drm_mm_put_block(list->file_offset_node); +out_free_list: + kfree(list->map); + list->map = NULL; + + return ret; +} diff --git a/drivers/staging/omapdrm/omap_priv.h b/drivers/staging/omapdrm/omap_priv.h new file mode 100644 index 00000000000..c324709aa9a --- /dev/null +++ b/drivers/staging/omapdrm/omap_priv.h @@ -0,0 +1,47 @@ +/* + * include/drm/omap_priv.h + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __OMAP_PRIV_H__ +#define __OMAP_PRIV_H__ + +/* Non-userspace facing APIs + */ + +/* optional platform data to configure the default configuration of which + * pipes/overlays/CRTCs are used.. if this is not provided, then instead the + * first CONFIG_DRM_OMAP_NUM_CRTCS are used, and they are each connected to + * one manager, with priority given to managers that are connected to + * detected devices. This should be a good default behavior for most cases, + * but yet there still might be times when you wish to do something different. + */ +struct omap_kms_platform_data { + int ovl_cnt; + const int *ovl_ids; + int mgr_cnt; + const int *mgr_ids; + int dev_cnt; + const char **dev_names; +}; + +struct omap_drm_platform_data { + struct omap_kms_platform_data *kms_pdata; + struct omap_dmm_platform_data *dmm_pdata; +}; + +#endif /* __OMAP_DRM_H__ */ diff --git a/drivers/staging/omapdrm/tcm-sita.c b/drivers/staging/omapdrm/tcm-sita.c new file mode 100644 index 00000000000..10d5ac3dae4 --- /dev/null +++ b/drivers/staging/omapdrm/tcm-sita.c @@ -0,0 +1,703 @@ +/* + * tcm-sita.c + * + * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm + * + * Authors: Ravi Ramachandra <r.ramachandra@ti.com>, + * Lajos Molnar <molnar@ti.com> + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include "tcm-sita.h" + +#define ALIGN_DOWN(value, align) ((value) & ~((align) - 1)) + +/* Individual selection criteria for different scan areas */ +static s32 CR_L2R_T2B = CR_BIAS_HORIZONTAL; +static s32 CR_R2L_T2B = CR_DIAGONAL_BALANCE; + +/********************************************* + * TCM API - Sita Implementation + *********************************************/ +static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align, + struct tcm_area *area); +static s32 sita_reserve_1d(struct tcm *tcm, u32 slots, struct tcm_area *area); +static s32 sita_free(struct tcm *tcm, struct tcm_area *area); +static void sita_deinit(struct tcm *tcm); + +/********************************************* + * Main Scanner functions + *********************************************/ +static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align, + struct tcm_area *area); + +static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, + struct tcm_area *field, struct tcm_area *area); + +static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, + struct tcm_area *field, struct tcm_area *area); + +static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots, + struct tcm_area *field, struct tcm_area *area); + +/********************************************* + * Support Infrastructure Methods + *********************************************/ +static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h); + +static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h, + struct tcm_area *field, s32 criteria, + struct score *best); + +static void get_nearness_factor(struct tcm_area *field, + struct tcm_area *candidate, + struct nearness_factor *nf); + +static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area, + struct neighbor_stats *stat); + +static void fill_area(struct tcm *tcm, + struct tcm_area *area, struct tcm_area *parent); + + +/*********************************************/ + +/********************************************* + * Utility Methods + *********************************************/ +struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr) +{ + struct tcm *tcm; + struct sita_pvt *pvt; + struct tcm_area area = {0}; + s32 i; + + if (width == 0 || height == 0) + return NULL; + + tcm = kmalloc(sizeof(*tcm), GFP_KERNEL); + pvt = kmalloc(sizeof(*pvt), GFP_KERNEL); + if (!tcm || !pvt) + goto error; + + memset(tcm, 0, sizeof(*tcm)); + memset(pvt, 0, sizeof(*pvt)); + + /* Updating the pointers to SiTA implementation APIs */ + tcm->height = height; + tcm->width = width; + tcm->reserve_2d = sita_reserve_2d; + tcm->reserve_1d = sita_reserve_1d; + tcm->free = sita_free; + tcm->deinit = sita_deinit; + tcm->pvt = (void *)pvt; + + spin_lock_init(&(pvt->lock)); + + /* Creating tam map */ + pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL); + if (!pvt->map) + goto error; + + for (i = 0; i < tcm->width; i++) { + pvt->map[i] = + kmalloc(sizeof(**pvt->map) * tcm->height, + GFP_KERNEL); + if (pvt->map[i] == NULL) { + while (i--) + kfree(pvt->map[i]); + kfree(pvt->map); + goto error; + } + } + + if (attr && attr->x <= tcm->width && attr->y <= tcm->height) { + pvt->div_pt.x = attr->x; + pvt->div_pt.y = attr->y; + + } else { + /* Defaulting to 3:1 ratio on width for 2D area split */ + /* Defaulting to 3:1 ratio on height for 2D and 1D split */ + pvt->div_pt.x = (tcm->width * 3) / 4; + pvt->div_pt.y = (tcm->height * 3) / 4; + } + + spin_lock(&(pvt->lock)); + assign(&area, 0, 0, width - 1, height - 1); + fill_area(tcm, &area, NULL); + spin_unlock(&(pvt->lock)); + return tcm; + +error: + kfree(tcm); + kfree(pvt); + return NULL; +} + +static void sita_deinit(struct tcm *tcm) +{ + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + struct tcm_area area = {0}; + s32 i; + + area.p1.x = tcm->width - 1; + area.p1.y = tcm->height - 1; + + spin_lock(&(pvt->lock)); + fill_area(tcm, &area, NULL); + spin_unlock(&(pvt->lock)); + + for (i = 0; i < tcm->height; i++) + kfree(pvt->map[i]); + kfree(pvt->map); + kfree(pvt); +} + +/** + * Reserve a 1D area in the container + * + * @param num_slots size of 1D area + * @param area pointer to the area that will be populated with the + * reserved area + * + * @return 0 on success, non-0 error value on failure. + */ +static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots, + struct tcm_area *area) +{ + s32 ret; + struct tcm_area field = {0}; + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + + spin_lock(&(pvt->lock)); + + /* Scanning entire container */ + assign(&field, tcm->width - 1, tcm->height - 1, 0, 0); + + ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area); + if (!ret) + /* update map */ + fill_area(tcm, area, area); + + spin_unlock(&(pvt->lock)); + return ret; +} + +/** + * Reserve a 2D area in the container + * + * @param w width + * @param h height + * @param area pointer to the area that will be populated with the reesrved + * area + * + * @return 0 on success, non-0 error value on failure. + */ +static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align, + struct tcm_area *area) +{ + s32 ret; + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + + /* not supporting more than 64 as alignment */ + if (align > 64) + return -EINVAL; + + /* we prefer 1, 32 and 64 as alignment */ + align = align <= 1 ? 1 : align <= 32 ? 32 : 64; + + spin_lock(&(pvt->lock)); + ret = scan_areas_and_find_fit(tcm, w, h, align, area); + if (!ret) + /* update map */ + fill_area(tcm, area, area); + + spin_unlock(&(pvt->lock)); + return ret; +} + +/** + * Unreserve a previously allocated 2D or 1D area + * @param area area to be freed + * @return 0 - success + */ +static s32 sita_free(struct tcm *tcm, struct tcm_area *area) +{ + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + + spin_lock(&(pvt->lock)); + + /* check that this is in fact an existing area */ + WARN_ON(pvt->map[area->p0.x][area->p0.y] != area || + pvt->map[area->p1.x][area->p1.y] != area); + + /* Clear the contents of the associated tiles in the map */ + fill_area(tcm, area, NULL); + + spin_unlock(&(pvt->lock)); + + return 0; +} + +/** + * Note: In general the cordinates in the scan field area relevant to the can + * sweep directions. The scan origin (e.g. top-left corner) will always be + * the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x + * and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y + * <= p0.y + */ + +/** + * Raster scan horizontally right to left from top to bottom to find a place for + * a 2D area of given size inside a scan field. + * + * @param w width of desired area + * @param h height of desired area + * @param align desired area alignment + * @param area pointer to the area that will be set to the best position + * @param field area to scan (inclusive) + * + * @return 0 on success, non-0 error value on failure. + */ +static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, + struct tcm_area *field, struct tcm_area *area) +{ + s32 x, y; + s16 start_x, end_x, start_y, end_y, found_x = -1; + struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map; + struct score best = {{0}, {0}, {0}, 0}; + + start_x = field->p0.x; + end_x = field->p1.x; + start_y = field->p0.y; + end_y = field->p1.y; + + /* check scan area co-ordinates */ + if (field->p0.x < field->p1.x || + field->p1.y < field->p0.y) + return -EINVAL; + + /* check if allocation would fit in scan area */ + if (w > LEN(start_x, end_x) || h > LEN(end_y, start_y)) + return -ENOSPC; + + /* adjust start_x and end_y, as allocation would not fit beyond */ + start_x = ALIGN_DOWN(start_x - w + 1, align); /* - 1 to be inclusive */ + end_y = end_y - h + 1; + + /* check if allocation would still fit in scan area */ + if (start_x < end_x) + return -ENOSPC; + + /* scan field top-to-bottom, right-to-left */ + for (y = start_y; y <= end_y; y++) { + for (x = start_x; x >= end_x; x -= align) { + if (is_area_free(map, x, y, w, h)) { + found_x = x; + + /* update best candidate */ + if (update_candidate(tcm, x, y, w, h, field, + CR_R2L_T2B, &best)) + goto done; + + /* change upper x bound */ + end_x = x + 1; + break; + } else if (map[x][y] && map[x][y]->is2d) { + /* step over 2D areas */ + x = ALIGN(map[x][y]->p0.x - w + 1, align); + } + } + + /* break if you find a free area shouldering the scan field */ + if (found_x == start_x) + break; + } + + if (!best.a.tcm) + return -ENOSPC; +done: + assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y); + return 0; +} + +/** + * Raster scan horizontally left to right from top to bottom to find a place for + * a 2D area of given size inside a scan field. + * + * @param w width of desired area + * @param h height of desired area + * @param align desired area alignment + * @param area pointer to the area that will be set to the best position + * @param field area to scan (inclusive) + * + * @return 0 on success, non-0 error value on failure. + */ +static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, + struct tcm_area *field, struct tcm_area *area) +{ + s32 x, y; + s16 start_x, end_x, start_y, end_y, found_x = -1; + struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map; + struct score best = {{0}, {0}, {0}, 0}; + + start_x = field->p0.x; + end_x = field->p1.x; + start_y = field->p0.y; + end_y = field->p1.y; + + /* check scan area co-ordinates */ + if (field->p1.x < field->p0.x || + field->p1.y < field->p0.y) + return -EINVAL; + + /* check if allocation would fit in scan area */ + if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y)) + return -ENOSPC; + + start_x = ALIGN(start_x, align); + + /* check if allocation would still fit in scan area */ + if (w > LEN(end_x, start_x)) + return -ENOSPC; + + /* adjust end_x and end_y, as allocation would not fit beyond */ + end_x = end_x - w + 1; /* + 1 to be inclusive */ + end_y = end_y - h + 1; + + /* scan field top-to-bottom, left-to-right */ + for (y = start_y; y <= end_y; y++) { + for (x = start_x; x <= end_x; x += align) { + if (is_area_free(map, x, y, w, h)) { + found_x = x; + + /* update best candidate */ + if (update_candidate(tcm, x, y, w, h, field, + CR_L2R_T2B, &best)) + goto done; + /* change upper x bound */ + end_x = x - 1; + + break; + } else if (map[x][y] && map[x][y]->is2d) { + /* step over 2D areas */ + x = ALIGN_DOWN(map[x][y]->p1.x, align); + } + } + + /* break if you find a free area shouldering the scan field */ + if (found_x == start_x) + break; + } + + if (!best.a.tcm) + return -ENOSPC; +done: + assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y); + return 0; +} + +/** + * Raster scan horizontally right to left from bottom to top to find a place + * for a 1D area of given size inside a scan field. + * + * @param num_slots size of desired area + * @param align desired area alignment + * @param area pointer to the area that will be set to the best + * position + * @param field area to scan (inclusive) + * + * @return 0 on success, non-0 error value on failure. + */ +static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots, + struct tcm_area *field, struct tcm_area *area) +{ + s32 found = 0; + s16 x, y; + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + struct tcm_area *p; + + /* check scan area co-ordinates */ + if (field->p0.y < field->p1.y) + return -EINVAL; + + /** + * Currently we only support full width 1D scan field, which makes sense + * since 1D slot-ordering spans the full container width. + */ + if (tcm->width != field->p0.x - field->p1.x + 1) + return -EINVAL; + + /* check if allocation would fit in scan area */ + if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y)) + return -ENOSPC; + + x = field->p0.x; + y = field->p0.y; + + /* find num_slots consecutive free slots to the left */ + while (found < num_slots) { + if (y < 0) + return -ENOSPC; + + /* remember bottom-right corner */ + if (found == 0) { + area->p1.x = x; + area->p1.y = y; + } + + /* skip busy regions */ + p = pvt->map[x][y]; + if (p) { + /* move to left of 2D areas, top left of 1D */ + x = p->p0.x; + if (!p->is2d) + y = p->p0.y; + + /* start over */ + found = 0; + } else { + /* count consecutive free slots */ + found++; + if (found == num_slots) + break; + } + + /* move to the left */ + if (x == 0) + y--; + x = (x ? : tcm->width) - 1; + + } + + /* set top-left corner */ + area->p0.x = x; + area->p0.y = y; + return 0; +} + +/** + * Find a place for a 2D area of given size inside a scan field based on its + * alignment needs. + * + * @param w width of desired area + * @param h height of desired area + * @param align desired area alignment + * @param area pointer to the area that will be set to the best position + * + * @return 0 on success, non-0 error value on failure. + */ +static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align, + struct tcm_area *area) +{ + s32 ret = 0; + struct tcm_area field = {0}; + u16 boundary_x, boundary_y; + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + + if (align > 1) { + /* prefer top-left corner */ + boundary_x = pvt->div_pt.x - 1; + boundary_y = pvt->div_pt.y - 1; + + /* expand width and height if needed */ + if (w > pvt->div_pt.x) + boundary_x = tcm->width - 1; + if (h > pvt->div_pt.y) + boundary_y = tcm->height - 1; + + assign(&field, 0, 0, boundary_x, boundary_y); + ret = scan_l2r_t2b(tcm, w, h, align, &field, area); + + /* scan whole container if failed, but do not scan 2x */ + if (ret != 0 && (boundary_x != tcm->width - 1 || + boundary_y != tcm->height - 1)) { + /* scan the entire container if nothing found */ + assign(&field, 0, 0, tcm->width - 1, tcm->height - 1); + ret = scan_l2r_t2b(tcm, w, h, align, &field, area); + } + } else if (align == 1) { + /* prefer top-right corner */ + boundary_x = pvt->div_pt.x; + boundary_y = pvt->div_pt.y - 1; + + /* expand width and height if needed */ + if (w > (tcm->width - pvt->div_pt.x)) + boundary_x = 0; + if (h > pvt->div_pt.y) + boundary_y = tcm->height - 1; + + assign(&field, tcm->width - 1, 0, boundary_x, boundary_y); + ret = scan_r2l_t2b(tcm, w, h, align, &field, area); + + /* scan whole container if failed, but do not scan 2x */ + if (ret != 0 && (boundary_x != 0 || + boundary_y != tcm->height - 1)) { + /* scan the entire container if nothing found */ + assign(&field, tcm->width - 1, 0, 0, tcm->height - 1); + ret = scan_r2l_t2b(tcm, w, h, align, &field, + area); + } + } + + return ret; +} + +/* check if an entire area is free */ +static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h) +{ + u16 x = 0, y = 0; + for (y = y0; y < y0 + h; y++) { + for (x = x0; x < x0 + w; x++) { + if (map[x][y]) + return false; + } + } + return true; +} + +/* fills an area with a parent tcm_area */ +static void fill_area(struct tcm *tcm, struct tcm_area *area, + struct tcm_area *parent) +{ + s32 x, y; + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + struct tcm_area a, a_; + + /* set area's tcm; otherwise, enumerator considers it invalid */ + area->tcm = tcm; + + tcm_for_each_slice(a, *area, a_) { + for (x = a.p0.x; x <= a.p1.x; ++x) + for (y = a.p0.y; y <= a.p1.y; ++y) + pvt->map[x][y] = parent; + + } +} + +/** + * Compares a candidate area to the current best area, and if it is a better + * fit, it updates the best to this one. + * + * @param x0, y0, w, h top, left, width, height of candidate area + * @param field scan field + * @param criteria scan criteria + * @param best best candidate and its scores + * + * @return 1 (true) if the candidate area is known to be the final best, so no + * more searching should be performed + */ +static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h, + struct tcm_area *field, s32 criteria, + struct score *best) +{ + struct score me; /* score for area */ + + /* + * NOTE: For horizontal bias we always give the first found, because our + * scan is horizontal-raster-based and the first candidate will always + * have the horizontal bias. + */ + bool first = criteria & CR_BIAS_HORIZONTAL; + + assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1); + + /* calculate score for current candidate */ + if (!first) { + get_neighbor_stats(tcm, &me.a, &me.n); + me.neighs = me.n.edge + me.n.busy; + get_nearness_factor(field, &me.a, &me.f); + } + + /* the 1st candidate is always the best */ + if (!best->a.tcm) + goto better; + + BUG_ON(first); + + /* diagonal balance check */ + if ((criteria & CR_DIAGONAL_BALANCE) && + best->neighs <= me.neighs && + (best->neighs < me.neighs || + /* this implies that neighs and occupied match */ + best->n.busy < me.n.busy || + (best->n.busy == me.n.busy && + /* check the nearness factor */ + best->f.x + best->f.y > me.f.x + me.f.y))) + goto better; + + /* not better, keep going */ + return 0; + +better: + /* save current area as best */ + memcpy(best, &me, sizeof(me)); + best->a.tcm = tcm; + return first; +} + +/** + * Calculate the nearness factor of an area in a search field. The nearness + * factor is smaller if the area is closer to the search origin. + */ +static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area, + struct nearness_factor *nf) +{ + /** + * Using signed math as field coordinates may be reversed if + * search direction is right-to-left or bottom-to-top. + */ + nf->x = (s32)(area->p0.x - field->p0.x) * 1000 / + (field->p1.x - field->p0.x); + nf->y = (s32)(area->p0.y - field->p0.y) * 1000 / + (field->p1.y - field->p0.y); +} + +/* get neighbor statistics */ +static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area, + struct neighbor_stats *stat) +{ + s16 x = 0, y = 0; + struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; + + /* Clearing any exisiting values */ + memset(stat, 0, sizeof(*stat)); + + /* process top & bottom edges */ + for (x = area->p0.x; x <= area->p1.x; x++) { + if (area->p0.y == 0) + stat->edge++; + else if (pvt->map[x][area->p0.y - 1]) + stat->busy++; + + if (area->p1.y == tcm->height - 1) + stat->edge++; + else if (pvt->map[x][area->p1.y + 1]) + stat->busy++; + } + + /* process left & right edges */ + for (y = area->p0.y; y <= area->p1.y; ++y) { + if (area->p0.x == 0) + stat->edge++; + else if (pvt->map[area->p0.x - 1][y]) + stat->busy++; + + if (area->p1.x == tcm->width - 1) + stat->edge++; + else if (pvt->map[area->p1.x + 1][y]) + stat->busy++; + } +} diff --git a/drivers/staging/omapdrm/tcm-sita.h b/drivers/staging/omapdrm/tcm-sita.h new file mode 100644 index 00000000000..0444f868671 --- /dev/null +++ b/drivers/staging/omapdrm/tcm-sita.h @@ -0,0 +1,95 @@ +/* + * tcm_sita.h + * + * SImple Tiler Allocator (SiTA) private structures. + * + * Author: Ravi Ramachandra <r.ramachandra@ti.com> + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TCM_SITA_H +#define _TCM_SITA_H + +#include "tcm.h" + +/* length between two coordinates */ +#define LEN(a, b) ((a) > (b) ? (a) - (b) + 1 : (b) - (a) + 1) + +enum criteria { + CR_MAX_NEIGHS = 0x01, + CR_FIRST_FOUND = 0x10, + CR_BIAS_HORIZONTAL = 0x20, + CR_BIAS_VERTICAL = 0x40, + CR_DIAGONAL_BALANCE = 0x80 +}; + +/* nearness to the beginning of the search field from 0 to 1000 */ +struct nearness_factor { + s32 x; + s32 y; +}; + +/* + * Statistics on immediately neighboring slots. Edge is the number of + * border segments that are also border segments of the scan field. Busy + * refers to the number of neighbors that are occupied. + */ +struct neighbor_stats { + u16 edge; + u16 busy; +}; + +/* structure to keep the score of a potential allocation */ +struct score { + struct nearness_factor f; + struct neighbor_stats n; + struct tcm_area a; + u16 neighs; /* number of busy neighbors */ +}; + +struct sita_pvt { + spinlock_t lock; /* spinlock to protect access */ + struct tcm_pt div_pt; /* divider point splitting container */ + struct tcm_area ***map; /* pointers to the parent area for each slot */ +}; + +/* assign coordinates to area */ +static inline +void assign(struct tcm_area *a, u16 x0, u16 y0, u16 x1, u16 y1) +{ + a->p0.x = x0; + a->p0.y = y0; + a->p1.x = x1; + a->p1.y = y1; +} + +#endif diff --git a/drivers/staging/omapdrm/tcm.h b/drivers/staging/omapdrm/tcm.h new file mode 100644 index 00000000000..d273e3ee0b4 --- /dev/null +++ b/drivers/staging/omapdrm/tcm.h @@ -0,0 +1,326 @@ +/* + * tcm.h + * + * TILER container manager specification and support functions for TI + * TILER driver. + * + * Author: Lajos Molnar <molnar@ti.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TCM_H +#define TCM_H + +struct tcm; + +/* point */ +struct tcm_pt { + u16 x; + u16 y; +}; + +/* 1d or 2d area */ +struct tcm_area { + bool is2d; /* whether area is 1d or 2d */ + struct tcm *tcm; /* parent */ + struct tcm_pt p0; + struct tcm_pt p1; +}; + +struct tcm { + u16 width, height; /* container dimensions */ + int lut_id; /* Lookup table identifier */ + + /* 'pvt' structure shall contain any tcm details (attr) along with + linked list of allocated areas and mutex for mutually exclusive access + to the list. It may also contain copies of width and height to notice + any changes to the publicly available width and height fields. */ + void *pvt; + + /* function table */ + s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u8 align, + struct tcm_area *area); + s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area); + s32 (*free) (struct tcm *tcm, struct tcm_area *area); + void (*deinit) (struct tcm *tcm); +}; + +/*============================================================================= + BASIC TILER CONTAINER MANAGER INTERFACE +=============================================================================*/ + +/* + * NOTE: + * + * Since some basic parameter checking is done outside the TCM algorithms, + * TCM implementation do NOT have to check the following: + * + * area pointer is NULL + * width and height fits within container + * number of pages is more than the size of the container + * + */ + +struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr); + + +/** + * Deinitialize tiler container manager. + * + * @param tcm Pointer to container manager. + * + * @return 0 on success, non-0 error value on error. The call + * should free as much memory as possible and meaningful + * even on failure. Some error codes: -ENODEV: invalid + * manager. + */ +static inline void tcm_deinit(struct tcm *tcm) +{ + if (tcm) + tcm->deinit(tcm); +} + +/** + * Reserves a 2D area in the container. + * + * @param tcm Pointer to container manager. + * @param height Height(in pages) of area to be reserved. + * @param width Width(in pages) of area to be reserved. + * @param align Alignment requirement for top-left corner of area. Not + * all values may be supported by the container manager, + * but it must support 0 (1), 32 and 64. + * 0 value is equivalent to 1. + * @param area Pointer to where the reserved area should be stored. + * + * @return 0 on success. Non-0 error code on failure. Also, + * the tcm field of the area will be set to NULL on + * failure. Some error codes: -ENODEV: invalid manager, + * -EINVAL: invalid area, -ENOMEM: not enough space for + * allocation. + */ +static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height, + u16 align, struct tcm_area *area) +{ + /* perform rudimentary error checking */ + s32 res = tcm == NULL ? -ENODEV : + (area == NULL || width == 0 || height == 0 || + /* align must be a 2 power */ + (align & (align - 1))) ? -EINVAL : + (height > tcm->height || width > tcm->width) ? -ENOMEM : 0; + + if (!res) { + area->is2d = true; + res = tcm->reserve_2d(tcm, height, width, align, area); + area->tcm = res ? NULL : tcm; + } + + return res; +} + +/** + * Reserves a 1D area in the container. + * + * @param tcm Pointer to container manager. + * @param slots Number of (contiguous) slots to reserve. + * @param area Pointer to where the reserved area should be stored. + * + * @return 0 on success. Non-0 error code on failure. Also, + * the tcm field of the area will be set to NULL on + * failure. Some error codes: -ENODEV: invalid manager, + * -EINVAL: invalid area, -ENOMEM: not enough space for + * allocation. + */ +static inline s32 tcm_reserve_1d(struct tcm *tcm, u32 slots, + struct tcm_area *area) +{ + /* perform rudimentary error checking */ + s32 res = tcm == NULL ? -ENODEV : + (area == NULL || slots == 0) ? -EINVAL : + slots > (tcm->width * (u32) tcm->height) ? -ENOMEM : 0; + + if (!res) { + area->is2d = false; + res = tcm->reserve_1d(tcm, slots, area); + area->tcm = res ? NULL : tcm; + } + + return res; +} + +/** + * Free a previously reserved area from the container. + * + * @param area Pointer to area reserved by a prior call to + * tcm_reserve_1d or tcm_reserve_2d call, whether + * it was successful or not. (Note: all fields of + * the structure must match.) + * + * @return 0 on success. Non-0 error code on failure. Also, the tcm + * field of the area is set to NULL on success to avoid subsequent + * freeing. This call will succeed even if supplying + * the area from a failed reserved call. + */ +static inline s32 tcm_free(struct tcm_area *area) +{ + s32 res = 0; /* free succeeds by default */ + + if (area && area->tcm) { + res = area->tcm->free(area->tcm, area); + if (res == 0) + area->tcm = NULL; + } + + return res; +} + +/*============================================================================= + HELPER FUNCTION FOR ANY TILER CONTAINER MANAGER +=============================================================================*/ + +/** + * This method slices off the topmost 2D slice from the parent area, and stores + * it in the 'slice' parameter. The 'parent' parameter will get modified to + * contain the remaining portion of the area. If the whole parent area can + * fit in a 2D slice, its tcm pointer is set to NULL to mark that it is no + * longer a valid area. + * + * @param parent Pointer to a VALID parent area that will get modified + * @param slice Pointer to the slice area that will get modified + */ +static inline void tcm_slice(struct tcm_area *parent, struct tcm_area *slice) +{ + *slice = *parent; + + /* check if we need to slice */ + if (slice->tcm && !slice->is2d && + slice->p0.y != slice->p1.y && + (slice->p0.x || (slice->p1.x != slice->tcm->width - 1))) { + /* set end point of slice (start always remains) */ + slice->p1.x = slice->tcm->width - 1; + slice->p1.y = (slice->p0.x) ? slice->p0.y : slice->p1.y - 1; + /* adjust remaining area */ + parent->p0.x = 0; + parent->p0.y = slice->p1.y + 1; + } else { + /* mark this as the last slice */ + parent->tcm = NULL; + } +} + +/* Verify if a tcm area is logically valid */ +static inline bool tcm_area_is_valid(struct tcm_area *area) +{ + return area && area->tcm && + /* coordinate bounds */ + area->p1.x < area->tcm->width && + area->p1.y < area->tcm->height && + area->p0.y <= area->p1.y && + /* 1D coordinate relationship + p0.x check */ + ((!area->is2d && + area->p0.x < area->tcm->width && + area->p0.x + area->p0.y * area->tcm->width <= + area->p1.x + area->p1.y * area->tcm->width) || + /* 2D coordinate relationship */ + (area->is2d && + area->p0.x <= area->p1.x)); +} + +/* see if a coordinate is within an area */ +static inline bool __tcm_is_in(struct tcm_pt *p, struct tcm_area *a) +{ + u16 i; + + if (a->is2d) { + return p->x >= a->p0.x && p->x <= a->p1.x && + p->y >= a->p0.y && p->y <= a->p1.y; + } else { + i = p->x + p->y * a->tcm->width; + return i >= a->p0.x + a->p0.y * a->tcm->width && + i <= a->p1.x + a->p1.y * a->tcm->width; + } +} + +/* calculate area width */ +static inline u16 __tcm_area_width(struct tcm_area *area) +{ + return area->p1.x - area->p0.x + 1; +} + +/* calculate area height */ +static inline u16 __tcm_area_height(struct tcm_area *area) +{ + return area->p1.y - area->p0.y + 1; +} + +/* calculate number of slots in an area */ +static inline u16 __tcm_sizeof(struct tcm_area *area) +{ + return area->is2d ? + __tcm_area_width(area) * __tcm_area_height(area) : + (area->p1.x - area->p0.x + 1) + (area->p1.y - area->p0.y) * + area->tcm->width; +} +#define tcm_sizeof(area) __tcm_sizeof(&(area)) +#define tcm_awidth(area) __tcm_area_width(&(area)) +#define tcm_aheight(area) __tcm_area_height(&(area)) +#define tcm_is_in(pt, area) __tcm_is_in(&(pt), &(area)) + +/* limit a 1D area to the first N pages */ +static inline s32 tcm_1d_limit(struct tcm_area *a, u32 num_pg) +{ + if (__tcm_sizeof(a) < num_pg) + return -ENOMEM; + if (!num_pg) + return -EINVAL; + + a->p1.x = (a->p0.x + num_pg - 1) % a->tcm->width; + a->p1.y = a->p0.y + ((a->p0.x + num_pg - 1) / a->tcm->width); + return 0; +} + +/** + * Iterate through 2D slices of a valid area. Behaves + * syntactically as a for(;;) statement. + * + * @param var Name of a local variable of type 'struct + * tcm_area *' that will get modified to + * contain each slice. + * @param area Pointer to the VALID parent area. This + * structure will not get modified + * throughout the loop. + * + */ +#define tcm_for_each_slice(var, area, safe) \ + for (safe = area, \ + tcm_slice(&safe, &var); \ + var.tcm; tcm_slice(&safe, &var)) + +#endif diff --git a/drivers/staging/phison/phison.c b/drivers/staging/phison/phison.c index 683657cb21f..d77b21f1eb2 100644 --- a/drivers/staging/phison/phison.c +++ b/drivers/staging/phison/phison.c @@ -70,7 +70,7 @@ static int phison_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } static DEFINE_PCI_DEVICE_TABLE(phison_pci_tbl) = { - { PCI_VENDOR_ID_PHISON, PCI_DEVICE_ID_PS5000, PCI_ANY_ID, PCI_ANY_ID, + { PCI_DEVICE(PCI_VENDOR_ID_PHISON, PCI_DEVICE_ID_PS5000), PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, { 0, }, }; diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig index 750c347bfbe..f87e2110185 100644 --- a/drivers/staging/rtl8192e/Kconfig +++ b/drivers/staging/rtl8192e/Kconfig @@ -1,9 +1,43 @@ -config RTL8192E - tristate "RealTek RTL8192E Wireless LAN NIC driver" - depends on PCI && WLAN - depends on m - select WIRELESS_EXT - select WEXT_PRIV - select CRYPTO - default N +config RTLLIB + tristate "Support for rtllib wireless devices" + depends on WLAN && m + default n + select LIB80211 ---help--- + If you have a wireless card that uses rtllib, say + Y. Currently the only card is the rtl8192e. + + If unsure, say N. + +if RTLLIB + +config RTLLIB_CRYPTO_CCMP + tristate "Support for rtllib CCMP crypto" + depends on RTLLIB + default y + ---help--- + CCMP crypto driver for rtllib. + + If you enabled RTLLIB, you want this. + +config RTLLIB_CRYPTO_TKIP + tristate "Support for rtllib TKIP crypto" + depends on RTLLIB + default y + ---help--- + TKIP crypto driver for rtllib. + + If you enabled RTLLIB, you want this. + +config RTLLIB_CRYPTO_WEP + tristate "Support for rtllib WEP crypto" + depends on RTLLIB + default y + ---help--- + TKIP crypto driver for rtllib. + + If you enabled RTLLIB, you want this. + +source "drivers/staging/rtl8192e/rtl8192e/Kconfig" + +endif diff --git a/drivers/staging/rtl8192e/Makefile b/drivers/staging/rtl8192e/Makefile index a66a9ad3368..cb18db74d78 100644 --- a/drivers/staging/rtl8192e/Makefile +++ b/drivers/staging/rtl8192e/Makefile @@ -1,41 +1,21 @@ -ccflags-y += -DUSE_FW_SOURCE_IMG_FILE -ccflags-y += -DCONFIG_PM_RTL -ccflags-y += -DCONFIG_PM -ccflags-y += -DHAVE_NET_DEVICE_OPS -ccflags-y += -DENABLE_DOT11D - -r8192e_pci-objs := \ - rtl_core.o \ - rtl_eeprom.o \ - rtl_ps.o \ - rtl_wx.o \ - rtl_cam.o \ - rtl_dm.o \ - rtl_pm.o \ - rtl_pci.o \ - rtl_debug.o \ - rtl_ethtool.o \ - r8192E_dev.o \ - r8192E_phy.o \ - r8192E_firmware.o \ - r8192E_cmdpkt.o \ - r8192E_hwimg.o \ - r8190P_rtl8256.o \ +rtllib-objs := \ + dot11d.o \ + rtllib_module.o \ rtllib_rx.o \ - rtllib_softmac.o \ rtllib_tx.o \ rtllib_wx.o \ - rtllib_module.o \ + rtllib_softmac.o \ rtllib_softmac_wx.o \ - rtl819x_HTProc.o \ - rtl819x_TSProc.o \ rtl819x_BAProc.o \ - dot11d.o \ - rtllib_crypt.o \ - rtllib_crypt_tkip.o \ - rtllib_crypt_ccmp.o \ - rtllib_crypt_wep.o + rtl819x_HTProc.o \ + rtl819x_TSProc.o + +obj-$(CONFIG_RTLLIB) += rtllib.o + +obj-$(CONFIG_RTLLIB_CRYPTO_CCMP) += rtllib_crypt_ccmp.o +obj-$(CONFIG_RTLLIB_CRYPTO_TKIP) += rtllib_crypt_tkip.o +obj-$(CONFIG_RTLLIB_CRYPTO_WEP) += rtllib_crypt_wep.o -obj-$(CONFIG_RTL8192E) += r8192e_pci.o +obj-$(CONFIG_RTL8192E) += rtl8192e/ ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c index ee0381e0a81..f7b14f8b7b8 100644 --- a/drivers/staging/rtl8192e/dot11d.c +++ b/drivers/staging/rtl8192e/dot11d.c @@ -46,7 +46,7 @@ static struct channel_list ChannelPlan[] = { 56, 60, 64}, 21} }; -void Dot11d_Init(struct rtllib_device *ieee) +void dot11d_init(struct rtllib_device *ieee) { struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(ieee); pDot11dInfo->bEnabled = false; @@ -58,6 +58,7 @@ void Dot11d_Init(struct rtllib_device *ieee) RESET_CIE_WATCHDOG(ieee); } +EXPORT_SYMBOL(dot11d_init); void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee) { @@ -99,6 +100,7 @@ void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee) break; } } +EXPORT_SYMBOL(Dot11d_Channelmap); void Dot11d_Reset(struct rtllib_device *ieee) diff --git a/drivers/staging/rtl8192e/dot11d.h b/drivers/staging/rtl8192e/dot11d.h index 032f7004a7f..71f4549a378 100644 --- a/drivers/staging/rtl8192e/dot11d.h +++ b/drivers/staging/rtl8192e/dot11d.h @@ -93,7 +93,7 @@ static inline void cpMacAddr(unsigned char *des, unsigned char *src) #define IS_DOT11D_STATE_DONE(__pIeeeDev) \ (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) -void Dot11d_Init(struct rtllib_device *dev); +void dot11d_init(struct rtllib_device *dev); void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee); void Dot11d_Reset(struct rtllib_device *dev); void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr, diff --git a/drivers/staging/rtl8192e/rtl8192e/Kconfig b/drivers/staging/rtl8192e/rtl8192e/Kconfig new file mode 100644 index 00000000000..50e0d91a409 --- /dev/null +++ b/drivers/staging/rtl8192e/rtl8192e/Kconfig @@ -0,0 +1,9 @@ +config RTL8192E + tristate "RealTek RTL8192E Wireless LAN NIC driver" + depends on PCI && WLAN && RTLLIB + depends on m + select WIRELESS_EXT + select WEXT_PRIV + select CRYPTO + default N + ---help--- diff --git a/drivers/staging/rtl8192e/rtl8192e/Makefile b/drivers/staging/rtl8192e/rtl8192e/Makefile new file mode 100644 index 00000000000..313a92ec683 --- /dev/null +++ b/drivers/staging/rtl8192e/rtl8192e/Makefile @@ -0,0 +1,21 @@ +r8192e_pci-objs := \ + r8192E_dev.o \ + r8192E_phy.o \ + r8192E_firmware.o \ + r8192E_cmdpkt.o \ + r8192E_hwimg.o \ + r8190P_rtl8256.o \ + rtl_cam.o \ + rtl_core.o \ + rtl_debug.o \ + rtl_dm.o \ + rtl_eeprom.o \ + rtl_ethtool.o \ + rtl_pci.o \ + rtl_pm.o \ + rtl_ps.o \ + rtl_wx.o \ + +obj-$(CONFIG_RTL8192E) += r8192e_pci.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/staging/rtl8192e/r8190P_def.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h index b7bb71fa9ec..b7bb71fa9ec 100644 --- a/drivers/staging/rtl8192e/r8190P_def.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h diff --git a/drivers/staging/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 0da56c80f08..0da56c80f08 100644 --- a/drivers/staging/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c diff --git a/drivers/staging/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h index 64e831d2f4e..64e831d2f4e 100644 --- a/drivers/staging/rtl8192e/r8190P_rtl8256.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h diff --git a/drivers/staging/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c index 58d044ea552..58d044ea552 100644 --- a/drivers/staging/rtl8192e/r8192E_cmdpkt.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c diff --git a/drivers/staging/rtl8192e/r8192E_cmdpkt.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h index 23219e17e5a..23219e17e5a 100644 --- a/drivers/staging/rtl8192e/r8192E_cmdpkt.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h diff --git a/drivers/staging/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 808aab6fa5e..808aab6fa5e 100644 --- a/drivers/staging/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c diff --git a/drivers/staging/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index b9b3b52f912..b9b3b52f912 100644 --- a/drivers/staging/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h diff --git a/drivers/staging/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index 37719859bda..37719859bda 100644 --- a/drivers/staging/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c diff --git a/drivers/staging/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h index caa87883310..caa87883310 100644 --- a/drivers/staging/rtl8192e/r8192E_firmware.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h diff --git a/drivers/staging/rtl8192e/r8192E_hw.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h index 43c3fb859d1..43c3fb859d1 100644 --- a/drivers/staging/rtl8192e/r8192E_hw.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h diff --git a/drivers/staging/rtl8192e/r8192E_hwimg.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c index 08e7dbb6694..08e7dbb6694 100644 --- a/drivers/staging/rtl8192e/r8192E_hwimg.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c diff --git a/drivers/staging/rtl8192e/r8192E_hwimg.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h index 019836bb36c..019836bb36c 100644 --- a/drivers/staging/rtl8192e/r8192E_hwimg.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h diff --git a/drivers/staging/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 7fe69a3348d..3e705efaaf2 100644 --- a/drivers/staging/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -23,7 +23,6 @@ #include "r8190P_rtl8256.h" #include "r8192E_phy.h" #include "rtl_dm.h" -#include "dot11d.h" #include "r8192E_hwimg.h" @@ -859,7 +858,7 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, RT_TRACE(COMP_TRACE, "====>%s()====stage:%d, step:%d, channel:%d\n", __func__, *stage, *step, channel); - if (!IsLegalChannel(priv->rtllib, channel)) { + if (!rtllib_legal_channel(priv->rtllib, channel)) { RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel); return true; diff --git a/drivers/staging/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 7318f8857af..7318f8857af 100644 --- a/drivers/staging/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h diff --git a/drivers/staging/rtl8192e/r8192E_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h index 7899dd538dc..7899dd538dc 100644 --- a/drivers/staging/rtl8192e/r8192E_phyreg.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h diff --git a/drivers/staging/rtl8192e/r819xE_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h index d5de279f664..d5de279f664 100644 --- a/drivers/staging/rtl8192e/r819xE_phyreg.h +++ b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h diff --git a/drivers/staging/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index baf3b6342e4..baf3b6342e4 100644 --- a/drivers/staging/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c diff --git a/drivers/staging/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h index fa607f98b17..fa607f98b17 100644 --- a/drivers/staging/rtl8192e/rtl_cam.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h diff --git a/drivers/staging/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 5ad96649f40..71adb6b3344 100644 --- a/drivers/staging/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -53,9 +53,7 @@ #include "rtl_wx.h" #include "rtl_dm.h" -#ifdef CONFIG_PM_RTL #include "rtl_pm.h" -#endif int hwwep = 1; static int channels = 0x3fff; @@ -581,7 +579,7 @@ static void rtl8192_update_beacon(void *data) struct rtllib_network *net = &ieee->current_network; if (ieee->pHTInfo->bCurrentHTSupport) - HTUpdateSelfAndPeerSetting(ieee, net); + HT_update_self_and_peer_setting(ieee, net); ieee->pHTInfo->bCurrentRT2RTLongSlotTime = net->bssht.bdRT2RTLongSlotTime; ieee->pHTInfo->RT2RT_HT_Mode = net->bssht.RT2RT_HT_Mode; @@ -1289,7 +1287,7 @@ static short rtl8192_get_channel_map(struct net_device *dev) priv->ChannelPlan = COUNTRY_CODE_FCC; } RT_TRACE(COMP_INIT, "Channel plan is %d\n", priv->ChannelPlan); - Dot11d_Init(priv->rtllib); + dot11d_init(priv->rtllib); Dot11d_Channelmap(priv->ChannelPlan, priv->rtllib); for (i = 1; i <= 11; i++) (priv->rtllib->active_channel_map)[i] = 1; @@ -1305,7 +1303,6 @@ static short rtl8192_init(struct net_device *dev) memset(&(priv->stats), 0, sizeof(struct rt_stats)); - rtl8192_dbgp_flag_init(dev); rtl8192_init_priv_handler(dev); rtl8192_init_priv_constant(dev); rtl8192_init_priv_variable(dev); @@ -2839,7 +2836,6 @@ done: /**************************************************************************** ---------------------------- PCI_STUFF--------------------------- *****************************************************************************/ -#ifdef HAVE_NET_DEVICE_OPS static const struct net_device_ops rtl8192_netdev_ops = { .ndo_open = rtl8192_open, .ndo_stop = rtl8192_close, @@ -2851,7 +2847,6 @@ static const struct net_device_ops rtl8192_netdev_ops = { .ndo_change_mtu = eth_change_mtu, .ndo_start_xmit = rtllib_xmit, }; -#endif static int __devinit rtl8192_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -2938,17 +2933,7 @@ static int __devinit rtl8192_pci_probe(struct pci_dev *pdev, dev->irq = pdev->irq; priv->irq = 0; -#ifdef HAVE_NET_DEVICE_OPS dev->netdev_ops = &rtl8192_netdev_ops; -#else - dev->open = rtl8192_open; - dev->stop = rtl8192_close; - dev->tx_timeout = rtl8192_tx_timeout; - dev->do_ioctl = rtl8192_ioctl; - dev->set_multicast_list = r8192_set_multicast; - dev->set_mac_address = r8192_set_mac_adr; - dev->hard_start_xmit = rtllib_xmit; -#endif dev->wireless_handlers = (struct iw_handler_def *) &r8192_wx_handlers_def; @@ -2974,10 +2959,7 @@ static int __devinit rtl8192_pci_probe(struct pci_dev *pdev, register_netdev(dev); RT_TRACE(COMP_INIT, "dev name: %s\n", dev->name); - err = rtl_debug_module_init(priv, dev->name); - if (err) - RT_TRACE(COMP_DBG, "failed to create debugfs files. Ignoring " - "error: %d\n", err); + rtl8192_proc_init_one(dev); if (priv->polling_timer_on == 0) @@ -3015,7 +2997,6 @@ static void __devexit rtl8192_pci_disconnect(struct pci_dev *pdev) del_timer_sync(&priv->gpio_polling_timer); cancel_delayed_work(&priv->gpio_change_rf_wq); priv->polling_timer_on = 0; - rtl_debug_module_remove(priv); rtl8192_proc_remove_one(dev); rtl8192_down(dev, true); deinit_hal_dm(dev); @@ -3103,43 +3084,9 @@ bool NicIFDisableNIC(struct net_device *dev) static int __init rtl8192_pci_module_init(void) { - int ret; - int error; - - ret = rtllib_init(); - if (ret) { - printk(KERN_ERR "rtllib_init() failed %d\n", ret); - return ret; - } - ret = rtllib_crypto_init(); - if (ret) { - printk(KERN_ERR "rtllib_crypto_init() failed %d\n", ret); - return ret; - } - ret = rtllib_crypto_tkip_init(); - if (ret) { - printk(KERN_ERR "rtllib_crypto_tkip_init() failed %d\n", ret); - return ret; - } - ret = rtllib_crypto_ccmp_init(); - if (ret) { - printk(KERN_ERR "rtllib_crypto_ccmp_init() failed %d\n", ret); - return ret; - } - ret = rtllib_crypto_wep_init(); - if (ret) { - printk(KERN_ERR "rtllib_crypto_wep_init() failed %d\n", ret); - return ret; - } printk(KERN_INFO "\nLinux kernel driver for RTL8192E WLAN cards\n"); printk(KERN_INFO "Copyright (c) 2007-2008, Realsil Wlan Driver\n"); - error = rtl_create_debugfs_root(); - if (error) { - RT_TRACE(COMP_DBG, "Create debugfs root fail: %d\n", error); - goto err_out; - } - rtl8192_proc_module_init(); if (0 != pci_register_driver(&rtl8192_pci_driver)) { DMESG("No device found"); @@ -3147,9 +3094,6 @@ static int __init rtl8192_pci_module_init(void) return -ENODEV; } return 0; -err_out: - return error; - } static void __exit rtl8192_pci_module_exit(void) @@ -3158,12 +3102,6 @@ static void __exit rtl8192_pci_module_exit(void) RT_TRACE(COMP_DOWN, "Exiting"); rtl8192_proc_module_remove(); - rtl_remove_debugfs_root(); - rtllib_crypto_tkip_exit(); - rtllib_crypto_ccmp_exit(); - rtllib_crypto_wep_exit(); - rtllib_crypto_deinit(); - rtllib_exit(); } void check_rfctrl_gpio_timer(unsigned long data) diff --git a/drivers/staging/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index f9af5153d9c..2a2519cc284 100644 --- a/drivers/staging/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -44,11 +44,14 @@ #include <linux/proc_fs.h> #include <linux/if_arp.h> #include <linux/random.h> -#include <linux/version.h> #include <linux/io.h> -#include "rtllib.h" -#include "dot11d.h" +/* Need this defined before including local include files */ +#define DRV_NAME "rtl819xE" + +#include "../rtllib.h" + +#include "../dot11d.h" #include "r8192E_firmware.h" #include "r8192E_hw.h" @@ -56,7 +59,6 @@ #include "r8190P_def.h" #include "r8192E_dev.h" -#include "rtl_debug.h" #include "rtl_eeprom.h" #include "rtl_ps.h" #include "rtl_pci.h" @@ -67,8 +69,6 @@ #define DRV_AUTHOR "<wlanfae@realtek.com>" #define DRV_VERSION "0014.0401.2010" -#define DRV_NAME "rtl819xE" - #define IS_HARDWARE_TYPE_819xP(_priv) \ ((((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8190P) || \ (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192E)) @@ -215,41 +215,6 @@ enum RTL819x_PHY_PARAM { RTL819X_EFUSE_MAP = 19, }; -enum RTL_DEBUG { - COMP_TRACE = BIT0, - COMP_DBG = BIT1, - COMP_INIT = BIT2, - COMP_RECV = BIT3, - COMP_SEND = BIT4, - COMP_CMD = BIT5, - COMP_POWER = BIT6, - COMP_EPROM = BIT7, - COMP_SWBW = BIT8, - COMP_SEC = BIT9, - COMP_LPS = BIT10, - COMP_QOS = BIT11, - COMP_RATE = BIT12, - COMP_RXDESC = BIT13, - COMP_PHY = BIT14, - COMP_DIG = BIT15, - COMP_TXAGC = BIT16, - COMP_HALDM = BIT17, - COMP_POWER_TRACKING = BIT18, - COMP_CH = BIT19, - COMP_RF = BIT20, - COMP_FIRMWARE = BIT21, - COMP_HT = BIT22, - COMP_RESET = BIT23, - COMP_CMDPKT = BIT24, - COMP_SCAN = BIT25, - COMP_PS = BIT26, - COMP_DOWN = BIT27, - COMP_INTR = BIT28, - COMP_LED = BIT29, - COMP_MLME = BIT30, - COMP_ERR = BIT31 -}; - enum nic_t { NIC_UNKNOWN = 0, NIC_8192E = 1, @@ -1121,4 +1086,10 @@ void ActUpdateChannelAccessSetting(struct net_device *dev, enum wireless_mode WirelessMode, struct channel_access_setting *ChnlAccessSetting); +/* proc stuff from rtl_debug.c */ +void rtl8192_proc_init_one(struct net_device *dev); +void rtl8192_proc_remove_one(struct net_device *dev); +void rtl8192_proc_module_init(void); +void rtl8192_proc_module_remove(void); + #endif diff --git a/drivers/staging/rtl8192e/rtl_crypto.h b/drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h index ee57c0f4fa6..ee57c0f4fa6 100644 --- a/drivers/staging/rtl8192e/rtl_crypto.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h diff --git a/drivers/staging/rtl8192e/rtl_debug.c b/drivers/staging/rtl8192e/rtl8192e/rtl_debug.c index 22bc2dd6e43..c19b14cd6f7 100644 --- a/drivers/staging/rtl8192e/rtl_debug.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_debug.c @@ -22,91 +22,12 @@ * Contact Information: * wlanfae <wlanfae@realtek.com> ******************************************************************************/ -#include "rtl_debug.h" #include "rtl_core.h" #include "r8192E_phy.h" #include "r8192E_phyreg.h" #include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */ #include "r8192E_cmdpkt.h" -u32 rt_global_debug_component = \ - COMP_ERR ; - -/*------------------Declare variable-----------------------*/ -u32 DBGP_Type[DBGP_TYPE_MAX]; - -/*----------------------------------------------------------------------------- - * Function: DBGP_Flag_Init - * - * Overview: Refresh all debug print control flag content to zero. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 10/20/2006 MHC Create Version 0. - * - *---------------------------------------------------------------------------*/ -void rtl8192_dbgp_flag_init(struct net_device *dev) -{ - u8 i; - - for (i = 0; i < DBGP_TYPE_MAX; i++) - DBGP_Type[i] = 0; - - -} /* DBGP_Flag_Init */ - -/* this is only for debugging */ -void print_buffer(u32 *buffer, int len) -{ - int i; - u8 *buf = (u8 *)buffer; - - printk(KERN_INFO "ASCII BUFFER DUMP (len: %x):\n", len); - - for (i = 0; i < len; i++) - printk(KERN_INFO "%c", buf[i]); - - printk(KERN_INFO "\nBINARY BUFFER DUMP (len: %x):\n", len); - - for (i = 0; i < len; i++) - printk(KERN_INFO "%x", buf[i]); - - printk(KERN_INFO "\n"); -} - -/* this is only for debug */ -void dump_eprom(struct net_device *dev) -{ - int i; - - for (i = 0; i < 0xff; i++) - RT_TRACE(COMP_INIT, "EEPROM addr %x : %x", i, - eprom_read(dev, i)); -} - -/* this is only for debug */ -void rtl8192_dump_reg(struct net_device *dev) -{ - int i; - int n; - int max = 0x5ff; - - RT_TRACE(COMP_INIT, "Dumping NIC register map"); - - for (n = 0; n <= max; ) { - printk(KERN_INFO "\nD: %2x> ", n); - for (i = 0; i < 16 && n <= max; i++, n++) - printk(KERN_INFO "%2x ", read_nic_byte(dev, n)); - } - printk(KERN_INFO "\n"); -} - /**************************************************************************** -----------------------------PROCFS STUFF------------------------- *****************************************************************************/ diff --git a/drivers/staging/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index a7fa9aad6f2..a7fa9aad6f2 100644 --- a/drivers/staging/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c diff --git a/drivers/staging/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index ab44a9a6927..ab44a9a6927 100644 --- a/drivers/staging/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h diff --git a/drivers/staging/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c index c1ccff4a832..c1ccff4a832 100644 --- a/drivers/staging/rtl8192e/rtl_eeprom.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c diff --git a/drivers/staging/rtl8192e/rtl_eeprom.h b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h index 9452e1683a7..9452e1683a7 100644 --- a/drivers/staging/rtl8192e/rtl_eeprom.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h diff --git a/drivers/staging/rtl8192e/rtl_ethtool.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c index 36452fb7cef..36452fb7cef 100644 --- a/drivers/staging/rtl8192e/rtl_ethtool.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c diff --git a/drivers/staging/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c index ddadcc3e4e7..ddadcc3e4e7 100644 --- a/drivers/staging/rtl8192e/rtl_pci.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c diff --git a/drivers/staging/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h index 7ea5a47dfd2..28c7da677a8 100644 --- a/drivers/staging/rtl8192e/rtl_pci.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h @@ -27,7 +27,6 @@ #include <linux/types.h> #include <linux/pci.h> -#include "rtllib.h" static inline void NdisRawWritePortUlong(u32 port, u32 val) { diff --git a/drivers/staging/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index 92e2fde7f5f..8e1a5d55dce 100644 --- a/drivers/staging/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -17,7 +17,6 @@ * wlanfae <wlanfae@realtek.com> ******************************************************************************/ -#ifdef CONFIG_PM_RTL #include "rtl_core.h" #include "r8192E_hw.h" #include "r8190P_rtl8256.h" @@ -133,4 +132,3 @@ int rtl8192E_enable_wake(struct pci_dev *dev, pm_message_t state, int enable) return -EAGAIN; } -#endif diff --git a/drivers/staging/rtl8192e/rtl_pm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h index 4d7f4067cc7..e5299fc3b34 100644 --- a/drivers/staging/rtl8192e/rtl_pm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h @@ -17,8 +17,6 @@ * wlanfae <wlanfae@realtek.com> ******************************************************************************/ -#ifdef CONFIG_PM_RTL - #ifndef R8192E_PM_H #define R8192E_PM_H @@ -31,5 +29,3 @@ int rtl8192E_resume(struct pci_dev *dev); int rtl8192E_enable_wake(struct pci_dev *dev, pm_message_t state, int enable); #endif - -#endif diff --git a/drivers/staging/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index c9a7c563b68..c9a7c563b68 100644 --- a/drivers/staging/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c diff --git a/drivers/staging/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index a9c2d799c08..df79d6c4ca0 100644 --- a/drivers/staging/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -26,7 +26,7 @@ #define _RTL_PS_H #include <linux/types.h> -#include "rtllib.h" + struct net_device; #define RT_CHECK_FOR_HANG_PERIOD 2 diff --git a/drivers/staging/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 93b1edbe6ba..4e93669210a 100644 --- a/drivers/staging/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -19,7 +19,6 @@ #include <linux/string.h> #include "rtl_core.h" -#include "dot11d.h" #define RATE_COUNT 12 static u32 rtl8192_rates[] = { @@ -803,7 +802,7 @@ static int r8192_wx_set_enc(struct net_device *dev, switch (wrqu->encoding.flags & IW_ENCODE_INDEX) { case 0: - key_idx = ieee->tx_keyidx; + key_idx = ieee->crypt_info.tx_keyidx; break; case 1: key_idx = 0; diff --git a/drivers/staging/rtl8192e/rtl_wx.h b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h index 6a51a25ec87..6a51a25ec87 100644 --- a/drivers/staging/rtl8192e/rtl_wx.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c index 8b9d85c48be..32fbbc9d0d9 100644 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -18,7 +18,6 @@ ******************************************************************************/ #include "rtllib.h" #include "rtl819x_BA.h" -#include "rtl_core.h" static void ActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA, u16 Time) diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c index b1c0c566882..8b7412980eb 100644 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -943,8 +943,8 @@ void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee, } } -void HTUpdateSelfAndPeerSetting(struct rtllib_device *ieee, - struct rtllib_network *pNetwork) +void HT_update_self_and_peer_setting(struct rtllib_device *ieee, + struct rtllib_network *pNetwork) { struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; struct ht_info_ele *pPeerHTInfo = @@ -955,6 +955,7 @@ void HTUpdateSelfAndPeerSetting(struct rtllib_device *ieee, pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; } } +EXPORT_SYMBOL(HT_update_self_and_peer_setting); void HTUseDefaultSetting(struct rtllib_device *ieee) { diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c index 09a602f7432..711a096be7a 100644 --- a/drivers/staging/rtl8192e/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c @@ -497,6 +497,7 @@ void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr) } } } +EXPORT_SYMBOL(RemovePeerTS); void RemoveAllTS(struct rtllib_device *ieee) { diff --git a/drivers/staging/rtl8192e/rtl_debug.h b/drivers/staging/rtl8192e/rtl_debug.h deleted file mode 100644 index 50fb9a9b828..00000000000 --- a/drivers/staging/rtl8192e/rtl_debug.h +++ /dev/null @@ -1,299 +0,0 @@ -/****************************************************************************** - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al. - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * wlanfae <wlanfae@realtek.com> -******************************************************************************/ -#ifndef _RTL_DEBUG_H -#define _RTL_DEBUG_H -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/debugfs.h> - -struct r8192_priv; -struct _tx_desc_8192se; -struct _TX_DESC_8192CE; -struct net_device; - -#define DBG_LOUD 4 - -#define RT_ASSERT(_Exp, Fmt) \ - if (!(_Exp)) { \ - printk("Rtl819x: "); \ - printk Fmt; \ - } - -enum dbgp_flag { - FQoS = 0, - FTX = 1, - FRX = 2, - FSEC = 3, - FMGNT = 4, - FMLME = 5, - FRESOURCE = 6, - FBEACON = 7, - FISR = 8, - FPHY = 9, - FMP = 10, - FEEPROM = 11, - FPWR = 12, - FDM = 13, - FDBGCtrl = 14, - FC2H = 15, - FBT = 16, - FINIT = 17, - FIOCTL = 18, - DBGP_TYPE_MAX -}; - -#define QoS_INIT BIT0 -#define QoS_VISTA BIT1 - -#define TX_DESC BIT0 -#define TX_DESC_TID BIT1 - -#define RX_DATA BIT0 -#define RX_PHY_STS BIT1 -#define RX_PHY_SS BIT2 -#define RX_PHY_SQ BIT3 -#define RX_PHY_ASTS BIT4 -#define RX_ERR_LEN BIT5 -#define RX_DEFRAG BIT6 -#define RX_ERR_RATE BIT7 - - - -#define MEDIA_STS BIT0 -#define LINK_STS BIT1 - -#define OS_CHK BIT0 - -#define BCN_SHOW BIT0 -#define BCN_PEER BIT1 - -#define ISR_CHK BIT0 - -#define PHY_BBR BIT0 -#define PHY_BBW BIT1 -#define PHY_RFR BIT2 -#define PHY_RFW BIT3 -#define PHY_MACR BIT4 -#define PHY_MACW BIT5 -#define PHY_ALLR BIT6 -#define PHY_ALLW BIT7 -#define PHY_TXPWR BIT8 -#define PHY_PWRDIFF BIT9 - -#define MP_RX BIT0 -#define MP_SWICH_CH BIT1 - -#define EEPROM_W BIT0 -#define EFUSE_PG BIT1 -#define EFUSE_READ_ALL BIT2 - -#define LPS BIT0 -#define IPS BIT1 -#define PWRSW BIT2 -#define PWRHW BIT3 -#define PWRHAL BIT4 - -#define WA_IOT BIT0 -#define DM_PWDB BIT1 -#define DM_Monitor BIT2 -#define DM_DIG BIT3 -#define DM_EDCA_Turbo BIT4 - -#define DbgCtrl_Trace BIT0 -#define DbgCtrl_InbandNoise BIT1 - -#define BT_TRACE BIT0 -#define BT_RFPoll BIT1 - -#define C2H_Summary BIT0 -#define C2H_PacketData BIT1 -#define C2H_ContentData BIT2 -#define BT_TRACE BIT0 -#define BT_RFPoll BIT1 - -#define INIT_EEPROM BIT0 -#define INIT_TxPower BIT1 -#define INIT_IQK BIT2 -#define INIT_RF BIT3 - -#define IOCTL_TRACE BIT0 -#define IOCTL_BT_EVENT BIT1 -#define IOCTL_BT_EVENT_DETAIL BIT2 -#define IOCTL_BT_TX_ACLDATA BIT3 -#define IOCTL_BT_TX_ACLDATA_DETAIL BIT4 -#define IOCTL_BT_RX_ACLDATA BIT5 -#define IOCTL_BT_RX_ACLDATA_DETAIL BIT6 -#define IOCTL_BT_HCICMD BIT7 -#define IOCTL_BT_HCICMD_DETAIL BIT8 -#define IOCTL_IRP BIT9 -#define IOCTL_IRP_DETAIL BIT10 -#define IOCTL_CALLBACK_FUN BIT11 -#define IOCTL_STATE BIT12 -#define IOCTL_BT_TP BIT13 -#define IOCTL_BT_LOGO BIT14 - -/* 2007/07/13 MH ------For DeBuG Print modeue------*/ -/*------------------------------Define structure----------------------------*/ - - -/*------------------------Export Marco Definition---------------------------*/ -#define DEBUG_PRINT 1 - -#if (DEBUG_PRINT == 1) -#define RTPRINT(dbgtype, dbgflag, printstr) \ -{ \ - if (DBGP_Type[dbgtype] & dbgflag) { \ - printk printstr; \ - } \ -} - -#define RTPRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr) \ -{ \ - if (DBGP_Type[dbgtype] & dbgflag) { \ - int __i; \ - u8 *ptr = (u8 *)_Ptr; \ - printk printstr; \ - printk(" "); \ - for (__i = 0; __i < 6; __i++) \ - printk("%02X%s", ptr[__i], \ - (__i == 5) ? "" : "-"); \ - printk("\n"); \ - } \ -} - -#define RTPRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\ -{ \ - if (DBGP_Type[dbgtype] & dbgflag) { \ - int __i; \ - u8 *ptr = (u8 *)_HexData; \ - printk(_TitleString); \ - for (__i = 0; __i < (int)_HexDataLen; __i++) { \ - printk("%02X%s", ptr[__i], (((__i + 1) \ - % 4) == 0) ? " " : " "); \ - if (((__i + 1) % 16) == 0) \ - printk("\n"); \ - } \ - printk("\n"); \ - } \ -} -#else -#define RTPRINT(dbgtype, dbgflag, printstr) -#define RTPRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr) -#define RTPRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen) -#endif - -extern u32 DBGP_Type[DBGP_TYPE_MAX]; - -#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) \ -do {\ - if (((_Comp) & rt_global_debug_component) && \ - (_Level <= rt_global_debug_component)) { \ - int __i; \ - u8* ptr = (u8 *)_HexData; \ - printk(KERN_INFO "Rtl819x: "); \ - printk(_TitleString); \ - for (__i = 0; __i < (int)_HexDataLen; __i++) { \ - printk("%02X%s", ptr[__i], (((__i + 1) % \ - 4) == 0) ? " " : " "); \ - if (((__i + 1) % 16) == 0) \ - printk("\n"); \ - } \ - printk("\n"); \ - } \ -} while (0); - -#define DMESG(x, a...) -#define DMESGW(x, a...) -#define DMESGE(x, a...) -extern u32 rt_global_debug_component; -#define RT_TRACE(component, x, args...) \ -do { \ - if (rt_global_debug_component & component) \ - printk(KERN_DEBUG DRV_NAME ":" x "\n" , \ - ##args);\ -} while (0); - -#define assert(expr) \ - if (!(expr)) { \ - printk(KERN_INFO "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr, __FILE__, __func__, __LINE__); \ - } -#define RT_DEBUG_DATA(level, data, datalen) \ - do { \ - if ((rt_global_debug_component & (level)) == (level)) {\ - int _i; \ - u8 *_pdata = (u8 *)data; \ - printk(KERN_DEBUG DRV_NAME ": %s()\n", __func__); \ - for (_i = 0; _i < (int)(datalen); _i++) { \ - printk(KERN_INFO "%2x ", _pdata[_i]); \ - if ((_i+1) % 16 == 0) \ - printk("\n"); \ - } \ - printk(KERN_INFO "\n"); \ - } \ - } while (0) - -struct rtl_fs_debug { - const char *name; - struct dentry *dir_drv; - struct dentry *debug_register; - u32 hw_type; - u32 hw_offset; - bool hw_holding; -}; - -void print_buffer(u32 *buffer, int len); -void dump_eprom(struct net_device *dev); -void rtl8192_dump_reg(struct net_device *dev); - -/* debugfs stuff */ -static inline int rtl_debug_module_init(struct r8192_priv *priv, - const char *name) -{ - return 0; -} - -static inline void rtl_debug_module_remove(struct r8192_priv *priv) -{ -} - -static inline int rtl_create_debugfs_root(void) -{ - return 0; -} - -static inline void rtl_remove_debugfs_root(void) -{ -} - -/* proc stuff */ -void rtl8192_proc_init_one(struct net_device *dev); -void rtl8192_proc_remove_one(struct net_device *dev); -void rtl8192_proc_module_init(void); -void rtl8192_proc_module_remove(void); -void rtl8192_dbgp_flag_init(struct net_device *dev); - -#endif diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index de25975ccee..e26aec86a5c 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -25,7 +25,6 @@ #define RTLLIB_H #include <linux/if_ether.h> /* ETH_ALEN */ #include <linux/kernel.h> /* ARRAY_SIZE */ -#include <linux/version.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/jiffies.h> @@ -36,12 +35,14 @@ #include <linux/delay.h> #include <linux/wireless.h> +#include "rtllib_debug.h" #include "rtl819x_HT.h" #include "rtl819x_BA.h" #include "rtl819x_TS.h" #include <linux/netdevice.h> #include <linux/if_arp.h> /* ARPHRD_ETHER */ +#include <net/lib80211.h> #define MAX_PRECMD_CNT 16 #define MAX_RFDEPENDCMD_CNT 16 @@ -870,69 +871,6 @@ enum _REG_PREAMBLE_MODE { #define WLAN_ERP_USE_PROTECTION (1<<1) #define WLAN_ERP_BARKER_PREAMBLE (1<<2) -/* Status codes */ -enum rtllib_statuscode { - WLAN_STATUS_SUCCESS = 0, - WLAN_STATUS_UNSPECIFIED_FAILURE = 1, - WLAN_STATUS_CAPS_UNSUPPORTED = 10, - WLAN_STATUS_REASSOC_NO_ASSOC = 11, - WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, - WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, - WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, - WLAN_STATUS_CHALLENGE_FAIL = 15, - WLAN_STATUS_AUTH_TIMEOUT = 16, - WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, - WLAN_STATUS_ASSOC_DENIED_RATES = 18, - /* 802.11b */ - WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, - WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, - WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, - /* 802.11h */ - WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, - WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, - WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, - /* 802.11g */ - WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, - WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, - /* 802.11i */ - WLAN_STATUS_INVALID_IE = 40, - WLAN_STATUS_INVALID_GROUP_CIPHER = 41, - WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, - WLAN_STATUS_INVALID_AKMP = 43, - WLAN_STATUS_UNSUPP_RSN_VERSION = 44, - WLAN_STATUS_INVALID_RSN_IE_CAP = 45, - WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, -}; - -/* Reason codes */ -enum rtllib_reasoncode { - WLAN_REASON_UNSPECIFIED = 1, - WLAN_REASON_PREV_AUTH_NOT_VALID = 2, - WLAN_REASON_DEAUTH_LEAVING = 3, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, - WLAN_REASON_DISASSOC_AP_BUSY = 5, - WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, - WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, - WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, - /* 802.11h */ - WLAN_REASON_DISASSOC_BAD_POWER = 10, - WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, - /* 802.11i */ - WLAN_REASON_INVALID_IE = 13, - WLAN_REASON_MIC_FAILURE = 14, - WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, - WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, - WLAN_REASON_IE_DIFFERENT = 17, - WLAN_REASON_INVALID_GROUP_CIPHER = 18, - WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, - WLAN_REASON_INVALID_AKMP = 20, - WLAN_REASON_UNSUPP_RSN_VERSION = 21, - WLAN_REASON_INVALID_RSN_IE_CAP = 22, - WLAN_REASON_IEEE8021X_FAILED = 23, - WLAN_REASON_CIPHER_SUITE_REJECTED = 24, -}; - #define RTLLIB_STATMASK_SIGNAL (1<<0) #define RTLLIB_STATMASK_RSSI (1<<1) #define RTLLIB_STATMASK_NOISE (1<<2) @@ -1122,8 +1060,6 @@ struct rtllib_stats { struct rtllib_device; -#include "rtllib_crypt.h" - #define SEC_KEY_1 (1<<0) #define SEC_KEY_2 (1<<1) #define SEC_KEY_3 (1<<2) @@ -1146,7 +1082,6 @@ struct rtllib_device; #define SEC_ALG_TKIP 2 #define SEC_ALG_CCMP 4 -#define WEP_KEYS 4 #define WEP_KEY_LEN 13 #define SCM_KEY_LEN 32 #define SCM_TEMPORAL_KEY_LENGTH 16 @@ -1158,8 +1093,8 @@ struct rtllib_security { auth_algo:4, unicast_uses_group:1, encrypt:1; - u8 key_sizes[WEP_KEYS]; - u8 keys[WEP_KEYS][SCM_KEY_LEN]; + u8 key_sizes[NUM_WEP_KEYS]; + u8 keys[NUM_WEP_KEYS][SCM_KEY_LEN]; u8 level; u16 flags; } __packed; @@ -2251,14 +2186,10 @@ struct rtllib_device { u8 ap_mac_addr[6]; u16 pairwise_key_type; u16 group_key_type; - struct list_head crypt_deinit_list; - struct rtllib_crypt_data *crypt[WEP_KEYS]; - int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ - struct sw_cam_table swcamtable[TOTAL_CAM_ENTRY]; - struct timer_list crypt_deinit_timer; - int crypt_quiesced; + struct lib80211_crypt_info crypt_info; + struct sw_cam_table swcamtable[TOTAL_CAM_ENTRY]; int bcrx_sta_key; /* use individual keys to override default keys even * with RX of broad/multicast frames */ @@ -2774,7 +2705,7 @@ extern void rtllib_rx_mgt(struct rtllib_device *ieee, struct rtllib_rx_stats *stats); extern void rtllib_rx_probe_rq(struct rtllib_device *ieee, struct sk_buff *skb); -extern int IsLegalChannel(struct rtllib_device *rtllib, u8 channel); +extern int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel); /* rtllib_wx.c */ extern int rtllib_wx_get_scan(struct rtllib_device *ieee, @@ -2804,7 +2735,7 @@ extern int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len); /* rtllib_softmac.c */ extern short rtllib_is_54g(struct rtllib_network *net); -extern short rtllib_is_shortslot(struct rtllib_network net); +extern short rtllib_is_shortslot(const struct rtllib_network *net); extern int rtllib_rx_frame_softmac(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_stats, u16 type, @@ -2971,8 +2902,8 @@ extern void HTInitializeHTInfo(struct rtllib_device *ieee); extern void HTInitializeBssDesc(struct bss_ht *pBssHT); extern void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee, struct rtllib_network *pNetwork); -extern void HTUpdateSelfAndPeerSetting(struct rtllib_device *ieee, - struct rtllib_network *pNetwork); +extern void HT_update_self_and_peer_setting(struct rtllib_device *ieee, + struct rtllib_network *pNetwork); extern u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet, u8 *pMCSFilter); extern u8 MCS_FILTER_ALL[]; @@ -3052,21 +2983,6 @@ static inline const char *escape_essid(const char *essid, u8 essid_len) (HTMcsToDataRate(_ieee, (u8)_MGN_RATE))) /* fun with the built-in rtllib stack... */ -int rtllib_init(void); -void rtllib_exit(void); -int rtllib_crypto_init(void); -void rtllib_crypto_deinit(void); -int rtllib_crypto_tkip_init(void); -void rtllib_crypto_tkip_exit(void); -int rtllib_crypto_ccmp_init(void); -void rtllib_crypto_ccmp_exit(void); -int rtllib_crypto_wep_init(void); -void rtllib_crypto_wep_exit(void); - -void rtllib_MgntDisconnectIBSS(struct rtllib_device *rtllib); -void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib, u8 *asSta, - u8 asRsn); -void rtllib_MgntDisconnectAP(struct rtllib_device *rtllib, u8 asRsn); bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn); @@ -3133,12 +3049,5 @@ extern void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p); #define MUTEX_LOCK_PRIV(pmutex) mutex_lock(pmutex) #define MUTEX_UNLOCK_PRIV(pmutex) mutex_unlock(pmutex) #endif -static inline void dump_buf(u8 *buf, u32 len) -{ - u32 i; - printk(KERN_INFO "-----------------Len %d----------------\n", len); - for (i = 0; i < len; i++) - printk("%2.2x-", *(buf+i)); - printk("\n"); -} + #endif /* RTLLIB_H */ diff --git a/drivers/staging/rtl8192e/rtllib_crypt.c b/drivers/staging/rtl8192e/rtllib_crypt.c index acda37b8184..86152d0e6b5 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt.c +++ b/drivers/staging/rtl8192e/rtllib_crypt.c @@ -11,7 +11,6 @@ * */ -#include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -22,7 +21,7 @@ struct rtllib_crypto_alg { struct list_head list; - struct rtllib_crypto_ops *ops; + struct lib80211_crypto_ops *ops; }; @@ -33,15 +32,15 @@ struct rtllib_crypto { static struct rtllib_crypto *hcrypt; -void rtllib_crypt_deinit_entries(struct rtllib_device *ieee, +void rtllib_crypt_deinit_entries(struct lib80211_crypt_info *info, int force) { struct list_head *ptr, *n; - struct rtllib_crypt_data *entry; + struct lib80211_crypt_data *entry; - for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; - ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct rtllib_crypt_data, list); + for (ptr = info->crypt_deinit_list.next, n = ptr->next; + ptr != &info->crypt_deinit_list; ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct lib80211_crypt_data, list); if (atomic_read(&entry->refcnt) != 0 && !force) continue; @@ -53,28 +52,30 @@ void rtllib_crypt_deinit_entries(struct rtllib_device *ieee, kfree(entry); } } +EXPORT_SYMBOL(rtllib_crypt_deinit_entries); void rtllib_crypt_deinit_handler(unsigned long data) { - struct rtllib_device *ieee = (struct rtllib_device *)data; + struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data; unsigned long flags; - spin_lock_irqsave(&ieee->lock, flags); - rtllib_crypt_deinit_entries(ieee, 0); - if (!list_empty(&ieee->crypt_deinit_list)) { + spin_lock_irqsave(info->lock, flags); + rtllib_crypt_deinit_entries(info, 0); + if (!list_empty(&info->crypt_deinit_list)) { printk(KERN_DEBUG "%s: entries remaining in delayed crypt " - "deletion list\n", ieee->dev->name); - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); + "deletion list\n", info->name); + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); } - spin_unlock_irqrestore(&ieee->lock, flags); + spin_unlock_irqrestore(info->lock, flags); } +EXPORT_SYMBOL(rtllib_crypt_deinit_handler); -void rtllib_crypt_delayed_deinit(struct rtllib_device *ieee, - struct rtllib_crypt_data **crypt) +void rtllib_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt) { - struct rtllib_crypt_data *tmp; + struct lib80211_crypt_data *tmp; unsigned long flags; if (*crypt == NULL) @@ -87,16 +88,17 @@ void rtllib_crypt_delayed_deinit(struct rtllib_device *ieee, * decrypt operations. Use a list of delayed deinits to avoid needing * locking. */ - spin_lock_irqsave(&ieee->lock, flags); - list_add(&tmp->list, &ieee->crypt_deinit_list); - if (!timer_pending(&ieee->crypt_deinit_timer)) { - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); + spin_lock_irqsave(info->lock, flags); + list_add(&tmp->list, &info->crypt_deinit_list); + if (!timer_pending(&info->crypt_deinit_timer)) { + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); } - spin_unlock_irqrestore(&ieee->lock, flags); + spin_unlock_irqrestore(info->lock, flags); } +EXPORT_SYMBOL(rtllib_crypt_delayed_deinit); -int rtllib_register_crypto_ops(struct rtllib_crypto_ops *ops) +int rtllib_register_crypto_ops(struct lib80211_crypto_ops *ops) { unsigned long flags; struct rtllib_crypto_alg *alg; @@ -104,11 +106,10 @@ int rtllib_register_crypto_ops(struct rtllib_crypto_ops *ops) if (hcrypt == NULL) return -1; - alg = kmalloc(sizeof(*alg), GFP_KERNEL); + alg = kzalloc(sizeof(*alg), GFP_KERNEL); if (alg == NULL) return -ENOMEM; - memset(alg, 0, sizeof(*alg)); alg->ops = ops; spin_lock_irqsave(&hcrypt->lock, flags); @@ -120,8 +121,9 @@ int rtllib_register_crypto_ops(struct rtllib_crypto_ops *ops) return 0; } +EXPORT_SYMBOL(rtllib_register_crypto_ops); -int rtllib_unregister_crypto_ops(struct rtllib_crypto_ops *ops) +int rtllib_unregister_crypto_ops(struct lib80211_crypto_ops *ops) { unsigned long flags; struct list_head *ptr; @@ -150,9 +152,10 @@ int rtllib_unregister_crypto_ops(struct rtllib_crypto_ops *ops) return del_alg ? 0 : -1; } +EXPORT_SYMBOL(rtllib_unregister_crypto_ops); -struct rtllib_crypto_ops *rtllib_get_crypto_ops(const char *name) +struct lib80211_crypto_ops *rtllib_get_crypto_ops(const char *name) { unsigned long flags; struct list_head *ptr; @@ -177,12 +180,13 @@ struct rtllib_crypto_ops *rtllib_get_crypto_ops(const char *name) else return NULL; } +EXPORT_SYMBOL(rtllib_get_crypto_ops); static void * rtllib_crypt_null_init(int keyidx) { return (void *) 1; } static void rtllib_crypt_null_deinit(void *priv) {} -static struct rtllib_crypto_ops rtllib_crypt_null = { +static struct lib80211_crypto_ops rtllib_crypt_null = { .name = "NULL", .init = rtllib_crypt_null_init, .deinit = rtllib_crypt_null_deinit, @@ -192,8 +196,10 @@ static struct rtllib_crypto_ops rtllib_crypt_null = { .decrypt_msdu = NULL, .set_key = NULL, .get_key = NULL, - .extra_prefix_len = 0, - .extra_postfix_len = 0, + .extra_mpdu_prefix_len = 0, + .extra_mpdu_postfix_len = 0, + .extra_msdu_prefix_len = 0, + .extra_msdu_postfix_len = 0, .owner = THIS_MODULE, }; @@ -202,15 +208,14 @@ int __init rtllib_crypto_init(void) { int ret = -ENOMEM; - hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL); + hcrypt = kzalloc(sizeof(*hcrypt), GFP_KERNEL); if (!hcrypt) goto out; - memset(hcrypt, 0, sizeof(*hcrypt)); INIT_LIST_HEAD(&hcrypt->algs); spin_lock_init(&hcrypt->lock); - ret = rtllib_register_crypto_ops(&rtllib_crypt_null); + ret = lib80211_register_crypto_ops(&rtllib_crypt_null); if (ret < 0) { kfree(hcrypt); hcrypt = NULL; @@ -239,3 +244,8 @@ void __exit rtllib_crypto_deinit(void) kfree(hcrypt); } + +module_init(rtllib_crypto_init); +module_exit(rtllib_crypto_deinit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_crypt.h b/drivers/staging/rtl8192e/rtllib_crypt.h index 49b90b73ed9..e177c9287b4 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt.h +++ b/drivers/staging/rtl8192e/rtllib_crypt.h @@ -25,61 +25,11 @@ #include <linux/skbuff.h> -struct rtllib_crypto_ops { - const char *name; - - /* init new crypto context (e.g., allocate private data space, - * select IV, etc.); returns NULL on failure or pointer to allocated - * private data on success */ - void * (*init)(int keyidx); - - /* deinitialize crypto context and free allocated private data */ - void (*deinit)(void *priv); - - /* encrypt/decrypt return < 0 on error or >= 0 on success. The return - * value from decrypt_mpdu is passed as the keyidx value for - * decrypt_msdu. skb must have enough head and tail room for the - * encryption; if not, error will be returned; these functions are - * called for all MPDUs (i.e., fragments). - */ - int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - - /* These functions are called for full MSDUs, i.e. full frames. - * These can be NULL if full MSDU operations are not needed. */ - int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, - void *priv, struct rtllib_device* ieee); - - int (*set_key)(void *key, int len, u8 *seq, void *priv); - int (*get_key)(void *key, int len, u8 *seq, void *priv); - - /* procfs handler for printing out key information and possible - * statistics */ - char * (*print_stats)(char *p, void *priv); - - /* maximum number of bytes added by encryption; encrypt buf is - * allocated with extra_prefix_len bytes, copy of in_buf, and - * extra_postfix_len; encrypt need not use all this space, but - * the result must start at the beginning of the struct buffer and - * correct length must be returned */ - int extra_prefix_len, extra_postfix_len; - - struct module *owner; -}; - -struct rtllib_crypt_data { - struct list_head list; /* delayed deletion list */ - struct rtllib_crypto_ops *ops; - void *priv; - atomic_t refcnt; -}; - -int rtllib_register_crypto_ops(struct rtllib_crypto_ops *ops); -int rtllib_unregister_crypto_ops(struct rtllib_crypto_ops *ops); -struct rtllib_crypto_ops *rtllib_get_crypto_ops(const char *name); -void rtllib_crypt_deinit_entries(struct rtllib_device *, int); -void rtllib_crypt_deinit_handler(unsigned long); -void rtllib_crypt_delayed_deinit(struct rtllib_device *ieee, - struct rtllib_crypt_data **crypt); +int rtllib_register_crypto_ops(struct lib80211_crypto_ops *ops); +int rtllib_unregister_crypto_ops(struct lib80211_crypto_ops *ops); +struct lib80211_crypto_ops *rtllib_get_crypto_ops(const char *name); +void rtllib_crypt_deinit_entries(struct lib80211_crypt_info *info, int force); +void rtllib_crypt_deinit_handler(unsigned long data); +void rtllib_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt); #endif diff --git a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c index 6196b9aa3a0..4217b88e6fc 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c @@ -9,7 +9,6 @@ * more details. */ -#include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -63,10 +62,9 @@ static void *rtllib_ccmp_init(int key_idx) { struct rtllib_ccmp_data *priv; - priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) goto fail; - memset(priv, 0, sizeof(*priv)); priv->key_idx = key_idx; priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); @@ -429,13 +427,8 @@ static char *rtllib_ccmp_print_stats(char *p, void *priv) return p; } -void rtllib_ccmp_null(void) -{ - return; -} - -static struct rtllib_crypto_ops rtllib_crypt_ccmp = { - .name = "CCMP", +static struct lib80211_crypto_ops rtllib_crypt_ccmp = { + .name = "R-CCMP", .init = rtllib_ccmp_init, .deinit = rtllib_ccmp_deinit, .encrypt_mpdu = rtllib_ccmp_encrypt, @@ -445,19 +438,24 @@ static struct rtllib_crypto_ops rtllib_crypt_ccmp = { .set_key = rtllib_ccmp_set_key, .get_key = rtllib_ccmp_get_key, .print_stats = rtllib_ccmp_print_stats, - .extra_prefix_len = CCMP_HDR_LEN, - .extra_postfix_len = CCMP_MIC_LEN, + .extra_mpdu_prefix_len = CCMP_HDR_LEN, + .extra_mpdu_postfix_len = CCMP_MIC_LEN, .owner = THIS_MODULE, }; int __init rtllib_crypto_ccmp_init(void) { - return rtllib_register_crypto_ops(&rtllib_crypt_ccmp); + return lib80211_register_crypto_ops(&rtllib_crypt_ccmp); } void __exit rtllib_crypto_ccmp_exit(void) { - rtllib_unregister_crypto_ops(&rtllib_crypt_ccmp); + lib80211_unregister_crypto_ops(&rtllib_crypt_ccmp); } + +module_init(rtllib_crypto_ccmp_init); +module_exit(rtllib_crypto_ccmp_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c index 6a0c8788642..800925053fb 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c @@ -9,7 +9,6 @@ * more details. */ -#include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -60,10 +59,9 @@ static void *rtllib_tkip_init(int key_idx) { struct rtllib_tkip_data *priv; - priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) goto fail; - memset(priv, 0, sizeof(*priv)); priv->key_idx = key_idx; priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); @@ -598,8 +596,7 @@ static void rtllib_michael_mic_failure(struct net_device *dev, } static int rtllib_michael_mic_verify(struct sk_buff *skb, int keyidx, - int hdr_len, void *priv, - struct rtllib_device *ieee) + int hdr_len, void *priv) { struct rtllib_tkip_data *tkey = priv; u8 mic[8]; @@ -618,23 +615,20 @@ static int rtllib_michael_mic_verify(struct sk_buff *skb, int keyidx, skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) return -1; - if ((memcmp(mic, skb->data + skb->len - 8, 8) != 0) || - (ieee->force_mic_error)) { + if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { struct rtllib_hdr_4addr *hdr; hdr = (struct rtllib_hdr_4addr *) skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " "MSDU from %pM keyidx=%d\n", skb->dev ? skb->dev->name : "N/A", hdr->addr2, keyidx); - printk(KERN_DEBUG "%d, force_mic_error = %d\n", - (memcmp(mic, skb->data + skb->len - 8, 8) != 0),\ - ieee->force_mic_error); + printk(KERN_DEBUG "%d\n", + memcmp(mic, skb->data + skb->len - 8, 8) != 0); if (skb->dev) { printk(KERN_INFO "skb->dev != NULL\n"); rtllib_michael_mic_failure(skb->dev, hdr, keyidx); } tkey->dot11RSNAStatsTKIPLocalMICFailures++; - ieee->force_mic_error = false; return -1; } @@ -740,9 +734,8 @@ static char *rtllib_tkip_print_stats(char *p, void *priv) return p; } - -static struct rtllib_crypto_ops rtllib_crypt_tkip = { - .name = "TKIP", +static struct lib80211_crypto_ops rtllib_crypt_tkip = { + .name = "R-TKIP", .init = rtllib_tkip_init, .deinit = rtllib_tkip_deinit, .encrypt_mpdu = rtllib_tkip_encrypt, @@ -752,24 +745,25 @@ static struct rtllib_crypto_ops rtllib_crypt_tkip = { .set_key = rtllib_tkip_set_key, .get_key = rtllib_tkip_get_key, .print_stats = rtllib_tkip_print_stats, - .extra_prefix_len = 4 + 4, /* IV + ExtIV */ - .extra_postfix_len = 8 + 4, /* MIC + ICV */ + .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .extra_msdu_postfix_len = 8, /* MIC */ .owner = THIS_MODULE, }; int __init rtllib_crypto_tkip_init(void) { - return rtllib_register_crypto_ops(&rtllib_crypt_tkip); + return lib80211_register_crypto_ops(&rtllib_crypt_tkip); } void __exit rtllib_crypto_tkip_exit(void) { - rtllib_unregister_crypto_ops(&rtllib_crypt_tkip); + lib80211_unregister_crypto_ops(&rtllib_crypt_tkip); } -void rtllib_tkip_null(void) -{ - return; -} +module_init(rtllib_crypto_tkip_init); +module_exit(rtllib_crypto_tkip_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/drivers/staging/rtl8192e/rtllib_crypt_wep.c index c59bf10fe78..8cdf38913a3 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_wep.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_wep.c @@ -9,7 +9,6 @@ * more details. */ -#include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -38,10 +37,9 @@ static void *prism2_wep_init(int keyidx) { struct prism2_wep_data *priv; - priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) goto fail; - memset(priv, 0, sizeof(*priv)); priv->key_idx = keyidx; priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); @@ -257,9 +255,8 @@ static char *prism2_wep_print_stats(char *p, void *priv) return p; } - -static struct rtllib_crypto_ops rtllib_crypt_wep = { - .name = "WEP", +static struct lib80211_crypto_ops rtllib_crypt_wep = { + .name = "R-WEP", .init = prism2_wep_init, .deinit = prism2_wep_deinit, .encrypt_mpdu = prism2_wep_encrypt, @@ -269,24 +266,24 @@ static struct rtllib_crypto_ops rtllib_crypt_wep = { .set_key = prism2_wep_set_key, .get_key = prism2_wep_get_key, .print_stats = prism2_wep_print_stats, - .extra_prefix_len = 4, /* IV */ - .extra_postfix_len = 4, /* ICV */ + .extra_mpdu_prefix_len = 4, /* IV */ + .extra_mpdu_postfix_len = 4, /* ICV */ .owner = THIS_MODULE, }; int __init rtllib_crypto_wep_init(void) { - return rtllib_register_crypto_ops(&rtllib_crypt_wep); + return lib80211_register_crypto_ops(&rtllib_crypt_wep); } void __exit rtllib_crypto_wep_exit(void) { - rtllib_unregister_crypto_ops(&rtllib_crypt_wep); + lib80211_unregister_crypto_ops(&rtllib_crypt_wep); } -void rtllib_wep_null(void) -{ - return; -} +module_init(rtllib_crypto_wep_init); +module_exit(rtllib_crypto_wep_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_debug.h b/drivers/staging/rtl8192e/rtllib_debug.h new file mode 100644 index 00000000000..2bfc1155f50 --- /dev/null +++ b/drivers/staging/rtl8192e/rtllib_debug.h @@ -0,0 +1,86 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> +******************************************************************************/ +#ifndef _RTL_DEBUG_H +#define _RTL_DEBUG_H + +/* Allow files to override DRV_NAME */ +#ifndef DRV_NAME +#define DRV_NAME "rtllib_92e" +#endif + +#define DMESG(x, a...) + +extern u32 rt_global_debug_component; + +/* These are the defines for rt_global_debug_component */ +enum RTL_DEBUG { + COMP_TRACE = (1 << 0), + COMP_DBG = (1 << 1), + COMP_INIT = (1 << 2), + COMP_RECV = (1 << 3), + COMP_SEND = (1 << 4), + COMP_CMD = (1 << 5), + COMP_POWER = (1 << 6), + COMP_EPROM = (1 << 7), + COMP_SWBW = (1 << 8), + COMP_SEC = (1 << 9), + COMP_LPS = (1 << 10), + COMP_QOS = (1 << 11), + COMP_RATE = (1 << 12), + COMP_RXDESC = (1 << 13), + COMP_PHY = (1 << 14), + COMP_DIG = (1 << 15), + COMP_TXAGC = (1 << 16), + COMP_HALDM = (1 << 17), + COMP_POWER_TRACKING = (1 << 18), + COMP_CH = (1 << 19), + COMP_RF = (1 << 20), + COMP_FIRMWARE = (1 << 21), + COMP_HT = (1 << 22), + COMP_RESET = (1 << 23), + COMP_CMDPKT = (1 << 24), + COMP_SCAN = (1 << 25), + COMP_PS = (1 << 26), + COMP_DOWN = (1 << 27), + COMP_INTR = (1 << 28), + COMP_LED = (1 << 29), + COMP_MLME = (1 << 30), + COMP_ERR = (1 << 31) +}; + +#define RT_TRACE(component, x, args...) \ +do { \ + if (rt_global_debug_component & component) \ + printk(KERN_DEBUG DRV_NAME ":" x "\n" , \ + ##args);\ +} while (0); + +#define assert(expr) \ + if (!(expr)) { \ + printk(KERN_INFO "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr, __FILE__, __func__, __LINE__); \ + } + +#endif diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c index c36a140a456..f9dae958a5d 100644 --- a/drivers/staging/rtl8192e/rtllib_module.c +++ b/drivers/staging/rtl8192e/rtllib_module.c @@ -45,7 +45,6 @@ #include <linux/slab.h> #include <linux/tcp.h> #include <linux/types.h> -#include <linux/version.h> #include <linux/wireless.h> #include <linux/etherdevice.h> #include <linux/uaccess.h> @@ -54,7 +53,9 @@ #include "rtllib.h" -#define DRV_NAME "rtllib_92e" +u32 rt_global_debug_component = COMP_ERR; +EXPORT_SYMBOL(rt_global_debug_component); + void _setup_timer(struct timer_list *ptimer, void *fun, unsigned long data) { @@ -135,10 +136,6 @@ struct net_device *alloc_rtllib(int sizeof_priv) ieee->host_decrypt = 1; ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ - INIT_LIST_HEAD(&ieee->crypt_deinit_list); - _setup_timer(&ieee->crypt_deinit_timer, - rtllib_crypt_deinit_handler, - (unsigned long) ieee); ieee->rtllib_ap_sec_type = rtllib_ap_sec_type; spin_lock_init(&ieee->lock); @@ -148,6 +145,9 @@ struct net_device *alloc_rtllib(int sizeof_priv) atomic_set(&(ieee->atm_chnlop), 0); atomic_set(&(ieee->atm_swbw), 0); + /* SAM FIXME */ + lib80211_crypt_info_init(&ieee->crypt_info, "RTLLIB", &ieee->lock); + ieee->bHalfNMode = false; ieee->wpa_enabled = 0; ieee->tkip_countermeasures = 0; @@ -177,10 +177,6 @@ struct net_device *alloc_rtllib(int sizeof_priv) ieee->last_packet_time[i] = 0; } - rtllib_tkip_null(); - rtllib_wep_null(); - rtllib_ccmp_null(); - return dev; failed: @@ -188,32 +184,23 @@ struct net_device *alloc_rtllib(int sizeof_priv) free_netdev(dev); return NULL; } +EXPORT_SYMBOL(alloc_rtllib); void free_rtllib(struct net_device *dev) { struct rtllib_device *ieee = (struct rtllib_device *) netdev_priv_rsl(dev); - int i; kfree(ieee->pHTInfo); ieee->pHTInfo = NULL; rtllib_softmac_free(ieee); - del_timer_sync(&ieee->crypt_deinit_timer); - rtllib_crypt_deinit_entries(ieee, 1); - - for (i = 0; i < WEP_KEYS; i++) { - struct rtllib_crypt_data *crypt = ieee->crypt[i]; - if (crypt) { - if (crypt->ops) - crypt->ops->deinit(crypt->priv); - kfree(crypt); - ieee->crypt[i] = NULL; - } - } + + lib80211_crypt_info_free(&ieee->crypt_info); rtllib_networks_free(ieee); free_netdev(dev); } +EXPORT_SYMBOL(free_rtllib); u32 rtllib_debug_level; static int debug = \ @@ -287,3 +274,8 @@ void __exit rtllib_exit(void) rtllib_proc = NULL; } } + +module_init(rtllib_init); +module_exit(rtllib_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 8d0af5ed8ec..6c5061f12ba 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -36,7 +36,6 @@ #include <linux/slab.h> #include <linux/tcp.h> #include <linux/types.h> -#include <linux/version.h> #include <linux/wireless.h> #include <linux/etherdevice.h> #include <linux/uaccess.h> @@ -281,7 +280,7 @@ static int rtllib_is_eapol_frame(struct rtllib_device *ieee, /* Called only as a tasklet (software IRQ), by rtllib_rx */ static inline int rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct rtllib_hdr_4addr *hdr; int res, hdrlen; @@ -322,7 +321,7 @@ rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, /* Called only as a tasklet (software IRQ), by rtllib_rx */ static inline int rtllib_rx_frame_decrypt_msdu(struct rtllib_device *ieee, struct sk_buff *skb, - int keyidx, struct rtllib_crypt_data *crypt) + int keyidx, struct lib80211_crypt_data *crypt) { struct rtllib_hdr_4addr *hdr; int res, hdrlen; @@ -341,7 +340,7 @@ rtllib_rx_frame_decrypt_msdu(struct rtllib_device *ieee, struct sk_buff *skb, hdrlen = rtllib_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv, ieee); + res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" @@ -1010,7 +1009,7 @@ static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc, } static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_crypt_data **crypt, size_t hdrlen) + struct lib80211_crypt_data **crypt, size_t hdrlen) { struct rtllib_hdr_4addr *hdr = (struct rtllib_hdr_4addr *)skb->data; u16 fc = le16_to_cpu(hdr->frame_ctl); @@ -1020,7 +1019,7 @@ static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb, if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; - *crypt = ieee->crypt[idx]; + *crypt = ieee->crypt_info.crypt[idx]; /* allow NULL decrypt to indicate an station specific override * for default encryption */ if (*crypt && ((*crypt)->ops == NULL || @@ -1045,7 +1044,7 @@ static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb, static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_stats, - struct rtllib_crypt_data *crypt, size_t hdrlen) + struct lib80211_crypt_data *crypt, size_t hdrlen) { struct rtllib_hdr_4addr *hdr; int keyidx = 0; @@ -1253,7 +1252,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb, { struct net_device *dev = ieee->dev; struct rtllib_hdr_4addr *hdr = (struct rtllib_hdr_4addr *)skb->data; - struct rtllib_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; struct rtllib_rxb *rxb = NULL; struct rx_ts_record *pTS = NULL; u16 fc, sc, SeqNum = 0; @@ -1497,6 +1496,7 @@ int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb, ieee->stats.rx_dropped++; return 0; } +EXPORT_SYMBOL(rtllib_rx); static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; @@ -2492,7 +2492,7 @@ static int IsPassiveChannel(struct rtllib_device *rtllib, u8 channel) return 0; } -int IsLegalChannel(struct rtllib_device *rtllib, u8 channel) +int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel) { if (MAX_CHANNEL_NUMBER < channel) { printk(KERN_INFO "%s(): Invalid Channel\n", __func__); @@ -2503,6 +2503,7 @@ int IsLegalChannel(struct rtllib_device *rtllib, u8 channel) return 0; } +EXPORT_SYMBOL(rtllib_legal_channel); static inline void rtllib_process_probe_response( struct rtllib_device *ieee, @@ -2553,7 +2554,7 @@ static inline void rtllib_process_probe_response( } - if (!IsLegalChannel(ieee, network->channel)) + if (!rtllib_legal_channel(ieee, network->channel)) goto free_network; if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index b5086850f0d..1637f111099 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -15,11 +15,9 @@ #include "rtllib.h" -#include "rtl_core.h" #include <linux/random.h> #include <linux/delay.h> -#include <linux/version.h> #include <linux/uaccess.h> #include "dot11d.h" @@ -28,9 +26,9 @@ short rtllib_is_54g(struct rtllib_network *net) return (net->rates_ex_len > 0) || (net->rates_len > 4); } -short rtllib_is_shortslot(struct rtllib_network net) +short rtllib_is_shortslot(const struct rtllib_network *net) { - return net.capability & WLAN_CAPABILITY_SHORT_SLOT_TIME; + return net->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME; } /* returns the total length needed for pleacing the RATE MFIE @@ -468,6 +466,7 @@ void rtllib_EnableIntelPromiscuousMode(struct net_device *dev, ieee->bNetPromiscuousMode = true; } +EXPORT_SYMBOL(rtllib_EnableIntelPromiscuousMode); /* @@ -490,6 +489,7 @@ void rtllib_DisableIntelPromiscuousMode(struct net_device *dev, ieee->bNetPromiscuousMode = false; } +EXPORT_SYMBOL(rtllib_DisableIntelPromiscuousMode); static void rtllib_send_probe(struct rtllib_device *ieee, u8 is_mesh) { @@ -685,6 +685,7 @@ void rtllib_stop_send_beacons(struct rtllib_device *ieee) if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) rtllib_beacons_stop(ieee); } +EXPORT_SYMBOL(rtllib_stop_send_beacons); void rtllib_start_send_beacons(struct rtllib_device *ieee) @@ -694,6 +695,7 @@ void rtllib_start_send_beacons(struct rtllib_device *ieee) if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) rtllib_beacons_start(ieee); } +EXPORT_SYMBOL(rtllib_start_send_beacons); static void rtllib_softmac_stop_scan(struct rtllib_device *ieee) @@ -719,6 +721,7 @@ void rtllib_stop_scan(struct rtllib_device *ieee) ieee->rtllib_stop_hw_scan(ieee->dev); } } +EXPORT_SYMBOL(rtllib_stop_scan); void rtllib_stop_scan_syncro(struct rtllib_device *ieee) { @@ -729,6 +732,7 @@ void rtllib_stop_scan_syncro(struct rtllib_device *ieee) ieee->rtllib_stop_hw_scan(ieee->dev); } } +EXPORT_SYMBOL(rtllib_stop_scan_syncro); bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan) { @@ -741,6 +745,7 @@ bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan) return test_bit(STATUS_SCANNING, &ieee->status); } } +EXPORT_SYMBOL(rtllib_act_scanning); /* called with ieee->lock held */ static void rtllib_start_scan(struct rtllib_device *ieee) @@ -781,6 +786,7 @@ void rtllib_start_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) ieee->rtllib_start_hw_scan(ieee->dev); } } +EXPORT_SYMBOL(rtllib_start_scan_syncro); inline struct sk_buff *rtllib_authentication_req(struct rtllib_network *beacon, struct rtllib_device *ieee, int challengelen, u8 *daddr) @@ -830,7 +836,7 @@ static struct sk_buff *rtllib_probe_resp(struct rtllib_device *ieee, u8 *dest) struct sk_buff *skb = NULL; int encrypt; int atim_len, erp_len; - struct rtllib_crypt_data *crypt; + struct lib80211_crypt_data *crypt; char *ssid = ieee->current_network.ssid; int ssid_len = ieee->current_network.ssid_len; @@ -865,9 +871,9 @@ static struct sk_buff *rtllib_probe_resp(struct rtllib_device *ieee, u8 *dest) } else erp_len = 0; - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; encrypt = ieee->host_encrypt && crypt && crypt->ops && - ((0 == strcmp(crypt->ops->name, "WEP") || wpa_ie_len)); + ((0 == strcmp(crypt->ops->name, "R-WEP") || wpa_ie_len)); if (ieee->pHTInfo->bCurrentHTSupport) { tmp_ht_cap_buf = (u8 *) &(ieee->pHTInfo->SelfHTCap); tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); @@ -917,7 +923,7 @@ static struct sk_buff *rtllib_probe_resp(struct rtllib_device *ieee, u8 *dest) cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT_TIME)); - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; if (encrypt) beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); @@ -976,7 +982,7 @@ static struct sk_buff *rtllib_assoc_resp(struct rtllib_device *ieee, u8 *dest) struct sk_buff *skb; u8 *tag; - struct rtllib_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct rtllib_assoc_response_frame *assoc; short encrypt; @@ -1007,7 +1013,7 @@ static struct sk_buff *rtllib_assoc_resp(struct rtllib_device *ieee, u8 *dest) cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); if (ieee->host_encrypt) - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; else crypt = NULL; @@ -1172,7 +1178,7 @@ inline struct sk_buff *rtllib_association_req(struct rtllib_network *beacon, unsigned int ckip_ie_len = 0; unsigned int ccxrm_ie_len = 0; unsigned int cxvernum_ie_len = 0; - struct rtllib_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int encrypt; int PMKCacheIdx; @@ -1185,10 +1191,10 @@ inline struct sk_buff *rtllib_association_req(struct rtllib_network *beacon, unsigned int turbo_info_len = beacon->Turbo_Enable ? 9 : 0; int len = 0; - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; if (crypt != NULL) encrypt = ieee->host_encrypt && crypt && crypt->ops && - ((0 == strcmp(crypt->ops->name, "WEP") || + ((0 == strcmp(crypt->ops->name, "R-WEP") || wpa_ie_len)); else encrypt = 0; @@ -1956,6 +1962,7 @@ void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr) if (buf) softmac_ps_mgmt_xmit(buf, ieee); } +EXPORT_SYMBOL(rtllib_sta_ps_send_null_frame); void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee) { @@ -2168,6 +2175,7 @@ void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success) } spin_unlock_irqrestore(&ieee->lock, flags); } +EXPORT_SYMBOL(rtllib_ps_tx_ack); static void rtllib_process_action(struct rtllib_device *ieee, struct sk_buff *skb) { @@ -2540,6 +2548,7 @@ void rtllib_reset_queue(struct rtllib_device *ieee) spin_unlock_irqrestore(&ieee->lock, flags); } +EXPORT_SYMBOL(rtllib_reset_queue); void rtllib_wake_queue(struct rtllib_device *ieee) { @@ -2928,6 +2937,7 @@ struct sk_buff *rtllib_get_beacon(struct rtllib_device *ieee) return skb; } +EXPORT_SYMBOL(rtllib_get_beacon); void rtllib_softmac_stop_protocol(struct rtllib_device *ieee, u8 mesh_flag, u8 shutdown) @@ -2937,6 +2947,7 @@ void rtllib_softmac_stop_protocol(struct rtllib_device *ieee, u8 mesh_flag, rtllib_stop_protocol(ieee, shutdown); up(&ieee->wx_sem); } +EXPORT_SYMBOL(rtllib_softmac_stop_protocol); void rtllib_stop_protocol(struct rtllib_device *ieee, u8 shutdown) @@ -2985,6 +2996,7 @@ void rtllib_softmac_start_protocol(struct rtllib_device *ieee, u8 mesh_flag) rtllib_start_protocol(ieee); up(&ieee->wx_sem); } +EXPORT_SYMBOL(rtllib_softmac_start_protocol); void rtllib_start_protocol(struct rtllib_device *ieee) { @@ -3048,10 +3060,9 @@ void rtllib_softmac_init(struct rtllib_device *ieee) ieee->state = RTLLIB_NOLINK; for (i = 0; i < 5; i++) ieee->seq_ctrl[i] = 0; - ieee->pDot11dInfo = kmalloc(sizeof(struct rt_dot11d_info), GFP_ATOMIC); + ieee->pDot11dInfo = kzalloc(sizeof(struct rt_dot11d_info), GFP_ATOMIC); if (!ieee->pDot11dInfo) RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc memory for DOT11D\n"); - memset(ieee->pDot11dInfo, 0, sizeof(struct rt_dot11d_info)); ieee->LinkDetectInfo.SlotIndex = 0; ieee->LinkDetectInfo.SlotNum = 2; ieee->LinkDetectInfo.NumRecvBcnInPeriod = 0; @@ -3207,11 +3218,11 @@ static int rtllib_wpa_set_wpa_ie(struct rtllib_device *ieee, return -EINVAL; if (param->u.wpa_ie.len) { - buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); + buf = kmemdup(param->u.wpa_ie.data, param->u.wpa_ie.len, + GFP_KERNEL); if (buf == NULL) return -ENOMEM; - memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); kfree(ieee->wpa_ie); ieee->wpa_ie = buf; ieee->wpa_ie_len = param->u.wpa_ie.len; @@ -3334,8 +3345,8 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, u8 is_mesh) { int ret = 0; - struct rtllib_crypto_ops *ops; - struct rtllib_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; struct rtllib_security sec = { .flags = 0, @@ -3354,9 +3365,9 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { - if (param->u.crypt.idx >= WEP_KEYS) + if (param->u.crypt.idx >= NUM_WEP_KEYS) return -EINVAL; - crypt = &ieee->crypt[param->u.crypt.idx]; + crypt = &ieee->crypt_info.crypt[param->u.crypt.idx]; } else { return -EINVAL; } @@ -3366,7 +3377,7 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, sec.enabled = 0; sec.level = SEC_LEVEL_0; sec.flags |= SEC_ENABLED | SEC_LEVEL; - rtllib_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } goto done; } @@ -3375,19 +3386,19 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, /* IPW HW cannot build TKIP MIC, host decryption still needed. */ if (!(ieee->host_encrypt || ieee->host_decrypt) && - strcmp(param->u.crypt.alg, "TKIP")) + strcmp(param->u.crypt.alg, "R-TKIP")) goto skip_host_crypt; - ops = rtllib_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { + ops = lib80211_get_crypto_ops(param->u.crypt.alg); + if (ops == NULL && strcmp(param->u.crypt.alg, "R-WEP") == 0) { request_module("rtllib_crypt_wep"); - ops = rtllib_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { + ops = lib80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "R-TKIP") == 0) { request_module("rtllib_crypt_tkip"); - ops = rtllib_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { + ops = lib80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "R-CCMP") == 0) { request_module("rtllib_crypt_ccmp"); - ops = rtllib_get_crypto_ops(param->u.crypt.alg); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } if (ops == NULL) { printk(KERN_INFO "unknown crypto alg '%s'\n", @@ -3397,17 +3408,17 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, goto done; } if (*crypt == NULL || (*crypt)->ops != ops) { - struct rtllib_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - rtllib_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - new_crypt = (struct rtllib_crypt_data *) + new_crypt = (struct lib80211_crypt_data *) kmalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; goto done; } - memset(new_crypt, 0, sizeof(struct rtllib_crypt_data)); + memset(new_crypt, 0, sizeof(struct lib80211_crypt_data)); new_crypt->ops = ops; if (new_crypt->ops) new_crypt->priv = @@ -3435,7 +3446,7 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, skip_host_crypt: if (param->u.crypt.set_tx) { - ieee->tx_keyidx = param->u.crypt.idx; + ieee->crypt_info.tx_keyidx = param->u.crypt.idx; sec.active_key = param->u.crypt.idx; sec.flags |= SEC_ACTIVE_KEY; } else @@ -3448,13 +3459,13 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; sec.flags |= (1 << param->u.crypt.idx); - if (strcmp(param->u.crypt.alg, "WEP") == 0) { + if (strcmp(param->u.crypt.alg, "R-WEP") == 0) { sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_1; - } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { + } else if (strcmp(param->u.crypt.alg, "R-TKIP") == 0) { sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_2; - } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { + } else if (strcmp(param->u.crypt.alg, "R-CCMP") == 0) { sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_3; } @@ -3551,13 +3562,13 @@ u8 rtllib_ap_sec_type(struct rtllib_device *ieee) static u8 ccmp_ie[4] = {0x00, 0x50, 0xf2, 0x04}; static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04}; int wpa_ie_len = ieee->wpa_ie_len; - struct rtllib_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int encrypt; - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; encrypt = (ieee->current_network.capability & WLAN_CAPABILITY_PRIVACY) || (ieee->host_encrypt && crypt && crypt->ops && - (0 == strcmp(crypt->ops->name, "WEP"))); + (0 == strcmp(crypt->ops->name, "R-WEP"))); /* simply judge */ if (encrypt && (wpa_ie_len == 0)) { @@ -3634,6 +3645,7 @@ out: return ret; } +EXPORT_SYMBOL(rtllib_wpa_supplicant_ioctl); void rtllib_MgntDisconnectIBSS(struct rtllib_device *rtllib) { @@ -3719,6 +3731,7 @@ bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn) return true; } +EXPORT_SYMBOL(rtllib_MgntDisconnect); void notify_wx_assoc_event(struct rtllib_device *ieee) { @@ -3739,3 +3752,4 @@ void notify_wx_assoc_event(struct rtllib_device *ieee) } wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); } +EXPORT_SYMBOL(notify_wx_assoc_event); diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c index 22988fbd444..1523bc7a210 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c +++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c @@ -15,7 +15,6 @@ #include "rtllib.h" -#include "rtl_core.h" #include "dot11d.h" /* FIXME: add A freqs */ @@ -25,6 +24,7 @@ const long rtllib_wlan_frequencies[] = { 2452, 2457, 2462, 2467, 2472, 2484 }; +EXPORT_SYMBOL(rtllib_wlan_frequencies); int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a, @@ -82,6 +82,7 @@ out: up(&ieee->wx_sem); return ret; } +EXPORT_SYMBOL(rtllib_wx_set_freq); int rtllib_wx_get_freq(struct rtllib_device *ieee, @@ -97,6 +98,7 @@ int rtllib_wx_get_freq(struct rtllib_device *ieee, fwrq->e = 1; return 0; } +EXPORT_SYMBOL(rtllib_wx_get_freq); int rtllib_wx_get_wap(struct rtllib_device *ieee, struct iw_request_info *info, @@ -125,6 +127,7 @@ int rtllib_wx_get_wap(struct rtllib_device *ieee, return 0; } +EXPORT_SYMBOL(rtllib_wx_get_wap); int rtllib_wx_set_wap(struct rtllib_device *ieee, @@ -184,6 +187,7 @@ out: up(&ieee->wx_sem); return ret; } +EXPORT_SYMBOL(rtllib_wx_set_wap); int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a, union iwreq_data *wrqu, char *b) @@ -220,6 +224,7 @@ out: return ret; } +EXPORT_SYMBOL(rtllib_wx_get_essid); int rtllib_wx_set_rate(struct rtllib_device *ieee, struct iw_request_info *info, @@ -231,6 +236,7 @@ int rtllib_wx_set_rate(struct rtllib_device *ieee, ieee->rate = target_rate/100000; return 0; } +EXPORT_SYMBOL(rtllib_wx_set_rate); int rtllib_wx_get_rate(struct rtllib_device *ieee, struct iw_request_info *info, @@ -243,6 +249,7 @@ int rtllib_wx_get_rate(struct rtllib_device *ieee, return 0; } +EXPORT_SYMBOL(rtllib_wx_get_rate); int rtllib_wx_set_rts(struct rtllib_device *ieee, @@ -259,6 +266,7 @@ int rtllib_wx_set_rts(struct rtllib_device *ieee, } return 0; } +EXPORT_SYMBOL(rtllib_wx_set_rts); int rtllib_wx_get_rts(struct rtllib_device *ieee, struct iw_request_info *info, @@ -269,6 +277,7 @@ int rtllib_wx_get_rts(struct rtllib_device *ieee, wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); return 0; } +EXPORT_SYMBOL(rtllib_wx_get_rts); int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a, union iwreq_data *wrqu, char *b) @@ -314,6 +323,7 @@ out: up(&ieee->wx_sem); return set_mode_status; } +EXPORT_SYMBOL(rtllib_wx_set_mode); void rtllib_wx_sync_scan_wq(void *data) { @@ -428,6 +438,7 @@ out: up(&ieee->wx_sem); return ret; } +EXPORT_SYMBOL(rtllib_wx_set_scan); int rtllib_wx_set_essid(struct rtllib_device *ieee, struct iw_request_info *a, @@ -490,6 +501,7 @@ out: up(&ieee->wx_sem); return ret; } +EXPORT_SYMBOL(rtllib_wx_set_essid); int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a, union iwreq_data *wrqu, char *b) @@ -497,6 +509,7 @@ int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a, wrqu->mode = ieee->iw_mode; return 0; } +EXPORT_SYMBOL(rtllib_wx_get_mode); int rtllib_wx_set_rawtx(struct rtllib_device *ieee, struct iw_request_info *info, @@ -533,6 +546,7 @@ int rtllib_wx_set_rawtx(struct rtllib_device *ieee, return 0; } +EXPORT_SYMBOL(rtllib_wx_set_rawtx); int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info, @@ -548,6 +562,7 @@ int rtllib_wx_get_name(struct rtllib_device *ieee, strcat(wrqu->name, "n"); return 0; } +EXPORT_SYMBOL(rtllib_wx_get_name); /* this is mostly stolen from hostap */ @@ -605,6 +620,7 @@ exit: return ret; } +EXPORT_SYMBOL(rtllib_wx_set_power); /* this is stolen from hostap */ int rtllib_wx_get_power(struct rtllib_device *ieee, @@ -643,3 +659,4 @@ exit: return ret; } +EXPORT_SYMBOL(rtllib_wx_get_power); diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index 44e8006bc1a..f451bfc27a8 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -46,7 +46,6 @@ #include <linux/slab.h> #include <linux/tcp.h> #include <linux/types.h> -#include <linux/version.h> #include <linux/wireless.h> #include <linux/etherdevice.h> #include <linux/uaccess.h> @@ -180,10 +179,10 @@ inline int rtllib_put_snap(u8 *data, u16 h_proto) int rtllib_encrypt_fragment(struct rtllib_device *ieee, struct sk_buff *frag, int hdr_len) { - struct rtllib_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; int res; - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; if (!(crypt && crypt->ops)) { printk(KERN_INFO "=========>%s(), crypt is null\n", __func__); @@ -569,7 +568,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) }; u8 dest[ETH_ALEN], src[ETH_ALEN]; int qos_actived = ieee->current_network.qos_data.active; - struct rtllib_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; struct cb_desc *tcb_desc; u8 bIsMulticast = false; u8 IsAmsdu = false; @@ -646,7 +645,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) } skb->priority = rtllib_classify(skb, IsAmsdu); - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && ieee->host_encrypt && crypt && crypt->ops; if (!encrypt && ieee->ieee802_1x && @@ -742,8 +741,10 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) /* Each fragment may need to have room for encryptiong * pre/postfix */ if (encrypt) { - bytes_per_frag -= crypt->ops->extra_prefix_len + - crypt->ops->extra_postfix_len; + bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + + crypt->ops->extra_mpdu_postfix_len + + crypt->ops->extra_msdu_prefix_len + + crypt->ops->extra_msdu_postfix_len; } /* Number of fragments is the total bytes_per_frag / * payload_per_fragment */ @@ -791,7 +792,8 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) else tcb_desc->bHwSec = 0; skb_reserve(skb_frag, - crypt->ops->extra_prefix_len); + crypt->ops->extra_mpdu_prefix_len + + crypt->ops->extra_msdu_prefix_len); } else { tcb_desc->bHwSec = 0; } @@ -965,3 +967,4 @@ int rtllib_xmit(struct sk_buff *skb, struct net_device *dev) memset(skb->cb, 0, sizeof(skb->cb)); return rtllib_xmit_inter(skb, dev); } +EXPORT_SYMBOL(rtllib_xmit); diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index 8cea4a60e1b..c27ff7edbaf 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -30,7 +30,6 @@ ******************************************************************************/ #include <linux/wireless.h> -#include <linux/version.h> #include <linux/kmod.h> #include <linux/module.h> @@ -295,6 +294,7 @@ int rtllib_wx_get_scan(struct rtllib_device *ieee, return err; } +EXPORT_SYMBOL(rtllib_wx_get_scan); int rtllib_wx_set_encode(struct rtllib_device *ieee, struct iw_request_info *info, @@ -306,44 +306,44 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, .flags = 0 }; int i, key, key_provided, len; - struct rtllib_crypt_data **crypt; + struct lib80211_crypt_data **crypt; RTLLIB_DEBUG_WX("SET_ENCODE\n"); key = erq->flags & IW_ENCODE_INDEX; if (key) { - if (key > WEP_KEYS) + if (key > NUM_WEP_KEYS) return -EINVAL; key--; key_provided = 1; } else { key_provided = 0; - key = ieee->tx_keyidx; + key = ieee->crypt_info.tx_keyidx; } RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? "provided" : "default"); - crypt = &ieee->crypt[key]; + crypt = &ieee->crypt_info.crypt[key]; if (erq->flags & IW_ENCODE_DISABLED) { if (key_provided && *crypt) { RTLLIB_DEBUG_WX("Disabling encryption on key %d.\n", key); - rtllib_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } else RTLLIB_DEBUG_WX("Disabling encryption.\n"); /* Check all the keys to see if any are still configured, * and if no key index was provided, de-init them all */ - for (i = 0; i < WEP_KEYS; i++) { - if (ieee->crypt[i] != NULL) { + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ieee->crypt_info.crypt[i] != NULL) { if (key_provided) break; - rtllib_crypt_delayed_deinit(ieee, - &ieee->crypt[i]); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, + &ieee->crypt_info.crypt[i]); } } - if (i == WEP_KEYS) { + if (i == NUM_WEP_KEYS) { sec.enabled = 0; sec.level = SEC_LEVEL_0; sec.flags |= SEC_ENABLED | SEC_LEVEL; @@ -358,25 +358,24 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, sec.flags |= SEC_ENABLED; if (*crypt != NULL && (*crypt)->ops != NULL && - strcmp((*crypt)->ops->name, "WEP") != 0) { + strcmp((*crypt)->ops->name, "R-WEP") != 0) { /* changing to use WEP; deinit previously used algorithm * on this key */ - rtllib_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } if (*crypt == NULL) { - struct rtllib_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kmalloc(sizeof(struct rtllib_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - memset(new_crypt, 0, sizeof(struct rtllib_crypt_data)); - new_crypt->ops = rtllib_get_crypto_ops("WEP"); + new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); if (!new_crypt->ops) { request_module("rtllib_crypt_wep"); - new_crypt->ops = rtllib_get_crypto_ops("WEP"); + new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); } if (new_crypt->ops) @@ -412,7 +411,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, * explicitely set */ if (key == sec.active_key) sec.flags |= SEC_ACTIVE_KEY; - ieee->tx_keyidx = key; + ieee->crypt_info.tx_keyidx = key; } else { len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, @@ -435,7 +434,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, if (key_provided) { RTLLIB_DEBUG_WX( "Setting key %d to default Tx key.\n", key); - ieee->tx_keyidx = key; + ieee->crypt_info.tx_keyidx = key; sec.active_key = key; sec.flags |= SEC_ACTIVE_KEY; } @@ -470,6 +469,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, } return 0; } +EXPORT_SYMBOL(rtllib_wx_set_encode); int rtllib_wx_get_encode(struct rtllib_device *ieee, struct iw_request_info *info, @@ -477,7 +477,7 @@ int rtllib_wx_get_encode(struct rtllib_device *ieee, { struct iw_point *erq = &(wrqu->encoding); int len, key; - struct rtllib_crypt_data *crypt; + struct lib80211_crypt_data *crypt; RTLLIB_DEBUG_WX("GET_ENCODE\n"); @@ -486,13 +486,13 @@ int rtllib_wx_get_encode(struct rtllib_device *ieee, key = erq->flags & IW_ENCODE_INDEX; if (key) { - if (key > WEP_KEYS) + if (key > NUM_WEP_KEYS) return -EINVAL; key--; } else { - key = ieee->tx_keyidx; + key = ieee->crypt_info.tx_keyidx; } - crypt = ieee->crypt[key]; + crypt = ieee->crypt_info.crypt[key]; erq->flags = key + 1; @@ -513,6 +513,7 @@ int rtllib_wx_get_encode(struct rtllib_device *ieee, return 0; } +EXPORT_SYMBOL(rtllib_wx_get_encode); int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, struct iw_request_info *info, @@ -525,29 +526,29 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, int i, idx; int group_key = 0; const char *alg, *module; - struct rtllib_crypto_ops *ops; - struct rtllib_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; struct rtllib_security sec = { .flags = 0, }; idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > NUM_WEP_KEYS) return -EINVAL; idx--; } else{ - idx = ieee->tx_keyidx; + idx = ieee->crypt_info.tx_keyidx; } if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - crypt = &ieee->crypt[idx]; + crypt = &ieee->crypt_info.crypt[idx]; group_key = 1; } else { /* some Cisco APs use idx>0 for unicast in dynamic WEP */ if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) return -EINVAL; if (ieee->iw_mode == IW_MODE_INFRA) - crypt = &ieee->crypt[idx]; + crypt = &ieee->crypt_info.crypt[idx]; else return -EINVAL; } @@ -556,13 +557,13 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, if ((encoding->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - rtllib_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - for (i = 0; i < WEP_KEYS; i++) { - if (ieee->crypt[i] != NULL) + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ieee->crypt_info.crypt[i] != NULL) break; } - if (i == WEP_KEYS) { + if (i == NUM_WEP_KEYS) { sec.enabled = 0; sec.level = SEC_LEVEL_0; sec.flags |= SEC_LEVEL; @@ -573,15 +574,15 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, sec.enabled = 1; switch (ext->alg) { case IW_ENCODE_ALG_WEP: - alg = "WEP"; + alg = "R-WEP"; module = "rtllib_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: - alg = "TKIP"; + alg = "R-TKIP"; module = "rtllib_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: - alg = "CCMP"; + alg = "R-CCMP"; module = "rtllib_crypt_ccmp"; break; default: @@ -592,14 +593,14 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, } printk(KERN_INFO "alg name:%s\n", alg); - ops = rtllib_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); if (ops == NULL) { char tempbuf[100]; memset(tempbuf, 0x00, 100); sprintf(tempbuf, "%s", module); request_module("%s", tempbuf); - ops = rtllib_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -610,9 +611,9 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct rtllib_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - rtllib_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) { @@ -641,7 +642,7 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, goto done; } if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - ieee->tx_keyidx = idx; + ieee->crypt_info.tx_keyidx = idx; sec.active_key = idx; sec.flags |= SEC_ACTIVE_KEY; } @@ -674,6 +675,7 @@ done: } return ret; } +EXPORT_SYMBOL(rtllib_wx_set_encode_ext); int rtllib_wx_get_encode_ext(struct rtllib_device *ieee, struct iw_request_info *info, @@ -681,7 +683,7 @@ int rtllib_wx_get_encode_ext(struct rtllib_device *ieee, { struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct rtllib_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int idx, max_key_len; max_key_len = encoding->length - sizeof(*ext); @@ -690,18 +692,18 @@ int rtllib_wx_get_encode_ext(struct rtllib_device *ieee, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > NUM_WEP_KEYS) return -EINVAL; idx--; } else { - idx = ieee->tx_keyidx; + idx = ieee->crypt_info.tx_keyidx; } if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && (ext->alg != IW_ENCODE_ALG_WEP)) if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA)) return -EINVAL; - crypt = ieee->crypt[idx]; + crypt = ieee->crypt_info.crypt[idx]; encoding->flags = idx + 1; memset(ext, 0, sizeof(*ext)); @@ -711,11 +713,11 @@ int rtllib_wx_get_encode_ext(struct rtllib_device *ieee, ext->key_len = 0; encoding->flags |= IW_ENCODE_DISABLED; } else { - if (strcmp(crypt->ops->name, "WEP") == 0) + if (strcmp(crypt->ops->name, "R-WEP") == 0) ext->alg = IW_ENCODE_ALG_WEP; - else if (strcmp(crypt->ops->name, "TKIP")) + else if (strcmp(crypt->ops->name, "R-TKIP")) ext->alg = IW_ENCODE_ALG_TKIP; - else if (strcmp(crypt->ops->name, "CCMP")) + else if (strcmp(crypt->ops->name, "R-CCMP")) ext->alg = IW_ENCODE_ALG_CCMP; else return -EINVAL; @@ -778,6 +780,7 @@ int rtllib_wx_set_mlme(struct rtllib_device *ieee, return 0; } +EXPORT_SYMBOL(rtllib_wx_set_mlme); int rtllib_wx_set_auth(struct rtllib_device *ieee, struct iw_request_info *info, @@ -830,6 +833,7 @@ int rtllib_wx_set_auth(struct rtllib_device *ieee, } return 0; } +EXPORT_SYMBOL(rtllib_wx_set_auth); int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) { @@ -846,10 +850,9 @@ int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len) : (MAX_WZC_IE_LEN); - buf = kmalloc(ieee->wps_ie_len, GFP_KERNEL); + buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - memcpy(buf, ie, ieee->wps_ie_len); ieee->wps_ie = buf; return 0; } @@ -860,10 +863,9 @@ int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) if (len) { if (len != ie[1]+2) return -EINVAL; - buf = kmalloc(len, GFP_KERNEL); + buf = kmemdup(ie, len, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - memcpy(buf, ie, len); kfree(ieee->wpa_ie); ieee->wpa_ie = buf; ieee->wpa_ie_len = len; @@ -874,3 +876,4 @@ int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) } return 0; } +EXPORT_SYMBOL(rtllib_wx_set_gen_ie); diff --git a/drivers/staging/rtl8192u/ieee80211/api.c b/drivers/staging/rtl8192u/ieee80211/api.c deleted file mode 100644 index 5f46e50e586..00000000000 --- a/drivers/staging/rtl8192u/ieee80211/api.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Scatterlist Cryptographic API. - * - * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> - * Copyright (c) 2002 David S. Miller (davem@redhat.com) - * - * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> - * and Nettle, by Niels M鰈ler. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include "kmap_types.h" - -#include <linux/init.h> -#include <linux/module.h> -//#include <linux/crypto.h> -#include "rtl_crypto.h" -#include <linux/errno.h> -#include <linux/rwsem.h> -#include <linux/slab.h> -#include "internal.h" - -LIST_HEAD(crypto_alg_list); -DECLARE_RWSEM(crypto_alg_sem); - -static inline int crypto_alg_get(struct crypto_alg *alg) -{ - return try_inc_mod_count(alg->cra_module); -} - -static inline void crypto_alg_put(struct crypto_alg *alg) -{ - if (alg->cra_module) - __MOD_DEC_USE_COUNT(alg->cra_module); -} - -struct crypto_alg *crypto_alg_lookup(const char *name) -{ - struct crypto_alg *q, *alg = NULL; - - if (!name) - return NULL; - - down_read(&crypto_alg_sem); - - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (!(strcmp(q->cra_name, name))) { - if (crypto_alg_get(q)) - alg = q; - break; - } - } - - up_read(&crypto_alg_sem); - return alg; -} - -static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) -{ - tfm->crt_flags = 0; - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - return crypto_init_cipher_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_DIGEST: - return crypto_init_digest_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_COMPRESS: - return crypto_init_compress_flags(tfm, flags); - - default: - break; - } - - BUG(); - return -EINVAL; -} - -static int crypto_init_ops(struct crypto_tfm *tfm) -{ - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - return crypto_init_cipher_ops(tfm); - - case CRYPTO_ALG_TYPE_DIGEST: - return crypto_init_digest_ops(tfm); - - case CRYPTO_ALG_TYPE_COMPRESS: - return crypto_init_compress_ops(tfm); - - default: - break; - } - - BUG(); - return -EINVAL; -} - -static void crypto_exit_ops(struct crypto_tfm *tfm) -{ - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - crypto_exit_cipher_ops(tfm); - break; - - case CRYPTO_ALG_TYPE_DIGEST: - crypto_exit_digest_ops(tfm); - break; - - case CRYPTO_ALG_TYPE_COMPRESS: - crypto_exit_compress_ops(tfm); - break; - - default: - BUG(); - - } -} - -struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) -{ - struct crypto_tfm *tfm = NULL; - struct crypto_alg *alg; - - alg = crypto_alg_mod_lookup(name); - if (alg == NULL) - goto out; - - tfm = kzalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL); - if (tfm == NULL) - goto out_put; - - tfm->__crt_alg = alg; - - if (crypto_init_flags(tfm, flags)) - goto out_free_tfm; - - if (crypto_init_ops(tfm)) { - crypto_exit_ops(tfm); - goto out_free_tfm; - } - - goto out; - -out_free_tfm: - kfree(tfm); - tfm = NULL; -out_put: - crypto_alg_put(alg); -out: - return tfm; -} - -void crypto_free_tfm(struct crypto_tfm *tfm) -{ - struct crypto_alg *alg = tfm->__crt_alg; - int size = sizeof(*tfm) + alg->cra_ctxsize; - - crypto_exit_ops(tfm); - crypto_alg_put(alg); - memset(tfm, 0, size); - kfree(tfm); -} - -int crypto_register_alg(struct crypto_alg *alg) -{ - int ret = 0; - struct crypto_alg *q; - - down_write(&crypto_alg_sem); - - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (!(strcmp(q->cra_name, alg->cra_name))) { - ret = -EEXIST; - goto out; - } - } - - list_add_tail(&alg->cra_list, &crypto_alg_list); -out: - up_write(&crypto_alg_sem); - return ret; -} - -int crypto_unregister_alg(struct crypto_alg *alg) -{ - int ret = -ENOENT; - struct crypto_alg *q; - - BUG_ON(!alg->cra_module); - - down_write(&crypto_alg_sem); - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (alg == q) { - list_del(&alg->cra_list); - ret = 0; - goto out; - } - } -out: - up_write(&crypto_alg_sem); - return ret; -} - -int crypto_alg_available(const char *name, u32 flags) -{ - int ret = 0; - struct crypto_alg *alg = crypto_alg_mod_lookup(name); - - if (alg) { - crypto_alg_put(alg); - ret = 1; - } - - return ret; -} - -static int __init init_crypto(void) -{ - printk(KERN_INFO "Initializing Cryptographic API\n"); - crypto_init_proc(); - return 0; -} - -__initcall(init_crypto); - -/* -EXPORT_SYMBOL_GPL(crypto_register_alg); -EXPORT_SYMBOL_GPL(crypto_unregister_alg); -EXPORT_SYMBOL_GPL(crypto_alloc_tfm); -EXPORT_SYMBOL_GPL(crypto_free_tfm); -EXPORT_SYMBOL_GPL(crypto_alg_available); -*/ - -EXPORT_SYMBOL_NOVERS(crypto_register_alg); -EXPORT_SYMBOL_NOVERS(crypto_unregister_alg); -EXPORT_SYMBOL_NOVERS(crypto_alloc_tfm); -EXPORT_SYMBOL_NOVERS(crypto_free_tfm); -EXPORT_SYMBOL_NOVERS(crypto_alg_available); diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index ef8eb6c7ee4..4277d0304b7 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -551,7 +551,7 @@ void r8712_survey_event_callback(struct _adapter *adapter, u8 *pbuf) ibss_wlan = r8712_find_network( &pmlmepriv->scanned_queue, pnetwork->MacAddress); - if (!ibss_wlan) { + if (ibss_wlan) { memcpy(ibss_wlan->network.IEs, pnetwork->IEs, 8); goto exit; diff --git a/drivers/staging/rts5139/rts51x.h b/drivers/staging/rts5139/rts51x.h index 9415d5c0550..b2c58390bfc 100644 --- a/drivers/staging/rts5139/rts51x.h +++ b/drivers/staging/rts5139/rts51x.h @@ -34,7 +34,6 @@ #include <linux/mutex.h> #include <linux/cdrom.h> #include <linux/kernel.h> -#include <linux/version.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> diff --git a/drivers/staging/rts5139/rts51x_transport.h b/drivers/staging/rts5139/rts51x_transport.h index f7aa87f7f1a..8464c4836d5 100644 --- a/drivers/staging/rts5139/rts51x_transport.h +++ b/drivers/staging/rts5139/rts51x_transport.h @@ -28,7 +28,6 @@ #define __RTS51X_TRANSPORT_H #include <linux/kernel.h> -#include <linux/version.h> #include "rts51x.h" #include "rts51x_chip.h" diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index f47571ea745..6b3d156d414 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -2120,6 +2120,8 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, } } if (tail_size) { + if (tail_size > sizeof(dcb_table_ptr->tail_data)) + return -EINVAL; if (is_kva == true) { memcpy(dcb_table_ptr->tail_data, (void *)(app_in_address + data_in_size - diff --git a/drivers/staging/serial/68360serial.c b/drivers/staging/serial/68360serial.c index 0a3e8787ed5..daf0b1d0dc2 100644 --- a/drivers/staging/serial/68360serial.c +++ b/drivers/staging/serial/68360serial.c @@ -2771,8 +2771,8 @@ static int __init rs_360_init(void) */ /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info); */ /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */ - request_irq(state->irq, rs_360_interrupt, - IRQ_FLG_LOCK, "ttyS", (void *)info); + request_irq(state->irq, rs_360_interrupt, 0, "ttyS", + (void *)info); /* Set up the baud rate generator. */ diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c index 39dbf339a4f..ae0035f327e 100644 --- a/drivers/staging/sm7xx/smtcfb.c +++ b/drivers/staging/sm7xx/smtcfb.c @@ -1024,9 +1024,9 @@ failed_free: /* Jason (08/11/2009) PCI_DRV wrapper essential structs */ static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = { - {0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_DEVICE(0x126f, 0x710), }, + { PCI_DEVICE(0x126f, 0x712), }, + { PCI_DEVICE(0x126f, 0x720), }, {0,} }; diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c index 07a7f543259..2093896c546 100644 --- a/drivers/staging/speakup/kobjects.c +++ b/drivers/staging/speakup/kobjects.c @@ -265,12 +265,11 @@ static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr, unsigned long flags; spk_lock(flags); - in_buff = kmalloc(count + 1, GFP_ATOMIC); + in_buff = kmemdup(buf, count + 1, GFP_ATOMIC); if (!in_buff) { spk_unlock(flags); return -ENOMEM; } - memcpy(in_buff, buf, count + 1); if (strchr("dDrR", *in_buff)) { set_key_info(key_defaults, key_buf); pr_info("keymap set to default values\n"); diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index 8be56045897..c7b03f0ef2d 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -2268,8 +2268,6 @@ static int __init speakup_init(void) set_mask_bits(0, i, 2); set_key_info(key_defaults, key_buf); - if (quiet_boot) - spk_shut_up |= 0x01; /* From here on out, initializations can fail. */ err = speakup_add_virtual_keyboard(); @@ -2292,6 +2290,9 @@ static int __init speakup_init(void) goto error_kobjects; } + if (quiet_boot) + spk_shut_up |= 0x01; + err = speakup_kobj_init(); if (err) goto error_kobjects; diff --git a/drivers/staging/spectra/Kconfig b/drivers/staging/spectra/Kconfig deleted file mode 100644 index 4fc20648483..00000000000 --- a/drivers/staging/spectra/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ - -menuconfig SPECTRA - tristate "Denali Spectra Flash Translation Layer" - depends on BLOCK - depends on X86_MRST - default n - ---help--- - Enable the FTL pseudo-filesystem used with the NAND Flash - controller on Intel Moorestown Platform to pretend to be a disk. - -choice - prompt "Compile for" - depends on SPECTRA - default SPECTRA_MRST_HW - -config SPECTRA_MRST_HW - bool "Moorestown hardware mode" - help - Driver communicates with the Moorestown hardware's register interface. - in DMA mode. - -config SPECTRA_MTD - bool "Linux MTD mode" - depends on MTD - help - Driver communicates with the kernel MTD subsystem instead of its own - built-in hardware driver. - -config SPECTRA_EMU - bool "RAM emulator testing" - help - Driver emulates Flash on a RAM buffer and / or disk file. Useful to test the behavior of FTL layer. - -endchoice - -config SPECTRA_MRST_HW_DMA - bool - default n - depends on SPECTRA_MRST_HW - help - Use DMA for native hardware interface. diff --git a/drivers/staging/spectra/Makefile b/drivers/staging/spectra/Makefile deleted file mode 100644 index f777dfba05a..00000000000 --- a/drivers/staging/spectra/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile of Intel Moorestown NAND controller driver -# - -obj-$(CONFIG_SPECTRA) += spectra.o -spectra-y := ffsport.o flash.o lld.o -spectra-$(CONFIG_SPECTRA_MRST_HW) += lld_nand.o -spectra-$(CONFIG_SPECTRA_MRST_HW_DMA) += lld_cdma.o -spectra-$(CONFIG_SPECTRA_EMU) += lld_emu.o -spectra-$(CONFIG_SPECTRA_MTD) += lld_mtd.o - diff --git a/drivers/staging/spectra/README b/drivers/staging/spectra/README deleted file mode 100644 index ecba559b899..00000000000 --- a/drivers/staging/spectra/README +++ /dev/null @@ -1,29 +0,0 @@ -This is a driver for NAND controller of Intel Moorestown platform. - -This driver is a standalone linux block device driver, it acts as if it's a normal hard disk. -It includes three layer: - block layer interface - file ffsport.c - Flash Translation Layer (FTL) - file flash.c (implement the NAND flash Translation Layer, includs address mapping, garbage collection, wear-leveling and so on) - Low level layer - file lld_nand.c/lld_cdma.c/lld_emu.c (which implements actual controller hardware registers access) - -This driver can be build as modules or build-in. - -Dependency: -This driver has dependency on IA Firmware of Intel Moorestown platform. -It need the IA Firmware to create the block table for the first time. -And to validate this driver code without IA Firmware, you can change the -macro AUTO_FORMAT_FLASH from 0 to 1 in file spectraswconfig.h. Thus the -driver will erase the whole nand flash and create a new block table. - -TODO: - - Enable Command DMA feature support - - lower the memory footprint - - Remove most of the unnecessary global variables - - Change all the upcase variable / functions name to lowercase - - Some other misc bugs - -Please send patches to: - Greg Kroah-Hartman <gregkh@suse.de> - -And Cc to: Gao Yunpeng <yunpeng.gao@intel.com> - diff --git a/drivers/staging/spectra/ffsdefs.h b/drivers/staging/spectra/ffsdefs.h deleted file mode 100644 index a9e9cd233d2..00000000000 --- a/drivers/staging/spectra/ffsdefs.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#ifndef _FFSDEFS_ -#define _FFSDEFS_ - -#define CLEAR 0 /*use this to clear a field instead of "fail"*/ -#define SET 1 /*use this to set a field instead of "pass"*/ -#define FAIL 1 /*failed flag*/ -#define PASS 0 /*success flag*/ -#define ERR -1 /*error flag*/ - -#define ERASE_CMD 10 -#define WRITE_MAIN_CMD 11 -#define READ_MAIN_CMD 12 -#define WRITE_SPARE_CMD 13 -#define READ_SPARE_CMD 14 -#define WRITE_MAIN_SPARE_CMD 15 -#define READ_MAIN_SPARE_CMD 16 -#define MEMCOPY_CMD 17 -#define DUMMY_CMD 99 - -#define EVENT_PASS 0x00 -#define EVENT_CORRECTABLE_DATA_ERROR_FIXED 0x01 -#define EVENT_UNCORRECTABLE_DATA_ERROR 0x02 -#define EVENT_TIME_OUT 0x03 -#define EVENT_PROGRAM_FAILURE 0x04 -#define EVENT_ERASE_FAILURE 0x05 -#define EVENT_MEMCOPY_FAILURE 0x06 -#define EVENT_FAIL 0x07 - -#define EVENT_NONE 0x22 -#define EVENT_DMA_CMD_COMP 0x77 -#define EVENT_ECC_TRANSACTION_DONE 0x88 -#define EVENT_DMA_CMD_FAIL 0x99 - -#define CMD_PASS 0 -#define CMD_FAIL 1 -#define CMD_ABORT 2 -#define CMD_NOT_DONE 3 - -#endif /* _FFSDEFS_ */ diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c deleted file mode 100644 index 86d556d6cf9..00000000000 --- a/drivers/staging/spectra/ffsport.c +++ /dev/null @@ -1,834 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#include "ffsport.h" -#include "flash.h" -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/blkdev.h> -#include <linux/wait.h> -#include <linux/mutex.h> -#include <linux/kthread.h> -#include <linux/log2.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/async.h> - -/**** Helper functions used for Div, Remainder operation on u64 ****/ - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_Calc_Used_Bits -* Inputs: Power of 2 number -* Outputs: Number of Used Bits -* 0, if the argument is 0 -* Description: Calculate the number of bits used by a given power of 2 number -* Number can be up to 32 bit -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_Calc_Used_Bits(u32 n) -{ - int tot_bits = 0; - - if (n >= 1 << 16) { - n >>= 16; - tot_bits += 16; - } - - if (n >= 1 << 8) { - n >>= 8; - tot_bits += 8; - } - - if (n >= 1 << 4) { - n >>= 4; - tot_bits += 4; - } - - if (n >= 1 << 2) { - n >>= 2; - tot_bits += 2; - } - - if (n >= 1 << 1) - tot_bits += 1; - - return ((n == 0) ? (0) : tot_bits); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_u64_Div -* Inputs: Number of u64 -* A power of 2 number as Division -* Outputs: Quotient of the Divisor operation -* Description: It divides the address by divisor by using bit shift operation -* (essentially without explicitely using "/"). -* Divisor is a power of 2 number and Divided is of u64 -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u64 GLOB_u64_Div(u64 addr, u32 divisor) -{ - return (u64)(addr >> GLOB_Calc_Used_Bits(divisor)); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_u64_Remainder -* Inputs: Number of u64 -* Divisor Type (1 -PageAddress, 2- BlockAddress) -* Outputs: Remainder of the Division operation -* Description: It calculates the remainder of a number (of u64) by -* divisor(power of 2 number ) by using bit shifting and multiply -* operation(essentially without explicitely using "/"). -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type) -{ - u64 result = 0; - - if (divisor_type == 1) { /* Remainder -- Page */ - result = (addr >> DeviceInfo.nBitsInPageDataSize); - result = result * DeviceInfo.wPageDataSize; - } else if (divisor_type == 2) { /* Remainder -- Block */ - result = (addr >> DeviceInfo.nBitsInBlockDataSize); - result = result * DeviceInfo.wBlockDataSize; - } - - result = addr - result; - - return result; -} - -#define NUM_DEVICES 1 -#define PARTITIONS 8 - -#define GLOB_SBD_NAME "nd" -#define GLOB_SBD_IRQ_NUM (29) - -#define GLOB_SBD_IOCTL_GC (0x7701) -#define GLOB_SBD_IOCTL_WL (0x7702) -#define GLOB_SBD_IOCTL_FORMAT (0x7703) -#define GLOB_SBD_IOCTL_ERASE_FLASH (0x7704) -#define GLOB_SBD_IOCTL_FLUSH_CACHE (0x7705) -#define GLOB_SBD_IOCTL_COPY_BLK_TABLE (0x7706) -#define GLOB_SBD_IOCTL_COPY_WEAR_LEVELING_TABLE (0x7707) -#define GLOB_SBD_IOCTL_GET_NAND_INFO (0x7708) -#define GLOB_SBD_IOCTL_WRITE_DATA (0x7709) -#define GLOB_SBD_IOCTL_READ_DATA (0x770A) - -static int reserved_mb = 0; -module_param(reserved_mb, int, 0); -MODULE_PARM_DESC(reserved_mb, "Reserved space for OS image, in MiB (default 25 MiB)"); - -int nand_debug_level; -module_param(nand_debug_level, int, 0644); -MODULE_PARM_DESC(nand_debug_level, "debug level value: 1-3"); - -MODULE_LICENSE("GPL"); - -struct spectra_nand_dev { - struct pci_dev *dev; - u64 size; - u16 users; - spinlock_t qlock; - void __iomem *ioaddr; /* Mapped address */ - struct request_queue *queue; - struct task_struct *thread; - struct gendisk *gd; - u8 *tmp_buf; -}; - - -static int GLOB_SBD_majornum; - -static char *GLOB_version = GLOB_VERSION; - -static struct spectra_nand_dev nand_device[NUM_DEVICES]; - -static struct mutex spectra_lock; - -static int res_blks_os = 1; - -struct spectra_indentfy_dev_tag IdentifyDeviceData; - -static int force_flush_cache(void) -{ - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (ERR == GLOB_FTL_Flush_Cache()) { - printk(KERN_ERR "Fail to Flush FTL Cache!\n"); - return -EFAULT; - } -#if CMD_DMA - if (glob_ftl_execute_cmds()) - return -EIO; - else - return 0; -#endif - return 0; -} - -struct ioctl_rw_page_info { - u8 *data; - unsigned int page; -}; - -static int ioctl_read_page_data(unsigned long arg) -{ - u8 *buf; - struct ioctl_rw_page_info info; - int result = PASS; - - if (copy_from_user(&info, (void __user *)arg, sizeof(info))) - return -EFAULT; - - buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC); - if (!buf) { - printk(KERN_ERR "ioctl_read_page_data: " - "failed to allocate memory\n"); - return -ENOMEM; - } - - mutex_lock(&spectra_lock); - result = GLOB_FTL_Page_Read(buf, - (u64)info.page * IdentifyDeviceData.PageDataSize); - mutex_unlock(&spectra_lock); - - if (copy_to_user((void __user *)info.data, buf, - IdentifyDeviceData.PageDataSize)) { - printk(KERN_ERR "ioctl_read_page_data: " - "failed to copy user data\n"); - kfree(buf); - return -EFAULT; - } - - kfree(buf); - return result; -} - -static int ioctl_write_page_data(unsigned long arg) -{ - u8 *buf; - struct ioctl_rw_page_info info; - int result = PASS; - - if (copy_from_user(&info, (void __user *)arg, sizeof(info))) - return -EFAULT; - - buf = memdup_user((void __user *)info.data, - IdentifyDeviceData.PageDataSize); - if (IS_ERR(buf)) { - printk(KERN_ERR "ioctl_write_page_data: " - "failed to copy user data\n"); - return PTR_ERR(buf); - } - - mutex_lock(&spectra_lock); - result = GLOB_FTL_Page_Write(buf, - (u64)info.page * IdentifyDeviceData.PageDataSize); - mutex_unlock(&spectra_lock); - - kfree(buf); - return result; -} - -/* Return how many blocks should be reserved for bad block replacement */ -static int get_res_blk_num_bad_blk(void) -{ - return IdentifyDeviceData.wDataBlockNum / 10; -} - -/* Return how many blocks should be reserved for OS image */ -static int get_res_blk_num_os(void) -{ - u32 res_blks, blk_size; - - blk_size = IdentifyDeviceData.PageDataSize * - IdentifyDeviceData.PagesPerBlock; - - res_blks = (reserved_mb * 1024 * 1024) / blk_size; - - if ((res_blks < 1) || (res_blks >= IdentifyDeviceData.wDataBlockNum)) - res_blks = 1; /* Reserved 1 block for block table */ - - return res_blks; -} - -/* Transfer a full request. */ -static int do_transfer(struct spectra_nand_dev *tr, struct request *req) -{ - u64 start_addr, addr; - u32 logical_start_sect, hd_start_sect; - u32 nsect, hd_sects; - u32 rsect, tsect = 0; - char *buf; - u32 ratio = IdentifyDeviceData.PageDataSize >> 9; - - start_addr = (u64)(blk_rq_pos(req)) << 9; - /* Add a big enough offset to prevent the OS Image from - * being accessed or damaged by file system */ - start_addr += IdentifyDeviceData.PageDataSize * - IdentifyDeviceData.PagesPerBlock * - res_blks_os; - - if (req->cmd_type & REQ_FLUSH) { - if (force_flush_cache()) /* Fail to flush cache */ - return -EIO; - else - return 0; - } - - if (req->cmd_type != REQ_TYPE_FS) - return -EIO; - - if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > get_capacity(tr->gd)) { - printk(KERN_ERR "Spectra error: request over the NAND " - "capacity!sector %d, current_nr_sectors %d, " - "while capacity is %d\n", - (int)blk_rq_pos(req), - blk_rq_cur_sectors(req), - (int)get_capacity(tr->gd)); - return -EIO; - } - - logical_start_sect = start_addr >> 9; - hd_start_sect = logical_start_sect / ratio; - rsect = logical_start_sect - hd_start_sect * ratio; - - addr = (u64)hd_start_sect * ratio * 512; - buf = req->buffer; - nsect = blk_rq_cur_sectors(req); - - if (rsect) - tsect = (ratio - rsect) < nsect ? (ratio - rsect) : nsect; - - switch (rq_data_dir(req)) { - case READ: - /* Read the first NAND page */ - if (rsect) { - if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - memcpy(buf, tr->tmp_buf + (rsect << 9), tsect << 9); - addr += IdentifyDeviceData.PageDataSize; - buf += tsect << 9; - nsect -= tsect; - } - - /* Read the other NAND pages */ - for (hd_sects = nsect / ratio; hd_sects > 0; hd_sects--) { - if (GLOB_FTL_Page_Read(buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - addr += IdentifyDeviceData.PageDataSize; - buf += IdentifyDeviceData.PageDataSize; - } - - /* Read the last NAND pages */ - if (nsect % ratio) { - if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - memcpy(buf, tr->tmp_buf, (nsect % ratio) << 9); - } -#if CMD_DMA - if (glob_ftl_execute_cmds()) - return -EIO; - else - return 0; -#endif - return 0; - - case WRITE: - /* Write the first NAND page */ - if (rsect) { - if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - memcpy(tr->tmp_buf + (rsect << 9), buf, tsect << 9); - if (GLOB_FTL_Page_Write(tr->tmp_buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - addr += IdentifyDeviceData.PageDataSize; - buf += tsect << 9; - nsect -= tsect; - } - - /* Write the other NAND pages */ - for (hd_sects = nsect / ratio; hd_sects > 0; hd_sects--) { - if (GLOB_FTL_Page_Write(buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - addr += IdentifyDeviceData.PageDataSize; - buf += IdentifyDeviceData.PageDataSize; - } - - /* Write the last NAND pages */ - if (nsect % ratio) { - if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - memcpy(tr->tmp_buf, buf, (nsect % ratio) << 9); - if (GLOB_FTL_Page_Write(tr->tmp_buf, addr)) { - printk(KERN_ERR "Error in %s, Line %d\n", - __FILE__, __LINE__); - return -EIO; - } - } -#if CMD_DMA - if (glob_ftl_execute_cmds()) - return -EIO; - else - return 0; -#endif - return 0; - - default: - printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); - return -EIO; - } -} - -/* This function is copied from drivers/mtd/mtd_blkdevs.c */ -static int spectra_trans_thread(void *arg) -{ - struct spectra_nand_dev *tr = arg; - struct request_queue *rq = tr->queue; - struct request *req = NULL; - - /* we might get involved when memory gets low, so use PF_MEMALLOC */ - current->flags |= PF_MEMALLOC; - - spin_lock_irq(rq->queue_lock); - while (!kthread_should_stop()) { - int res; - - if (!req) { - req = blk_fetch_request(rq); - if (!req) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(rq->queue_lock); - schedule(); - spin_lock_irq(rq->queue_lock); - continue; - } - } - - spin_unlock_irq(rq->queue_lock); - - mutex_lock(&spectra_lock); - res = do_transfer(tr, req); - mutex_unlock(&spectra_lock); - - spin_lock_irq(rq->queue_lock); - - if (!__blk_end_request_cur(req, res)) - req = NULL; - } - - if (req) - __blk_end_request_all(req, -EIO); - - spin_unlock_irq(rq->queue_lock); - - return 0; -} - - -/* Request function that "handles clustering". */ -static void GLOB_SBD_request(struct request_queue *rq) -{ - struct spectra_nand_dev *pdev = rq->queuedata; - wake_up_process(pdev->thread); -} - -static int GLOB_SBD_open(struct block_device *bdev, fmode_t mode) - -{ - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - return 0; -} - -static int GLOB_SBD_release(struct gendisk *disk, fmode_t mode) -{ - int ret; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - mutex_lock(&spectra_lock); - ret = force_flush_cache(); - mutex_unlock(&spectra_lock); - - return 0; -} - -static int GLOB_SBD_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - geo->heads = 4; - geo->sectors = 16; - geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16); - - nand_dbg_print(NAND_DBG_DEBUG, - "heads: %d, sectors: %d, cylinders: %d\n", - geo->heads, geo->sectors, geo->cylinders); - - return 0; -} - -int GLOB_SBD_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int ret; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - switch (cmd) { - case GLOB_SBD_IOCTL_GC: - nand_dbg_print(NAND_DBG_DEBUG, - "Spectra IOCTL: Garbage Collection " - "being performed\n"); - if (PASS != GLOB_FTL_Garbage_Collection()) - return -EFAULT; - return 0; - - case GLOB_SBD_IOCTL_WL: - nand_dbg_print(NAND_DBG_DEBUG, - "Spectra IOCTL: Static Wear Leveling " - "being performed\n"); - if (PASS != GLOB_FTL_Wear_Leveling()) - return -EFAULT; - return 0; - - case GLOB_SBD_IOCTL_FORMAT: - nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: Flash format " - "being performed\n"); - if (PASS != GLOB_FTL_Flash_Format()) - return -EFAULT; - return 0; - - case GLOB_SBD_IOCTL_FLUSH_CACHE: - nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: Cache flush " - "being performed\n"); - mutex_lock(&spectra_lock); - ret = force_flush_cache(); - mutex_unlock(&spectra_lock); - return ret; - - case GLOB_SBD_IOCTL_COPY_BLK_TABLE: - nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: " - "Copy block table\n"); - if (copy_to_user((void __user *)arg, - get_blk_table_start_addr(), - get_blk_table_len())) - return -EFAULT; - return 0; - - case GLOB_SBD_IOCTL_COPY_WEAR_LEVELING_TABLE: - nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: " - "Copy wear leveling table\n"); - if (copy_to_user((void __user *)arg, - get_wear_leveling_table_start_addr(), - get_wear_leveling_table_len())) - return -EFAULT; - return 0; - - case GLOB_SBD_IOCTL_GET_NAND_INFO: - nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: " - "Get NAND info\n"); - if (copy_to_user((void __user *)arg, &IdentifyDeviceData, - sizeof(IdentifyDeviceData))) - return -EFAULT; - return 0; - - case GLOB_SBD_IOCTL_WRITE_DATA: - nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: " - "Write one page data\n"); - return ioctl_write_page_data(arg); - - case GLOB_SBD_IOCTL_READ_DATA: - nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: " - "Read one page data\n"); - return ioctl_read_page_data(arg); - } - - return -ENOTTY; -} - -static DEFINE_MUTEX(ffsport_mutex); - -int GLOB_SBD_unlocked_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&ffsport_mutex); - ret = GLOB_SBD_ioctl(bdev, mode, cmd, arg); - mutex_unlock(&ffsport_mutex); - - return ret; -} - -static struct block_device_operations GLOB_SBD_ops = { - .owner = THIS_MODULE, - .open = GLOB_SBD_open, - .release = GLOB_SBD_release, - .ioctl = GLOB_SBD_unlocked_ioctl, - .getgeo = GLOB_SBD_getgeo, -}; - -static int SBD_setup_device(struct spectra_nand_dev *dev, int which) -{ - int res_blks; - u32 sects; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - memset(dev, 0, sizeof(struct spectra_nand_dev)); - - nand_dbg_print(NAND_DBG_WARN, "Reserved %d blocks " - "for OS image, %d blocks for bad block replacement.\n", - get_res_blk_num_os(), - get_res_blk_num_bad_blk()); - - res_blks = get_res_blk_num_bad_blk() + get_res_blk_num_os(); - - dev->size = (u64)IdentifyDeviceData.PageDataSize * - IdentifyDeviceData.PagesPerBlock * - (IdentifyDeviceData.wDataBlockNum - res_blks); - - res_blks_os = get_res_blk_num_os(); - - spin_lock_init(&dev->qlock); - - dev->tmp_buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC); - if (!dev->tmp_buf) { - printk(KERN_ERR "Failed to kmalloc memory in %s Line %d, exit.\n", - __FILE__, __LINE__); - goto out_vfree; - } - - dev->queue = blk_init_queue(GLOB_SBD_request, &dev->qlock); - if (dev->queue == NULL) { - printk(KERN_ERR - "Spectra: Request queue could not be initialized." - " Aborting\n "); - goto out_vfree; - } - dev->queue->queuedata = dev; - - /* As Linux block layer doesn't support >4KB hardware sector, */ - /* Here we force report 512 byte hardware sector size to Kernel */ - blk_queue_logical_block_size(dev->queue, 512); - - blk_queue_flush(dev->queue, REQ_FLUSH); - - dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd"); - if (IS_ERR(dev->thread)) { - blk_cleanup_queue(dev->queue); - unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME); - return PTR_ERR(dev->thread); - } - - dev->gd = alloc_disk(PARTITIONS); - if (!dev->gd) { - printk(KERN_ERR - "Spectra: Could not allocate disk. Aborting \n "); - goto out_vfree; - } - dev->gd->major = GLOB_SBD_majornum; - dev->gd->first_minor = which * PARTITIONS; - dev->gd->fops = &GLOB_SBD_ops; - dev->gd->queue = dev->queue; - dev->gd->private_data = dev; - snprintf(dev->gd->disk_name, 32, "%s%c", GLOB_SBD_NAME, which + 'a'); - - sects = dev->size >> 9; - nand_dbg_print(NAND_DBG_WARN, "Capacity sects: %d\n", sects); - set_capacity(dev->gd, sects); - - add_disk(dev->gd); - - return 0; -out_vfree: - return -ENOMEM; -} - -/* -static ssize_t show_nand_block_num(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - (int)IdentifyDeviceData.wDataBlockNum); -} - -static ssize_t show_nand_pages_per_block(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - (int)IdentifyDeviceData.PagesPerBlock); -} - -static ssize_t show_nand_page_size(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - (int)IdentifyDeviceData.PageDataSize); -} - -static DEVICE_ATTR(nand_block_num, 0444, show_nand_block_num, NULL); -static DEVICE_ATTR(nand_pages_per_block, 0444, show_nand_pages_per_block, NULL); -static DEVICE_ATTR(nand_page_size, 0444, show_nand_page_size, NULL); - -static void create_sysfs_entry(struct device *dev) -{ - if (device_create_file(dev, &dev_attr_nand_block_num)) - printk(KERN_ERR "Spectra: " - "failed to create sysfs entry nand_block_num.\n"); - if (device_create_file(dev, &dev_attr_nand_pages_per_block)) - printk(KERN_ERR "Spectra: " - "failed to create sysfs entry nand_pages_per_block.\n"); - if (device_create_file(dev, &dev_attr_nand_page_size)) - printk(KERN_ERR "Spectra: " - "failed to create sysfs entry nand_page_size.\n"); -} -*/ - -static void register_spectra_ftl_async(void *unused, async_cookie_t cookie) -{ - int i; - - /* create_sysfs_entry(&dev->dev); */ - - if (PASS != GLOB_FTL_IdentifyDevice(&IdentifyDeviceData)) { - printk(KERN_ERR "Spectra: Unable to Read Flash Device. " - "Aborting\n"); - return; - } else { - nand_dbg_print(NAND_DBG_WARN, "In GLOB_SBD_init: " - "Num blocks=%d, pagesperblock=%d, " - "pagedatasize=%d, ECCBytesPerSector=%d\n", - (int)IdentifyDeviceData.NumBlocks, - (int)IdentifyDeviceData.PagesPerBlock, - (int)IdentifyDeviceData.PageDataSize, - (int)IdentifyDeviceData.wECCBytesPerSector); - } - - printk(KERN_ALERT "Spectra: searching block table, please wait ...\n"); - if (GLOB_FTL_Init() != PASS) { - printk(KERN_ERR "Spectra: Unable to Initialize FTL Layer. " - "Aborting\n"); - goto out_ftl_flash_register; - } - printk(KERN_ALERT "Spectra: block table has been found.\n"); - - GLOB_SBD_majornum = register_blkdev(0, GLOB_SBD_NAME); - if (GLOB_SBD_majornum <= 0) { - printk(KERN_ERR "Unable to get the major %d for Spectra", - GLOB_SBD_majornum); - goto out_ftl_flash_register; - } - - for (i = 0; i < NUM_DEVICES; i++) - if (SBD_setup_device(&nand_device[i], i) == -ENOMEM) - goto out_blk_register; - - nand_dbg_print(NAND_DBG_DEBUG, - "Spectra: module loaded with major number %d\n", - GLOB_SBD_majornum); - - return; - -out_blk_register: - unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME); -out_ftl_flash_register: - GLOB_FTL_Cache_Release(); - printk(KERN_ERR "Spectra: Module load failed.\n"); -} - -int register_spectra_ftl() -{ - async_schedule(register_spectra_ftl_async, NULL); - return 0; -} -EXPORT_SYMBOL_GPL(register_spectra_ftl); - -static int GLOB_SBD_init(void) -{ - /* Set debug output level (0~3) here. 3 is most verbose */ - printk(KERN_ALERT "Spectra: %s\n", GLOB_version); - - mutex_init(&spectra_lock); - - if (PASS != GLOB_FTL_Flash_Init()) { - printk(KERN_ERR "Spectra: Unable to Initialize Flash Device. " - "Aborting\n"); - return -ENODEV; - } - return 0; -} - -static void __exit GLOB_SBD_exit(void) -{ - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < NUM_DEVICES; i++) { - struct spectra_nand_dev *dev = &nand_device[i]; - if (dev->gd) { - del_gendisk(dev->gd); - put_disk(dev->gd); - } - if (dev->queue) - blk_cleanup_queue(dev->queue); - kfree(dev->tmp_buf); - } - - unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME); - - mutex_lock(&spectra_lock); - force_flush_cache(); - mutex_unlock(&spectra_lock); - - GLOB_FTL_Cache_Release(); - - GLOB_FTL_Flash_Release(); - - nand_dbg_print(NAND_DBG_DEBUG, - "Spectra FTL module (major number %d) unloaded.\n", - GLOB_SBD_majornum); -} - -module_init(GLOB_SBD_init); -module_exit(GLOB_SBD_exit); diff --git a/drivers/staging/spectra/ffsport.h b/drivers/staging/spectra/ffsport.h deleted file mode 100644 index 85c0750612f..00000000000 --- a/drivers/staging/spectra/ffsport.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#ifndef _FFSPORT_ -#define _FFSPORT_ - -#include "ffsdefs.h" - -#if defined __GNUC__ -#define PACKED -#define PACKED_GNU __attribute__ ((packed)) -#define UNALIGNED -#endif - -#include <linux/semaphore.h> -#include <linux/string.h> /* for strcpy(), stricmp(), etc */ -#include <linux/mm.h> /* for kmalloc(), kfree() */ -#include <linux/vmalloc.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> - -#include <linux/kernel.h> /* printk() */ -#include <linux/fs.h> /* everything... */ -#include <linux/errno.h> /* error codes */ -#include <linux/types.h> /* size_t */ -#include <linux/genhd.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/pci.h> -#include "flash.h" - -#define VERBOSE 1 - -#define NAND_DBG_WARN 1 -#define NAND_DBG_DEBUG 2 -#define NAND_DBG_TRACE 3 - -extern int nand_debug_level; - -#ifdef VERBOSE -#define nand_dbg_print(level, args...) \ - do { \ - if (level <= nand_debug_level) \ - printk(KERN_ALERT args); \ - } while (0) -#else -#define nand_dbg_print(level, args...) -#endif - -#ifdef SUPPORT_BIG_ENDIAN -#define INVERTUINT16(w) ((u16)(((u16)(w)) << 8) | \ - (u16)((u16)(w) >> 8)) - -#define INVERTUINT32(dw) (((u32)(dw) << 24) | \ - (((u32)(dw) << 8) & 0x00ff0000) | \ - (((u32)(dw) >> 8) & 0x0000ff00) | \ - ((u32)(dw) >> 24)) -#else -#define INVERTUINT16(w) w -#define INVERTUINT32(dw) dw -#endif - -extern int GLOB_Calc_Used_Bits(u32 n); -extern u64 GLOB_u64_Div(u64 addr, u32 divisor); -extern u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type); -extern int register_spectra_ftl(void); - -#endif /* _FFSPORT_ */ diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c deleted file mode 100644 index aead358e5c2..00000000000 --- a/drivers/staging/spectra/flash.c +++ /dev/null @@ -1,4305 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#include <linux/fs.h> -#include <linux/slab.h> - -#include "flash.h" -#include "ffsdefs.h" -#include "lld.h" -#include "lld_nand.h" -#if CMD_DMA -#include "lld_cdma.h" -#endif - -#define BLK_FROM_ADDR(addr) ((u32)(addr >> DeviceInfo.nBitsInBlockDataSize)) -#define PAGE_FROM_ADDR(addr, Block) ((u16)((addr - (u64)Block * \ - DeviceInfo.wBlockDataSize) >> DeviceInfo.nBitsInPageDataSize)) - -#define IS_SPARE_BLOCK(blk) (BAD_BLOCK != (pbt[blk] &\ - BAD_BLOCK) && SPARE_BLOCK == (pbt[blk] & SPARE_BLOCK)) - -#define IS_DATA_BLOCK(blk) (0 == (pbt[blk] & BAD_BLOCK)) - -#define IS_DISCARDED_BLOCK(blk) (BAD_BLOCK != (pbt[blk] &\ - BAD_BLOCK) && DISCARD_BLOCK == (pbt[blk] & DISCARD_BLOCK)) - -#define IS_BAD_BLOCK(blk) (BAD_BLOCK == (pbt[blk] & BAD_BLOCK)) - -#if DEBUG_BNDRY -void debug_boundary_lineno_error(int chnl, int limit, int no, - int lineno, char *filename) -{ - if (chnl >= limit) - printk(KERN_ERR "Boundary Check Fail value %d >= limit %d, " - "at %s:%d. Other info:%d. Aborting...\n", - chnl, limit, filename, lineno, no); -} -/* static int globalmemsize; */ -#endif - -static u16 FTL_Cache_If_Hit(u64 dwPageAddr); -static int FTL_Cache_Read(u64 dwPageAddr); -static void FTL_Cache_Read_Page(u8 *pData, u64 dwPageAddr, - u16 cache_blk); -static void FTL_Cache_Write_Page(u8 *pData, u64 dwPageAddr, - u8 cache_blk, u16 flag); -static int FTL_Cache_Write(void); -static void FTL_Calculate_LRU(void); -static u32 FTL_Get_Block_Index(u32 wBlockNum); - -static int FTL_Search_Block_Table_IN_Block(u32 BT_Block, - u8 BT_Tag, u16 *Page); -static int FTL_Read_Block_Table(void); -static int FTL_Write_Block_Table(int wForce); -static int FTL_Write_Block_Table_Data(void); -static int FTL_Check_Block_Table(int wOldTable); -static int FTL_Static_Wear_Leveling(void); -static u32 FTL_Replace_Block_Table(void); -static int FTL_Write_IN_Progress_Block_Table_Page(void); - -static u32 FTL_Get_Page_Num(u64 length); -static u64 FTL_Get_Physical_Block_Addr(u64 blk_addr); - -static u32 FTL_Replace_OneBlock(u32 wBlockNum, - u32 wReplaceNum); -static u32 FTL_Replace_LWBlock(u32 wBlockNum, - int *pGarbageCollect); -static u32 FTL_Replace_MWBlock(void); -static int FTL_Replace_Block(u64 blk_addr); -static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX); - -struct device_info_tag DeviceInfo; -struct flash_cache_tag Cache; -static struct spectra_l2_cache_info cache_l2; - -static u8 *cache_l2_page_buf; -static u8 *cache_l2_blk_buf; - -u8 *g_pBlockTable; -u8 *g_pWearCounter; -u16 *g_pReadCounter; -u32 *g_pBTBlocks; -static u16 g_wBlockTableOffset; -static u32 g_wBlockTableIndex; -static u8 g_cBlockTableStatus; - -static u8 *g_pTempBuf; -static u8 *flag_check_blk_table; -static u8 *tmp_buf_search_bt_in_block; -static u8 *spare_buf_search_bt_in_block; -static u8 *spare_buf_bt_search_bt_in_block; -static u8 *tmp_buf1_read_blk_table; -static u8 *tmp_buf2_read_blk_table; -static u8 *flags_static_wear_leveling; -static u8 *tmp_buf_write_blk_table_data; -static u8 *tmp_buf_read_disturbance; - -u8 *buf_read_page_main_spare; -u8 *buf_write_page_main_spare; -u8 *buf_read_page_spare; -u8 *buf_get_bad_block; - -#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA) -struct flash_cache_delta_list_tag int_cache[MAX_CHANS + MAX_DESCS]; -struct flash_cache_tag cache_start_copy; -#endif - -int g_wNumFreeBlocks; -u8 g_SBDCmdIndex; - -static u8 *g_pIPF; -static u8 bt_flag = FIRST_BT_ID; -static u8 bt_block_changed; - -static u16 cache_block_to_write; -static u8 last_erased = FIRST_BT_ID; - -static u8 GC_Called; -static u8 BT_GC_Called; - -#if CMD_DMA -#define COPY_BACK_BUF_NUM 10 - -static u8 ftl_cmd_cnt; /* Init value is 0 */ -u8 *g_pBTDelta; -u8 *g_pBTDelta_Free; -u8 *g_pBTStartingCopy; -u8 *g_pWearCounterCopy; -u16 *g_pReadCounterCopy; -u8 *g_pBlockTableCopies; -u8 *g_pNextBlockTable; -static u8 *cp_back_buf_copies[COPY_BACK_BUF_NUM]; -static int cp_back_buf_idx; - -static u8 *g_temp_buf; - -#pragma pack(push, 1) -#pragma pack(1) -struct BTableChangesDelta { - u8 ftl_cmd_cnt; - u8 ValidFields; - u16 g_wBlockTableOffset; - u32 g_wBlockTableIndex; - u32 BT_Index; - u32 BT_Entry_Value; - u32 WC_Index; - u8 WC_Entry_Value; - u32 RC_Index; - u16 RC_Entry_Value; -}; - -#pragma pack(pop) - -struct BTableChangesDelta *p_BTableChangesDelta; -#endif - - -#define MARK_BLOCK_AS_BAD(blocknode) (blocknode |= BAD_BLOCK) -#define MARK_BLK_AS_DISCARD(blk) (blk = (blk & ~SPARE_BLOCK) | DISCARD_BLOCK) - -#define FTL_Get_LBAPBA_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\ - sizeof(u32)) -#define FTL_Get_WearCounter_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\ - sizeof(u8)) -#define FTL_Get_ReadCounter_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\ - sizeof(u16)) -#if SUPPORT_LARGE_BLOCKNUM -#define FTL_Get_LBAPBA_Table_Flash_Size_Bytes() (DeviceInfo.wDataBlockNum *\ - sizeof(u8) * 3) -#else -#define FTL_Get_LBAPBA_Table_Flash_Size_Bytes() (DeviceInfo.wDataBlockNum *\ - sizeof(u16)) -#endif -#define FTL_Get_WearCounter_Table_Flash_Size_Bytes \ - FTL_Get_WearCounter_Table_Mem_Size_Bytes -#define FTL_Get_ReadCounter_Table_Flash_Size_Bytes \ - FTL_Get_ReadCounter_Table_Mem_Size_Bytes - -static u32 FTL_Get_Block_Table_Flash_Size_Bytes(void) -{ - u32 byte_num; - - if (DeviceInfo.MLCDevice) { - byte_num = FTL_Get_LBAPBA_Table_Flash_Size_Bytes() + - DeviceInfo.wDataBlockNum * sizeof(u8) + - DeviceInfo.wDataBlockNum * sizeof(u16); - } else { - byte_num = FTL_Get_LBAPBA_Table_Flash_Size_Bytes() + - DeviceInfo.wDataBlockNum * sizeof(u8); - } - - byte_num += 4 * sizeof(u8); - - return byte_num; -} - -static u16 FTL_Get_Block_Table_Flash_Size_Pages(void) -{ - return (u16)FTL_Get_Page_Num(FTL_Get_Block_Table_Flash_Size_Bytes()); -} - -static int FTL_Copy_Block_Table_To_Flash(u8 *flashBuf, u32 sizeToTx, - u32 sizeTxed) -{ - u32 wBytesCopied, blk_tbl_size, wBytes; - u32 *pbt = (u32 *)g_pBlockTable; - - blk_tbl_size = FTL_Get_LBAPBA_Table_Flash_Size_Bytes(); - for (wBytes = 0; - (wBytes < sizeToTx) && ((wBytes + sizeTxed) < blk_tbl_size); - wBytes++) { -#if SUPPORT_LARGE_BLOCKNUM - flashBuf[wBytes] = (u8)(pbt[(wBytes + sizeTxed) / 3] - >> (((wBytes + sizeTxed) % 3) ? - ((((wBytes + sizeTxed) % 3) == 2) ? 0 : 8) : 16)) & 0xFF; -#else - flashBuf[wBytes] = (u8)(pbt[(wBytes + sizeTxed) / 2] - >> (((wBytes + sizeTxed) % 2) ? 0 : 8)) & 0xFF; -#endif - } - - sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0; - blk_tbl_size = FTL_Get_WearCounter_Table_Flash_Size_Bytes(); - wBytesCopied = wBytes; - wBytes = ((blk_tbl_size - sizeTxed) > (sizeToTx - wBytesCopied)) ? - (sizeToTx - wBytesCopied) : (blk_tbl_size - sizeTxed); - memcpy(flashBuf + wBytesCopied, g_pWearCounter + sizeTxed, wBytes); - - sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0; - - if (DeviceInfo.MLCDevice) { - blk_tbl_size = FTL_Get_ReadCounter_Table_Flash_Size_Bytes(); - wBytesCopied += wBytes; - for (wBytes = 0; ((wBytes + wBytesCopied) < sizeToTx) && - ((wBytes + sizeTxed) < blk_tbl_size); wBytes++) - flashBuf[wBytes + wBytesCopied] = - (g_pReadCounter[(wBytes + sizeTxed) / 2] >> - (((wBytes + sizeTxed) % 2) ? 0 : 8)) & 0xFF; - } - - return wBytesCopied + wBytes; -} - -static int FTL_Copy_Block_Table_From_Flash(u8 *flashBuf, - u32 sizeToTx, u32 sizeTxed) -{ - u32 wBytesCopied, blk_tbl_size, wBytes; - u32 *pbt = (u32 *)g_pBlockTable; - - blk_tbl_size = FTL_Get_LBAPBA_Table_Flash_Size_Bytes(); - for (wBytes = 0; (wBytes < sizeToTx) && - ((wBytes + sizeTxed) < blk_tbl_size); wBytes++) { -#if SUPPORT_LARGE_BLOCKNUM - if (!((wBytes + sizeTxed) % 3)) - pbt[(wBytes + sizeTxed) / 3] = 0; - pbt[(wBytes + sizeTxed) / 3] |= - (flashBuf[wBytes] << (((wBytes + sizeTxed) % 3) ? - ((((wBytes + sizeTxed) % 3) == 2) ? 0 : 8) : 16)); -#else - if (!((wBytes + sizeTxed) % 2)) - pbt[(wBytes + sizeTxed) / 2] = 0; - pbt[(wBytes + sizeTxed) / 2] |= - (flashBuf[wBytes] << (((wBytes + sizeTxed) % 2) ? - 0 : 8)); -#endif - } - - sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0; - blk_tbl_size = FTL_Get_WearCounter_Table_Flash_Size_Bytes(); - wBytesCopied = wBytes; - wBytes = ((blk_tbl_size - sizeTxed) > (sizeToTx - wBytesCopied)) ? - (sizeToTx - wBytesCopied) : (blk_tbl_size - sizeTxed); - memcpy(g_pWearCounter + sizeTxed, flashBuf + wBytesCopied, wBytes); - sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0; - - if (DeviceInfo.MLCDevice) { - wBytesCopied += wBytes; - blk_tbl_size = FTL_Get_ReadCounter_Table_Flash_Size_Bytes(); - for (wBytes = 0; ((wBytes + wBytesCopied) < sizeToTx) && - ((wBytes + sizeTxed) < blk_tbl_size); wBytes++) { - if (((wBytes + sizeTxed) % 2)) - g_pReadCounter[(wBytes + sizeTxed) / 2] = 0; - g_pReadCounter[(wBytes + sizeTxed) / 2] |= - (flashBuf[wBytes] << - (((wBytes + sizeTxed) % 2) ? 0 : 8)); - } - } - - return wBytesCopied+wBytes; -} - -static int FTL_Insert_Block_Table_Signature(u8 *buf, u8 tag) -{ - int i; - - for (i = 0; i < BTSIG_BYTES; i++) - buf[BTSIG_OFFSET + i] = - ((tag + (i * BTSIG_DELTA) - FIRST_BT_ID) % - (1 + LAST_BT_ID-FIRST_BT_ID)) + FIRST_BT_ID; - - return PASS; -} - -static int FTL_Extract_Block_Table_Tag(u8 *buf, u8 **tagarray) -{ - static u8 tag[BTSIG_BYTES >> 1]; - int i, j, k, tagi, tagtemp, status; - - *tagarray = (u8 *)tag; - tagi = 0; - - for (i = 0; i < (BTSIG_BYTES - 1); i++) { - for (j = i + 1; (j < BTSIG_BYTES) && - (tagi < (BTSIG_BYTES >> 1)); j++) { - tagtemp = buf[BTSIG_OFFSET + j] - - buf[BTSIG_OFFSET + i]; - if (tagtemp && !(tagtemp % BTSIG_DELTA)) { - tagtemp = (buf[BTSIG_OFFSET + i] + - (1 + LAST_BT_ID - FIRST_BT_ID) - - (i * BTSIG_DELTA)) % - (1 + LAST_BT_ID - FIRST_BT_ID); - status = FAIL; - for (k = 0; k < tagi; k++) { - if (tagtemp == tag[k]) - status = PASS; - } - - if (status == FAIL) { - tag[tagi++] = tagtemp; - i = (j == (i + 1)) ? i + 1 : i; - j = (j == (i + 1)) ? i + 1 : i; - } - } - } - } - - return tagi; -} - - -static int FTL_Execute_SPL_Recovery(void) -{ - u32 j, block, blks; - u32 *pbt = (u32 *)g_pBlockTable; - int ret; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - blks = DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock; - for (j = 0; j <= blks; j++) { - block = (pbt[j]); - if (((block & BAD_BLOCK) != BAD_BLOCK) && - ((block & SPARE_BLOCK) == SPARE_BLOCK)) { - ret = GLOB_LLD_Erase_Block(block & ~BAD_BLOCK); - if (FAIL == ret) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d " - "generated!\n", - __FILE__, __LINE__, __func__, - (int)(block & ~BAD_BLOCK)); - MARK_BLOCK_AS_BAD(pbt[j]); - } - } - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_IdentifyDevice -* Inputs: pointer to identify data structure -* Outputs: PASS / FAIL -* Description: the identify data structure is filled in with -* information for the block driver. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_IdentifyDevice(struct spectra_indentfy_dev_tag *dev_data) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - dev_data->NumBlocks = DeviceInfo.wTotalBlocks; - dev_data->PagesPerBlock = DeviceInfo.wPagesPerBlock; - dev_data->PageDataSize = DeviceInfo.wPageDataSize; - dev_data->wECCBytesPerSector = DeviceInfo.wECCBytesPerSector; - dev_data->wDataBlockNum = DeviceInfo.wDataBlockNum; - - return PASS; -} - -/* ..... */ -static int allocate_memory(void) -{ - u32 block_table_size, page_size, block_size, mem_size; - u32 total_bytes = 0; - int i; -#if CMD_DMA - int j; -#endif - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - page_size = DeviceInfo.wPageSize; - block_size = DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize; - - block_table_size = DeviceInfo.wDataBlockNum * - (sizeof(u32) + sizeof(u8) + sizeof(u16)); - block_table_size += (DeviceInfo.wPageDataSize - - (block_table_size % DeviceInfo.wPageDataSize)) % - DeviceInfo.wPageDataSize; - - /* Malloc memory for block tables */ - g_pBlockTable = kzalloc(block_table_size, GFP_ATOMIC); - if (!g_pBlockTable) - goto block_table_fail; - total_bytes += block_table_size; - - g_pWearCounter = (u8 *)(g_pBlockTable + - DeviceInfo.wDataBlockNum * sizeof(u32)); - - if (DeviceInfo.MLCDevice) - g_pReadCounter = (u16 *)(g_pBlockTable + - DeviceInfo.wDataBlockNum * - (sizeof(u32) + sizeof(u8))); - - /* Malloc memory and init for cache items */ - for (i = 0; i < CACHE_ITEM_NUM; i++) { - Cache.array[i].address = NAND_CACHE_INIT_ADDR; - Cache.array[i].use_cnt = 0; - Cache.array[i].changed = CLEAR; - Cache.array[i].buf = kzalloc(Cache.cache_item_size, - GFP_ATOMIC); - if (!Cache.array[i].buf) - goto cache_item_fail; - total_bytes += Cache.cache_item_size; - } - - /* Malloc memory for IPF */ - g_pIPF = kzalloc(page_size, GFP_ATOMIC); - if (!g_pIPF) - goto ipf_fail; - total_bytes += page_size; - - /* Malloc memory for data merging during Level2 Cache flush */ - cache_l2_page_buf = kmalloc(page_size, GFP_ATOMIC); - if (!cache_l2_page_buf) - goto cache_l2_page_buf_fail; - memset(cache_l2_page_buf, 0xff, page_size); - total_bytes += page_size; - - cache_l2_blk_buf = kmalloc(block_size, GFP_ATOMIC); - if (!cache_l2_blk_buf) - goto cache_l2_blk_buf_fail; - memset(cache_l2_blk_buf, 0xff, block_size); - total_bytes += block_size; - - /* Malloc memory for temp buffer */ - g_pTempBuf = kzalloc(Cache.cache_item_size, GFP_ATOMIC); - if (!g_pTempBuf) - goto Temp_buf_fail; - total_bytes += Cache.cache_item_size; - - /* Malloc memory for block table blocks */ - mem_size = (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32); - g_pBTBlocks = kmalloc(mem_size, GFP_ATOMIC); - if (!g_pBTBlocks) - goto bt_blocks_fail; - memset(g_pBTBlocks, 0xff, mem_size); - total_bytes += mem_size; - - /* Malloc memory for function FTL_Check_Block_Table */ - flag_check_blk_table = kmalloc(DeviceInfo.wDataBlockNum, GFP_ATOMIC); - if (!flag_check_blk_table) - goto flag_check_blk_table_fail; - total_bytes += DeviceInfo.wDataBlockNum; - - /* Malloc memory for function FTL_Search_Block_Table_IN_Block */ - tmp_buf_search_bt_in_block = kmalloc(page_size, GFP_ATOMIC); - if (!tmp_buf_search_bt_in_block) - goto tmp_buf_search_bt_in_block_fail; - memset(tmp_buf_search_bt_in_block, 0xff, page_size); - total_bytes += page_size; - - mem_size = DeviceInfo.wPageSize - DeviceInfo.wPageDataSize; - spare_buf_search_bt_in_block = kmalloc(mem_size, GFP_ATOMIC); - if (!spare_buf_search_bt_in_block) - goto spare_buf_search_bt_in_block_fail; - memset(spare_buf_search_bt_in_block, 0xff, mem_size); - total_bytes += mem_size; - - spare_buf_bt_search_bt_in_block = kmalloc(mem_size, GFP_ATOMIC); - if (!spare_buf_bt_search_bt_in_block) - goto spare_buf_bt_search_bt_in_block_fail; - memset(spare_buf_bt_search_bt_in_block, 0xff, mem_size); - total_bytes += mem_size; - - /* Malloc memory for function FTL_Read_Block_Table */ - tmp_buf1_read_blk_table = kmalloc(page_size, GFP_ATOMIC); - if (!tmp_buf1_read_blk_table) - goto tmp_buf1_read_blk_table_fail; - memset(tmp_buf1_read_blk_table, 0xff, page_size); - total_bytes += page_size; - - tmp_buf2_read_blk_table = kmalloc(page_size, GFP_ATOMIC); - if (!tmp_buf2_read_blk_table) - goto tmp_buf2_read_blk_table_fail; - memset(tmp_buf2_read_blk_table, 0xff, page_size); - total_bytes += page_size; - - /* Malloc memory for function FTL_Static_Wear_Leveling */ - flags_static_wear_leveling = kmalloc(DeviceInfo.wDataBlockNum, - GFP_ATOMIC); - if (!flags_static_wear_leveling) - goto flags_static_wear_leveling_fail; - total_bytes += DeviceInfo.wDataBlockNum; - - /* Malloc memory for function FTL_Write_Block_Table_Data */ - if (FTL_Get_Block_Table_Flash_Size_Pages() > 3) - mem_size = FTL_Get_Block_Table_Flash_Size_Bytes() - - 2 * DeviceInfo.wPageSize; - else - mem_size = DeviceInfo.wPageSize; - tmp_buf_write_blk_table_data = kmalloc(mem_size, GFP_ATOMIC); - if (!tmp_buf_write_blk_table_data) - goto tmp_buf_write_blk_table_data_fail; - memset(tmp_buf_write_blk_table_data, 0xff, mem_size); - total_bytes += mem_size; - - /* Malloc memory for function FTL_Read_Disturbance */ - tmp_buf_read_disturbance = kmalloc(block_size, GFP_ATOMIC); - if (!tmp_buf_read_disturbance) - goto tmp_buf_read_disturbance_fail; - memset(tmp_buf_read_disturbance, 0xff, block_size); - total_bytes += block_size; - - /* Alloc mem for function NAND_Read_Page_Main_Spare of lld_nand.c */ - buf_read_page_main_spare = kmalloc(DeviceInfo.wPageSize, GFP_ATOMIC); - if (!buf_read_page_main_spare) - goto buf_read_page_main_spare_fail; - total_bytes += DeviceInfo.wPageSize; - - /* Alloc mem for function NAND_Write_Page_Main_Spare of lld_nand.c */ - buf_write_page_main_spare = kmalloc(DeviceInfo.wPageSize, GFP_ATOMIC); - if (!buf_write_page_main_spare) - goto buf_write_page_main_spare_fail; - total_bytes += DeviceInfo.wPageSize; - - /* Alloc mem for function NAND_Read_Page_Spare of lld_nand.c */ - buf_read_page_spare = kmalloc(DeviceInfo.wPageSpareSize, GFP_ATOMIC); - if (!buf_read_page_spare) - goto buf_read_page_spare_fail; - memset(buf_read_page_spare, 0xff, DeviceInfo.wPageSpareSize); - total_bytes += DeviceInfo.wPageSpareSize; - - /* Alloc mem for function NAND_Get_Bad_Block of lld_nand.c */ - buf_get_bad_block = kmalloc(DeviceInfo.wPageSpareSize, GFP_ATOMIC); - if (!buf_get_bad_block) - goto buf_get_bad_block_fail; - memset(buf_get_bad_block, 0xff, DeviceInfo.wPageSpareSize); - total_bytes += DeviceInfo.wPageSpareSize; - -#if CMD_DMA - g_temp_buf = kmalloc(block_size, GFP_ATOMIC); - if (!g_temp_buf) - goto temp_buf_fail; - memset(g_temp_buf, 0xff, block_size); - total_bytes += block_size; - - /* Malloc memory for copy of block table used in CDMA mode */ - g_pBTStartingCopy = kzalloc(block_table_size, GFP_ATOMIC); - if (!g_pBTStartingCopy) - goto bt_starting_copy; - total_bytes += block_table_size; - - g_pWearCounterCopy = (u8 *)(g_pBTStartingCopy + - DeviceInfo.wDataBlockNum * sizeof(u32)); - - if (DeviceInfo.MLCDevice) - g_pReadCounterCopy = (u16 *)(g_pBTStartingCopy + - DeviceInfo.wDataBlockNum * - (sizeof(u32) + sizeof(u8))); - - /* Malloc memory for block table copies */ - mem_size = 5 * DeviceInfo.wDataBlockNum * sizeof(u32) + - 5 * DeviceInfo.wDataBlockNum * sizeof(u8); - if (DeviceInfo.MLCDevice) - mem_size += 5 * DeviceInfo.wDataBlockNum * sizeof(u16); - g_pBlockTableCopies = kzalloc(mem_size, GFP_ATOMIC); - if (!g_pBlockTableCopies) - goto blk_table_copies_fail; - total_bytes += mem_size; - g_pNextBlockTable = g_pBlockTableCopies; - - /* Malloc memory for Block Table Delta */ - mem_size = MAX_DESCS * sizeof(struct BTableChangesDelta); - g_pBTDelta = kzalloc(mem_size, GFP_ATOMIC); - if (!g_pBTDelta) - goto bt_delta_fail; - total_bytes += mem_size; - g_pBTDelta_Free = g_pBTDelta; - - /* Malloc memory for Copy Back Buffers */ - for (j = 0; j < COPY_BACK_BUF_NUM; j++) { - cp_back_buf_copies[j] = kzalloc(block_size, GFP_ATOMIC); - if (!cp_back_buf_copies[j]) - goto cp_back_buf_copies_fail; - total_bytes += block_size; - } - cp_back_buf_idx = 0; - - /* Malloc memory for pending commands list */ - mem_size = sizeof(struct pending_cmd) * MAX_DESCS; - info.pcmds = kzalloc(mem_size, GFP_KERNEL); - if (!info.pcmds) - goto pending_cmds_buf_fail; - total_bytes += mem_size; - - /* Malloc memory for CDMA descripter table */ - mem_size = sizeof(struct cdma_descriptor) * MAX_DESCS; - info.cdma_desc_buf = kzalloc(mem_size, GFP_KERNEL); - if (!info.cdma_desc_buf) - goto cdma_desc_buf_fail; - total_bytes += mem_size; - - /* Malloc memory for Memcpy descripter table */ - mem_size = sizeof(struct memcpy_descriptor) * MAX_DESCS; - info.memcp_desc_buf = kzalloc(mem_size, GFP_KERNEL); - if (!info.memcp_desc_buf) - goto memcp_desc_buf_fail; - total_bytes += mem_size; -#endif - - nand_dbg_print(NAND_DBG_WARN, - "Total memory allocated in FTL layer: %d\n", total_bytes); - - return PASS; - -#if CMD_DMA -memcp_desc_buf_fail: - kfree(info.cdma_desc_buf); -cdma_desc_buf_fail: - kfree(info.pcmds); -pending_cmds_buf_fail: -cp_back_buf_copies_fail: - j--; - for (; j >= 0; j--) - kfree(cp_back_buf_copies[j]); - kfree(g_pBTDelta); -bt_delta_fail: - kfree(g_pBlockTableCopies); -blk_table_copies_fail: - kfree(g_pBTStartingCopy); -bt_starting_copy: - kfree(g_temp_buf); -temp_buf_fail: - kfree(buf_get_bad_block); -#endif - -buf_get_bad_block_fail: - kfree(buf_read_page_spare); -buf_read_page_spare_fail: - kfree(buf_write_page_main_spare); -buf_write_page_main_spare_fail: - kfree(buf_read_page_main_spare); -buf_read_page_main_spare_fail: - kfree(tmp_buf_read_disturbance); -tmp_buf_read_disturbance_fail: - kfree(tmp_buf_write_blk_table_data); -tmp_buf_write_blk_table_data_fail: - kfree(flags_static_wear_leveling); -flags_static_wear_leveling_fail: - kfree(tmp_buf2_read_blk_table); -tmp_buf2_read_blk_table_fail: - kfree(tmp_buf1_read_blk_table); -tmp_buf1_read_blk_table_fail: - kfree(spare_buf_bt_search_bt_in_block); -spare_buf_bt_search_bt_in_block_fail: - kfree(spare_buf_search_bt_in_block); -spare_buf_search_bt_in_block_fail: - kfree(tmp_buf_search_bt_in_block); -tmp_buf_search_bt_in_block_fail: - kfree(flag_check_blk_table); -flag_check_blk_table_fail: - kfree(g_pBTBlocks); -bt_blocks_fail: - kfree(g_pTempBuf); -Temp_buf_fail: - kfree(cache_l2_blk_buf); -cache_l2_blk_buf_fail: - kfree(cache_l2_page_buf); -cache_l2_page_buf_fail: - kfree(g_pIPF); -ipf_fail: -cache_item_fail: - i--; - for (; i >= 0; i--) - kfree(Cache.array[i].buf); - kfree(g_pBlockTable); -block_table_fail: - printk(KERN_ERR "Failed to kmalloc memory in %s Line %d.\n", - __FILE__, __LINE__); - - return -ENOMEM; -} - -/* .... */ -static int free_memory(void) -{ - int i; - -#if CMD_DMA - kfree(info.memcp_desc_buf); - kfree(info.cdma_desc_buf); - kfree(info.pcmds); - for (i = COPY_BACK_BUF_NUM - 1; i >= 0; i--) - kfree(cp_back_buf_copies[i]); - kfree(g_pBTDelta); - kfree(g_pBlockTableCopies); - kfree(g_pBTStartingCopy); - kfree(g_temp_buf); - kfree(buf_get_bad_block); -#endif - kfree(buf_read_page_spare); - kfree(buf_write_page_main_spare); - kfree(buf_read_page_main_spare); - kfree(tmp_buf_read_disturbance); - kfree(tmp_buf_write_blk_table_data); - kfree(flags_static_wear_leveling); - kfree(tmp_buf2_read_blk_table); - kfree(tmp_buf1_read_blk_table); - kfree(spare_buf_bt_search_bt_in_block); - kfree(spare_buf_search_bt_in_block); - kfree(tmp_buf_search_bt_in_block); - kfree(flag_check_blk_table); - kfree(g_pBTBlocks); - kfree(g_pTempBuf); - kfree(g_pIPF); - for (i = CACHE_ITEM_NUM - 1; i >= 0; i--) - kfree(Cache.array[i].buf); - kfree(g_pBlockTable); - - return 0; -} - -static void dump_cache_l2_table(void) -{ - struct list_head *p; - struct spectra_l2_cache_list *pnd; - int n; - - n = 0; - list_for_each(p, &cache_l2.table.list) { - pnd = list_entry(p, struct spectra_l2_cache_list, list); - nand_dbg_print(NAND_DBG_WARN, "dump_cache_l2_table node: %d, logical_blk_num: %d\n", n, pnd->logical_blk_num); -/* - for (i = 0; i < DeviceInfo.wPagesPerBlock; i++) { - if (pnd->pages_array[i] != MAX_U32_VALUE) - nand_dbg_print(NAND_DBG_WARN, " pages_array[%d]: 0x%x\n", i, pnd->pages_array[i]); - } -*/ - n++; - } -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Init -* Inputs: none -* Outputs: PASS=0 / FAIL=1 -* Description: allocates the memory for cache array, -* important data structures -* clears the cache array -* reads the block table from flash into array -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Init(void) -{ - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - Cache.pages_per_item = 1; - Cache.cache_item_size = 1 * DeviceInfo.wPageDataSize; - - if (allocate_memory() != PASS) - return FAIL; - -#if CMD_DMA -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - memcpy((void *)&cache_start_copy, (void *)&Cache, - sizeof(struct flash_cache_tag)); - memset((void *)&int_cache, -1, - sizeof(struct flash_cache_delta_list_tag) * - (MAX_CHANS + MAX_DESCS)); -#endif - ftl_cmd_cnt = 0; -#endif - - if (FTL_Read_Block_Table() != PASS) - return FAIL; - - /* Init the Level2 Cache data structure */ - for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++) - cache_l2.blk_array[i] = MAX_U32_VALUE; - cache_l2.cur_blk_idx = 0; - cache_l2.cur_page_num = 0; - INIT_LIST_HEAD(&cache_l2.table.list); - cache_l2.table.logical_blk_num = MAX_U32_VALUE; - - dump_cache_l2_table(); - - return 0; -} - - -#if CMD_DMA -#if 0 -static void save_blk_table_changes(u16 idx) -{ - u8 ftl_cmd; - u32 *pbt = (u32 *)g_pBTStartingCopy; - -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - u16 id; - u8 cache_blks; - - id = idx - MAX_CHANS; - if (int_cache[id].item != -1) { - cache_blks = int_cache[id].item; - cache_start_copy.array[cache_blks].address = - int_cache[id].cache.address; - cache_start_copy.array[cache_blks].changed = - int_cache[id].cache.changed; - } -#endif - - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - - while (ftl_cmd <= PendingCMD[idx].Tag) { - if (p_BTableChangesDelta->ValidFields == 0x01) { - g_wBlockTableOffset = - p_BTableChangesDelta->g_wBlockTableOffset; - } else if (p_BTableChangesDelta->ValidFields == 0x0C) { - pbt[p_BTableChangesDelta->BT_Index] = - p_BTableChangesDelta->BT_Entry_Value; - debug_boundary_error((( - p_BTableChangesDelta->BT_Index)), - DeviceInfo.wDataBlockNum, 0); - } else if (p_BTableChangesDelta->ValidFields == 0x03) { - g_wBlockTableOffset = - p_BTableChangesDelta->g_wBlockTableOffset; - g_wBlockTableIndex = - p_BTableChangesDelta->g_wBlockTableIndex; - } else if (p_BTableChangesDelta->ValidFields == 0x30) { - g_pWearCounterCopy[p_BTableChangesDelta->WC_Index] = - p_BTableChangesDelta->WC_Entry_Value; - } else if ((DeviceInfo.MLCDevice) && - (p_BTableChangesDelta->ValidFields == 0xC0)) { - g_pReadCounterCopy[p_BTableChangesDelta->RC_Index] = - p_BTableChangesDelta->RC_Entry_Value; - nand_dbg_print(NAND_DBG_DEBUG, - "In event status setting read counter " - "GLOB_ftl_cmd_cnt %u Count %u Index %u\n", - ftl_cmd, - p_BTableChangesDelta->RC_Entry_Value, - (unsigned int)p_BTableChangesDelta->RC_Index); - } else { - nand_dbg_print(NAND_DBG_DEBUG, - "This should never occur \n"); - } - p_BTableChangesDelta += 1; - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - } -} - -static void discard_cmds(u16 n) -{ - u32 *pbt = (u32 *)g_pBTStartingCopy; - u8 ftl_cmd; - unsigned long k; -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - u8 cache_blks; - u16 id; -#endif - - if ((PendingCMD[n].CMD == WRITE_MAIN_CMD) || - (PendingCMD[n].CMD == WRITE_MAIN_SPARE_CMD)) { - for (k = 0; k < DeviceInfo.wDataBlockNum; k++) { - if (PendingCMD[n].Block == (pbt[k] & (~BAD_BLOCK))) - MARK_BLK_AS_DISCARD(pbt[k]); - } - } - - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - while (ftl_cmd <= PendingCMD[n].Tag) { - p_BTableChangesDelta += 1; - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - } - -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - id = n - MAX_CHANS; - - if (int_cache[id].item != -1) { - cache_blks = int_cache[id].item; - if (PendingCMD[n].CMD == MEMCOPY_CMD) { - if ((cache_start_copy.array[cache_blks].buf <= - PendingCMD[n].DataDestAddr) && - ((cache_start_copy.array[cache_blks].buf + - Cache.cache_item_size) > - PendingCMD[n].DataDestAddr)) { - cache_start_copy.array[cache_blks].address = - NAND_CACHE_INIT_ADDR; - cache_start_copy.array[cache_blks].use_cnt = - 0; - cache_start_copy.array[cache_blks].changed = - CLEAR; - } - } else { - cache_start_copy.array[cache_blks].address = - int_cache[id].cache.address; - cache_start_copy.array[cache_blks].changed = - int_cache[id].cache.changed; - } - } -#endif -} - -static void process_cmd_pass(int *first_failed_cmd, u16 idx) -{ - if (0 == *first_failed_cmd) - save_blk_table_changes(idx); - else - discard_cmds(idx); -} - -static void process_cmd_fail_abort(int *first_failed_cmd, - u16 idx, int event) -{ - u32 *pbt = (u32 *)g_pBTStartingCopy; - u8 ftl_cmd; - unsigned long i; - int erase_fail, program_fail; -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - u8 cache_blks; - u16 id; -#endif - - if (0 == *first_failed_cmd) - *first_failed_cmd = PendingCMD[idx].SBDCmdIndex; - - nand_dbg_print(NAND_DBG_DEBUG, "Uncorrectable error has occurred " - "while executing %u Command %u accesing Block %u\n", - (unsigned int)p_BTableChangesDelta->ftl_cmd_cnt, - PendingCMD[idx].CMD, - (unsigned int)PendingCMD[idx].Block); - - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - while (ftl_cmd <= PendingCMD[idx].Tag) { - p_BTableChangesDelta += 1; - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - } - -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - id = idx - MAX_CHANS; - - if (int_cache[id].item != -1) { - cache_blks = int_cache[id].item; - if ((PendingCMD[idx].CMD == WRITE_MAIN_CMD)) { - cache_start_copy.array[cache_blks].address = - int_cache[id].cache.address; - cache_start_copy.array[cache_blks].changed = SET; - } else if ((PendingCMD[idx].CMD == READ_MAIN_CMD)) { - cache_start_copy.array[cache_blks].address = - NAND_CACHE_INIT_ADDR; - cache_start_copy.array[cache_blks].use_cnt = 0; - cache_start_copy.array[cache_blks].changed = - CLEAR; - } else if (PendingCMD[idx].CMD == ERASE_CMD) { - /* ? */ - } else if (PendingCMD[idx].CMD == MEMCOPY_CMD) { - /* ? */ - } - } -#endif - - erase_fail = (event == EVENT_ERASE_FAILURE) && - (PendingCMD[idx].CMD == ERASE_CMD); - - program_fail = (event == EVENT_PROGRAM_FAILURE) && - ((PendingCMD[idx].CMD == WRITE_MAIN_CMD) || - (PendingCMD[idx].CMD == WRITE_MAIN_SPARE_CMD)); - - if (erase_fail || program_fail) { - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - if (PendingCMD[idx].Block == - (pbt[i] & (~BAD_BLOCK))) - MARK_BLOCK_AS_BAD(pbt[i]); - } - } -} - -static void process_cmd(int *first_failed_cmd, u16 idx, int event) -{ - u8 ftl_cmd; - int cmd_match = 0; - - if (p_BTableChangesDelta->ftl_cmd_cnt == PendingCMD[idx].Tag) - cmd_match = 1; - - if (PendingCMD[idx].Status == CMD_PASS) { - process_cmd_pass(first_failed_cmd, idx); - } else if ((PendingCMD[idx].Status == CMD_FAIL) || - (PendingCMD[idx].Status == CMD_ABORT)) { - process_cmd_fail_abort(first_failed_cmd, idx, event); - } else if ((PendingCMD[idx].Status == CMD_NOT_DONE) && - PendingCMD[idx].Tag) { - nand_dbg_print(NAND_DBG_DEBUG, - " Command no. %hu is not executed\n", - (unsigned int)PendingCMD[idx].Tag); - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - while (ftl_cmd <= PendingCMD[idx].Tag) { - p_BTableChangesDelta += 1; - ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt; - } - } -} -#endif - -static void process_cmd(int *first_failed_cmd, u16 idx, int event) -{ - printk(KERN_ERR "temporary workaround function. " - "Should not be called! \n"); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Event_Status -* Inputs: none -* Outputs: Event Code -* Description: It is called by SBD after hardware interrupt signalling -* completion of commands chain -* It does following things -* get event status from LLD -* analyze command chain status -* determine last command executed -* analyze results -* rebuild the block table in case of uncorrectable error -* return event code -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Event_Status(int *first_failed_cmd) -{ - int event_code = PASS; - u16 i_P; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - *first_failed_cmd = 0; - - event_code = GLOB_LLD_Event_Status(); - - switch (event_code) { - case EVENT_PASS: - nand_dbg_print(NAND_DBG_DEBUG, "Handling EVENT_PASS\n"); - break; - case EVENT_UNCORRECTABLE_DATA_ERROR: - nand_dbg_print(NAND_DBG_DEBUG, "Handling Uncorrectable ECC!\n"); - break; - case EVENT_PROGRAM_FAILURE: - case EVENT_ERASE_FAILURE: - nand_dbg_print(NAND_DBG_WARN, "Handling Ugly case. " - "Event code: 0x%x\n", event_code); - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta; - for (i_P = MAX_CHANS; i_P < (ftl_cmd_cnt + MAX_CHANS); - i_P++) - process_cmd(first_failed_cmd, i_P, event_code); - memcpy(g_pBlockTable, g_pBTStartingCopy, - DeviceInfo.wDataBlockNum * sizeof(u32)); - memcpy(g_pWearCounter, g_pWearCounterCopy, - DeviceInfo.wDataBlockNum * sizeof(u8)); - if (DeviceInfo.MLCDevice) - memcpy(g_pReadCounter, g_pReadCounterCopy, - DeviceInfo.wDataBlockNum * sizeof(u16)); - -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - memcpy((void *)&Cache, (void *)&cache_start_copy, - sizeof(struct flash_cache_tag)); - memset((void *)&int_cache, -1, - sizeof(struct flash_cache_delta_list_tag) * - (MAX_DESCS + MAX_CHANS)); -#endif - break; - default: - nand_dbg_print(NAND_DBG_WARN, - "Handling unexpected event code - 0x%x\n", - event_code); - event_code = ERR; - break; - } - - memcpy(g_pBTStartingCopy, g_pBlockTable, - DeviceInfo.wDataBlockNum * sizeof(u32)); - memcpy(g_pWearCounterCopy, g_pWearCounter, - DeviceInfo.wDataBlockNum * sizeof(u8)); - if (DeviceInfo.MLCDevice) - memcpy(g_pReadCounterCopy, g_pReadCounter, - DeviceInfo.wDataBlockNum * sizeof(u16)); - - g_pBTDelta_Free = g_pBTDelta; - ftl_cmd_cnt = 0; - g_pNextBlockTable = g_pBlockTableCopies; - cp_back_buf_idx = 0; - -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - memcpy((void *)&cache_start_copy, (void *)&Cache, - sizeof(struct flash_cache_tag)); - memset((void *)&int_cache, -1, - sizeof(struct flash_cache_delta_list_tag) * - (MAX_DESCS + MAX_CHANS)); -#endif - - return event_code; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: glob_ftl_execute_cmds -* Inputs: none -* Outputs: none -* Description: pass thru to LLD -***************************************************************/ -u16 glob_ftl_execute_cmds(void) -{ - nand_dbg_print(NAND_DBG_TRACE, - "glob_ftl_execute_cmds: ftl_cmd_cnt %u\n", - (unsigned int)ftl_cmd_cnt); - g_SBDCmdIndex = 0; - return glob_lld_execute_cmds(); -} - -#endif - -#if !CMD_DMA -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Read Immediate -* Inputs: pointer to data -* address of data -* Outputs: PASS / FAIL -* Description: Reads one page of data into RAM directly from flash without -* using or disturbing cache.It is assumed this function is called -* with CMD-DMA disabled. -*****************************************************************/ -int GLOB_FTL_Read_Immediate(u8 *read_data, u64 addr) -{ - int wResult = FAIL; - u32 Block; - u16 Page; - u32 phy_blk; - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - Block = BLK_FROM_ADDR(addr); - Page = PAGE_FROM_ADDR(addr, Block); - - if (!IS_SPARE_BLOCK(Block)) - return FAIL; - - phy_blk = pbt[Block]; - wResult = GLOB_LLD_Read_Page_Main(read_data, phy_blk, Page, 1); - - if (DeviceInfo.MLCDevice) { - g_pReadCounter[phy_blk - DeviceInfo.wSpectraStartBlock]++; - if (g_pReadCounter[phy_blk - DeviceInfo.wSpectraStartBlock] - >= MAX_READ_COUNTER) - FTL_Read_Disturbance(phy_blk); - if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - } - - return wResult; -} -#endif - -#ifdef SUPPORT_BIG_ENDIAN -/********************************************************************* -* Function: FTL_Invert_Block_Table -* Inputs: none -* Outputs: none -* Description: Re-format the block table in ram based on BIG_ENDIAN and -* LARGE_BLOCKNUM if necessary -**********************************************************************/ -static void FTL_Invert_Block_Table(void) -{ - u32 i; - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - -#ifdef SUPPORT_LARGE_BLOCKNUM - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - pbt[i] = INVERTUINT32(pbt[i]); - g_pWearCounter[i] = INVERTUINT32(g_pWearCounter[i]); - } -#else - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - pbt[i] = INVERTUINT16(pbt[i]); - g_pWearCounter[i] = INVERTUINT16(g_pWearCounter[i]); - } -#endif -} -#endif - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Flash_Init -* Inputs: none -* Outputs: PASS=0 / FAIL=0x01 (based on read ID) -* Description: The flash controller is initialized -* The flash device is reset -* Perform a flash READ ID command to confirm that a -* valid device is attached and active. -* The DeviceInfo structure gets filled in -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Flash_Init(void) -{ - int status = FAIL; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - g_SBDCmdIndex = 0; - - status = GLOB_LLD_Flash_Init(); - - return status; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Inputs: none -* Outputs: PASS=0 / FAIL=0x01 (based on read ID) -* Description: The flash controller is released -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Flash_Release(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return GLOB_LLD_Flash_Release(); -} - - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Cache_Release -* Inputs: none -* Outputs: none -* Description: release all allocated memory in GLOB_FTL_Init -* (allocated in GLOB_FTL_Init) -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -void GLOB_FTL_Cache_Release(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - free_memory(); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_If_Hit -* Inputs: Page Address -* Outputs: Block number/UNHIT BLOCK -* Description: Determines if the addressed page is in cache -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u16 FTL_Cache_If_Hit(u64 page_addr) -{ - u16 item; - u64 addr; - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - item = UNHIT_CACHE_ITEM; - for (i = 0; i < CACHE_ITEM_NUM; i++) { - addr = Cache.array[i].address; - if ((page_addr >= addr) && - (page_addr < (addr + Cache.cache_item_size))) { - item = i; - break; - } - } - - return item; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Calculate_LRU -* Inputs: None -* Outputs: None -* Description: Calculate the least recently block in a cache and record its -* index in LRU field. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static void FTL_Calculate_LRU(void) -{ - u16 i, bCurrentLRU, bTempCount; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - bCurrentLRU = 0; - bTempCount = MAX_WORD_VALUE; - - for (i = 0; i < CACHE_ITEM_NUM; i++) { - if (Cache.array[i].use_cnt < bTempCount) { - bCurrentLRU = i; - bTempCount = Cache.array[i].use_cnt; - } - } - - Cache.LRU = bCurrentLRU; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Read_Page -* Inputs: pointer to read buffer, logical address and cache item number -* Outputs: None -* Description: Read the page from the cached block addressed by blocknumber -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static void FTL_Cache_Read_Page(u8 *data_buf, u64 logic_addr, u16 cache_item) -{ - u8 *start_addr; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - start_addr = Cache.array[cache_item].buf; - start_addr += (u32)(((logic_addr - Cache.array[cache_item].address) >> - DeviceInfo.nBitsInPageDataSize) * DeviceInfo.wPageDataSize); - -#if CMD_DMA - GLOB_LLD_MemCopy_CMD(data_buf, start_addr, - DeviceInfo.wPageDataSize, 0); - ftl_cmd_cnt++; -#else - memcpy(data_buf, start_addr, DeviceInfo.wPageDataSize); -#endif - - if (Cache.array[cache_item].use_cnt < MAX_WORD_VALUE) - Cache.array[cache_item].use_cnt++; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Read_All -* Inputs: pointer to read buffer,block address -* Outputs: PASS=0 / FAIL =1 -* Description: It reads pages in cache -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Read_All(u8 *pData, u64 phy_addr) -{ - int wResult = PASS; - u32 Block; - u32 lba; - u16 Page; - u16 PageCount; - u32 *pbt = (u32 *)g_pBlockTable; - u32 i; - - Block = BLK_FROM_ADDR(phy_addr); - Page = PAGE_FROM_ADDR(phy_addr, Block); - PageCount = Cache.pages_per_item; - - nand_dbg_print(NAND_DBG_DEBUG, - "%s, Line %d, Function: %s, Block: 0x%x\n", - __FILE__, __LINE__, __func__, Block); - - lba = 0xffffffff; - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - if ((pbt[i] & (~BAD_BLOCK)) == Block) { - lba = i; - if (IS_SPARE_BLOCK(i) || IS_BAD_BLOCK(i) || - IS_DISCARDED_BLOCK(i)) { - /* Add by yunpeng -2008.12.3 */ -#if CMD_DMA - GLOB_LLD_MemCopy_CMD(pData, g_temp_buf, - PageCount * DeviceInfo.wPageDataSize, 0); - ftl_cmd_cnt++; -#else - memset(pData, 0xFF, - PageCount * DeviceInfo.wPageDataSize); -#endif - return wResult; - } else { - continue; /* break ?? */ - } - } - } - - if (0xffffffff == lba) - printk(KERN_ERR "FTL_Cache_Read_All: Block is not found in BT\n"); - -#if CMD_DMA - wResult = GLOB_LLD_Read_Page_Main_cdma(pData, Block, Page, - PageCount, LLD_CMD_FLAG_MODE_CDMA); - if (DeviceInfo.MLCDevice) { - g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock]++; - nand_dbg_print(NAND_DBG_DEBUG, - "Read Counter modified in ftl_cmd_cnt %u" - " Block %u Counter%u\n", - ftl_cmd_cnt, (unsigned int)Block, - g_pReadCounter[Block - - DeviceInfo.wSpectraStartBlock]); - - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->RC_Index = - Block - DeviceInfo.wSpectraStartBlock; - p_BTableChangesDelta->RC_Entry_Value = - g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock]; - p_BTableChangesDelta->ValidFields = 0xC0; - - ftl_cmd_cnt++; - - if (g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock] >= - MAX_READ_COUNTER) - FTL_Read_Disturbance(Block); - if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - } else { - ftl_cmd_cnt++; - } -#else - wResult = GLOB_LLD_Read_Page_Main(pData, Block, Page, PageCount); - if (wResult == FAIL) - return wResult; - - if (DeviceInfo.MLCDevice) { - g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock]++; - if (g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock] >= - MAX_READ_COUNTER) - FTL_Read_Disturbance(Block); - if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - } -#endif - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Write_All -* Inputs: pointer to cache in sys memory -* address of free block in flash -* Outputs: PASS=0 / FAIL=1 -* Description: writes all the pages of the block in cache to flash -* -* NOTE:need to make sure this works ok when cache is limited -* to a partial block. This is where copy-back would be -* activated. This would require knowing which pages in the -* cached block are clean/dirty.Right now we only know if -* the whole block is clean/dirty. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Write_All(u8 *pData, u64 blk_addr) -{ - u16 wResult = PASS; - u32 Block; - u16 Page; - u16 PageCount; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - nand_dbg_print(NAND_DBG_DEBUG, "This block %d going to be written " - "on %d\n", cache_block_to_write, - (u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize)); - - Block = BLK_FROM_ADDR(blk_addr); - Page = PAGE_FROM_ADDR(blk_addr, Block); - PageCount = Cache.pages_per_item; - -#if CMD_DMA - if (FAIL == GLOB_LLD_Write_Page_Main_cdma(pData, - Block, Page, PageCount)) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated! " - "Need Bad Block replacing.\n", - __FILE__, __LINE__, __func__, Block); - wResult = FAIL; - } - ftl_cmd_cnt++; -#else - if (FAIL == GLOB_LLD_Write_Page_Main(pData, Block, Page, PageCount)) { - nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in %s," - " Line %d, Function %s, new Bad Block %d generated!" - "Need Bad Block replacing.\n", - __FILE__, __LINE__, __func__, Block); - wResult = FAIL; - } -#endif - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Copy_Block -* Inputs: source block address -* Destination block address -* Outputs: PASS=0 / FAIL=1 -* Description: used only for static wear leveling to move the block -* containing static data to new blocks(more worn) -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int FTL_Copy_Block(u64 old_blk_addr, u64 blk_addr) -{ - int i, r1, r2, wResult = PASS; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) { - r1 = FTL_Cache_Read_All(g_pTempBuf, old_blk_addr + - i * DeviceInfo.wPageDataSize); - r2 = FTL_Cache_Write_All(g_pTempBuf, blk_addr + - i * DeviceInfo.wPageDataSize); - if ((ERR == r1) || (FAIL == r2)) { - wResult = FAIL; - break; - } - } - - return wResult; -} - -/* Search the block table to find out the least wear block and then return it */ -static u32 find_least_worn_blk_for_l2_cache(void) -{ - int i; - u32 *pbt = (u32 *)g_pBlockTable; - u8 least_wear_cnt = MAX_BYTE_VALUE; - u32 least_wear_blk_idx = MAX_U32_VALUE; - u32 phy_idx; - - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - if (IS_SPARE_BLOCK(i)) { - phy_idx = (u32)((~BAD_BLOCK) & pbt[i]); - if (phy_idx > DeviceInfo.wSpectraEndBlock) - printk(KERN_ERR "find_least_worn_blk_for_l2_cache: " - "Too big phy block num (%d)\n", phy_idx); - if (g_pWearCounter[phy_idx -DeviceInfo.wSpectraStartBlock] < least_wear_cnt) { - least_wear_cnt = g_pWearCounter[phy_idx - DeviceInfo.wSpectraStartBlock]; - least_wear_blk_idx = i; - } - } - } - - nand_dbg_print(NAND_DBG_WARN, - "find_least_worn_blk_for_l2_cache: " - "find block %d with least worn counter (%d)\n", - least_wear_blk_idx, least_wear_cnt); - - return least_wear_blk_idx; -} - - - -/* Get blocks for Level2 Cache */ -static int get_l2_cache_blks(void) -{ - int n; - u32 blk; - u32 *pbt = (u32 *)g_pBlockTable; - - for (n = 0; n < BLK_NUM_FOR_L2_CACHE; n++) { - blk = find_least_worn_blk_for_l2_cache(); - if (blk >= DeviceInfo.wDataBlockNum) { - nand_dbg_print(NAND_DBG_WARN, - "find_least_worn_blk_for_l2_cache: " - "No enough free NAND blocks (n: %d) for L2 Cache!\n", n); - return FAIL; - } - /* Tag the free block as discard in block table */ - pbt[blk] = (pbt[blk] & (~BAD_BLOCK)) | DISCARD_BLOCK; - /* Add the free block to the L2 Cache block array */ - cache_l2.blk_array[n] = pbt[blk] & (~BAD_BLOCK); - } - - return PASS; -} - -static int erase_l2_cache_blocks(void) -{ - int i, ret = PASS; - u32 pblk, lblk = BAD_BLOCK; - u64 addr; - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++) { - pblk = cache_l2.blk_array[i]; - - /* If the L2 cache block is invalid, then just skip it */ - if (MAX_U32_VALUE == pblk) - continue; - - BUG_ON(pblk > DeviceInfo.wSpectraEndBlock); - - addr = (u64)pblk << DeviceInfo.nBitsInBlockDataSize; - if (PASS == GLOB_FTL_Block_Erase(addr)) { - /* Get logical block number of the erased block */ - lblk = FTL_Get_Block_Index(pblk); - BUG_ON(BAD_BLOCK == lblk); - /* Tag it as free in the block table */ - pbt[lblk] &= (u32)(~DISCARD_BLOCK); - pbt[lblk] |= (u32)(SPARE_BLOCK); - } else { - MARK_BLOCK_AS_BAD(pbt[lblk]); - ret = ERR; - } - } - - return ret; -} - -/* - * Merge the valid data page in the L2 cache blocks into NAND. -*/ -static int flush_l2_cache(void) -{ - struct list_head *p; - struct spectra_l2_cache_list *pnd, *tmp_pnd; - u32 *pbt = (u32 *)g_pBlockTable; - u32 phy_blk, l2_blk; - u64 addr; - u16 l2_page; - int i, ret = PASS; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (list_empty(&cache_l2.table.list)) /* No data to flush */ - return ret; - - //dump_cache_l2_table(); - - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - list_for_each(p, &cache_l2.table.list) { - pnd = list_entry(p, struct spectra_l2_cache_list, list); - if (IS_SPARE_BLOCK(pnd->logical_blk_num) || - IS_BAD_BLOCK(pnd->logical_blk_num) || - IS_DISCARDED_BLOCK(pnd->logical_blk_num)) { - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d\n", __FILE__, __LINE__); - memset(cache_l2_blk_buf, 0xff, DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize); - } else { - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d\n", __FILE__, __LINE__); - phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK); - ret = GLOB_LLD_Read_Page_Main(cache_l2_blk_buf, - phy_blk, 0, DeviceInfo.wPagesPerBlock); - if (ret == FAIL) { - printk(KERN_ERR "Read NAND page fail in %s, Line %d\n", __FILE__, __LINE__); - } - } - - for (i = 0; i < DeviceInfo.wPagesPerBlock; i++) { - if (pnd->pages_array[i] != MAX_U32_VALUE) { - l2_blk = cache_l2.blk_array[(pnd->pages_array[i] >> 16) & 0xffff]; - l2_page = pnd->pages_array[i] & 0xffff; - ret = GLOB_LLD_Read_Page_Main(cache_l2_page_buf, l2_blk, l2_page, 1); - if (ret == FAIL) { - printk(KERN_ERR "Read NAND page fail in %s, Line %d\n", __FILE__, __LINE__); - } - memcpy(cache_l2_blk_buf + i * DeviceInfo.wPageDataSize, cache_l2_page_buf, DeviceInfo.wPageDataSize); - } - } - - /* Find a free block and tag the original block as discarded */ - addr = (u64)pnd->logical_blk_num << DeviceInfo.nBitsInBlockDataSize; - ret = FTL_Replace_Block(addr); - if (ret == FAIL) { - printk(KERN_ERR "FTL_Replace_Block fail in %s, Line %d\n", __FILE__, __LINE__); - } - - /* Write back the updated data into NAND */ - phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK); - if (FAIL == GLOB_LLD_Write_Page_Main(cache_l2_blk_buf, phy_blk, 0, DeviceInfo.wPagesPerBlock)) { - nand_dbg_print(NAND_DBG_WARN, - "Program NAND block %d fail in %s, Line %d\n", - phy_blk, __FILE__, __LINE__); - /* This may not be really a bad block. So just tag it as discarded. */ - /* Then it has a chance to be erased when garbage collection. */ - /* If it is really bad, then the erase will fail and it will be marked */ - /* as bad then. Otherwise it will be marked as free and can be used again */ - MARK_BLK_AS_DISCARD(pbt[pnd->logical_blk_num]); - /* Find another free block and write it again */ - FTL_Replace_Block(addr); - phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK); - if (FAIL == GLOB_LLD_Write_Page_Main(cache_l2_blk_buf, phy_blk, 0, DeviceInfo.wPagesPerBlock)) { - printk(KERN_ERR "Failed to write back block %d when flush L2 cache." - "Some data will be lost!\n", phy_blk); - MARK_BLOCK_AS_BAD(pbt[pnd->logical_blk_num]); - } - } else { - /* tag the new free block as used block */ - pbt[pnd->logical_blk_num] &= (~SPARE_BLOCK); - } - } - - /* Destroy the L2 Cache table and free the memory of all nodes */ - list_for_each_entry_safe(pnd, tmp_pnd, &cache_l2.table.list, list) { - list_del(&pnd->list); - kfree(pnd); - } - - /* Erase discard L2 cache blocks */ - if (erase_l2_cache_blocks() != PASS) - nand_dbg_print(NAND_DBG_WARN, - " Erase L2 cache blocks error in %s, Line %d\n", - __FILE__, __LINE__); - - /* Init the Level2 Cache data structure */ - for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++) - cache_l2.blk_array[i] = MAX_U32_VALUE; - cache_l2.cur_blk_idx = 0; - cache_l2.cur_page_num = 0; - INIT_LIST_HEAD(&cache_l2.table.list); - cache_l2.table.logical_blk_num = MAX_U32_VALUE; - - return ret; -} - -/* - * Write back a changed victim cache item to the Level2 Cache - * and update the L2 Cache table to map the change. - * If the L2 Cache is full, then start to do the L2 Cache flush. -*/ -static int write_back_to_l2_cache(u8 *buf, u64 logical_addr) -{ - u32 logical_blk_num; - u16 logical_page_num; - struct list_head *p; - struct spectra_l2_cache_list *pnd, *pnd_new; - u32 node_size; - int i, found; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - /* - * If Level2 Cache table is empty, then it means either: - * 1. This is the first time that the function called after FTL_init - * or - * 2. The Level2 Cache has just been flushed - * - * So, 'steal' some free blocks from NAND for L2 Cache using - * by just mask them as discard in the block table - */ - if (list_empty(&cache_l2.table.list)) { - BUG_ON(cache_l2.cur_blk_idx != 0); - BUG_ON(cache_l2.cur_page_num!= 0); - BUG_ON(cache_l2.table.logical_blk_num != MAX_U32_VALUE); - if (FAIL == get_l2_cache_blks()) { - GLOB_FTL_Garbage_Collection(); - if (FAIL == get_l2_cache_blks()) { - printk(KERN_ALERT "Fail to get L2 cache blks!\n"); - return FAIL; - } - } - } - - logical_blk_num = BLK_FROM_ADDR(logical_addr); - logical_page_num = PAGE_FROM_ADDR(logical_addr, logical_blk_num); - BUG_ON(logical_blk_num == MAX_U32_VALUE); - - /* Write the cache item data into the current position of L2 Cache */ -#if CMD_DMA - /* - * TODO - */ -#else - if (FAIL == GLOB_LLD_Write_Page_Main(buf, - cache_l2.blk_array[cache_l2.cur_blk_idx], - cache_l2.cur_page_num, 1)) { - nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in " - "%s, Line %d, new Bad Block %d generated!\n", - __FILE__, __LINE__, - cache_l2.blk_array[cache_l2.cur_blk_idx]); - - /* TODO: tag the current block as bad and try again */ - - return FAIL; - } -#endif - - /* - * Update the L2 Cache table. - * - * First seaching in the table to see whether the logical block - * has been mapped. If not, then kmalloc a new node for the - * logical block, fill data, and then insert it to the list. - * Otherwise, just update the mapped node directly. - */ - found = 0; - list_for_each(p, &cache_l2.table.list) { - pnd = list_entry(p, struct spectra_l2_cache_list, list); - if (pnd->logical_blk_num == logical_blk_num) { - pnd->pages_array[logical_page_num] = - (cache_l2.cur_blk_idx << 16) | - cache_l2.cur_page_num; - found = 1; - break; - } - } - if (!found) { /* Create new node for the logical block here */ - - /* The logical pages to physical pages map array is - * located at the end of struct spectra_l2_cache_list. - */ - node_size = sizeof(struct spectra_l2_cache_list) + - sizeof(u32) * DeviceInfo.wPagesPerBlock; - pnd_new = kmalloc(node_size, GFP_ATOMIC); - if (!pnd_new) { - printk(KERN_ERR "Failed to kmalloc in %s Line %d\n", - __FILE__, __LINE__); - /* - * TODO: Need to flush all the L2 cache into NAND ASAP - * since no memory available here - */ - } - pnd_new->logical_blk_num = logical_blk_num; - for (i = 0; i < DeviceInfo.wPagesPerBlock; i++) - pnd_new->pages_array[i] = MAX_U32_VALUE; - pnd_new->pages_array[logical_page_num] = - (cache_l2.cur_blk_idx << 16) | cache_l2.cur_page_num; - list_add(&pnd_new->list, &cache_l2.table.list); - } - - /* Increasing the current position pointer of the L2 Cache */ - cache_l2.cur_page_num++; - if (cache_l2.cur_page_num >= DeviceInfo.wPagesPerBlock) { - cache_l2.cur_blk_idx++; - if (cache_l2.cur_blk_idx >= BLK_NUM_FOR_L2_CACHE) { - /* The L2 Cache is full. Need to flush it now */ - nand_dbg_print(NAND_DBG_WARN, - "L2 Cache is full, will start to flush it\n"); - flush_l2_cache(); - } else { - cache_l2.cur_page_num = 0; - } - } - - return PASS; -} - -/* - * Search in the Level2 Cache table to find the cache item. - * If find, read the data from the NAND page of L2 Cache, - * Otherwise, return FAIL. - */ -static int search_l2_cache(u8 *buf, u64 logical_addr) -{ - u32 logical_blk_num; - u16 logical_page_num; - struct list_head *p; - struct spectra_l2_cache_list *pnd; - u32 tmp = MAX_U32_VALUE; - u32 phy_blk; - u16 phy_page; - int ret = FAIL; - - logical_blk_num = BLK_FROM_ADDR(logical_addr); - logical_page_num = PAGE_FROM_ADDR(logical_addr, logical_blk_num); - - list_for_each(p, &cache_l2.table.list) { - pnd = list_entry(p, struct spectra_l2_cache_list, list); - if (pnd->logical_blk_num == logical_blk_num) { - tmp = pnd->pages_array[logical_page_num]; - break; - } - } - - if (tmp != MAX_U32_VALUE) { /* Found valid map */ - phy_blk = cache_l2.blk_array[(tmp >> 16) & 0xFFFF]; - phy_page = tmp & 0xFFFF; -#if CMD_DMA - /* TODO */ -#else - ret = GLOB_LLD_Read_Page_Main(buf, phy_blk, phy_page, 1); -#endif - } - - return ret; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Write_Page -* Inputs: Pointer to buffer, page address, cache block number -* Outputs: PASS=0 / FAIL=1 -* Description: It writes the data in Cache Block -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static void FTL_Cache_Write_Page(u8 *pData, u64 page_addr, - u8 cache_blk, u16 flag) -{ - u8 *pDest; - u64 addr; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - addr = Cache.array[cache_blk].address; - pDest = Cache.array[cache_blk].buf; - - pDest += (unsigned long)(page_addr - addr); - Cache.array[cache_blk].changed = SET; -#if CMD_DMA -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - int_cache[ftl_cmd_cnt].item = cache_blk; - int_cache[ftl_cmd_cnt].cache.address = - Cache.array[cache_blk].address; - int_cache[ftl_cmd_cnt].cache.changed = - Cache.array[cache_blk].changed; -#endif - GLOB_LLD_MemCopy_CMD(pDest, pData, DeviceInfo.wPageDataSize, flag); - ftl_cmd_cnt++; -#else - memcpy(pDest, pData, DeviceInfo.wPageDataSize); -#endif - if (Cache.array[cache_blk].use_cnt < MAX_WORD_VALUE) - Cache.array[cache_blk].use_cnt++; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Write -* Inputs: none -* Outputs: PASS=0 / FAIL=1 -* Description: It writes least frequently used Cache block to flash if it -* has been changed -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Write(void) -{ - int i, bResult = PASS; - u16 bNO, least_count = 0xFFFF; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - FTL_Calculate_LRU(); - - bNO = Cache.LRU; - nand_dbg_print(NAND_DBG_DEBUG, "FTL_Cache_Write: " - "Least used cache block is %d\n", bNO); - - if (Cache.array[bNO].changed != SET) - return bResult; - - nand_dbg_print(NAND_DBG_DEBUG, "FTL_Cache_Write: Cache" - " Block %d containing logical block %d is dirty\n", - bNO, - (u32)(Cache.array[bNO].address >> - DeviceInfo.nBitsInBlockDataSize)); -#if CMD_DMA -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - int_cache[ftl_cmd_cnt].item = bNO; - int_cache[ftl_cmd_cnt].cache.address = - Cache.array[bNO].address; - int_cache[ftl_cmd_cnt].cache.changed = CLEAR; -#endif -#endif - bResult = write_back_to_l2_cache(Cache.array[bNO].buf, - Cache.array[bNO].address); - if (bResult != ERR) - Cache.array[bNO].changed = CLEAR; - - least_count = Cache.array[bNO].use_cnt; - - for (i = 0; i < CACHE_ITEM_NUM; i++) { - if (i == bNO) - continue; - if (Cache.array[i].use_cnt > 0) - Cache.array[i].use_cnt -= least_count; - } - - return bResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Read -* Inputs: Page address -* Outputs: PASS=0 / FAIL=1 -* Description: It reads the block from device in Cache Block -* Set the LRU count to 1 -* Mark the Cache Block as clean -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Read(u64 logical_addr) -{ - u64 item_addr, phy_addr; - u16 num; - int ret; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - num = Cache.LRU; /* The LRU cache item will be overwritten */ - - item_addr = (u64)GLOB_u64_Div(logical_addr, Cache.cache_item_size) * - Cache.cache_item_size; - Cache.array[num].address = item_addr; - Cache.array[num].use_cnt = 1; - Cache.array[num].changed = CLEAR; - -#if CMD_DMA -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - int_cache[ftl_cmd_cnt].item = num; - int_cache[ftl_cmd_cnt].cache.address = - Cache.array[num].address; - int_cache[ftl_cmd_cnt].cache.changed = - Cache.array[num].changed; -#endif -#endif - /* - * Search in L2 Cache. If hit, fill data into L1 Cache item buffer, - * Otherwise, read it from NAND - */ - ret = search_l2_cache(Cache.array[num].buf, logical_addr); - if (PASS == ret) /* Hit in L2 Cache */ - return ret; - - /* Compute the physical start address of NAND device according to */ - /* the logical start address of the cache item (LRU cache item) */ - phy_addr = FTL_Get_Physical_Block_Addr(item_addr) + - GLOB_u64_Remainder(item_addr, 2); - - return FTL_Cache_Read_All(Cache.array[num].buf, phy_addr); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Check_Block_Table -* Inputs: ? -* Outputs: PASS=0 / FAIL=1 -* Description: It checks the correctness of each block table entry -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Check_Block_Table(int wOldTable) -{ - u32 i; - int wResult = PASS; - u32 blk_idx; - u32 *pbt = (u32 *)g_pBlockTable; - u8 *pFlag = flag_check_blk_table; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (NULL != pFlag) { - memset(pFlag, FAIL, DeviceInfo.wDataBlockNum); - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - blk_idx = (u32)(pbt[i] & (~BAD_BLOCK)); - - /* - * 20081006/KBV - Changed to pFlag[i] reference - * to avoid buffer overflow - */ - - /* - * 2008-10-20 Yunpeng Note: This change avoid - * buffer overflow, but changed function of - * the code, so it should be re-write later - */ - if ((blk_idx > DeviceInfo.wSpectraEndBlock) || - PASS == pFlag[i]) { - wResult = FAIL; - break; - } else { - pFlag[i] = PASS; - } - } - } - - return wResult; -} - - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Write_Block_Table -* Inputs: flasg -* Outputs: 0=Block Table was updated. No write done. 1=Block write needs to -* happen. -1 Error -* Description: It writes the block table -* Block table always mapped to LBA 0 which inturn mapped -* to any physical block -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Write_Block_Table(int wForce) -{ - u32 *pbt = (u32 *)g_pBlockTable; - int wSuccess = PASS; - u32 wTempBlockTableIndex; - u16 bt_pages, new_bt_offset; - u8 blockchangeoccured = 0; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - bt_pages = FTL_Get_Block_Table_Flash_Size_Pages(); - - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) - return 0; - - if (PASS == wForce) { - g_wBlockTableOffset = - (u16)(DeviceInfo.wPagesPerBlock - bt_pages); -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->g_wBlockTableOffset = - g_wBlockTableOffset; - p_BTableChangesDelta->ValidFields = 0x01; -#endif - } - - nand_dbg_print(NAND_DBG_DEBUG, - "Inside FTL_Write_Block_Table: block %d Page:%d\n", - g_wBlockTableIndex, g_wBlockTableOffset); - - do { - new_bt_offset = g_wBlockTableOffset + bt_pages + 1; - if ((0 == (new_bt_offset % DeviceInfo.wPagesPerBlock)) || - (new_bt_offset > DeviceInfo.wPagesPerBlock) || - (FAIL == wSuccess)) { - wTempBlockTableIndex = FTL_Replace_Block_Table(); - if (BAD_BLOCK == wTempBlockTableIndex) - return ERR; - if (!blockchangeoccured) { - bt_block_changed = 1; - blockchangeoccured = 1; - } - - g_wBlockTableIndex = wTempBlockTableIndex; - g_wBlockTableOffset = 0; - pbt[BLOCK_TABLE_INDEX] = g_wBlockTableIndex; -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->g_wBlockTableOffset = - g_wBlockTableOffset; - p_BTableChangesDelta->g_wBlockTableIndex = - g_wBlockTableIndex; - p_BTableChangesDelta->ValidFields = 0x03; - - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = - BLOCK_TABLE_INDEX; - p_BTableChangesDelta->BT_Entry_Value = - pbt[BLOCK_TABLE_INDEX]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - } - - wSuccess = FTL_Write_Block_Table_Data(); - if (FAIL == wSuccess) - MARK_BLOCK_AS_BAD(pbt[BLOCK_TABLE_INDEX]); - } while (FAIL == wSuccess); - - g_cBlockTableStatus = CURRENT_BLOCK_TABLE; - - return 1; -} - -static int force_format_nand(void) -{ - u32 i; - - /* Force erase the whole unprotected physical partiton of NAND */ - printk(KERN_ALERT "Start to force erase whole NAND device ...\n"); - printk(KERN_ALERT "From phyical block %d to %d\n", - DeviceInfo.wSpectraStartBlock, DeviceInfo.wSpectraEndBlock); - for (i = DeviceInfo.wSpectraStartBlock; i <= DeviceInfo.wSpectraEndBlock; i++) { - if (GLOB_LLD_Erase_Block(i)) - printk(KERN_ERR "Failed to force erase NAND block %d\n", i); - } - printk(KERN_ALERT "Force Erase ends. Please reboot the system ...\n"); - while(1); - - return PASS; -} - -int GLOB_FTL_Flash_Format(void) -{ - //return FTL_Format_Flash(1); - return force_format_nand(); - -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Search_Block_Table_IN_Block -* Inputs: Block Number -* Pointer to page -* Outputs: PASS / FAIL -* Page contatining the block table -* Description: It searches the block table in the block -* passed as an argument. -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Search_Block_Table_IN_Block(u32 BT_Block, - u8 BT_Tag, u16 *Page) -{ - u16 i, j, k; - u16 Result = PASS; - u16 Last_IPF = 0; - u8 BT_Found = 0; - u8 *tagarray; - u8 *tempbuf = tmp_buf_search_bt_in_block; - u8 *pSpareBuf = spare_buf_search_bt_in_block; - u8 *pSpareBufBTLastPage = spare_buf_bt_search_bt_in_block; - u8 bt_flag_last_page = 0xFF; - u8 search_in_previous_pages = 0; - u16 bt_pages; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - nand_dbg_print(NAND_DBG_DEBUG, - "Searching block table in %u block\n", - (unsigned int)BT_Block); - - bt_pages = FTL_Get_Block_Table_Flash_Size_Pages(); - - for (i = bt_pages; i < DeviceInfo.wPagesPerBlock; - i += (bt_pages + 1)) { - nand_dbg_print(NAND_DBG_DEBUG, - "Searching last IPF: %d\n", i); - Result = GLOB_LLD_Read_Page_Main_Polling(tempbuf, - BT_Block, i, 1); - - if (0 == memcmp(tempbuf, g_pIPF, DeviceInfo.wPageDataSize)) { - if ((i + bt_pages + 1) < DeviceInfo.wPagesPerBlock) { - continue; - } else { - search_in_previous_pages = 1; - Last_IPF = i; - } - } - - if (!search_in_previous_pages) { - if (i != bt_pages) { - i -= (bt_pages + 1); - Last_IPF = i; - } - } - - if (0 == Last_IPF) - break; - - if (!search_in_previous_pages) { - i = i + 1; - nand_dbg_print(NAND_DBG_DEBUG, - "Reading the spare area of Block %u Page %u", - (unsigned int)BT_Block, i); - Result = GLOB_LLD_Read_Page_Spare(pSpareBuf, - BT_Block, i, 1); - nand_dbg_print(NAND_DBG_DEBUG, - "Reading the spare area of Block %u Page %u", - (unsigned int)BT_Block, i + bt_pages - 1); - Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage, - BT_Block, i + bt_pages - 1, 1); - - k = 0; - j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray); - if (j) { - for (; k < j; k++) { - if (tagarray[k] == BT_Tag) - break; - } - } - - if (k < j) - bt_flag = tagarray[k]; - else - Result = FAIL; - - if (Result == PASS) { - k = 0; - j = FTL_Extract_Block_Table_Tag( - pSpareBufBTLastPage, &tagarray); - if (j) { - for (; k < j; k++) { - if (tagarray[k] == BT_Tag) - break; - } - } - - if (k < j) - bt_flag_last_page = tagarray[k]; - else - Result = FAIL; - - if (Result == PASS) { - if (bt_flag == bt_flag_last_page) { - nand_dbg_print(NAND_DBG_DEBUG, - "Block table is found" - " in page after IPF " - "at block %d " - "page %d\n", - (int)BT_Block, i); - BT_Found = 1; - *Page = i; - g_cBlockTableStatus = - CURRENT_BLOCK_TABLE; - break; - } else { - Result = FAIL; - } - } - } - } - - if (search_in_previous_pages) - i = i - bt_pages; - else - i = i - (bt_pages + 1); - - Result = PASS; - - nand_dbg_print(NAND_DBG_DEBUG, - "Reading the spare area of Block %d Page %d", - (int)BT_Block, i); - - Result = GLOB_LLD_Read_Page_Spare(pSpareBuf, BT_Block, i, 1); - nand_dbg_print(NAND_DBG_DEBUG, - "Reading the spare area of Block %u Page %u", - (unsigned int)BT_Block, i + bt_pages - 1); - - Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage, - BT_Block, i + bt_pages - 1, 1); - - k = 0; - j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray); - if (j) { - for (; k < j; k++) { - if (tagarray[k] == BT_Tag) - break; - } - } - - if (k < j) - bt_flag = tagarray[k]; - else - Result = FAIL; - - if (Result == PASS) { - k = 0; - j = FTL_Extract_Block_Table_Tag(pSpareBufBTLastPage, - &tagarray); - if (j) { - for (; k < j; k++) { - if (tagarray[k] == BT_Tag) - break; - } - } - - if (k < j) { - bt_flag_last_page = tagarray[k]; - } else { - Result = FAIL; - break; - } - - if (Result == PASS) { - if (bt_flag == bt_flag_last_page) { - nand_dbg_print(NAND_DBG_DEBUG, - "Block table is found " - "in page prior to IPF " - "at block %u page %d\n", - (unsigned int)BT_Block, i); - BT_Found = 1; - *Page = i; - g_cBlockTableStatus = - IN_PROGRESS_BLOCK_TABLE; - break; - } else { - Result = FAIL; - break; - } - } - } - } - - if (Result == FAIL) { - if ((Last_IPF > bt_pages) && (i < Last_IPF) && (!BT_Found)) { - BT_Found = 1; - *Page = i - (bt_pages + 1); - } - if ((Last_IPF == bt_pages) && (i < Last_IPF) && (!BT_Found)) - goto func_return; - } - - if (Last_IPF == 0) { - i = 0; - Result = PASS; - nand_dbg_print(NAND_DBG_DEBUG, "Reading the spare area of " - "Block %u Page %u", (unsigned int)BT_Block, i); - - Result = GLOB_LLD_Read_Page_Spare(pSpareBuf, BT_Block, i, 1); - nand_dbg_print(NAND_DBG_DEBUG, - "Reading the spare area of Block %u Page %u", - (unsigned int)BT_Block, i + bt_pages - 1); - Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage, - BT_Block, i + bt_pages - 1, 1); - - k = 0; - j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray); - if (j) { - for (; k < j; k++) { - if (tagarray[k] == BT_Tag) - break; - } - } - - if (k < j) - bt_flag = tagarray[k]; - else - Result = FAIL; - - if (Result == PASS) { - k = 0; - j = FTL_Extract_Block_Table_Tag(pSpareBufBTLastPage, - &tagarray); - if (j) { - for (; k < j; k++) { - if (tagarray[k] == BT_Tag) - break; - } - } - - if (k < j) - bt_flag_last_page = tagarray[k]; - else - Result = FAIL; - - if (Result == PASS) { - if (bt_flag == bt_flag_last_page) { - nand_dbg_print(NAND_DBG_DEBUG, - "Block table is found " - "in page after IPF at " - "block %u page %u\n", - (unsigned int)BT_Block, - (unsigned int)i); - BT_Found = 1; - *Page = i; - g_cBlockTableStatus = - CURRENT_BLOCK_TABLE; - goto func_return; - } else { - Result = FAIL; - } - } - } - - if (Result == FAIL) - goto func_return; - } -func_return: - return Result; -} - -u8 *get_blk_table_start_addr(void) -{ - return g_pBlockTable; -} - -unsigned long get_blk_table_len(void) -{ - return DeviceInfo.wDataBlockNum * sizeof(u32); -} - -u8 *get_wear_leveling_table_start_addr(void) -{ - return g_pWearCounter; -} - -unsigned long get_wear_leveling_table_len(void) -{ - return DeviceInfo.wDataBlockNum * sizeof(u8); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Read_Block_Table -* Inputs: none -* Outputs: PASS / FAIL -* Description: read the flash spare area and find a block containing the -* most recent block table(having largest block_table_counter). -* Find the last written Block table in this block. -* Check the correctness of Block Table -* If CDMA is enabled, this function is called in -* polling mode. -* We don't need to store changes in Block table in this -* function as it is called only at initialization -* -* Note: Currently this function is called at initialization -* before any read/erase/write command issued to flash so, -* there is no need to wait for CDMA list to complete as of now -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Read_Block_Table(void) -{ - u16 i = 0; - int k, j; - u8 *tempBuf, *tagarray; - int wResult = FAIL; - int status = FAIL; - u8 block_table_found = 0; - int search_result; - u32 Block; - u16 Page = 0; - u16 PageCount; - u16 bt_pages; - int wBytesCopied = 0, tempvar; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - tempBuf = tmp_buf1_read_blk_table; - bt_pages = FTL_Get_Block_Table_Flash_Size_Pages(); - - for (j = DeviceInfo.wSpectraStartBlock; - j <= (int)DeviceInfo.wSpectraEndBlock; - j++) { - status = GLOB_LLD_Read_Page_Spare(tempBuf, j, 0, 1); - k = 0; - i = FTL_Extract_Block_Table_Tag(tempBuf, &tagarray); - if (i) { - status = GLOB_LLD_Read_Page_Main_Polling(tempBuf, - j, 0, 1); - for (; k < i; k++) { - if (tagarray[k] == tempBuf[3]) - break; - } - } - - if (k < i) - k = tagarray[k]; - else - continue; - - nand_dbg_print(NAND_DBG_DEBUG, - "Block table is contained in Block %d %d\n", - (unsigned int)j, (unsigned int)k); - - if (g_pBTBlocks[k-FIRST_BT_ID] == BTBLOCK_INVAL) { - g_pBTBlocks[k-FIRST_BT_ID] = j; - block_table_found = 1; - } else { - printk(KERN_ERR "FTL_Read_Block_Table -" - "This should never happens. " - "Two block table have same counter %u!\n", k); - } - } - - if (block_table_found) { - if (g_pBTBlocks[FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL && - g_pBTBlocks[LAST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL) { - j = LAST_BT_ID; - while ((j > FIRST_BT_ID) && - (g_pBTBlocks[j - FIRST_BT_ID] != BTBLOCK_INVAL)) - j--; - if (j == FIRST_BT_ID) { - j = LAST_BT_ID; - last_erased = LAST_BT_ID; - } else { - last_erased = (u8)j + 1; - while ((j > FIRST_BT_ID) && (BTBLOCK_INVAL == - g_pBTBlocks[j - FIRST_BT_ID])) - j--; - } - } else { - j = FIRST_BT_ID; - while (g_pBTBlocks[j - FIRST_BT_ID] == BTBLOCK_INVAL) - j++; - last_erased = (u8)j; - while ((j < LAST_BT_ID) && (BTBLOCK_INVAL != - g_pBTBlocks[j - FIRST_BT_ID])) - j++; - if (g_pBTBlocks[j-FIRST_BT_ID] == BTBLOCK_INVAL) - j--; - } - - if (last_erased > j) - j += (1 + LAST_BT_ID - FIRST_BT_ID); - - for (; (j >= last_erased) && (FAIL == wResult); j--) { - i = (j - FIRST_BT_ID) % - (1 + LAST_BT_ID - FIRST_BT_ID); - search_result = - FTL_Search_Block_Table_IN_Block(g_pBTBlocks[i], - i + FIRST_BT_ID, &Page); - if (g_cBlockTableStatus == IN_PROGRESS_BLOCK_TABLE) - block_table_found = 0; - - while ((search_result == PASS) && (FAIL == wResult)) { - nand_dbg_print(NAND_DBG_DEBUG, - "FTL_Read_Block_Table:" - "Block: %u Page: %u " - "contains block table\n", - (unsigned int)g_pBTBlocks[i], - (unsigned int)Page); - - tempBuf = tmp_buf2_read_blk_table; - - for (k = 0; k < bt_pages; k++) { - Block = g_pBTBlocks[i]; - PageCount = 1; - - status = - GLOB_LLD_Read_Page_Main_Polling( - tempBuf, Block, Page, PageCount); - - tempvar = k ? 0 : 4; - - wBytesCopied += - FTL_Copy_Block_Table_From_Flash( - tempBuf + tempvar, - DeviceInfo.wPageDataSize - tempvar, - wBytesCopied); - - Page++; - } - - wResult = FTL_Check_Block_Table(FAIL); - if (FAIL == wResult) { - block_table_found = 0; - if (Page > bt_pages) - Page -= ((bt_pages<<1) + 1); - else - search_result = FAIL; - } - } - } - } - - if (PASS == wResult) { - if (!block_table_found) - FTL_Execute_SPL_Recovery(); - - if (g_cBlockTableStatus == IN_PROGRESS_BLOCK_TABLE) - g_wBlockTableOffset = (u16)Page + 1; - else - g_wBlockTableOffset = (u16)Page - bt_pages; - - g_wBlockTableIndex = (u32)g_pBTBlocks[i]; - -#if CMD_DMA - if (DeviceInfo.MLCDevice) - memcpy(g_pBTStartingCopy, g_pBlockTable, - DeviceInfo.wDataBlockNum * sizeof(u32) - + DeviceInfo.wDataBlockNum * sizeof(u8) - + DeviceInfo.wDataBlockNum * sizeof(u16)); - else - memcpy(g_pBTStartingCopy, g_pBlockTable, - DeviceInfo.wDataBlockNum * sizeof(u32) - + DeviceInfo.wDataBlockNum * sizeof(u8)); -#endif - } - - if (FAIL == wResult) - printk(KERN_ERR "Yunpeng - " - "Can not find valid spectra block table!\n"); - -#if AUTO_FORMAT_FLASH - if (FAIL == wResult) { - nand_dbg_print(NAND_DBG_DEBUG, "doing auto-format\n"); - wResult = FTL_Format_Flash(0); - } -#endif - - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Get_Page_Num -* Inputs: Size in bytes -* Outputs: Size in pages -* Description: It calculates the pages required for the length passed -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u32 FTL_Get_Page_Num(u64 length) -{ - return (u32)((length >> DeviceInfo.nBitsInPageDataSize) + - (GLOB_u64_Remainder(length , 1) > 0 ? 1 : 0)); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Get_Physical_Block_Addr -* Inputs: Block Address (byte format) -* Outputs: Physical address of the block. -* Description: It translates LBA to PBA by returning address stored -* at the LBA location in the block table -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u64 FTL_Get_Physical_Block_Addr(u64 logical_addr) -{ - u32 *pbt; - u64 physical_addr; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - pbt = (u32 *)g_pBlockTable; - physical_addr = (u64) DeviceInfo.wBlockDataSize * - (pbt[BLK_FROM_ADDR(logical_addr)] & (~BAD_BLOCK)); - - return physical_addr; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Get_Block_Index -* Inputs: Physical Block no. -* Outputs: Logical block no. /BAD_BLOCK -* Description: It returns the logical block no. for the PBA passed -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u32 FTL_Get_Block_Index(u32 wBlockNum) -{ - u32 *pbt = (u32 *)g_pBlockTable; - u32 i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) - if (wBlockNum == (pbt[i] & (~BAD_BLOCK))) - return i; - - return BAD_BLOCK; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Wear_Leveling -* Inputs: none -* Outputs: PASS=0 -* Description: This is static wear leveling (done by explicit call) -* do complete static wear leveling -* do complete garbage collection -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Wear_Leveling(void) -{ - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - FTL_Static_Wear_Leveling(); - GLOB_FTL_Garbage_Collection(); - - return PASS; -} - -static void find_least_most_worn(u8 *chg, - u32 *least_idx, u8 *least_cnt, - u32 *most_idx, u8 *most_cnt) -{ - u32 *pbt = (u32 *)g_pBlockTable; - u32 idx; - u8 cnt; - int i; - - for (i = BLOCK_TABLE_INDEX + 1; i < DeviceInfo.wDataBlockNum; i++) { - if (IS_BAD_BLOCK(i) || PASS == chg[i]) - continue; - - idx = (u32) ((~BAD_BLOCK) & pbt[i]); - cnt = g_pWearCounter[idx - DeviceInfo.wSpectraStartBlock]; - - if (IS_SPARE_BLOCK(i)) { - if (cnt > *most_cnt) { - *most_cnt = cnt; - *most_idx = idx; - } - } - - if (IS_DATA_BLOCK(i)) { - if (cnt < *least_cnt) { - *least_cnt = cnt; - *least_idx = idx; - } - } - - if (PASS == chg[*most_idx] || PASS == chg[*least_idx]) { - debug_boundary_error(*most_idx, - DeviceInfo.wDataBlockNum, 0); - debug_boundary_error(*least_idx, - DeviceInfo.wDataBlockNum, 0); - continue; - } - } -} - -static int move_blks_for_wear_leveling(u8 *chg, - u32 *least_idx, u32 *rep_blk_num, int *result) -{ - u32 *pbt = (u32 *)g_pBlockTable; - u32 rep_blk; - int j, ret_cp_blk, ret_erase; - int ret = PASS; - - chg[*least_idx] = PASS; - debug_boundary_error(*least_idx, DeviceInfo.wDataBlockNum, 0); - - rep_blk = FTL_Replace_MWBlock(); - if (rep_blk != BAD_BLOCK) { - nand_dbg_print(NAND_DBG_DEBUG, - "More than two spare blocks exist so do it\n"); - nand_dbg_print(NAND_DBG_DEBUG, "Block Replaced is %d\n", - rep_blk); - - chg[rep_blk] = PASS; - - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - for (j = 0; j < RETRY_TIMES; j++) { - ret_cp_blk = FTL_Copy_Block((u64)(*least_idx) * - DeviceInfo.wBlockDataSize, - (u64)rep_blk * DeviceInfo.wBlockDataSize); - if (FAIL == ret_cp_blk) { - ret_erase = GLOB_FTL_Block_Erase((u64)rep_blk - * DeviceInfo.wBlockDataSize); - if (FAIL == ret_erase) - MARK_BLOCK_AS_BAD(pbt[rep_blk]); - } else { - nand_dbg_print(NAND_DBG_DEBUG, - "FTL_Copy_Block == OK\n"); - break; - } - } - - if (j < RETRY_TIMES) { - u32 tmp; - u32 old_idx = FTL_Get_Block_Index(*least_idx); - u32 rep_idx = FTL_Get_Block_Index(rep_blk); - tmp = (u32)(DISCARD_BLOCK | pbt[old_idx]); - pbt[old_idx] = (u32)((~SPARE_BLOCK) & - pbt[rep_idx]); - pbt[rep_idx] = tmp; -#if CMD_DMA - p_BTableChangesDelta = (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = old_idx; - p_BTableChangesDelta->BT_Entry_Value = pbt[old_idx]; - p_BTableChangesDelta->ValidFields = 0x0C; - - p_BTableChangesDelta = (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = rep_idx; - p_BTableChangesDelta->BT_Entry_Value = pbt[rep_idx]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - } else { - pbt[FTL_Get_Block_Index(rep_blk)] |= BAD_BLOCK; -#if CMD_DMA - p_BTableChangesDelta = (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = - FTL_Get_Block_Index(rep_blk); - p_BTableChangesDelta->BT_Entry_Value = - pbt[FTL_Get_Block_Index(rep_blk)]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - *result = FAIL; - ret = FAIL; - } - - if (((*rep_blk_num)++) > WEAR_LEVELING_BLOCK_NUM) - ret = FAIL; - } else { - printk(KERN_ERR "Less than 3 spare blocks exist so quit\n"); - ret = FAIL; - } - - return ret; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Static_Wear_Leveling -* Inputs: none -* Outputs: PASS=0 / FAIL=1 -* Description: This is static wear leveling (done by explicit call) -* search for most&least used -* if difference < GATE: -* update the block table with exhange -* mark block table in flash as IN_PROGRESS -* copy flash block -* the caller should handle GC clean up after calling this function -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int FTL_Static_Wear_Leveling(void) -{ - u8 most_worn_cnt; - u8 least_worn_cnt; - u32 most_worn_idx; - u32 least_worn_idx; - int result = PASS; - int go_on = PASS; - u32 replaced_blks = 0; - u8 *chang_flag = flags_static_wear_leveling; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (!chang_flag) - return FAIL; - - memset(chang_flag, FAIL, DeviceInfo.wDataBlockNum); - while (go_on == PASS) { - nand_dbg_print(NAND_DBG_DEBUG, - "starting static wear leveling\n"); - most_worn_cnt = 0; - least_worn_cnt = 0xFF; - least_worn_idx = BLOCK_TABLE_INDEX; - most_worn_idx = BLOCK_TABLE_INDEX; - - find_least_most_worn(chang_flag, &least_worn_idx, - &least_worn_cnt, &most_worn_idx, &most_worn_cnt); - - nand_dbg_print(NAND_DBG_DEBUG, - "Used and least worn is block %u, whos count is %u\n", - (unsigned int)least_worn_idx, - (unsigned int)least_worn_cnt); - - nand_dbg_print(NAND_DBG_DEBUG, - "Free and most worn is block %u, whos count is %u\n", - (unsigned int)most_worn_idx, - (unsigned int)most_worn_cnt); - - if ((most_worn_cnt > least_worn_cnt) && - (most_worn_cnt - least_worn_cnt > WEAR_LEVELING_GATE)) - go_on = move_blks_for_wear_leveling(chang_flag, - &least_worn_idx, &replaced_blks, &result); - else - go_on = FAIL; - } - - return result; -} - -#if CMD_DMA -static int do_garbage_collection(u32 discard_cnt) -{ - u32 *pbt = (u32 *)g_pBlockTable; - u32 pba; - u8 bt_block_erased = 0; - int i, cnt, ret = FAIL; - u64 addr; - - i = 0; - while ((i < DeviceInfo.wDataBlockNum) && (discard_cnt > 0) && - ((ftl_cmd_cnt + 28) < 256)) { - if (((pbt[i] & BAD_BLOCK) != BAD_BLOCK) && - (pbt[i] & DISCARD_BLOCK)) { - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - addr = FTL_Get_Physical_Block_Addr((u64)i * - DeviceInfo.wBlockDataSize); - pba = BLK_FROM_ADDR(addr); - - for (cnt = FIRST_BT_ID; cnt <= LAST_BT_ID; cnt++) { - if (pba == g_pBTBlocks[cnt - FIRST_BT_ID]) { - nand_dbg_print(NAND_DBG_DEBUG, - "GC will erase BT block %u\n", - (unsigned int)pba); - discard_cnt--; - i++; - bt_block_erased = 1; - break; - } - } - - if (bt_block_erased) { - bt_block_erased = 0; - continue; - } - - addr = FTL_Get_Physical_Block_Addr((u64)i * - DeviceInfo.wBlockDataSize); - - if (PASS == GLOB_FTL_Block_Erase(addr)) { - pbt[i] &= (u32)(~DISCARD_BLOCK); - pbt[i] |= (u32)(SPARE_BLOCK); - p_BTableChangesDelta = - (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt - 1; - p_BTableChangesDelta->BT_Index = i; - p_BTableChangesDelta->BT_Entry_Value = pbt[i]; - p_BTableChangesDelta->ValidFields = 0x0C; - discard_cnt--; - ret = PASS; - } else { - MARK_BLOCK_AS_BAD(pbt[i]); - } - } - - i++; - } - - return ret; -} - -#else -static int do_garbage_collection(u32 discard_cnt) -{ - u32 *pbt = (u32 *)g_pBlockTable; - u32 pba; - u8 bt_block_erased = 0; - int i, cnt, ret = FAIL; - u64 addr; - - i = 0; - while ((i < DeviceInfo.wDataBlockNum) && (discard_cnt > 0)) { - if (((pbt[i] & BAD_BLOCK) != BAD_BLOCK) && - (pbt[i] & DISCARD_BLOCK)) { - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - addr = FTL_Get_Physical_Block_Addr((u64)i * - DeviceInfo.wBlockDataSize); - pba = BLK_FROM_ADDR(addr); - - for (cnt = FIRST_BT_ID; cnt <= LAST_BT_ID; cnt++) { - if (pba == g_pBTBlocks[cnt - FIRST_BT_ID]) { - nand_dbg_print(NAND_DBG_DEBUG, - "GC will erase BT block %d\n", - pba); - discard_cnt--; - i++; - bt_block_erased = 1; - break; - } - } - - if (bt_block_erased) { - bt_block_erased = 0; - continue; - } - - /* If the discard block is L2 cache block, then just skip it */ - for (cnt = 0; cnt < BLK_NUM_FOR_L2_CACHE; cnt++) { - if (cache_l2.blk_array[cnt] == pba) { - nand_dbg_print(NAND_DBG_DEBUG, - "GC will erase L2 cache blk %d\n", - pba); - break; - } - } - if (cnt < BLK_NUM_FOR_L2_CACHE) { /* Skip it */ - discard_cnt--; - i++; - continue; - } - - addr = FTL_Get_Physical_Block_Addr((u64)i * - DeviceInfo.wBlockDataSize); - - if (PASS == GLOB_FTL_Block_Erase(addr)) { - pbt[i] &= (u32)(~DISCARD_BLOCK); - pbt[i] |= (u32)(SPARE_BLOCK); - discard_cnt--; - ret = PASS; - } else { - MARK_BLOCK_AS_BAD(pbt[i]); - } - } - - i++; - } - - return ret; -} -#endif - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Garbage_Collection -* Inputs: none -* Outputs: PASS / FAIL (returns the number of un-erased blocks -* Description: search the block table for all discarded blocks to erase -* for each discarded block: -* set the flash block to IN_PROGRESS -* erase the block -* update the block table -* write the block table to flash -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Garbage_Collection(void) -{ - u32 i; - u32 wDiscard = 0; - int wResult = FAIL; - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (GC_Called) { - printk(KERN_ALERT "GLOB_FTL_Garbage_Collection() " - "has been re-entered! Exit.\n"); - return PASS; - } - - GC_Called = 1; - - GLOB_FTL_BT_Garbage_Collection(); - - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - if (IS_DISCARDED_BLOCK(i)) - wDiscard++; - } - - if (wDiscard <= 0) { - GC_Called = 0; - return wResult; - } - - nand_dbg_print(NAND_DBG_DEBUG, - "Found %d discarded blocks\n", wDiscard); - - FTL_Write_Block_Table(FAIL); - - wResult = do_garbage_collection(wDiscard); - - FTL_Write_Block_Table(FAIL); - - GC_Called = 0; - - return wResult; -} - - -#if CMD_DMA -static int do_bt_garbage_collection(void) -{ - u32 pba, lba; - u32 *pbt = (u32 *)g_pBlockTable; - u32 *pBTBlocksNode = (u32 *)g_pBTBlocks; - u64 addr; - int i, ret = FAIL; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (BT_GC_Called) - return PASS; - - BT_GC_Called = 1; - - for (i = last_erased; (i <= LAST_BT_ID) && - (g_pBTBlocks[((i + 2) % (1 + LAST_BT_ID - FIRST_BT_ID)) + - FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL) && - ((ftl_cmd_cnt + 28)) < 256; i++) { - pba = pBTBlocksNode[i - FIRST_BT_ID]; - lba = FTL_Get_Block_Index(pba); - nand_dbg_print(NAND_DBG_DEBUG, - "do_bt_garbage_collection: pba %d, lba %d\n", - pba, lba); - nand_dbg_print(NAND_DBG_DEBUG, - "Block Table Entry: %d", pbt[lba]); - - if (((pbt[lba] & BAD_BLOCK) != BAD_BLOCK) && - (pbt[lba] & DISCARD_BLOCK)) { - nand_dbg_print(NAND_DBG_DEBUG, - "do_bt_garbage_collection_cdma: " - "Erasing Block tables present in block %d\n", - pba); - addr = FTL_Get_Physical_Block_Addr((u64)lba * - DeviceInfo.wBlockDataSize); - if (PASS == GLOB_FTL_Block_Erase(addr)) { - pbt[lba] &= (u32)(~DISCARD_BLOCK); - pbt[lba] |= (u32)(SPARE_BLOCK); - - p_BTableChangesDelta = - (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt - 1; - p_BTableChangesDelta->BT_Index = lba; - p_BTableChangesDelta->BT_Entry_Value = - pbt[lba]; - - p_BTableChangesDelta->ValidFields = 0x0C; - - ret = PASS; - pBTBlocksNode[last_erased - FIRST_BT_ID] = - BTBLOCK_INVAL; - nand_dbg_print(NAND_DBG_DEBUG, - "resetting bt entry at index %d " - "value %d\n", i, - pBTBlocksNode[i - FIRST_BT_ID]); - if (last_erased == LAST_BT_ID) - last_erased = FIRST_BT_ID; - else - last_erased++; - } else { - MARK_BLOCK_AS_BAD(pbt[lba]); - } - } - } - - BT_GC_Called = 0; - - return ret; -} - -#else -static int do_bt_garbage_collection(void) -{ - u32 pba, lba; - u32 *pbt = (u32 *)g_pBlockTable; - u32 *pBTBlocksNode = (u32 *)g_pBTBlocks; - u64 addr; - int i, ret = FAIL; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (BT_GC_Called) - return PASS; - - BT_GC_Called = 1; - - for (i = last_erased; (i <= LAST_BT_ID) && - (g_pBTBlocks[((i + 2) % (1 + LAST_BT_ID - FIRST_BT_ID)) + - FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL); i++) { - pba = pBTBlocksNode[i - FIRST_BT_ID]; - lba = FTL_Get_Block_Index(pba); - nand_dbg_print(NAND_DBG_DEBUG, - "do_bt_garbage_collection_cdma: pba %d, lba %d\n", - pba, lba); - nand_dbg_print(NAND_DBG_DEBUG, - "Block Table Entry: %d", pbt[lba]); - - if (((pbt[lba] & BAD_BLOCK) != BAD_BLOCK) && - (pbt[lba] & DISCARD_BLOCK)) { - nand_dbg_print(NAND_DBG_DEBUG, - "do_bt_garbage_collection: " - "Erasing Block tables present in block %d\n", - pba); - addr = FTL_Get_Physical_Block_Addr((u64)lba * - DeviceInfo.wBlockDataSize); - if (PASS == GLOB_FTL_Block_Erase(addr)) { - pbt[lba] &= (u32)(~DISCARD_BLOCK); - pbt[lba] |= (u32)(SPARE_BLOCK); - ret = PASS; - pBTBlocksNode[last_erased - FIRST_BT_ID] = - BTBLOCK_INVAL; - nand_dbg_print(NAND_DBG_DEBUG, - "resetting bt entry at index %d " - "value %d\n", i, - pBTBlocksNode[i - FIRST_BT_ID]); - if (last_erased == LAST_BT_ID) - last_erased = FIRST_BT_ID; - else - last_erased++; - } else { - MARK_BLOCK_AS_BAD(pbt[lba]); - } - } - } - - BT_GC_Called = 0; - - return ret; -} - -#endif - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_BT_Garbage_Collection -* Inputs: none -* Outputs: PASS / FAIL (returns the number of un-erased blocks -* Description: Erases discarded blocks containing Block table -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_BT_Garbage_Collection(void) -{ - return do_bt_garbage_collection(); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Replace_OneBlock -* Inputs: Block number 1 -* Block number 2 -* Outputs: Replaced Block Number -* Description: Interchange block table entries at wBlockNum and wReplaceNum -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u32 FTL_Replace_OneBlock(u32 blk, u32 rep_blk) -{ - u32 tmp_blk; - u32 replace_node = BAD_BLOCK; - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (rep_blk != BAD_BLOCK) { - if (IS_BAD_BLOCK(blk)) - tmp_blk = pbt[blk]; - else - tmp_blk = DISCARD_BLOCK | (~SPARE_BLOCK & pbt[blk]); - - replace_node = (u32) ((~SPARE_BLOCK) & pbt[rep_blk]); - pbt[blk] = replace_node; - pbt[rep_blk] = tmp_blk; - -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = blk; - p_BTableChangesDelta->BT_Entry_Value = pbt[blk]; - - p_BTableChangesDelta->ValidFields = 0x0C; - - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = rep_blk; - p_BTableChangesDelta->BT_Entry_Value = pbt[rep_blk]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - } - - return replace_node; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Write_Block_Table_Data -* Inputs: Block table size in pages -* Outputs: PASS=0 / FAIL=1 -* Description: Write block table data in flash -* If first page and last page -* Write data+BT flag -* else -* Write data -* BT flag is a counter. Its value is incremented for block table -* write in a new Block -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Write_Block_Table_Data(void) -{ - u64 dwBlockTableAddr, pTempAddr; - u32 Block; - u16 Page, PageCount; - u8 *tempBuf = tmp_buf_write_blk_table_data; - int wBytesCopied; - u16 bt_pages; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - dwBlockTableAddr = - (u64)((u64)g_wBlockTableIndex * DeviceInfo.wBlockDataSize + - (u64)g_wBlockTableOffset * DeviceInfo.wPageDataSize); - pTempAddr = dwBlockTableAddr; - - bt_pages = FTL_Get_Block_Table_Flash_Size_Pages(); - - nand_dbg_print(NAND_DBG_DEBUG, "FTL_Write_Block_Table_Data: " - "page= %d BlockTableIndex= %d " - "BlockTableOffset=%d\n", bt_pages, - g_wBlockTableIndex, g_wBlockTableOffset); - - Block = BLK_FROM_ADDR(pTempAddr); - Page = PAGE_FROM_ADDR(pTempAddr, Block); - PageCount = 1; - - if (bt_block_changed) { - if (bt_flag == LAST_BT_ID) { - bt_flag = FIRST_BT_ID; - g_pBTBlocks[bt_flag - FIRST_BT_ID] = Block; - } else if (bt_flag < LAST_BT_ID) { - bt_flag++; - g_pBTBlocks[bt_flag - FIRST_BT_ID] = Block; - } - - if ((bt_flag > (LAST_BT_ID-4)) && - g_pBTBlocks[FIRST_BT_ID - FIRST_BT_ID] != - BTBLOCK_INVAL) { - bt_block_changed = 0; - GLOB_FTL_BT_Garbage_Collection(); - } - - bt_block_changed = 0; - nand_dbg_print(NAND_DBG_DEBUG, - "Block Table Counter is %u Block %u\n", - bt_flag, (unsigned int)Block); - } - - memset(tempBuf, 0, 3); - tempBuf[3] = bt_flag; - wBytesCopied = FTL_Copy_Block_Table_To_Flash(tempBuf + 4, - DeviceInfo.wPageDataSize - 4, 0); - memset(&tempBuf[wBytesCopied + 4], 0xff, - DeviceInfo.wPageSize - (wBytesCopied + 4)); - FTL_Insert_Block_Table_Signature(&tempBuf[DeviceInfo.wPageDataSize], - bt_flag); - -#if CMD_DMA - memcpy(g_pNextBlockTable, tempBuf, - DeviceInfo.wPageSize * sizeof(u8)); - nand_dbg_print(NAND_DBG_DEBUG, "Writing First Page of Block Table " - "Block %u Page %u\n", (unsigned int)Block, Page); - if (FAIL == GLOB_LLD_Write_Page_Main_Spare_cdma(g_pNextBlockTable, - Block, Page, 1, - LLD_CMD_FLAG_MODE_CDMA | LLD_CMD_FLAG_ORDER_BEFORE_REST)) { - nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in " - "%s, Line %d, Function: %s, " - "new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, Block); - goto func_return; - } - - ftl_cmd_cnt++; - g_pNextBlockTable += ((DeviceInfo.wPageSize * sizeof(u8))); -#else - if (FAIL == GLOB_LLD_Write_Page_Main_Spare(tempBuf, Block, Page, 1)) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, Function: %s, " - "new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, Block); - goto func_return; - } -#endif - - if (bt_pages > 1) { - PageCount = bt_pages - 1; - if (PageCount > 1) { - wBytesCopied += FTL_Copy_Block_Table_To_Flash(tempBuf, - DeviceInfo.wPageDataSize * (PageCount - 1), - wBytesCopied); - -#if CMD_DMA - memcpy(g_pNextBlockTable, tempBuf, - (PageCount - 1) * DeviceInfo.wPageDataSize); - if (FAIL == GLOB_LLD_Write_Page_Main_cdma( - g_pNextBlockTable, Block, Page + 1, - PageCount - 1)) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, " - "new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, - (int)Block); - goto func_return; - } - - ftl_cmd_cnt++; - g_pNextBlockTable += (PageCount - 1) * - DeviceInfo.wPageDataSize * sizeof(u8); -#else - if (FAIL == GLOB_LLD_Write_Page_Main(tempBuf, - Block, Page + 1, PageCount - 1)) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, " - "new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, - (int)Block); - goto func_return; - } -#endif - } - - wBytesCopied = FTL_Copy_Block_Table_To_Flash(tempBuf, - DeviceInfo.wPageDataSize, wBytesCopied); - memset(&tempBuf[wBytesCopied], 0xff, - DeviceInfo.wPageSize-wBytesCopied); - FTL_Insert_Block_Table_Signature( - &tempBuf[DeviceInfo.wPageDataSize], bt_flag); -#if CMD_DMA - memcpy(g_pNextBlockTable, tempBuf, - DeviceInfo.wPageSize * sizeof(u8)); - nand_dbg_print(NAND_DBG_DEBUG, - "Writing the last Page of Block Table " - "Block %u Page %u\n", - (unsigned int)Block, Page + bt_pages - 1); - if (FAIL == GLOB_LLD_Write_Page_Main_Spare_cdma( - g_pNextBlockTable, Block, Page + bt_pages - 1, 1, - LLD_CMD_FLAG_MODE_CDMA | - LLD_CMD_FLAG_ORDER_BEFORE_REST)) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, Block); - goto func_return; - } - ftl_cmd_cnt++; -#else - if (FAIL == GLOB_LLD_Write_Page_Main_Spare(tempBuf, - Block, Page+bt_pages - 1, 1)) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, " - "new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, Block); - goto func_return; - } -#endif - } - - nand_dbg_print(NAND_DBG_DEBUG, "FTL_Write_Block_Table_Data: done\n"); - -func_return: - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Replace_Block_Table -* Inputs: None -* Outputs: PASS=0 / FAIL=1 -* Description: Get a new block to write block table -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u32 FTL_Replace_Block_Table(void) -{ - u32 blk; - int gc; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - blk = FTL_Replace_LWBlock(BLOCK_TABLE_INDEX, &gc); - - if ((BAD_BLOCK == blk) && (PASS == gc)) { - GLOB_FTL_Garbage_Collection(); - blk = FTL_Replace_LWBlock(BLOCK_TABLE_INDEX, &gc); - } - if (BAD_BLOCK == blk) - printk(KERN_ERR "%s, %s: There is no spare block. " - "It should never happen\n", - __FILE__, __func__); - - nand_dbg_print(NAND_DBG_DEBUG, "New Block table Block is %d\n", blk); - - return blk; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Replace_LWBlock -* Inputs: Block number -* Pointer to Garbage Collect flag -* Outputs: -* Description: Determine the least weared block by traversing -* block table -* Set Garbage collection to be called if number of spare -* block is less than Free Block Gate count -* Change Block table entry to map least worn block for current -* operation -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u32 FTL_Replace_LWBlock(u32 wBlockNum, int *pGarbageCollect) -{ - u32 i; - u32 *pbt = (u32 *)g_pBlockTable; - u8 wLeastWornCounter = 0xFF; - u32 wLeastWornIndex = BAD_BLOCK; - u32 wSpareBlockNum = 0; - u32 wDiscardBlockNum = 0; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (IS_SPARE_BLOCK(wBlockNum)) { - *pGarbageCollect = FAIL; - pbt[wBlockNum] = (u32)(pbt[wBlockNum] & (~SPARE_BLOCK)); -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = (u32)(wBlockNum); - p_BTableChangesDelta->BT_Entry_Value = pbt[wBlockNum]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - return pbt[wBlockNum]; - } - - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - if (IS_DISCARDED_BLOCK(i)) - wDiscardBlockNum++; - - if (IS_SPARE_BLOCK(i)) { - u32 wPhysicalIndex = (u32)((~BAD_BLOCK) & pbt[i]); - if (wPhysicalIndex > DeviceInfo.wSpectraEndBlock) - printk(KERN_ERR "FTL_Replace_LWBlock: " - "This should never occur!\n"); - if (g_pWearCounter[wPhysicalIndex - - DeviceInfo.wSpectraStartBlock] < - wLeastWornCounter) { - wLeastWornCounter = - g_pWearCounter[wPhysicalIndex - - DeviceInfo.wSpectraStartBlock]; - wLeastWornIndex = i; - } - wSpareBlockNum++; - } - } - - nand_dbg_print(NAND_DBG_WARN, - "FTL_Replace_LWBlock: Least Worn Counter %d\n", - (int)wLeastWornCounter); - - if ((wDiscardBlockNum >= NUM_FREE_BLOCKS_GATE) || - (wSpareBlockNum <= NUM_FREE_BLOCKS_GATE)) - *pGarbageCollect = PASS; - else - *pGarbageCollect = FAIL; - - nand_dbg_print(NAND_DBG_DEBUG, - "FTL_Replace_LWBlock: Discarded Blocks %u Spare" - " Blocks %u\n", - (unsigned int)wDiscardBlockNum, - (unsigned int)wSpareBlockNum); - - return FTL_Replace_OneBlock(wBlockNum, wLeastWornIndex); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Replace_MWBlock -* Inputs: None -* Outputs: most worn spare block no./BAD_BLOCK -* Description: It finds most worn spare block. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static u32 FTL_Replace_MWBlock(void) -{ - u32 i; - u32 *pbt = (u32 *)g_pBlockTable; - u8 wMostWornCounter = 0; - u32 wMostWornIndex = BAD_BLOCK; - u32 wSpareBlockNum = 0; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - if (IS_SPARE_BLOCK(i)) { - u32 wPhysicalIndex = (u32)((~SPARE_BLOCK) & pbt[i]); - if (g_pWearCounter[wPhysicalIndex - - DeviceInfo.wSpectraStartBlock] > - wMostWornCounter) { - wMostWornCounter = - g_pWearCounter[wPhysicalIndex - - DeviceInfo.wSpectraStartBlock]; - wMostWornIndex = wPhysicalIndex; - } - wSpareBlockNum++; - } - } - - if (wSpareBlockNum <= 2) - return BAD_BLOCK; - - return wMostWornIndex; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Replace_Block -* Inputs: Block Address -* Outputs: PASS=0 / FAIL=1 -* Description: If block specified by blk_addr parameter is not free, -* replace it with the least worn block. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Replace_Block(u64 blk_addr) -{ - u32 current_blk = BLK_FROM_ADDR(blk_addr); - u32 *pbt = (u32 *)g_pBlockTable; - int wResult = PASS; - int GarbageCollect = FAIL; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (IS_SPARE_BLOCK(current_blk)) { - pbt[current_blk] = (~SPARE_BLOCK) & pbt[current_blk]; -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = current_blk; - p_BTableChangesDelta->BT_Entry_Value = pbt[current_blk]; - p_BTableChangesDelta->ValidFields = 0x0C ; -#endif - return wResult; - } - - FTL_Replace_LWBlock(current_blk, &GarbageCollect); - - if (PASS == GarbageCollect) - wResult = GLOB_FTL_Garbage_Collection(); - - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Is_BadBlock -* Inputs: block number to test -* Outputs: PASS (block is BAD) / FAIL (block is not bad) -* Description: test if this block number is flagged as bad -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Is_BadBlock(u32 wBlockNum) -{ - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (wBlockNum >= DeviceInfo.wSpectraStartBlock - && BAD_BLOCK == (pbt[wBlockNum] & BAD_BLOCK)) - return PASS; - else - return FAIL; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Flush_Cache -* Inputs: none -* Outputs: PASS=0 / FAIL=1 -* Description: flush all the cache blocks to flash -* if a cache block is not dirty, don't do anything with it -* else, write the block and update the block table -* Note: This function should be called at shutdown/power down. -* to write important data into device -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Flush_Cache(void) -{ - int i, ret; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < CACHE_ITEM_NUM; i++) { - if (SET == Cache.array[i].changed) { -#if CMD_DMA -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - int_cache[ftl_cmd_cnt].item = i; - int_cache[ftl_cmd_cnt].cache.address = - Cache.array[i].address; - int_cache[ftl_cmd_cnt].cache.changed = CLEAR; -#endif -#endif - ret = write_back_to_l2_cache(Cache.array[i].buf, Cache.array[i].address); - if (PASS == ret) { - Cache.array[i].changed = CLEAR; - } else { - printk(KERN_ALERT "Failed when write back to L2 cache!\n"); - /* TODO - How to handle this? */ - } - } - } - - flush_l2_cache(); - - return FTL_Write_Block_Table(FAIL); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Page_Read -* Inputs: pointer to data -* logical address of data (u64 is LBA * Bytes/Page) -* Outputs: PASS=0 / FAIL=1 -* Description: reads a page of data into RAM from the cache -* if the data is not already in cache, read from flash to cache -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Page_Read(u8 *data, u64 logical_addr) -{ - u16 cache_item; - int res = PASS; - - nand_dbg_print(NAND_DBG_DEBUG, "GLOB_FTL_Page_Read - " - "page_addr: %llu\n", logical_addr); - - cache_item = FTL_Cache_If_Hit(logical_addr); - - if (UNHIT_CACHE_ITEM == cache_item) { - nand_dbg_print(NAND_DBG_DEBUG, - "GLOB_FTL_Page_Read: Cache not hit\n"); - res = FTL_Cache_Write(); - if (ERR == FTL_Cache_Read(logical_addr)) - res = ERR; - cache_item = Cache.LRU; - } - - FTL_Cache_Read_Page(data, logical_addr, cache_item); - - return res; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Page_Write -* Inputs: pointer to data -* address of data (ADDRESSTYPE is LBA * Bytes/Page) -* Outputs: PASS=0 / FAIL=1 -* Description: writes a page of data from RAM to the cache -* if the data is not already in cache, write back the -* least recently used block and read the addressed block -* from flash to cache -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Page_Write(u8 *pData, u64 dwPageAddr) -{ - u16 cache_blk; - u32 *pbt = (u32 *)g_pBlockTable; - int wResult = PASS; - - nand_dbg_print(NAND_DBG_TRACE, "GLOB_FTL_Page_Write - " - "dwPageAddr: %llu\n", dwPageAddr); - - cache_blk = FTL_Cache_If_Hit(dwPageAddr); - - if (UNHIT_CACHE_ITEM == cache_blk) { - wResult = FTL_Cache_Write(); - if (IS_BAD_BLOCK(BLK_FROM_ADDR(dwPageAddr))) { - wResult = FTL_Replace_Block(dwPageAddr); - pbt[BLK_FROM_ADDR(dwPageAddr)] |= SPARE_BLOCK; - if (wResult == FAIL) - return FAIL; - } - if (ERR == FTL_Cache_Read(dwPageAddr)) - wResult = ERR; - cache_blk = Cache.LRU; - FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk, 0); - } else { -#if CMD_DMA - FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk, - LLD_CMD_FLAG_ORDER_BEFORE_REST); -#else - FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk, 0); -#endif - } - - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: GLOB_FTL_Block_Erase -* Inputs: address of block to erase (now in byte format, should change to -* block format) -* Outputs: PASS=0 / FAIL=1 -* Description: erases the specified block -* increments the erase count -* If erase count reaches its upper limit,call function to -* do the adjustment as per the relative erase count values -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int GLOB_FTL_Block_Erase(u64 blk_addr) -{ - int status; - u32 BlkIdx; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - BlkIdx = (u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize); - - if (BlkIdx < DeviceInfo.wSpectraStartBlock) { - printk(KERN_ERR "GLOB_FTL_Block_Erase: " - "This should never occur\n"); - return FAIL; - } - -#if CMD_DMA - status = GLOB_LLD_Erase_Block_cdma(BlkIdx, LLD_CMD_FLAG_MODE_CDMA); - if (status == FAIL) - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, BlkIdx); -#else - status = GLOB_LLD_Erase_Block(BlkIdx); - if (status == FAIL) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, BlkIdx); - return status; - } -#endif - - if (DeviceInfo.MLCDevice) { - g_pReadCounter[BlkIdx - DeviceInfo.wSpectraStartBlock] = 0; - if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - } - - g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock]++; - -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->WC_Index = - BlkIdx - DeviceInfo.wSpectraStartBlock; - p_BTableChangesDelta->WC_Entry_Value = - g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock]; - p_BTableChangesDelta->ValidFields = 0x30; - - if (DeviceInfo.MLCDevice) { - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->RC_Index = - BlkIdx - DeviceInfo.wSpectraStartBlock; - p_BTableChangesDelta->RC_Entry_Value = - g_pReadCounter[BlkIdx - - DeviceInfo.wSpectraStartBlock]; - p_BTableChangesDelta->ValidFields = 0xC0; - } - - ftl_cmd_cnt++; -#endif - - if (g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock] == 0xFE) - FTL_Adjust_Relative_Erase_Count(BlkIdx); - - return status; -} - - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Adjust_Relative_Erase_Count -* Inputs: index to block that was just incremented and is at the max -* Outputs: PASS=0 / FAIL=1 -* Description: If any erase counts at MAX, adjusts erase count of every -* block by subtracting least worn -* counter from counter value of every entry in wear table -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX) -{ - u8 wLeastWornCounter = MAX_BYTE_VALUE; - u8 wWearCounter; - u32 i, wWearIndex; - u32 *pbt = (u32 *)g_pBlockTable; - int wResult = PASS; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) { - if (IS_BAD_BLOCK(i)) - continue; - wWearIndex = (u32)(pbt[i] & (~BAD_BLOCK)); - - if ((wWearIndex - DeviceInfo.wSpectraStartBlock) < 0) - printk(KERN_ERR "FTL_Adjust_Relative_Erase_Count:" - "This should never occur\n"); - wWearCounter = g_pWearCounter[wWearIndex - - DeviceInfo.wSpectraStartBlock]; - if (wWearCounter < wLeastWornCounter) - wLeastWornCounter = wWearCounter; - } - - if (wLeastWornCounter == 0) { - nand_dbg_print(NAND_DBG_WARN, - "Adjusting Wear Levelling Counters: Special Case\n"); - g_pWearCounter[Index_of_MAX - - DeviceInfo.wSpectraStartBlock]--; -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->WC_Index = - Index_of_MAX - DeviceInfo.wSpectraStartBlock; - p_BTableChangesDelta->WC_Entry_Value = - g_pWearCounter[Index_of_MAX - - DeviceInfo.wSpectraStartBlock]; - p_BTableChangesDelta->ValidFields = 0x30; -#endif - FTL_Static_Wear_Leveling(); - } else { - for (i = 0; i < DeviceInfo.wDataBlockNum; i++) - if (!IS_BAD_BLOCK(i)) { - wWearIndex = (u32)(pbt[i] & (~BAD_BLOCK)); - g_pWearCounter[wWearIndex - - DeviceInfo.wSpectraStartBlock] = - (u8)(g_pWearCounter - [wWearIndex - - DeviceInfo.wSpectraStartBlock] - - wLeastWornCounter); -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->WC_Index = wWearIndex - - DeviceInfo.wSpectraStartBlock; - p_BTableChangesDelta->WC_Entry_Value = - g_pWearCounter[wWearIndex - - DeviceInfo.wSpectraStartBlock]; - p_BTableChangesDelta->ValidFields = 0x30; -#endif - } - } - - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Write_IN_Progress_Block_Table_Page -* Inputs: None -* Outputs: None -* Description: It writes in-progress flag page to the page next to -* block table -***********************************************************************/ -static int FTL_Write_IN_Progress_Block_Table_Page(void) -{ - int wResult = PASS; - u16 bt_pages; - u16 dwIPFPageAddr; -#if CMD_DMA -#else - u32 *pbt = (u32 *)g_pBlockTable; - u32 wTempBlockTableIndex; -#endif - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - bt_pages = FTL_Get_Block_Table_Flash_Size_Pages(); - - dwIPFPageAddr = g_wBlockTableOffset + bt_pages; - - nand_dbg_print(NAND_DBG_DEBUG, "Writing IPF at " - "Block %d Page %d\n", - g_wBlockTableIndex, dwIPFPageAddr); - -#if CMD_DMA - wResult = GLOB_LLD_Write_Page_Main_Spare_cdma(g_pIPF, - g_wBlockTableIndex, dwIPFPageAddr, 1, - LLD_CMD_FLAG_MODE_CDMA | LLD_CMD_FLAG_ORDER_BEFORE_REST); - if (wResult == FAIL) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, - g_wBlockTableIndex); - } - g_wBlockTableOffset = dwIPFPageAddr + 1; - p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->g_wBlockTableOffset = g_wBlockTableOffset; - p_BTableChangesDelta->ValidFields = 0x01; - ftl_cmd_cnt++; -#else - wResult = GLOB_LLD_Write_Page_Main_Spare(g_pIPF, - g_wBlockTableIndex, dwIPFPageAddr, 1); - if (wResult == FAIL) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, - (int)g_wBlockTableIndex); - MARK_BLOCK_AS_BAD(pbt[BLOCK_TABLE_INDEX]); - wTempBlockTableIndex = FTL_Replace_Block_Table(); - bt_block_changed = 1; - if (BAD_BLOCK == wTempBlockTableIndex) - return ERR; - g_wBlockTableIndex = wTempBlockTableIndex; - g_wBlockTableOffset = 0; - /* Block table tag is '00'. Means it's used one */ - pbt[BLOCK_TABLE_INDEX] = g_wBlockTableIndex; - return FAIL; - } - g_wBlockTableOffset = dwIPFPageAddr + 1; -#endif - return wResult; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Read_Disturbance -* Inputs: block address -* Outputs: PASS=0 / FAIL=1 -* Description: used to handle read disturbance. Data in block that -* reaches its read limit is moved to new block -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int FTL_Read_Disturbance(u32 blk_addr) -{ - int wResult = FAIL; - u32 *pbt = (u32 *) g_pBlockTable; - u32 dwOldBlockAddr = blk_addr; - u32 wBlockNum; - u32 i; - u32 wLeastReadCounter = 0xFFFF; - u32 wLeastReadIndex = BAD_BLOCK; - u32 wSpareBlockNum = 0; - u32 wTempNode; - u32 wReplacedNode; - u8 *g_pTempBuf; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - -#if CMD_DMA - g_pTempBuf = cp_back_buf_copies[cp_back_buf_idx]; - cp_back_buf_idx++; - if (cp_back_buf_idx > COPY_BACK_BUF_NUM) { - printk(KERN_ERR "cp_back_buf_copies overflow! Exit." - "Maybe too many pending commands in your CDMA chain.\n"); - return FAIL; - } -#else - g_pTempBuf = tmp_buf_read_disturbance; -#endif - - wBlockNum = FTL_Get_Block_Index(blk_addr); - - do { - /* This is a bug.Here 'i' should be logical block number - * and start from 1 (0 is reserved for block table). - * Have fixed it. - Yunpeng 2008. 12. 19 - */ - for (i = 1; i < DeviceInfo.wDataBlockNum; i++) { - if (IS_SPARE_BLOCK(i)) { - u32 wPhysicalIndex = - (u32)((~SPARE_BLOCK) & pbt[i]); - if (g_pReadCounter[wPhysicalIndex - - DeviceInfo.wSpectraStartBlock] < - wLeastReadCounter) { - wLeastReadCounter = - g_pReadCounter[wPhysicalIndex - - DeviceInfo.wSpectraStartBlock]; - wLeastReadIndex = i; - } - wSpareBlockNum++; - } - } - - if (wSpareBlockNum <= NUM_FREE_BLOCKS_GATE) { - wResult = GLOB_FTL_Garbage_Collection(); - if (PASS == wResult) - continue; - else - break; - } else { - wTempNode = (u32)(DISCARD_BLOCK | pbt[wBlockNum]); - wReplacedNode = (u32)((~SPARE_BLOCK) & - pbt[wLeastReadIndex]); -#if CMD_DMA - pbt[wBlockNum] = wReplacedNode; - pbt[wLeastReadIndex] = wTempNode; - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = wBlockNum; - p_BTableChangesDelta->BT_Entry_Value = pbt[wBlockNum]; - p_BTableChangesDelta->ValidFields = 0x0C; - - p_BTableChangesDelta = - (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = wLeastReadIndex; - p_BTableChangesDelta->BT_Entry_Value = - pbt[wLeastReadIndex]; - p_BTableChangesDelta->ValidFields = 0x0C; - - wResult = GLOB_LLD_Read_Page_Main_cdma(g_pTempBuf, - dwOldBlockAddr, 0, DeviceInfo.wPagesPerBlock, - LLD_CMD_FLAG_MODE_CDMA); - if (wResult == FAIL) - return wResult; - - ftl_cmd_cnt++; - - if (wResult != FAIL) { - if (FAIL == GLOB_LLD_Write_Page_Main_cdma( - g_pTempBuf, pbt[wBlockNum], 0, - DeviceInfo.wPagesPerBlock)) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in " - "%s, Line %d, Function: %s, " - "new Bad Block %d " - "generated!\n", - __FILE__, __LINE__, __func__, - (int)pbt[wBlockNum]); - wResult = FAIL; - MARK_BLOCK_AS_BAD(pbt[wBlockNum]); - } - ftl_cmd_cnt++; - } -#else - wResult = GLOB_LLD_Read_Page_Main(g_pTempBuf, - dwOldBlockAddr, 0, DeviceInfo.wPagesPerBlock); - if (wResult == FAIL) - return wResult; - - if (wResult != FAIL) { - /* This is a bug. At this time, pbt[wBlockNum] - is still the physical address of - discard block, and should not be write. - Have fixed it as below. - -- Yunpeng 2008.12.19 - */ - wResult = GLOB_LLD_Write_Page_Main(g_pTempBuf, - wReplacedNode, 0, - DeviceInfo.wPagesPerBlock); - if (wResult == FAIL) { - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in " - "%s, Line %d, Function: %s, " - "new Bad Block %d " - "generated!\n", - __FILE__, __LINE__, __func__, - (int)wReplacedNode); - MARK_BLOCK_AS_BAD(wReplacedNode); - } else { - pbt[wBlockNum] = wReplacedNode; - pbt[wLeastReadIndex] = wTempNode; - } - } - - if ((wResult == PASS) && (g_cBlockTableStatus != - IN_PROGRESS_BLOCK_TABLE)) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } -#endif - } - } while (wResult != PASS) - ; - -#if CMD_DMA - /* ... */ -#endif - - return wResult; -} - diff --git a/drivers/staging/spectra/flash.h b/drivers/staging/spectra/flash.h deleted file mode 100644 index e59cf4ede55..00000000000 --- a/drivers/staging/spectra/flash.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#ifndef _FLASH_INTERFACE_ -#define _FLASH_INTERFACE_ - -#include "ffsport.h" -#include "spectraswconfig.h" - -#define MAX_BYTE_VALUE 0xFF -#define MAX_WORD_VALUE 0xFFFF -#define MAX_U32_VALUE 0xFFFFFFFF - -#define MAX_BLOCKNODE_VALUE 0xFFFFFF -#define DISCARD_BLOCK 0x800000 -#define SPARE_BLOCK 0x400000 -#define BAD_BLOCK 0xC00000 - -#define UNHIT_CACHE_ITEM 0xFFFF - -#define NAND_CACHE_INIT_ADDR 0xffffffffffffffffULL - -#define IN_PROGRESS_BLOCK_TABLE 0x00 -#define CURRENT_BLOCK_TABLE 0x01 - -#define BTSIG_OFFSET (0) -#define BTSIG_BYTES (5) -#define BTSIG_DELTA (3) - -#define MAX_READ_COUNTER 0x2710 - -#define FIRST_BT_ID (1) -#define LAST_BT_ID (254) -#define BTBLOCK_INVAL (u32)(0xFFFFFFFF) - -struct device_info_tag { - u16 wDeviceMaker; - u16 wDeviceID; - u32 wDeviceType; - u32 wSpectraStartBlock; - u32 wSpectraEndBlock; - u32 wTotalBlocks; - u16 wPagesPerBlock; - u16 wPageSize; - u16 wPageDataSize; - u16 wPageSpareSize; - u16 wNumPageSpareFlag; - u16 wECCBytesPerSector; - u32 wBlockSize; - u32 wBlockDataSize; - u32 wDataBlockNum; - u8 bPlaneNum; - u16 wDeviceMainAreaSize; - u16 wDeviceSpareAreaSize; - u16 wDevicesConnected; - u16 wDeviceWidth; - u16 wHWRevision; - u16 wHWFeatures; - - u16 wONFIDevFeatures; - u16 wONFIOptCommands; - u16 wONFITimingMode; - u16 wONFIPgmCacheTimingMode; - - u16 MLCDevice; - u16 wSpareSkipBytes; - - u8 nBitsInPageNumber; - u8 nBitsInPageDataSize; - u8 nBitsInBlockDataSize; -}; - -extern struct device_info_tag DeviceInfo; - -/* Cache item format */ -struct flash_cache_item_tag { - u64 address; - u16 use_cnt; - u16 changed; - u8 *buf; -}; - -struct flash_cache_tag { - u32 cache_item_size; /* Size in bytes of each cache item */ - u16 pages_per_item; /* How many NAND pages in each cache item */ - u16 LRU; /* No. of the least recently used cache item */ - struct flash_cache_item_tag array[CACHE_ITEM_NUM]; -}; - -/* - *Data structure for each list node of the management table - * used for the Level 2 Cache. Each node maps one logical NAND block. - */ -struct spectra_l2_cache_list { - struct list_head list; - u32 logical_blk_num; /* Logical block number */ - u32 pages_array[]; /* Page map array of this logical block. - * Array index is the logical block number, - * and for every item of this arry: - * high 16 bit is index of the L2 cache block num, - * low 16 bit is the phy page num - * of the above L2 cache block. - * This array will be kmalloc during run time. - */ -}; - -struct spectra_l2_cache_info { - u32 blk_array[BLK_NUM_FOR_L2_CACHE]; - u16 cur_blk_idx; /* idx to the phy block number of current using */ - u16 cur_page_num; /* pages number of current using */ - struct spectra_l2_cache_list table; /* First node of the table */ -}; - -#define RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE 1 - -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE -struct flash_cache_mod_item_tag { - u64 address; - u8 changed; -}; - -struct flash_cache_delta_list_tag { - u8 item; /* used cache item */ - struct flash_cache_mod_item_tag cache; -}; -#endif - -extern struct flash_cache_tag Cache; - -extern u8 *buf_read_page_main_spare; -extern u8 *buf_write_page_main_spare; -extern u8 *buf_read_page_spare; -extern u8 *buf_get_bad_block; -extern u8 *cdma_desc_buf; -extern u8 *memcp_desc_buf; - -/* struture used for IndentfyDevice function */ -struct spectra_indentfy_dev_tag { - u32 NumBlocks; - u16 PagesPerBlock; - u16 PageDataSize; - u16 wECCBytesPerSector; - u32 wDataBlockNum; -}; - -int GLOB_FTL_Flash_Init(void); -int GLOB_FTL_Flash_Release(void); -/*void GLOB_FTL_Erase_Flash(void);*/ -int GLOB_FTL_Block_Erase(u64 block_addr); -int GLOB_FTL_Is_BadBlock(u32 block_num); -int GLOB_FTL_IdentifyDevice(struct spectra_indentfy_dev_tag *dev_data); -int GLOB_FTL_Event_Status(int *); -u16 glob_ftl_execute_cmds(void); - -/*int FTL_Read_Disturbance(ADDRESSTYPE dwBlockAddr);*/ -int FTL_Read_Disturbance(u32 dwBlockAddr); - -/*Flash r/w based on cache*/ -int GLOB_FTL_Page_Read(u8 *read_data, u64 page_addr); -int GLOB_FTL_Page_Write(u8 *write_data, u64 page_addr); -int GLOB_FTL_Wear_Leveling(void); -int GLOB_FTL_Flash_Format(void); -int GLOB_FTL_Init(void); -int GLOB_FTL_Flush_Cache(void); -int GLOB_FTL_Garbage_Collection(void); -int GLOB_FTL_BT_Garbage_Collection(void); -void GLOB_FTL_Cache_Release(void); -u8 *get_blk_table_start_addr(void); -u8 *get_wear_leveling_table_start_addr(void); -unsigned long get_blk_table_len(void); -unsigned long get_wear_leveling_table_len(void); - -#if DEBUG_BNDRY -void debug_boundary_lineno_error(int chnl, int limit, int no, int lineno, - char *filename); -#define debug_boundary_error(chnl, limit, no) debug_boundary_lineno_error(chnl,\ - limit, no, __LINE__, __FILE__) -#else -#define debug_boundary_error(chnl, limit, no) ; -#endif - -#endif /*_FLASH_INTERFACE_*/ diff --git a/drivers/staging/spectra/lld.c b/drivers/staging/spectra/lld.c deleted file mode 100644 index 5c3b9762dc3..00000000000 --- a/drivers/staging/spectra/lld.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#include "spectraswconfig.h" -#include "ffsport.h" -#include "ffsdefs.h" -#include "lld.h" -#include "lld_nand.h" - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -#if FLASH_EMU /* vector all the LLD calls to the LLD_EMU code */ -#include "lld_emu.h" -#include "lld_cdma.h" - -/* common functions: */ -u16 GLOB_LLD_Flash_Reset(void) -{ - return emu_Flash_Reset(); -} - -u16 GLOB_LLD_Read_Device_ID(void) -{ - return emu_Read_Device_ID(); -} - -int GLOB_LLD_Flash_Release(void) -{ - return emu_Flash_Release(); -} - -u16 GLOB_LLD_Flash_Init(void) -{ - return emu_Flash_Init(); -} - -u16 GLOB_LLD_Erase_Block(u32 block_add) -{ - return emu_Erase_Block(block_add); -} - -u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page, - u16 PageCount) -{ - return emu_Write_Page_Main(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 Page, - u16 PageCount) -{ - return emu_Read_Page_Main(read_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count) -{ - return emu_Read_Page_Main(read_data, block, page, page_count); -} - -u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block, - u16 Page, u16 PageCount) -{ - return emu_Write_Page_Main_Spare(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block, - u16 Page, u16 PageCount) -{ - return emu_Read_Page_Main_Spare(read_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page, - u16 PageCount) -{ - return emu_Write_Page_Spare(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page, - u16 PageCount) -{ - return emu_Read_Page_Spare(read_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Get_Bad_Block(u32 block) -{ - return emu_Get_Bad_Block(block); -} - -#endif /* FLASH_EMU */ - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -#if FLASH_MTD /* vector all the LLD calls to the LLD_MTD code */ -#include "lld_mtd.h" -#include "lld_cdma.h" - -/* common functions: */ -u16 GLOB_LLD_Flash_Reset(void) -{ - return mtd_Flash_Reset(); -} - -u16 GLOB_LLD_Read_Device_ID(void) -{ - return mtd_Read_Device_ID(); -} - -int GLOB_LLD_Flash_Release(void) -{ - return mtd_Flash_Release(); -} - -u16 GLOB_LLD_Flash_Init(void) -{ - return mtd_Flash_Init(); -} - -u16 GLOB_LLD_Erase_Block(u32 block_add) -{ - return mtd_Erase_Block(block_add); -} - -u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page, - u16 PageCount) -{ - return mtd_Write_Page_Main(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 Page, - u16 PageCount) -{ - return mtd_Read_Page_Main(read_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count) -{ - return mtd_Read_Page_Main(read_data, block, page, page_count); -} - -u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block, - u16 Page, u16 PageCount) -{ - return mtd_Write_Page_Main_Spare(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block, - u16 Page, u16 PageCount) -{ - return mtd_Read_Page_Main_Spare(read_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page, - u16 PageCount) -{ - return mtd_Write_Page_Spare(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page, - u16 PageCount) -{ - return mtd_Read_Page_Spare(read_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Get_Bad_Block(u32 block) -{ - return mtd_Get_Bad_Block(block); -} - -#endif /* FLASH_MTD */ - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -#if FLASH_NAND /* vector all the LLD calls to the NAND controller code */ -#include "lld_nand.h" -#include "lld_cdma.h" -#include "flash.h" - -/* common functions for LLD_NAND */ -void GLOB_LLD_ECC_Control(int enable) -{ - NAND_ECC_Ctrl(enable); -} - -/* common functions for LLD_NAND */ -u16 GLOB_LLD_Flash_Reset(void) -{ - return NAND_Flash_Reset(); -} - -u16 GLOB_LLD_Read_Device_ID(void) -{ - return NAND_Read_Device_ID(); -} - -u16 GLOB_LLD_UnlockArrayAll(void) -{ - return NAND_UnlockArrayAll(); -} - -u16 GLOB_LLD_Flash_Init(void) -{ - return NAND_Flash_Init(); -} - -int GLOB_LLD_Flash_Release(void) -{ - return nand_release_spectra(); -} - -u16 GLOB_LLD_Erase_Block(u32 block_add) -{ - return NAND_Erase_Block(block_add); -} - - -u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page, - u16 PageCount) -{ - return NAND_Write_Page_Main(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 page, - u16 page_count) -{ - if (page_count == 1) /* Using polling to improve read speed */ - return NAND_Read_Page_Main_Polling(read_data, block, page, 1); - else - return NAND_Read_Page_Main(read_data, block, page, page_count); -} - -u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count) -{ - return NAND_Read_Page_Main_Polling(read_data, - block, page, page_count); -} - -u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block, - u16 Page, u16 PageCount) -{ - return NAND_Write_Page_Main_Spare(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page, - u16 PageCount) -{ - return NAND_Write_Page_Spare(write_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block, - u16 page, u16 page_count) -{ - return NAND_Read_Page_Main_Spare(read_data, block, page, page_count); -} - -u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page, - u16 PageCount) -{ - return NAND_Read_Page_Spare(read_data, block, Page, PageCount); -} - -u16 GLOB_LLD_Get_Bad_Block(u32 block) -{ - return NAND_Get_Bad_Block(block); -} - -#if CMD_DMA -u16 GLOB_LLD_Event_Status(void) -{ - return CDMA_Event_Status(); -} - -u16 glob_lld_execute_cmds(void) -{ - return CDMA_Execute_CMDs(); -} - -u16 GLOB_LLD_MemCopy_CMD(u8 *dest, u8 *src, - u32 ByteCount, u16 flag) -{ - /* Replace the hardware memcopy with software memcpy function */ - if (CDMA_Execute_CMDs()) - return FAIL; - memcpy(dest, src, ByteCount); - return PASS; - - /* return CDMA_MemCopy_CMD(dest, src, ByteCount, flag); */ -} - -u16 GLOB_LLD_Erase_Block_cdma(u32 block, u16 flags) -{ - return CDMA_Data_CMD(ERASE_CMD, 0, block, 0, 0, flags); -} - -u16 GLOB_LLD_Write_Page_Main_cdma(u8 *data, u32 block, u16 page, u16 count) -{ - return CDMA_Data_CMD(WRITE_MAIN_CMD, data, block, page, count, 0); -} - -u16 GLOB_LLD_Read_Page_Main_cdma(u8 *data, u32 block, u16 page, - u16 count, u16 flags) -{ - return CDMA_Data_CMD(READ_MAIN_CMD, data, block, page, count, flags); -} - -u16 GLOB_LLD_Write_Page_Main_Spare_cdma(u8 *data, u32 block, u16 page, - u16 count, u16 flags) -{ - return CDMA_Data_CMD(WRITE_MAIN_SPARE_CMD, - data, block, page, count, flags); -} - -u16 GLOB_LLD_Read_Page_Main_Spare_cdma(u8 *data, - u32 block, u16 page, u16 count) -{ - return CDMA_Data_CMD(READ_MAIN_SPARE_CMD, data, block, page, count, - LLD_CMD_FLAG_MODE_CDMA); -} - -#endif /* CMD_DMA */ -#endif /* FLASH_NAND */ - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ - -/* end of LLD.c */ diff --git a/drivers/staging/spectra/lld.h b/drivers/staging/spectra/lld.h deleted file mode 100644 index d3738e0e1fe..00000000000 --- a/drivers/staging/spectra/lld.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - - - -#ifndef _LLD_ -#define _LLD_ - -#include "ffsport.h" -#include "spectraswconfig.h" -#include "flash.h" - -#define GOOD_BLOCK 0 -#define DEFECTIVE_BLOCK 1 -#define READ_ERROR 2 - -#define CLK_X 5 -#define CLK_MULTI 4 - -/* Typedefs */ - -/* prototypes: API for LLD */ -/* Currently, Write_Page_Main - * MemCopy - * Read_Page_Main_Spare - * do not have flag because they were not implemented prior to this - * They are not being added to keep changes to a minimum for now. - * Currently, they are not required (only reqd for Wr_P_M_S.) - * Later on, these NEED to be changed. - */ - -extern void GLOB_LLD_ECC_Control(int enable); - -extern u16 GLOB_LLD_Flash_Reset(void); - -extern u16 GLOB_LLD_Read_Device_ID(void); - -extern u16 GLOB_LLD_UnlockArrayAll(void); - -extern u16 GLOB_LLD_Flash_Init(void); - -extern int GLOB_LLD_Flash_Release(void); - -extern u16 GLOB_LLD_Erase_Block(u32 block_add); - -extern u16 GLOB_LLD_Write_Page_Main(u8 *write_data, - u32 block, u16 Page, u16 PageCount); - -extern u16 GLOB_LLD_Read_Page_Main(u8 *read_data, - u32 block, u16 page, u16 page_count); - -extern u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count); - -extern u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, - u32 block, u16 Page, u16 PageCount); - -extern u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, - u32 block, u16 Page, u16 PageCount); - -extern u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, - u32 block, u16 page, u16 page_count); - -extern u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, - u32 block, u16 Page, u16 PageCount); - -extern u16 GLOB_LLD_Get_Bad_Block(u32 block); - -extern u16 GLOB_LLD_Event_Status(void); - -extern u16 GLOB_LLD_MemCopy_CMD(u8 *dest, u8 *src, u32 ByteCount, u16 flag); - -extern u16 glob_lld_execute_cmds(void); - -extern u16 GLOB_LLD_Erase_Block_cdma(u32 block, u16 flags); - -extern u16 GLOB_LLD_Write_Page_Main_cdma(u8 *data, - u32 block, u16 page, u16 count); - -extern u16 GLOB_LLD_Read_Page_Main_cdma(u8 *data, - u32 block, u16 page, u16 count, u16 flags); - -extern u16 GLOB_LLD_Write_Page_Main_Spare_cdma(u8 *data, - u32 block, u16 page, u16 count, u16 flags); - -extern u16 GLOB_LLD_Read_Page_Main_Spare_cdma(u8 *data, - u32 block, u16 page, u16 count); - -#define LLD_CMD_FLAG_ORDER_BEFORE_REST (0x1) -#define LLD_CMD_FLAG_MODE_CDMA (0x8) - - -#endif /*_LLD_ */ - - diff --git a/drivers/staging/spectra/lld_cdma.c b/drivers/staging/spectra/lld_cdma.c deleted file mode 100644 index c6e76103d43..00000000000 --- a/drivers/staging/spectra/lld_cdma.c +++ /dev/null @@ -1,910 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#include <linux/fs.h> -#include <linux/slab.h> - -#include "spectraswconfig.h" -#include "lld.h" -#include "lld_nand.h" -#include "lld_cdma.h" -#include "lld_emu.h" -#include "flash.h" -#include "nand_regs.h" - -#define MAX_PENDING_CMDS 4 -#define MODE_02 (0x2 << 26) - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: CDMA_Data_Cmd -* Inputs: cmd code (aligned for hw) -* data: pointer to source or destination -* block: block address -* page: page address -* num: num pages to transfer -* Outputs: PASS -* Description: This function takes the parameters and puts them -* into the "pending commands" array. -* It does not parse or validate the parameters. -* The array index is same as the tag. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 CDMA_Data_CMD(u8 cmd, u8 *data, u32 block, u16 page, u16 num, u16 flags) -{ - u8 bank; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (0 == cmd) - nand_dbg_print(NAND_DBG_DEBUG, - "%s, Line %d, Illegal cmd (0)\n", __FILE__, __LINE__); - - /* If a command of another bank comes, then first execute */ - /* pending commands of the current bank, then set the new */ - /* bank as current bank */ - bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - if (bank != info.flash_bank) { - nand_dbg_print(NAND_DBG_WARN, - "Will access new bank. old bank: %d, new bank: %d\n", - info.flash_bank, bank); - if (CDMA_Execute_CMDs()) { - printk(KERN_ERR "CDMA_Execute_CMDs fail!\n"); - return FAIL; - } - info.flash_bank = bank; - } - - info.pcmds[info.pcmds_num].CMD = cmd; - info.pcmds[info.pcmds_num].DataAddr = data; - info.pcmds[info.pcmds_num].Block = block; - info.pcmds[info.pcmds_num].Page = page; - info.pcmds[info.pcmds_num].PageCount = num; - info.pcmds[info.pcmds_num].DataDestAddr = 0; - info.pcmds[info.pcmds_num].DataSrcAddr = 0; - info.pcmds[info.pcmds_num].MemCopyByteCnt = 0; - info.pcmds[info.pcmds_num].Flags = flags; - info.pcmds[info.pcmds_num].Status = 0xB0B; - - switch (cmd) { - case WRITE_MAIN_SPARE_CMD: - Conv_Main_Spare_Data_Log2Phy_Format(data, num); - break; - case WRITE_SPARE_CMD: - Conv_Spare_Data_Log2Phy_Format(data); - break; - default: - break; - } - - info.pcmds_num++; - - if (info.pcmds_num >= MAX_PENDING_CMDS) { - if (CDMA_Execute_CMDs()) { - printk(KERN_ERR "CDMA_Execute_CMDs fail!\n"); - return FAIL; - } - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: CDMA_MemCopy_CMD -* Inputs: dest: pointer to destination -* src: pointer to source -* count: num bytes to transfer -* Outputs: PASS -* Description: This function takes the parameters and puts them -* into the "pending commands" array. -* It does not parse or validate the parameters. -* The array index is same as the tag. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 CDMA_MemCopy_CMD(u8 *dest, u8 *src, u32 byte_cnt, u16 flags) -{ - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - info.pcmds[info.pcmds_num].CMD = MEMCOPY_CMD; - info.pcmds[info.pcmds_num].DataAddr = 0; - info.pcmds[info.pcmds_num].Block = 0; - info.pcmds[info.pcmds_num].Page = 0; - info.pcmds[info.pcmds_num].PageCount = 0; - info.pcmds[info.pcmds_num].DataDestAddr = dest; - info.pcmds[info.pcmds_num].DataSrcAddr = src; - info.pcmds[info.pcmds_num].MemCopyByteCnt = byte_cnt; - info.pcmds[info.pcmds_num].Flags = flags; - info.pcmds[info.pcmds_num].Status = 0xB0B; - - info.pcmds_num++; - - if (info.pcmds_num >= MAX_PENDING_CMDS) { - if (CDMA_Execute_CMDs()) { - printk(KERN_ERR "CDMA_Execute_CMDs fail!\n"); - return FAIL; - } - } - - return PASS; -} - -#if 0 -/* Prints the PendingCMDs array */ -void print_pending_cmds(void) -{ - u16 i; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < info.pcmds_num; i++) { - nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i); - switch (info.pcmds[i].CMD) { - case ERASE_CMD: - nand_dbg_print(NAND_DBG_DEBUG, - "Erase Command (0x%x)\n", - info.pcmds[i].CMD); - break; - case WRITE_MAIN_CMD: - nand_dbg_print(NAND_DBG_DEBUG, - "Write Main Command (0x%x)\n", - info.pcmds[i].CMD); - break; - case WRITE_MAIN_SPARE_CMD: - nand_dbg_print(NAND_DBG_DEBUG, - "Write Main Spare Command (0x%x)\n", - info.pcmds[i].CMD); - break; - case READ_MAIN_SPARE_CMD: - nand_dbg_print(NAND_DBG_DEBUG, - "Read Main Spare Command (0x%x)\n", - info.pcmds[i].CMD); - break; - case READ_MAIN_CMD: - nand_dbg_print(NAND_DBG_DEBUG, - "Read Main Command (0x%x)\n", - info.pcmds[i].CMD); - break; - case MEMCOPY_CMD: - nand_dbg_print(NAND_DBG_DEBUG, - "Memcopy Command (0x%x)\n", - info.pcmds[i].CMD); - break; - case DUMMY_CMD: - nand_dbg_print(NAND_DBG_DEBUG, - "Dummy Command (0x%x)\n", - info.pcmds[i].CMD); - break; - default: - nand_dbg_print(NAND_DBG_DEBUG, - "Illegal Command (0x%x)\n", - info.pcmds[i].CMD); - break; - } - - nand_dbg_print(NAND_DBG_DEBUG, "DataAddr: 0x%x\n", - (u32)info.pcmds[i].DataAddr); - nand_dbg_print(NAND_DBG_DEBUG, "Block: %d\n", - info.pcmds[i].Block); - nand_dbg_print(NAND_DBG_DEBUG, "Page: %d\n", - info.pcmds[i].Page); - nand_dbg_print(NAND_DBG_DEBUG, "PageCount: %d\n", - info.pcmds[i].PageCount); - nand_dbg_print(NAND_DBG_DEBUG, "DataDestAddr: 0x%x\n", - (u32)info.pcmds[i].DataDestAddr); - nand_dbg_print(NAND_DBG_DEBUG, "DataSrcAddr: 0x%x\n", - (u32)info.pcmds[i].DataSrcAddr); - nand_dbg_print(NAND_DBG_DEBUG, "MemCopyByteCnt: %d\n", - info.pcmds[i].MemCopyByteCnt); - nand_dbg_print(NAND_DBG_DEBUG, "Flags: 0x%x\n", - info.pcmds[i].Flags); - nand_dbg_print(NAND_DBG_DEBUG, "Status: 0x%x\n", - info.pcmds[i].Status); - } -} - -/* Print the CDMA descriptors */ -void print_cdma_descriptors(void) -{ - struct cdma_descriptor *pc; - int i; - - pc = (struct cdma_descriptor *)info.cdma_desc_buf; - - nand_dbg_print(NAND_DBG_DEBUG, "\nWill dump cdma descriptors:\n"); - - for (i = 0; i < info.cdma_num; i++) { - nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i); - nand_dbg_print(NAND_DBG_DEBUG, - "NxtPointerHi: 0x%x, NxtPointerLo: 0x%x\n", - pc[i].NxtPointerHi, pc[i].NxtPointerLo); - nand_dbg_print(NAND_DBG_DEBUG, - "FlashPointerHi: 0x%x, FlashPointerLo: 0x%x\n", - pc[i].FlashPointerHi, pc[i].FlashPointerLo); - nand_dbg_print(NAND_DBG_DEBUG, "CommandType: 0x%x\n", - pc[i].CommandType); - nand_dbg_print(NAND_DBG_DEBUG, - "MemAddrHi: 0x%x, MemAddrLo: 0x%x\n", - pc[i].MemAddrHi, pc[i].MemAddrLo); - nand_dbg_print(NAND_DBG_DEBUG, "CommandFlags: 0x%x\n", - pc[i].CommandFlags); - nand_dbg_print(NAND_DBG_DEBUG, "Channel: %d, Status: 0x%x\n", - pc[i].Channel, pc[i].Status); - nand_dbg_print(NAND_DBG_DEBUG, - "MemCopyPointerHi: 0x%x, MemCopyPointerLo: 0x%x\n", - pc[i].MemCopyPointerHi, pc[i].MemCopyPointerLo); - nand_dbg_print(NAND_DBG_DEBUG, - "Reserved12: 0x%x, Reserved13: 0x%x, " - "Reserved14: 0x%x, pcmd: %d\n", - pc[i].Reserved12, pc[i].Reserved13, - pc[i].Reserved14, pc[i].pcmd); - } -} - -/* Print the Memory copy descriptors */ -static void print_memcp_descriptors(void) -{ - struct memcpy_descriptor *pm; - int i; - - pm = (struct memcpy_descriptor *)info.memcp_desc_buf; - - nand_dbg_print(NAND_DBG_DEBUG, "\nWill dump mem_cpy descriptors:\n"); - - for (i = 0; i < info.cdma_num; i++) { - nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i); - nand_dbg_print(NAND_DBG_DEBUG, - "NxtPointerHi: 0x%x, NxtPointerLo: 0x%x\n", - pm[i].NxtPointerHi, pm[i].NxtPointerLo); - nand_dbg_print(NAND_DBG_DEBUG, - "SrcAddrHi: 0x%x, SrcAddrLo: 0x%x\n", - pm[i].SrcAddrHi, pm[i].SrcAddrLo); - nand_dbg_print(NAND_DBG_DEBUG, - "DestAddrHi: 0x%x, DestAddrLo: 0x%x\n", - pm[i].DestAddrHi, pm[i].DestAddrLo); - nand_dbg_print(NAND_DBG_DEBUG, "XferSize: %d\n", - pm[i].XferSize); - nand_dbg_print(NAND_DBG_DEBUG, "MemCopyFlags: 0x%x\n", - pm[i].MemCopyFlags); - nand_dbg_print(NAND_DBG_DEBUG, "MemCopyStatus: %d\n", - pm[i].MemCopyStatus); - nand_dbg_print(NAND_DBG_DEBUG, "reserved9: 0x%x\n", - pm[i].reserved9); - nand_dbg_print(NAND_DBG_DEBUG, "reserved10: 0x%x\n", - pm[i].reserved10); - nand_dbg_print(NAND_DBG_DEBUG, "reserved11: 0x%x\n", - pm[i].reserved11); - nand_dbg_print(NAND_DBG_DEBUG, "reserved12: 0x%x\n", - pm[i].reserved12); - nand_dbg_print(NAND_DBG_DEBUG, "reserved13: 0x%x\n", - pm[i].reserved13); - nand_dbg_print(NAND_DBG_DEBUG, "reserved14: 0x%x\n", - pm[i].reserved14); - nand_dbg_print(NAND_DBG_DEBUG, "reserved15: 0x%x\n", - pm[i].reserved15); - } -} -#endif - -/* Reset cdma_descriptor chain to 0 */ -static void reset_cdma_desc(int i) -{ - struct cdma_descriptor *ptr; - - BUG_ON(i >= MAX_DESCS); - - ptr = (struct cdma_descriptor *)info.cdma_desc_buf; - - ptr[i].NxtPointerHi = 0; - ptr[i].NxtPointerLo = 0; - ptr[i].FlashPointerHi = 0; - ptr[i].FlashPointerLo = 0; - ptr[i].CommandType = 0; - ptr[i].MemAddrHi = 0; - ptr[i].MemAddrLo = 0; - ptr[i].CommandFlags = 0; - ptr[i].Channel = 0; - ptr[i].Status = 0; - ptr[i].MemCopyPointerHi = 0; - ptr[i].MemCopyPointerLo = 0; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: CDMA_UpdateEventStatus -* Inputs: none -* Outputs: none -* Description: This function update the event status of all the channels -* when an error condition is reported. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -void CDMA_UpdateEventStatus(void) -{ - int i, j, active_chan; - struct cdma_descriptor *ptr; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - ptr = (struct cdma_descriptor *)info.cdma_desc_buf; - - for (j = 0; j < info.cdma_num; j++) { - /* Check for the descriptor with failure */ - if ((ptr[j].Status & CMD_DMA_DESC_FAIL)) - break; - - } - - /* All the previous cmd's status for this channel must be good */ - for (i = 0; i < j; i++) { - if (ptr[i].pcmd != 0xff) - info.pcmds[ptr[i].pcmd].Status = CMD_PASS; - } - - /* Abort the channel with type 0 reset command. It resets the */ - /* selected channel after the descriptor completes the flash */ - /* operation and status has been updated for the descriptor. */ - /* Memory Copy and Sync associated with this descriptor will */ - /* not be executed */ - active_chan = ioread32(FlashReg + CHNL_ACTIVE); - if ((active_chan & (1 << info.flash_bank)) == (1 << info.flash_bank)) { - iowrite32(MODE_02 | (0 << 4), FlashMem); /* Type 0 reset */ - iowrite32((0xF << 4) | info.flash_bank, FlashMem + 0x10); - } else { /* Should not reached here */ - printk(KERN_ERR "Error! Used bank is not set in" - " reg CHNL_ACTIVE\n"); - } -} - -static void cdma_trans(u16 chan) -{ - u32 addr; - - addr = info.cdma_desc; - - iowrite32(MODE_10 | (chan << 24), FlashMem); - iowrite32((1 << 7) | chan, FlashMem + 0x10); - - iowrite32(MODE_10 | (chan << 24) | ((0x0FFFF & (addr >> 16)) << 8), - FlashMem); - iowrite32((1 << 7) | (1 << 4) | 0, FlashMem + 0x10); - - iowrite32(MODE_10 | (chan << 24) | ((0x0FFFF & addr) << 8), FlashMem); - iowrite32((1 << 7) | (1 << 5) | 0, FlashMem + 0x10); - - iowrite32(MODE_10 | (chan << 24), FlashMem); - iowrite32((1 << 7) | (1 << 5) | (1 << 4) | 0, FlashMem + 0x10); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: CDMA_Execute_CMDs (for use with CMD_DMA) -* Inputs: tag_count: the number of pending cmds to do -* Outputs: PASS/FAIL -* Description: Build the SDMA chain(s) by making one CMD-DMA descriptor -* for each pending command, start the CDMA engine, and return. -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 CDMA_Execute_CMDs(void) -{ - int i, ret; - u64 flash_add; - u32 ptr; - dma_addr_t map_addr, next_ptr; - u16 status = PASS; - u16 tmp_c; - struct cdma_descriptor *pc; - struct memcpy_descriptor *pm; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - /* No pending cmds to execute, just exit */ - if (0 == info.pcmds_num) { - nand_dbg_print(NAND_DBG_TRACE, - "No pending cmds to execute. Just exit.\n"); - return PASS; - } - - for (i = 0; i < MAX_DESCS; i++) - reset_cdma_desc(i); - - pc = (struct cdma_descriptor *)info.cdma_desc_buf; - pm = (struct memcpy_descriptor *)info.memcp_desc_buf; - - info.cdma_desc = virt_to_bus(info.cdma_desc_buf); - info.memcp_desc = virt_to_bus(info.memcp_desc_buf); - next_ptr = info.cdma_desc; - info.cdma_num = 0; - - for (i = 0; i < info.pcmds_num; i++) { - if (info.pcmds[i].Block >= DeviceInfo.wTotalBlocks) { - info.pcmds[i].Status = CMD_NOT_DONE; - continue; - } - - next_ptr += sizeof(struct cdma_descriptor); - pc[info.cdma_num].NxtPointerHi = next_ptr >> 16; - pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff; - - /* Use the Block offset within a bank */ - tmp_c = info.pcmds[i].Block / - (DeviceInfo.wTotalBlocks / totalUsedBanks); - flash_add = (u64)(info.pcmds[i].Block - tmp_c * - (DeviceInfo.wTotalBlocks / totalUsedBanks)) * - DeviceInfo.wBlockDataSize + - (u64)(info.pcmds[i].Page) * - DeviceInfo.wPageDataSize; - - ptr = MODE_10 | (info.flash_bank << 24) | - (u32)GLOB_u64_Div(flash_add, - DeviceInfo.wPageDataSize); - pc[info.cdma_num].FlashPointerHi = ptr >> 16; - pc[info.cdma_num].FlashPointerLo = ptr & 0xffff; - - if ((info.pcmds[i].CMD == WRITE_MAIN_SPARE_CMD) || - (info.pcmds[i].CMD == READ_MAIN_SPARE_CMD)) { - /* Descriptor to set Main+Spare Access Mode */ - pc[info.cdma_num].CommandType = 0x43; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - pc[info.cdma_num].MemAddrHi = 0; - pc[info.cdma_num].MemAddrLo = 0; - pc[info.cdma_num].Channel = 0; - pc[info.cdma_num].Status = 0; - pc[info.cdma_num].pcmd = i; - - info.cdma_num++; - BUG_ON(info.cdma_num >= MAX_DESCS); - - reset_cdma_desc(info.cdma_num); - next_ptr += sizeof(struct cdma_descriptor); - pc[info.cdma_num].NxtPointerHi = next_ptr >> 16; - pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff; - pc[info.cdma_num].FlashPointerHi = ptr >> 16; - pc[info.cdma_num].FlashPointerLo = ptr & 0xffff; - } - - switch (info.pcmds[i].CMD) { - case ERASE_CMD: - pc[info.cdma_num].CommandType = 1; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - pc[info.cdma_num].MemAddrHi = 0; - pc[info.cdma_num].MemAddrLo = 0; - break; - - case WRITE_MAIN_CMD: - pc[info.cdma_num].CommandType = - 0x2100 | info.pcmds[i].PageCount; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - map_addr = virt_to_bus(info.pcmds[i].DataAddr); - pc[info.cdma_num].MemAddrHi = map_addr >> 16; - pc[info.cdma_num].MemAddrLo = map_addr & 0xffff; - break; - - case READ_MAIN_CMD: - pc[info.cdma_num].CommandType = - 0x2000 | info.pcmds[i].PageCount; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - map_addr = virt_to_bus(info.pcmds[i].DataAddr); - pc[info.cdma_num].MemAddrHi = map_addr >> 16; - pc[info.cdma_num].MemAddrLo = map_addr & 0xffff; - break; - - case WRITE_MAIN_SPARE_CMD: - pc[info.cdma_num].CommandType = - 0x2100 | info.pcmds[i].PageCount; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - map_addr = virt_to_bus(info.pcmds[i].DataAddr); - pc[info.cdma_num].MemAddrHi = map_addr >> 16; - pc[info.cdma_num].MemAddrLo = map_addr & 0xffff; - break; - - case READ_MAIN_SPARE_CMD: - pc[info.cdma_num].CommandType = - 0x2000 | info.pcmds[i].PageCount; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - map_addr = virt_to_bus(info.pcmds[i].DataAddr); - pc[info.cdma_num].MemAddrHi = map_addr >> 16; - pc[info.cdma_num].MemAddrLo = map_addr & 0xffff; - break; - - case MEMCOPY_CMD: - pc[info.cdma_num].CommandType = 0xFFFF; /* NOP cmd */ - /* Set bit 11 to let the CDMA engine continue to */ - /* execute only after it has finished processing */ - /* the memcopy descriptor. */ - /* Also set bit 10 and bit 9 to 1 */ - pc[info.cdma_num].CommandFlags = 0x0E40; - map_addr = info.memcp_desc + info.cdma_num * - sizeof(struct memcpy_descriptor); - pc[info.cdma_num].MemCopyPointerHi = map_addr >> 16; - pc[info.cdma_num].MemCopyPointerLo = map_addr & 0xffff; - - pm[info.cdma_num].NxtPointerHi = 0; - pm[info.cdma_num].NxtPointerLo = 0; - - map_addr = virt_to_bus(info.pcmds[i].DataSrcAddr); - pm[info.cdma_num].SrcAddrHi = map_addr >> 16; - pm[info.cdma_num].SrcAddrLo = map_addr & 0xffff; - map_addr = virt_to_bus(info.pcmds[i].DataDestAddr); - pm[info.cdma_num].DestAddrHi = map_addr >> 16; - pm[info.cdma_num].DestAddrLo = map_addr & 0xffff; - - pm[info.cdma_num].XferSize = - info.pcmds[i].MemCopyByteCnt; - pm[info.cdma_num].MemCopyFlags = - (0 << 15 | 0 << 14 | 27 << 8 | 0x40); - pm[info.cdma_num].MemCopyStatus = 0; - break; - - case DUMMY_CMD: - default: - pc[info.cdma_num].CommandType = 0XFFFF; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - pc[info.cdma_num].MemAddrHi = 0; - pc[info.cdma_num].MemAddrLo = 0; - break; - } - - pc[info.cdma_num].Channel = 0; - pc[info.cdma_num].Status = 0; - pc[info.cdma_num].pcmd = i; - - info.cdma_num++; - BUG_ON(info.cdma_num >= MAX_DESCS); - - if ((info.pcmds[i].CMD == WRITE_MAIN_SPARE_CMD) || - (info.pcmds[i].CMD == READ_MAIN_SPARE_CMD)) { - /* Descriptor to set back Main Area Access Mode */ - reset_cdma_desc(info.cdma_num); - next_ptr += sizeof(struct cdma_descriptor); - pc[info.cdma_num].NxtPointerHi = next_ptr >> 16; - pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff; - - pc[info.cdma_num].FlashPointerHi = ptr >> 16; - pc[info.cdma_num].FlashPointerLo = ptr & 0xffff; - - pc[info.cdma_num].CommandType = 0x42; - pc[info.cdma_num].CommandFlags = - (0 << 10) | (1 << 9) | (0 << 8) | 0x40; - pc[info.cdma_num].MemAddrHi = 0; - pc[info.cdma_num].MemAddrLo = 0; - - pc[info.cdma_num].Channel = 0; - pc[info.cdma_num].Status = 0; - pc[info.cdma_num].pcmd = i; - - info.cdma_num++; - BUG_ON(info.cdma_num >= MAX_DESCS); - } - } - - /* Add a dummy descriptor at end of the CDMA chain */ - reset_cdma_desc(info.cdma_num); - ptr = MODE_10 | (info.flash_bank << 24); - pc[info.cdma_num].FlashPointerHi = ptr >> 16; - pc[info.cdma_num].FlashPointerLo = ptr & 0xffff; - pc[info.cdma_num].CommandType = 0xFFFF; /* NOP command */ - /* Set Command Flags for the last CDMA descriptor: */ - /* set Continue bit (bit 9) to 0 and Interrupt bit (bit 8) to 1 */ - pc[info.cdma_num].CommandFlags = - (0 << 10) | (0 << 9) | (1 << 8) | 0x40; - pc[info.cdma_num].pcmd = 0xff; /* Set it to an illegal value */ - info.cdma_num++; - BUG_ON(info.cdma_num >= MAX_DESCS); - - iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable Interrupt */ - - iowrite32(1, FlashReg + DMA_ENABLE); - /* Wait for DMA to be enabled before issuing the next command */ - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - cdma_trans(info.flash_bank); - - ret = wait_for_completion_timeout(&info.complete, 50 * HZ); - if (!ret) - printk(KERN_ERR "Wait for completion timeout " - "in %s, Line %d\n", __FILE__, __LINE__); - status = info.ret; - - info.pcmds_num = 0; /* Clear the pending cmds number to 0 */ - - return status; -} - -int is_cdma_interrupt(void) -{ - u32 ints_b0, ints_b1, ints_b2, ints_b3, ints_cdma; - u32 int_en_mask; - u32 cdma_int_en_mask; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - /* Set the global Enable masks for only those interrupts - * that are supported */ - cdma_int_en_mask = (DMA_INTR__DESC_COMP_CHANNEL0 | - DMA_INTR__DESC_COMP_CHANNEL1 | - DMA_INTR__DESC_COMP_CHANNEL2 | - DMA_INTR__DESC_COMP_CHANNEL3 | - DMA_INTR__MEMCOPY_DESC_COMP); - - int_en_mask = (INTR_STATUS0__ECC_ERR | - INTR_STATUS0__PROGRAM_FAIL | - INTR_STATUS0__ERASE_FAIL); - - ints_b0 = ioread32(FlashReg + INTR_STATUS0) & int_en_mask; - ints_b1 = ioread32(FlashReg + INTR_STATUS1) & int_en_mask; - ints_b2 = ioread32(FlashReg + INTR_STATUS2) & int_en_mask; - ints_b3 = ioread32(FlashReg + INTR_STATUS3) & int_en_mask; - ints_cdma = ioread32(FlashReg + DMA_INTR) & cdma_int_en_mask; - - nand_dbg_print(NAND_DBG_WARN, "ints_bank0 to ints_bank3: " - "0x%x, 0x%x, 0x%x, 0x%x, ints_cdma: 0x%x\n", - ints_b0, ints_b1, ints_b2, ints_b3, ints_cdma); - - if (ints_b0 || ints_b1 || ints_b2 || ints_b3 || ints_cdma) { - return 1; - } else { - iowrite32(ints_b0, FlashReg + INTR_STATUS0); - iowrite32(ints_b1, FlashReg + INTR_STATUS1); - iowrite32(ints_b2, FlashReg + INTR_STATUS2); - iowrite32(ints_b3, FlashReg + INTR_STATUS3); - nand_dbg_print(NAND_DBG_DEBUG, - "Not a NAND controller interrupt! Ignore it.\n"); - return 0; - } -} - -static void update_event_status(void) -{ - int i; - struct cdma_descriptor *ptr; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - ptr = (struct cdma_descriptor *)info.cdma_desc_buf; - - for (i = 0; i < info.cdma_num; i++) { - if (ptr[i].pcmd != 0xff) - info.pcmds[ptr[i].pcmd].Status = CMD_PASS; - if ((ptr[i].CommandType == 0x41) || - (ptr[i].CommandType == 0x42) || - (ptr[i].CommandType == 0x43)) - continue; - - switch (info.pcmds[ptr[i].pcmd].CMD) { - case READ_MAIN_SPARE_CMD: - Conv_Main_Spare_Data_Phy2Log_Format( - info.pcmds[ptr[i].pcmd].DataAddr, - info.pcmds[ptr[i].pcmd].PageCount); - break; - case READ_SPARE_CMD: - Conv_Spare_Data_Phy2Log_Format( - info.pcmds[ptr[i].pcmd].DataAddr); - break; - } - } -} - -static u16 do_ecc_for_desc(u32 ch, u8 *buf, u16 page) -{ - u16 event = EVENT_NONE; - u16 err_byte; - u16 err_page = 0; - u8 err_sector; - u8 err_device; - u16 ecc_correction_info; - u16 err_address; - u32 eccSectorSize; - u8 *err_pos; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected); - - do { - if (0 == ch) - err_page = ioread32(FlashReg + ERR_PAGE_ADDR0); - else if (1 == ch) - err_page = ioread32(FlashReg + ERR_PAGE_ADDR1); - else if (2 == ch) - err_page = ioread32(FlashReg + ERR_PAGE_ADDR2); - else if (3 == ch) - err_page = ioread32(FlashReg + ERR_PAGE_ADDR3); - - err_address = ioread32(FlashReg + ECC_ERROR_ADDRESS); - err_byte = err_address & ECC_ERROR_ADDRESS__OFFSET; - err_sector = ((err_address & - ECC_ERROR_ADDRESS__SECTOR_NR) >> 12); - - ecc_correction_info = ioread32(FlashReg + ERR_CORRECTION_INFO); - err_device = ((ecc_correction_info & - ERR_CORRECTION_INFO__DEVICE_NR) >> 8); - - if (ecc_correction_info & ERR_CORRECTION_INFO__ERROR_TYPE) { - event = EVENT_UNCORRECTABLE_DATA_ERROR; - } else { - event = EVENT_CORRECTABLE_DATA_ERROR_FIXED; - if (err_byte < ECC_SECTOR_SIZE) { - err_pos = buf + - (err_page - page) * - DeviceInfo.wPageDataSize + - err_sector * eccSectorSize + - err_byte * - DeviceInfo.wDevicesConnected + - err_device; - *err_pos ^= ecc_correction_info & - ERR_CORRECTION_INFO__BYTEMASK; - } - } - } while (!(ecc_correction_info & ERR_CORRECTION_INFO__LAST_ERR_INFO)); - - return event; -} - -static u16 process_ecc_int(u32 c, u16 *p_desc_num) -{ - struct cdma_descriptor *ptr; - u16 j; - int event = EVENT_PASS; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (c != info.flash_bank) - printk(KERN_ERR "Error!info.flash_bank is %d, while c is %d\n", - info.flash_bank, c); - - ptr = (struct cdma_descriptor *)info.cdma_desc_buf; - - for (j = 0; j < info.cdma_num; j++) - if ((ptr[j].Status & CMD_DMA_DESC_COMP) != CMD_DMA_DESC_COMP) - break; - - *p_desc_num = j; /* Pass the descripter number found here */ - - if (j >= info.cdma_num) { - printk(KERN_ERR "Can not find the correct descriptor number " - "when ecc interrupt triggered!" - "info.cdma_num: %d, j: %d\n", info.cdma_num, j); - return EVENT_UNCORRECTABLE_DATA_ERROR; - } - - event = do_ecc_for_desc(c, info.pcmds[ptr[j].pcmd].DataAddr, - info.pcmds[ptr[j].pcmd].Page); - - if (EVENT_UNCORRECTABLE_DATA_ERROR == event) { - printk(KERN_ERR "Uncorrectable ECC error!" - "info.cdma_num: %d, j: %d, " - "pending cmd CMD: 0x%x, " - "Block: 0x%x, Page: 0x%x, PageCount: 0x%x\n", - info.cdma_num, j, - info.pcmds[ptr[j].pcmd].CMD, - info.pcmds[ptr[j].pcmd].Block, - info.pcmds[ptr[j].pcmd].Page, - info.pcmds[ptr[j].pcmd].PageCount); - - if (ptr[j].pcmd != 0xff) - info.pcmds[ptr[j].pcmd].Status = CMD_FAIL; - CDMA_UpdateEventStatus(); - } - - return event; -} - -static void process_prog_erase_fail_int(u16 desc_num) -{ - struct cdma_descriptor *ptr; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - ptr = (struct cdma_descriptor *)info.cdma_desc_buf; - - if (ptr[desc_num].pcmd != 0xFF) - info.pcmds[ptr[desc_num].pcmd].Status = CMD_FAIL; - - CDMA_UpdateEventStatus(); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: CDMA_Event_Status (for use with CMD_DMA) -* Inputs: none -* Outputs: Event_Status code -* Description: This function is called after an interrupt has happened -* It reads the HW status register and ...tbd -* It returns the appropriate event status -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 CDMA_Event_Status(void) -{ - u32 ints_addr[4] = {INTR_STATUS0, INTR_STATUS1, - INTR_STATUS2, INTR_STATUS3}; - u32 dma_intr_bit[4] = {DMA_INTR__DESC_COMP_CHANNEL0, - DMA_INTR__DESC_COMP_CHANNEL1, - DMA_INTR__DESC_COMP_CHANNEL2, - DMA_INTR__DESC_COMP_CHANNEL3}; - u32 cdma_int_status, int_status; - u32 ecc_enable = 0; - u16 event = EVENT_PASS; - u16 cur_desc = 0; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - ecc_enable = ioread32(FlashReg + ECC_ENABLE); - - while (1) { - int_status = ioread32(FlashReg + ints_addr[info.flash_bank]); - if (ecc_enable && (int_status & INTR_STATUS0__ECC_ERR)) { - event = process_ecc_int(info.flash_bank, &cur_desc); - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + ints_addr[info.flash_bank]); - if (EVENT_UNCORRECTABLE_DATA_ERROR == event) { - nand_dbg_print(NAND_DBG_WARN, - "ints_bank0 to ints_bank3: " - "0x%x, 0x%x, 0x%x, 0x%x, " - "ints_cdma: 0x%x\n", - ioread32(FlashReg + INTR_STATUS0), - ioread32(FlashReg + INTR_STATUS1), - ioread32(FlashReg + INTR_STATUS2), - ioread32(FlashReg + INTR_STATUS3), - ioread32(FlashReg + DMA_INTR)); - break; - } - } else if (int_status & INTR_STATUS0__PROGRAM_FAIL) { - printk(KERN_ERR "NAND program fail interrupt!\n"); - process_prog_erase_fail_int(cur_desc); - event = EVENT_PROGRAM_FAILURE; - break; - } else if (int_status & INTR_STATUS0__ERASE_FAIL) { - printk(KERN_ERR "NAND erase fail interrupt!\n"); - process_prog_erase_fail_int(cur_desc); - event = EVENT_ERASE_FAILURE; - break; - } else { - cdma_int_status = ioread32(FlashReg + DMA_INTR); - if (cdma_int_status & dma_intr_bit[info.flash_bank]) { - iowrite32(dma_intr_bit[info.flash_bank], - FlashReg + DMA_INTR); - update_event_status(); - event = EVENT_PASS; - break; - } - } - } - - int_status = ioread32(FlashReg + ints_addr[info.flash_bank]); - iowrite32(int_status, FlashReg + ints_addr[info.flash_bank]); - cdma_int_status = ioread32(FlashReg + DMA_INTR); - iowrite32(cdma_int_status, FlashReg + DMA_INTR); - - iowrite32(0, FlashReg + DMA_ENABLE); - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - return event; -} - - - diff --git a/drivers/staging/spectra/lld_cdma.h b/drivers/staging/spectra/lld_cdma.h deleted file mode 100644 index 854ea066f0c..00000000000 --- a/drivers/staging/spectra/lld_cdma.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -/* header for LLD_CDMA.c module */ - -#ifndef _LLD_CDMA_ -#define _LLD_CDMA_ - -#include "flash.h" - -#define DEBUG_SYNC 1 - -/*/////////// CDMA specific MACRO definition */ -#define MAX_DESCS (255) -#define MAX_CHANS (4) -#define MAX_SYNC_POINTS (16) -#define MAX_DESC_PER_CHAN (MAX_DESCS * 3 + MAX_SYNC_POINTS + 2) - -#define CHANNEL_SYNC_MASK (0x000F) -#define CHANNEL_DMA_MASK (0x00F0) -#define CHANNEL_ID_MASK (0x0300) -#define CHANNEL_CONT_MASK (0x4000) -#define CHANNEL_INTR_MASK (0x8000) - -#define CHANNEL_SYNC_OFFSET (0) -#define CHANNEL_DMA_OFFSET (4) -#define CHANNEL_ID_OFFSET (8) -#define CHANNEL_CONT_OFFSET (14) -#define CHANNEL_INTR_OFFSET (15) - -u16 CDMA_Data_CMD(u8 cmd, u8 *data, u32 block, u16 page, u16 num, u16 flags); -u16 CDMA_MemCopy_CMD(u8 *dest, u8 *src, u32 byte_cnt, u16 flags); -u16 CDMA_Execute_CMDs(void); -void print_pending_cmds(void); -void print_cdma_descriptors(void); - -extern u8 g_SBDCmdIndex; -extern struct mrst_nand_info info; - - -/*/////////// prototypes: APIs for LLD_CDMA */ -int is_cdma_interrupt(void); -u16 CDMA_Event_Status(void); - -/* CMD-DMA Descriptor Struct. These are defined by the CMD_DMA HW */ -struct cdma_descriptor { - u32 NxtPointerHi; - u32 NxtPointerLo; - u32 FlashPointerHi; - u32 FlashPointerLo; - u32 CommandType; - u32 MemAddrHi; - u32 MemAddrLo; - u32 CommandFlags; - u32 Channel; - u32 Status; - u32 MemCopyPointerHi; - u32 MemCopyPointerLo; - u32 Reserved12; - u32 Reserved13; - u32 Reserved14; - u32 pcmd; /* pending cmd num related to this descriptor */ -}; - -/* This struct holds one MemCopy descriptor as defined by the HW */ -struct memcpy_descriptor { - u32 NxtPointerHi; - u32 NxtPointerLo; - u32 SrcAddrHi; - u32 SrcAddrLo; - u32 DestAddrHi; - u32 DestAddrLo; - u32 XferSize; - u32 MemCopyFlags; - u32 MemCopyStatus; - u32 reserved9; - u32 reserved10; - u32 reserved11; - u32 reserved12; - u32 reserved13; - u32 reserved14; - u32 reserved15; -}; - -/* Pending CMD table entries (includes MemCopy parameters */ -struct pending_cmd { - u8 CMD; - u8 *DataAddr; - u32 Block; - u16 Page; - u16 PageCount; - u8 *DataDestAddr; - u8 *DataSrcAddr; - u32 MemCopyByteCnt; - u16 Flags; - u16 Status; -}; - -#if DEBUG_SYNC -extern u32 debug_sync_cnt; -#endif - -/* Definitions for CMD DMA descriptor chain fields */ -#define CMD_DMA_DESC_COMP 0x8000 -#define CMD_DMA_DESC_FAIL 0x4000 - -#endif /*_LLD_CDMA_*/ diff --git a/drivers/staging/spectra/lld_emu.c b/drivers/staging/spectra/lld_emu.c deleted file mode 100644 index 095f2f0c2e5..00000000000 --- a/drivers/staging/spectra/lld_emu.c +++ /dev/null @@ -1,776 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#include <linux/fs.h> -#include <linux/slab.h> -#include "flash.h" -#include "ffsdefs.h" -#include "lld_emu.h" -#include "lld.h" -#if CMD_DMA -#include "lld_cdma.h" -#if FLASH_EMU -u32 totalUsedBanks; -u32 valid_banks[MAX_CHANS]; -#endif -#endif - -#define GLOB_LLD_PAGES 64 -#define GLOB_LLD_PAGE_SIZE (512+16) -#define GLOB_LLD_PAGE_DATA_SIZE 512 -#define GLOB_LLD_BLOCKS 2048 - -#if FLASH_EMU /* This is for entire module */ - -static u8 *flash_memory[GLOB_LLD_BLOCKS * GLOB_LLD_PAGES]; - -/* Read nand emu file and then fill it's content to flash_memory */ -int emu_load_file_to_mem(void) -{ - mm_segment_t fs; - struct file *nef_filp = NULL; - struct inode *inode = NULL; - loff_t nef_size = 0; - loff_t tmp_file_offset, file_offset; - ssize_t nread; - int i, rc = -EINVAL; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - fs = get_fs(); - set_fs(get_ds()); - - nef_filp = filp_open("/root/nand_emu_file", O_RDWR | O_LARGEFILE, 0); - if (IS_ERR(nef_filp)) { - printk(KERN_ERR "filp_open error: " - "Unable to open nand emu file!\n"); - return PTR_ERR(nef_filp); - } - - if (nef_filp->f_path.dentry) { - inode = nef_filp->f_path.dentry->d_inode; - } else { - printk(KERN_ERR "Can not get valid inode!\n"); - goto out; - } - - nef_size = i_size_read(inode->i_mapping->host); - if (nef_size <= 0) { - printk(KERN_ERR "Invalid nand emu file size: " - "0x%llx\n", nef_size); - goto out; - } else { - nand_dbg_print(NAND_DBG_DEBUG, "nand emu file size: %lld\n", - nef_size); - } - - file_offset = 0; - for (i = 0; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++) { - tmp_file_offset = file_offset; - nread = vfs_read(nef_filp, - (char __user *)flash_memory[i], - GLOB_LLD_PAGE_SIZE, &tmp_file_offset); - if (nread < GLOB_LLD_PAGE_SIZE) { - printk(KERN_ERR "%s, Line %d - " - "nand emu file partial read: " - "%d bytes\n", __FILE__, __LINE__, (int)nread); - goto out; - } - file_offset += GLOB_LLD_PAGE_SIZE; - } - rc = 0; - -out: - filp_close(nef_filp, current->files); - set_fs(fs); - return rc; -} - -/* Write contents of flash_memory to nand emu file */ -int emu_write_mem_to_file(void) -{ - mm_segment_t fs; - struct file *nef_filp = NULL; - struct inode *inode = NULL; - loff_t nef_size = 0; - loff_t tmp_file_offset, file_offset; - ssize_t nwritten; - int i, rc = -EINVAL; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - fs = get_fs(); - set_fs(get_ds()); - - nef_filp = filp_open("/root/nand_emu_file", O_RDWR | O_LARGEFILE, 0); - if (IS_ERR(nef_filp)) { - printk(KERN_ERR "filp_open error: " - "Unable to open nand emu file!\n"); - return PTR_ERR(nef_filp); - } - - if (nef_filp->f_path.dentry) { - inode = nef_filp->f_path.dentry->d_inode; - } else { - printk(KERN_ERR "Invalid " "nef_filp->f_path.dentry value!\n"); - goto out; - } - - nef_size = i_size_read(inode->i_mapping->host); - if (nef_size <= 0) { - printk(KERN_ERR "Invalid " - "nand emu file size: 0x%llx\n", nef_size); - goto out; - } else { - nand_dbg_print(NAND_DBG_DEBUG, "nand emu file size: " - "%lld\n", nef_size); - } - - file_offset = 0; - for (i = 0; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++) { - tmp_file_offset = file_offset; - nwritten = vfs_write(nef_filp, - (char __user *)flash_memory[i], - GLOB_LLD_PAGE_SIZE, &tmp_file_offset); - if (nwritten < GLOB_LLD_PAGE_SIZE) { - printk(KERN_ERR "%s, Line %d - " - "nand emu file partial write: " - "%d bytes\n", __FILE__, __LINE__, (int)nwritten); - goto out; - } - file_offset += GLOB_LLD_PAGE_SIZE; - } - rc = 0; - -out: - filp_close(nef_filp, current->files); - set_fs(fs); - return rc; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Flash_Init -* Inputs: none -* Outputs: PASS=0 (notice 0=ok here) -* Description: Creates & initializes the flash RAM array. -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Flash_Init(void) -{ - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - flash_memory[0] = vmalloc(GLOB_LLD_PAGE_SIZE * GLOB_LLD_BLOCKS * - GLOB_LLD_PAGES * sizeof(u8)); - if (!flash_memory[0]) { - printk(KERN_ERR "Fail to allocate memory " - "for nand emulator!\n"); - return ERR; - } - - memset((char *)(flash_memory[0]), 0xFF, - GLOB_LLD_PAGE_SIZE * GLOB_LLD_BLOCKS * GLOB_LLD_PAGES * - sizeof(u8)); - - for (i = 1; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++) - flash_memory[i] = flash_memory[i - 1] + GLOB_LLD_PAGE_SIZE; - - emu_load_file_to_mem(); /* Load nand emu file to mem */ - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Flash_Release -* Inputs: none -* Outputs: PASS=0 (notice 0=ok here) -* Description: Releases the flash. -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int emu_Flash_Release(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - emu_write_mem_to_file(); /* Write back mem to nand emu file */ - - vfree(flash_memory[0]); - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Read_Device_ID -* Inputs: none -* Outputs: PASS=1 FAIL=0 -* Description: Reads the info from the controller registers. -* Sets up DeviceInfo structure with device parameters -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ - -u16 emu_Read_Device_ID(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - DeviceInfo.wDeviceMaker = 0; - DeviceInfo.wDeviceType = 8; - DeviceInfo.wSpectraStartBlock = 36; - DeviceInfo.wSpectraEndBlock = GLOB_LLD_BLOCKS - 1; - DeviceInfo.wTotalBlocks = GLOB_LLD_BLOCKS; - DeviceInfo.wPagesPerBlock = GLOB_LLD_PAGES; - DeviceInfo.wPageSize = GLOB_LLD_PAGE_SIZE; - DeviceInfo.wPageDataSize = GLOB_LLD_PAGE_DATA_SIZE; - DeviceInfo.wPageSpareSize = GLOB_LLD_PAGE_SIZE - - GLOB_LLD_PAGE_DATA_SIZE; - DeviceInfo.wBlockSize = DeviceInfo.wPageSize * GLOB_LLD_PAGES; - DeviceInfo.wBlockDataSize = DeviceInfo.wPageDataSize * GLOB_LLD_PAGES; - DeviceInfo.wDataBlockNum = (u32) (DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock - + 1); - DeviceInfo.MLCDevice = 1; /* Emulate MLC device */ - DeviceInfo.nBitsInPageNumber = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock); - DeviceInfo.nBitsInPageDataSize = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize); - DeviceInfo.nBitsInBlockDataSize = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize); - -#if CMD_DMA - totalUsedBanks = 4; - valid_banks[0] = 1; - valid_banks[1] = 1; - valid_banks[2] = 1; - valid_banks[3] = 1; -#endif - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Flash_Reset -* Inputs: none -* Outputs: PASS=0 (notice 0=ok here) -* Description: Reset the flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Flash_Reset(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Erase_Block -* Inputs: Address -* Outputs: PASS=0 (notice 0=ok here) -* Description: Erase a block -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Erase_Block(u32 block_add) -{ - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (block_add >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "emu_Erase_Block error! " - "Too big block address: %d\n", block_add); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Erasing block %d\n", - (int)block_add); - - for (i = block_add * GLOB_LLD_PAGES; - i < ((block_add + 1) * GLOB_LLD_PAGES); i++) { - if (flash_memory[i]) { - memset((u8 *)(flash_memory[i]), 0xFF, - DeviceInfo.wPageSize * sizeof(u8)); - } - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Write_Page_Main -* Inputs: Write buffer address pointer -* Block number -* Page number -* Number of pages to process -* Outputs: PASS=0 (notice 0=ok here) -* Description: Write the data in the buffer to main area of flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Write_Page_Main(u8 *write_data, u32 Block, - u16 Page, u16 PageCount) -{ - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) - return FAIL; - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) - return FAIL; - - nand_dbg_print(NAND_DBG_DEBUG, "emu_Write_Page_Main: " - "lba %u Page %u PageCount %u\n", - (unsigned int)Block, - (unsigned int)Page, (unsigned int)PageCount); - - for (i = 0; i < PageCount; i++) { - if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) { - printk(KERN_ERR "Run out of memory\n"); - return FAIL; - } - memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]), - write_data, DeviceInfo.wPageDataSize); - write_data += DeviceInfo.wPageDataSize; - Page++; - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Read_Page_Main -* Inputs: Read buffer address pointer -* Block number -* Page number -* Number of pages to process -* Outputs: PASS=0 (notice 0=ok here) -* Description: Read the data from the flash main area to the buffer -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Read_Page_Main(u8 *read_data, u32 Block, - u16 Page, u16 PageCount) -{ - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) - return FAIL; - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) - return FAIL; - - nand_dbg_print(NAND_DBG_DEBUG, "emu_Read_Page_Main: " - "lba %u Page %u PageCount %u\n", - (unsigned int)Block, - (unsigned int)Page, (unsigned int)PageCount); - - for (i = 0; i < PageCount; i++) { - if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) { - memset(read_data, 0xFF, DeviceInfo.wPageDataSize); - } else { - memcpy(read_data, - (u8 *) (flash_memory[Block * GLOB_LLD_PAGES - + Page]), - DeviceInfo.wPageDataSize); - } - read_data += DeviceInfo.wPageDataSize; - Page++; - } - - return PASS; -} - -#ifndef ELDORA -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Read_Page_Main_Spare -* Inputs: Write Buffer -* Address -* Buffer size -* Outputs: PASS=0 (notice 0=ok here) -* Description: Read from flash main+spare area -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Read_Page_Main_Spare(u8 *read_data, u32 Block, - u16 Page, u16 PageCount) -{ - int i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "Read Page Main+Spare " - "Error: Block Address too big\n"); - return FAIL; - } - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "Read Page Main+Spare " - "Error: Page number too big\n"); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Read Page Main + Spare - " - "No. of pages %u block %u start page %u\n", - (unsigned int)PageCount, - (unsigned int)Block, (unsigned int)Page); - - for (i = 0; i < PageCount; i++) { - if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) { - memset(read_data, 0xFF, DeviceInfo.wPageSize); - } else { - memcpy(read_data, (u8 *) (flash_memory[Block * - GLOB_LLD_PAGES - + Page]), - DeviceInfo.wPageSize); - } - - read_data += DeviceInfo.wPageSize; - Page++; - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Write_Page_Main_Spare -* Inputs: Write buffer -* address -* buffer length -* Outputs: PASS=0 (notice 0=ok here) -* Description: Write the buffer to main+spare area of flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Write_Page_Main_Spare(u8 *write_data, u32 Block, - u16 Page, u16 page_count) -{ - u16 i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "Write Page Main + Spare " - "Error: Block Address too big\n"); - return FAIL; - } - - if (Page + page_count > DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "Write Page Main + Spare " - "Error: Page number too big\n"); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Write Page Main+Spare - " - "No. of pages %u block %u start page %u\n", - (unsigned int)page_count, - (unsigned int)Block, (unsigned int)Page); - - for (i = 0; i < page_count; i++) { - if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) { - printk(KERN_ERR "Run out of memory!\n"); - return FAIL; - } - memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]), - write_data, DeviceInfo.wPageSize); - write_data += DeviceInfo.wPageSize; - Page++; - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Write_Page_Spare -* Inputs: Write buffer -* Address -* buffer size -* Outputs: PASS=0 (notice 0=ok here) -* Description: Write the buffer in the spare area -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Write_Page_Spare(u8 *write_data, u32 Block, - u16 Page, u16 PageCount) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "Read Page Spare Error: " - "Block Address too big\n"); - return FAIL; - } - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "Read Page Spare Error: " - "Page number too big\n"); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Write Page Spare- " - "block %u page %u\n", - (unsigned int)Block, (unsigned int)Page); - - if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) { - printk(KERN_ERR "Run out of memory!\n"); - return FAIL; - } - - memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page] + - DeviceInfo.wPageDataSize), write_data, - (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize)); - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Read_Page_Spare -* Inputs: Write Buffer -* Address -* Buffer size -* Outputs: PASS=0 (notice 0=ok here) -* Description: Read data from the spare area -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_Read_Page_Spare(u8 *write_data, u32 Block, - u16 Page, u16 PageCount) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "Read Page Spare " - "Error: Block Address too big\n"); - return FAIL; - } - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "Read Page Spare " - "Error: Page number too big\n"); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Read Page Spare- " - "block %u page %u\n", - (unsigned int)Block, (unsigned int)Page); - - if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) { - memset(write_data, 0xFF, - (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize)); - } else { - memcpy(write_data, - (u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page] - + DeviceInfo.wPageDataSize), - (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize)); - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Enable_Disable_Interrupts -* Inputs: enable or disable -* Outputs: none -* Description: NOP -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -void emu_Enable_Disable_Interrupts(u16 INT_ENABLE) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); -} - -u16 emu_Get_Bad_Block(u32 block) -{ - return 0; -} - -#if CMD_DMA -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Support for CDMA functions -************************************ -* emu_CDMA_Flash_Init -* CDMA_process_data command (use LLD_CDMA) -* CDMA_MemCopy_CMD (use LLD_CDMA) -* emu_CDMA_execute all commands -* emu_CDMA_Event_Status -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_CDMA_Flash_Init(void) -{ - u16 i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < MAX_DESCS + MAX_CHANS; i++) { - PendingCMD[i].CMD = 0; - PendingCMD[i].Tag = 0; - PendingCMD[i].DataAddr = 0; - PendingCMD[i].Block = 0; - PendingCMD[i].Page = 0; - PendingCMD[i].PageCount = 0; - PendingCMD[i].DataDestAddr = 0; - PendingCMD[i].DataSrcAddr = 0; - PendingCMD[i].MemCopyByteCnt = 0; - PendingCMD[i].ChanSync[0] = 0; - PendingCMD[i].ChanSync[1] = 0; - PendingCMD[i].ChanSync[2] = 0; - PendingCMD[i].ChanSync[3] = 0; - PendingCMD[i].ChanSync[4] = 0; - PendingCMD[i].Status = 3; - } - - return PASS; -} - -static void emu_isr(int irq, void *dev_id) -{ - /* TODO: ... */ -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: CDMA_Execute_CMDs -* Inputs: tag_count: the number of pending cmds to do -* Outputs: PASS/FAIL -* Description: execute each command in the pending CMD array -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_CDMA_Execute_CMDs(u16 tag_count) -{ - u16 i, j; - u8 CMD; /* cmd parameter */ - u8 *data; - u32 block; - u16 page; - u16 count; - u16 status = PASS; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - nand_dbg_print(NAND_DBG_TRACE, "At start of Execute CMDs: " - "Tag Count %u\n", tag_count); - - for (i = 0; i < totalUsedBanks; i++) { - PendingCMD[i].CMD = DUMMY_CMD; - PendingCMD[i].Tag = 0xFF; - PendingCMD[i].Block = - (DeviceInfo.wTotalBlocks / totalUsedBanks) * i; - - for (j = 0; j <= MAX_CHANS; j++) - PendingCMD[i].ChanSync[j] = 0; - } - - CDMA_Execute_CMDs(tag_count); - - print_pending_cmds(tag_count); - -#if DEBUG_SYNC - } - debug_sync_cnt++; -#endif - - for (i = MAX_CHANS; - i < tag_count + MAX_CHANS; i++) { - CMD = PendingCMD[i].CMD; - data = PendingCMD[i].DataAddr; - block = PendingCMD[i].Block; - page = PendingCMD[i].Page; - count = PendingCMD[i].PageCount; - - switch (CMD) { - case ERASE_CMD: - emu_Erase_Block(block); - PendingCMD[i].Status = PASS; - break; - case WRITE_MAIN_CMD: - emu_Write_Page_Main(data, block, page, count); - PendingCMD[i].Status = PASS; - break; - case WRITE_MAIN_SPARE_CMD: - emu_Write_Page_Main_Spare(data, block, page, count); - PendingCMD[i].Status = PASS; - break; - case READ_MAIN_CMD: - emu_Read_Page_Main(data, block, page, count); - PendingCMD[i].Status = PASS; - break; - case MEMCOPY_CMD: - memcpy(PendingCMD[i].DataDestAddr, - PendingCMD[i].DataSrcAddr, - PendingCMD[i].MemCopyByteCnt); - case DUMMY_CMD: - PendingCMD[i].Status = PASS; - break; - default: - PendingCMD[i].Status = FAIL; - break; - } - } - - /* - * Temperory adding code to reset PendingCMD array for basic testing. - * It should be done at the end of event status function. - */ - for (i = tag_count + MAX_CHANS; i < MAX_DESCS; i++) { - PendingCMD[i].CMD = 0; - PendingCMD[i].Tag = 0; - PendingCMD[i].DataAddr = 0; - PendingCMD[i].Block = 0; - PendingCMD[i].Page = 0; - PendingCMD[i].PageCount = 0; - PendingCMD[i].DataDestAddr = 0; - PendingCMD[i].DataSrcAddr = 0; - PendingCMD[i].MemCopyByteCnt = 0; - PendingCMD[i].ChanSync[0] = 0; - PendingCMD[i].ChanSync[1] = 0; - PendingCMD[i].ChanSync[2] = 0; - PendingCMD[i].ChanSync[3] = 0; - PendingCMD[i].ChanSync[4] = 0; - PendingCMD[i].Status = CMD_NOT_DONE; - } - - nand_dbg_print(NAND_DBG_TRACE, "At end of Execute CMDs.\n"); - - emu_isr(0, 0); /* This is a null isr now. Need fill it in future */ - - return status; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: emu_Event_Status -* Inputs: none -* Outputs: Event_Status code -* Description: This function can also be used to force errors -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 emu_CDMA_Event_Status(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return EVENT_PASS; -} - -#endif /* CMD_DMA */ -#endif /* !ELDORA */ -#endif /* FLASH_EMU */ diff --git a/drivers/staging/spectra/lld_emu.h b/drivers/staging/spectra/lld_emu.h deleted file mode 100644 index 63f84c38d3c..00000000000 --- a/drivers/staging/spectra/lld_emu.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#ifndef _LLD_EMU_ -#define _LLD_EMU_ - -#include "ffsport.h" -#include "ffsdefs.h" - -/* prototypes: emulator API functions */ -extern u16 emu_Flash_Reset(void); -extern u16 emu_Flash_Init(void); -extern int emu_Flash_Release(void); -extern u16 emu_Read_Device_ID(void); -extern u16 emu_Erase_Block(u32 block_addr); -extern u16 emu_Write_Page_Main(u8 *write_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 emu_Read_Page_Main(u8 *read_data, u32 Block, u16 Page, - u16 PageCount); -extern u16 emu_Event_Status(void); -extern void emu_Enable_Disable_Interrupts(u16 INT_ENABLE); -extern u16 emu_Write_Page_Main_Spare(u8 *write_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 emu_Write_Page_Spare(u8 *write_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 emu_Read_Page_Main_Spare(u8 *read_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 emu_Read_Page_Spare(u8 *read_data, u32 Block, u16 Page, - u16 PageCount); -extern u16 emu_Get_Bad_Block(u32 block); - -u16 emu_CDMA_Flash_Init(void); -u16 emu_CDMA_Execute_CMDs(u16 tag_count); -u16 emu_CDMA_Event_Status(void); -#endif /*_LLD_EMU_*/ diff --git a/drivers/staging/spectra/lld_mtd.c b/drivers/staging/spectra/lld_mtd.c deleted file mode 100644 index a9c309a167c..00000000000 --- a/drivers/staging/spectra/lld_mtd.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/mtd/mtd.h> -#include "flash.h" -#include "ffsdefs.h" -#include "lld_emu.h" -#include "lld.h" -#if CMD_DMA -#include "lld_cdma.h" -u32 totalUsedBanks; -u32 valid_banks[MAX_CHANS]; -#endif - -#define GLOB_LLD_PAGES 64 -#define GLOB_LLD_PAGE_SIZE (512+16) -#define GLOB_LLD_PAGE_DATA_SIZE 512 -#define GLOB_LLD_BLOCKS 2048 - -static struct mtd_info *spectra_mtd; -static int mtddev = -1; -module_param(mtddev, int, 0); - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Flash_Init -* Inputs: none -* Outputs: PASS=0 (notice 0=ok here) -* Description: Creates & initializes the flash RAM array. -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Flash_Init(void) -{ - if (mtddev == -1) { - printk(KERN_ERR "No MTD device specified. Give mtddev parameter\n"); - return FAIL; - } - - spectra_mtd = get_mtd_device(NULL, mtddev); - if (!spectra_mtd) { - printk(KERN_ERR "Failed to obtain MTD device #%d\n", mtddev); - return FAIL; - } - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Flash_Release -* Inputs: none -* Outputs: PASS=0 (notice 0=ok here) -* Description: Releases the flash. -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -int mtd_Flash_Release(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - if (!spectra_mtd) - return PASS; - - put_mtd_device(spectra_mtd); - spectra_mtd = NULL; - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Read_Device_ID -* Inputs: none -* Outputs: PASS=1 FAIL=0 -* Description: Reads the info from the controller registers. -* Sets up DeviceInfo structure with device parameters -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ - -u16 mtd_Read_Device_ID(void) -{ - uint64_t tmp; - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (!spectra_mtd) - return FAIL; - - DeviceInfo.wDeviceMaker = 0; - DeviceInfo.wDeviceType = 8; - DeviceInfo.wSpectraStartBlock = SPECTRA_START_BLOCK; - tmp = spectra_mtd->size; - do_div(tmp, spectra_mtd->erasesize); - DeviceInfo.wTotalBlocks = tmp; - DeviceInfo.wSpectraEndBlock = DeviceInfo.wTotalBlocks - 1; - DeviceInfo.wPagesPerBlock = spectra_mtd->erasesize / spectra_mtd->writesize; - DeviceInfo.wPageSize = spectra_mtd->writesize + spectra_mtd->oobsize; - DeviceInfo.wPageDataSize = spectra_mtd->writesize; - DeviceInfo.wPageSpareSize = spectra_mtd->oobsize; - DeviceInfo.wBlockSize = DeviceInfo.wPageSize * DeviceInfo.wPagesPerBlock; - DeviceInfo.wBlockDataSize = DeviceInfo.wPageDataSize * DeviceInfo.wPagesPerBlock; - DeviceInfo.wDataBlockNum = (u32) (DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock - + 1); - DeviceInfo.MLCDevice = 0;//spectra_mtd->celltype & NAND_CI_CELLTYPE_MSK; - DeviceInfo.nBitsInPageNumber = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock); - DeviceInfo.nBitsInPageDataSize = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize); - DeviceInfo.nBitsInBlockDataSize = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize); - -#if CMD_DMA - totalUsedBanks = 4; - valid_banks[0] = 1; - valid_banks[1] = 1; - valid_banks[2] = 1; - valid_banks[3] = 1; -#endif - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Flash_Reset -* Inputs: none -* Outputs: PASS=0 (notice 0=ok here) -* Description: Reset the flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Flash_Reset(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return PASS; -} - -void erase_callback(struct erase_info *e) -{ - complete((void *)e->priv); -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Erase_Block -* Inputs: Address -* Outputs: PASS=0 (notice 0=ok here) -* Description: Erase a block -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Erase_Block(u32 block_add) -{ - struct erase_info erase; - DECLARE_COMPLETION_ONSTACK(comp); - int ret; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (block_add >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "mtd_Erase_Block error! " - "Too big block address: %d\n", block_add); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Erasing block %d\n", - (int)block_add); - - erase.mtd = spectra_mtd; - erase.callback = erase_callback; - erase.addr = block_add * spectra_mtd->erasesize; - erase.len = spectra_mtd->erasesize; - erase.priv = (unsigned long)∁ - - ret = spectra_mtd->erase(spectra_mtd, &erase); - if (!ret) { - wait_for_completion(&comp); - if (erase.state != MTD_ERASE_DONE) - ret = -EIO; - } - if (ret) { - printk(KERN_WARNING "mtd_Erase_Block error! " - "erase of region [0x%llx, 0x%llx] failed\n", - erase.addr, erase.len); - return FAIL; - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Write_Page_Main -* Inputs: Write buffer address pointer -* Block number -* Page number -* Number of pages to process -* Outputs: PASS=0 (notice 0=ok here) -* Description: Write the data in the buffer to main area of flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Write_Page_Main(u8 *write_data, u32 Block, - u16 Page, u16 PageCount) -{ - size_t retlen; - int ret = 0; - - if (Block >= DeviceInfo.wTotalBlocks) - return FAIL; - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) - return FAIL; - - nand_dbg_print(NAND_DBG_DEBUG, "mtd_Write_Page_Main: " - "lba %u Page %u PageCount %u\n", - (unsigned int)Block, - (unsigned int)Page, (unsigned int)PageCount); - - - while (PageCount) { - ret = spectra_mtd->write(spectra_mtd, - (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize), - DeviceInfo.wPageDataSize, &retlen, write_data); - if (ret) { - printk(KERN_ERR "%s failed %d\n", __func__, ret); - return FAIL; - } - write_data += DeviceInfo.wPageDataSize; - Page++; - PageCount--; - } - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Read_Page_Main -* Inputs: Read buffer address pointer -* Block number -* Page number -* Number of pages to process -* Outputs: PASS=0 (notice 0=ok here) -* Description: Read the data from the flash main area to the buffer -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Read_Page_Main(u8 *read_data, u32 Block, - u16 Page, u16 PageCount) -{ - size_t retlen; - int ret = 0; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) - return FAIL; - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) - return FAIL; - - nand_dbg_print(NAND_DBG_DEBUG, "mtd_Read_Page_Main: " - "lba %u Page %u PageCount %u\n", - (unsigned int)Block, - (unsigned int)Page, (unsigned int)PageCount); - - - while (PageCount) { - ret = spectra_mtd->read(spectra_mtd, - (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize), - DeviceInfo.wPageDataSize, &retlen, read_data); - if (ret) { - printk(KERN_ERR "%s failed %d\n", __func__, ret); - return FAIL; - } - read_data += DeviceInfo.wPageDataSize; - Page++; - PageCount--; - } - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return PASS; -} - -#ifndef ELDORA -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Read_Page_Main_Spare -* Inputs: Write Buffer -* Address -* Buffer size -* Outputs: PASS=0 (notice 0=ok here) -* Description: Read from flash main+spare area -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block, - u16 Page, u16 PageCount) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "Read Page Main+Spare " - "Error: Block Address too big\n"); - return FAIL; - } - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "Read Page Main+Spare " - "Error: Page number %d+%d too big in block %d\n", - Page, PageCount, Block); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Read Page Main + Spare - " - "No. of pages %u block %u start page %u\n", - (unsigned int)PageCount, - (unsigned int)Block, (unsigned int)Page); - - - while (PageCount) { - struct mtd_oob_ops ops; - int ret; - - ops.mode = MTD_OPS_AUTO_OOB; - ops.datbuf = read_data; - ops.len = DeviceInfo.wPageDataSize; - ops.oobbuf = read_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; - ops.ooblen = BTSIG_BYTES; - ops.ooboffs = 0; - - ret = spectra_mtd->read_oob(spectra_mtd, - (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize), - &ops); - if (ret) { - printk(KERN_ERR "%s failed %d\n", __func__, ret); - return FAIL; - } - read_data += DeviceInfo.wPageSize; - Page++; - PageCount--; - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Write_Page_Main_Spare -* Inputs: Write buffer -* address -* buffer length -* Outputs: PASS=0 (notice 0=ok here) -* Description: Write the buffer to main+spare area of flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block, - u16 Page, u16 page_count) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "Write Page Main + Spare " - "Error: Block Address too big\n"); - return FAIL; - } - - if (Page + page_count > DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "Write Page Main + Spare " - "Error: Page number %d+%d too big in block %d\n", - Page, page_count, Block); - WARN_ON(1); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Write Page Main+Spare - " - "No. of pages %u block %u start page %u\n", - (unsigned int)page_count, - (unsigned int)Block, (unsigned int)Page); - - while (page_count) { - struct mtd_oob_ops ops; - int ret; - - ops.mode = MTD_OPS_AUTO_OOB; - ops.datbuf = write_data; - ops.len = DeviceInfo.wPageDataSize; - ops.oobbuf = write_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; - ops.ooblen = BTSIG_BYTES; - ops.ooboffs = 0; - - ret = spectra_mtd->write_oob(spectra_mtd, - (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize), - &ops); - if (ret) { - printk(KERN_ERR "%s failed %d\n", __func__, ret); - return FAIL; - } - write_data += DeviceInfo.wPageSize; - Page++; - page_count--; - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Write_Page_Spare -* Inputs: Write buffer -* Address -* buffer size -* Outputs: PASS=0 (notice 0=ok here) -* Description: Write the buffer in the spare area -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Write_Page_Spare(u8 *write_data, u32 Block, - u16 Page, u16 PageCount) -{ - WARN_ON(1); - return FAIL; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Read_Page_Spare -* Inputs: Write Buffer -* Address -* Buffer size -* Outputs: PASS=0 (notice 0=ok here) -* Description: Read data from the spare area -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block, - u16 Page, u16 PageCount) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (Block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "Read Page Spare " - "Error: Block Address too big\n"); - return FAIL; - } - - if (Page + PageCount > DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "Read Page Spare " - "Error: Page number too big\n"); - return FAIL; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Read Page Spare- " - "block %u page %u (%u pages)\n", - (unsigned int)Block, (unsigned int)Page, PageCount); - - while (PageCount) { - struct mtd_oob_ops ops; - int ret; - - ops.mode = MTD_OPS_AUTO_OOB; - ops.datbuf = NULL; - ops.len = 0; - ops.oobbuf = read_data; - ops.ooblen = BTSIG_BYTES; - ops.ooboffs = 0; - - ret = spectra_mtd->read_oob(spectra_mtd, - (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize), - &ops); - if (ret) { - printk(KERN_ERR "%s failed %d\n", __func__, ret); - return FAIL; - } - - read_data += DeviceInfo.wPageSize; - Page++; - PageCount--; - } - - return PASS; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Enable_Disable_Interrupts -* Inputs: enable or disable -* Outputs: none -* Description: NOP -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -void mtd_Enable_Disable_Interrupts(u16 INT_ENABLE) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); -} - -u16 mtd_Get_Bad_Block(u32 block) -{ - return 0; -} - -#if CMD_DMA -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Support for CDMA functions -************************************ -* mtd_CDMA_Flash_Init -* CDMA_process_data command (use LLD_CDMA) -* CDMA_MemCopy_CMD (use LLD_CDMA) -* mtd_CDMA_execute all commands -* mtd_CDMA_Event_Status -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_CDMA_Flash_Init(void) -{ - u16 i; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0; i < MAX_DESCS + MAX_CHANS; i++) { - PendingCMD[i].CMD = 0; - PendingCMD[i].Tag = 0; - PendingCMD[i].DataAddr = 0; - PendingCMD[i].Block = 0; - PendingCMD[i].Page = 0; - PendingCMD[i].PageCount = 0; - PendingCMD[i].DataDestAddr = 0; - PendingCMD[i].DataSrcAddr = 0; - PendingCMD[i].MemCopyByteCnt = 0; - PendingCMD[i].ChanSync[0] = 0; - PendingCMD[i].ChanSync[1] = 0; - PendingCMD[i].ChanSync[2] = 0; - PendingCMD[i].ChanSync[3] = 0; - PendingCMD[i].ChanSync[4] = 0; - PendingCMD[i].Status = 3; - } - - return PASS; -} - -static void mtd_isr(int irq, void *dev_id) -{ - /* TODO: ... */ -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: CDMA_Execute_CMDs -* Inputs: tag_count: the number of pending cmds to do -* Outputs: PASS/FAIL -* Description: execute each command in the pending CMD array -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_CDMA_Execute_CMDs(u16 tag_count) -{ - u16 i, j; - u8 CMD; /* cmd parameter */ - u8 *data; - u32 block; - u16 page; - u16 count; - u16 status = PASS; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - nand_dbg_print(NAND_DBG_TRACE, "At start of Execute CMDs: " - "Tag Count %u\n", tag_count); - - for (i = 0; i < totalUsedBanks; i++) { - PendingCMD[i].CMD = DUMMY_CMD; - PendingCMD[i].Tag = 0xFF; - PendingCMD[i].Block = - (DeviceInfo.wTotalBlocks / totalUsedBanks) * i; - - for (j = 0; j <= MAX_CHANS; j++) - PendingCMD[i].ChanSync[j] = 0; - } - - CDMA_Execute_CMDs(tag_count); - -#ifdef VERBOSE - print_pending_cmds(tag_count); -#endif -#if DEBUG_SYNC - } - debug_sync_cnt++; -#endif - - for (i = MAX_CHANS; - i < tag_count + MAX_CHANS; i++) { - CMD = PendingCMD[i].CMD; - data = PendingCMD[i].DataAddr; - block = PendingCMD[i].Block; - page = PendingCMD[i].Page; - count = PendingCMD[i].PageCount; - - switch (CMD) { - case ERASE_CMD: - mtd_Erase_Block(block); - PendingCMD[i].Status = PASS; - break; - case WRITE_MAIN_CMD: - mtd_Write_Page_Main(data, block, page, count); - PendingCMD[i].Status = PASS; - break; - case WRITE_MAIN_SPARE_CMD: - mtd_Write_Page_Main_Spare(data, block, page, count); - PendingCMD[i].Status = PASS; - break; - case READ_MAIN_CMD: - mtd_Read_Page_Main(data, block, page, count); - PendingCMD[i].Status = PASS; - break; - case MEMCOPY_CMD: - memcpy(PendingCMD[i].DataDestAddr, - PendingCMD[i].DataSrcAddr, - PendingCMD[i].MemCopyByteCnt); - case DUMMY_CMD: - PendingCMD[i].Status = PASS; - break; - default: - PendingCMD[i].Status = FAIL; - break; - } - } - - /* - * Temperory adding code to reset PendingCMD array for basic testing. - * It should be done at the end of event status function. - */ - for (i = tag_count + MAX_CHANS; i < MAX_DESCS; i++) { - PendingCMD[i].CMD = 0; - PendingCMD[i].Tag = 0; - PendingCMD[i].DataAddr = 0; - PendingCMD[i].Block = 0; - PendingCMD[i].Page = 0; - PendingCMD[i].PageCount = 0; - PendingCMD[i].DataDestAddr = 0; - PendingCMD[i].DataSrcAddr = 0; - PendingCMD[i].MemCopyByteCnt = 0; - PendingCMD[i].ChanSync[0] = 0; - PendingCMD[i].ChanSync[1] = 0; - PendingCMD[i].ChanSync[2] = 0; - PendingCMD[i].ChanSync[3] = 0; - PendingCMD[i].ChanSync[4] = 0; - PendingCMD[i].Status = CMD_NOT_DONE; - } - - nand_dbg_print(NAND_DBG_TRACE, "At end of Execute CMDs.\n"); - - mtd_isr(0, 0); /* This is a null isr now. Need fill it in future */ - - return status; -} - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: mtd_Event_Status -* Inputs: none -* Outputs: Event_Status code -* Description: This function can also be used to force errors -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -u16 mtd_CDMA_Event_Status(void) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - return EVENT_PASS; -} - -#endif /* CMD_DMA */ -#endif /* !ELDORA */ diff --git a/drivers/staging/spectra/lld_mtd.h b/drivers/staging/spectra/lld_mtd.h deleted file mode 100644 index 4e81ee87b53..00000000000 --- a/drivers/staging/spectra/lld_mtd.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#ifndef _LLD_MTD_ -#define _LLD_MTD_ - -#include "ffsport.h" -#include "ffsdefs.h" - -/* prototypes: MTD API functions */ -extern u16 mtd_Flash_Reset(void); -extern u16 mtd_Flash_Init(void); -extern int mtd_Flash_Release(void); -extern u16 mtd_Read_Device_ID(void); -extern u16 mtd_Erase_Block(u32 block_addr); -extern u16 mtd_Write_Page_Main(u8 *write_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 mtd_Read_Page_Main(u8 *read_data, u32 Block, u16 Page, - u16 PageCount); -extern u16 mtd_Event_Status(void); -extern void mtd_Enable_Disable_Interrupts(u16 INT_ENABLE); -extern u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 mtd_Write_Page_Spare(u8 *write_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block, - u16 Page, u16 PageCount); -extern u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block, u16 Page, - u16 PageCount); -extern u16 mtd_Get_Bad_Block(u32 block); - -u16 mtd_CDMA_Flash_Init(void); -u16 mtd_CDMA_Execute_CMDs(u16 tag_count); -u16 mtd_CDMA_Event_Status(void); -#endif /*_LLD_MTD_*/ diff --git a/drivers/staging/spectra/lld_nand.c b/drivers/staging/spectra/lld_nand.c deleted file mode 100644 index 60a14ff26c7..00000000000 --- a/drivers/staging/spectra/lld_nand.c +++ /dev/null @@ -1,2619 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#include "lld.h" -#include "lld_nand.h" -#include "lld_cdma.h" - -#include "spectraswconfig.h" -#include "flash.h" -#include "ffsdefs.h" - -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <linux/mutex.h> - -#include "nand_regs.h" - -#define SPECTRA_NAND_NAME "nd" - -#define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) -#define MAX_PAGES_PER_RW 128 - -#define INT_IDLE_STATE 0 -#define INT_READ_PAGE_MAIN 0x01 -#define INT_WRITE_PAGE_MAIN 0x02 -#define INT_PIPELINE_READ_AHEAD 0x04 -#define INT_PIPELINE_WRITE_AHEAD 0x08 -#define INT_MULTI_PLANE_READ 0x10 -#define INT_MULTI_PLANE_WRITE 0x11 - -static u32 enable_ecc; - -struct mrst_nand_info info; - -int totalUsedBanks; -u32 GLOB_valid_banks[LLD_MAX_FLASH_BANKS]; - -void __iomem *FlashReg; -void __iomem *FlashMem; - -u16 conf_parameters[] = { - 0x0000, - 0x0000, - 0x01F4, - 0x01F4, - 0x01F4, - 0x01F4, - 0x0000, - 0x0000, - 0x0001, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0040, - 0x0001, - 0x000A, - 0x000A, - 0x000A, - 0x0000, - 0x0000, - 0x0005, - 0x0012, - 0x000C -}; - -u16 NAND_Get_Bad_Block(u32 block) -{ - u32 status = PASS; - u32 flag_bytes = 0; - u32 skip_bytes = DeviceInfo.wSpareSkipBytes; - u32 page, i; - u8 *pReadSpareBuf = buf_get_bad_block; - - if (enable_ecc) - flag_bytes = DeviceInfo.wNumPageSpareFlag; - - for (page = 0; page < 2; page++) { - status = NAND_Read_Page_Spare(pReadSpareBuf, block, page, 1); - if (status != PASS) - return READ_ERROR; - for (i = flag_bytes; i < (flag_bytes + skip_bytes); i++) - if (pReadSpareBuf[i] != 0xff) - return DEFECTIVE_BLOCK; - } - - for (page = 1; page < 3; page++) { - status = NAND_Read_Page_Spare(pReadSpareBuf, block, - DeviceInfo.wPagesPerBlock - page , 1); - if (status != PASS) - return READ_ERROR; - for (i = flag_bytes; i < (flag_bytes + skip_bytes); i++) - if (pReadSpareBuf[i] != 0xff) - return DEFECTIVE_BLOCK; - } - - return GOOD_BLOCK; -} - - -u16 NAND_Flash_Reset(void) -{ - u32 i; - u32 intr_status_rst_comp[4] = {INTR_STATUS0__RST_COMP, - INTR_STATUS1__RST_COMP, - INTR_STATUS2__RST_COMP, - INTR_STATUS3__RST_COMP}; - u32 intr_status_time_out[4] = {INTR_STATUS0__TIME_OUT, - INTR_STATUS1__TIME_OUT, - INTR_STATUS2__TIME_OUT, - INTR_STATUS3__TIME_OUT}; - u32 intr_status[4] = {INTR_STATUS0, INTR_STATUS1, - INTR_STATUS2, INTR_STATUS3}; - u32 device_reset_banks[4] = {DEVICE_RESET__BANK0, - DEVICE_RESET__BANK1, - DEVICE_RESET__BANK2, - DEVICE_RESET__BANK3}; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - for (i = 0 ; i < LLD_MAX_FLASH_BANKS; i++) - iowrite32(intr_status_rst_comp[i] | intr_status_time_out[i], - FlashReg + intr_status[i]); - - for (i = 0 ; i < LLD_MAX_FLASH_BANKS; i++) { - iowrite32(device_reset_banks[i], FlashReg + DEVICE_RESET); - while (!(ioread32(FlashReg + intr_status[i]) & - (intr_status_rst_comp[i] | intr_status_time_out[i]))) - ; - if (ioread32(FlashReg + intr_status[i]) & - intr_status_time_out[i]) - nand_dbg_print(NAND_DBG_WARN, - "NAND Reset operation timed out on bank %d\n", i); - } - - for (i = 0; i < LLD_MAX_FLASH_BANKS; i++) - iowrite32(intr_status_rst_comp[i] | intr_status_time_out[i], - FlashReg + intr_status[i]); - - return PASS; -} - -static void NAND_ONFi_Timing_Mode(u16 mode) -{ - u16 Trea[6] = {40, 30, 25, 20, 20, 16}; - u16 Trp[6] = {50, 25, 17, 15, 12, 10}; - u16 Treh[6] = {30, 15, 15, 10, 10, 7}; - u16 Trc[6] = {100, 50, 35, 30, 25, 20}; - u16 Trhoh[6] = {0, 15, 15, 15, 15, 15}; - u16 Trloh[6] = {0, 0, 0, 0, 5, 5}; - u16 Tcea[6] = {100, 45, 30, 25, 25, 25}; - u16 Tadl[6] = {200, 100, 100, 100, 70, 70}; - u16 Trhw[6] = {200, 100, 100, 100, 100, 100}; - u16 Trhz[6] = {200, 100, 100, 100, 100, 100}; - u16 Twhr[6] = {120, 80, 80, 60, 60, 60}; - u16 Tcs[6] = {70, 35, 25, 25, 20, 15}; - - u16 TclsRising = 1; - u16 data_invalid_rhoh, data_invalid_rloh, data_invalid; - u16 dv_window = 0; - u16 en_lo, en_hi; - u16 acc_clks; - u16 addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - en_lo = CEIL_DIV(Trp[mode], CLK_X); - en_hi = CEIL_DIV(Treh[mode], CLK_X); - -#if ONFI_BLOOM_TIME - if ((en_hi * CLK_X) < (Treh[mode] + 2)) - en_hi++; -#endif - - if ((en_lo + en_hi) * CLK_X < Trc[mode]) - en_lo += CEIL_DIV((Trc[mode] - (en_lo + en_hi) * CLK_X), CLK_X); - - if ((en_lo + en_hi) < CLK_MULTI) - en_lo += CLK_MULTI - en_lo - en_hi; - - while (dv_window < 8) { - data_invalid_rhoh = en_lo * CLK_X + Trhoh[mode]; - - data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; - - data_invalid = - data_invalid_rhoh < - data_invalid_rloh ? data_invalid_rhoh : data_invalid_rloh; - - dv_window = data_invalid - Trea[mode]; - - if (dv_window < 8) - en_lo++; - } - - acc_clks = CEIL_DIV(Trea[mode], CLK_X); - - while (((acc_clks * CLK_X) - Trea[mode]) < 3) - acc_clks++; - - if ((data_invalid - acc_clks * CLK_X) < 2) - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); - - addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); - re_2_we = CEIL_DIV(Trhw[mode], CLK_X); - re_2_re = CEIL_DIV(Trhz[mode], CLK_X); - we_2_re = CEIL_DIV(Twhr[mode], CLK_X); - cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); - if (!TclsRising) - cs_cnt = CEIL_DIV(Tcs[mode], CLK_X); - if (cs_cnt == 0) - cs_cnt = 1; - - if (Tcea[mode]) { - while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode]) - cs_cnt++; - } - -#if MODE5_WORKAROUND - if (mode == 5) - acc_clks = 5; -#endif - - /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if ((ioread32(FlashReg + MANUFACTURER_ID) == 0) && - (ioread32(FlashReg + DEVICE_ID) == 0x88)) - acc_clks = 6; - - iowrite32(acc_clks, FlashReg + ACC_CLKS); - iowrite32(re_2_we, FlashReg + RE_2_WE); - iowrite32(re_2_re, FlashReg + RE_2_RE); - iowrite32(we_2_re, FlashReg + WE_2_RE); - iowrite32(addr_2_data, FlashReg + ADDR_2_DATA); - iowrite32(en_lo, FlashReg + RDWR_EN_LO_CNT); - iowrite32(en_hi, FlashReg + RDWR_EN_HI_CNT); - iowrite32(cs_cnt, FlashReg + CS_SETUP_CNT); -} - -static void index_addr(u32 address, u32 data) -{ - iowrite32(address, FlashMem); - iowrite32(data, FlashMem + 0x10); -} - -static void index_addr_read_data(u32 address, u32 *pdata) -{ - iowrite32(address, FlashMem); - *pdata = ioread32(FlashMem + 0x10); -} - -static void set_ecc_config(void) -{ -#if SUPPORT_8BITECC - if ((ioread32(FlashReg + DEVICE_MAIN_AREA_SIZE) < 4096) || - (ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE) <= 128)) - iowrite32(8, FlashReg + ECC_CORRECTION); -#endif - - if ((ioread32(FlashReg + ECC_CORRECTION) & ECC_CORRECTION__VALUE) - == 1) { - DeviceInfo.wECCBytesPerSector = 4; - DeviceInfo.wECCBytesPerSector *= DeviceInfo.wDevicesConnected; - DeviceInfo.wNumPageSpareFlag = - DeviceInfo.wPageSpareSize - - DeviceInfo.wPageDataSize / - (ECC_SECTOR_SIZE * DeviceInfo.wDevicesConnected) * - DeviceInfo.wECCBytesPerSector - - DeviceInfo.wSpareSkipBytes; - } else { - DeviceInfo.wECCBytesPerSector = - (ioread32(FlashReg + ECC_CORRECTION) & - ECC_CORRECTION__VALUE) * 13 / 8; - if ((DeviceInfo.wECCBytesPerSector) % 2 == 0) - DeviceInfo.wECCBytesPerSector += 2; - else - DeviceInfo.wECCBytesPerSector += 1; - - DeviceInfo.wECCBytesPerSector *= DeviceInfo.wDevicesConnected; - DeviceInfo.wNumPageSpareFlag = DeviceInfo.wPageSpareSize - - DeviceInfo.wPageDataSize / - (ECC_SECTOR_SIZE * DeviceInfo.wDevicesConnected) * - DeviceInfo.wECCBytesPerSector - - DeviceInfo.wSpareSkipBytes; - } -} - -static u16 get_onfi_nand_para(void) -{ - int i; - u16 blks_lun_l, blks_lun_h, n_of_luns; - u32 blockperlun, id; - - iowrite32(DEVICE_RESET__BANK0, FlashReg + DEVICE_RESET); - - while (!((ioread32(FlashReg + INTR_STATUS0) & - INTR_STATUS0__RST_COMP) | - (ioread32(FlashReg + INTR_STATUS0) & - INTR_STATUS0__TIME_OUT))) - ; - - if (ioread32(FlashReg + INTR_STATUS0) & INTR_STATUS0__RST_COMP) { - iowrite32(DEVICE_RESET__BANK1, FlashReg + DEVICE_RESET); - while (!((ioread32(FlashReg + INTR_STATUS1) & - INTR_STATUS1__RST_COMP) | - (ioread32(FlashReg + INTR_STATUS1) & - INTR_STATUS1__TIME_OUT))) - ; - - if (ioread32(FlashReg + INTR_STATUS1) & - INTR_STATUS1__RST_COMP) { - iowrite32(DEVICE_RESET__BANK2, - FlashReg + DEVICE_RESET); - while (!((ioread32(FlashReg + INTR_STATUS2) & - INTR_STATUS2__RST_COMP) | - (ioread32(FlashReg + INTR_STATUS2) & - INTR_STATUS2__TIME_OUT))) - ; - - if (ioread32(FlashReg + INTR_STATUS2) & - INTR_STATUS2__RST_COMP) { - iowrite32(DEVICE_RESET__BANK3, - FlashReg + DEVICE_RESET); - while (!((ioread32(FlashReg + INTR_STATUS3) & - INTR_STATUS3__RST_COMP) | - (ioread32(FlashReg + INTR_STATUS3) & - INTR_STATUS3__TIME_OUT))) - ; - } else { - printk(KERN_ERR "Getting a time out for bank 2!\n"); - } - } else { - printk(KERN_ERR "Getting a time out for bank 1!\n"); - } - } - - iowrite32(INTR_STATUS0__TIME_OUT, FlashReg + INTR_STATUS0); - iowrite32(INTR_STATUS1__TIME_OUT, FlashReg + INTR_STATUS1); - iowrite32(INTR_STATUS2__TIME_OUT, FlashReg + INTR_STATUS2); - iowrite32(INTR_STATUS3__TIME_OUT, FlashReg + INTR_STATUS3); - - DeviceInfo.wONFIDevFeatures = - ioread32(FlashReg + ONFI_DEVICE_FEATURES); - DeviceInfo.wONFIOptCommands = - ioread32(FlashReg + ONFI_OPTIONAL_COMMANDS); - DeviceInfo.wONFITimingMode = - ioread32(FlashReg + ONFI_TIMING_MODE); - DeviceInfo.wONFIPgmCacheTimingMode = - ioread32(FlashReg + ONFI_PGM_CACHE_TIMING_MODE); - - n_of_luns = ioread32(FlashReg + ONFI_DEVICE_NO_OF_LUNS) & - ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS; - blks_lun_l = ioread32(FlashReg + ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L); - blks_lun_h = ioread32(FlashReg + ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U); - - blockperlun = (blks_lun_h << 16) | blks_lun_l; - - DeviceInfo.wTotalBlocks = n_of_luns * blockperlun; - - if (!(ioread32(FlashReg + ONFI_TIMING_MODE) & - ONFI_TIMING_MODE__VALUE)) - return FAIL; - - for (i = 5; i > 0; i--) { - if (ioread32(FlashReg + ONFI_TIMING_MODE) & (0x01 << i)) - break; - } - - NAND_ONFi_Timing_Mode(i); - - index_addr(MODE_11 | 0, 0x90); - index_addr(MODE_11 | 1, 0); - - for (i = 0; i < 3; i++) - index_addr_read_data(MODE_11 | 2, &id); - - nand_dbg_print(NAND_DBG_DEBUG, "3rd ID: 0x%x\n", id); - - DeviceInfo.MLCDevice = id & 0x0C; - - /* By now, all the ONFI devices we know support the page cache */ - /* rw feature. So here we enable the pipeline_rw_ahead feature */ - /* iowrite32(1, FlashReg + CACHE_WRITE_ENABLE); */ - /* iowrite32(1, FlashReg + CACHE_READ_ENABLE); */ - - return PASS; -} - -static void get_samsung_nand_para(void) -{ - u8 no_of_planes; - u32 blk_size; - u64 plane_size, capacity; - u32 id_bytes[5]; - int i; - - index_addr((u32)(MODE_11 | 0), 0x90); - index_addr((u32)(MODE_11 | 1), 0); - for (i = 0; i < 5; i++) - index_addr_read_data((u32)(MODE_11 | 2), &id_bytes[i]); - - nand_dbg_print(NAND_DBG_DEBUG, - "ID bytes: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", - id_bytes[0], id_bytes[1], id_bytes[2], - id_bytes[3], id_bytes[4]); - - if ((id_bytes[1] & 0xff) == 0xd3) { /* Samsung K9WAG08U1A */ - /* Set timing register values according to datasheet */ - iowrite32(5, FlashReg + ACC_CLKS); - iowrite32(20, FlashReg + RE_2_WE); - iowrite32(12, FlashReg + WE_2_RE); - iowrite32(14, FlashReg + ADDR_2_DATA); - iowrite32(3, FlashReg + RDWR_EN_LO_CNT); - iowrite32(2, FlashReg + RDWR_EN_HI_CNT); - iowrite32(2, FlashReg + CS_SETUP_CNT); - } - - no_of_planes = 1 << ((id_bytes[4] & 0x0c) >> 2); - plane_size = (u64)64 << ((id_bytes[4] & 0x70) >> 4); - blk_size = 64 << ((ioread32(FlashReg + DEVICE_PARAM_1) & 0x30) >> 4); - capacity = (u64)128 * plane_size * no_of_planes; - - DeviceInfo.wTotalBlocks = (u32)GLOB_u64_Div(capacity, blk_size); -} - -static void get_toshiba_nand_para(void) -{ - void __iomem *scratch_reg; - u32 tmp; - - /* Workaround to fix a controller bug which reports a wrong */ - /* spare area size for some kind of Toshiba NAND device */ - if ((ioread32(FlashReg + DEVICE_MAIN_AREA_SIZE) == 4096) && - (ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE) == 64)) { - iowrite32(216, FlashReg + DEVICE_SPARE_AREA_SIZE); - tmp = ioread32(FlashReg + DEVICES_CONNECTED) * - ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE); - iowrite32(tmp, FlashReg + LOGICAL_PAGE_SPARE_SIZE); -#if SUPPORT_15BITECC - iowrite32(15, FlashReg + ECC_CORRECTION); -#elif SUPPORT_8BITECC - iowrite32(8, FlashReg + ECC_CORRECTION); -#endif - } - - /* As Toshiba NAND can not provide it's block number, */ - /* so here we need user to provide the correct block */ - /* number in a scratch register before the Linux NAND */ - /* driver is loaded. If no valid value found in the scratch */ - /* register, then we use default block number value */ - scratch_reg = ioremap_nocache(SCRATCH_REG_ADDR, SCRATCH_REG_SIZE); - if (!scratch_reg) { - printk(KERN_ERR "Spectra: ioremap failed in %s, Line %d", - __FILE__, __LINE__); - DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - } else { - nand_dbg_print(NAND_DBG_WARN, - "Spectra: ioremap reg address: 0x%p\n", scratch_reg); - DeviceInfo.wTotalBlocks = 1 << ioread8(scratch_reg); - if (DeviceInfo.wTotalBlocks < 512) - DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - iounmap(scratch_reg); - } -} - -static void get_hynix_nand_para(void) -{ - void __iomem *scratch_reg; - u32 main_size, spare_size; - - switch (DeviceInfo.wDeviceID) { - case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */ - case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */ - iowrite32(128, FlashReg + PAGES_PER_BLOCK); - iowrite32(4096, FlashReg + DEVICE_MAIN_AREA_SIZE); - iowrite32(224, FlashReg + DEVICE_SPARE_AREA_SIZE); - main_size = 4096 * ioread32(FlashReg + DEVICES_CONNECTED); - spare_size = 224 * ioread32(FlashReg + DEVICES_CONNECTED); - iowrite32(main_size, FlashReg + LOGICAL_PAGE_DATA_SIZE); - iowrite32(spare_size, FlashReg + LOGICAL_PAGE_SPARE_SIZE); - iowrite32(0, FlashReg + DEVICE_WIDTH); -#if SUPPORT_15BITECC - iowrite32(15, FlashReg + ECC_CORRECTION); -#elif SUPPORT_8BITECC - iowrite32(8, FlashReg + ECC_CORRECTION); -#endif - DeviceInfo.MLCDevice = 1; - break; - default: - nand_dbg_print(NAND_DBG_WARN, - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." - "Will use default parameter values instead.\n", - DeviceInfo.wDeviceID); - } - - scratch_reg = ioremap_nocache(SCRATCH_REG_ADDR, SCRATCH_REG_SIZE); - if (!scratch_reg) { - printk(KERN_ERR "Spectra: ioremap failed in %s, Line %d", - __FILE__, __LINE__); - DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - } else { - nand_dbg_print(NAND_DBG_WARN, - "Spectra: ioremap reg address: 0x%p\n", scratch_reg); - DeviceInfo.wTotalBlocks = 1 << ioread8(scratch_reg); - if (DeviceInfo.wTotalBlocks < 512) - DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - iounmap(scratch_reg); - } -} - -static void find_valid_banks(void) -{ - u32 id[LLD_MAX_FLASH_BANKS]; - int i; - - totalUsedBanks = 0; - for (i = 0; i < LLD_MAX_FLASH_BANKS; i++) { - index_addr((u32)(MODE_11 | (i << 24) | 0), 0x90); - index_addr((u32)(MODE_11 | (i << 24) | 1), 0); - index_addr_read_data((u32)(MODE_11 | (i << 24) | 2), &id[i]); - - nand_dbg_print(NAND_DBG_DEBUG, - "Return 1st ID for bank[%d]: %x\n", i, id[i]); - - if (i == 0) { - if (id[i] & 0x0ff) - GLOB_valid_banks[i] = 1; - } else { - if ((id[i] & 0x0ff) == (id[0] & 0x0ff)) - GLOB_valid_banks[i] = 1; - } - - totalUsedBanks += GLOB_valid_banks[i]; - } - - nand_dbg_print(NAND_DBG_DEBUG, - "totalUsedBanks: %d\n", totalUsedBanks); -} - -static void detect_partition_feature(void) -{ - if (ioread32(FlashReg + FEATURES) & FEATURES__PARTITION) { - if ((ioread32(FlashReg + PERM_SRC_ID_1) & - PERM_SRC_ID_1__SRCID) == SPECTRA_PARTITION_ID) { - DeviceInfo.wSpectraStartBlock = - ((ioread32(FlashReg + MIN_MAX_BANK_1) & - MIN_MAX_BANK_1__MIN_VALUE) * - DeviceInfo.wTotalBlocks) - + - (ioread32(FlashReg + MIN_BLK_ADDR_1) & - MIN_BLK_ADDR_1__VALUE); - - DeviceInfo.wSpectraEndBlock = - (((ioread32(FlashReg + MIN_MAX_BANK_1) & - MIN_MAX_BANK_1__MAX_VALUE) >> 2) * - DeviceInfo.wTotalBlocks) - + - (ioread32(FlashReg + MAX_BLK_ADDR_1) & - MAX_BLK_ADDR_1__VALUE); - - DeviceInfo.wTotalBlocks *= totalUsedBanks; - - if (DeviceInfo.wSpectraEndBlock >= - DeviceInfo.wTotalBlocks) { - DeviceInfo.wSpectraEndBlock = - DeviceInfo.wTotalBlocks - 1; - } - - DeviceInfo.wDataBlockNum = - DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock + 1; - } else { - DeviceInfo.wTotalBlocks *= totalUsedBanks; - DeviceInfo.wSpectraStartBlock = SPECTRA_START_BLOCK; - DeviceInfo.wSpectraEndBlock = - DeviceInfo.wTotalBlocks - 1; - DeviceInfo.wDataBlockNum = - DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock + 1; - } - } else { - DeviceInfo.wTotalBlocks *= totalUsedBanks; - DeviceInfo.wSpectraStartBlock = SPECTRA_START_BLOCK; - DeviceInfo.wSpectraEndBlock = DeviceInfo.wTotalBlocks - 1; - DeviceInfo.wDataBlockNum = - DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock + 1; - } -} - -static void dump_device_info(void) -{ - nand_dbg_print(NAND_DBG_DEBUG, "DeviceInfo:\n"); - nand_dbg_print(NAND_DBG_DEBUG, "DeviceMaker: 0x%x\n", - DeviceInfo.wDeviceMaker); - nand_dbg_print(NAND_DBG_DEBUG, "DeviceID: 0x%x\n", - DeviceInfo.wDeviceID); - nand_dbg_print(NAND_DBG_DEBUG, "DeviceType: 0x%x\n", - DeviceInfo.wDeviceType); - nand_dbg_print(NAND_DBG_DEBUG, "SpectraStartBlock: %d\n", - DeviceInfo.wSpectraStartBlock); - nand_dbg_print(NAND_DBG_DEBUG, "SpectraEndBlock: %d\n", - DeviceInfo.wSpectraEndBlock); - nand_dbg_print(NAND_DBG_DEBUG, "TotalBlocks: %d\n", - DeviceInfo.wTotalBlocks); - nand_dbg_print(NAND_DBG_DEBUG, "PagesPerBlock: %d\n", - DeviceInfo.wPagesPerBlock); - nand_dbg_print(NAND_DBG_DEBUG, "PageSize: %d\n", - DeviceInfo.wPageSize); - nand_dbg_print(NAND_DBG_DEBUG, "PageDataSize: %d\n", - DeviceInfo.wPageDataSize); - nand_dbg_print(NAND_DBG_DEBUG, "PageSpareSize: %d\n", - DeviceInfo.wPageSpareSize); - nand_dbg_print(NAND_DBG_DEBUG, "NumPageSpareFlag: %d\n", - DeviceInfo.wNumPageSpareFlag); - nand_dbg_print(NAND_DBG_DEBUG, "ECCBytesPerSector: %d\n", - DeviceInfo.wECCBytesPerSector); - nand_dbg_print(NAND_DBG_DEBUG, "BlockSize: %d\n", - DeviceInfo.wBlockSize); - nand_dbg_print(NAND_DBG_DEBUG, "BlockDataSize: %d\n", - DeviceInfo.wBlockDataSize); - nand_dbg_print(NAND_DBG_DEBUG, "DataBlockNum: %d\n", - DeviceInfo.wDataBlockNum); - nand_dbg_print(NAND_DBG_DEBUG, "PlaneNum: %d\n", - DeviceInfo.bPlaneNum); - nand_dbg_print(NAND_DBG_DEBUG, "DeviceMainAreaSize: %d\n", - DeviceInfo.wDeviceMainAreaSize); - nand_dbg_print(NAND_DBG_DEBUG, "DeviceSpareAreaSize: %d\n", - DeviceInfo.wDeviceSpareAreaSize); - nand_dbg_print(NAND_DBG_DEBUG, "DevicesConnected: %d\n", - DeviceInfo.wDevicesConnected); - nand_dbg_print(NAND_DBG_DEBUG, "DeviceWidth: %d\n", - DeviceInfo.wDeviceWidth); - nand_dbg_print(NAND_DBG_DEBUG, "HWRevision: 0x%x\n", - DeviceInfo.wHWRevision); - nand_dbg_print(NAND_DBG_DEBUG, "HWFeatures: 0x%x\n", - DeviceInfo.wHWFeatures); - nand_dbg_print(NAND_DBG_DEBUG, "ONFIDevFeatures: 0x%x\n", - DeviceInfo.wONFIDevFeatures); - nand_dbg_print(NAND_DBG_DEBUG, "ONFIOptCommands: 0x%x\n", - DeviceInfo.wONFIOptCommands); - nand_dbg_print(NAND_DBG_DEBUG, "ONFITimingMode: 0x%x\n", - DeviceInfo.wONFITimingMode); - nand_dbg_print(NAND_DBG_DEBUG, "ONFIPgmCacheTimingMode: 0x%x\n", - DeviceInfo.wONFIPgmCacheTimingMode); - nand_dbg_print(NAND_DBG_DEBUG, "MLCDevice: %s\n", - DeviceInfo.MLCDevice ? "Yes" : "No"); - nand_dbg_print(NAND_DBG_DEBUG, "SpareSkipBytes: %d\n", - DeviceInfo.wSpareSkipBytes); - nand_dbg_print(NAND_DBG_DEBUG, "BitsInPageNumber: %d\n", - DeviceInfo.nBitsInPageNumber); - nand_dbg_print(NAND_DBG_DEBUG, "BitsInPageDataSize: %d\n", - DeviceInfo.nBitsInPageDataSize); - nand_dbg_print(NAND_DBG_DEBUG, "BitsInBlockDataSize: %d\n", - DeviceInfo.nBitsInBlockDataSize); -} - -u16 NAND_Read_Device_ID(void) -{ - u16 status = PASS; - u8 no_of_planes; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - iowrite32(0x02, FlashReg + SPARE_AREA_SKIP_BYTES); - iowrite32(0xffff, FlashReg + SPARE_AREA_MARKER); - DeviceInfo.wDeviceMaker = ioread32(FlashReg + MANUFACTURER_ID); - DeviceInfo.wDeviceID = ioread32(FlashReg + DEVICE_ID); - DeviceInfo.MLCDevice = ioread32(FlashReg + DEVICE_PARAM_0) & 0x0c; - - if (ioread32(FlashReg + ONFI_DEVICE_NO_OF_LUNS) & - ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */ - if (FAIL == get_onfi_nand_para()) - return FAIL; - } else if (DeviceInfo.wDeviceMaker == 0xEC) { /* Samsung NAND */ - get_samsung_nand_para(); - } else if (DeviceInfo.wDeviceMaker == 0x98) { /* Toshiba NAND */ - get_toshiba_nand_para(); - } else if (DeviceInfo.wDeviceMaker == 0xAD) { /* Hynix NAND */ - get_hynix_nand_para(); - } else { - DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS; - } - - nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:" - "acc_clks: %d, re_2_we: %d, we_2_re: %d," - "addr_2_data: %d, rdwr_en_lo_cnt: %d, " - "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", - ioread32(FlashReg + ACC_CLKS), - ioread32(FlashReg + RE_2_WE), - ioread32(FlashReg + WE_2_RE), - ioread32(FlashReg + ADDR_2_DATA), - ioread32(FlashReg + RDWR_EN_LO_CNT), - ioread32(FlashReg + RDWR_EN_HI_CNT), - ioread32(FlashReg + CS_SETUP_CNT)); - - DeviceInfo.wHWRevision = ioread32(FlashReg + REVISION); - DeviceInfo.wHWFeatures = ioread32(FlashReg + FEATURES); - - DeviceInfo.wDeviceMainAreaSize = - ioread32(FlashReg + DEVICE_MAIN_AREA_SIZE); - DeviceInfo.wDeviceSpareAreaSize = - ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE); - - DeviceInfo.wPageDataSize = - ioread32(FlashReg + LOGICAL_PAGE_DATA_SIZE); - - /* Note: When using the Micon 4K NAND device, the controller will report - * Page Spare Size as 216 bytes. But Micron's Spec say it's 218 bytes. - * And if force set it to 218 bytes, the controller can not work - * correctly. So just let it be. But keep in mind that this bug may - * cause - * other problems in future. - Yunpeng 2008-10-10 - */ - DeviceInfo.wPageSpareSize = - ioread32(FlashReg + LOGICAL_PAGE_SPARE_SIZE); - - DeviceInfo.wPagesPerBlock = ioread32(FlashReg + PAGES_PER_BLOCK); - - DeviceInfo.wPageSize = - DeviceInfo.wPageDataSize + DeviceInfo.wPageSpareSize; - DeviceInfo.wBlockSize = - DeviceInfo.wPageSize * DeviceInfo.wPagesPerBlock; - DeviceInfo.wBlockDataSize = - DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize; - - DeviceInfo.wDeviceWidth = ioread32(FlashReg + DEVICE_WIDTH); - DeviceInfo.wDeviceType = - ((ioread32(FlashReg + DEVICE_WIDTH) > 0) ? 16 : 8); - - DeviceInfo.wDevicesConnected = ioread32(FlashReg + DEVICES_CONNECTED); - - DeviceInfo.wSpareSkipBytes = - ioread32(FlashReg + SPARE_AREA_SKIP_BYTES) * - DeviceInfo.wDevicesConnected; - - DeviceInfo.nBitsInPageNumber = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock); - DeviceInfo.nBitsInPageDataSize = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize); - DeviceInfo.nBitsInBlockDataSize = - (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize); - - set_ecc_config(); - - no_of_planes = ioread32(FlashReg + NUMBER_OF_PLANES) & - NUMBER_OF_PLANES__VALUE; - - switch (no_of_planes) { - case 0: - case 1: - case 3: - case 7: - DeviceInfo.bPlaneNum = no_of_planes + 1; - break; - default: - status = FAIL; - break; - } - - find_valid_banks(); - - detect_partition_feature(); - - dump_device_info(); - - return status; -} - -u16 NAND_UnlockArrayAll(void) -{ - u64 start_addr, end_addr; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - start_addr = 0; - end_addr = ((u64)DeviceInfo.wBlockSize * - (DeviceInfo.wTotalBlocks - 1)) >> - DeviceInfo.nBitsInPageDataSize; - - index_addr((u32)(MODE_10 | (u32)start_addr), 0x10); - index_addr((u32)(MODE_10 | (u32)end_addr), 0x11); - - return PASS; -} - -void NAND_LLD_Enable_Disable_Interrupts(u16 INT_ENABLE) -{ - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (INT_ENABLE) - iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); - else - iowrite32(0, FlashReg + GLOBAL_INT_ENABLE); -} - -u16 NAND_Erase_Block(u32 block) -{ - u16 status = PASS; - u64 flash_add; - u16 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - if (block >= DeviceInfo.wTotalBlocks) - status = FAIL; - - if (status == PASS) { - intr_status = intr_status_addresses[flash_bank]; - - iowrite32(INTR_STATUS0__ERASE_COMP | INTR_STATUS0__ERASE_FAIL, - FlashReg + intr_status); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 1); - - while (!(ioread32(FlashReg + intr_status) & - (INTR_STATUS0__ERASE_COMP | INTR_STATUS0__ERASE_FAIL))) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ERASE_FAIL) - status = FAIL; - - iowrite32(INTR_STATUS0__ERASE_COMP | INTR_STATUS0__ERASE_FAIL, - FlashReg + intr_status); - } - - return status; -} - -static u32 Boundary_Check_Block_Page(u32 block, u16 page, - u16 page_count) -{ - u32 status = PASS; - - if (block >= DeviceInfo.wTotalBlocks) - status = FAIL; - - if (page + page_count > DeviceInfo.wPagesPerBlock) - status = FAIL; - - return status; -} - -u16 NAND_Read_Page_Spare(u8 *read_data, u32 block, u16 page, - u16 page_count) -{ - u32 status = PASS; - u32 i; - u64 flash_add; - u32 PageSpareSize = DeviceInfo.wPageSpareSize; - u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag; - u32 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u8 *page_spare = buf_read_page_spare; - - if (block >= DeviceInfo.wTotalBlocks) { - printk(KERN_ERR "block too big: %d\n", (int)block); - status = FAIL; - } - - if (page >= DeviceInfo.wPagesPerBlock) { - printk(KERN_ERR "page too big: %d\n", page); - status = FAIL; - } - - if (page_count > 1) { - printk(KERN_ERR "page count too big: %d\n", page_count); - status = FAIL; - } - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - if (status == PASS) { - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), - 0x41); - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), - 0x2000 | page_count); - while (!(ioread32(FlashReg + intr_status) & - INTR_STATUS0__LOAD_COMP)) - ; - - iowrite32((u32)(MODE_01 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), - FlashMem); - - for (i = 0; i < (PageSpareSize / 4); i++) - *((u32 *)page_spare + i) = - ioread32(FlashMem + 0x10); - - if (enable_ecc) { - for (i = 0; i < spareFlagBytes; i++) - read_data[i] = - page_spare[PageSpareSize - - spareFlagBytes + i]; - for (i = 0; i < (PageSpareSize - spareFlagBytes); i++) - read_data[spareFlagBytes + i] = - page_spare[i]; - } else { - for (i = 0; i < PageSpareSize; i++) - read_data[i] = page_spare[i]; - } - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42); - } - - return status; -} - -/* No use function. Should be removed later */ -u16 NAND_Write_Page_Spare(u8 *write_data, u32 block, u16 page, - u16 page_count) -{ - printk(KERN_ERR - "Error! This function (NAND_Write_Page_Spare) should never" - " be called!\n"); - return ERR; -} - -/* op value: 0 - DDMA read; 1 - DDMA write */ -static void ddma_trans(u8 *data, u64 flash_add, - u32 flash_bank, int op, u32 numPages) -{ - u32 data_addr; - - /* Map virtual address to bus address for DDMA */ - data_addr = virt_to_bus(data); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), - (u16)(2 << 12) | (op << 8) | numPages); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - ((u16)(0x0FFFF & (data_addr >> 16)) << 8)), - (u16)(2 << 12) | (2 << 8) | 0); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - ((u16)(0x0FFFF & data_addr) << 8)), - (u16)(2 << 12) | (3 << 8) | 0); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (1 << 16) | (0x40 << 8)), - (u16)(2 << 12) | (4 << 8) | 0); -} - -/* If data in buf are all 0xff, then return 1; otherwise return 0 */ -static int check_all_1(u8 *buf) -{ - int i, j, cnt; - - for (i = 0; i < DeviceInfo.wPageDataSize; i++) { - if (buf[i] != 0xff) { - cnt = 0; - nand_dbg_print(NAND_DBG_WARN, - "the first non-0xff data byte is: %d\n", i); - for (j = i; j < DeviceInfo.wPageDataSize; j++) { - nand_dbg_print(NAND_DBG_WARN, "0x%x ", buf[j]); - cnt++; - if (cnt > 8) - break; - } - nand_dbg_print(NAND_DBG_WARN, "\n"); - return 0; - } - } - - return 1; -} - -static int do_ecc_new(unsigned long bank, u8 *buf, - u32 block, u16 page) -{ - int status = PASS; - u16 err_page = 0; - u16 err_byte; - u8 err_sect; - u8 err_dev; - u16 err_fix_info; - u16 err_addr; - u32 ecc_sect_size; - u8 *err_pos; - u32 err_page_addr[4] = {ERR_PAGE_ADDR0, - ERR_PAGE_ADDR1, ERR_PAGE_ADDR2, ERR_PAGE_ADDR3}; - - ecc_sect_size = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected); - - do { - err_page = ioread32(FlashReg + err_page_addr[bank]); - err_addr = ioread32(FlashReg + ECC_ERROR_ADDRESS); - err_byte = err_addr & ECC_ERROR_ADDRESS__OFFSET; - err_sect = ((err_addr & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12); - err_fix_info = ioread32(FlashReg + ERR_CORRECTION_INFO); - err_dev = ((err_fix_info & ERR_CORRECTION_INFO__DEVICE_NR) - >> 8); - if (err_fix_info & ERR_CORRECTION_INFO__ERROR_TYPE) { - nand_dbg_print(NAND_DBG_WARN, - "%s, Line %d Uncorrectable ECC error " - "when read block %d page %d." - "PTN_INTR register: 0x%x " - "err_page: %d, err_sect: %d, err_byte: %d, " - "err_dev: %d, ecc_sect_size: %d, " - "err_fix_info: 0x%x\n", - __FILE__, __LINE__, block, page, - ioread32(FlashReg + PTN_INTR), - err_page, err_sect, err_byte, err_dev, - ecc_sect_size, (u32)err_fix_info); - - if (check_all_1(buf)) - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d" - "All 0xff!\n", - __FILE__, __LINE__); - else - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d" - "Not all 0xff!\n", - __FILE__, __LINE__); - status = FAIL; - } else { - nand_dbg_print(NAND_DBG_WARN, - "%s, Line %d Found ECC error " - "when read block %d page %d." - "err_page: %d, err_sect: %d, err_byte: %d, " - "err_dev: %d, ecc_sect_size: %d, " - "err_fix_info: 0x%x\n", - __FILE__, __LINE__, block, page, - err_page, err_sect, err_byte, err_dev, - ecc_sect_size, (u32)err_fix_info); - if (err_byte < ECC_SECTOR_SIZE) { - err_pos = buf + - (err_page - page) * - DeviceInfo.wPageDataSize + - err_sect * ecc_sect_size + - err_byte * - DeviceInfo.wDevicesConnected + - err_dev; - - *err_pos ^= err_fix_info & - ERR_CORRECTION_INFO__BYTEMASK; - } - } - } while (!(err_fix_info & ERR_CORRECTION_INFO__LAST_ERR_INFO)); - - return status; -} - -u16 NAND_Read_Page_Main_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count) -{ - u32 status = PASS; - u64 flash_add; - u32 intr_status = 0; - u32 flash_bank; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u8 *read_data_l; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - if (status != PASS) - return status; - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - if (page_count > 1) { - read_data_l = read_data; - while (page_count > MAX_PAGES_PER_RW) { - if (ioread32(FlashReg + MULTIPLANE_OPERATION)) - status = NAND_Multiplane_Read(read_data_l, - block, page, MAX_PAGES_PER_RW); - else - status = NAND_Pipeline_Read_Ahead_Polling( - read_data_l, block, page, - MAX_PAGES_PER_RW); - - if (status == FAIL) - return status; - - read_data_l += DeviceInfo.wPageDataSize * - MAX_PAGES_PER_RW; - page_count -= MAX_PAGES_PER_RW; - page += MAX_PAGES_PER_RW; - } - if (ioread32(FlashReg + MULTIPLANE_OPERATION)) - status = NAND_Multiplane_Read(read_data_l, - block, page, page_count); - else - status = NAND_Pipeline_Read_Ahead_Polling( - read_data_l, block, page, page_count); - - return status; - } - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - ddma_trans(read_data, flash_add, flash_bank, 0, 1); - - if (enable_ecc) { - while (!(ioread32(FlashReg + intr_status) & - (INTR_STATUS0__ECC_TRANSACTION_DONE | - INTR_STATUS0__ECC_ERR))) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_ERR) { - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - status = do_ecc_new(flash_bank, read_data, - block, page); - } - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_TRANSACTION_DONE & - INTR_STATUS0__ECC_ERR) - iowrite32(INTR_STATUS0__ECC_TRANSACTION_DONE | - INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_TRANSACTION_DONE) - iowrite32(INTR_STATUS0__ECC_TRANSACTION_DONE, - FlashReg + intr_status); - else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_ERR) - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - } else { - while (!(ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP)) - ; - iowrite32(INTR_STATUS0__DMA_CMD_COMP, FlashReg + intr_status); - } - - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - return status; -} - -u16 NAND_Pipeline_Read_Ahead_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count) -{ - u32 status = PASS; - u32 NumPages = page_count; - u64 flash_add; - u32 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u32 ecc_done_OR_dma_comp; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - - if (page_count < 2) - status = FAIL; - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - *DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - if (status == PASS) { - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42); - ddma_trans(read_data, flash_add, flash_bank, 0, NumPages); - - ecc_done_OR_dma_comp = 0; - while (1) { - if (enable_ecc) { - while (!ioread32(FlashReg + intr_status)) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_ERR) { - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - status = do_ecc_new(flash_bank, - read_data, block, page); - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP) { - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - - if (1 == ecc_done_OR_dma_comp) - break; - - ecc_done_OR_dma_comp = 1; - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_TRANSACTION_DONE) { - iowrite32( - INTR_STATUS0__ECC_TRANSACTION_DONE, - FlashReg + intr_status); - - if (1 == ecc_done_OR_dma_comp) - break; - - ecc_done_OR_dma_comp = 1; - } - } else { - while (!(ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP)) - ; - - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - break; - } - - iowrite32((~INTR_STATUS0__ECC_ERR) & - (~INTR_STATUS0__ECC_TRANSACTION_DONE) & - (~INTR_STATUS0__DMA_CMD_COMP), - FlashReg + intr_status); - - } - - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - } - return status; -} - -u16 NAND_Read_Page_Main(u8 *read_data, u32 block, u16 page, - u16 page_count) -{ - u32 status = PASS; - u64 flash_add; - u32 intr_status = 0; - u32 flash_bank; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - int ret; - u8 *read_data_l; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - if (status != PASS) - return status; - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - if (page_count > 1) { - read_data_l = read_data; - while (page_count > MAX_PAGES_PER_RW) { - if (ioread32(FlashReg + MULTIPLANE_OPERATION)) - status = NAND_Multiplane_Read(read_data_l, - block, page, MAX_PAGES_PER_RW); - else - status = NAND_Pipeline_Read_Ahead( - read_data_l, block, page, - MAX_PAGES_PER_RW); - - if (status == FAIL) - return status; - - read_data_l += DeviceInfo.wPageDataSize * - MAX_PAGES_PER_RW; - page_count -= MAX_PAGES_PER_RW; - page += MAX_PAGES_PER_RW; - } - if (ioread32(FlashReg + MULTIPLANE_OPERATION)) - status = NAND_Multiplane_Read(read_data_l, - block, page, page_count); - else - status = NAND_Pipeline_Read_Ahead( - read_data_l, block, page, page_count); - - return status; - } - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - /* Fill the mrst_nand_info structure */ - info.state = INT_READ_PAGE_MAIN; - info.read_data = read_data; - info.flash_bank = flash_bank; - info.block = block; - info.page = page; - info.ret = PASS; - - ddma_trans(read_data, flash_add, flash_bank, 0, 1); - - iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable Interrupt */ - - ret = wait_for_completion_timeout(&info.complete, 10 * HZ); - if (!ret) { - printk(KERN_ERR "Wait for completion timeout " - "in %s, Line %d\n", __FILE__, __LINE__); - status = ERR; - } else { - status = info.ret; - } - - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - return status; -} - -void Conv_Spare_Data_Log2Phy_Format(u8 *data) -{ - int i; - const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag; - const u32 PageSpareSize = DeviceInfo.wPageSpareSize; - - if (enable_ecc) { - for (i = spareFlagBytes - 1; i >= 0; i--) - data[PageSpareSize - spareFlagBytes + i] = data[i]; - } -} - -void Conv_Spare_Data_Phy2Log_Format(u8 *data) -{ - int i; - const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag; - const u32 PageSpareSize = DeviceInfo.wPageSpareSize; - - if (enable_ecc) { - for (i = 0; i < spareFlagBytes; i++) - data[i] = data[PageSpareSize - spareFlagBytes + i]; - } -} - - -void Conv_Main_Spare_Data_Log2Phy_Format(u8 *data, u16 page_count) -{ - const u32 PageSize = DeviceInfo.wPageSize; - const u32 PageDataSize = DeviceInfo.wPageDataSize; - const u32 eccBytes = DeviceInfo.wECCBytesPerSector; - const u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes; - const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag; - u32 eccSectorSize; - u32 page_offset; - int i, j; - - eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected); - if (enable_ecc) { - while (page_count > 0) { - page_offset = (page_count - 1) * PageSize; - j = (DeviceInfo.wPageDataSize / eccSectorSize); - for (i = spareFlagBytes - 1; i >= 0; i--) - data[page_offset + - (eccSectorSize + eccBytes) * j + i] = - data[page_offset + PageDataSize + i]; - for (j--; j >= 1; j--) { - for (i = eccSectorSize - 1; i >= 0; i--) - data[page_offset + - (eccSectorSize + eccBytes) * j + i] = - data[page_offset + - eccSectorSize * j + i]; - } - for (i = (PageSize - spareSkipBytes) - 1; - i >= PageDataSize; i--) - data[page_offset + i + spareSkipBytes] = - data[page_offset + i]; - page_count--; - } - } -} - -void Conv_Main_Spare_Data_Phy2Log_Format(u8 *data, u16 page_count) -{ - const u32 PageSize = DeviceInfo.wPageSize; - const u32 PageDataSize = DeviceInfo.wPageDataSize; - const u32 eccBytes = DeviceInfo.wECCBytesPerSector; - const u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes; - const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag; - u32 eccSectorSize; - u32 page_offset; - int i, j; - - eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected); - if (enable_ecc) { - while (page_count > 0) { - page_offset = (page_count - 1) * PageSize; - for (i = PageDataSize; - i < PageSize - spareSkipBytes; - i++) - data[page_offset + i] = - data[page_offset + i + - spareSkipBytes]; - for (j = 1; - j < DeviceInfo.wPageDataSize / eccSectorSize; - j++) { - for (i = 0; i < eccSectorSize; i++) - data[page_offset + - eccSectorSize * j + i] = - data[page_offset + - (eccSectorSize + eccBytes) * j - + i]; - } - for (i = 0; i < spareFlagBytes; i++) - data[page_offset + PageDataSize + i] = - data[page_offset + - (eccSectorSize + eccBytes) * j + i]; - page_count--; - } - } -} - -/* Un-tested function */ -u16 NAND_Multiplane_Read(u8 *read_data, u32 block, u16 page, - u16 page_count) -{ - u32 status = PASS; - u32 NumPages = page_count; - u64 flash_add; - u32 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u32 ecc_done_OR_dma_comp; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - if (status == PASS) { - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - iowrite32(0x01, FlashReg + MULTIPLANE_OPERATION); - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42); - ddma_trans(read_data, flash_add, flash_bank, 0, NumPages); - - ecc_done_OR_dma_comp = 0; - while (1) { - if (enable_ecc) { - while (!ioread32(FlashReg + intr_status)) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_ERR) { - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - status = do_ecc_new(flash_bank, - read_data, block, page); - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP) { - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - - if (1 == ecc_done_OR_dma_comp) - break; - - ecc_done_OR_dma_comp = 1; - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_TRANSACTION_DONE) { - iowrite32( - INTR_STATUS0__ECC_TRANSACTION_DONE, - FlashReg + intr_status); - - if (1 == ecc_done_OR_dma_comp) - break; - - ecc_done_OR_dma_comp = 1; - } - } else { - while (!(ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP)) - ; - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - break; - } - - iowrite32((~INTR_STATUS0__ECC_ERR) & - (~INTR_STATUS0__ECC_TRANSACTION_DONE) & - (~INTR_STATUS0__DMA_CMD_COMP), - FlashReg + intr_status); - - } - - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + MULTIPLANE_OPERATION); - } - - return status; -} - -u16 NAND_Pipeline_Read_Ahead(u8 *read_data, u32 block, - u16 page, u16 page_count) -{ - u32 status = PASS; - u32 NumPages = page_count; - u64 flash_add; - u32 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - int ret; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - - if (page_count < 2) - status = FAIL; - - if (status != PASS) - return status; - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - *DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - /* Fill the mrst_nand_info structure */ - info.state = INT_PIPELINE_READ_AHEAD; - info.read_data = read_data; - info.flash_bank = flash_bank; - info.block = block; - info.page = page; - info.ret = PASS; - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42); - - ddma_trans(read_data, flash_add, flash_bank, 0, NumPages); - - iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable Interrupt */ - - ret = wait_for_completion_timeout(&info.complete, 10 * HZ); - if (!ret) { - printk(KERN_ERR "Wait for completion timeout " - "in %s, Line %d\n", __FILE__, __LINE__); - status = ERR; - } else { - status = info.ret; - } - - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - return status; -} - - -u16 NAND_Write_Page_Main(u8 *write_data, u32 block, u16 page, - u16 page_count) -{ - u32 status = PASS; - u64 flash_add; - u32 intr_status = 0; - u32 flash_bank; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - int ret; - u8 *write_data_l; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - if (status != PASS) - return status; - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - intr_status = intr_status_addresses[flash_bank]; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - iowrite32(INTR_STATUS0__PROGRAM_COMP | - INTR_STATUS0__PROGRAM_FAIL, FlashReg + intr_status); - - if (page_count > 1) { - write_data_l = write_data; - while (page_count > MAX_PAGES_PER_RW) { - if (ioread32(FlashReg + MULTIPLANE_OPERATION)) - status = NAND_Multiplane_Write(write_data_l, - block, page, MAX_PAGES_PER_RW); - else - status = NAND_Pipeline_Write_Ahead( - write_data_l, block, page, - MAX_PAGES_PER_RW); - if (status == FAIL) - return status; - - write_data_l += DeviceInfo.wPageDataSize * - MAX_PAGES_PER_RW; - page_count -= MAX_PAGES_PER_RW; - page += MAX_PAGES_PER_RW; - } - if (ioread32(FlashReg + MULTIPLANE_OPERATION)) - status = NAND_Multiplane_Write(write_data_l, - block, page, page_count); - else - status = NAND_Pipeline_Write_Ahead(write_data_l, - block, page, page_count); - - return status; - } - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - /* Fill the mrst_nand_info structure */ - info.state = INT_WRITE_PAGE_MAIN; - info.write_data = write_data; - info.flash_bank = flash_bank; - info.block = block; - info.page = page; - info.ret = PASS; - - ddma_trans(write_data, flash_add, flash_bank, 1, 1); - - iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable interrupt */ - - ret = wait_for_completion_timeout(&info.complete, 10 * HZ); - if (!ret) { - printk(KERN_ERR "Wait for completion timeout " - "in %s, Line %d\n", __FILE__, __LINE__); - status = ERR; - } else { - status = info.ret; - } - - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - while (ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG) - ; - - return status; -} - -void NAND_ECC_Ctrl(int enable) -{ - if (enable) { - nand_dbg_print(NAND_DBG_WARN, - "Will enable ECC in %s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - iowrite32(1, FlashReg + ECC_ENABLE); - enable_ecc = 1; - } else { - nand_dbg_print(NAND_DBG_WARN, - "Will disable ECC in %s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - iowrite32(0, FlashReg + ECC_ENABLE); - enable_ecc = 0; - } -} - -u16 NAND_Write_Page_Main_Spare(u8 *write_data, u32 block, - u16 page, u16 page_count) -{ - u32 status = PASS; - u32 i, j, page_num = 0; - u32 PageSize = DeviceInfo.wPageSize; - u32 PageDataSize = DeviceInfo.wPageDataSize; - u32 eccBytes = DeviceInfo.wECCBytesPerSector; - u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag; - u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes; - u64 flash_add; - u32 eccSectorSize; - u32 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u8 *page_main_spare = buf_write_page_main_spare; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected); - - status = Boundary_Check_Block_Page(block, page, page_count); - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - if (status == PASS) { - intr_status = intr_status_addresses[flash_bank]; - - iowrite32(1, FlashReg + TRANSFER_SPARE_REG); - - while ((status != FAIL) && (page_count > 0)) { - flash_add = (u64)(block % - (DeviceInfo.wTotalBlocks / totalUsedBanks)) * - DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - iowrite32((u32)(MODE_01 | (flash_bank << 24) | - (flash_add >> - DeviceInfo.nBitsInPageDataSize)), - FlashMem); - - if (enable_ecc) { - for (j = 0; - j < - DeviceInfo.wPageDataSize / eccSectorSize; - j++) { - for (i = 0; i < eccSectorSize; i++) - page_main_spare[(eccSectorSize + - eccBytes) * j + - i] = - write_data[eccSectorSize * - j + i]; - - for (i = 0; i < eccBytes; i++) - page_main_spare[(eccSectorSize + - eccBytes) * j + - eccSectorSize + - i] = - write_data[PageDataSize + - spareFlagBytes + - eccBytes * j + - i]; - } - - for (i = 0; i < spareFlagBytes; i++) - page_main_spare[(eccSectorSize + - eccBytes) * j + i] = - write_data[PageDataSize + i]; - - for (i = PageSize - 1; i >= PageDataSize + - spareSkipBytes; i--) - page_main_spare[i] = page_main_spare[i - - spareSkipBytes]; - - for (i = PageDataSize; i < PageDataSize + - spareSkipBytes; i++) - page_main_spare[i] = 0xff; - - for (i = 0; i < PageSize / 4; i++) - iowrite32( - *((u32 *)page_main_spare + i), - FlashMem + 0x10); - } else { - - for (i = 0; i < PageSize / 4; i++) - iowrite32(*((u32 *)write_data + i), - FlashMem + 0x10); - } - - while (!(ioread32(FlashReg + intr_status) & - (INTR_STATUS0__PROGRAM_COMP | - INTR_STATUS0__PROGRAM_FAIL))) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__PROGRAM_FAIL) - status = FAIL; - - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - page_num++; - page_count--; - write_data += PageSize; - } - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - } - - return status; -} - -u16 NAND_Read_Page_Main_Spare(u8 *read_data, u32 block, u16 page, - u16 page_count) -{ - u32 status = PASS; - u32 i, j; - u64 flash_add = 0; - u32 PageSize = DeviceInfo.wPageSize; - u32 PageDataSize = DeviceInfo.wPageDataSize; - u32 PageSpareSize = DeviceInfo.wPageSpareSize; - u32 eccBytes = DeviceInfo.wECCBytesPerSector; - u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag; - u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes; - u32 eccSectorSize; - u32 flash_bank; - u32 intr_status = 0; - u8 *read_data_l = read_data; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u8 *page_main_spare = buf_read_page_main_spare; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected); - - status = Boundary_Check_Block_Page(block, page, page_count); - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - if (status == PASS) { - intr_status = intr_status_addresses[flash_bank]; - - iowrite32(1, FlashReg + TRANSFER_SPARE_REG); - - iowrite32(ioread32(FlashReg + intr_status), - FlashReg + intr_status); - - while ((status != FAIL) && (page_count > 0)) { - flash_add = (u64)(block % - (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), - 0x43); - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), - 0x2000 | page_count); - - while (!(ioread32(FlashReg + intr_status) & - INTR_STATUS0__LOAD_COMP)) - ; - - iowrite32((u32)(MODE_01 | (flash_bank << 24) | - (flash_add >> - DeviceInfo.nBitsInPageDataSize)), - FlashMem); - - for (i = 0; i < PageSize / 4; i++) - *(((u32 *)page_main_spare) + i) = - ioread32(FlashMem + 0x10); - - if (enable_ecc) { - for (i = PageDataSize; i < PageSize - - spareSkipBytes; i++) - page_main_spare[i] = page_main_spare[i + - spareSkipBytes]; - - for (j = 0; - j < DeviceInfo.wPageDataSize / eccSectorSize; - j++) { - - for (i = 0; i < eccSectorSize; i++) - read_data_l[eccSectorSize * j + - i] = - page_main_spare[ - (eccSectorSize + - eccBytes) * j + i]; - - for (i = 0; i < eccBytes; i++) - read_data_l[PageDataSize + - spareFlagBytes + - eccBytes * j + i] = - page_main_spare[ - (eccSectorSize + - eccBytes) * j + - eccSectorSize + i]; - } - - for (i = 0; i < spareFlagBytes; i++) - read_data_l[PageDataSize + i] = - page_main_spare[(eccSectorSize + - eccBytes) * j + i]; - } else { - for (i = 0; i < (PageDataSize + PageSpareSize); - i++) - read_data_l[i] = page_main_spare[i]; - - } - - if (enable_ecc) { - while (!(ioread32(FlashReg + intr_status) & - (INTR_STATUS0__ECC_TRANSACTION_DONE | - INTR_STATUS0__ECC_ERR))) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_ERR) { - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - status = do_ecc_new(flash_bank, - read_data, block, page); - } - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_TRANSACTION_DONE & - INTR_STATUS0__ECC_ERR) { - iowrite32(INTR_STATUS0__ECC_ERR | - INTR_STATUS0__ECC_TRANSACTION_DONE, - FlashReg + intr_status); - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_TRANSACTION_DONE) { - iowrite32( - INTR_STATUS0__ECC_TRANSACTION_DONE, - FlashReg + intr_status); - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_ERR) { - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - } - } - - page++; - page_count--; - read_data_l += PageSize; - } - } - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42); - - return status; -} - -u16 NAND_Pipeline_Write_Ahead(u8 *write_data, u32 block, - u16 page, u16 page_count) -{ - u16 status = PASS; - u32 NumPages = page_count; - u64 flash_add; - u32 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - int ret; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - - if (page_count < 2) - status = FAIL; - - if (status != PASS) - return status; - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - /* Fill the mrst_nand_info structure */ - info.state = INT_PIPELINE_WRITE_AHEAD; - info.write_data = write_data; - info.flash_bank = flash_bank; - info.block = block; - info.page = page; - info.ret = PASS; - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42); - - ddma_trans(write_data, flash_add, flash_bank, 1, NumPages); - - iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable interrupt */ - - ret = wait_for_completion_timeout(&info.complete, 10 * HZ); - if (!ret) { - printk(KERN_ERR "Wait for completion timeout " - "in %s, Line %d\n", __FILE__, __LINE__); - status = ERR; - } else { - status = info.ret; - } - - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - return status; -} - -/* Un-tested function */ -u16 NAND_Multiplane_Write(u8 *write_data, u32 block, u16 page, - u16 page_count) -{ - u16 status = PASS; - u32 NumPages = page_count; - u64 flash_add; - u32 flash_bank; - u32 intr_status = 0; - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u16 status2 = PASS; - u32 t; - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - status = Boundary_Check_Block_Page(block, page, page_count); - if (status != PASS) - return status; - - flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks)) - * DeviceInfo.wBlockDataSize + - (u64)page * DeviceInfo.wPageDataSize; - - flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks); - - intr_status = intr_status_addresses[flash_bank]; - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - iowrite32(0x01, FlashReg + MULTIPLANE_OPERATION); - - iowrite32(1, FlashReg + DMA_ENABLE); - while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + TRANSFER_SPARE_REG); - - index_addr((u32)(MODE_10 | (flash_bank << 24) | - (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42); - - ddma_trans(write_data, flash_add, flash_bank, 1, NumPages); - - while (1) { - while (!ioread32(FlashReg + intr_status)) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP) { - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - status = PASS; - if (status2 == FAIL) - status = FAIL; - break; - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__PROGRAM_FAIL) { - status2 = FAIL; - status = FAIL; - t = ioread32(FlashReg + intr_status) & - INTR_STATUS0__PROGRAM_FAIL; - iowrite32(t, FlashReg + intr_status); - } else { - iowrite32((~INTR_STATUS0__PROGRAM_FAIL) & - (~INTR_STATUS0__DMA_CMD_COMP), - FlashReg + intr_status); - } - } - - iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status); - - iowrite32(0, FlashReg + DMA_ENABLE); - - while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)) - ; - - iowrite32(0, FlashReg + MULTIPLANE_OPERATION); - - return status; -} - - -#if CMD_DMA -static irqreturn_t cdma_isr(int irq, void *dev_id) -{ - struct mrst_nand_info *dev = dev_id; - int first_failed_cmd; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (!is_cdma_interrupt()) - return IRQ_NONE; - - /* Disable controller interrupts */ - iowrite32(0, FlashReg + GLOBAL_INT_ENABLE); - GLOB_FTL_Event_Status(&first_failed_cmd); - complete(&dev->complete); - - return IRQ_HANDLED; -} -#else -static void handle_nand_int_read(struct mrst_nand_info *dev) -{ - u32 intr_status_addresses[4] = {INTR_STATUS0, - INTR_STATUS1, INTR_STATUS2, INTR_STATUS3}; - u32 intr_status; - u32 ecc_done_OR_dma_comp = 0; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - dev->ret = PASS; - intr_status = intr_status_addresses[dev->flash_bank]; - - while (1) { - if (enable_ecc) { - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_ERR) { - iowrite32(INTR_STATUS0__ECC_ERR, - FlashReg + intr_status); - dev->ret = do_ecc_new(dev->flash_bank, - dev->read_data, - dev->block, dev->page); - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP) { - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - if (1 == ecc_done_OR_dma_comp) - break; - ecc_done_OR_dma_comp = 1; - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__ECC_TRANSACTION_DONE) { - iowrite32(INTR_STATUS0__ECC_TRANSACTION_DONE, - FlashReg + intr_status); - if (1 == ecc_done_OR_dma_comp) - break; - ecc_done_OR_dma_comp = 1; - } - } else { - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP) { - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - break; - } else { - printk(KERN_ERR "Illegal INTS " - "(offset addr 0x%x) value: 0x%x\n", - intr_status, - ioread32(FlashReg + intr_status)); - } - } - - iowrite32((~INTR_STATUS0__ECC_ERR) & - (~INTR_STATUS0__ECC_TRANSACTION_DONE) & - (~INTR_STATUS0__DMA_CMD_COMP), - FlashReg + intr_status); - } -} - -static void handle_nand_int_write(struct mrst_nand_info *dev) -{ - u32 intr_status; - u32 intr[4] = {INTR_STATUS0, INTR_STATUS1, - INTR_STATUS2, INTR_STATUS3}; - int status = PASS; - - nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - dev->ret = PASS; - intr_status = intr[dev->flash_bank]; - - while (1) { - while (!ioread32(FlashReg + intr_status)) - ; - - if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__DMA_CMD_COMP) { - iowrite32(INTR_STATUS0__DMA_CMD_COMP, - FlashReg + intr_status); - if (FAIL == status) - dev->ret = FAIL; - break; - } else if (ioread32(FlashReg + intr_status) & - INTR_STATUS0__PROGRAM_FAIL) { - status = FAIL; - iowrite32(INTR_STATUS0__PROGRAM_FAIL, - FlashReg + intr_status); - } else { - iowrite32((~INTR_STATUS0__PROGRAM_FAIL) & - (~INTR_STATUS0__DMA_CMD_COMP), - FlashReg + intr_status); - } - } -} - -static irqreturn_t ddma_isr(int irq, void *dev_id) -{ - struct mrst_nand_info *dev = dev_id; - u32 int_mask, ints0, ints1, ints2, ints3, ints_offset; - u32 intr[4] = {INTR_STATUS0, INTR_STATUS1, - INTR_STATUS2, INTR_STATUS3}; - - int_mask = INTR_STATUS0__DMA_CMD_COMP | - INTR_STATUS0__ECC_TRANSACTION_DONE | - INTR_STATUS0__ECC_ERR | - INTR_STATUS0__PROGRAM_FAIL | - INTR_STATUS0__ERASE_FAIL; - - ints0 = ioread32(FlashReg + INTR_STATUS0); - ints1 = ioread32(FlashReg + INTR_STATUS1); - ints2 = ioread32(FlashReg + INTR_STATUS2); - ints3 = ioread32(FlashReg + INTR_STATUS3); - - ints_offset = intr[dev->flash_bank]; - - nand_dbg_print(NAND_DBG_DEBUG, - "INTR0: 0x%x, INTR1: 0x%x, INTR2: 0x%x, INTR3: 0x%x, " - "DMA_INTR: 0x%x, " - "dev->state: 0x%x, dev->flash_bank: %d\n", - ints0, ints1, ints2, ints3, - ioread32(FlashReg + DMA_INTR), - dev->state, dev->flash_bank); - - if (!(ioread32(FlashReg + ints_offset) & int_mask)) { - iowrite32(ints0, FlashReg + INTR_STATUS0); - iowrite32(ints1, FlashReg + INTR_STATUS1); - iowrite32(ints2, FlashReg + INTR_STATUS2); - iowrite32(ints3, FlashReg + INTR_STATUS3); - nand_dbg_print(NAND_DBG_WARN, - "ddma_isr: Invalid interrupt for NAND controller. " - "Ignore it\n"); - return IRQ_NONE; - } - - switch (dev->state) { - case INT_READ_PAGE_MAIN: - case INT_PIPELINE_READ_AHEAD: - /* Disable controller interrupts */ - iowrite32(0, FlashReg + GLOBAL_INT_ENABLE); - handle_nand_int_read(dev); - break; - case INT_WRITE_PAGE_MAIN: - case INT_PIPELINE_WRITE_AHEAD: - iowrite32(0, FlashReg + GLOBAL_INT_ENABLE); - handle_nand_int_write(dev); - break; - default: - printk(KERN_ERR "ddma_isr - Illegal state: 0x%x\n", - dev->state); - return IRQ_NONE; - } - - dev->state = INT_IDLE_STATE; - complete(&dev->complete); - return IRQ_HANDLED; -} -#endif - -static const struct pci_device_id nand_pci_ids[] = { - { - .vendor = 0x8086, - .device = 0x0809, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { /* end: all zeroes */ } -}; - -static int nand_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int ret = -ENODEV; - unsigned long csr_base; - unsigned long csr_len; - struct mrst_nand_info *pndev = &info; - u32 int_mask; - - ret = pci_enable_device(dev); - if (ret) { - printk(KERN_ERR "Spectra: pci_enable_device failed.\n"); - return ret; - } - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - FlashReg = ioremap_nocache(GLOB_HWCTL_REG_BASE, - GLOB_HWCTL_REG_SIZE); - if (!FlashReg) { - printk(KERN_ERR "Spectra: ioremap_nocache failed!"); - goto failed_disable; - } - nand_dbg_print(NAND_DBG_WARN, - "Spectra: Remapped reg base address: " - "0x%p, len: %d\n", - FlashReg, GLOB_HWCTL_REG_SIZE); - - FlashMem = ioremap_nocache(GLOB_HWCTL_MEM_BASE, - GLOB_HWCTL_MEM_SIZE); - if (!FlashMem) { - printk(KERN_ERR "Spectra: ioremap_nocache failed!"); - iounmap(FlashReg); - goto failed_disable; - } - nand_dbg_print(NAND_DBG_WARN, - "Spectra: Remapped flash base address: " - "0x%p, len: %d\n", - (void *)FlashMem, GLOB_HWCTL_MEM_SIZE); - - nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:" - "acc_clks: %d, re_2_we: %d, we_2_re: %d," - "addr_2_data: %d, rdwr_en_lo_cnt: %d, " - "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", - ioread32(FlashReg + ACC_CLKS), - ioread32(FlashReg + RE_2_WE), - ioread32(FlashReg + WE_2_RE), - ioread32(FlashReg + ADDR_2_DATA), - ioread32(FlashReg + RDWR_EN_LO_CNT), - ioread32(FlashReg + RDWR_EN_HI_CNT), - ioread32(FlashReg + CS_SETUP_CNT)); - - NAND_Flash_Reset(); - - iowrite32(0, FlashReg + GLOBAL_INT_ENABLE); - -#if CMD_DMA - info.pcmds_num = 0; - info.flash_bank = 0; - info.cdma_num = 0; - int_mask = (DMA_INTR__DESC_COMP_CHANNEL0 | - DMA_INTR__DESC_COMP_CHANNEL1 | - DMA_INTR__DESC_COMP_CHANNEL2 | - DMA_INTR__DESC_COMP_CHANNEL3 | - DMA_INTR__MEMCOPY_DESC_COMP); - iowrite32(int_mask, FlashReg + DMA_INTR_EN); - iowrite32(0xFFFF, FlashReg + DMA_INTR); - - int_mask = (INTR_STATUS0__ECC_ERR | - INTR_STATUS0__PROGRAM_FAIL | - INTR_STATUS0__ERASE_FAIL); -#else - int_mask = INTR_STATUS0__DMA_CMD_COMP | - INTR_STATUS0__ECC_TRANSACTION_DONE | - INTR_STATUS0__ECC_ERR | - INTR_STATUS0__PROGRAM_FAIL | - INTR_STATUS0__ERASE_FAIL; -#endif - iowrite32(int_mask, FlashReg + INTR_EN0); - iowrite32(int_mask, FlashReg + INTR_EN1); - iowrite32(int_mask, FlashReg + INTR_EN2); - iowrite32(int_mask, FlashReg + INTR_EN3); - - /* Clear all status bits */ - iowrite32(0xFFFF, FlashReg + INTR_STATUS0); - iowrite32(0xFFFF, FlashReg + INTR_STATUS1); - iowrite32(0xFFFF, FlashReg + INTR_STATUS2); - iowrite32(0xFFFF, FlashReg + INTR_STATUS3); - - iowrite32(0x0F, FlashReg + RB_PIN_ENABLED); - iowrite32(CHIP_EN_DONT_CARE__FLAG, FlashReg + CHIP_ENABLE_DONT_CARE); - - /* Should set value for these registers when init */ - iowrite32(0, FlashReg + TWO_ROW_ADDR_CYCLES); - iowrite32(1, FlashReg + ECC_ENABLE); - enable_ecc = 1; - - pci_set_master(dev); - pndev->dev = dev; - - csr_base = pci_resource_start(dev, 0); - if (!csr_base) { - printk(KERN_ERR "Spectra: pci_resource_start failed!\n"); - ret = -ENODEV; - goto failed_req_csr; - } - - csr_len = pci_resource_len(dev, 0); - if (!csr_len) { - printk(KERN_ERR "Spectra: pci_resource_len failed!\n"); - ret = -ENODEV; - goto failed_req_csr; - } - - ret = pci_request_regions(dev, SPECTRA_NAND_NAME); - if (ret) { - printk(KERN_ERR "Spectra: Unable to request " - "memory region\n"); - goto failed_req_csr; - } - - pndev->ioaddr = ioremap_nocache(csr_base, csr_len); - if (!pndev->ioaddr) { - printk(KERN_ERR "Spectra: Unable to remap memory region\n"); - ret = -ENOMEM; - goto failed_remap_csr; - } - nand_dbg_print(NAND_DBG_DEBUG, "Spectra: CSR 0x%08lx -> 0x%p (0x%lx)\n", - csr_base, pndev->ioaddr, csr_len); - - init_completion(&pndev->complete); - nand_dbg_print(NAND_DBG_DEBUG, "Spectra: IRQ %d\n", dev->irq); - -#if CMD_DMA - if (request_irq(dev->irq, cdma_isr, IRQF_SHARED, - SPECTRA_NAND_NAME, &info)) { - printk(KERN_ERR "Spectra: Unable to allocate IRQ\n"); - ret = -ENODEV; - iounmap(pndev->ioaddr); - goto failed_remap_csr; - } -#else - if (request_irq(dev->irq, ddma_isr, IRQF_SHARED, - SPECTRA_NAND_NAME, &info)) { - printk(KERN_ERR "Spectra: Unable to allocate IRQ\n"); - ret = -ENODEV; - iounmap(pndev->ioaddr); - goto failed_remap_csr; - } -#endif - - pci_set_drvdata(dev, pndev); - - ret = GLOB_LLD_Read_Device_ID(); - if (ret) { - iounmap(pndev->ioaddr); - goto failed_remap_csr; - } - - ret = register_spectra_ftl(); - if (ret) { - iounmap(pndev->ioaddr); - goto failed_remap_csr; - } - - return 0; - -failed_remap_csr: - pci_release_regions(dev); -failed_req_csr: - iounmap(FlashMem); - iounmap(FlashReg); -failed_disable: - pci_disable_device(dev); - - return ret; -} - -static void nand_pci_remove(struct pci_dev *dev) -{ - struct mrst_nand_info *pndev = pci_get_drvdata(dev); - - nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - -#if CMD_DMA - free_irq(dev->irq, pndev); -#endif - iounmap(pndev->ioaddr); - pci_release_regions(dev); - pci_disable_device(dev); -} - -MODULE_DEVICE_TABLE(pci, nand_pci_ids); - -static struct pci_driver nand_pci_driver = { - .name = SPECTRA_NAND_NAME, - .id_table = nand_pci_ids, - .probe = nand_pci_probe, - .remove = nand_pci_remove, -}; - -int NAND_Flash_Init(void) -{ - int retval; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - retval = pci_register_driver(&nand_pci_driver); - if (retval) - return -ENOMEM; - - return PASS; -} - -/* Free memory */ -int nand_release_spectra(void) -{ - pci_unregister_driver(&nand_pci_driver); - iounmap(FlashMem); - iounmap(FlashReg); - - return 0; -} - - - diff --git a/drivers/staging/spectra/lld_nand.h b/drivers/staging/spectra/lld_nand.h deleted file mode 100644 index d08388287da..00000000000 --- a/drivers/staging/spectra/lld_nand.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#ifndef _LLD_NAND_ -#define _LLD_NAND_ - -#ifdef ELDORA -#include "defs.h" -#else -#include "flash.h" -#include "ffsport.h" -#endif - -#define MODE_00 0x00000000 -#define MODE_01 0x04000000 -#define MODE_10 0x08000000 -#define MODE_11 0x0C000000 - - -#define DATA_TRANSFER_MODE 0 -#define PROTECTION_PER_BLOCK 1 -#define LOAD_WAIT_COUNT 2 -#define PROGRAM_WAIT_COUNT 3 -#define ERASE_WAIT_COUNT 4 -#define INT_MONITOR_CYCLE_COUNT 5 -#define READ_BUSY_PIN_ENABLED 6 -#define MULTIPLANE_OPERATION_SUPPORT 7 -#define PRE_FETCH_MODE 8 -#define CE_DONT_CARE_SUPPORT 9 -#define COPYBACK_SUPPORT 10 -#define CACHE_WRITE_SUPPORT 11 -#define CACHE_READ_SUPPORT 12 -#define NUM_PAGES_IN_BLOCK 13 -#define ECC_ENABLE_SELECT 14 -#define WRITE_ENABLE_2_READ_ENABLE 15 -#define ADDRESS_2_DATA 16 -#define READ_ENABLE_2_WRITE_ENABLE 17 -#define TWO_ROW_ADDRESS_CYCLES 18 -#define MULTIPLANE_ADDRESS_RESTRICT 19 -#define ACC_CLOCKS 20 -#define READ_WRITE_ENABLE_LOW_COUNT 21 -#define READ_WRITE_ENABLE_HIGH_COUNT 22 - -#define ECC_SECTOR_SIZE 512 -#define LLD_MAX_FLASH_BANKS 4 - -struct mrst_nand_info { - struct pci_dev *dev; - u32 state; - u32 flash_bank; - u8 *read_data; - u8 *write_data; - u32 block; - u16 page; - u32 use_dma; - void __iomem *ioaddr; /* Mapped io reg base address */ - int ret; - u32 pcmds_num; - struct pending_cmd *pcmds; - int cdma_num; /* CDMA descriptor number in this chan */ - u8 *cdma_desc_buf; /* CDMA descriptor table */ - u8 *memcp_desc_buf; /* Memory copy descriptor table */ - dma_addr_t cdma_desc; /* Mapped CDMA descriptor table */ - dma_addr_t memcp_desc; /* Mapped memory copy descriptor table */ - struct completion complete; -}; - -int NAND_Flash_Init(void); -int nand_release_spectra(void); -u16 NAND_Flash_Reset(void); -u16 NAND_Read_Device_ID(void); -u16 NAND_Erase_Block(u32 flash_add); -u16 NAND_Write_Page_Main(u8 *write_data, u32 block, u16 page, - u16 page_count); -u16 NAND_Read_Page_Main(u8 *read_data, u32 block, u16 page, - u16 page_count); -u16 NAND_UnlockArrayAll(void); -u16 NAND_Write_Page_Main_Spare(u8 *write_data, u32 block, - u16 page, u16 page_count); -u16 NAND_Write_Page_Spare(u8 *read_data, u32 block, u16 page, - u16 page_count); -u16 NAND_Read_Page_Main_Spare(u8 *read_data, u32 block, u16 page, - u16 page_count); -u16 NAND_Read_Page_Spare(u8 *read_data, u32 block, u16 page, - u16 page_count); -void NAND_LLD_Enable_Disable_Interrupts(u16 INT_ENABLE); -u16 NAND_Get_Bad_Block(u32 block); -u16 NAND_Pipeline_Read_Ahead(u8 *read_data, u32 block, u16 page, - u16 page_count); -u16 NAND_Pipeline_Write_Ahead(u8 *write_data, u32 block, - u16 page, u16 page_count); -u16 NAND_Multiplane_Read(u8 *read_data, u32 block, u16 page, - u16 page_count); -u16 NAND_Multiplane_Write(u8 *write_data, u32 block, u16 page, - u16 page_count); -void NAND_ECC_Ctrl(int enable); -u16 NAND_Read_Page_Main_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count); -u16 NAND_Pipeline_Read_Ahead_Polling(u8 *read_data, - u32 block, u16 page, u16 page_count); -void Conv_Spare_Data_Log2Phy_Format(u8 *data); -void Conv_Spare_Data_Phy2Log_Format(u8 *data); -void Conv_Main_Spare_Data_Log2Phy_Format(u8 *data, u16 page_count); -void Conv_Main_Spare_Data_Phy2Log_Format(u8 *data, u16 page_count); - -extern void __iomem *FlashReg; -extern void __iomem *FlashMem; - -extern int totalUsedBanks; -extern u32 GLOB_valid_banks[LLD_MAX_FLASH_BANKS]; - -#endif /*_LLD_NAND_*/ - - - diff --git a/drivers/staging/spectra/nand_regs.h b/drivers/staging/spectra/nand_regs.h deleted file mode 100644 index e192e4ae8c1..00000000000 --- a/drivers/staging/spectra/nand_regs.h +++ /dev/null @@ -1,619 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#define DEVICE_RESET 0x0 -#define DEVICE_RESET__BANK0 0x0001 -#define DEVICE_RESET__BANK1 0x0002 -#define DEVICE_RESET__BANK2 0x0004 -#define DEVICE_RESET__BANK3 0x0008 - -#define TRANSFER_SPARE_REG 0x10 -#define TRANSFER_SPARE_REG__FLAG 0x0001 - -#define LOAD_WAIT_CNT 0x20 -#define LOAD_WAIT_CNT__VALUE 0xffff - -#define PROGRAM_WAIT_CNT 0x30 -#define PROGRAM_WAIT_CNT__VALUE 0xffff - -#define ERASE_WAIT_CNT 0x40 -#define ERASE_WAIT_CNT__VALUE 0xffff - -#define INT_MON_CYCCNT 0x50 -#define INT_MON_CYCCNT__VALUE 0xffff - -#define RB_PIN_ENABLED 0x60 -#define RB_PIN_ENABLED__BANK0 0x0001 -#define RB_PIN_ENABLED__BANK1 0x0002 -#define RB_PIN_ENABLED__BANK2 0x0004 -#define RB_PIN_ENABLED__BANK3 0x0008 - -#define MULTIPLANE_OPERATION 0x70 -#define MULTIPLANE_OPERATION__FLAG 0x0001 - -#define MULTIPLANE_READ_ENABLE 0x80 -#define MULTIPLANE_READ_ENABLE__FLAG 0x0001 - -#define COPYBACK_DISABLE 0x90 -#define COPYBACK_DISABLE__FLAG 0x0001 - -#define CACHE_WRITE_ENABLE 0xa0 -#define CACHE_WRITE_ENABLE__FLAG 0x0001 - -#define CACHE_READ_ENABLE 0xb0 -#define CACHE_READ_ENABLE__FLAG 0x0001 - -#define PREFETCH_MODE 0xc0 -#define PREFETCH_MODE__PREFETCH_EN 0x0001 -#define PREFETCH_MODE__PREFETCH_BURST_LENGTH 0xfff0 - -#define CHIP_ENABLE_DONT_CARE 0xd0 -#define CHIP_EN_DONT_CARE__FLAG 0x01 - -#define ECC_ENABLE 0xe0 -#define ECC_ENABLE__FLAG 0x0001 - -#define GLOBAL_INT_ENABLE 0xf0 -#define GLOBAL_INT_EN_FLAG 0x01 - -#define WE_2_RE 0x100 -#define WE_2_RE__VALUE 0x003f - -#define ADDR_2_DATA 0x110 -#define ADDR_2_DATA__VALUE 0x003f - -#define RE_2_WE 0x120 -#define RE_2_WE__VALUE 0x003f - -#define ACC_CLKS 0x130 -#define ACC_CLKS__VALUE 0x000f - -#define NUMBER_OF_PLANES 0x140 -#define NUMBER_OF_PLANES__VALUE 0x0007 - -#define PAGES_PER_BLOCK 0x150 -#define PAGES_PER_BLOCK__VALUE 0xffff - -#define DEVICE_WIDTH 0x160 -#define DEVICE_WIDTH__VALUE 0x0003 - -#define DEVICE_MAIN_AREA_SIZE 0x170 -#define DEVICE_MAIN_AREA_SIZE__VALUE 0xffff - -#define DEVICE_SPARE_AREA_SIZE 0x180 -#define DEVICE_SPARE_AREA_SIZE__VALUE 0xffff - -#define TWO_ROW_ADDR_CYCLES 0x190 -#define TWO_ROW_ADDR_CYCLES__FLAG 0x0001 - -#define MULTIPLANE_ADDR_RESTRICT 0x1a0 -#define MULTIPLANE_ADDR_RESTRICT__FLAG 0x0001 - -#define ECC_CORRECTION 0x1b0 -#define ECC_CORRECTION__VALUE 0x001f - -#define READ_MODE 0x1c0 -#define READ_MODE__VALUE 0x000f - -#define WRITE_MODE 0x1d0 -#define WRITE_MODE__VALUE 0x000f - -#define COPYBACK_MODE 0x1e0 -#define COPYBACK_MODE__VALUE 0x000f - -#define RDWR_EN_LO_CNT 0x1f0 -#define RDWR_EN_LO_CNT__VALUE 0x001f - -#define RDWR_EN_HI_CNT 0x200 -#define RDWR_EN_HI_CNT__VALUE 0x001f - -#define MAX_RD_DELAY 0x210 -#define MAX_RD_DELAY__VALUE 0x000f - -#define CS_SETUP_CNT 0x220 -#define CS_SETUP_CNT__VALUE 0x001f - -#define SPARE_AREA_SKIP_BYTES 0x230 -#define SPARE_AREA_SKIP_BYTES__VALUE 0x003f - -#define SPARE_AREA_MARKER 0x240 -#define SPARE_AREA_MARKER__VALUE 0xffff - -#define DEVICES_CONNECTED 0x250 -#define DEVICES_CONNECTED__VALUE 0x0007 - -#define DIE_MASK 0x260 -#define DIE_MASK__VALUE 0x00ff - -#define FIRST_BLOCK_OF_NEXT_PLANE 0x270 -#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE 0xffff - -#define WRITE_PROTECT 0x280 -#define WRITE_PROTECT__FLAG 0x0001 - -#define RE_2_RE 0x290 -#define RE_2_RE__VALUE 0x003f - -#define MANUFACTURER_ID 0x300 -#define MANUFACTURER_ID__VALUE 0x00ff - -#define DEVICE_ID 0x310 -#define DEVICE_ID__VALUE 0x00ff - -#define DEVICE_PARAM_0 0x320 -#define DEVICE_PARAM_0__VALUE 0x00ff - -#define DEVICE_PARAM_1 0x330 -#define DEVICE_PARAM_1__VALUE 0x00ff - -#define DEVICE_PARAM_2 0x340 -#define DEVICE_PARAM_2__VALUE 0x00ff - -#define LOGICAL_PAGE_DATA_SIZE 0x350 -#define LOGICAL_PAGE_DATA_SIZE__VALUE 0xffff - -#define LOGICAL_PAGE_SPARE_SIZE 0x360 -#define LOGICAL_PAGE_SPARE_SIZE__VALUE 0xffff - -#define REVISION 0x370 -#define REVISION__VALUE 0xffff - -#define ONFI_DEVICE_FEATURES 0x380 -#define ONFI_DEVICE_FEATURES__VALUE 0x003f - -#define ONFI_OPTIONAL_COMMANDS 0x390 -#define ONFI_OPTIONAL_COMMANDS__VALUE 0x003f - -#define ONFI_TIMING_MODE 0x3a0 -#define ONFI_TIMING_MODE__VALUE 0x003f - -#define ONFI_PGM_CACHE_TIMING_MODE 0x3b0 -#define ONFI_PGM_CACHE_TIMING_MODE__VALUE 0x003f - -#define ONFI_DEVICE_NO_OF_LUNS 0x3c0 -#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS 0x00ff -#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE 0x0100 - -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE 0xffff - -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE 0xffff - -#define FEATURES 0x3f0 -#define FEATURES__N_BANKS 0x0003 -#define FEATURES__ECC_MAX_ERR 0x003c -#define FEATURES__DMA 0x0040 -#define FEATURES__CMD_DMA 0x0080 -#define FEATURES__PARTITION 0x0100 -#define FEATURES__XDMA_SIDEBAND 0x0200 -#define FEATURES__GPREG 0x0400 -#define FEATURES__INDEX_ADDR 0x0800 - -#define TRANSFER_MODE 0x400 -#define TRANSFER_MODE__VALUE 0x0003 - -#define INTR_STATUS0 0x410 -#define INTR_STATUS0__ECC_TRANSACTION_DONE 0x0001 -#define INTR_STATUS0__ECC_ERR 0x0002 -#define INTR_STATUS0__DMA_CMD_COMP 0x0004 -#define INTR_STATUS0__TIME_OUT 0x0008 -#define INTR_STATUS0__PROGRAM_FAIL 0x0010 -#define INTR_STATUS0__ERASE_FAIL 0x0020 -#define INTR_STATUS0__LOAD_COMP 0x0040 -#define INTR_STATUS0__PROGRAM_COMP 0x0080 -#define INTR_STATUS0__ERASE_COMP 0x0100 -#define INTR_STATUS0__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_STATUS0__LOCKED_BLK 0x0400 -#define INTR_STATUS0__UNSUP_CMD 0x0800 -#define INTR_STATUS0__INT_ACT 0x1000 -#define INTR_STATUS0__RST_COMP 0x2000 -#define INTR_STATUS0__PIPE_CMD_ERR 0x4000 -#define INTR_STATUS0__PAGE_XFER_INC 0x8000 - -#define INTR_EN0 0x420 -#define INTR_EN0__ECC_TRANSACTION_DONE 0x0001 -#define INTR_EN0__ECC_ERR 0x0002 -#define INTR_EN0__DMA_CMD_COMP 0x0004 -#define INTR_EN0__TIME_OUT 0x0008 -#define INTR_EN0__PROGRAM_FAIL 0x0010 -#define INTR_EN0__ERASE_FAIL 0x0020 -#define INTR_EN0__LOAD_COMP 0x0040 -#define INTR_EN0__PROGRAM_COMP 0x0080 -#define INTR_EN0__ERASE_COMP 0x0100 -#define INTR_EN0__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_EN0__LOCKED_BLK 0x0400 -#define INTR_EN0__UNSUP_CMD 0x0800 -#define INTR_EN0__INT_ACT 0x1000 -#define INTR_EN0__RST_COMP 0x2000 -#define INTR_EN0__PIPE_CMD_ERR 0x4000 -#define INTR_EN0__PAGE_XFER_INC 0x8000 - -#define PAGE_CNT0 0x430 -#define PAGE_CNT0__VALUE 0x00ff - -#define ERR_PAGE_ADDR0 0x440 -#define ERR_PAGE_ADDR0__VALUE 0xffff - -#define ERR_BLOCK_ADDR0 0x450 -#define ERR_BLOCK_ADDR0__VALUE 0xffff - -#define INTR_STATUS1 0x460 -#define INTR_STATUS1__ECC_TRANSACTION_DONE 0x0001 -#define INTR_STATUS1__ECC_ERR 0x0002 -#define INTR_STATUS1__DMA_CMD_COMP 0x0004 -#define INTR_STATUS1__TIME_OUT 0x0008 -#define INTR_STATUS1__PROGRAM_FAIL 0x0010 -#define INTR_STATUS1__ERASE_FAIL 0x0020 -#define INTR_STATUS1__LOAD_COMP 0x0040 -#define INTR_STATUS1__PROGRAM_COMP 0x0080 -#define INTR_STATUS1__ERASE_COMP 0x0100 -#define INTR_STATUS1__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_STATUS1__LOCKED_BLK 0x0400 -#define INTR_STATUS1__UNSUP_CMD 0x0800 -#define INTR_STATUS1__INT_ACT 0x1000 -#define INTR_STATUS1__RST_COMP 0x2000 -#define INTR_STATUS1__PIPE_CMD_ERR 0x4000 -#define INTR_STATUS1__PAGE_XFER_INC 0x8000 - -#define INTR_EN1 0x470 -#define INTR_EN1__ECC_TRANSACTION_DONE 0x0001 -#define INTR_EN1__ECC_ERR 0x0002 -#define INTR_EN1__DMA_CMD_COMP 0x0004 -#define INTR_EN1__TIME_OUT 0x0008 -#define INTR_EN1__PROGRAM_FAIL 0x0010 -#define INTR_EN1__ERASE_FAIL 0x0020 -#define INTR_EN1__LOAD_COMP 0x0040 -#define INTR_EN1__PROGRAM_COMP 0x0080 -#define INTR_EN1__ERASE_COMP 0x0100 -#define INTR_EN1__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_EN1__LOCKED_BLK 0x0400 -#define INTR_EN1__UNSUP_CMD 0x0800 -#define INTR_EN1__INT_ACT 0x1000 -#define INTR_EN1__RST_COMP 0x2000 -#define INTR_EN1__PIPE_CMD_ERR 0x4000 -#define INTR_EN1__PAGE_XFER_INC 0x8000 - -#define PAGE_CNT1 0x480 -#define PAGE_CNT1__VALUE 0x00ff - -#define ERR_PAGE_ADDR1 0x490 -#define ERR_PAGE_ADDR1__VALUE 0xffff - -#define ERR_BLOCK_ADDR1 0x4a0 -#define ERR_BLOCK_ADDR1__VALUE 0xffff - -#define INTR_STATUS2 0x4b0 -#define INTR_STATUS2__ECC_TRANSACTION_DONE 0x0001 -#define INTR_STATUS2__ECC_ERR 0x0002 -#define INTR_STATUS2__DMA_CMD_COMP 0x0004 -#define INTR_STATUS2__TIME_OUT 0x0008 -#define INTR_STATUS2__PROGRAM_FAIL 0x0010 -#define INTR_STATUS2__ERASE_FAIL 0x0020 -#define INTR_STATUS2__LOAD_COMP 0x0040 -#define INTR_STATUS2__PROGRAM_COMP 0x0080 -#define INTR_STATUS2__ERASE_COMP 0x0100 -#define INTR_STATUS2__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_STATUS2__LOCKED_BLK 0x0400 -#define INTR_STATUS2__UNSUP_CMD 0x0800 -#define INTR_STATUS2__INT_ACT 0x1000 -#define INTR_STATUS2__RST_COMP 0x2000 -#define INTR_STATUS2__PIPE_CMD_ERR 0x4000 -#define INTR_STATUS2__PAGE_XFER_INC 0x8000 - -#define INTR_EN2 0x4c0 -#define INTR_EN2__ECC_TRANSACTION_DONE 0x0001 -#define INTR_EN2__ECC_ERR 0x0002 -#define INTR_EN2__DMA_CMD_COMP 0x0004 -#define INTR_EN2__TIME_OUT 0x0008 -#define INTR_EN2__PROGRAM_FAIL 0x0010 -#define INTR_EN2__ERASE_FAIL 0x0020 -#define INTR_EN2__LOAD_COMP 0x0040 -#define INTR_EN2__PROGRAM_COMP 0x0080 -#define INTR_EN2__ERASE_COMP 0x0100 -#define INTR_EN2__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_EN2__LOCKED_BLK 0x0400 -#define INTR_EN2__UNSUP_CMD 0x0800 -#define INTR_EN2__INT_ACT 0x1000 -#define INTR_EN2__RST_COMP 0x2000 -#define INTR_EN2__PIPE_CMD_ERR 0x4000 -#define INTR_EN2__PAGE_XFER_INC 0x8000 - -#define PAGE_CNT2 0x4d0 -#define PAGE_CNT2__VALUE 0x00ff - -#define ERR_PAGE_ADDR2 0x4e0 -#define ERR_PAGE_ADDR2__VALUE 0xffff - -#define ERR_BLOCK_ADDR2 0x4f0 -#define ERR_BLOCK_ADDR2__VALUE 0xffff - -#define INTR_STATUS3 0x500 -#define INTR_STATUS3__ECC_TRANSACTION_DONE 0x0001 -#define INTR_STATUS3__ECC_ERR 0x0002 -#define INTR_STATUS3__DMA_CMD_COMP 0x0004 -#define INTR_STATUS3__TIME_OUT 0x0008 -#define INTR_STATUS3__PROGRAM_FAIL 0x0010 -#define INTR_STATUS3__ERASE_FAIL 0x0020 -#define INTR_STATUS3__LOAD_COMP 0x0040 -#define INTR_STATUS3__PROGRAM_COMP 0x0080 -#define INTR_STATUS3__ERASE_COMP 0x0100 -#define INTR_STATUS3__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_STATUS3__LOCKED_BLK 0x0400 -#define INTR_STATUS3__UNSUP_CMD 0x0800 -#define INTR_STATUS3__INT_ACT 0x1000 -#define INTR_STATUS3__RST_COMP 0x2000 -#define INTR_STATUS3__PIPE_CMD_ERR 0x4000 -#define INTR_STATUS3__PAGE_XFER_INC 0x8000 - -#define INTR_EN3 0x510 -#define INTR_EN3__ECC_TRANSACTION_DONE 0x0001 -#define INTR_EN3__ECC_ERR 0x0002 -#define INTR_EN3__DMA_CMD_COMP 0x0004 -#define INTR_EN3__TIME_OUT 0x0008 -#define INTR_EN3__PROGRAM_FAIL 0x0010 -#define INTR_EN3__ERASE_FAIL 0x0020 -#define INTR_EN3__LOAD_COMP 0x0040 -#define INTR_EN3__PROGRAM_COMP 0x0080 -#define INTR_EN3__ERASE_COMP 0x0100 -#define INTR_EN3__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_EN3__LOCKED_BLK 0x0400 -#define INTR_EN3__UNSUP_CMD 0x0800 -#define INTR_EN3__INT_ACT 0x1000 -#define INTR_EN3__RST_COMP 0x2000 -#define INTR_EN3__PIPE_CMD_ERR 0x4000 -#define INTR_EN3__PAGE_XFER_INC 0x8000 - -#define PAGE_CNT3 0x520 -#define PAGE_CNT3__VALUE 0x00ff - -#define ERR_PAGE_ADDR3 0x530 -#define ERR_PAGE_ADDR3__VALUE 0xffff - -#define ERR_BLOCK_ADDR3 0x540 -#define ERR_BLOCK_ADDR3__VALUE 0xffff - -#define DATA_INTR 0x550 -#define DATA_INTR__WRITE_SPACE_AV 0x0001 -#define DATA_INTR__READ_DATA_AV 0x0002 - -#define DATA_INTR_EN 0x560 -#define DATA_INTR_EN__WRITE_SPACE_AV 0x0001 -#define DATA_INTR_EN__READ_DATA_AV 0x0002 - -#define GPREG_0 0x570 -#define GPREG_0__VALUE 0xffff - -#define GPREG_1 0x580 -#define GPREG_1__VALUE 0xffff - -#define GPREG_2 0x590 -#define GPREG_2__VALUE 0xffff - -#define GPREG_3 0x5a0 -#define GPREG_3__VALUE 0xffff - -#define ECC_THRESHOLD 0x600 -#define ECC_THRESHOLD__VALUE 0x03ff - -#define ECC_ERROR_BLOCK_ADDRESS 0x610 -#define ECC_ERROR_BLOCK_ADDRESS__VALUE 0xffff - -#define ECC_ERROR_PAGE_ADDRESS 0x620 -#define ECC_ERROR_PAGE_ADDRESS__VALUE 0x0fff -#define ECC_ERROR_PAGE_ADDRESS__BANK 0xf000 - -#define ECC_ERROR_ADDRESS 0x630 -#define ECC_ERROR_ADDRESS__OFFSET 0x0fff -#define ECC_ERROR_ADDRESS__SECTOR_NR 0xf000 - -#define ERR_CORRECTION_INFO 0x640 -#define ERR_CORRECTION_INFO__BYTEMASK 0x00ff -#define ERR_CORRECTION_INFO__DEVICE_NR 0x0f00 -#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000 -#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000 - -#define DMA_ENABLE 0x700 -#define DMA_ENABLE__FLAG 0x0001 - -#define IGNORE_ECC_DONE 0x710 -#define IGNORE_ECC_DONE__FLAG 0x0001 - -#define DMA_INTR 0x720 -#define DMA_INTR__TARGET_ERROR 0x0001 -#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002 -#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004 -#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008 -#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010 -#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020 - -#define DMA_INTR_EN 0x730 -#define DMA_INTR_EN__TARGET_ERROR 0x0001 -#define DMA_INTR_EN__DESC_COMP_CHANNEL0 0x0002 -#define DMA_INTR_EN__DESC_COMP_CHANNEL1 0x0004 -#define DMA_INTR_EN__DESC_COMP_CHANNEL2 0x0008 -#define DMA_INTR_EN__DESC_COMP_CHANNEL3 0x0010 -#define DMA_INTR_EN__MEMCOPY_DESC_COMP 0x0020 - -#define TARGET_ERR_ADDR_LO 0x740 -#define TARGET_ERR_ADDR_LO__VALUE 0xffff - -#define TARGET_ERR_ADDR_HI 0x750 -#define TARGET_ERR_ADDR_HI__VALUE 0xffff - -#define CHNL_ACTIVE 0x760 -#define CHNL_ACTIVE__CHANNEL0 0x0001 -#define CHNL_ACTIVE__CHANNEL1 0x0002 -#define CHNL_ACTIVE__CHANNEL2 0x0004 -#define CHNL_ACTIVE__CHANNEL3 0x0008 - -#define ACTIVE_SRC_ID 0x800 -#define ACTIVE_SRC_ID__VALUE 0x00ff - -#define PTN_INTR 0x810 -#define PTN_INTR__CONFIG_ERROR 0x0001 -#define PTN_INTR__ACCESS_ERROR_BANK0 0x0002 -#define PTN_INTR__ACCESS_ERROR_BANK1 0x0004 -#define PTN_INTR__ACCESS_ERROR_BANK2 0x0008 -#define PTN_INTR__ACCESS_ERROR_BANK3 0x0010 -#define PTN_INTR__REG_ACCESS_ERROR 0x0020 - -#define PTN_INTR_EN 0x820 -#define PTN_INTR_EN__CONFIG_ERROR 0x0001 -#define PTN_INTR_EN__ACCESS_ERROR_BANK0 0x0002 -#define PTN_INTR_EN__ACCESS_ERROR_BANK1 0x0004 -#define PTN_INTR_EN__ACCESS_ERROR_BANK2 0x0008 -#define PTN_INTR_EN__ACCESS_ERROR_BANK3 0x0010 -#define PTN_INTR_EN__REG_ACCESS_ERROR 0x0020 - -#define PERM_SRC_ID_0 0x830 -#define PERM_SRC_ID_0__SRCID 0x00ff -#define PERM_SRC_ID_0__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_0__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_0__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_0__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_0 0x840 -#define MIN_BLK_ADDR_0__VALUE 0xffff - -#define MAX_BLK_ADDR_0 0x850 -#define MAX_BLK_ADDR_0__VALUE 0xffff - -#define MIN_MAX_BANK_0 0x860 -#define MIN_MAX_BANK_0__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_0__MAX_VALUE 0x000c - -#define PERM_SRC_ID_1 0x870 -#define PERM_SRC_ID_1__SRCID 0x00ff -#define PERM_SRC_ID_1__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_1__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_1__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_1__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_1 0x880 -#define MIN_BLK_ADDR_1__VALUE 0xffff - -#define MAX_BLK_ADDR_1 0x890 -#define MAX_BLK_ADDR_1__VALUE 0xffff - -#define MIN_MAX_BANK_1 0x8a0 -#define MIN_MAX_BANK_1__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_1__MAX_VALUE 0x000c - -#define PERM_SRC_ID_2 0x8b0 -#define PERM_SRC_ID_2__SRCID 0x00ff -#define PERM_SRC_ID_2__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_2__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_2__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_2__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_2 0x8c0 -#define MIN_BLK_ADDR_2__VALUE 0xffff - -#define MAX_BLK_ADDR_2 0x8d0 -#define MAX_BLK_ADDR_2__VALUE 0xffff - -#define MIN_MAX_BANK_2 0x8e0 -#define MIN_MAX_BANK_2__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_2__MAX_VALUE 0x000c - -#define PERM_SRC_ID_3 0x8f0 -#define PERM_SRC_ID_3__SRCID 0x00ff -#define PERM_SRC_ID_3__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_3__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_3__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_3__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_3 0x900 -#define MIN_BLK_ADDR_3__VALUE 0xffff - -#define MAX_BLK_ADDR_3 0x910 -#define MAX_BLK_ADDR_3__VALUE 0xffff - -#define MIN_MAX_BANK_3 0x920 -#define MIN_MAX_BANK_3__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_3__MAX_VALUE 0x000c - -#define PERM_SRC_ID_4 0x930 -#define PERM_SRC_ID_4__SRCID 0x00ff -#define PERM_SRC_ID_4__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_4__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_4__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_4__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_4 0x940 -#define MIN_BLK_ADDR_4__VALUE 0xffff - -#define MAX_BLK_ADDR_4 0x950 -#define MAX_BLK_ADDR_4__VALUE 0xffff - -#define MIN_MAX_BANK_4 0x960 -#define MIN_MAX_BANK_4__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_4__MAX_VALUE 0x000c - -#define PERM_SRC_ID_5 0x970 -#define PERM_SRC_ID_5__SRCID 0x00ff -#define PERM_SRC_ID_5__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_5__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_5__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_5__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_5 0x980 -#define MIN_BLK_ADDR_5__VALUE 0xffff - -#define MAX_BLK_ADDR_5 0x990 -#define MAX_BLK_ADDR_5__VALUE 0xffff - -#define MIN_MAX_BANK_5 0x9a0 -#define MIN_MAX_BANK_5__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_5__MAX_VALUE 0x000c - -#define PERM_SRC_ID_6 0x9b0 -#define PERM_SRC_ID_6__SRCID 0x00ff -#define PERM_SRC_ID_6__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_6__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_6__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_6__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_6 0x9c0 -#define MIN_BLK_ADDR_6__VALUE 0xffff - -#define MAX_BLK_ADDR_6 0x9d0 -#define MAX_BLK_ADDR_6__VALUE 0xffff - -#define MIN_MAX_BANK_6 0x9e0 -#define MIN_MAX_BANK_6__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_6__MAX_VALUE 0x000c - -#define PERM_SRC_ID_7 0x9f0 -#define PERM_SRC_ID_7__SRCID 0x00ff -#define PERM_SRC_ID_7__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID_7__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID_7__READ_ACTIVE 0x4000 -#define PERM_SRC_ID_7__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR_7 0xa00 -#define MIN_BLK_ADDR_7__VALUE 0xffff - -#define MAX_BLK_ADDR_7 0xa10 -#define MAX_BLK_ADDR_7__VALUE 0xffff - -#define MIN_MAX_BANK_7 0xa20 -#define MIN_MAX_BANK_7__MIN_VALUE 0x0003 -#define MIN_MAX_BANK_7__MAX_VALUE 0x000c diff --git a/drivers/staging/spectra/spectraswconfig.h b/drivers/staging/spectra/spectraswconfig.h deleted file mode 100644 index 17259469e95..00000000000 --- a/drivers/staging/spectra/spectraswconfig.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * 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 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. - * - */ - -#ifndef _SPECTRASWCONFIG_ -#define _SPECTRASWCONFIG_ - -/* NAND driver version */ -#define GLOB_VERSION "driver version 20100311" - - -/***** Common Parameters *****/ -#define RETRY_TIMES 3 - -#define READ_BADBLOCK_INFO 1 -#define READBACK_VERIFY 0 -#define AUTO_FORMAT_FLASH 0 - -/***** Cache Parameters *****/ -#define CACHE_ITEM_NUM 128 -#define BLK_NUM_FOR_L2_CACHE 16 - -/***** Block Table Parameters *****/ -#define BLOCK_TABLE_INDEX 0 - -/***** Wear Leveling Parameters *****/ -#define WEAR_LEVELING_GATE 0x10 -#define WEAR_LEVELING_BLOCK_NUM 10 - -#define DEBUG_BNDRY 0 - -/***** Product Feature Support *****/ -#define FLASH_EMU defined(CONFIG_SPECTRA_EMU) -#define FLASH_NAND defined(CONFIG_SPECTRA_MRST_HW) -#define FLASH_MTD defined(CONFIG_SPECTRA_MTD) -#define CMD_DMA defined(CONFIG_SPECTRA_MRST_HW_DMA) - -#define SPECTRA_PARTITION_ID 0 - -/* Enable this macro if the number of flash blocks is larger than 16K. */ -#define SUPPORT_LARGE_BLOCKNUM 1 - -/**** Block Table and Reserved Block Parameters *****/ -#define SPECTRA_START_BLOCK 3 -//#define NUM_FREE_BLOCKS_GATE 30 -#define NUM_FREE_BLOCKS_GATE 60 - -/**** Hardware Parameters ****/ -#define GLOB_HWCTL_REG_BASE 0xFFA40000 -#define GLOB_HWCTL_REG_SIZE 4096 - -#define GLOB_HWCTL_MEM_BASE 0xFFA48000 -#define GLOB_HWCTL_MEM_SIZE 4096 - -/* KBV - Updated to LNW scratch register address */ -#define SCRATCH_REG_ADDR 0xFF108018 -#define SCRATCH_REG_SIZE 64 - -#define GLOB_HWCTL_DEFAULT_BLKS 2048 - -#define SUPPORT_15BITECC 1 -#define SUPPORT_8BITECC 1 - -#define ONFI_BLOOM_TIME 0 -#define MODE5_WORKAROUND 1 - -#endif /*_SPECTRASWCONFIG_*/ diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 55c0b510889..03420e25d9c 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -109,11 +109,6 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, spin_unlock(&sdev->ud.lock); return -EINVAL; } -#if 0 - setnodelay(socket); - setkeepalive(socket); - setreuse(socket); -#endif sdev->ud.tcp_socket = socket; spin_unlock(&sdev->ud.lock); diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index 6b4e3e182de..27ac363d1cf 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -564,7 +564,7 @@ static void stub_rx_pdu(struct usbip_device *ud) memset(&pdu, 0, sizeof(pdu)); /* 1. receive a pdu header */ - ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0); + ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu)); if (ret != sizeof(pdu)) { dev_err(dev, "recv a header, %d\n", ret); usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 3b7a847f465..d93e7f1f797 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -334,9 +334,8 @@ void usbip_dump_header(struct usbip_header *pdu) } EXPORT_SYMBOL_GPL(usbip_dump_header); -/* Send/receive messages over TCP/IP. I refer drivers/block/nbd.c */ -int usbip_xmit(int send, struct socket *sock, char *buf, int size, - int msg_flags) +/* Receive data over TCP/IP. */ +int usbip_recv(struct socket *sock, void *buf, int size) { int result; struct msghdr msg; @@ -355,19 +354,6 @@ int usbip_xmit(int send, struct socket *sock, char *buf, int size, return -EINVAL; } - if (usbip_dbg_flag_xmit) { - if (send) { - if (!in_interrupt()) - pr_debug("%-10s:", current->comm); - else - pr_debug("interrupt :"); - - pr_debug("sending... , sock %p, buf %p, size %d, " - "msg_flags %d\n", sock, buf, size, msg_flags); - usbip_dump_buffer(buf, size); - } - } - do { sock->sk->sk_allocation = GFP_NOIO; iov.iov_base = buf; @@ -377,42 +363,30 @@ int usbip_xmit(int send, struct socket *sock, char *buf, int size, msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_namelen = 0; - msg.msg_flags = msg_flags | MSG_NOSIGNAL; - - if (send) - result = kernel_sendmsg(sock, &msg, &iov, 1, size); - else - result = kernel_recvmsg(sock, &msg, &iov, 1, size, - MSG_WAITALL); + msg.msg_flags = MSG_NOSIGNAL; + result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL); if (result <= 0) { - pr_debug("%s sock %p buf %p size %u ret %d total %d\n", - send ? "send" : "receive", sock, buf, size, - result, total); + pr_debug("receive sock %p buf %p size %u ret %d total %d\n", + sock, buf, size, result, total); goto err; } size -= result; buf += result; total += result; - } while (size > 0); if (usbip_dbg_flag_xmit) { - if (!send) { - if (!in_interrupt()) - pr_debug("%-10s:", current->comm); - else - pr_debug("interrupt :"); - - pr_debug("receiving....\n"); - usbip_dump_buffer(bp, osize); - pr_debug("received, osize %d ret %d size %d total %d\n", - osize, result, size, total); - } + if (!in_interrupt()) + pr_debug("%-10s:", current->comm); + else + pr_debug("interrupt :"); - if (send) - pr_debug("send, total %d\n", total); + pr_debug("receiving....\n"); + usbip_dump_buffer(bp, osize); + pr_debug("received, osize %d ret %d size %d total %d\n", + osize, result, size, total); } return total; @@ -420,7 +394,7 @@ int usbip_xmit(int send, struct socket *sock, char *buf, int size, err: return result; } -EXPORT_SYMBOL_GPL(usbip_xmit); +EXPORT_SYMBOL_GPL(usbip_recv); struct socket *sockfd_to_socket(unsigned int sockfd) { @@ -712,7 +686,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) if (!buff) return -ENOMEM; - ret = usbip_xmit(0, ud->tcp_socket, buff, size, 0); + ret = usbip_recv(ud->tcp_socket, buff, size); if (ret != size) { dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n", ret); @@ -823,8 +797,7 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) if (!(size > 0)) return 0; - ret = usbip_xmit(0, ud->tcp_socket, (char *)urb->transfer_buffer, - size, 0); + ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); if (ret != size) { dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); if (ud->side == USBIP_STUB) { diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h index be216175ae8..b8f8c48b8a7 100644 --- a/drivers/staging/usbip/usbip_common.h +++ b/drivers/staging/usbip/usbip_common.h @@ -292,21 +292,11 @@ struct usbip_device { } eh_ops; }; -#if 0 -int usbip_sendmsg(struct socket *, struct msghdr *, int); -int set_sockaddr(struct socket *socket, struct sockaddr_storage *ss); -int setnodelay(struct socket *); -int setquickack(struct socket *); -int setkeepalive(struct socket *socket); -void setreuse(struct socket *); -#endif - /* usbip_common.c */ void usbip_dump_urb(struct urb *purb); void usbip_dump_header(struct usbip_header *pdu); -int usbip_xmit(int send, struct socket *sock, char *buf, int size, - int msg_flags); +int usbip_recv(struct socket *sock, void *buf, int size); struct socket *sockfd_to_socket(unsigned int sockfd); void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, @@ -337,9 +327,4 @@ static inline int interface_to_devnum(struct usb_interface *interface) return udev->devnum; } -static inline int interface_to_infnum(struct usb_interface *interface) -{ - return interface->cur_altsetting->desc.bInterfaceNumber; -} - #endif /* __USBIP_COMMON_H */ diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index 3872b8cccdc..3f511b47563 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c @@ -206,7 +206,7 @@ static void vhci_rx_pdu(struct usbip_device *ud) memset(&pdu, 0, sizeof(pdu)); /* 1. receive a pdu header */ - ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0); + ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu)); if (ret < 0) { if (ret == -ECONNRESET) pr_info("connection reset by peer\n"); diff --git a/drivers/staging/vme/TODO b/drivers/staging/vme/TODO index 82c222b4a14..79f00333e7e 100644 --- a/drivers/staging/vme/TODO +++ b/drivers/staging/vme/TODO @@ -1,70 +1,5 @@ TODO ==== -API -=== - -Master window broadcast select mask ------------------------------------ - -API currently provides no method to set or get Broadcast Select mask. Suggest -somthing like: - - int vme_master_bmsk_set (struct vme_resource *res, int mask); - int vme_master_bmsk_get (struct vme_resource *res, int *mask); - - -Interrupt Generation --------------------- - -Add optional timeout when waiting for an IACK. - - -CR/CSR Buffer -------------- - -The VME API provides no functions to access the buffer mapped into the CR/CSR -space. - - -Mailboxes ---------- - -Whilst not part of the VME specification, they are provided by a number of -chips. They are currently not supported at all by the API. - - -Core -==== - -- Improve generic sanity checks (Such as does an offset and size fit within a - window and parameter checking). - -Bridge Support -============== - -Tempe (tsi148) --------------- - -- 2eSST Broadcast mode. -- Mailboxes unsupported. -- Improve error detection. -- Control of prefetch size, threshold. -- Arbiter control -- Requestor control - -Universe II (ca91c142) ----------------------- - -- Mailboxes unsupported. -- Error Detection. -- Control of prefetch size, threshold. -- Arbiter control -- Requestor control -- Slot detection - -Universe I (ca91x042) ---------------------- - -Currently completely unsupported. +- Add one or more device drivers which use the VME framework. diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index 0e4feac138e..515b8b8e32a 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -338,7 +338,7 @@ static int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, static int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled, unsigned long long vme_base, unsigned long long size, - dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle) + dma_addr_t pci_base, u32 aspace, u32 cycle) { unsigned int i, addr = 0, granularity; unsigned int temp_ctl = 0; @@ -444,7 +444,7 @@ static int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled, static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, - dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle) + dma_addr_t *pci_base, u32 *aspace, u32 *cycle) { unsigned int i, granularity = 0, ctl = 0; unsigned long long vme_bound, pci_offset; @@ -595,8 +595,8 @@ static void ca91cx42_free_resource(struct vme_master_resource *image) static int ca91cx42_master_set(struct vme_master_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) + unsigned long long vme_base, unsigned long long size, u32 aspace, + u32 cycle, u32 dwidth) { int retval = 0; unsigned int i, granularity = 0; @@ -753,7 +753,7 @@ err_window: static int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, - vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) + u32 *aspace, u32 *cycle, u32 *dwidth) { unsigned int i, ctl; unsigned long long pci_base, pci_bound, vme_offset; @@ -839,8 +839,8 @@ static int __ca91cx42_master_get(struct vme_master_resource *image, } static int ca91cx42_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) + unsigned long long *vme_base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *dwidth) { int retval; @@ -876,13 +876,13 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image, * maximal configured data cycle is used and splits it * automatically for non-aligned addresses. */ - if ((int)addr & 0x1) { + if ((uintptr_t)addr & 0x1) { *(u8 *)buf = ioread8(addr); done += 1; if (done == count) goto out; } - if ((int)addr & 0x2) { + if ((uintptr_t)addr & 0x2) { if ((count - done) < 2) { *(u8 *)(buf + done) = ioread8(addr + done); done += 1; @@ -930,13 +930,13 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image, /* Here we apply for the same strategy we do in master_read * function in order to assure D16 cycle when required. */ - if ((int)addr & 0x1) { + if ((uintptr_t)addr & 0x1) { iowrite8(*(u8 *)buf, addr); done += 1; if (done == count) goto out; } - if ((int)addr & 0x2) { + if ((uintptr_t)addr & 0x2) { if ((count - done) < 2) { iowrite8(*(u8 *)(buf + done), addr + done); done += 1; @@ -973,7 +973,8 @@ static unsigned int ca91cx42_master_rmw(struct vme_master_resource *image, unsigned int mask, unsigned int compare, unsigned int swap, loff_t offset) { - u32 pci_addr, result; + u32 result; + uintptr_t pci_addr; int i; struct ca91cx42_driver *bridge; struct device *dev; @@ -990,7 +991,7 @@ static unsigned int ca91cx42_master_rmw(struct vme_master_resource *image, /* Lock image */ spin_lock(&image->lock); - pci_addr = (u32)image->kern_base + offset; + pci_addr = (uintptr_t)image->kern_base + offset; /* Address must be 4-byte aligned */ if (pci_addr & 0x3) { @@ -1291,7 +1292,7 @@ static int ca91cx42_dma_list_empty(struct vme_dma_list *list) * callback is attached and disabled when the last callback is removed. */ static int ca91cx42_lm_set(struct vme_lm_resource *lm, - unsigned long long lm_base, vme_address_t aspace, vme_cycle_t cycle) + unsigned long long lm_base, u32 aspace, u32 cycle) { u32 temp_base, lm_ctl = 0; int i; @@ -1359,7 +1360,7 @@ static int ca91cx42_lm_set(struct vme_lm_resource *lm, * or disabled. */ static int ca91cx42_lm_get(struct vme_lm_resource *lm, - unsigned long long *lm_base, vme_address_t *aspace, vme_cycle_t *cycle) + unsigned long long *lm_base, u32 *aspace, u32 *cycle) { u32 lm_ctl, enabled = 0; struct ca91cx42_driver *bridge; diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 6c1167c2bea..08a449b4abf 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -483,7 +483,7 @@ static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, * Find the first error in this address range */ static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge, - vme_address_t aspace, unsigned long long address, size_t count) + u32 aspace, unsigned long long address, size_t count) { struct list_head *err_pos; struct vme_bus_error *vme_err, *valid = NULL; @@ -517,7 +517,7 @@ static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge, * Clear errors in the provided address range. */ static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge, - vme_address_t aspace, unsigned long long address, size_t count) + u32 aspace, unsigned long long address, size_t count) { struct list_head *err_pos, *temp; struct vme_bus_error *vme_err; @@ -551,7 +551,7 @@ static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge, */ static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, unsigned long long vme_base, unsigned long long size, - dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle) + dma_addr_t pci_base, u32 aspace, u32 cycle) { unsigned int i, addr = 0, granularity = 0; unsigned int temp_ctl = 0; @@ -701,7 +701,7 @@ static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, */ static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, - dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle) + dma_addr_t *pci_base, u32 *aspace, u32 *cycle) { unsigned int i, granularity = 0, ctl = 0; unsigned int vme_base_low, vme_base_high; @@ -893,8 +893,8 @@ static void tsi148_free_resource(struct vme_master_resource *image) * Set the attributes of an outbound window. */ static int tsi148_master_set(struct vme_master_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) + unsigned long long vme_base, unsigned long long size, u32 aspace, + u32 cycle, u32 dwidth) { int retval = 0; unsigned int i; @@ -1129,8 +1129,8 @@ err_window: * XXX Not parsing prefetch information. */ static int __tsi148_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) + unsigned long long *vme_base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *dwidth) { unsigned int i, ctl; unsigned int pci_base_low, pci_base_high; @@ -1239,8 +1239,8 @@ static int __tsi148_master_get(struct vme_master_resource *image, int *enabled, static int tsi148_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) + unsigned long long *vme_base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *dwidth) { int retval; @@ -1259,9 +1259,7 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, { int retval, enabled; unsigned long long vme_base, size; - vme_address_t aspace; - vme_cycle_t cycle; - vme_width_t dwidth; + u32 aspace, cycle, dwidth; struct vme_bus_error *vme_err = NULL; struct vme_bridge *tsi148_bridge; @@ -1301,9 +1299,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, { int retval = 0, enabled; unsigned long long vme_base, size; - vme_address_t aspace; - vme_cycle_t cycle; - vme_width_t dwidth; + u32 aspace, cycle, dwidth; struct vme_bus_error *vme_err = NULL; struct vme_bridge *tsi148_bridge; @@ -1420,7 +1416,7 @@ static unsigned int tsi148_master_rmw(struct vme_master_resource *image, } static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) + u32 aspace, u32 cycle, u32 dwidth) { /* Setup 2eSST speeds */ switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { @@ -1514,7 +1510,7 @@ static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr, } static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) + u32 aspace, u32 cycle, u32 dwidth) { /* Setup 2eSST speeds */ switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { @@ -1886,7 +1882,7 @@ static int tsi148_dma_list_empty(struct vme_dma_list *list) * callback is attached and disabled when the last callback is removed. */ static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, - vme_address_t aspace, vme_cycle_t cycle) + u32 aspace, u32 cycle) { u32 lm_base_high, lm_base_low, lm_ctl = 0; int i; @@ -1953,7 +1949,7 @@ static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, * or disabled. */ static int tsi148_lm_get(struct vme_lm_resource *lm, - unsigned long long *lm_base, vme_address_t *aspace, vme_cycle_t *cycle) + unsigned long long *lm_base, u32 *aspace, u32 *cycle) { u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0; struct tsi148_driver *bridge; diff --git a/drivers/staging/vme/devices/Kconfig b/drivers/staging/vme/devices/Kconfig index ca5ba89e2d8..55ec30cb1fa 100644 --- a/drivers/staging/vme/devices/Kconfig +++ b/drivers/staging/vme/devices/Kconfig @@ -6,3 +6,16 @@ config VME_USER If you say Y here you want to be able to access a limited number of VME windows in a manner at least semi-compatible with the interface provided with the original driver at http://vmelinux.org/. + +config VME_PIO2 + tristate "GE PIO2 VME" + depends on GPIOLIB + help + Say Y here to include support for the GE PIO2. The PIO2 is a 6U VME + slave card, implementing 32 solid-state relay switched IO lines, in + 4 groups of 8. Each bank of IO lines is built to function as input, + output or both depending on the variant of the card. + + To compile this driver as a module, choose M here. The module will + be called vme_pio2. If unsure, say N. + diff --git a/drivers/staging/vme/devices/Makefile b/drivers/staging/vme/devices/Makefile index 459742a7528..172512cb5db 100644 --- a/drivers/staging/vme/devices/Makefile +++ b/drivers/staging/vme/devices/Makefile @@ -3,3 +3,6 @@ # obj-$(CONFIG_VME_USER) += vme_user.o + +vme_pio2-objs := vme_pio2_cntr.o vme_pio2_gpio.o vme_pio2_core.o +obj-$(CONFIG_VME_PIO2) += vme_pio2.o diff --git a/drivers/staging/vme/devices/vme_pio2.h b/drivers/staging/vme/devices/vme_pio2.h new file mode 100644 index 00000000000..3c593136453 --- /dev/null +++ b/drivers/staging/vme/devices/vme_pio2.h @@ -0,0 +1,249 @@ +#ifndef _VME_PIO2_H_ +#define _VME_PIO2_H_ + +#define PIO2_CARDS_MAX 32 + +#define PIO2_VARIANT_LENGTH 5 + +#define PIO2_NUM_CHANNELS 32 +#define PIO2_NUM_IRQS 11 +#define PIO2_NUM_CNTRS 6 + +#define PIO2_REGS_SIZE 0x40 + +#define PIO2_REGS_DATA0 0x0 +#define PIO2_REGS_DATA1 0x1 +#define PIO2_REGS_DATA2 0x2 +#define PIO2_REGS_DATA3 0x3 + +static const int PIO2_REGS_DATA[4] = { PIO2_REGS_DATA0, PIO2_REGS_DATA1, + PIO2_REGS_DATA2, PIO2_REGS_DATA3 }; + +#define PIO2_REGS_INT_STAT0 0x8 +#define PIO2_REGS_INT_STAT1 0x9 +#define PIO2_REGS_INT_STAT2 0xa +#define PIO2_REGS_INT_STAT3 0xb + +static const int PIO2_REGS_INT_STAT[4] = { PIO2_REGS_INT_STAT0, + PIO2_REGS_INT_STAT1, + PIO2_REGS_INT_STAT2, + PIO2_REGS_INT_STAT3 }; + +#define PIO2_REGS_INT_STAT_CNTR 0xc +#define PIO2_REGS_INT_MASK0 0x10 +#define PIO2_REGS_INT_MASK1 0x11 +#define PIO2_REGS_INT_MASK2 0x12 +#define PIO2_REGS_INT_MASK3 0x13 +#define PIO2_REGS_INT_MASK4 0x14 +#define PIO2_REGS_INT_MASK5 0x15 +#define PIO2_REGS_INT_MASK6 0x16 +#define PIO2_REGS_INT_MASK7 0x17 + +static const int PIO2_REGS_INT_MASK[8] = { PIO2_REGS_INT_MASK0, + PIO2_REGS_INT_MASK1, + PIO2_REGS_INT_MASK2, + PIO2_REGS_INT_MASK3, + PIO2_REGS_INT_MASK4, + PIO2_REGS_INT_MASK5, + PIO2_REGS_INT_MASK6, + PIO2_REGS_INT_MASK7 }; + + + +#define PIO2_REGS_CTRL 0x18 +#define PIO2_REGS_VME_VECTOR 0x19 +#define PIO2_REGS_CNTR0 0x20 +#define PIO2_REGS_CNTR1 0x22 +#define PIO2_REGS_CNTR2 0x24 +#define PIO2_REGS_CTRL_WRD0 0x26 +#define PIO2_REGS_CNTR3 0x28 +#define PIO2_REGS_CNTR4 0x2a +#define PIO2_REGS_CNTR5 0x2c +#define PIO2_REGS_CTRL_WRD1 0x2e + +#define PIO2_REGS_ID 0x30 + + +/* PIO2_REGS_DATAx (0x0 - 0x3) */ + +static const int PIO2_CHANNEL_BANK[32] = { 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 }; + +#define PIO2_CHANNEL0_BIT (1 << 0) +#define PIO2_CHANNEL1_BIT (1 << 1) +#define PIO2_CHANNEL2_BIT (1 << 2) +#define PIO2_CHANNEL3_BIT (1 << 3) +#define PIO2_CHANNEL4_BIT (1 << 4) +#define PIO2_CHANNEL5_BIT (1 << 5) +#define PIO2_CHANNEL6_BIT (1 << 6) +#define PIO2_CHANNEL7_BIT (1 << 7) +#define PIO2_CHANNEL8_BIT (1 << 0) +#define PIO2_CHANNEL9_BIT (1 << 1) +#define PIO2_CHANNEL10_BIT (1 << 2) +#define PIO2_CHANNEL11_BIT (1 << 3) +#define PIO2_CHANNEL12_BIT (1 << 4) +#define PIO2_CHANNEL13_BIT (1 << 5) +#define PIO2_CHANNEL14_BIT (1 << 6) +#define PIO2_CHANNEL15_BIT (1 << 7) +#define PIO2_CHANNEL16_BIT (1 << 0) +#define PIO2_CHANNEL17_BIT (1 << 1) +#define PIO2_CHANNEL18_BIT (1 << 2) +#define PIO2_CHANNEL19_BIT (1 << 3) +#define PIO2_CHANNEL20_BIT (1 << 4) +#define PIO2_CHANNEL21_BIT (1 << 5) +#define PIO2_CHANNEL22_BIT (1 << 6) +#define PIO2_CHANNEL23_BIT (1 << 7) +#define PIO2_CHANNEL24_BIT (1 << 0) +#define PIO2_CHANNEL25_BIT (1 << 1) +#define PIO2_CHANNEL26_BIT (1 << 2) +#define PIO2_CHANNEL27_BIT (1 << 3) +#define PIO2_CHANNEL28_BIT (1 << 4) +#define PIO2_CHANNEL29_BIT (1 << 5) +#define PIO2_CHANNEL30_BIT (1 << 6) +#define PIO2_CHANNEL31_BIT (1 << 7) + +static const int PIO2_CHANNEL_BIT[32] = { PIO2_CHANNEL0_BIT, PIO2_CHANNEL1_BIT, + PIO2_CHANNEL2_BIT, PIO2_CHANNEL3_BIT, + PIO2_CHANNEL4_BIT, PIO2_CHANNEL5_BIT, + PIO2_CHANNEL6_BIT, PIO2_CHANNEL7_BIT, + PIO2_CHANNEL8_BIT, PIO2_CHANNEL9_BIT, + PIO2_CHANNEL10_BIT, PIO2_CHANNEL11_BIT, + PIO2_CHANNEL12_BIT, PIO2_CHANNEL13_BIT, + PIO2_CHANNEL14_BIT, PIO2_CHANNEL15_BIT, + PIO2_CHANNEL16_BIT, PIO2_CHANNEL17_BIT, + PIO2_CHANNEL18_BIT, PIO2_CHANNEL19_BIT, + PIO2_CHANNEL20_BIT, PIO2_CHANNEL21_BIT, + PIO2_CHANNEL22_BIT, PIO2_CHANNEL23_BIT, + PIO2_CHANNEL24_BIT, PIO2_CHANNEL25_BIT, + PIO2_CHANNEL26_BIT, PIO2_CHANNEL27_BIT, + PIO2_CHANNEL28_BIT, PIO2_CHANNEL29_BIT, + PIO2_CHANNEL30_BIT, PIO2_CHANNEL31_BIT + }; + +/* PIO2_REGS_INT_STAT_CNTR (0xc) */ +#define PIO2_COUNTER0 (1 << 0) +#define PIO2_COUNTER1 (1 << 1) +#define PIO2_COUNTER2 (1 << 2) +#define PIO2_COUNTER3 (1 << 3) +#define PIO2_COUNTER4 (1 << 4) +#define PIO2_COUNTER5 (1 << 5) + +static const int PIO2_COUNTER[6] = { PIO2_COUNTER0, PIO2_COUNTER1, + PIO2_COUNTER2, PIO2_COUNTER3, + PIO2_COUNTER4, PIO2_COUNTER5 }; + +/* PIO2_REGS_CTRL (0x18) */ +#define PIO2_VME_INT_MASK 0x7 +#define PIO2_LED (1 << 6) +#define PIO2_LOOP (1 << 7) + +/* PIO2_REGS_VME_VECTOR (0x19) */ +#define PIO2_VME_VECTOR_SPUR 0x0 +#define PIO2_VME_VECTOR_BANK0 0x1 +#define PIO2_VME_VECTOR_BANK1 0x2 +#define PIO2_VME_VECTOR_BANK2 0x3 +#define PIO2_VME_VECTOR_BANK3 0x4 +#define PIO2_VME_VECTOR_CNTR0 0x5 +#define PIO2_VME_VECTOR_CNTR1 0x6 +#define PIO2_VME_VECTOR_CNTR2 0x7 +#define PIO2_VME_VECTOR_CNTR3 0x8 +#define PIO2_VME_VECTOR_CNTR4 0x9 +#define PIO2_VME_VECTOR_CNTR5 0xa + +#define PIO2_VME_VECTOR_MASK 0xf0 + +static const int PIO2_VECTOR_BANK[4] = { PIO2_VME_VECTOR_BANK0, + PIO2_VME_VECTOR_BANK1, + PIO2_VME_VECTOR_BANK2, + PIO2_VME_VECTOR_BANK3 }; + +static const int PIO2_VECTOR_CNTR[6] = { PIO2_VME_VECTOR_CNTR0, + PIO2_VME_VECTOR_CNTR1, + PIO2_VME_VECTOR_CNTR2, + PIO2_VME_VECTOR_CNTR3, + PIO2_VME_VECTOR_CNTR4, + PIO2_VME_VECTOR_CNTR5 }; + +/* PIO2_REGS_CNTRx (0x20 - 0x24 & 0x28 - 0x2c) */ + +static const int PIO2_CNTR_DATA[6] = { PIO2_REGS_CNTR0, PIO2_REGS_CNTR1, + PIO2_REGS_CNTR2, PIO2_REGS_CNTR3, + PIO2_REGS_CNTR4, PIO2_REGS_CNTR5 }; + +/* PIO2_REGS_CTRL_WRDx (0x26 & 0x2e) */ + +static const int PIO2_CNTR_CTRL[6] = { PIO2_REGS_CTRL_WRD0, + PIO2_REGS_CTRL_WRD0, + PIO2_REGS_CTRL_WRD0, + PIO2_REGS_CTRL_WRD1, + PIO2_REGS_CTRL_WRD1, + PIO2_REGS_CTRL_WRD1 }; + +#define PIO2_CNTR_SC_DEV0 0 +#define PIO2_CNTR_SC_DEV1 (1 << 6) +#define PIO2_CNTR_SC_DEV2 (2 << 6) +#define PIO2_CNTR_SC_RDBACK (3 << 6) + +static const int PIO2_CNTR_SC_DEV[6] = { PIO2_CNTR_SC_DEV0, PIO2_CNTR_SC_DEV1, + PIO2_CNTR_SC_DEV2, PIO2_CNTR_SC_DEV0, + PIO2_CNTR_SC_DEV1, PIO2_CNTR_SC_DEV2 }; + +#define PIO2_CNTR_RW_LATCH 0 +#define PIO2_CNTR_RW_LSB (1 << 4) +#define PIO2_CNTR_RW_MSB (2 << 4) +#define PIO2_CNTR_RW_BOTH (3 << 4) + +#define PIO2_CNTR_MODE0 0 +#define PIO2_CNTR_MODE1 (1 << 1) +#define PIO2_CNTR_MODE2 (2 << 1) +#define PIO2_CNTR_MODE3 (3 << 1) +#define PIO2_CNTR_MODE4 (4 << 1) +#define PIO2_CNTR_MODE5 (5 << 1) + +#define PIO2_CNTR_BCD 1 + + + +enum pio2_bank_config { NOFIT, INPUT, OUTPUT, BOTH }; +enum pio2_int_config { NONE = 0, LOW2HIGH = 1, HIGH2LOW = 2, EITHER = 4 }; + +/* Bank configuration structure */ +struct pio2_io_bank { + enum pio2_bank_config config; + u8 value; + enum pio2_int_config irq[8]; +}; + +/* Counter configuration structure */ +struct pio2_cntr { + int mode; + int count; +}; + +struct pio2_card { + int id; + int bus; + long base; + int irq_vector; + int irq_level; + char variant[6]; + int led; + + struct vme_dev *vdev; + struct vme_resource *window; + + struct gpio_chip gc; + struct pio2_io_bank bank[4]; + + struct pio2_cntr cntr[6]; +}; + +int pio2_cntr_reset(struct pio2_card *); + +int pio2_gpio_reset(struct pio2_card *); +int __init pio2_gpio_init(struct pio2_card *); +void __exit pio2_gpio_exit(struct pio2_card *); + +#endif /* _VME_PIO2_H_ */ diff --git a/drivers/staging/vme/devices/vme_pio2_cntr.c b/drivers/staging/vme/devices/vme_pio2_cntr.c new file mode 100644 index 00000000000..08e0d59806c --- /dev/null +++ b/drivers/staging/vme/devices/vme_pio2_cntr.c @@ -0,0 +1,71 @@ +/* + * GE PIO2 Counter Driver + * + * Author: Martyn Welch <martyn.welch@ge.com> + * Copyright 2009 GE Intelligent Platforms Embedded Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * The PIO-2 has 6 counters, currently this code just disables the interrupts + * and leaves them alone. + * + */ + +#include <linux/device.h> +#include <linux/types.h> +#include <linux/gpio.h> + +#include "../vme.h" +#include "vme_pio2.h" + +static int pio2_cntr_irq_set(struct pio2_card *card, int id) +{ + int retval; + u8 data; + + data = PIO2_CNTR_SC_DEV[id] | PIO2_CNTR_RW_BOTH | card->cntr[id].mode; + retval = vme_master_write(card->window, &data, 1, PIO2_CNTR_CTRL[id]); + if (retval < 0) + return retval; + + data = card->cntr[id].count & 0xFF; + retval = vme_master_write(card->window, &data, 1, PIO2_CNTR_DATA[id]); + if (retval < 0) + return retval; + + data = (card->cntr[id].count >> 8) & 0xFF; + retval = vme_master_write(card->window, &data, 1, PIO2_CNTR_DATA[id]); + if (retval < 0) + return retval; + + return 0; +} + +int pio2_cntr_reset(struct pio2_card *card) +{ + int i, retval = 0; + u8 reg; + + /* Clear down all timers */ + for (i = 0; i < 6; i++) { + card->cntr[i].mode = PIO2_CNTR_MODE5; + card->cntr[i].count = 0; + retval = pio2_cntr_irq_set(card, i); + if (retval < 0) + return retval; + } + + /* Ensure all counter interrupts are cleared */ + do { + retval = vme_master_read(card->window, ®, 1, + PIO2_REGS_INT_STAT_CNTR); + if (retval < 0) + return retval; + } while (reg != 0); + + return retval; +} + diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c new file mode 100644 index 00000000000..9fedc442a77 --- /dev/null +++ b/drivers/staging/vme/devices/vme_pio2_core.c @@ -0,0 +1,524 @@ +/* + * GE PIO2 6U VME I/O Driver + * + * Author: Martyn Welch <martyn.welch@ge.com> + * Copyright 2009 GE Intelligent Platforms Embedded Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/device.h> +#include <linux/ctype.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include "../vme.h" +#include "vme_pio2.h" + + +static const char driver_name[] = "pio2"; + +static int bus[PIO2_CARDS_MAX]; +static int bus_num; +static long base[PIO2_CARDS_MAX]; +static int base_num; +static int vector[PIO2_CARDS_MAX]; +static int vector_num; +static int level[PIO2_CARDS_MAX]; +static int level_num; +static const char *variant[PIO2_CARDS_MAX]; +static int variant_num; + +static int loopback; + +static int pio2_match(struct vme_dev *); +static int __devinit pio2_probe(struct vme_dev *); +static int __devexit pio2_remove(struct vme_dev *); + +static int pio2_get_led(struct pio2_card *card) +{ + /* Can't read hardware, state saved in structure */ + return card->led; +} + +static int pio2_set_led(struct pio2_card *card, int state) +{ + u8 reg; + int retval; + + reg = card->irq_level; + + /* Register state inverse of led state */ + if (!state) + reg |= PIO2_LED; + + if (loopback) + reg |= PIO2_LOOP; + + retval = vme_master_write(card->window, ®, 1, PIO2_REGS_CTRL); + if (retval < 0) + return retval; + + card->led = state ? 1 : 0; + + return 0; +} + +static void pio2_int(int level, int vector, void *ptr) +{ + int vec, i, channel, retval; + u8 reg; + struct pio2_card *card = ptr; + + vec = vector & ~PIO2_VME_VECTOR_MASK; + + switch (vec) { + case 0: + dev_warn(&card->vdev->dev, "Spurious Interrupt\n"); + break; + case 1: + case 2: + case 3: + case 4: + /* Channels 0 to 7 */ + retval = vme_master_read(card->window, ®, 1, + PIO2_REGS_INT_STAT[vec - 1]); + if (retval < 0) { + dev_err(&card->vdev->dev, + "Unable to read IRQ status register\n"); + return; + } + for (i = 0; i < 8; i++) { + channel = ((vec - 1) * 8) + i; + if (reg & PIO2_CHANNEL_BIT[channel]) + dev_info(&card->vdev->dev, + "Interrupt on I/O channel %d\n", + channel); + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + /* Counters are dealt with by their own handler */ + dev_err(&card->vdev->dev, + "Counter interrupt\n"); + break; + } +} + + +/* + * We return whether this has been successful - this is used in the probe to + * ensure we have a valid card. + */ +static int pio2_reset_card(struct pio2_card *card) +{ + int retval = 0; + u8 data = 0; + + /* Clear main register*/ + retval = vme_master_write(card->window, &data, 1, PIO2_REGS_CTRL); + if (retval < 0) + return retval; + + /* Clear VME vector */ + retval = vme_master_write(card->window, &data, 1, PIO2_REGS_VME_VECTOR); + if (retval < 0) + return retval; + + /* Reset GPIO */ + retval = pio2_gpio_reset(card); + if (retval < 0) + return retval; + + /* Reset counters */ + retval = pio2_cntr_reset(card); + if (retval < 0) + return retval; + + return 0; +} + +static struct vme_driver pio2_driver = { + .name = driver_name, + .match = pio2_match, + .probe = pio2_probe, + .remove = __devexit_p(pio2_remove), +}; + + +static int __init pio2_init(void) +{ + int retval = 0; + + if (bus_num == 0) { + printk(KERN_ERR "%s: No cards, skipping registration\n", + driver_name); + goto err_nocard; + } + + if (bus_num > PIO2_CARDS_MAX) { + printk(KERN_ERR + "%s: Driver only able to handle %d PIO2 Cards\n", + driver_name, PIO2_CARDS_MAX); + bus_num = PIO2_CARDS_MAX; + } + + /* Register the PIO2 driver */ + retval = vme_register_driver(&pio2_driver, bus_num); + if (retval != 0) + goto err_reg; + + return retval; + +err_reg: +err_nocard: + return retval; +} + +static int pio2_match(struct vme_dev *vdev) +{ + + if (vdev->num >= bus_num) { + dev_err(&vdev->dev, + "The enumeration of the VMEbus to which the board is connected must be specified"); + return 0; + } + + if (vdev->num >= base_num) { + dev_err(&vdev->dev, + "The VME address for the cards registers must be specified"); + return 0; + } + + if (vdev->num >= vector_num) { + dev_err(&vdev->dev, + "The IRQ vector used by the card must be specified"); + return 0; + } + + if (vdev->num >= level_num) { + dev_err(&vdev->dev, + "The IRQ level used by the card must be specified"); + return 0; + } + + if (vdev->num >= variant_num) { + dev_err(&vdev->dev, "The variant of the card must be specified"); + return 0; + } + + return 1; +} + +static int __devinit pio2_probe(struct vme_dev *vdev) +{ + struct pio2_card *card; + int retval; + int i; + u8 reg; + int vec; + + card = kzalloc(sizeof(struct pio2_card), GFP_KERNEL); + if (card == NULL) { + dev_err(&vdev->dev, "Unable to allocate card structure\n"); + retval = -ENOMEM; + goto err_struct; + } + + card->id = vdev->num; + card->bus = bus[card->id]; + card->base = base[card->id]; + card->irq_vector = vector[card->id]; + card->irq_level = level[card->id] & PIO2_VME_INT_MASK; + strncpy(card->variant, variant[card->id], PIO2_VARIANT_LENGTH); + card->vdev = vdev; + + for (i = 0; i < PIO2_VARIANT_LENGTH; i++) { + + if (isdigit(card->variant[i]) == 0) { + dev_err(&card->vdev->dev, "Variant invalid\n"); + retval = -EINVAL; + goto err_variant; + } + } + + /* + * Bottom 4 bits of VME interrupt vector used to determine source, + * provided vector should only use upper 4 bits. + */ + if (card->irq_vector & ~PIO2_VME_VECTOR_MASK) { + dev_err(&card->vdev->dev, + "Invalid VME IRQ Vector, vector must not use lower 4 bits\n"); + retval = -EINVAL; + goto err_vector; + } + + /* + * There is no way to determine the build variant or whether each bank + * is input, output or both at run time. The inputs are also inverted + * if configured as both. + * + * We pass in the board variant and use that to determine the + * configuration of the banks. + */ + for (i = 1; i < PIO2_VARIANT_LENGTH; i++) { + switch (card->variant[i]) { + case '0': + card->bank[i-1].config = NOFIT; + break; + case '1': + case '2': + case '3': + case '4': + card->bank[i-1].config = INPUT; + break; + case '5': + card->bank[i-1].config = OUTPUT; + break; + case '6': + case '7': + case '8': + case '9': + card->bank[i-1].config = BOTH; + break; + } + } + + /* Get a master window and position over regs */ + card->window = vme_master_request(vdev, VME_A24, VME_SCT, VME_D16); + if (card->window == NULL) { + dev_err(&card->vdev->dev, + "Unable to assign VME master resource\n"); + retval = -EIO; + goto err_window; + } + + retval = vme_master_set(card->window, 1, card->base, 0x10000, VME_A24, + (VME_SCT | VME_USER | VME_DATA), VME_D16); + if (retval) { + dev_err(&card->vdev->dev, + "Unable to configure VME master resource\n"); + goto err_set; + } + + /* + * There is also no obvious register which we can probe to determine + * whether the provided base is valid. If we can read the "ID Register" + * offset and the reset function doesn't error, assume we have a valid + * location. + */ + retval = vme_master_read(card->window, ®, 1, PIO2_REGS_ID); + if (retval < 0) { + dev_err(&card->vdev->dev, "Unable to read from device\n"); + goto err_read; + } + + dev_dbg(&card->vdev->dev, "ID Register:%x\n", reg); + + /* + * Ensure all the I/O is cleared. We can't read back the states, so + * this is the only method we have to ensure that the I/O is in a known + * state. + */ + retval = pio2_reset_card(card); + if (retval) { + dev_err(&card->vdev->dev, + "Failed to reset card, is location valid?"); + retval = -ENODEV; + goto err_reset; + } + + /* Configure VME Interrupts */ + reg = card->irq_level; + if (pio2_get_led(card)) + reg |= PIO2_LED; + if (loopback) + reg |= PIO2_LOOP; + retval = vme_master_write(card->window, ®, 1, PIO2_REGS_CTRL); + if (retval < 0) + return retval; + + /* Set VME vector */ + retval = vme_master_write(card->window, &card->irq_vector, 1, + PIO2_REGS_VME_VECTOR); + if (retval < 0) + return retval; + + /* Attach spurious interrupt handler. */ + vec = card->irq_vector | PIO2_VME_VECTOR_SPUR; + + retval = vme_irq_request(vdev, card->irq_level, vec, + &pio2_int, (void *)card); + if (retval < 0) { + dev_err(&card->vdev->dev, + "Unable to attach VME interrupt vector0x%x, level 0x%x\n", + vec, card->irq_level); + goto err_irq; + } + + /* Attach GPIO interrupt handlers. */ + for (i = 0; i < 4; i++) { + vec = card->irq_vector | PIO2_VECTOR_BANK[i]; + + retval = vme_irq_request(vdev, card->irq_level, vec, + &pio2_int, (void *)card); + if (retval < 0) { + dev_err(&card->vdev->dev, + "Unable to attach VME interrupt vector0x%x, level 0x%x\n", + vec, card->irq_level); + goto err_gpio_irq; + } + } + + /* Attach counter interrupt handlers. */ + for (i = 0; i < 6; i++) { + vec = card->irq_vector | PIO2_VECTOR_CNTR[i]; + + retval = vme_irq_request(vdev, card->irq_level, vec, + &pio2_int, (void *)card); + if (retval < 0) { + dev_err(&card->vdev->dev, + "Unable to attach VME interrupt vector0x%x, level 0x%x\n", + vec, card->irq_level); + goto err_cntr_irq; + } + } + + /* Register IO */ + retval = pio2_gpio_init(card); + if (retval < 0) { + dev_err(&card->vdev->dev, + "Unable to register with GPIO framework\n"); + goto err_gpio; + } + + /* Set LED - This also sets interrupt level */ + retval = pio2_set_led(card, 0); + if (retval < 0) { + dev_err(&card->vdev->dev, "Unable to set LED\n"); + goto err_led; + } + + dev_set_drvdata(&card->vdev->dev, card); + + dev_info(&card->vdev->dev, + "PIO2 (variant %s) configured at 0x%lx\n", card->variant, + card->base); + + return 0; + +err_led: + pio2_gpio_exit(card); +err_gpio: + i = 6; +err_cntr_irq: + while (i > 0) { + i--; + vec = card->irq_vector | PIO2_VECTOR_CNTR[i]; + vme_irq_free(vdev, card->irq_level, vec); + } + + i = 4; +err_gpio_irq: + while (i > 0) { + i--; + vec = card->irq_vector | PIO2_VECTOR_BANK[i]; + vme_irq_free(vdev, card->irq_level, vec); + } + + vec = (card->irq_vector & PIO2_VME_VECTOR_MASK) | PIO2_VME_VECTOR_SPUR; + vme_irq_free(vdev, card->irq_level, vec); +err_irq: + pio2_reset_card(card); +err_reset: +err_read: + vme_master_set(card->window, 0, 0, 0, VME_A16, 0, VME_D16); +err_set: + vme_master_free(card->window); +err_window: +err_vector: +err_variant: + kfree(card); +err_struct: + return retval; +} + +static int __devexit pio2_remove(struct vme_dev *vdev) +{ + int vec; + int i; + + struct pio2_card *card = dev_get_drvdata(&vdev->dev); + + pio2_gpio_exit(card); + + for (i = 0; i < 6; i++) { + vec = card->irq_vector | PIO2_VECTOR_CNTR[i]; + vme_irq_free(vdev, card->irq_level, vec); + } + + for (i = 0; i < 4; i++) { + vec = card->irq_vector | PIO2_VECTOR_BANK[i]; + vme_irq_free(vdev, card->irq_level, vec); + } + + vec = (card->irq_vector & PIO2_VME_VECTOR_MASK) | PIO2_VME_VECTOR_SPUR; + vme_irq_free(vdev, card->irq_level, vec); + + pio2_reset_card(card); + + vme_master_set(card->window, 0, 0, 0, VME_A16, 0, VME_D16); + + vme_master_free(card->window); + + kfree(card); + + return 0; +} + +static void __exit pio2_exit(void) +{ + vme_unregister_driver(&pio2_driver); +} + + +/* These are required for each board */ +MODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the board is connected"); +module_param_array(bus, int, &bus_num, S_IRUGO); + +MODULE_PARM_DESC(base, "Base VME address for PIO2 Registers"); +module_param_array(base, long, &base_num, S_IRUGO); + +MODULE_PARM_DESC(vector, "VME IRQ Vector (Lower 4 bits masked)"); +module_param_array(vector, int, &vector_num, S_IRUGO); + +MODULE_PARM_DESC(level, "VME IRQ Level"); +module_param_array(level, int, &level_num, S_IRUGO); + +MODULE_PARM_DESC(variant, "Last 4 characters of PIO2 board variant"); +module_param_array(variant, charp, &variant_num, S_IRUGO); + +/* This is for debugging */ +MODULE_PARM_DESC(loopback, "Enable loopback mode on all cards"); +module_param(loopback, bool, S_IRUGO); + +MODULE_DESCRIPTION("GE PIO2 6U VME I/O Driver"); +MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); +MODULE_LICENSE("GPL"); + +module_init(pio2_init); +module_exit(pio2_exit); + diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c new file mode 100644 index 00000000000..dc837deb99d --- /dev/null +++ b/drivers/staging/vme/devices/vme_pio2_gpio.c @@ -0,0 +1,232 @@ +/* + * GE PIO2 GPIO Driver + * + * Author: Martyn Welch <martyn.welch@ge.com> + * Copyright 2009 GE Intelligent Platforms Embedded Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/ctype.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include "../vme.h" +#include "vme_pio2.h" + +static const char driver_name[] = "pio2_gpio"; + +static struct pio2_card *gpio_to_pio2_card(struct gpio_chip *chip) +{ + return container_of(chip, struct pio2_card, gc); +} + +static int pio2_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + u8 reg; + int retval; + struct pio2_card *card = gpio_to_pio2_card(chip); + + if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) | + (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { + + dev_err(&card->vdev->dev, "Channel not available as input\n"); + return 0; + } + + retval = vme_master_read(card->window, ®, 1, + PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]); + if (retval < 0) { + dev_err(&card->vdev->dev, "Unable to read from GPIO\n"); + return 0; + } + + /* + * Remember, input on channels configured as both input and output + * are inverted! + */ + if (reg & PIO2_CHANNEL_BIT[offset]) { + if (card->bank[PIO2_CHANNEL_BANK[offset]].config != BOTH) + return 0; + else + return 1; + } else { + if (card->bank[PIO2_CHANNEL_BANK[offset]].config != BOTH) + return 1; + else + return 0; + } +} + +static void pio2_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + u8 reg; + int retval; + struct pio2_card *card = gpio_to_pio2_card(chip); + + if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) | + (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { + + dev_err(&card->vdev->dev, "Channel not availabe as output\n"); + return; + } + + if (value) + reg = card->bank[PIO2_CHANNEL_BANK[offset]].value | + PIO2_CHANNEL_BIT[offset]; + else + reg = card->bank[PIO2_CHANNEL_BANK[offset]].value & + ~PIO2_CHANNEL_BIT[offset]; + + retval = vme_master_write(card->window, ®, 1, + PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]); + if (retval < 0) { + dev_err(&card->vdev->dev, "Unable to write to GPIO\n"); + return; + } + + card->bank[PIO2_CHANNEL_BANK[offset]].value = reg; +} + +/* Directionality configured at board build - send appropriate response */ +static int pio2_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + int data; + struct pio2_card *card = gpio_to_pio2_card(chip); + + if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) | + (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { + dev_err(&card->vdev->dev, + "Channel directionality not configurable at runtine\n"); + + data = -EINVAL; + } else { + data = 0; + } + + return data; +} + +/* Directionality configured at board build - send appropriate response */ +static int pio2_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) +{ + int data; + struct pio2_card *card = gpio_to_pio2_card(chip); + + if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) | + (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { + dev_err(&card->vdev->dev, + "Channel directionality not configurable at runtine\n"); + + data = -EINVAL; + } else { + data = 0; + } + + return data; +} + +/* + * We return whether this has been successful - this is used in the probe to + * ensure we have a valid card. + */ +int pio2_gpio_reset(struct pio2_card *card) +{ + int retval = 0; + int i, j; + + u8 data = 0; + + /* Zero output registers */ + for (i = 0; i < 4; i++) { + retval = vme_master_write(card->window, &data, 1, + PIO2_REGS_DATA[i]); + if (retval < 0) + return retval; + card->bank[i].value = 0; + } + + /* Set input interrupt masks */ + for (i = 0; i < 4; i++) { + retval = vme_master_write(card->window, &data, 1, + PIO2_REGS_INT_MASK[i * 2]); + if (retval < 0) + return retval; + + retval = vme_master_write(card->window, &data, 1, + PIO2_REGS_INT_MASK[(i * 2) + 1]); + if (retval < 0) + return retval; + + for (j = 0; j < 8; j++) + card->bank[i].irq[j] = NONE; + } + + /* Ensure all I/O interrupts are cleared */ + for (i = 0; i < 4; i++) { + do { + retval = vme_master_read(card->window, &data, 1, + PIO2_REGS_INT_STAT[i]); + if (retval < 0) + return retval; + } while (data != 0); + } + + return 0; +} + +int __init pio2_gpio_init(struct pio2_card *card) +{ + int retval = 0; + char *label; + + label = kmalloc(PIO2_NUM_CHANNELS, GFP_KERNEL); + if (label == NULL) { + dev_err(&card->vdev->dev, "Unable to allocate GPIO label\n"); + return -ENOMEM; + } + + sprintf(label, "%s@%s", driver_name, dev_name(&card->vdev->dev)); + card->gc.label = label; + + card->gc.ngpio = PIO2_NUM_CHANNELS; + /* Dynamic allocation of base */ + card->gc.base = -1; + /* Setup pointers to chip functions */ + card->gc.direction_input = pio2_gpio_dir_in; + card->gc.direction_output = pio2_gpio_dir_out; + card->gc.get = pio2_gpio_get; + card->gc.set = pio2_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = gpiochip_add(&(card->gc)); + if (retval) { + dev_err(&card->vdev->dev, "Unable to register GPIO\n"); + kfree(card->gc.label); + } + + return retval; +}; + +void __exit pio2_gpio_exit(struct pio2_card *card) +{ + const char *label = card->gc.label; + + if (gpiochip_remove(&(card->gc))) + dev_err(&card->vdev->dev, "Failed to remove GPIO"); + + kfree(label); +} + diff --git a/drivers/staging/vme/devices/vme_user.h b/drivers/staging/vme/devices/vme_user.h index d85a1e9dbe3..7d24cd6343e 100644 --- a/drivers/staging/vme/devices/vme_user.h +++ b/drivers/staging/vme/devices/vme_user.h @@ -10,9 +10,9 @@ struct vme_master { int enable; /* State of Window */ unsigned long long vme_addr; /* Starting Address on the VMEbus */ unsigned long long size; /* Window Size */ - vme_address_t aspace; /* Address Space */ - vme_cycle_t cycle; /* Cycle properties */ - vme_width_t dwidth; /* Maximum Data Width */ + u32 aspace; /* Address Space */ + u32 cycle; /* Cycle properties */ + u32 dwidth; /* Maximum Data Width */ #if 0 char prefetchEnable; /* Prefetch Read Enable State */ int prefetchSize; /* Prefetch Read Size (Cache Lines) */ @@ -34,8 +34,8 @@ struct vme_slave { int enable; /* State of Window */ unsigned long long vme_addr; /* Starting Address on the VMEbus */ unsigned long long size; /* Window Size */ - vme_address_t aspace; /* Address Space */ - vme_cycle_t cycle; /* Cycle properties */ + u32 aspace; /* Address Space */ + u32 cycle; /* Cycle properties */ #if 0 char wrPostEnable; /* Write Post State */ char rmwLock; /* Lock PCI during RMW Cycles */ diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c index b04b4688f70..70722ae5232 100644 --- a/drivers/staging/vme/vme.c +++ b/drivers/staging/vme/vme.c @@ -153,9 +153,7 @@ size_t vme_get_size(struct vme_resource *resource) int enabled, retval; unsigned long long base, size; dma_addr_t buf_base; - vme_address_t aspace; - vme_cycle_t cycle; - vme_width_t dwidth; + u32 aspace, cycle, dwidth; switch (resource->type) { case VME_MASTER: @@ -181,7 +179,7 @@ size_t vme_get_size(struct vme_resource *resource) } EXPORT_SYMBOL(vme_get_size); -static int vme_check_window(vme_address_t aspace, unsigned long long vme_base, +static int vme_check_window(u32 aspace, unsigned long long vme_base, unsigned long long size) { int retval = 0; @@ -232,8 +230,8 @@ static int vme_check_window(vme_address_t aspace, unsigned long long vme_base, * Request a slave image with specific attributes, return some unique * identifier. */ -struct vme_resource *vme_slave_request(struct vme_dev *vdev, - vme_address_t address, vme_cycle_t cycle) +struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, + u32 cycle) { struct vme_bridge *bridge; struct list_head *slave_pos = NULL; @@ -298,7 +296,7 @@ EXPORT_SYMBOL(vme_slave_request); int vme_slave_set(struct vme_resource *resource, int enabled, unsigned long long vme_base, unsigned long long size, - dma_addr_t buf_base, vme_address_t aspace, vme_cycle_t cycle) + dma_addr_t buf_base, u32 aspace, u32 cycle) { struct vme_bridge *bridge = find_bridge(resource); struct vme_slave_resource *image; @@ -333,7 +331,7 @@ EXPORT_SYMBOL(vme_slave_set); int vme_slave_get(struct vme_resource *resource, int *enabled, unsigned long long *vme_base, unsigned long long *size, - dma_addr_t *buf_base, vme_address_t *aspace, vme_cycle_t *cycle) + dma_addr_t *buf_base, u32 *aspace, u32 *cycle) { struct vme_bridge *bridge = find_bridge(resource); struct vme_slave_resource *image; @@ -388,8 +386,8 @@ EXPORT_SYMBOL(vme_slave_free); * Request a master image with specific attributes, return some unique * identifier. */ -struct vme_resource *vme_master_request(struct vme_dev *vdev, - vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth) +struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, + u32 cycle, u32 dwidth) { struct vme_bridge *bridge; struct list_head *master_pos = NULL; @@ -456,8 +454,8 @@ err_bus: EXPORT_SYMBOL(vme_master_request); int vme_master_set(struct vme_resource *resource, int enabled, - unsigned long long vme_base, unsigned long long size, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) + unsigned long long vme_base, unsigned long long size, u32 aspace, + u32 cycle, u32 dwidth) { struct vme_bridge *bridge = find_bridge(resource); struct vme_master_resource *image; @@ -492,8 +490,8 @@ int vme_master_set(struct vme_resource *resource, int enabled, EXPORT_SYMBOL(vme_master_set); int vme_master_get(struct vme_resource *resource, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) + unsigned long long *vme_base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *dwidth) { struct vme_bridge *bridge = find_bridge(resource); struct vme_master_resource *image; @@ -646,8 +644,7 @@ EXPORT_SYMBOL(vme_master_free); * Request a DMA controller with specific attributes, return some unique * identifier. */ -struct vme_resource *vme_dma_request(struct vme_dev *vdev, - vme_dma_route_t route) +struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) { struct vme_bridge *bridge; struct list_head *dma_pos = NULL; @@ -743,8 +740,7 @@ EXPORT_SYMBOL(vme_new_dma_list); /* * Create "Pattern" type attributes */ -struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, - vme_pattern_t type) +struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) { struct vme_dma_attr *attributes; struct vme_dma_pattern *pattern_attr; @@ -822,7 +818,7 @@ EXPORT_SYMBOL(vme_dma_pci_attribute); * Create "VME" type attributes */ struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) + u32 aspace, u32 cycle, u32 dwidth) { struct vme_dma_attr *attributes; struct vme_dma_vme *vme_attr; @@ -1173,7 +1169,7 @@ int vme_lm_count(struct vme_resource *resource) EXPORT_SYMBOL(vme_lm_count); int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, - vme_address_t aspace, vme_cycle_t cycle) + u32 aspace, u32 cycle) { struct vme_bridge *bridge = find_bridge(resource); struct vme_lm_resource *lm; @@ -1195,7 +1191,7 @@ int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, EXPORT_SYMBOL(vme_lm_set); int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, - vme_address_t *aspace, vme_cycle_t *cycle) + u32 *aspace, u32 *cycle) { struct vme_bridge *bridge = find_bridge(resource); struct vme_lm_resource *lm; @@ -1307,7 +1303,12 @@ EXPORT_SYMBOL(vme_slot_get); /* - Bridge Registration --------------------------------------------------- */ -static int vme_add_bus(struct vme_bridge *bridge) +static void vme_dev_release(struct device *dev) +{ + kfree(dev_to_vme_dev(dev)); +} + +int vme_register_bridge(struct vme_bridge *bridge) { int i; int ret = -1; @@ -1327,8 +1328,9 @@ static int vme_add_bus(struct vme_bridge *bridge) return ret; } +EXPORT_SYMBOL(vme_register_bridge); -static void vme_remove_bus(struct vme_bridge *bridge) +void vme_unregister_bridge(struct vme_bridge *bridge) { struct vme_dev *vdev; struct vme_dev *tmp; @@ -1343,22 +1345,6 @@ static void vme_remove_bus(struct vme_bridge *bridge) list_del(&bridge->bus_list); mutex_unlock(&vme_buses_lock); } - -static void vme_dev_release(struct device *dev) -{ - kfree(dev_to_vme_dev(dev)); -} - -int vme_register_bridge(struct vme_bridge *bridge) -{ - return vme_add_bus(bridge); -} -EXPORT_SYMBOL(vme_register_bridge); - -void vme_unregister_bridge(struct vme_bridge *bridge) -{ - vme_remove_bus(bridge); -} EXPORT_SYMBOL(vme_unregister_bridge); /* - Driver Registration --------------------------------------------------- */ @@ -1421,10 +1407,7 @@ static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) * and if the bridge is removed, it will have to go through * vme_unregister_bridge() to do it (which calls remove() on * the bridge which in turn tries to acquire vme_buses_lock and - * will have to wait). The probe() called after device - * registration in __vme_register_driver below will also fail - * as the bridge is being removed (since the probe() calls - * vme_bridge_get()). + * will have to wait). */ err = __vme_register_driver_bus(drv, bridge, ndevs); if (err) diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h index e3828badca6..9d38ceed60e 100644 --- a/drivers/staging/vme/vme.h +++ b/drivers/staging/vme/vme.h @@ -10,7 +10,6 @@ enum vme_resource_type { }; /* VME Address Spaces */ -typedef u32 vme_address_t; #define VME_A16 0x1 #define VME_A24 0x2 #define VME_A32 0x4 @@ -29,7 +28,6 @@ typedef u32 vme_address_t; /* VME Cycle Types */ -typedef u32 vme_cycle_t; #define VME_SCT 0x1 #define VME_BLT 0x2 #define VME_MBLT 0x4 @@ -47,28 +45,23 @@ typedef u32 vme_cycle_t; #define VME_DATA 0x8000 /* VME Data Widths */ -typedef u32 vme_width_t; #define VME_D8 0x1 #define VME_D16 0x2 #define VME_D32 0x4 #define VME_D64 0x8 /* Arbitration Scheduling Modes */ -typedef u32 vme_arbitration_t; #define VME_R_ROBIN_MODE 0x1 #define VME_PRIORITY_MODE 0x2 -typedef u32 vme_dma_t; #define VME_DMA_PATTERN (1<<0) #define VME_DMA_PCI (1<<1) #define VME_DMA_VME (1<<2) -typedef u32 vme_pattern_t; #define VME_DMA_PATTERN_BYTE (1<<0) #define VME_DMA_PATTERN_WORD (1<<1) #define VME_DMA_PATTERN_INCREMENT (1<<2) -typedef u32 vme_dma_route_t; #define VME_DMA_VME_TO_MEM (1<<0) #define VME_DMA_MEM_TO_VME (1<<1) #define VME_DMA_VME_TO_VME (1<<2) @@ -77,7 +70,7 @@ typedef u32 vme_dma_route_t; #define VME_DMA_PATTERN_TO_MEM (1<<5) struct vme_dma_attr { - vme_dma_t type; + u32 type; void *private; }; @@ -97,7 +90,7 @@ extern struct bus_type vme_bus_type; /** * Structure representing a VME device - * @id: The ID of the device (currently the bus and slot number) + * @num: The device number * @bridge: Pointer to the bridge device this device is on * @dev: Internal device structure * @drv_list: List of devices (per driver) @@ -128,32 +121,29 @@ void vme_free_consistent(struct vme_resource *, size_t, void *, size_t vme_get_size(struct vme_resource *); -struct vme_resource *vme_slave_request(struct vme_dev *, vme_address_t, - vme_cycle_t); +struct vme_resource *vme_slave_request(struct vme_dev *, u32, u32); int vme_slave_set(struct vme_resource *, int, unsigned long long, - unsigned long long, dma_addr_t, vme_address_t, vme_cycle_t); + unsigned long long, dma_addr_t, u32, u32); int vme_slave_get(struct vme_resource *, int *, unsigned long long *, - unsigned long long *, dma_addr_t *, vme_address_t *, vme_cycle_t *); + unsigned long long *, dma_addr_t *, u32 *, u32 *); void vme_slave_free(struct vme_resource *); -struct vme_resource *vme_master_request(struct vme_dev *, vme_address_t, - vme_cycle_t, vme_width_t); +struct vme_resource *vme_master_request(struct vme_dev *, u32, u32, u32); int vme_master_set(struct vme_resource *, int, unsigned long long, - unsigned long long, vme_address_t, vme_cycle_t, vme_width_t); + unsigned long long, u32, u32, u32); int vme_master_get(struct vme_resource *, int *, unsigned long long *, - unsigned long long *, vme_address_t *, vme_cycle_t *, vme_width_t *); + unsigned long long *, u32 *, u32 *, u32 *); ssize_t vme_master_read(struct vme_resource *, void *, size_t, loff_t); ssize_t vme_master_write(struct vme_resource *, void *, size_t, loff_t); unsigned int vme_master_rmw(struct vme_resource *, unsigned int, unsigned int, unsigned int, loff_t); void vme_master_free(struct vme_resource *); -struct vme_resource *vme_dma_request(struct vme_dev *, vme_dma_route_t); +struct vme_resource *vme_dma_request(struct vme_dev *, u32); struct vme_dma_list *vme_new_dma_list(struct vme_resource *); -struct vme_dma_attr *vme_dma_pattern_attribute(u32, vme_pattern_t); +struct vme_dma_attr *vme_dma_pattern_attribute(u32, u32); struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t); -struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long, vme_address_t, - vme_cycle_t, vme_width_t); +struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long, u32, u32, u32); void vme_dma_free_attribute(struct vme_dma_attr *); int vme_dma_list_add(struct vme_dma_list *, struct vme_dma_attr *, struct vme_dma_attr *, size_t); @@ -168,10 +158,8 @@ int vme_irq_generate(struct vme_dev *, int, int); struct vme_resource * vme_lm_request(struct vme_dev *); int vme_lm_count(struct vme_resource *); -int vme_lm_set(struct vme_resource *, unsigned long long, vme_address_t, - vme_cycle_t); -int vme_lm_get(struct vme_resource *, unsigned long long *, vme_address_t *, - vme_cycle_t *); +int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32); +int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *); int vme_lm_attach(struct vme_resource *, int, void (*callback)(int)); int vme_lm_detach(struct vme_resource *, int); void vme_lm_free(struct vme_resource *); diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt index e8ff2151a48..856efa35f6e 100644 --- a/drivers/staging/vme/vme_api.txt +++ b/drivers/staging/vme/vme_api.txt @@ -86,26 +86,26 @@ driver allows a resource to be assigned based on the required attributes of the driver in question: struct vme_resource * vme_master_request(struct vme_dev *dev, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t width); - - struct vme_resource * vme_slave_request(struct vme_dev *dev, - vme_address_t aspace, vme_cycle_t cycle); - - struct vme_resource *vme_dma_request(struct vme_dev *dev, - vme_dma_route_t route); - -For slave windows these attributes are split into those of type 'vme_address_t' -and 'vme_cycle_t'. Master windows add a further set of attributes -'vme_cycle_t'. These attributes are defined as bitmasks and as such any -combination of the attributes can be requested for a single window, the core -will assign a window that meets the requirements, returning a pointer of type -vme_resource that should be used to identify the allocated resource when it is -used. For DMA controllers, the request function requires the potential -direction of any transfers to be provided in the route attributes. This is -typically VME-to-MEM and/or MEM-to-VME, though some hardware can support -VME-to-VME and MEM-to-MEM transfers as well as test pattern generation. If an -unallocated window fitting the requirements can not be found a NULL pointer -will be returned. + u32 aspace, u32 cycle, u32 width); + + struct vme_resource * vme_slave_request(struct vme_dev *dev, u32 aspace, + u32 cycle); + + struct vme_resource *vme_dma_request(struct vme_dev *dev, u32 route); + +For slave windows these attributes are split into the VME address spaces that +need to be accessed in 'aspace' and VME bus cycle types required in 'cycle'. +Master windows add a further set of attributes in 'width' specifying the +required data transfer widths. These attributes are defined as bitmasks and as +such any combination of the attributes can be requested for a single window, +the core will assign a window that meets the requirements, returning a pointer +of type vme_resource that should be used to identify the allocated resource +when it is used. For DMA controllers, the request function requires the +potential direction of any transfers to be provided in the route attributes. +This is typically VME-to-MEM and/or MEM-to-VME, though some hardware can +support VME-to-VME and MEM-to-MEM transfers as well as test pattern generation. +If an unallocated window fitting the requirements can not be found a NULL +pointer will be returned. Functions are also provided to free window allocations once they are no longer required. These functions should be passed the pointer to the resource provided @@ -133,12 +133,12 @@ Once a master window has been assigned the following functions can be used to configure it and retrieve the current settings: int vme_master_set (struct vme_resource *res, int enabled, - unsigned long long base, unsigned long long size, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t width); + unsigned long long base, unsigned long long size, u32 aspace, + u32 cycle, u32 width); int vme_master_get (struct vme_resource *res, int *enabled, - unsigned long long *base, unsigned long long *size, - vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *width); + unsigned long long *base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *width); The address spaces, transfer widths and cycle types are the same as described under resource management, however some of the options are mutually exclusive. @@ -189,11 +189,11 @@ configure it and retrieve the current settings: int vme_slave_set (struct vme_resource *res, int enabled, unsigned long long base, unsigned long long size, - dma_addr_t mem, vme_address_t aspace, vme_cycle_t cycle); + dma_addr_t mem, u32 aspace, u32 cycle); int vme_slave_get (struct vme_resource *res, int *enabled, unsigned long long *base, unsigned long long *size, - dma_addr_t *mem, vme_address_t *aspace, vme_cycle_t *cycle); + dma_addr_t *mem, u32 *aspace, u32 *cycle); The address spaces, transfer widths and cycle types are the same as described under resource management, however some of the options are mutually exclusive. @@ -273,8 +273,7 @@ and pattern sources and destinations (where appropriate): Pattern source: - struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, - vme_pattern_t type); + struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type); PCI source or destination: @@ -283,7 +282,7 @@ PCI source or destination: VME source or destination: struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long base, - vme_address_t aspace, vme_cycle_t cycle, vme_width_t width); + u32 aspace, u32 cycle, u32 width); The following function should be used to free an attribute: @@ -366,10 +365,10 @@ Once a bank of location monitors has been allocated, the following functions are provided to configure the location and mode of the location monitor: int vme_lm_set(struct vme_resource *res, unsigned long long base, - vme_address_t aspace, vme_cycle_t cycle); + u32 aspace, u32 cycle); int vme_lm_get(struct vme_resource *res, unsigned long long *base, - vme_address_t *aspace, vme_cycle_t *cycle); + u32 *aspace, u32 *cycle); Location Monitor Use diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h index c2deda2c38d..934949abd74 100644 --- a/drivers/staging/vme/vme_bridge.h +++ b/drivers/staging/vme/vme_bridge.h @@ -15,9 +15,9 @@ struct vme_master_resource { spinlock_t lock; int locked; int number; - vme_address_t address_attr; - vme_cycle_t cycle_attr; - vme_width_t width_attr; + u32 address_attr; + u32 cycle_attr; + u32 width_attr; struct resource bus_resource; void __iomem *kern_base; }; @@ -28,13 +28,13 @@ struct vme_slave_resource { struct mutex mtx; int locked; int number; - vme_address_t address_attr; - vme_cycle_t cycle_attr; + u32 address_attr; + u32 cycle_attr; }; struct vme_dma_pattern { u32 pattern; - vme_pattern_t type; + u32 type; }; struct vme_dma_pci { @@ -43,9 +43,9 @@ struct vme_dma_pci { struct vme_dma_vme { unsigned long long address; - vme_address_t aspace; - vme_cycle_t cycle; - vme_width_t dwidth; + u32 aspace; + u32 cycle; + u32 dwidth; }; struct vme_dma_list { @@ -63,7 +63,7 @@ struct vme_dma_resource { int number; struct list_head pending; struct list_head running; - vme_dma_route_t route_attr; + u32 route_attr; }; struct vme_lm_resource { @@ -122,17 +122,16 @@ struct vme_bridge { /* Slave Functions */ int (*slave_get) (struct vme_slave_resource *, int *, unsigned long long *, unsigned long long *, dma_addr_t *, - vme_address_t *, vme_cycle_t *); + u32 *, u32 *); int (*slave_set) (struct vme_slave_resource *, int, unsigned long long, - unsigned long long, dma_addr_t, vme_address_t, vme_cycle_t); + unsigned long long, dma_addr_t, u32, u32); /* Master Functions */ int (*master_get) (struct vme_master_resource *, int *, - unsigned long long *, unsigned long long *, vme_address_t *, - vme_cycle_t *, vme_width_t *); + unsigned long long *, unsigned long long *, u32 *, u32 *, + u32 *); int (*master_set) (struct vme_master_resource *, int, - unsigned long long, unsigned long long, vme_address_t, - vme_cycle_t, vme_width_t); + unsigned long long, unsigned long long, u32, u32, u32); ssize_t (*master_read) (struct vme_master_resource *, void *, size_t, loff_t); ssize_t (*master_write) (struct vme_master_resource *, void *, size_t, @@ -151,10 +150,9 @@ struct vme_bridge { int (*irq_generate) (struct vme_bridge *, int, int); /* Location monitor functions */ - int (*lm_set) (struct vme_lm_resource *, unsigned long long, - vme_address_t, vme_cycle_t); - int (*lm_get) (struct vme_lm_resource *, unsigned long long *, - vme_address_t *, vme_cycle_t *); + int (*lm_set) (struct vme_lm_resource *, unsigned long long, u32, u32); + int (*lm_get) (struct vme_lm_resource *, unsigned long long *, u32 *, + u32 *); int (*lm_attach) (struct vme_lm_resource *, int, void (*callback)(int)); int (*lm_detach) (struct vme_lm_resource *, int); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index d8dd7846447..3e8283c2dc7 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -3153,11 +3153,7 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { break; case SIOCGIWNWID: //0x8b03 support - #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT - rc = iwctl_giwnwid(dev, NULL, &(wrq->u.nwid), NULL); - #else - rc = -EOPNOTSUPP; - #endif + rc = -EOPNOTSUPP; break; // Set frequency/channel diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c index 432a20993c6..7fd5cc5a55f 100644 --- a/drivers/staging/vt6655/ioctl.c +++ b/drivers/staging/vt6655/ioctl.c @@ -300,6 +300,10 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EFAULT; break; } + if (sList.uItem > (ULONG_MAX - sizeof(SBSSIDList)) / sizeof(SBSSIDItem)) { + result = -EINVAL; + break; + } pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC); if (pList == NULL) { result = -ENOMEM; @@ -571,6 +575,10 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EFAULT; break; } + if (sNodeList.uItem > (ULONG_MAX - sizeof(SNodeList)) / sizeof(SNodeItem)) { + result = -EINVAL; + break; + } pNodeList = (PSNodeList)kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC); if (pNodeList == NULL) { result = -ENOMEM; diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c index 5e425d1476b..87288db2178 100644 --- a/drivers/staging/vt6655/iwctl.c +++ b/drivers/staging/vt6655/iwctl.c @@ -151,18 +151,6 @@ int iwctl_giwname(struct net_device *dev, return 0; } -int iwctl_giwnwid(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, - char *extra) -{ - //wrq->value = 0x100; - //wrq->disabled = 0; - //wrq->fixed = 1; - //return 0; - return -EOPNOTSUPP; -} - /* * Wireless Handler : set scan */ diff --git a/drivers/staging/vt6655/iwctl.h b/drivers/staging/vt6655/iwctl.h index 3096de0ba1b..d224f913a62 100644 --- a/drivers/staging/vt6655/iwctl.h +++ b/drivers/staging/vt6655/iwctl.h @@ -79,11 +79,6 @@ int iwctl_giwname(struct net_device *dev, char *wrq, char *extra); -int iwctl_giwnwid(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, - char *extra) ; - int iwctl_giwsens(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, diff --git a/drivers/staging/vt6656/80211mgr.c b/drivers/staging/vt6656/80211mgr.c index fceec4999c3..39f98423dc0 100644 --- a/drivers/staging/vt6656/80211mgr.c +++ b/drivers/staging/vt6656/80211mgr.c @@ -224,8 +224,6 @@ vMgrDecodeBeacon( } pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); } - - return; } @@ -248,8 +246,6 @@ vMgrEncodeIBSSATIM( { pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; pFrame->len = WLAN_HDR_ADDR3_LEN; - - return; } @@ -270,8 +266,6 @@ vMgrDecodeIBSSATIM( ) { pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; - - return; } @@ -298,8 +292,6 @@ vMgrEncodeDisassociation( pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_DISASSOC_OFF_REASON); pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason)); - - return; } @@ -324,8 +316,6 @@ vMgrDecodeDisassociation( /* Fixed Fields */ pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_DISASSOC_OFF_REASON); - - return; } /*+ @@ -352,7 +342,6 @@ vMgrEncodeAssocRequest( pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_ASSOCREQ_OFF_LISTEN_INT); pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT + sizeof(*(pFrame->pwListenInterval)); - return; } @@ -418,7 +407,6 @@ vMgrDecodeAssocRequest( } pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); } - return; } /*+ @@ -448,8 +436,6 @@ vMgrEncodeAssocResponse( + WLAN_ASSOCRESP_OFF_AID); pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid)); - - return; } @@ -491,10 +477,8 @@ vMgrDecodeAssocResponse( if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) { pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem); - } else { + } else pFrame->pExtSuppRates = NULL; - } - return; } @@ -524,8 +508,6 @@ vMgrEncodeReassocRequest( pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_REASSOCREQ_OFF_CURR_AP); pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCREQ_OFF_CURR_AP + sizeof(*(pFrame->pAddrCurrAP)); - - return; } @@ -578,10 +560,9 @@ vMgrDecodeReassocRequest( pFrame->pRSN = (PWLAN_IE_RSN)pItem; break; case WLAN_EID_RSN_WPA: - if (pFrame->pRSNWPA == NULL) { + if (pFrame->pRSNWPA == NULL) if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE) pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem; - } break; case WLAN_EID_EXTSUPP_RATES: @@ -595,7 +576,6 @@ vMgrDecodeReassocRequest( } pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); } - return; } @@ -619,7 +599,6 @@ vMgrEncodeProbeRequest( { pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; pFrame->len = WLAN_HDR_ADDR3_LEN; - return; } /*+ @@ -670,7 +649,6 @@ vMgrDecodeProbeRequest( pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); } - return; } @@ -703,8 +681,6 @@ vMgrEncodeProbeResponse( pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_PROBERESP_OFF_CAP_INFO + sizeof(*(pFrame->pwCapInfo)); - - return; } @@ -818,7 +794,6 @@ vMgrDecodeProbeResponse( pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); } - return; } @@ -848,7 +823,6 @@ vMgrEncodeAuthen( pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_AUTHEN_OFF_STATUS); pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus)); - return; } @@ -886,7 +860,6 @@ vMgrDecodeAuthen( if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem; - return; } @@ -912,7 +885,6 @@ vMgrEncodeDeauthen( pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_DEAUTHEN_OFF_REASON); pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason)); - return; } @@ -937,7 +909,6 @@ vMgrDecodeDeauthen( /* Fixed Fields */ pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_DEAUTHEN_OFF_REASON); - return; } @@ -968,7 +939,6 @@ vMgrEncodeReassocResponse( + WLAN_REASSOCRESP_OFF_AID); pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid)); - return; } @@ -1010,5 +980,4 @@ vMgrDecodeReassocResponse( if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; - return; } diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c index 0d11147f91c..06f27f624db 100644 --- a/drivers/staging/vt6656/baseband.c +++ b/drivers/staging/vt6656/baseband.c @@ -932,30 +932,8 @@ BBvCaculateParameter ( void BBvSetAntennaMode (PSDevice pDevice, BYTE byAntennaMode) { - //{{ RobertYu: 20041124, ABG Mode, VC1/VC2 define, make the ANT_A, ANT_B inverted - /*if ( (pDevice->byRFType == RF_MAXIM2829) || - (pDevice->byRFType == RF_UW2452) || - (pDevice->byRFType == RF_AIROHA7230) ) { // RobertYu: 20041210, 20050104 - - switch (byAntennaMode) { - case ANT_TXA: - byAntennaMode = ANT_TXB; - break; - case ANT_TXB: - byAntennaMode = ANT_TXA; - break; - case ANT_RXA: - byAntennaMode = ANT_RXB; - break; - case ANT_RXB: - byAntennaMode = ANT_RXA; - break; - } - }*/ - switch (byAntennaMode) { case ANT_TXA: - break; case ANT_TXB: break; case ANT_RXA: @@ -1249,8 +1227,7 @@ void BBvLoopbackOff (PSDevice pDevice) // Set the CR33 Bit2 to disable internal Loopback. ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x21, &byData);//CR33 ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x21, (BYTE)(byData & 0xFE));//CR33 - } - else { // OFDM + } else { /* OFDM */ ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x9A, &byData);//CR154 ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x9A, (BYTE)(byData & 0xFE));//CR154 } @@ -1277,19 +1254,16 @@ BBvSetShortSlotTime (PSDevice pDevice) { BYTE byBBVGA=0; - if (pDevice->bShortSlotTime) { + if (pDevice->bShortSlotTime) pDevice->byBBRxConf &= 0xDF;//1101 1111 - } else { + else pDevice->byBBRxConf |= 0x20;//0010 0000 - } ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0xE7, &byBBVGA); - if (byBBVGA == pDevice->abyBBVGA[0]) { + if (byBBVGA == pDevice->abyBBVGA[0]) pDevice->byBBRxConf |= 0x20;//0010 0000 - } ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x0A, pDevice->byBBRxConf); - } @@ -1299,13 +1273,11 @@ void BBvSetVGAGainOffset(PSDevice pDevice, BYTE byData) ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xE7, byData); // patch for 3253B0 Baseband with Cardbus module - if (byData == pDevice->abyBBVGA[0]) { - pDevice->byBBRxConf |= 0x20;//0010 0000 - } else if (pDevice->bShortSlotTime) { - pDevice->byBBRxConf &= 0xDF;//1101 1111 - } else { - pDevice->byBBRxConf |= 0x20;//0010 0000 - } + if (pDevice->bShortSlotTime) + pDevice->byBBRxConf &= 0xDF; /* 1101 1111 */ + else + pDevice->byBBRxConf |= 0x20; /* 0010 0000 */ + ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x0A, pDevice->byBBRxConf);//CR10 } @@ -1365,15 +1337,14 @@ static unsigned long s_ulGetLowSQ3(PSDevice pDevice) unsigned long ulMaxPacket; ulMaxPacket = pDevice->aulPktNum[RATE_54M]; - if ( pDevice->aulPktNum[RATE_54M] != 0 ) { + if (pDevice->aulPktNum[RATE_54M] != 0) ulSQ3 = pDevice->aulSQ3Val[RATE_54M] / pDevice->aulPktNum[RATE_54M]; - } - for ( ii=RATE_48M;ii>=RATE_6M;ii-- ) { - if ( pDevice->aulPktNum[ii] > ulMaxPacket ) { + + for (ii = RATE_48M; ii >= RATE_6M; ii--) + if (pDevice->aulPktNum[ii] > ulMaxPacket) { ulMaxPacket = pDevice->aulPktNum[ii]; ulSQ3 = pDevice->aulSQ3Val[ii] / pDevice->aulPktNum[ii]; } - } return ulSQ3; } @@ -1392,7 +1363,7 @@ static unsigned long s_ulGetRatio(PSDevice pDevice) ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); ulRatio += TOP_RATE_54M; } - for ( ii=RATE_48M;ii>=RATE_1M;ii-- ) { + for (ii = RATE_48M; ii >= RATE_1M; ii--) if ( pDevice->aulPktNum[ii] > ulMaxPacket ) { ulPacketNum = 0; for ( jj=RATE_54M;jj>=ii;jj--) @@ -1402,8 +1373,6 @@ static unsigned long s_ulGetRatio(PSDevice pDevice) ulMaxPacket = pDevice->aulPktNum[ii]; } - } - return ulRatio; } @@ -1589,7 +1558,6 @@ void TimerSQ3CallBack(void *hDeviceContext) spin_unlock_irq(&pDevice->lock); - return; } @@ -1637,7 +1605,6 @@ void TimerSQ3Tmax3CallBack(void *hDeviceContext) add_timer(&pDevice->TimerSQ3Tmax1); spin_unlock_irq(&pDevice->lock); - return; } void diff --git a/drivers/staging/vt6656/bssdb.c b/drivers/staging/vt6656/bssdb.c index af006df4c8e..32c67ed8435 100644 --- a/drivers/staging/vt6656/bssdb.c +++ b/drivers/staging/vt6656/bssdb.c @@ -216,26 +216,6 @@ PKnownBSS BSSpSearchBSSList(void *hDeviceContext, continue; } } -/* - if (pMgmt->eAuthenMode < WMAC_AUTH_WPA) { - if (pCurrBSS->bWPAValid == TRUE) { - // WPA AP will reject connection of station without WPA enable. - continue; - } - } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) || - (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) { - if (pCurrBSS->bWPAValid == FALSE) { - // station with WPA enable can't join NonWPA AP. - continue; - } - } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || - (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { - if (pCurrBSS->bWPA2Valid == FALSE) { - // station with WPA2 enable can't join NonWPA2 AP. - continue; - } - } -*/ pMgmt->pSameBSS[jj].uChannel = pCurrBSS->uChannel; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSpSearchBSSList pSelect1[%02X %02X %02X-%02X %02X %02X]\n",*pCurrBSS->abyBSSID,*(pCurrBSS->abyBSSID+1),*(pCurrBSS->abyBSSID+2),*(pCurrBSS->abyBSSID+3),*(pCurrBSS->abyBSSID+4),*(pCurrBSS->abyBSSID+5)); @@ -300,18 +280,11 @@ void BSSvClearBSSList(void *hDeviceContext, BOOL bKeepCurrBSSID) continue; } } -/* - if ((pMgmt->sBSSList[ii].bActive) && (pMgmt->sBSSList[ii].uClearCount < BSS_CLEAR_COUNT)) { - pMgmt->sBSSList[ii].uClearCount ++; - continue; - } -*/ - pMgmt->sBSSList[ii].bActive = FALSE; + + pMgmt->sBSSList[ii].bActive = FALSE; memset(&pMgmt->sBSSList[ii], 0, sizeof(KnownBSS)); } BSSvClearAnyBSSJoinRecord(pDevice); - - return; } @@ -524,46 +497,6 @@ BOOL BSSbInsertToBSSList(void *hDeviceContext, pBSSList->ldBmAverage[ii] = 0; } -/* - if ((pIE_Country != NULL) && - (pMgmt->b11hEnable == TRUE)) { - CARDvSetCountryInfo(pMgmt->pAdapter, - pBSSList->eNetworkTypeInUse, - pIE_Country); - } - - if ((bParsingQuiet == TRUE) && (pIE_Quiet != NULL)) { - if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) && - (((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) { - // valid EID - if (pQuiet == NULL) { - pQuiet = (PWLAN_IE_QUIET)pIE_Quiet; - CARDbSetQuiet( pMgmt->pAdapter, - TRUE, - pQuiet->byQuietCount, - pQuiet->byQuietPeriod, - *((PWORD)pQuiet->abyQuietDuration), - *((PWORD)pQuiet->abyQuietOffset) - ); - } else { - pQuiet = (PWLAN_IE_QUIET)pIE_Quiet; - CARDbSetQuiet( pMgmt->pAdapter, - FALSE, - pQuiet->byQuietCount, - pQuiet->byQuietPeriod, - *((PWORD)pQuiet->abyQuietDuration), - *((PWORD)pQuiet->abyQuietOffset) - ); - } - } - } - - if ((bParsingQuiet == TRUE) && - (pQuiet != NULL)) { - CARDbStartQuiet(pMgmt->pAdapter); - } -*/ - pBSSList->uIELength = uIELength; if (pBSSList->uIELength > WLAN_BEACON_FR_MAXLEN) pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN; @@ -609,8 +542,6 @@ BOOL BSSbUpdateToBSSList(void *hDeviceContext, PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext; signed long ldBm, ldBmSum; BOOL bParsingQuiet = FALSE; - // BYTE abyTmpSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; - if (pBSSList == NULL) return FALSE; @@ -622,7 +553,6 @@ BOOL BSSbUpdateToBSSList(void *hDeviceContext, pBSSList->wCapInfo = cpu_to_le16(wCapInfo); pBSSList->uClearCount = 0; pBSSList->uChannel = byCurrChannel; -// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSbUpdateToBSSList: pBSSList->uChannel: %d\n", pBSSList->uChannel); if (pSSID->len > WLAN_SSID_MAXLEN) pSSID->len = WLAN_SSID_MAXLEN; @@ -809,7 +739,6 @@ void BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex) pMgmt->sNodeDBTable[*puNodeIndex].byAuthSequence = 0; pMgmt->sNodeDBTable[*puNodeIndex].wEnQueueCnt = 0; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create node index = %d\n", ii); - return; }; @@ -840,8 +769,6 @@ void BSSvRemoveOneNode(void *hDeviceContext, unsigned int uNodeIndex) memset(&pMgmt->sNodeDBTable[uNodeIndex], 0, sizeof(KnownNodeDB)); // clear tx bit map pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[uNodeIndex].wAID >> 3] &= ~byMask[pMgmt->sNodeDBTable[uNodeIndex].wAID & 7]; - - return; }; /*+ * @@ -1054,10 +981,6 @@ if((pMgmt->eCurrState!=WMAC_STATE_ASSOC) && // Rate fallback check if (!pDevice->bFixRate) { -/* - if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (ii == 0)) - RATEvTxRateFallBack(pDevice, &(pMgmt->sNodeDBTable[ii])); -*/ if (ii > 0) { // ii = 0 for multicast node (AP & Adhoc) RATEvTxRateFallBack((void *)pDevice, @@ -1152,7 +1075,6 @@ if((pMgmt->eCurrState!=WMAC_STATE_ASSOC) && (pMgmt->eCurrMode == WMAC_MODE_ESS_STA)) { if (pMgmt->sNodeDBTable[0].bActive) { // Assoc with BSS - // DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Callback inactive Count = [%d]\n", pMgmt->sNodeDBTable[0].uInActiveCount); if (pDevice->bUpdateBBVGA) { /* s_vCheckSensitivity((void *) pDevice); */ @@ -1194,7 +1116,6 @@ if((pMgmt->eCurrState!=WMAC_STATE_ASSOC) && pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); } #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT - // if(pDevice->bWPASuppWextEnabled == TRUE) { union iwreq_data wrqu; memset(&wrqu, 0, sizeof (wrqu)); @@ -1223,7 +1144,6 @@ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bIsRoaming %d, !\n", pDevice->bIsRoaming ); pDevice->uIsroamingTime = 0; pDevice->bRoaming = FALSE; -// if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) { wpahdr = (viawget_wpa_header *)pDevice->skb->data; wpahdr->type = VIAWGET_CCKM_ROAM_MSG; wpahdr->resp_ie_len = 0; @@ -1237,7 +1157,6 @@ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bIsRoaming %d, !\n", pDevice->bIsRoaming ); netif_rx(pDevice->skb); pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); -// } } else if ((pDevice->bRoaming == FALSE)&&(pDevice->bIsRoaming == TRUE)) { pDevice->uIsroamingTime++; @@ -1315,7 +1234,6 @@ else { pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ); add_timer(&pMgmt->sTimerSecondCallback); - return; } /*+ @@ -1364,7 +1282,6 @@ void BSSvUpdateNodeTxCounter(void *hDeviceContext, // Only Unicast using support rates if (wFIFOCtl & FIFOCTL_NEEDACK) { - //DBG_PRN_GRP21(("Device %08X, wRate %04X, byTSR %02X\n", hDeviceContext, wRate, byTSR)); if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) { pMgmt->sNodeDBTable[0].uTxAttempts += 1; if ( !(byTSR & (TSR_TMO | TSR_RETRYTMO))) { @@ -1475,10 +1392,6 @@ void BSSvUpdateNodeTxCounter(void *hDeviceContext, } } } - - return; - - } /*+ @@ -1519,8 +1432,6 @@ void BSSvClearNodeDBTable(void *hDeviceContext, memset(&pMgmt->sNodeDBTable[ii], 0, sizeof(KnownNodeDB)); } } - - return; }; void s_vCheckSensitivity(void *hDeviceContext) @@ -1584,7 +1495,6 @@ RxOkRatio = (RxCnt < 6) ? 2000:((pDevice->scStatistic.RxOkCnt * 2000) / RxCnt); //decide link quality if(pDevice->bLinkPass !=TRUE) { - // printk("s_uCalculateLinkQual-->Link disconnect and Poor quality**\n"); pDevice->scStatistic.LinkQuality = 0; pDevice->scStatistic.SignalStren = 0; } @@ -1608,7 +1518,6 @@ else pDevice->scStatistic.TxFailCount = 0; pDevice->scStatistic.TxNoRetryOkCount = 0; pDevice->scStatistic.TxRetryOkCount = 0; - return; } void BSSvClearAnyBSSJoinRecord(void *hDeviceContext) @@ -1617,10 +1526,8 @@ void BSSvClearAnyBSSJoinRecord(void *hDeviceContext) PSMgmtObject pMgmt = &(pDevice->sMgmtObj); unsigned int ii; - for (ii = 0; ii < MAX_BSS_NUM; ii++) { + for (ii = 0; ii < MAX_BSS_NUM; ii++) pMgmt->sBSSList[ii].bSelected = FALSE; - } - return; } void s_vCheckPreEDThreshold(void *hDeviceContext) @@ -1637,6 +1544,5 @@ void s_vCheckPreEDThreshold(void *hDeviceContext) BBvUpdatePreEDThreshold(pDevice, FALSE); } } - return; } diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c index a49053bd7c6..9d09e9fd8e1 100644 --- a/drivers/staging/vt6656/card.c +++ b/drivers/staging/vt6656/card.c @@ -91,15 +91,10 @@ const WORD cwRXBCNTSFOff[MAX_RATE] = * uConnectionChannel - Channel to be set * Out: * none - * - * Return Value: TRUE if succeeded; FALSE if failed. - * */ -BOOL CARDbSetMediaChannel(void *pDeviceHandler, unsigned int uConnectionChannel) +void CARDbSetMediaChannel(void *pDeviceHandler, unsigned int uConnectionChannel) { PSDevice pDevice = (PSDevice) pDeviceHandler; -BOOL bResult = TRUE; - if (pDevice->byBBType == BB_TYPE_11A) { // 15 ~ 38 if ((uConnectionChannel < (CB_MAX_CHANNEL_24G+1)) || (uConnectionChannel > CB_MAX_CHANNEL)) @@ -140,7 +135,6 @@ BOOL bResult = TRUE; RFbRawSetPower(pDevice, pDevice->abyCCKPwrTbl[uConnectionChannel-1], RATE_1M); } ControlvWriteByte(pDevice,MESSAGE_REQUEST_MACREG,MAC_REG_CHANNEL,(BYTE)(uConnectionChannel|0x80)); - return(bResult); } /* @@ -607,7 +601,7 @@ BYTE ii; * Return Value: TRUE if succeeded; FALSE if failed. * */ -BOOL CARDbAddBasicRate(void *pDeviceHandler, WORD wRateIdx) +void CARDbAddBasicRate(void *pDeviceHandler, WORD wRateIdx) { PSDevice pDevice = (PSDevice) pDeviceHandler; WORD wRate = (WORD)(1<<wRateIdx); @@ -616,8 +610,6 @@ WORD wRate = (WORD)(1<<wRateIdx); //Determines the highest basic rate. CARDvUpdateBasicTopRate(pDevice); - - return(TRUE); } BOOL CARDbIsOFDMinBasicRate(void *pDeviceHandler) @@ -1090,7 +1082,7 @@ CARDbChannelSwitch ( if (byCount == 0) { pDevice->sMgmtObj.uCurrChannel = byNewChannel; - bResult = CARDbSetMediaChannel(pDevice, byNewChannel); + CARDbSetMediaChannel(pDevice, byNewChannel); return bResult; } diff --git a/drivers/staging/vt6656/card.h b/drivers/staging/vt6656/card.h index 6c91343d0d1..9cf71a3d880 100644 --- a/drivers/staging/vt6656/card.h +++ b/drivers/staging/vt6656/card.h @@ -60,12 +60,12 @@ typedef enum _CARD_OP_MODE { /*--------------------- Export Functions --------------------------*/ -BOOL CARDbSetMediaChannel(void *pDeviceHandler, +void CARDbSetMediaChannel(void *pDeviceHandler, unsigned int uConnectionChannel); void CARDvSetRSPINF(void *pDeviceHandler, BYTE byBBType); void vUpdateIFS(void *pDeviceHandler); void CARDvUpdateBasicTopRate(void *pDeviceHandler); -BOOL CARDbAddBasicRate(void *pDeviceHandler, WORD wRateIdx); +void CARDbAddBasicRate(void *pDeviceHandler, WORD wRateIdx); BOOL CARDbIsOFDMinBasicRate(void *pDeviceHandler); void CARDvAdjustTSF(void *pDeviceHandler, BYTE byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF); diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c index c95833ac58e..0a114231145 100644 --- a/drivers/staging/vt6656/int.c +++ b/drivers/staging/vt6656/int.c @@ -92,9 +92,8 @@ void INTvWorkItem(void *Context) spin_unlock_irq(&pDevice->lock); } -int INTnsProcessData(PSDevice pDevice) +void INTnsProcessData(PSDevice pDevice) { - int status = STATUS_SUCCESS; PSINTData pINTData; PSMgmtObject pMgmt = &(pDevice->sMgmtObj); struct net_device_stats *pStats = &pDevice->stats; @@ -218,6 +217,4 @@ int INTnsProcessData(PSDevice pDevice) pDevice->scStatistic.ullTxBroadcastBytes; pStats->tx_errors = pDevice->scStatistic.dwTsrErr; pStats->tx_dropped = pDevice->scStatistic.dwTsrErr; - - return status; } diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h index 3176c8d08d6..a5d96b96817 100644 --- a/drivers/staging/vt6656/int.h +++ b/drivers/staging/vt6656/int.h @@ -68,6 +68,6 @@ SINTData, *PSINTData; /*--------------------- Export Functions --------------------------*/ void INTvWorkItem(void *Context); -int INTnsProcessData(PSDevice pDevice); +void INTnsProcessData(PSDevice pDevice); #endif /* __INT_H__ */ diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c index 49390026dea..1463d76895f 100644 --- a/drivers/staging/vt6656/ioctl.c +++ b/drivers/staging/vt6656/ioctl.c @@ -295,6 +295,10 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EFAULT; break; } + if (sList.uItem > (ULONG_MAX - sizeof(SBSSIDList)) / sizeof(SBSSIDItem)) { + result = -EINVAL; + break; + } pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC); if (pList == NULL) { result = -ENOMEM; @@ -557,6 +561,10 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EFAULT; break; } + if (sNodeList.uItem > (ULONG_MAX - sizeof(SNodeList)) / sizeof(SNodeItem)) { + result = -ENOMEM; + break; + } pNodeList = (PSNodeList)kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC); if (pNodeList == NULL) { result = -ENOMEM; diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c index 2121205a912..ecfda5272fa 100644 --- a/drivers/staging/vt6656/iwctl.c +++ b/drivers/staging/vt6656/iwctl.c @@ -128,17 +128,6 @@ int iwctl_giwname(struct net_device *dev, return 0; } -int iwctl_giwnwid(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, - char *extra) -{ - //wrq->value = 0x100; - //wrq->disabled = 0; - //wrq->fixed = 1; - //return 0; - return -EOPNOTSUPP; -} /* * Wireless Handler : set scan */ @@ -1939,7 +1928,6 @@ static const iw_handler iwctl_handler[] = (iw_handler) iwctl_commit, // SIOCSIWCOMMIT (iw_handler) iwctl_giwname, // SIOCGIWNAME (iw_handler) NULL, // SIOCSIWNWID - (iw_handler) NULL, // SIOCGIWNWID (iw_handler) iwctl_siwfreq, // SIOCSIWFREQ (iw_handler) iwctl_giwfreq, // SIOCGIWFREQ (iw_handler) iwctl_siwmode, // SIOCSIWMODE diff --git a/drivers/staging/vt6656/iwctl.h b/drivers/staging/vt6656/iwctl.h index cc48954783f..10a240e6501 100644 --- a/drivers/staging/vt6656/iwctl.h +++ b/drivers/staging/vt6656/iwctl.h @@ -77,11 +77,6 @@ int iwctl_giwname(struct net_device *dev, char *wrq, char *extra); -int iwctl_giwnwid(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, - char *extra) ; - int iwctl_giwsens(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c index 26c19d1408c..af4a29d1477 100644 --- a/drivers/staging/vt6656/mac.c +++ b/drivers/staging/vt6656/mac.c @@ -133,10 +133,9 @@ void MACvWriteMultiAddr(PSDevice pDevice, unsigned int uByteIdx, BYTE byData) * Out: * none * - * Return Value: TRUE if success; otherwise FALSE * */ -BOOL MACbShutdown (PSDevice pDevice) +void MACbShutdown(PSDevice pDevice) { CONTROLnsRequestOutAsyn(pDevice, MESSAGE_TYPE_MACSHUTDOWN, @@ -145,7 +144,6 @@ BOOL MACbShutdown (PSDevice pDevice) 0, NULL ); - return TRUE; } void MACvSetBBType(PSDevice pDevice,BYTE byType) diff --git a/drivers/staging/vt6656/mac.h b/drivers/staging/vt6656/mac.h index 491ff5ecd04..147ac50218d 100644 --- a/drivers/staging/vt6656/mac.h +++ b/drivers/staging/vt6656/mac.h @@ -422,7 +422,7 @@ void MACvSetMultiAddrByHash(PSDevice pDevice, BYTE byHashIdx); void MACvWriteMultiAddr(PSDevice pDevice, unsigned int uByteIdx, BYTE byData); -BOOL MACbShutdown(PSDevice pDevice); +void MACbShutdown(PSDevice pDevice); void MACvSetBBType(PSDevice pDevice, BYTE byType); void MACvSetMISCFifo(PSDevice pDevice, WORD wOffset, DWORD dwData); void MACvDisableKeyEntry(PSDevice pDevice, unsigned int uEntryIdx); diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 541f9aa8ef6..6a708f44765 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -900,7 +900,7 @@ static BOOL device_alloc_bufs(PSDevice pDevice) { } // allocate rcb mem - pDevice->pRCBMem = kmalloc((sizeof(RCB) * pDevice->cbRD), GFP_KERNEL); + pDevice->pRCBMem = kzalloc((sizeof(RCB) * pDevice->cbRD), GFP_KERNEL); if (pDevice->pRCBMem == NULL) { DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : alloc rx usb context failed\n", pDevice->dev->name); goto free_tx; @@ -912,7 +912,6 @@ static BOOL device_alloc_bufs(PSDevice pDevice) { pDevice->FirstRecvMngList = NULL; pDevice->LastRecvMngList = NULL; pDevice->NumRecvFreeList = 0; - memset(pDevice->pRCBMem, 0, (sizeof(RCB) * pDevice->cbRD)); pRCB = (PRCB) pDevice->pRCBMem; for (ii = 0; ii < pDevice->cbRD; ii++) { @@ -1618,15 +1617,8 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { break; case SIOCSIWNWID: - rc = -EOPNOTSUPP; - break; - case SIOCGIWNWID: //0x8b03 support - #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT - rc = iwctl_giwnwid(dev, NULL, &(wrq->u.nwid), NULL); - #else - rc = -EOPNOTSUPP; - #endif + rc = -EOPNOTSUPP; break; // Set frequency/channel diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c index 1f1d9867917..2bd9b84ace8 100644 --- a/drivers/staging/wlags49_h2/wl_pci.c +++ b/drivers/staging/wlags49_h2/wl_pci.c @@ -112,17 +112,10 @@ extern dbg_info_t *DbgInfo; #endif // DBG /* define the PCI device Table Cardname and id tables */ -enum hermes_pci_versions { - CH_Agere_Systems_Mini_PCI_V1 = 0, -}; - static struct pci_device_id wl_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_0, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 }, - { PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 }, - { PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 }, + { PCI_DEVICE(PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_0), }, + { PCI_DEVICE(PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_1), }, + { PCI_DEVICE(PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_2), }, { } /* Terminating entry */ }; diff --git a/drivers/staging/xgifb/Makefile b/drivers/staging/xgifb/Makefile index 3c8c7de9ead..55e51990534 100644 --- a/drivers/staging/xgifb/Makefile +++ b/drivers/staging/xgifb/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_FB_XGI) += xgifb.o -xgifb-y := XGI_main_26.o vb_init.o vb_setmode.o vb_util.o vb_ext.o +xgifb-y := XGI_main_26.o vb_init.o vb_setmode.o vb_util.o diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h index 71aebe3e84d..35f7b2a485e 100644 --- a/drivers/staging/xgifb/XGI_main.h +++ b/drivers/staging/xgifb/XGI_main.h @@ -32,14 +32,10 @@ #endif static DEFINE_PCI_DEVICE_TABLE(xgifb_pci_table) = { - {PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_20, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0}, - {PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_27, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 1}, - {PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_40, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 2}, - {PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_42, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 3}, + {PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_20)}, + {PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_27)}, + {PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_40)}, + {PCI_DEVICE(PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_42)}, {0} }; @@ -128,7 +124,6 @@ MODULE_DEVICE_TABLE(pci, xgifb_pci_table); /* display status */ static int XGIfb_crt1off; static int XGIfb_forcecrt1 = -1; -static int XGIfb_userom ; /* global flags */ static int XGIfb_tvmode; diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 277e408c39c..2502c49c9c5 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -21,7 +21,6 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/vmalloc.h> #include <linux/vt_kern.h> #include <linux/capability.h> #include <linux/fs.h> @@ -46,8 +45,7 @@ #define GPIOG_EN (1<<6) #define GPIOG_READ (1<<1) -#define XGIFB_ROM_SIZE 65536 - +static char *forcecrt2type; static char *mode; static int vesa = -1; static unsigned int refresh_rate; @@ -159,7 +157,6 @@ static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr, /* unsigned long temp = 0; */ int Clock; - XGI_Pr->ROMAddr = HwDeviceExtension->pjVirtualRomBase; InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr); RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo, @@ -199,7 +196,6 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr, unsigned char sr_data, cr_data, cr_data2; unsigned long cr_data3; int A, B, C, D, E, F, temp, j; - XGI_Pr->ROMAddr = HwDeviceExtension->pjVirtualRomBase; InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr); RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo, ModeIdIndex, XGI_Pr); @@ -387,7 +383,7 @@ static void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr) /* ------------------ Internal helper routines ----------------- */ -static int XGIfb_GetXG21DefaultLVDSModeIdx(void) +static int XGIfb_GetXG21DefaultLVDSModeIdx(struct xgifb_video_info *xgifb_info) { int found_mode = 0; @@ -396,11 +392,11 @@ static int XGIfb_GetXG21DefaultLVDSModeIdx(void) found_mode = 0; while ((XGIbios_mode[XGIfb_mode_idx].mode_no != 0) && (XGIbios_mode[XGIfb_mode_idx].xres - <= XGI21_LCDCapList[0].LVDSHDE)) { + <= xgifb_info->lvds_data.LVDSHDE)) { if ((XGIbios_mode[XGIfb_mode_idx].xres - == XGI21_LCDCapList[0].LVDSHDE) + == xgifb_info->lvds_data.LVDSHDE) && (XGIbios_mode[XGIfb_mode_idx].yres - == XGI21_LCDCapList[0].LVDSVDE) + == xgifb_info->lvds_data.LVDSVDE) && (XGIbios_mode[XGIfb_mode_idx].bpp == 8)) { found_mode = 1; break; @@ -456,51 +452,6 @@ invalid: printk(KERN_INFO "XGIfb: Invalid VESA mode 0x%x'\n", vesamode); } -static int XGIfb_GetXG21LVDSData(struct xgifb_video_info *xgifb_info) -{ - u8 tmp; - void __iomem *data = xgifb_info->mmio_vbase + 0x20000; - int i, j, k; - - tmp = xgifb_reg_get(XGISR, 0x1e); - xgifb_reg_set(XGISR, 0x1e, tmp | 4); - - if ((readb(data) == 0x55) && - (readb(data + 1) == 0xAA) && - (readb(data + 0x65) & 0x1)) { - i = readw(data + 0x316); - j = readb(data + i - 1); - if (j == 0xff) - j = 1; - - k = 0; - do { - XGI21_LCDCapList[k].LVDS_Capability = readw(data + i); - XGI21_LCDCapList[k].LVDSHT = readw(data + i + 2); - XGI21_LCDCapList[k].LVDSVT = readw(data + i + 4); - XGI21_LCDCapList[k].LVDSHDE = readw(data + i + 6); - XGI21_LCDCapList[k].LVDSVDE = readw(data + i + 8); - XGI21_LCDCapList[k].LVDSHFP = readw(data + i + 10); - XGI21_LCDCapList[k].LVDSVFP = readw(data + i + 12); - XGI21_LCDCapList[k].LVDSHSYNC = readw(data + i + 14); - XGI21_LCDCapList[k].LVDSVSYNC = readw(data + i + 16); - XGI21_LCDCapList[k].VCLKData1 = readb(data + i + 18); - XGI21_LCDCapList[k].VCLKData2 = readb(data + i + 19); - XGI21_LCDCapList[k].PSC_S1 = readb(data + i + 20); - XGI21_LCDCapList[k].PSC_S2 = readb(data + i + 21); - XGI21_LCDCapList[k].PSC_S3 = readb(data + i + 22); - XGI21_LCDCapList[k].PSC_S4 = readb(data + i + 23); - XGI21_LCDCapList[k].PSC_S5 = readb(data + i + 24); - i += 25; - j--; - k++; - } while ((j > 0) && (k < (sizeof(XGI21_LCDCapList) - / sizeof(struct XGI21_LVDSCapStruct)))); - return 1; - } - return 0; -} - static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex) { u16 xres, yres; @@ -508,8 +459,8 @@ static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex) if (xgifb_info->chip == XG21) { if (xgifb_info->display2 == XGIFB_DISP_LCD) { - xres = XGI21_LCDCapList[0].LVDSHDE; - yres = XGI21_LCDCapList[0].LVDSVDE; + xres = xgifb_info->lvds_data.LVDSHDE; + yres = xgifb_info->lvds_data.LVDSVDE; if (XGIbios_mode[myindex].xres > xres) return -1; if (XGIbios_mode[myindex].yres > yres) @@ -1223,7 +1174,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive, if (isactive) { XGIfb_pre_setmode(xgifb_info); - if (XGISetModeNew(hw_info, + if (XGISetModeNew(xgifb_info, hw_info, XGIbios_mode[xgifb_info->mode_idx].mode_no) == 0) { printk(KERN_ERR "XGIfb: Setting mode[0x%x] failed\n", @@ -1794,17 +1745,16 @@ static void XGIfb_detect_VB(struct xgifb_video_info *xgifb_info) XGIfb_crt1off = 0; } - if (XGIfb_crt2type != -1) - /* TW: Override with option */ - xgifb_info->display2 = XGIfb_crt2type; - else if (cr32 & XGI_VB_TV) - xgifb_info->display2 = XGIFB_DISP_TV; - else if (cr32 & XGI_VB_LCD) - xgifb_info->display2 = XGIFB_DISP_LCD; - else if (cr32 & XGI_VB_CRT2) - xgifb_info->display2 = XGIFB_DISP_CRT; - else - xgifb_info->display2 = XGIFB_DISP_NONE; + if (!xgifb_info->display2_force) { + if (cr32 & XGI_VB_TV) + xgifb_info->display2 = XGIFB_DISP_TV; + else if (cr32 & XGI_VB_LCD) + xgifb_info->display2 = XGIFB_DISP_LCD; + else if (cr32 & XGI_VB_CRT2) + xgifb_info->display2 = XGIFB_DISP_CRT; + else + xgifb_info->display2 = XGIFB_DISP_NONE; + } if (XGIfb_tvplug != -1) /* PR/TW: Override with option */ @@ -1925,8 +1875,6 @@ static int __init XGIfb_setup(char *options) XGIfb_crt2type = XGIFB_DISP_LCD; } else if (!strncmp(this_opt, "noypan", 6)) { XGIfb_ypan = 0; - } else if (!strncmp(this_opt, "userom:", 7)) { - XGIfb_userom = xgifb_optval(this_opt, 7); } else { mode = this_opt; } @@ -1934,35 +1882,12 @@ static int __init XGIfb_setup(char *options) return 0; } -static unsigned char *xgifb_copy_rom(struct pci_dev *dev) -{ - void __iomem *rom_address; - unsigned char *rom_copy; - size_t rom_size; - - rom_address = pci_map_rom(dev, &rom_size); - if (rom_address == NULL) - return NULL; - - rom_copy = vzalloc(XGIFB_ROM_SIZE); - if (rom_copy == NULL) - goto done; - - rom_size = min_t(size_t, rom_size, XGIFB_ROM_SIZE); - memcpy_fromio(rom_copy, rom_address, rom_size); - -done: - pci_unmap_rom(dev, rom_address); - return rom_copy; -} - static int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u8 reg, reg1; u8 CR48, CR38; int ret; - bool xgi21_drvlcdcaplist = false; struct fb_info *fb_info; struct xgifb_video_info *xgifb_info; struct xgi_hw_device_info *hw_info; @@ -2001,6 +1926,11 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, goto error; } + if (XGIfb_crt2type != -1) { + xgifb_info->display2 = XGIfb_crt2type; + xgifb_info->display2_force = true; + } + XGIRegInit(&xgifb_info->dev_info, (unsigned long)hw_info->pjIOAddress); xgifb_reg_set(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD); @@ -2041,18 +1971,6 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, printk("XGIfb:chipid = %x\n", xgifb_info->chip); hw_info->jChipType = xgifb_info->chip; - if ((xgifb_info->chip == XG21) || (XGIfb_userom)) { - hw_info->pjVirtualRomBase = xgifb_copy_rom(pdev); - if (hw_info->pjVirtualRomBase) - printk(KERN_INFO "XGIfb: Video ROM found and mapped to %p\n", - hw_info->pjVirtualRomBase); - else - printk(KERN_INFO "XGIfb: Video ROM not found\n"); - } else { - hw_info->pjVirtualRomBase = NULL; - printk(KERN_INFO "XGIfb: Video ROM usage disabled\n"); - } - if (XGIfb_get_dram_size(xgifb_info)) { printk(KERN_INFO "XGIfb: Fatal error: Unable to determine RAM size.\n"); ret = -ENODEV; @@ -2117,8 +2035,6 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, CR38 = xgifb_reg_get(XGICR, 0x38); if ((CR38&0xE0) == 0xC0) { xgifb_info->display2 = XGIFB_DISP_LCD; - if (!XGIfb_GetXG21LVDSData(xgifb_info)) - xgi21_drvlcdcaplist = true; } else if ((CR38&0xE0) == 0x60) { xgifb_info->hasVB = HASVB_CHRONTEL; } else { @@ -2193,6 +2109,8 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, if (xgifb_info->hasVB != HASVB_NONE) XGIfb_detect_VB(xgifb_info); + else if (xgifb_info->chip != XG21) + xgifb_info->display2 = XGIFB_DISP_NONE; if (xgifb_info->display2 == XGIFB_DISP_LCD) { if (!enable_dstn) { @@ -2254,7 +2172,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, if (xgifb_info->display2 == XGIFB_DISP_LCD && xgifb_info->chip == XG21) xgifb_info->mode_idx = - XGIfb_GetXG21DefaultLVDSModeIdx(); + XGIfb_GetXG21DefaultLVDSModeIdx(xgifb_info); else xgifb_info->mode_idx = DEFAULT_MODE; } @@ -2264,21 +2182,6 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, goto error_1; } - if (xgi21_drvlcdcaplist) { - int m; - - for (m = 0; m < ARRAY_SIZE(XGI21_LCDCapList); m++) - if ((XGI21_LCDCapList[m].LVDSHDE == - XGIbios_mode[xgifb_info->mode_idx].xres) && - (XGI21_LCDCapList[m].LVDSVDE == - XGIbios_mode[xgifb_info->mode_idx].yres)) { - xgifb_reg_set(xgifb_info->dev_info.P3d4, - 0x36, - m); - break; - } - } - /* yilin set default refresh rate */ xgifb_info->refresh_rate = refresh_rate; if (xgifb_info->refresh_rate == 0) @@ -2418,7 +2321,6 @@ error_1: error_0: release_mem_region(xgifb_info->video_base, xgifb_info->video_size); error: - vfree(hw_info->pjVirtualRomBase); framebuffer_release(fb_info); return ret; } @@ -2442,7 +2344,6 @@ static void __devexit xgifb_remove(struct pci_dev *pdev) iounmap(xgifb_info->video_vbase); release_mem_region(xgifb_info->mmio_base, xgifb_info->mmio_size); release_mem_region(xgifb_info->video_base, xgifb_info->video_size); - vfree(xgifb_info->hw_info.pjVirtualRomBase); framebuffer_release(fb_info); pci_set_drvdata(pdev, NULL); } @@ -2458,6 +2359,8 @@ static int __init xgifb_init(void) { char *option = NULL; + if (forcecrt2type != NULL) + XGIfb_search_crt2type(forcecrt2type); if (fb_get_options("xgifb", &option)) return -ENODEV; XGIfb_setup(option); @@ -2480,6 +2383,11 @@ MODULE_AUTHOR("XGITECH , Others"); module_param(mode, charp, 0); module_param(vesa, int, 0); module_param(filter, int, 0); +module_param(forcecrt2type, charp, 0); + +MODULE_PARM_DESC(forcecrt2type, + "\nForce the second display output type. Possible values are NONE,\n" + "LCD, TV, VGA, SVIDEO or COMPOSITE.\n"); MODULE_PARM_DESC(mode, "\nSelects the desired default display mode in the format XxYxDepth,\n" diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h index 7611846a703..2c866bb65a0 100644 --- a/drivers/staging/xgifb/XGIfb.h +++ b/drivers/staging/xgifb/XGIfb.h @@ -86,10 +86,13 @@ struct xgifb_video_info { unsigned int refresh_rate; enum xgifb_display_type display2; /* the second display output type */ + bool display2_force; unsigned char hasVB; unsigned char TV_type; unsigned char TV_plug; + struct XGI21_LVDSCapStruct lvds_data; + enum XGI_CHIP_TYPE chip; unsigned char revision_id; diff --git a/drivers/staging/xgifb/vb_ext.c b/drivers/staging/xgifb/vb_ext.c deleted file mode 100644 index b1a25730b7c..00000000000 --- a/drivers/staging/xgifb/vb_ext.c +++ /dev/null @@ -1,444 +0,0 @@ -#include <linux/io.h> -#include <linux/types.h> -#include "XGIfb.h" - -#include "vb_def.h" -#include "vgatypes.h" -#include "vb_struct.h" -#include "vb_util.h" -#include "vb_setmode.h" -#include "vb_ext.h" - -/************************************************************** - *********************** Dynamic Sense ************************ - *************************************************************/ - -static unsigned char XGINew_Is301B(struct vb_device_info *pVBInfo) -{ - unsigned short flag; - - flag = xgifb_reg_get(pVBInfo->Part4Port, 0x01); - - if (flag > 0x0B0) - return 0; /* 301b */ - else - return 1; -} - -static unsigned char XGINew_Sense(unsigned short tempbx, - unsigned short tempcx, - struct vb_device_info *pVBInfo) -{ - unsigned short temp, i, tempch; - - temp = tempbx & 0xFF; - xgifb_reg_set(pVBInfo->Part4Port, 0x11, temp); - temp = (tempbx & 0xFF00) >> 8; - temp |= (tempcx & 0x00FF); - xgifb_reg_and_or(pVBInfo->Part4Port, 0x10, ~0x1F, temp); - - for (i = 0; i < 10; i++) - XGI_LongWait(pVBInfo); - - tempch = (tempcx & 0x7F00) >> 8; - temp = xgifb_reg_get(pVBInfo->Part4Port, 0x03); - temp = temp ^ (0x0E); - temp &= tempch; - - if (temp > 0) - return 1; - else - return 0; -} - -static unsigned char -XGINew_GetLCDDDCInfo(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *pVBInfo) -{ - unsigned short temp; - - /* add lcd sense */ - if (HwDeviceExtension->ulCRT2LCDType == LCD_UNKNOWN) { - return 0; - } else { - temp = (unsigned short) HwDeviceExtension->ulCRT2LCDType; - switch (HwDeviceExtension->ulCRT2LCDType) { - case LCD_INVALID: - case LCD_800x600: - case LCD_1024x768: - case LCD_1280x1024: - break; - - case LCD_640x480: - case LCD_1024x600: - case LCD_1152x864: - case LCD_1280x960: - case LCD_1152x768: - temp = 0; - break; - - case LCD_1400x1050: - case LCD_1280x768: - case LCD_1600x1200: - break; - - case LCD_1920x1440: - case LCD_2048x1536: - temp = 0; - break; - - default: - break; - } - xgifb_reg_and_or(pVBInfo->P3d4, 0x36, 0xF0, temp); - return 1; - } -} - -static unsigned char XGINew_GetPanelID(struct vb_device_info *pVBInfo) -{ - unsigned short PanelTypeTable[16] = { SyncNN | PanelRGB18Bit - | Panel800x600 | _PanelType00, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType01, SyncNN | PanelRGB18Bit - | Panel800x600 | _PanelType02, SyncNN | PanelRGB18Bit - | Panel640x480 | _PanelType03, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType04, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType05, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType06, SyncNN | PanelRGB24Bit - | Panel1024x768 | _PanelType07, SyncNN | PanelRGB18Bit - | Panel800x600 | _PanelType08, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType09, SyncNN | PanelRGB18Bit - | Panel800x600 | _PanelType0A, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType0B, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType0C, SyncNN | PanelRGB24Bit - | Panel1024x768 | _PanelType0D, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType0E, SyncNN | PanelRGB18Bit - | Panel1024x768 | _PanelType0F }; - unsigned short tempax, tempbx, temp; - /* unsigned short return_flag; */ - - tempax = xgifb_reg_get(pVBInfo->P3c4, 0x1A); - tempbx = tempax & 0x1E; - - if (tempax == 0) - return 0; - else { - /* - if (!(tempax & 0x10)) { - if (pVBInfo->IF_DEF_LVDS == 1) { - tempbx = 0; - temp = xgifb_reg_get(pVBInfo->P3c4, 0x38); - if (temp & 0x40) - tempbx |= 0x08; - if (temp & 0x20) - tempbx |= 0x02; - if (temp & 0x01) - tempbx |= 0x01; - - temp = xgifb_reg_get(pVBInfo->P3c4, 0x39); - if (temp & 0x80) - tempbx |= 0x04; - } else { - return(0); - } - } - */ - - tempbx = tempbx >> 1; - temp = tempbx & 0x00F; - xgifb_reg_set(pVBInfo->P3d4, 0x36, temp); - tempbx--; - tempbx = PanelTypeTable[tempbx]; - - temp = (tempbx & 0xFF00) >> 8; - xgifb_reg_and_or(pVBInfo->P3d4, 0x37, ~(LCDSyncBit - | LCDRGB18Bit), temp); - return 1; - } -} - -static unsigned char -XGINew_BridgeIsEnable(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *pVBInfo) -{ - unsigned short flag; - - if (XGI_BridgeIsOn(pVBInfo) == 0) { - flag = xgifb_reg_get(pVBInfo->Part1Port, 0x0); - - if (flag & 0x050) - return 1; - else - return 0; - - } - return 0; -} - -static unsigned char -XGINew_SenseHiTV(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *pVBInfo) -{ - unsigned short tempbx, tempcx, temp, i, tempch; - - tempbx = *pVBInfo->pYCSenseData2; - - tempcx = 0x0604; - - temp = tempbx & 0xFF; - xgifb_reg_set(pVBInfo->Part4Port, 0x11, temp); - temp = (tempbx & 0xFF00) >> 8; - temp |= (tempcx & 0x00FF); - xgifb_reg_and_or(pVBInfo->Part4Port, 0x10, ~0x1F, temp); - - for (i = 0; i < 10; i++) - XGI_LongWait(pVBInfo); - - tempch = (tempcx & 0xFF00) >> 8; - temp = xgifb_reg_get(pVBInfo->Part4Port, 0x03); - temp = temp ^ (0x0E); - temp &= tempch; - - if (temp != tempch) - return 0; - - tempbx = *pVBInfo->pVideoSenseData2; - - tempcx = 0x0804; - temp = tempbx & 0xFF; - xgifb_reg_set(pVBInfo->Part4Port, 0x11, temp); - temp = (tempbx & 0xFF00) >> 8; - temp |= (tempcx & 0x00FF); - xgifb_reg_and_or(pVBInfo->Part4Port, 0x10, ~0x1F, temp); - - for (i = 0; i < 10; i++) - XGI_LongWait(pVBInfo); - - tempch = (tempcx & 0xFF00) >> 8; - temp = xgifb_reg_get(pVBInfo->Part4Port, 0x03); - temp = temp ^ (0x0E); - temp &= tempch; - - if (temp != tempch) { - return 0; - } else { - tempbx = 0x3FF; - tempcx = 0x0804; - temp = tempbx & 0xFF; - xgifb_reg_set(pVBInfo->Part4Port, 0x11, temp); - temp = (tempbx & 0xFF00) >> 8; - temp |= (tempcx & 0x00FF); - xgifb_reg_and_or(pVBInfo->Part4Port, 0x10, ~0x1F, temp); - - for (i = 0; i < 10; i++) - XGI_LongWait(pVBInfo); - - tempch = (tempcx & 0xFF00) >> 8; - temp = xgifb_reg_get(pVBInfo->Part4Port, 0x03); - temp = temp ^ (0x0E); - temp &= tempch; - - if (temp != tempch) - return 1; - else - return 0; - } -} - -void XGI_GetSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *pVBInfo) -{ - unsigned short tempax = 0, tempbx, tempcx, temp, - P2reg0 = 0, SenseModeNo = 0, - OutputSelect = *pVBInfo->pOutputSelect, - ModeIdIndex, i; - pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress; - - if (pVBInfo->IF_DEF_LVDS == 1) { - /* ynlai 02/27/2002 */ - tempax = xgifb_reg_get(pVBInfo->P3c4, 0x1A); - tempbx = xgifb_reg_get(pVBInfo->P3c4, 0x1B); - tempax = ((tempax & 0xFE) >> 1) | (tempbx << 8); - if (tempax == 0x00) { /* Get Panel id from DDC */ - temp = XGINew_GetLCDDDCInfo(HwDeviceExtension, pVBInfo); - if (temp == 1) { /* LCD connect */ - /* set CR39 bit0="1" */ - xgifb_reg_and_or(pVBInfo->P3d4, - 0x39, 0xFF, 0x01); - /* clean CR37 bit4="0" */ - xgifb_reg_and_or(pVBInfo->P3d4, - 0x37, 0xEF, 0x00); - temp = LCDSense; - } else { /* LCD don't connect */ - temp = 0; - } - } else { - XGINew_GetPanelID(pVBInfo); - temp = LCDSense; - } - - tempbx = ~(LCDSense | AVIDEOSense | SVIDEOSense); - xgifb_reg_and_or(pVBInfo->P3d4, 0x32, tempbx, temp); - } else { /* for 301 */ - if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) { /* for HiVision */ - tempax = xgifb_reg_get(pVBInfo->P3c4, 0x38); - temp = tempax & 0x01; - tempax = xgifb_reg_get(pVBInfo->P3c4, 0x3A); - temp = temp | (tempax & 0x02); - xgifb_reg_and_or(pVBInfo->P3d4, 0x32, 0xA0, temp); - } else { - if (XGI_BridgeIsOn(pVBInfo)) { - P2reg0 = xgifb_reg_get(pVBInfo->Part2Port, - 0x00); - if (!XGINew_BridgeIsEnable(HwDeviceExtension, - pVBInfo)) { - SenseModeNo = 0x2e; - /* xgifb_reg_set(pVBInfo->P3d4, 0x30, 0x41); - * XGISetModeNew(HwDeviceExtension, 0x2e); - * // ynlai InitMode */ - - temp = XGI_SearchModeID(SenseModeNo, - &ModeIdIndex, - pVBInfo); - XGI_GetVGAType(HwDeviceExtension, - pVBInfo); - XGI_GetVBType(pVBInfo); - pVBInfo->SetFlag = 0x00; - pVBInfo->ModeType = ModeVGA; - pVBInfo->VBInfo = SetCRT2ToRAMDAC | - LoadDACFlag | - SetInSlaveMode; - XGI_GetLCDInfo(0x2e, - ModeIdIndex, - pVBInfo); - XGI_GetTVInfo(0x2e, - ModeIdIndex, - pVBInfo); - XGI_EnableBridge(HwDeviceExtension, - pVBInfo); - XGI_SetCRT2Group301(SenseModeNo, - HwDeviceExtension, - pVBInfo); - XGI_SetCRT2ModeRegs(0x2e, - HwDeviceExtension, - pVBInfo); - /* XGI_DisableBridge(HwDeviceExtension, - * pVBInfo ) ; */ - /* Display Off 0212 */ - xgifb_reg_and_or(pVBInfo->P3c4, - 0x01, - 0xDF, - 0x20); - for (i = 0; i < 20; i++) - XGI_LongWait(pVBInfo); - } - xgifb_reg_set(pVBInfo->Part2Port, 0x00, 0x1c); - tempax = 0; - tempbx = *pVBInfo->pRGBSenseData; - - if (!(XGINew_Is301B(pVBInfo))) - tempbx = *pVBInfo->pRGBSenseData2; - - tempcx = 0x0E08; - if (XGINew_Sense(tempbx, tempcx, pVBInfo)) { - if (XGINew_Sense(tempbx, - tempcx, - pVBInfo)) - tempax |= Monitor2Sense; - } - - if (pVBInfo->VBType & VB_XGI301C) - xgifb_reg_or(pVBInfo->Part4Port, - 0x0d, - 0x04); - - /* add by kuku for Multi-adapter sense HiTV */ - if (XGINew_SenseHiTV(HwDeviceExtension, - pVBInfo)) { - tempax |= HiTVSense; - if ((pVBInfo->VBType & VB_XGI301C)) - tempax ^= (HiTVSense | - YPbPrSense); - } - - /* start */ - if (!(tempax & (HiTVSense | YPbPrSense))) { - tempbx = *pVBInfo->pYCSenseData; - if (!(XGINew_Is301B(pVBInfo))) - tempbx = *pVBInfo->pYCSenseData2; - tempcx = 0x0604; - if (XGINew_Sense(tempbx, - tempcx, - pVBInfo)) { - if (XGINew_Sense(tempbx, - tempcx, - pVBInfo)) - tempax |= SVIDEOSense; - } - - if (OutputSelect & BoardTVType) { - tempbx = *pVBInfo->pVideoSenseData; - - if (!(XGINew_Is301B(pVBInfo))) - tempbx = *pVBInfo->pVideoSenseData2; - - tempcx = 0x0804; - if (XGINew_Sense(tempbx, - tempcx, - pVBInfo)) { - if (XGINew_Sense(tempbx, - tempcx, - pVBInfo)) - tempax |= AVIDEOSense; - } - } else { - if (!(tempax & SVIDEOSense)) { - tempbx = *pVBInfo->pVideoSenseData; - - if (!(XGINew_Is301B(pVBInfo))) - tempbx = *pVBInfo->pVideoSenseData2; - - tempcx = 0x0804; - if (XGINew_Sense(tempbx, - tempcx, - pVBInfo)) { - if (XGINew_Sense(tempbx, tempcx, pVBInfo)) - tempax |= AVIDEOSense; - } - } - } - } - } /* end */ - if (!(tempax & Monitor2Sense)) { - if (XGINew_SenseLCD(HwDeviceExtension, pVBInfo)) - tempax |= LCDSense; - } - tempbx = 0; - tempcx = 0; - XGINew_Sense(tempbx, tempcx, pVBInfo); - - xgifb_reg_and_or(pVBInfo->P3d4, 0x32, ~0xDF, tempax); - xgifb_reg_set(pVBInfo->Part2Port, 0x00, P2reg0); - - if (!(P2reg0 & 0x20)) { - pVBInfo->VBInfo = DisableCRT2Display; - /* XGI_SetCRT2Group301(SenseModeNo, - * HwDeviceExtension, - * pVBInfo); */ - } - } - } - XGI_DisableBridge(HwDeviceExtension, pVBInfo); /* shampoo 0226 */ - -} - -unsigned short XGINew_SenseLCD(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *pVBInfo) -{ - /* unsigned short SoftSetting ; */ - unsigned short temp; - - temp = XGINew_GetLCDDDCInfo(HwDeviceExtension, pVBInfo); - - return temp; -} diff --git a/drivers/staging/xgifb/vb_ext.h b/drivers/staging/xgifb/vb_ext.h deleted file mode 100644 index 0b1f55b4242..00000000000 --- a/drivers/staging/xgifb/vb_ext.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _VBEXT_ -#define _VBEXT_ - -extern void XGI_GetSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *pVBInfo); -extern unsigned short XGINew_SenseLCD(struct xgi_hw_device_info *, - struct vb_device_info *pVBInfo); - -#endif diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c index 9e890a17fbc..4ccd988ffd7 100644 --- a/drivers/staging/xgifb/vb_init.c +++ b/drivers/staging/xgifb/vb_init.c @@ -1,6 +1,7 @@ #include <linux/types.h> #include <linux/delay.h> /* udelay */ #include <linux/pci.h> +#include <linux/vmalloc.h> #include "vgatypes.h" #include "XGIfb.h" @@ -10,7 +11,6 @@ #include "vb_util.h" #include "vb_setmode.h" #include "vb_init.h" -#include "vb_ext.h" #include <linux/io.h> @@ -35,6 +35,8 @@ static const unsigned short XGINew_DDRDRAM_TYPE20[12][5] = { { 2, 12, 9, 8, 0x35}, { 2, 12, 8, 4, 0x31} }; +#define XGIFB_ROM_SIZE 65536 + static unsigned char XGINew_GetXG20DRAMType(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) @@ -1068,20 +1070,20 @@ static int XGINew_DDRSizing340(struct xgi_hw_device_info *HwDeviceExtension, return 0; } -static void XGINew_SetDRAMSize_340(struct xgi_hw_device_info *HwDeviceExtension, +static void XGINew_SetDRAMSize_340(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) { unsigned short data; - pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase; pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress; - XGISetModeNew(HwDeviceExtension, 0x2e); + XGISetModeNew(xgifb_info, HwDeviceExtension, 0x2e); data = xgifb_reg_get(pVBInfo->P3c4, 0x21); /* disable read cache */ xgifb_reg_set(pVBInfo->P3c4, 0x21, (unsigned short) (data & 0xDF)); - XGI_DisplayOff(HwDeviceExtension, pVBInfo); + XGI_DisplayOff(xgifb_info, HwDeviceExtension, pVBInfo); /* data = xgifb_reg_get(pVBInfo->P3c4, 0x1); */ /* data |= 0x20 ; */ @@ -1092,118 +1094,100 @@ static void XGINew_SetDRAMSize_340(struct xgi_hw_device_info *HwDeviceExtension, xgifb_reg_set(pVBInfo->P3c4, 0x21, (unsigned short) (data | 0x20)); } -static void ReadVBIOSTablData(unsigned char ChipType, +static u8 *xgifb_copy_rom(struct pci_dev *dev, size_t *rom_size) +{ + void __iomem *rom_address; + u8 *rom_copy; + + rom_address = pci_map_rom(dev, rom_size); + if (rom_address == NULL) + return NULL; + + rom_copy = vzalloc(XGIFB_ROM_SIZE); + if (rom_copy == NULL) + goto done; + + *rom_size = min_t(size_t, *rom_size, XGIFB_ROM_SIZE); + memcpy_fromio(rom_copy, rom_address, *rom_size); + +done: + pci_unmap_rom(dev, rom_address); + return rom_copy; +} + +static void xgifb_read_vbios(struct pci_dev *pdev, struct vb_device_info *pVBInfo) { - volatile unsigned char *pVideoMemory = - (unsigned char *) pVBInfo->ROMAddr; + struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev); + u8 *vbios; unsigned long i; - unsigned char j, k; - /* Volari customize data area end */ - - if (ChipType == XG21) { - pVBInfo->IF_DEF_LVDS = 0; - if (pVideoMemory[0x65] & 0x1) { - pVBInfo->IF_DEF_LVDS = 1; - i = pVideoMemory[0x316] | (pVideoMemory[0x317] << 8); - j = pVideoMemory[i - 1]; - if (j != 0xff) { - k = 0; - do { - pVBInfo->XG21_LVDSCapList[k]. - LVDS_Capability - = pVideoMemory[i] | - (pVideoMemory[i + 1] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSHT - = pVideoMemory[i + 2] | - (pVideoMemory[i + 3] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSVT - = pVideoMemory[i + 4] | - (pVideoMemory[i + 5] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSHDE - = pVideoMemory[i + 6] | - (pVideoMemory[i + 7] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSVDE - = pVideoMemory[i + 8] | - (pVideoMemory[i + 9] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSHFP - = pVideoMemory[i + 10] | - (pVideoMemory[i + 11] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSVFP - = pVideoMemory[i + 12] | - (pVideoMemory[i + 13] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSHSYNC - = pVideoMemory[i + 14] | - (pVideoMemory[i + 15] << 8); - pVBInfo->XG21_LVDSCapList[k].LVDSVSYNC - = pVideoMemory[i + 16] | - (pVideoMemory[i + 17] << 8); - pVBInfo->XG21_LVDSCapList[k].VCLKData1 - = pVideoMemory[i + 18]; - pVBInfo->XG21_LVDSCapList[k].VCLKData2 - = pVideoMemory[i + 19]; - pVBInfo->XG21_LVDSCapList[k].PSC_S1 - = pVideoMemory[i + 20]; - pVBInfo->XG21_LVDSCapList[k].PSC_S2 - = pVideoMemory[i + 21]; - pVBInfo->XG21_LVDSCapList[k].PSC_S3 - = pVideoMemory[i + 22]; - pVBInfo->XG21_LVDSCapList[k].PSC_S4 - = pVideoMemory[i + 23]; - pVBInfo->XG21_LVDSCapList[k].PSC_S5 - = pVideoMemory[i + 24]; - i += 25; - j--; - k++; - } while ((j > 0) && - (k < (sizeof(XGI21_LCDCapList) / - sizeof(struct - XGI21_LVDSCapStruct)))); - } else { - pVBInfo->XG21_LVDSCapList[0].LVDS_Capability - = pVideoMemory[i] | - (pVideoMemory[i + 1] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSHT - = pVideoMemory[i + 2] | - (pVideoMemory[i + 3] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSVT - = pVideoMemory[i + 4] | - (pVideoMemory[i + 5] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSHDE - = pVideoMemory[i + 6] | - (pVideoMemory[i + 7] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSVDE - = pVideoMemory[i + 8] | - (pVideoMemory[i + 9] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSHFP - = pVideoMemory[i + 10] | - (pVideoMemory[i + 11] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSVFP - = pVideoMemory[i + 12] | - (pVideoMemory[i + 13] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSHSYNC - = pVideoMemory[i + 14] | - (pVideoMemory[i + 15] << 8); - pVBInfo->XG21_LVDSCapList[0].LVDSVSYNC - = pVideoMemory[i + 16] | - (pVideoMemory[i + 17] << 8); - pVBInfo->XG21_LVDSCapList[0].VCLKData1 - = pVideoMemory[i + 18]; - pVBInfo->XG21_LVDSCapList[0].VCLKData2 - = pVideoMemory[i + 19]; - pVBInfo->XG21_LVDSCapList[0].PSC_S1 - = pVideoMemory[i + 20]; - pVBInfo->XG21_LVDSCapList[0].PSC_S2 - = pVideoMemory[i + 21]; - pVBInfo->XG21_LVDSCapList[0].PSC_S3 - = pVideoMemory[i + 22]; - pVBInfo->XG21_LVDSCapList[0].PSC_S4 - = pVideoMemory[i + 23]; - pVBInfo->XG21_LVDSCapList[0].PSC_S5 - = pVideoMemory[i + 24]; - } - } + unsigned char j; + struct XGI21_LVDSCapStruct *lvds; + size_t vbios_size; + int entry; + + if (xgifb_info->chip != XG21) + return; + pVBInfo->IF_DEF_LVDS = 0; + vbios = xgifb_copy_rom(pdev, &vbios_size); + if (vbios == NULL) { + dev_err(&pdev->dev, "video BIOS not available\n"); + return; + } + if (vbios_size <= 0x65) + goto error; + /* + * The user can ignore the LVDS bit in the BIOS and force the display + * type. + */ + if (!(vbios[0x65] & 0x1) && + (!xgifb_info->display2_force || + xgifb_info->display2 != XGIFB_DISP_LCD)) { + vfree(vbios); + return; } + if (vbios_size <= 0x317) + goto error; + i = vbios[0x316] | (vbios[0x317] << 8); + if (vbios_size <= i - 1) + goto error; + j = vbios[i - 1]; + if (j == 0) + goto error; + if (j == 0xff) + j = 1; + /* + * Read the LVDS table index scratch register set by the BIOS. + */ + entry = xgifb_reg_get(xgifb_info->dev_info.P3d4, 0x36); + if (entry >= j) + entry = 0; + i += entry * 25; + lvds = &xgifb_info->lvds_data; + if (vbios_size <= i + 24) + goto error; + lvds->LVDS_Capability = vbios[i] | (vbios[i + 1] << 8); + lvds->LVDSHT = vbios[i + 2] | (vbios[i + 3] << 8); + lvds->LVDSVT = vbios[i + 4] | (vbios[i + 5] << 8); + lvds->LVDSHDE = vbios[i + 6] | (vbios[i + 7] << 8); + lvds->LVDSVDE = vbios[i + 8] | (vbios[i + 9] << 8); + lvds->LVDSHFP = vbios[i + 10] | (vbios[i + 11] << 8); + lvds->LVDSVFP = vbios[i + 12] | (vbios[i + 13] << 8); + lvds->LVDSHSYNC = vbios[i + 14] | (vbios[i + 15] << 8); + lvds->LVDSVSYNC = vbios[i + 16] | (vbios[i + 17] << 8); + lvds->VCLKData1 = vbios[i + 18]; + lvds->VCLKData2 = vbios[i + 19]; + lvds->PSC_S1 = vbios[i + 20]; + lvds->PSC_S2 = vbios[i + 21]; + lvds->PSC_S3 = vbios[i + 22]; + lvds->PSC_S4 = vbios[i + 23]; + lvds->PSC_S5 = vbios[i + 24]; + vfree(vbios); + pVBInfo->IF_DEF_LVDS = 1; + return; +error: + dev_err(&pdev->dev, "video BIOS corrupted\n"); + vfree(vbios); } static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, @@ -1336,18 +1320,57 @@ static void XGINew_SetModeScratch(struct xgi_hw_device_info *HwDeviceExtension, } +static unsigned short XGINew_SenseLCD(struct xgi_hw_device_info + *HwDeviceExtension, + struct vb_device_info *pVBInfo) +{ + unsigned short temp; + + /* add lcd sense */ + if (HwDeviceExtension->ulCRT2LCDType == LCD_UNKNOWN) { + return 0; + } else { + temp = (unsigned short) HwDeviceExtension->ulCRT2LCDType; + switch (HwDeviceExtension->ulCRT2LCDType) { + case LCD_INVALID: + case LCD_800x600: + case LCD_1024x768: + case LCD_1280x1024: + break; + + case LCD_640x480: + case LCD_1024x600: + case LCD_1152x864: + case LCD_1280x960: + case LCD_1152x768: + temp = 0; + break; + + case LCD_1400x1050: + case LCD_1280x768: + case LCD_1600x1200: + break; + + case LCD_1920x1440: + case LCD_2048x1536: + temp = 0; + break; + + default: + break; + } + xgifb_reg_and_or(pVBInfo->P3d4, 0x36, 0xF0, temp); + return 1; + } +} + static void XGINew_GetXG21Sense(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) { unsigned char Temp; - volatile unsigned char *pVideoMemory = - (unsigned char *) pVBInfo->ROMAddr; - - pVBInfo->IF_DEF_LVDS = 0; #if 1 - if ((pVideoMemory[0x65] & 0x01)) { /* For XG21 LVDS */ - pVBInfo->IF_DEF_LVDS = 1; + if (pVBInfo->IF_DEF_LVDS) { /* For XG21 LVDS */ xgifb_reg_or(pVBInfo->P3d4, 0x32, LCDSense); /* LVDS on chip */ xgifb_reg_and_or(pVBInfo->P3d4, 0x38, ~0xE0, 0xC0); @@ -1393,7 +1416,6 @@ static void XGINew_GetXG27Sense(struct xgi_hw_device_info *HwDeviceExtension, xgifb_reg_set(pVBInfo->P3d4, 0x4A, bCR4A); if (Temp <= 0x02) { - pVBInfo->IF_DEF_LVDS = 1; /* LVDS setting */ xgifb_reg_and_or(pVBInfo->P3d4, 0x38, ~0xE0, 0xC0); xgifb_reg_set(pVBInfo->P3d4, 0x30, 0x21); @@ -1451,24 +1473,15 @@ unsigned char XGIInitNew(struct pci_dev *pdev) struct vb_device_info *pVBInfo = &VBINF; unsigned char i, temp = 0, temp1; /* VBIOSVersion[5]; */ - volatile unsigned char *pVideoMemory; /* unsigned long j, k; */ - pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase; - pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress; pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress; - pVideoMemory = (unsigned char *) pVBInfo->ROMAddr; - /* Newdebugcode(0x99); */ - - /* if (pVBInfo->ROMAddr == 0) */ - /* return(0); */ - if (pVBInfo->FBAddr == NULL) { printk("\n pVBInfo->FBAddr == 0 "); return 0; @@ -1516,8 +1529,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev) InitTo330Pointer(HwDeviceExtension->jChipType, pVBInfo); - /* ReadVBIOSData */ - ReadVBIOSTablData(HwDeviceExtension->jChipType, pVBInfo); + xgifb_read_vbios(pdev, pVBInfo); /* 1.Openkey */ xgifb_reg_set(pVBInfo->P3c4, 0x05, 0x86); @@ -1774,7 +1786,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev) pVBInfo); printk("20"); - XGINew_SetDRAMSize_340(HwDeviceExtension, pVBInfo); + XGINew_SetDRAMSize_340(xgifb_info, HwDeviceExtension, pVBInfo); printk("21"); printk("22"); diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c index 81c0cc41bb4..67a316c3c10 100644 --- a/drivers/staging/xgifb/vb_setmode.c +++ b/drivers/staging/xgifb/vb_setmode.c @@ -67,11 +67,6 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) pVBInfo->XGINEWUB_CRT1Table = (struct XGI_CRT1TableStruct *) XGI_CRT1Table; - /* add for new UNIVGABIOS */ - /* XGINew_UBLCDDataTable = - * (struct XGI_LCDDataTablStruct *) XGI_LCDDataTable; */ - /* XGINew_UBTVDataTable = (XGI_TVDataTablStruct *) XGI_TVDataTable; */ - pVBInfo->MCLKData = (struct XGI_MCLKDataStruct *) XGI340New_MCLKData; pVBInfo->ECLKData = (struct XGI_ECLKDataStruct *) XGI340_ECLKData; pVBInfo->VCLKData = (struct XGI_VCLKDataStruct *) XGI_VCLKData; @@ -148,9 +143,6 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) else pVBInfo->LCDCapList = XGI_LCDCapList; - if ((ChipType == XG21) || (ChipType == XG27)) - pVBInfo->XG21_LVDSCapList = XGI21_LCDCapList; - pVBInfo->XGI_TVDelayList = XGI301TVDelayList; pVBInfo->XGI_TVDelayList2 = XGI301TVDelayList2; @@ -236,28 +228,6 @@ static void XGI_SetSeqRegs(unsigned short ModeNo, } } -static void XGI_SetMiscRegs(unsigned short StandTableIndex, - struct vb_device_info *pVBInfo) -{ - unsigned char Miscdata; - - /* Get Misc from file */ - Miscdata = pVBInfo->StandTable[StandTableIndex].MISC; - /* - if (pVBInfo->VBType & (VB_XGI301B | - VB_XGI302B | - VB_XGI301LV | - VB_XGI302LV | - VB_XGI301C)) { - if (pVBInfo->VBInfo & SetCRT2ToLCDA) { - Miscdata |= 0x0C; - } - } - */ - - outb(Miscdata, pVBInfo->P3c2); /* Set Misc(3c2) */ -} - static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension, unsigned short StandTableIndex, struct vb_device_info *pVBInfo) @@ -274,16 +244,6 @@ static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension, CRTCdata = pVBInfo->StandTable[StandTableIndex].CRTC[i]; xgifb_reg_set(pVBInfo->P3d4, i, CRTCdata); /* Set CRTC(3d4) */ } - /* - if ((HwDeviceExtension->jChipType == XGI_630) && - (HwDeviceExtension->jChipRevision == 0x30)) { - if (pVBInfo->VBInfo & SetInSlaveMode) { - if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { - xgifb_reg_set(pVBInfo->P3d4, 0x18, 0xFE); - } - } - } - */ } static void XGI_SetATTRegs(unsigned short ModeNo, @@ -530,10 +490,6 @@ static void XGI_SetCRT1Timing_H(struct vb_device_info *pVBInfo, unsigned char data, data1, pushax; unsigned short i, j; - /* xgifb_reg_set(pVBInfo->P3d4, 0x51, 0); */ - /* xgifb_reg_set(pVBInfo->P3d4, 0x56, 0); */ - /* xgifb_reg_and_or(pVBInfo->P3d4, 0x11, 0x7f, 0x00); */ - /* unlock cr0-7 */ data = (unsigned char) xgifb_reg_get(pVBInfo->P3d4, 0x11); data &= 0x7F; @@ -595,10 +551,6 @@ static void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex, unsigned char data; unsigned short i, j; - /* xgifb_reg_set(pVBInfo->P3d4, 0x51, 0); */ - /* xgifb_reg_set(pVBInfo->P3d4, 0x56, 0); */ - /* xgifb_reg_and_or(pVBInfo->P3d4, 0x11, 0x7f, 0x00); */ - for (i = 0x00; i <= 0x01; i++) { data = pVBInfo->TimingV[0].data[i]; xgifb_reg_set(pVBInfo->P3d4, (unsigned short) (i + 6), data); @@ -976,6 +928,20 @@ static void XGI_SetXG27CRTC(unsigned short ModeNo, } } +static void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo) +{ + unsigned char temp; + + /* D[1:0] 01: 18bit, 00: dual 12, 10: single 24 */ + temp = xgifb_reg_get(pVBInfo->P3d4, 0x37); + temp = (temp & 3) << 6; + /* SR06[7]0: dual 12/1: single 24 [6] 18bit Dither <= 0 h/w recommend */ + xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0xc0, temp & 0x80); + /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: 24bits */ + xgifb_reg_and_or(pVBInfo->P3c4, 0x09, ~0xc0, temp | 0x80); + +} + static void xgifb_set_lcd(int chip_id, struct vb_device_info *pVBInfo, unsigned short RefreshRateTableIndex, @@ -1088,6 +1054,20 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo, } } +static unsigned short XGI_GetResInfo(unsigned short ModeNo, + unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) +{ + unsigned short resindex; + + if (ModeNo <= 0x13) + /* si+St_ResInfo */ + resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; + else + /* si+Ext_ResInfo */ + resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + return resindex; +} + static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, @@ -1127,9 +1107,6 @@ static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension, tempcx = 8; - /* if (!(modeflag & Charx8Dot)) */ - /* tempcx = 9; */ - tempax /= tempcx; tempax -= 1; tempbx -= 1; @@ -1163,20 +1140,6 @@ static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension, xgifb_reg_set(pVBInfo->P3d4, 0x11, temp); } -unsigned short XGI_GetResInfo(unsigned short ModeNo, - unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) -{ - unsigned short resindex; - - if (ModeNo <= 0x13) - /* si+St_ResInfo */ - resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - else - /* si+Ext_ResInfo */ - resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - return resindex; -} - static void XGI_SetCRT1Offset(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, @@ -1308,77 +1271,55 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo, VCLKIndex = LCDXlat2VCLK[CRT2Index]; else VCLKIndex = LCDXlat1VCLK[CRT2Index]; - } else { /* for TV */ - if (pVBInfo->VBInfo & SetCRT2ToTV) { - if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) { - if (pVBInfo->SetFlag & RPLLDIV2XO) { - VCLKIndex = HiTVVCLKDIV2; - VCLKIndex += 25; - } else { - VCLKIndex = HiTVVCLK; - VCLKIndex += 25; - } - - if (pVBInfo->SetFlag & TVSimuMode) { - if (modeflag & Charx8Dot) { - VCLKIndex = - HiTVSimuVCLK; - VCLKIndex += 25; - } else { - VCLKIndex = - HiTVTextVCLK; - VCLKIndex += 25; - } - } + } else if (pVBInfo->VBInfo & SetCRT2ToHiVisionTV) { + if (pVBInfo->SetFlag & RPLLDIV2XO) { + VCLKIndex = HiTVVCLKDIV2; + VCLKIndex += 25; + } else { + VCLKIndex = HiTVVCLK; + VCLKIndex += 25; + } - /* 301lv */ - if (pVBInfo->VBType & VB_XGI301LV) { - if (!(pVBInfo->VBExtInfo == - VB_YPbPr1080i)) { - VCLKIndex = - YPbPr750pVCLK; - if (!(pVBInfo->VBExtInfo - == - VB_YPbPr750p)) { - VCLKIndex = - YPbPr525pVCLK; - if (!(pVBInfo->VBExtInfo - == VB_YPbPr525p)) { - VCLKIndex - = YPbPr525iVCLK_2; - if (!(pVBInfo->SetFlag - & RPLLDIV2XO)) - VCLKIndex - = YPbPr525iVCLK; - } - } - } - } + if (pVBInfo->SetFlag & TVSimuMode) { + if (modeflag & Charx8Dot) { + VCLKIndex = HiTVSimuVCLK; + VCLKIndex += 25; } else { - if (pVBInfo->VBInfo & SetCRT2ToTV) { - if (pVBInfo->SetFlag & - RPLLDIV2XO) { - VCLKIndex = TVVCLKDIV2; - VCLKIndex += 25; - } else { - VCLKIndex = TVVCLK; - VCLKIndex += 25; - } - } + VCLKIndex = HiTVTextVCLK; + VCLKIndex += 25; } - } else { /* for CRT2 */ - /* Port 3cch */ - VCLKIndex = (unsigned char) inb( - (pVBInfo->P3ca + 0x02)); - VCLKIndex = ((VCLKIndex >> 2) & 0x03); - if (ModeNo > 0x13) { - /* di+Ext_CRTVCLK */ - VCLKIndex = - pVBInfo->RefIndex[ + } + + /* 301lv */ + if ((pVBInfo->VBType & VB_XGI301LV) && + !(pVBInfo->VBExtInfo == VB_YPbPr1080i)) { + if (pVBInfo->VBExtInfo == VB_YPbPr750p) + VCLKIndex = YPbPr750pVCLK; + else if (pVBInfo->VBExtInfo == VB_YPbPr525p) + VCLKIndex = YPbPr525pVCLK; + else if (pVBInfo->SetFlag & RPLLDIV2XO) + VCLKIndex = YPbPr525iVCLK_2; + else + VCLKIndex = YPbPr525iVCLK; + } + } else if (pVBInfo->VBInfo & SetCRT2ToTV) { + if (pVBInfo->SetFlag & RPLLDIV2XO) { + VCLKIndex = TVVCLKDIV2; + VCLKIndex += 25; + } else { + VCLKIndex = TVVCLK; + VCLKIndex += 25; + } + } else { /* for CRT2 */ + /* Port 3cch */ + VCLKIndex = (unsigned char) inb((pVBInfo->P3ca + 0x02)); + VCLKIndex = ((VCLKIndex >> 2) & 0x03); + if (ModeNo > 0x13) { + /* di+Ext_CRTVCLK */ + VCLKIndex = pVBInfo->RefIndex[ RefreshRateTableIndex]. Ext_CRTVCLK; - VCLKIndex &= IndexMask; - } + VCLKIndex &= IndexMask; } } } else { /* LVDS */ @@ -1397,7 +1338,6 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo, else VCLKIndex = LVDSXlat3VCLK[VCLKIndex]; } - /* VCLKIndex = VCLKIndex&IndexMask; */ return VCLKIndex; } @@ -1461,6 +1401,19 @@ static void XGI_SetCRT1VCLK(unsigned short ModeNo, } } +static void XGI_SetXG21FPBits(struct vb_device_info *pVBInfo) +{ + unsigned char temp; + + temp = xgifb_reg_get(pVBInfo->P3d4, 0x37); /* D[0] 1: 18bit */ + temp = (temp & 1) << 6; + /* SR06[6] 18bit Dither */ + xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0x40, temp); + /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: dual 12bits */ + xgifb_reg_and_or(pVBInfo->P3c4, 0x09, ~0xc0, temp | 0x80); + +} + static void XGI_SetCRT1FIFO(unsigned short ModeNo, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) @@ -1532,16 +1485,6 @@ static void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension, xgifb_reg_set(pVBInfo->P3c4, 0x1F, data); } - /* Jong for Adavantech LCD ripple issue - if ((VCLK >= 0) && (VCLK < 135)) - data2 = 0x03; - else if ((VCLK >= 135) && (VCLK < 160)) - data2 = 0x02; - else if ((VCLK >= 160) && (VCLK < 260)) - data2 = 0x01; - else if (VCLK > 260) - data2 = 0x00; - */ data2 = 0x00; xgifb_reg_and_or(pVBInfo->P3c4, 0x07, 0xFC, data2); @@ -1591,7 +1534,6 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension, data2 |= 0x20; xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0x3F, data2); - /* xgifb_reg_set(pVBInfo->P3c4,0x06,data2); */ resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); if (ModeNo <= 0x13) xres = pVBInfo->StResInfo[resindex].HTotal; @@ -1636,11 +1578,6 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension, XGI_SetVCLKState(HwDeviceExtension, ModeNo, RefreshRateTableIndex, pVBInfo); - /* if (modeflag&HalfDCLK) //030305 fix lowresolution bug */ - /* if (XGINew_IF_DEF_NEW_LOWRES) */ - /* XGI_VesaLowResolution(ModeNo, ModeIdIndex); - * //030305 fix lowresolution bug */ - data = xgifb_reg_get(pVBInfo->P3d4, 0x31); if (HwDeviceExtension->jChipType == XG27) { @@ -1803,11 +1740,6 @@ static void XGI_GetLVDSResInfo(unsigned short ModeNo, /* si+Ext_ResInfo */ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - /* if (ModeNo > 0x13) */ - /* modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; */ - /* else */ - /* modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; */ - if (ModeNo <= 0x13) /* si+St_ResInfo */ resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; @@ -1815,8 +1747,6 @@ static void XGI_GetLVDSResInfo(unsigned short ModeNo, /* si+Ext_ResInfo */ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - /* resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); */ - if (ModeNo <= 0x13) { xres = pVBInfo->StResInfo[resindex].HTotal; yres = pVBInfo->StResInfo[resindex].VTotal; @@ -1831,13 +1761,10 @@ static void XGI_GetLVDSResInfo(unsigned short ModeNo, if (modeflag & DoubleScanMode) yres = yres << 1; } - /* if (modeflag & Charx8Dot) */ - /* { */ if (xres == 720) xres = 640; - /* } */ pVBInfo->VGAHDE = xres; pVBInfo->HDE = xres; pVBInfo->VGAVDE = yres; @@ -1890,7 +1817,7 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, tempal = (tempal & 0x0f); } - tempcx = LCDLenList[tempbx]; /* mov cl,byte ptr cs:LCDLenList[bx] */ + tempcx = LCDLenList[tempbx]; if (pVBInfo->LCDInfo & EnableScalingLCD) { /* ScaleLCD */ if ((tempbx == 5) || (tempbx) == 7) @@ -1898,9 +1825,6 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, else if ((tempbx == 3) || (tempbx == 8)) tempcx = LVDSDesDataLen2; } - /* mov di, word ptr cs:LCDDataList[bx] */ - /* tempdi = pVideoMemory[LCDDataList + tempbx * 2] | - (pVideoMemory[LCDDataList + tempbx * 2 + 1] << 8); */ switch (tempbx) { case 0: @@ -2321,10 +2245,10 @@ static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo, switch (tempbx) { case 0: - tempdi = NULL; /*EPLCHTVCRT1Ptr_H;*/ + tempdi = NULL; break; case 1: - tempdi = NULL; /*EPLCHTVCRT1Ptr_V;*/ + tempdi = NULL; break; case 2: case 6: @@ -2363,9 +2287,7 @@ static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo, } /* 07/05/22 */ - if (table == 0x00) { - } else if (table == 0x01) { - } else if (table == 0x04) { + if (table == 0x04) { switch (tempdi[i].DATAPTR) { case 0: return &XGI_ExtPALData[tempal]; @@ -2429,7 +2351,6 @@ static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo, default: break; } - } else if (table == 0x06) { } return NULL; } @@ -2741,7 +2662,6 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex, else tempbx = LCDPtr->LCDVRS; - /* tempbx = tempbx >> 4; */ tempcx = push1; if (pVBInfo->LCDInfo & EnableScalingLCD) @@ -2881,7 +2801,6 @@ static void XGI_GetLCDVCLKPtr(unsigned char *di_0, unsigned char *di_1, unsigned short index; if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - /* index = XGI_GetLCDCapPtr(pVBInfo); */ index = XGI_GetLCDCapPtr1(pVBInfo); if (pVBInfo->VBInfo & SetCRT2ToLCD) { /* LCDB */ @@ -3105,19 +3024,6 @@ static void XGI_UpdateModeInfo(struct xgi_hw_device_info *HwDeviceExtension, } } -void XGI_GetVGAType(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *pVBInfo) -{ - /* - if ( HwDeviceExtension->jChipType >= XG20 ) { - pVBInfo->Set_VGAType = XG20; - } else { - pVBInfo->Set_VGAType = VGA_XGI340; - } - */ - pVBInfo->Set_VGAType = HwDeviceExtension->jChipType; -} - void XGI_GetVBType(struct vb_device_info *pVBInfo) { unsigned short flag, tempbx, tempah; @@ -3160,7 +3066,7 @@ void XGI_GetVBType(struct vb_device_info *pVBInfo) } } -void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, +static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) { @@ -3193,14 +3099,9 @@ void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, if (pVBInfo->IF_DEF_LCDA == 1) { - if ((pVBInfo->Set_VGAType >= XG20) - || (pVBInfo->Set_VGAType >= XG40)) { + if ((HwDeviceExtension->jChipType >= XG20) || + (HwDeviceExtension->jChipType >= XG40)) { if (pVBInfo->IF_DEF_LVDS == 0) { - /* if ((pVBInfo->VBType & VB_XGI302B) - || (pVBInfo->VBType & VB_XGI301LV) - || (pVBInfo->VBType & VB_XGI302LV) - || (pVBInfo->VBType & VB_XGI301C)) - */ if (pVBInfo->VBType & (VB_XGI302B | VB_XGI301LV | @@ -3225,7 +3126,7 @@ void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, ((pVBInfo->VBType & VB_XGI301LV) || (pVBInfo->VBType & VB_XGI302LV) || (pVBInfo->VBType & VB_XGI301C)))) { - if (temp & SetYPbPr) { /* temp = CR38 */ + if (temp & SetYPbPr) { if (pVBInfo->IF_DEF_HiVision == 1) { /* shampoo add for new * scratch */ @@ -3242,8 +3143,6 @@ void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, SetCRT2ToYPbPr; } } - - /* tempbx |= SetCRT2ToYPbPr; */ } } } @@ -3368,7 +3267,7 @@ void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, pVBInfo->VBInfo = tempbx; } -void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, +static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { unsigned short temp, tempbx = 0, resinfo = 0, modeflag, index1; @@ -3404,17 +3303,6 @@ void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx &= (SetCHTVOverScan | SetNTSCJ | SetPALTV); - /* - if (pVBInfo->IF_DEF_LVDS == 0) { - //PAL-M/PAL-N Info - index1 = xgifb_reg_get(pVBInfo->P3d4, 0x38); - //00:PAL, 01:PAL-M, 10:PAL-N - temp2 = (index1 & 0xC0) >> 5; - tempbx |= temp2; - if (temp2 & 0x02) //PAL-M - tempbx &= (~SetPALTV); - } - */ } if (pVBInfo->IF_DEF_LVDS == 0) { @@ -3476,8 +3364,8 @@ void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, pVBInfo->TVInfo = tempbx; } -unsigned char XGI_GetLCDInfo(unsigned short ModeNo, unsigned short ModeIdIndex, - struct vb_device_info *pVBInfo) +static unsigned char XGI_GetLCDInfo(unsigned short ModeNo, + unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { unsigned short temp, tempax, tempbx, modeflag, resinfo = 0, LCDIdIndex; @@ -3553,15 +3441,8 @@ unsigned char XGI_GetLCDInfo(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx |= SetLCDtoNonExpanding; } - /* - if (tempax & LCDBToA) { - tempbx |= SetLCDBToA; - } - */ - if (pVBInfo->IF_DEF_ExpLink == 1) { if (modeflag & HalfDCLK) { - /* if (!(pVBInfo->LCDInfo&LCDNonExpanding)) */ if (!(tempbx & SetLCDtoNonExpanding)) { tempbx |= EnableLVDSDDA; } else { @@ -3604,25 +3485,6 @@ unsigned char XGI_GetLCDInfo(unsigned short ModeNo, unsigned short ModeIdIndex, } } - /* - if (pVBInfo->IF_DEF_LVDS == 0) { - if (tempax & (LockLCDBToA | StLCDBToA)) { - if (pVBInfo->VBInfo & SetInSlaveMode) { - if (!((!(tempax & LockLCDBToA)) && - (ModeNo > 0x13))) { - pVBInfo->VBInfo &= - ~(SetSimuScanMode | - SetInSlaveMode | - SetCRT2ToLCD); - pVBInfo->VBInfo |= - SetCRT2ToLCDA | - SetCRT2ToDualEdge; - } - } - } - } - */ - return 1; } @@ -3632,10 +3494,6 @@ unsigned char XGI_SearchModeID(unsigned short ModeNo, if (ModeNo <= 5) ModeNo |= 1; if (ModeNo <= 0x13) { - /* for (*ModeIdIndex=0; - *ModeIdIndex < sizeof(pVBInfo->SModeIDTable) - / sizeof(struct XGI_StStruct); - (*ModeIdIndex)++) */ for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID == ModeNo) @@ -3651,10 +3509,6 @@ unsigned char XGI_SearchModeID(unsigned short ModeNo, (*ModeIdIndex) += 2; /* 400 lines */ /* else 350 lines */ } else { - /* for (*ModeIdIndex=0; - *ModeIdIndex < sizeof(pVBInfo->EModeIDTable) - / sizeof(struct XGI_ExtStruct); - (*ModeIdIndex)++) */ for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo) @@ -3675,7 +3529,6 @@ static unsigned char XG21GPIODataTransfer(unsigned char ujDate) for (i = 0; i < 8; i++) { ujRet = ujRet << 1; - /* ujRet |= GETBITS(ujDate >> i, 0:0); */ ujRet |= (ujDate >> i) & 1; } @@ -3726,7 +3579,101 @@ static unsigned char XGI_XG27GetPSCValue(struct vb_device_info *pVBInfo) return temp; } -void XGI_DisplayOn(struct xgi_hw_device_info *pXGIHWDE, +/*----------------------------------------------------------------------------*/ +/* input */ +/* bl[5] : 1;LVDS signal on */ +/* bl[1] : 1;LVDS backlight on */ +/* bl[0] : 1:LVDS VDD on */ +/* bh: 100000b : clear bit 5, to set bit5 */ +/* 000010b : clear bit 1, to set bit1 */ +/* 000001b : clear bit 0, to set bit0 */ +/*----------------------------------------------------------------------------*/ +static void XGI_XG21BLSignalVDD(unsigned short tempbh, unsigned short tempbl, + struct vb_device_info *pVBInfo) +{ + unsigned char CR4A, temp; + + CR4A = xgifb_reg_get(pVBInfo->P3d4, 0x4A); + tempbh &= 0x23; + tempbl &= 0x23; + xgifb_reg_and(pVBInfo->P3d4, 0x4A, ~tempbh); /* enable GPIO write */ + + if (tempbh & 0x20) { + temp = (tempbl >> 4) & 0x02; + + /* CR B4[1] */ + xgifb_reg_and_or(pVBInfo->P3d4, 0xB4, ~0x02, temp); + + } + + temp = xgifb_reg_get(pVBInfo->P3d4, 0x48); + + temp = XG21GPIODataTransfer(temp); + temp &= ~tempbh; + temp |= tempbl; + xgifb_reg_set(pVBInfo->P3d4, 0x48, temp); +} + +static void XGI_XG27BLSignalVDD(unsigned short tempbh, unsigned short tempbl, + struct vb_device_info *pVBInfo) +{ + unsigned char CR4A, temp; + unsigned short tempbh0, tempbl0; + + tempbh0 = tempbh; + tempbl0 = tempbl; + tempbh0 &= 0x20; + tempbl0 &= 0x20; + tempbh0 >>= 3; + tempbl0 >>= 3; + + if (tempbh & 0x20) { + temp = (tempbl >> 4) & 0x02; + + /* CR B4[1] */ + xgifb_reg_and_or(pVBInfo->P3d4, 0xB4, ~0x02, temp); + + } + xgifb_reg_and_or(pVBInfo->P3d4, 0xB4, ~tempbh0, tempbl0); + + CR4A = xgifb_reg_get(pVBInfo->P3d4, 0x4A); + tempbh &= 0x03; + tempbl &= 0x03; + tempbh <<= 2; + tempbl <<= 2; /* GPIOC,GPIOD */ + xgifb_reg_and(pVBInfo->P3d4, 0x4A, ~tempbh); /* enable GPIO write */ + xgifb_reg_and_or(pVBInfo->P3d4, 0x48, ~tempbh, tempbl); +} + +/* --------------------------------------------------------------------- */ +/* Function : XGI_XG21SetPanelDelay */ +/* Input : */ +/* Output : */ +/* Description : */ +/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */ +/* : bl : 2 ; T2 : the duration signal on and Vdd on */ +/* : bl : 3 ; T3 : the duration between CPL off and signal off */ +/* : bl : 4 ; T4 : the duration signal off and Vdd off */ +/* --------------------------------------------------------------------- */ +static void XGI_XG21SetPanelDelay(struct xgifb_video_info *xgifb_info, + unsigned short tempbl, + struct vb_device_info *pVBInfo) +{ + if (tempbl == 1) + mdelay(xgifb_info->lvds_data.PSC_S1); + + if (tempbl == 2) + mdelay(xgifb_info->lvds_data.PSC_S2); + + if (tempbl == 3) + mdelay(xgifb_info->lvds_data.PSC_S3); + + if (tempbl == 4) + mdelay(xgifb_info->lvds_data.PSC_S4); +} + +static void XGI_DisplayOn(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *pXGIHWDE, struct vb_device_info *pVBInfo) { @@ -3736,12 +3683,12 @@ void XGI_DisplayOn(struct xgi_hw_device_info *pXGIHWDE, if (!(XGI_XG21GetPSCValue(pVBInfo) & 0x1)) { /* LVDS VDD on */ XGI_XG21BLSignalVDD(0x01, 0x01, pVBInfo); - XGI_XG21SetPanelDelay(2, pVBInfo); + XGI_XG21SetPanelDelay(xgifb_info, 2, pVBInfo); } if (!(XGI_XG21GetPSCValue(pVBInfo) & 0x20)) /* LVDS signal on */ XGI_XG21BLSignalVDD(0x20, 0x20, pVBInfo); - XGI_XG21SetPanelDelay(3, pVBInfo); + XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); /* LVDS backlight on */ XGI_XG21BLSignalVDD(0x02, 0x02, pVBInfo); } else { @@ -3756,12 +3703,12 @@ void XGI_DisplayOn(struct xgi_hw_device_info *pXGIHWDE, if (!(XGI_XG27GetPSCValue(pVBInfo) & 0x1)) { /* LVDS VDD on */ XGI_XG27BLSignalVDD(0x01, 0x01, pVBInfo); - XGI_XG21SetPanelDelay(2, pVBInfo); + XGI_XG21SetPanelDelay(xgifb_info, 2, pVBInfo); } if (!(XGI_XG27GetPSCValue(pVBInfo) & 0x20)) /* LVDS signal on */ XGI_XG27BLSignalVDD(0x20, 0x20, pVBInfo); - XGI_XG21SetPanelDelay(3, pVBInfo); + XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); /* LVDS backlight on */ XGI_XG27BLSignalVDD(0x02, 0x02, pVBInfo); } else { @@ -3772,7 +3719,8 @@ void XGI_DisplayOn(struct xgi_hw_device_info *pXGIHWDE, } } -void XGI_DisplayOff(struct xgi_hw_device_info *pXGIHWDE, +void XGI_DisplayOff(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *pXGIHWDE, struct vb_device_info *pVBInfo) { @@ -3780,7 +3728,7 @@ void XGI_DisplayOff(struct xgi_hw_device_info *pXGIHWDE, if (pVBInfo->IF_DEF_LVDS == 1) { /* LVDS backlight off */ XGI_XG21BLSignalVDD(0x02, 0x00, pVBInfo); - XGI_XG21SetPanelDelay(3, pVBInfo); + XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); } else { /* DVO/DVI signal off */ XGI_XG21BLSignalVDD(0x20, 0x00, pVBInfo); @@ -3791,7 +3739,7 @@ void XGI_DisplayOff(struct xgi_hw_device_info *pXGIHWDE, if ((XGI_XG27GetPSCValue(pVBInfo) & 0x2)) { /* LVDS backlight off */ XGI_XG27BLSignalVDD(0x02, 0x00, pVBInfo); - XGI_XG21SetPanelDelay(3, pVBInfo); + XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); } if (pVBInfo->IF_DEF_LVDS == 0) @@ -3838,26 +3786,17 @@ static void XGI_GetCRT2ResInfo(unsigned short ModeNo, if (ModeNo <= 0x13) { xres = pVBInfo->StResInfo[resindex].HTotal; yres = pVBInfo->StResInfo[resindex].VTotal; - /* si+St_ResInfo */ - /* modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;*/ } else { xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */ /* si+St_ModeFlag */ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - /* - if (pVBInfo->IF_DEF_FSTN) { - xres *= 2; - yres *= 2; - } else { - */ if (modeflag & HalfDCLK) xres *= 2; if (modeflag & DoubleScanMode) yres *= 2; - /* } */ } if (pVBInfo->VBInfo & SetCRT2ToLCD) { @@ -4028,8 +3967,6 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx = 775; else if (pVBInfo->VGAVDE == 600) tempbx = 775; - /* else if (pVBInfo->VGAVDE==350) tempbx=560; */ - /* else if (pVBInfo->VGAVDE==400) tempbx=640; */ else tempbx = 768; } else @@ -4294,7 +4231,6 @@ static void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex, XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex, HwDeviceExtension, pVBInfo); XGI_SetCRT2FIFO(pVBInfo); - /* XGI_SetCRT2Sync(ModeNo,RefreshRateTableIndex); */ for (tempcx = 4; tempcx < 7; tempcx++) xgifb_reg_set(pVBInfo->Part1Port, tempcx, 0x0); @@ -4497,9 +4433,6 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, temp = 0xFF; /* set MAX HT */ xgifb_reg_set(pVBInfo->Part1Port, 0x03, temp); - /* if (modeflag & Charx8Dot) */ - /* tempcx = 0x08; */ - /* else */ tempcx = 0x08; if (pVBInfo->VBType & (VB_XGI301LV | VB_XGI302LV | VB_XGI301C)) @@ -4565,7 +4498,6 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, } } } else { - /* tempcx = tempbx & 0x00FF ; */ tempbx = (tempbx & 0xFF00) >> 8; tempcx = (tempcx + tempbx) >> 1; temp = (tempcx & 0x00FF) + 2; @@ -4579,36 +4511,23 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, temp -= 6; } } - } else { - if (!(modeflag & HalfDCLK)) { - temp -= 4; - if (pVBInfo->LCDResInfo != Panel1280x960) { - if (pVBInfo->VGAHDE >= 800) { - temp -= 7; - if (pVBInfo->ModeType == - ModeEGA) { - if (pVBInfo->VGAVDE == - 1024) { - temp += 15; - if (pVBInfo->LCDResInfo != Panel1280x1024) { - temp += - 7; - } - } - } - - if (pVBInfo->VGAHDE >= 1280) { - if (pVBInfo->LCDResInfo - != Panel1280x960) { - if (pVBInfo->LCDInfo - & LCDNonExpanding) { - temp - += 28; - } - } - } - } + } else if (!(modeflag & HalfDCLK)) { + temp -= 4; + if (pVBInfo->LCDResInfo != Panel1280x960 && + pVBInfo->VGAHDE >= 800) { + temp -= 7; + if (pVBInfo->ModeType == ModeEGA && + pVBInfo->VGAVDE == 1024) { + temp += 15; + if (pVBInfo->LCDResInfo != + Panel1280x1024) + temp += 7; } + + if (pVBInfo->VGAHDE >= 1280 && + pVBInfo->LCDResInfo != Panel1280x960 && + (pVBInfo->LCDInfo & LCDNonExpanding)) + temp += 28; } } } @@ -5297,7 +5216,6 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex, tempax--; xgifb_reg_and(pVBInfo->Part2Port, 0x01, tempax); - /* if ( !( pVBInfo->VBType & VB_XGI301C ) ) */ xgifb_reg_and(pVBInfo->Part2Port, 0x00, 0xEF); } @@ -5436,7 +5354,6 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex, tempax = pVBInfo->VT; tempbx = pVBInfo->LCDVRS; - /* if (SetLCD_Info & EnableScalingLCD) */ tempcx += tempbx; if (tempcx >= tempax) tempcx -= tempax; @@ -5478,12 +5395,10 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex, temp = (tempcx & 0xFF00) >> 8; xgifb_reg_set(pVBInfo->Part2Port, 0x25, temp); - /* getlcdsync() */ XGI_GetLCDSync(&tempax, &tempbx, pVBInfo); tempcx = tempax; tempax = pVBInfo->HT; tempbx = pVBInfo->LCDHRS; - /* if ( SetLCD_Info & EnableScalingLCD) */ if (XGI_IsLCDDualLink(pVBInfo)) { tempax = tempax >> 1; tempbx = tempbx >> 1; @@ -5801,9 +5716,6 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex, if (XGI_IsLCDDualLink(pVBInfo)) tempax = tempax >> 1; - /* if((pVBInfo->VBInfo&(SetCRT2ToLCD)) || - ((pVBInfo->TVInfo&SetYPbPrMode525p) || - (pVBInfo->TVInfo&SetYPbPrMode750p))) { */ if (pVBInfo->VBInfo & SetCRT2ToLCD) { if (tempax > 800) tempax -= 800; @@ -5817,33 +5729,6 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex, } tempax -= 1; - /* - if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToHiVisionTV)) { - if (pVBInfo->VBType & VB_XGI301LV) { - if (!(pVBInfo->TVInfo & - (SetYPbPrMode525p | - SetYPbPrMode750p | - SetYPbPrMode1080i))) { - if (pVBInfo->VGAHDE > 800) { - if (pVBInfo->VGAHDE == 1024) - tempax =(tempax * 25 / - 32) - 1; - else - tempax = (tempax * 20 / - 32) - 1; - } - } - } else { - if (pVBInfo->VGAHDE > 800) { - if (pVBInfo->VGAHDE == 1024) - tempax = (tempax * 25 / 32) - 1; - else - tempax = (tempax * 20 / 32) - 1; - } - } - } - */ - temp = (tempax & 0xFF00) >> 8; temp = ((temp & 0x0003) << 4); xgifb_reg_set(pVBInfo->Part4Port, 0x1E, temp); @@ -5902,7 +5787,6 @@ static void XGI_SetGroup5(unsigned short ModeNo, unsigned short ModeIdIndex, if (!(pVBInfo->VBInfo & (SetInSlaveMode | LoadDACFlag | CRT2DisplayFlag))) { XGINew_EnableCRT2(pVBInfo); - /* LoadDAC2(pVBInfo->Part5Port, ModeNo, ModeIdIndex); */ } } return; @@ -5921,118 +5805,11 @@ static void XGI_DisableGatingCRT(struct xgi_hw_device_info *HwDeviceExtension, xgifb_reg_and_or(pVBInfo->P3d4, 0x63, 0xBF, 0x00); } -/*----------------------------------------------------------------------------*/ -/* input */ -/* bl[5] : 1;LVDS signal on */ -/* bl[1] : 1;LVDS backlight on */ -/* bl[0] : 1:LVDS VDD on */ -/* bh: 100000b : clear bit 5, to set bit5 */ -/* 000010b : clear bit 1, to set bit1 */ -/* 000001b : clear bit 0, to set bit0 */ -/*----------------------------------------------------------------------------*/ -void XGI_XG21BLSignalVDD(unsigned short tempbh, unsigned short tempbl, - struct vb_device_info *pVBInfo) -{ - unsigned char CR4A, temp; - - CR4A = xgifb_reg_get(pVBInfo->P3d4, 0x4A); - tempbh &= 0x23; - tempbl &= 0x23; - xgifb_reg_and(pVBInfo->P3d4, 0x4A, ~tempbh); /* enable GPIO write */ - - if (tempbh & 0x20) { - temp = (tempbl >> 4) & 0x02; - - /* CR B4[1] */ - xgifb_reg_and_or(pVBInfo->P3d4, 0xB4, ~0x02, temp); - - } - - temp = xgifb_reg_get(pVBInfo->P3d4, 0x48); - - temp = XG21GPIODataTransfer(temp); - temp &= ~tempbh; - temp |= tempbl; - xgifb_reg_set(pVBInfo->P3d4, 0x48, temp); -} - -void XGI_XG27BLSignalVDD(unsigned short tempbh, unsigned short tempbl, - struct vb_device_info *pVBInfo) -{ - unsigned char CR4A, temp; - unsigned short tempbh0, tempbl0; - - tempbh0 = tempbh; - tempbl0 = tempbl; - tempbh0 &= 0x20; - tempbl0 &= 0x20; - tempbh0 >>= 3; - tempbl0 >>= 3; - - if (tempbh & 0x20) { - temp = (tempbl >> 4) & 0x02; - - /* CR B4[1] */ - xgifb_reg_and_or(pVBInfo->P3d4, 0xB4, ~0x02, temp); - - } - xgifb_reg_and_or(pVBInfo->P3d4, 0xB4, ~tempbh0, tempbl0); - - CR4A = xgifb_reg_get(pVBInfo->P3d4, 0x4A); - tempbh &= 0x03; - tempbl &= 0x03; - tempbh <<= 2; - tempbl <<= 2; /* GPIOC,GPIOD */ - xgifb_reg_and(pVBInfo->P3d4, 0x4A, ~tempbh); /* enable GPIO write */ - xgifb_reg_and_or(pVBInfo->P3d4, 0x48, ~tempbh, tempbl); -} - -/* --------------------------------------------------------------------- */ -unsigned short XGI_GetLVDSOEMTableIndex(struct vb_device_info *pVBInfo) -{ - unsigned short index; - - index = xgifb_reg_get(pVBInfo->P3d4, 0x36); - if (index < sizeof(XGI21_LCDCapList) - / sizeof(struct XGI21_LVDSCapStruct)) - return index; - return 0; -} - -/* --------------------------------------------------------------------- */ -/* Function : XGI_XG21SetPanelDelay */ -/* Input : */ -/* Output : */ -/* Description : */ -/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */ -/* : bl : 2 ; T2 : the duration signal on and Vdd on */ -/* : bl : 3 ; T3 : the duration between CPL off and signal off */ -/* : bl : 4 ; T4 : the duration signal off and Vdd off */ -/* --------------------------------------------------------------------- */ -void XGI_XG21SetPanelDelay(unsigned short tempbl, +static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info, + unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { - unsigned short index; - - index = XGI_GetLVDSOEMTableIndex(pVBInfo); - if (tempbl == 1) - mdelay(pVBInfo->XG21_LVDSCapList[index].PSC_S1); - - if (tempbl == 2) - mdelay(pVBInfo->XG21_LVDSCapList[index].PSC_S2); - - if (tempbl == 3) - mdelay(pVBInfo->XG21_LVDSCapList[index].PSC_S3); - - if (tempbl == 4) - mdelay(pVBInfo->XG21_LVDSCapList[index].PSC_S4); -} - -unsigned char XGI_XG21CheckLVDSMode(unsigned short ModeNo, - unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) -{ - unsigned short xres, yres, colordepth, modeflag, resindex, - lvdstableindex; + unsigned short xres, yres, colordepth, modeflag, resindex; resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); if (ModeNo <= 0x13) { @@ -6061,18 +5838,15 @@ unsigned char XGI_XG21CheckLVDSMode(unsigned short ModeNo, } - lvdstableindex = XGI_GetLVDSOEMTableIndex(pVBInfo); - if (xres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE)) + if (xres > xgifb_info->lvds_data.LVDSHDE) return 0; - if (yres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE)) + if (yres > xgifb_info->lvds_data.LVDSVDE) return 0; if (ModeNo > 0x13) { - if ((xres != (pVBInfo->XG21_LVDSCapList[lvdstableindex]. - LVDSHDE)) || - (yres != (pVBInfo->XG21_LVDSCapList[lvdstableindex]. - LVDSVDE))) { + if (xres != xgifb_info->lvds_data.LVDSHDE || + yres != xgifb_info->lvds_data.LVDSVDE) { colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo); @@ -6084,55 +5858,26 @@ unsigned char XGI_XG21CheckLVDSMode(unsigned short ModeNo, return 1; } -void XGI_SetXG21FPBits(struct vb_device_info *pVBInfo) -{ - unsigned char temp; - - temp = xgifb_reg_get(pVBInfo->P3d4, 0x37); /* D[0] 1: 18bit */ - temp = (temp & 1) << 6; - /* SR06[6] 18bit Dither */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0x40, temp); - /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: dual 12bits */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x09, ~0xc0, temp | 0x80); - -} - -void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo) -{ - unsigned char temp; - - /* D[1:0] 01: 18bit, 00: dual 12, 10: single 24 */ - temp = xgifb_reg_get(pVBInfo->P3d4, 0x37); - temp = (temp & 3) << 6; - /* SR06[7]0: dual 12/1: single 24 [6] 18bit Dither <= 0 h/w recommend */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0xc0, temp & 0x80); - /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: 24bits */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x09, ~0xc0, temp | 0x80); - -} - -static void xgifb_set_lvds(int chip_id, +static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info, + int chip_id, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { unsigned char temp, Miscdata; - unsigned short xres, yres, modeflag, resindex, lvdstableindex; + unsigned short xres, yres, modeflag, resindex; unsigned short LVDSHT, LVDSHBS, LVDSHRS, LVDSHRE, LVDSHBE; unsigned short LVDSVT, LVDSVBS, LVDSVRS, LVDSVRE, LVDSVBE; unsigned short value; - lvdstableindex = XGI_GetLVDSOEMTableIndex(pVBInfo); - temp = (unsigned char) ((pVBInfo->XG21_LVDSCapList[lvdstableindex]. - LVDS_Capability & + temp = (unsigned char) ((xgifb_info->lvds_data.LVDS_Capability & (LCDPolarity << 8)) >> 8); temp &= LCDPolarity; Miscdata = (unsigned char) inb(pVBInfo->P3cc); outb((Miscdata & 0x3F) | temp, pVBInfo->P3c2); - temp = (unsigned char) (pVBInfo->XG21_LVDSCapList[lvdstableindex]. - LVDS_Capability & LCDPolarity); + temp = xgifb_info->lvds_data.LVDS_Capability & LCDPolarity; /* SR35[7] FP VSync polarity */ xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x80, temp & 0x80); /* SR30[5] FP HSync polarity */ @@ -6159,48 +5904,43 @@ static void xgifb_set_lvds(int chip_id, if (!(modeflag & Charx8Dot)) xres = xres * 8 / 9; - LVDSHT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHT; + LVDSHT = xgifb_info->lvds_data.LVDSHT; - LVDSHBS = xres + (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE - - xres) / 2; + LVDSHBS = xres + (xgifb_info->lvds_data.LVDSHDE - xres) / 2; if ((ModeNo <= 0x13) && (modeflag & HalfDCLK)) LVDSHBS -= xres / 4; if (LVDSHBS > LVDSHT) LVDSHBS -= LVDSHT; - LVDSHRS = LVDSHBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHFP; + LVDSHRS = LVDSHBS + xgifb_info->lvds_data.LVDSHFP; if (LVDSHRS > LVDSHT) LVDSHRS -= LVDSHT; - LVDSHRE = LVDSHRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHSYNC; + LVDSHRE = LVDSHRS + xgifb_info->lvds_data.LVDSHSYNC; if (LVDSHRE > LVDSHT) LVDSHRE -= LVDSHT; - LVDSHBE = LVDSHBS + LVDSHT - - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE; + LVDSHBE = LVDSHBS + LVDSHT - xgifb_info->lvds_data.LVDSHDE; - LVDSVT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVT; + LVDSVT = xgifb_info->lvds_data.LVDSVT; - LVDSVBS = yres + (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE - - yres) / 2; + LVDSVBS = yres + (xgifb_info->lvds_data.LVDSVDE - yres) / 2; if ((ModeNo > 0x13) && (modeflag & DoubleScanMode)) LVDSVBS += yres / 2; if (LVDSVBS > LVDSVT) LVDSVBS -= LVDSVT; - LVDSVRS = LVDSVBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVFP; + LVDSVRS = LVDSVBS + xgifb_info->lvds_data.LVDSVFP; if (LVDSVRS > LVDSVT) LVDSVRS -= LVDSVT; - LVDSVRE = LVDSVRS + pVBInfo->XG21_LVDSCapList[lvdstableindex]. - LVDSVSYNC; + LVDSVRE = LVDSVRS + xgifb_info->lvds_data.LVDSVSYNC; if (LVDSVRE > LVDSVT) LVDSVRE -= LVDSVT; - LVDSVBE = LVDSVBS + LVDSVT - - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE; + LVDSVBE = LVDSVBS + LVDSVT - xgifb_info->lvds_data.LVDSVDE; temp = (unsigned char) xgifb_reg_get(pVBInfo->P3d4, 0x11); xgifb_reg_set(pVBInfo->P3d4, 0x11, temp & 0x7f); /* Unlock CRTC */ @@ -6300,13 +6040,9 @@ static void xgifb_set_lvds(int chip_id, xgifb_reg_and_or(pVBInfo->P3c4, 0x31, ~0x30, value); xgifb_reg_set(pVBInfo->P3c4, - 0x2B, - pVBInfo->XG21_LVDSCapList[lvdstableindex]. - VCLKData1); + 0x2B, xgifb_info->lvds_data.VCLKData1); xgifb_reg_set(pVBInfo->P3c4, - 0x2C, - pVBInfo->XG21_LVDSCapList[lvdstableindex]. - VCLKData2); + 0x2C, xgifb_info->lvds_data.VCLKData2); value += 0x10; } @@ -6398,7 +6134,8 @@ static unsigned char XGI_EnableChISLCD(struct vb_device_info *pVBInfo) return 0; } -void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, +static void XGI_DisableBridge(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) { unsigned short tempah = 0; @@ -6442,7 +6179,7 @@ void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, | SetSimuScanMode))) { if (pVBInfo->SetFlag & GatingCRT) XGI_EnableGatingCRT(HwDeviceExtension, pVBInfo); - XGI_DisplayOff(HwDeviceExtension, pVBInfo); + XGI_DisplayOff(xgifb_info, HwDeviceExtension, pVBInfo); } if (pVBInfo->VBInfo & SetCRT2ToLCDA) { @@ -6464,7 +6201,6 @@ void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, ((!(pVBInfo->VBInfo & SetCRT2ToLCDA)) && (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV)))) - /* BScreenOff=1 */ xgifb_reg_or(pVBInfo->Part1Port, 0x00, 0x80); if ((pVBInfo->SetFlag & DisableChB) || @@ -6484,7 +6220,6 @@ void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, } } else { /* {301} */ if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { - /* BScreenOff=1 */ xgifb_reg_or(pVBInfo->Part1Port, 0x00, 0x80); /* Disable CRT2 */ xgifb_reg_and(pVBInfo->Part1Port, 0x1E, 0xDF); @@ -6494,7 +6229,7 @@ void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, if (pVBInfo->VBInfo & (DisableCRT2Display | SetCRT2ToLCDA | SetSimuScanMode)) - XGI_DisplayOff(HwDeviceExtension, pVBInfo); + XGI_DisplayOff(xgifb_info, HwDeviceExtension, pVBInfo); } } @@ -6610,17 +6345,6 @@ static void XGI_SetDelayComp(struct vb_device_info *pVBInfo) if (pVBInfo->VBInfo & SetCRT2ToDualEdge) tempbl = tempbl >> 4; - /* - if (pVBInfo->VBInfo & SetCRT2ToRAMDAC) - tempbl = CRT2Delay1; // Get CRT2 Delay - if (pVBInfo->VBType & - (VB_XGI301B | - VB_XGI302B | - VB_XGI301LV | - VB_XGI302LV | - VB_XGI301C)) - tempbl = CRT2Delay2; - */ if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /* Get LCD Delay */ index = XGI_GetLCDCapPtr(pVBInfo); @@ -6680,23 +6404,6 @@ static void XGI_SetLCDCap_A(unsigned short tempcx, (unsigned short) (0x30 | (tempcx & 0x00C0))); xgifb_reg_and_or(pVBInfo->Part1Port, 0x1A, 0x7F, 0x00); } - - /* - if (tempcx & EnableLCD24bpp) { // 24bits - xgifb_reg_and_or(pVBInfo->Part1Port, - 0x19, - 0x0F, - (unsigned short)(0x30 | (tempcx&0x00C0))); - xgifb_reg_and_or(pVBInfo->Part1Port, 0x1A, 0x7F, 0x00); - } else { - xgifb_reg_and_or(pVBInfo->Part1Port, - 0x19, - 0x0F, - // Enable Dither - (unsigned short)(0x20 | (tempcx&0x00C0))); - xgifb_reg_and_or(pVBInfo->Part1Port, 0x1A, 0x7F, 0x80); - } - */ } /* --------------------------------------------------------------------- */ @@ -6718,6 +6425,25 @@ static void XGI_SetLCDCap_B(unsigned short tempcx, | 0x18)); /* Enable Dither */ } +static void XGI_LongWait(struct vb_device_info *pVBInfo) +{ + unsigned short i; + + i = xgifb_reg_get(pVBInfo->P3c4, 0x1F); + + if (!(i & 0xC0)) { + for (i = 0; i < 0xFFFF; i++) { + if (!(inb(pVBInfo->P3da) & 0x08)) + break; + } + + for (i = 0; i < 0xFFFF; i++) { + if ((inb(pVBInfo->P3da) & 0x08)) + break; + } + } +} + static void SetSpectrum(struct vb_device_info *pVBInfo) { unsigned short index; @@ -6940,14 +6666,12 @@ static void XGI_OEM310Setting(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { - /* GetPart1IO(); */ XGI_SetDelayComp(pVBInfo); if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) XGI_SetLCDCap(pVBInfo); if (pVBInfo->VBInfo & SetCRT2ToTV) { - /* GetPart2IO() */ XGI_SetPhaseIncr(pVBInfo); XGI_SetYFilter(ModeNo, ModeIdIndex, pVBInfo); XGI_SetAntiFlicker(ModeNo, ModeIdIndex, pVBInfo); @@ -6963,7 +6687,7 @@ static void XGI_OEM310Setting(unsigned short ModeNo, /* Output : */ /* Description : Origin code for crt2group */ /* --------------------------------------------------------------------- */ -void XGI_SetCRT2ModeRegs(unsigned short ModeNo, +static void XGI_SetCRT2ModeRegs(unsigned short ModeNo, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) { @@ -6972,8 +6696,6 @@ void XGI_SetCRT2ModeRegs(unsigned short ModeNo, unsigned char tempah; - /* // fix write part1 index 0 BTDRAM bit Bug - * xgifb_reg_set(pVBInfo->Part1Port, 0x03, 0x00); */ tempah = 0; if (!(pVBInfo->VBInfo & DisableCRT2Display)) { tempah = xgifb_reg_get(pVBInfo->Part1Port, 0x00); @@ -6999,32 +6721,6 @@ void XGI_SetCRT2ModeRegs(unsigned short ModeNo, } } - /* 0210 shampoo - if (pVBInfo->VBInfo & DisableCRT2Display) { - tempah = 0; - } - - xgifb_reg_set(pVBInfo->Part1Port, 0x00, tempah); - if (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD)) { - tempcl = pVBInfo->ModeType; - if (ModeNo > 0x13) { - tempcl -= ModeVGA; - if ((tempcl > 0) || (tempcl == 0)) { - tempah=(0x008>>tempcl) ; - if (tempah == 0) - tempah = 1; - tempah |= 0x040; - } - } else { - tempah = 0x040; - } - - if (pVBInfo->VBInfo & SetInSlaveMode) { - tempah = (tempah ^ 0x050); - } - } - */ - xgifb_reg_set(pVBInfo->Part1Port, 0x00, tempah); tempah = 0x08; tempbl = 0xf0; @@ -7093,14 +6789,11 @@ void XGI_SetCRT2ModeRegs(unsigned short ModeNo, tempah |= 0x080; if (pVBInfo->VBInfo & SetCRT2ToTV) { - /* if (!(pVBInfo->TVInfo & - (SetYPbPrMode525p | SetYPbPrMode750p))) { */ tempah |= 0x020; if (ModeNo > 0x13) { if (pVBInfo->VBInfo & DriverMode) tempah = tempah ^ 0x20; } - /* } */ } xgifb_reg_and_or(pVBInfo->Part4Port, 0x0D, ~0x0BF, tempah); @@ -7110,12 +6803,8 @@ void XGI_SetCRT2ModeRegs(unsigned short ModeNo, tempah |= 0x40; if (pVBInfo->VBInfo & SetCRT2ToTV) { - /* if ((!(pVBInfo->VBInfo & SetCRT2ToHiVisionTV)) && - (!(pVBInfo->TVInfo & - (SetYPbPrMode525p | SetYPbPrMode750p)))) { */ if (pVBInfo->TVInfo & RPLLDIV2XO) tempah |= 0x40; - /* } */ } if ((pVBInfo->LCDResInfo == Panel1280x1024) @@ -7219,57 +6908,6 @@ unsigned char XGI_BridgeIsOn(struct vb_device_info *pVBInfo) } } -void XGI_LongWait(struct vb_device_info *pVBInfo) -{ - unsigned short i; - - i = xgifb_reg_get(pVBInfo->P3c4, 0x1F); - - if (!(i & 0xC0)) { - for (i = 0; i < 0xFFFF; i++) { - if (!(inb(pVBInfo->P3da) & 0x08)) - break; - } - - for (i = 0; i < 0xFFFF; i++) { - if ((inb(pVBInfo->P3da) & 0x08)) - break; - } - } -} - -static void XGI_VBLongWait(struct vb_device_info *pVBInfo) -{ - unsigned short tempal, temp, i, j; - return; - if (!(pVBInfo->VBInfo & SetCRT2ToTV)) { - temp = 0; - for (i = 0; i < 3; i++) { - for (j = 0; j < 100; j++) { - tempal = inb(pVBInfo->P3da); - if (temp & 0x01) { /* VBWaitMode2 */ - if ((tempal & 0x08)) - continue; - - if (!(tempal & 0x08)) - break; - - } else { /* VBWaitMode1 */ - if (!(tempal & 0x08)) - continue; - - if ((tempal & 0x08)) - break; - } - } - temp = temp ^ 0x01; - } - } else { - XGI_LongWait(pVBInfo); - } - return; -} - unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) @@ -7322,12 +6960,6 @@ unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE, RefreshRateTableIndex = pVBInfo->EModeIDTable[ModeIdIndex].REFindex; ModeNo = pVBInfo->RefIndex[RefreshRateTableIndex].ModeID; if (pXGIHWDE->jChipType >= XG20) { /* for XG20, XG21, XG27 */ - /* - if (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & - XG2xNotSupport) { - index++; - } - */ if ((pVBInfo->RefIndex[RefreshRateTableIndex].XRes == 800) && (pVBInfo->RefIndex[RefreshRateTableIndex].YRes == 600)) { index++; @@ -7371,7 +7003,7 @@ unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE, temp = XGI_AjustCRT2Rate(ModeNo, ModeIdIndex, RefreshRateTableIndex, &i, pVBInfo); } - return RefreshRateTableIndex + i; /* return (0x01 | (temp1<<1)); */ + return RefreshRateTableIndex + i; } static void XGI_SetLCDAGroup(unsigned short ModeNo, unsigned short ModeIdIndex, @@ -7379,9 +7011,6 @@ static void XGI_SetLCDAGroup(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { unsigned short RefreshRateTableIndex; - /* unsigned short temp ; */ - - /* pVBInfo->SelectCRT2Rate = 0; */ pVBInfo->SetFlag |= ProgrammingCRT2; RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo, @@ -7394,7 +7023,7 @@ static void XGI_SetLCDAGroup(unsigned short ModeNo, unsigned short ModeIdIndex, XGI_SetCRT2ECLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo); } -unsigned char XGI_SetCRT2Group301(unsigned short ModeNo, +static unsigned char XGI_SetCRT2Group301(unsigned short ModeNo, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) { @@ -7499,10 +7128,6 @@ void XGI_SenseCRT1(struct vb_device_info *pVBInfo) outb((unsigned char) DAC_TEST_PARMS[2], (pVBInfo->P3c8 + 1)); } - XGI_VBLongWait(pVBInfo); - XGI_VBLongWait(pVBInfo); - XGI_VBLongWait(pVBInfo); - mdelay(1); XGI_WaitDisply(pVBInfo); @@ -7532,7 +7157,8 @@ void XGI_SenseCRT1(struct vb_device_info *pVBInfo) xgifb_reg_set(pVBInfo->P3c4, 0x1F, (unsigned char) SR1F); } -void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, +static void XGI_EnableBridge(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) { unsigned short tempah; @@ -7544,7 +7170,6 @@ void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, /* Power on */ xgifb_reg_set(pVBInfo->Part1Port, 0x1E, 0x20); } else { - /* SetCRT2ToLCDA ) */ if (pVBInfo->VBInfo & SetCRT2ToDualEdge) { /* Power on */ xgifb_reg_set(pVBInfo->Part1Port, @@ -7572,10 +7197,8 @@ void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, pVBInfo->Part1Port, 0x2E); if (!(tempah & 0x80)) - /* BVBDOENABLE = 1 */ xgifb_reg_or(pVBInfo->Part1Port, 0x2E, 0x80); - /* BScreenOFF = 0 */ xgifb_reg_and(pVBInfo->Part1Port, 0x00, 0x7F); } } @@ -7638,12 +7261,11 @@ void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, xgifb_reg_or(pVBInfo->Part4Port, 0x1F, tempah); if (!(pVBInfo->SetFlag & DisableChA)) { - XGI_VBLongWait(pVBInfo); if (!(pVBInfo->SetFlag & GatingCRT)) { XGI_DisableGatingCRT(HwDeviceExtension, pVBInfo); - XGI_DisplayOn(HwDeviceExtension, pVBInfo); - XGI_VBLongWait(pVBInfo); + XGI_DisplayOn(xgifb_info, HwDeviceExtension, + pVBInfo); } } } /* 301 */ @@ -7656,15 +7278,15 @@ void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, tempah = (unsigned char) xgifb_reg_get(pVBInfo->Part1Port, 0x2E); if (!(tempah & 0x80)) - /* BVBDOENABLE = 1 */ xgifb_reg_or(pVBInfo->Part1Port, 0x2E, 0x80); xgifb_reg_and(pVBInfo->Part1Port, 0x00, 0x7F); - XGI_DisplayOn(HwDeviceExtension, pVBInfo); + XGI_DisplayOn(xgifb_info, HwDeviceExtension, pVBInfo); } /* End of VB */ } -static void XGI_SetCRT1Group(struct xgi_hw_device_info *HwDeviceExtension, +static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { @@ -7672,18 +7294,14 @@ static void XGI_SetCRT1Group(struct xgi_hw_device_info *HwDeviceExtension, unsigned short XGINew_P3cc = pVBInfo->P3cc; - /* XGINew_CRT1Mode = ModeNo; // SaveModeID */ StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo); - /* XGI_SetBIOSData(ModeNo, ModeIdIndex); */ - /* XGI_ClearBankRegs(ModeNo, ModeIdIndex); */ XGI_SetSeqRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo); - XGI_SetMiscRegs(StandTableIndex, pVBInfo); + outb(pVBInfo->StandTable[StandTableIndex].MISC, pVBInfo->P3c2); XGI_SetCRTCRegs(HwDeviceExtension, StandTableIndex, pVBInfo); XGI_SetATTRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo); XGI_SetGRCRegs(StandTableIndex, pVBInfo); XGI_ClearExt1Regs(pVBInfo); - /* if (pVBInfo->IF_DEF_ExpLink) */ if (HwDeviceExtension->jChipType == XG27) { if (pVBInfo->IF_DEF_LVDS == 0) XGI_SetDefaultVCLK(pVBInfo); @@ -7735,11 +7353,6 @@ static void XGI_SetCRT1Group(struct xgi_hw_device_info *HwDeviceExtension, temp = xgifb_reg_get(pVBInfo->P3d4, 0x38); if (temp & 0xA0) { - /* Enable write GPIOF */ - /* xgifb_reg_and(pVBInfo->P3d4, 0x4A, ~0x20); */ - /* P. DWN */ - /* xgifb_reg_and(pVBInfo->P3d4, 0x48, ~0x20); */ - /* XG21 CRT1 Timing */ if (HwDeviceExtension->jChipType == XG27) XGI_SetXG27CRTC(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo); @@ -7754,10 +7367,9 @@ static void XGI_SetCRT1Group(struct xgi_hw_device_info *HwDeviceExtension, pVBInfo, RefreshRateTableIndex, ModeNo); if (pVBInfo->IF_DEF_LVDS == 1) - xgifb_set_lvds(HwDeviceExtension->jChipType, + xgifb_set_lvds(xgifb_info, + HwDeviceExtension->jChipType, ModeNo, ModeIdIndex, pVBInfo); - /* P. ON */ - /* xgifb_reg_or(pVBInfo->P3d4, 0x48, 0x20); */ } } @@ -7765,22 +7377,16 @@ static void XGI_SetCRT1Group(struct xgi_hw_device_info *HwDeviceExtension, XGI_SetCRT1FIFO(ModeNo, HwDeviceExtension, pVBInfo); XGI_SetCRT1ModeRegs(HwDeviceExtension, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo); - - /* XGI_LoadCharacter(); //dif ifdef TVFont */ - XGI_LoadDAC(ModeNo, ModeIdIndex, pVBInfo); - /* XGI_ClearBuffer(HwDeviceExtension, ModeNo, pVBInfo); */ } -unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, +unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo) { unsigned short ModeIdIndex; - /* unsigned char *pVBInfo->FBAddr = - HwDeviceExtension->pjVideoMemoryAddress; */ struct vb_device_info VBINF; struct vb_device_info *pVBInfo = &VBINF; - pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase; pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress; pVBInfo->IF_DEF_LVDS = 0; pVBInfo->IF_DEF_LCDA = 1; @@ -7831,14 +7437,8 @@ unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, XGI_GetVBType(pVBInfo); InitTo330Pointer(HwDeviceExtension->jChipType, pVBInfo); - if (ModeNo & 0x80) { + if (ModeNo & 0x80) ModeNo = ModeNo & 0x7F; - /* XGINew_flag_clearbuffer = 0; */ - } - /* else { - XGINew_flag_clearbuffer = 1; - } - */ xgifb_reg_set(pVBInfo->P3c4, 0x05, 0x86); if (HwDeviceExtension->jChipType < XG20) /* kuku 2004/06/25 1.Openkey */ @@ -7846,16 +7446,14 @@ unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, XGI_SearchModeID(ModeNo, &ModeIdIndex, pVBInfo); - XGI_GetVGAType(HwDeviceExtension, pVBInfo); - if (HwDeviceExtension->jChipType < XG20) { /* kuku 2004/06/25 */ XGI_GetVBInfo(ModeNo, ModeIdIndex, HwDeviceExtension, pVBInfo); XGI_GetTVInfo(ModeNo, ModeIdIndex, pVBInfo); XGI_GetLCDInfo(ModeNo, ModeIdIndex, pVBInfo); - XGI_DisableBridge(HwDeviceExtension, pVBInfo); + XGI_DisableBridge(xgifb_info, HwDeviceExtension, pVBInfo); if (pVBInfo->VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) { - XGI_SetCRT1Group(HwDeviceExtension, ModeNo, + XGI_SetCRT1Group(xgifb_info, HwDeviceExtension, ModeNo, ModeIdIndex, pVBInfo); if (pVBInfo->VBInfo & SetCRT2ToLCDA) { @@ -7864,7 +7462,8 @@ unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, } } else { if (!(pVBInfo->VBInfo & SwitchToCRT2)) { - XGI_SetCRT1Group(HwDeviceExtension, ModeNo, + XGI_SetCRT1Group(xgifb_info, + HwDeviceExtension, ModeNo, ModeIdIndex, pVBInfo); if (pVBInfo->VBInfo & SetCRT2ToLCDA) { XGI_SetLCDAGroup(ModeNo, ModeIdIndex, @@ -7894,11 +7493,11 @@ unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, XGI_SetCRT2ModeRegs(ModeNo, HwDeviceExtension, pVBInfo); XGI_OEM310Setting(ModeNo, ModeIdIndex, pVBInfo); /*0212*/ XGI_CloseCRTC(HwDeviceExtension, pVBInfo); - XGI_EnableBridge(HwDeviceExtension, pVBInfo); + XGI_EnableBridge(xgifb_info, HwDeviceExtension, pVBInfo); } /* !XG20 */ else { if (pVBInfo->IF_DEF_LVDS == 1) - if (!XGI_XG21CheckLVDSMode(ModeNo, + if (!XGI_XG21CheckLVDSMode(xgifb_info, ModeNo, ModeIdIndex, pVBInfo)) return 0; @@ -7914,39 +7513,13 @@ unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, pVBInfo->SetFlag = 0; pVBInfo->VBInfo = DisableCRT2Display; - XGI_DisplayOff(HwDeviceExtension, pVBInfo); + XGI_DisplayOff(xgifb_info, HwDeviceExtension, pVBInfo); - XGI_SetCRT1Group(HwDeviceExtension, ModeNo, ModeIdIndex, - pVBInfo); + XGI_SetCRT1Group(xgifb_info, HwDeviceExtension, ModeNo, + ModeIdIndex, pVBInfo); - XGI_DisplayOn(HwDeviceExtension, pVBInfo); - /* - if (HwDeviceExtension->jChipType == XG21) - xgifb_reg_and_or(pVBInfo->P3c4, 0x09, ~0x80, 0x80); - */ - } - - /* - if (ModeNo <= 0x13) { - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + XGI_DisplayOn(xgifb_info, HwDeviceExtension, pVBInfo); } - pVBInfo->ModeType = modeflag&ModeInfoFlag; - pVBInfo->SetFlag = 0x00; - pVBInfo->VBInfo = DisableCRT2Display; - temp = XGINew_CheckMemorySize(HwDeviceExtension, - ModeNo, - ModeIdIndex, - pVBInfo); - - if (temp == 0) - return (0); - - XGI_DisplayOff(HwDeviceExtension, pVBInfo) ; - XGI_SetCRT1Group(HwDeviceExtension, ModeNo, ModeIdIndex, pVBInfo); - XGI_DisplayOn(HwDeviceExtension, pVBInfo); - */ XGI_UpdateModeInfo(HwDeviceExtension, pVBInfo); diff --git a/drivers/staging/xgifb/vb_setmode.h b/drivers/staging/xgifb/vb_setmode.h index 1bd8667ff5c..552482858c1 100644 --- a/drivers/staging/xgifb/vb_setmode.h +++ b/drivers/staging/xgifb/vb_setmode.h @@ -6,66 +6,22 @@ extern void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *); extern void XGI_LockCRT2(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *); -extern void XGI_LongWait(struct vb_device_info *); -extern void XGI_SetCRT2ModeRegs(unsigned short ModeNo, - struct xgi_hw_device_info *, - struct vb_device_info *); -extern void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *); -extern void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *); -extern void XGI_DisplayOff(struct xgi_hw_device_info *, +extern void XGI_DisplayOff(struct xgifb_video_info *, + struct xgi_hw_device_info *, struct vb_device_info *); -extern void XGI_DisplayOn(struct xgi_hw_device_info *, - struct vb_device_info *); extern void XGI_GetVBType(struct vb_device_info *); extern void XGI_SenseCRT1(struct vb_device_info *); -extern void XGI_GetVGAType(struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *); -extern void XGI_GetVBInfo(unsigned short ModeNo, - unsigned short ModeIdIndex, - struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *); -extern void XGI_GetTVInfo(unsigned short ModeNo, - unsigned short ModeIdIndex, - struct vb_device_info *); -extern unsigned short XGI_GetResInfo(unsigned short ModeNo, - unsigned short ModeIdIndex, - struct vb_device_info *pVBInfo); - -extern unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, +extern unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info, + struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo) ; extern unsigned char XGI_SearchModeID(unsigned short ModeNo, unsigned short *ModeIdIndex, struct vb_device_info *); -extern unsigned char XGI_GetLCDInfo(unsigned short ModeNo, - unsigned short ModeIdIndex, - struct vb_device_info *); extern unsigned char XGI_BridgeIsOn(struct vb_device_info *); - -extern unsigned char -XGI_SetCRT2Group301(unsigned short ModeNo, - struct xgi_hw_device_info *HwDeviceExtension, - struct vb_device_info *); extern unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *); -extern void XGI_SetXG21FPBits(struct vb_device_info *pVBInfo); -extern void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo); -extern void XGI_XG21BLSignalVDD(unsigned short tempbh, - unsigned short tempbl, - struct vb_device_info *pVBInfo); -extern void XGI_XG27BLSignalVDD(unsigned short tempbh, - unsigned short tempbl, - struct vb_device_info *pVBInfo); -extern void XGI_XG21SetPanelDelay(unsigned short tempbl, - struct vb_device_info *pVBInfo); -extern unsigned char XGI_XG21CheckLVDSMode(unsigned short ModeNo, - unsigned short ModeIdIndex, - struct vb_device_info *pVBInfo); -extern unsigned short XGI_GetLVDSOEMTableIndex(struct vb_device_info *pVBInfo); - #endif diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h index f9ade6f9f7e..6556a0d6ff8 100644 --- a/drivers/staging/xgifb/vb_struct.h +++ b/drivers/staging/xgifb/vb_struct.h @@ -293,13 +293,12 @@ struct vb_device_info { unsigned short IF_DEF_ExpLink; unsigned short IF_DEF_HiVision; unsigned short LCDResInfo, LCDTypeInfo, VBType;/*301b*/ - unsigned short VBInfo, TVInfo, LCDInfo, Set_VGAType; + unsigned short VBInfo, TVInfo, LCDInfo; unsigned short VBExtInfo;/*301lv*/ unsigned short SetFlag; unsigned short NewFlickerMode; unsigned short SelectCRT2Rate; - unsigned char *ROMAddr; void __iomem *FBAddr; unsigned long BaseAddr; unsigned long RelIO; @@ -376,7 +375,6 @@ struct vb_device_info { unsigned char *pXGINew_CR97 ; struct XGI330_LCDCapStruct *LCDCapList; - struct XGI21_LVDSCapStruct *XG21_LVDSCapList; struct XGI_TimingHStruct *TimingH; struct XGI_TimingVStruct *TimingV; diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h index b81ac7726d1..e7946f1c114 100644 --- a/drivers/staging/xgifb/vb_table.h +++ b/drivers/staging/xgifb/vb_table.h @@ -2569,33 +2569,6 @@ static struct XGI330_LCDCapStruct XGI_LCDCapList[] = { 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10} }; -struct XGI21_LVDSCapStruct XGI21_LCDCapList[] = { - {DisableLCD24bpp + LCDPolarity, - 2160, 1250, 1600, 1200, 64, 1, 192, 3, - 0x70, 0x24, 0x20, 0x04, 0x0A, 0x02, 0xC8 - }, - {DisableLCD24bpp + LCDPolarity, - 1688, 1066, 1280, 1024, 48, 1, 112, 3, - 0x70, 0x44, 0x20, 0x04, 0x0A, 0x02, 0xC8 - }, - {DisableLCD24bpp + LCDPolarity + (LCDPolarity << 8), - 1344, 806, 1024, 768, 24, 3, 136, 6, - 0x6C, 0x65, 0x20, 0x04, 0x0A, 0x02, 0xC8 - }, - {DisableLCD24bpp + LCDPolarity, - 1056, 628, 800, 600, 40, 1, 128, 4, - 0x42, 0xE2, 0x20, 0x14, 0x0A, 0x02, 0x00 - }, - {DisableLCD24bpp + LCDPolarity, - 928, 525, 800, 480, 40, 13, 48, 3, - 0x52, 0xC5, 0x20, 0x14, 0x0A, 0x02, 0x00 - }, - {DisableLCD24bpp + LCDPolarity + (LCDPolarity << 8), - 800, 525, 640, 480, 16, 10, 96, 2, - 0x1B, 0xE1, 0x20, 0x04, 0x0A, 0x02, 0xC8 - } -}; - static struct XGI_Ext2Struct XGI330_RefIndex[] = { {Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175, 0x00, 0x10, 0x59, 320, 200},/* 00 */ diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h index 9b939b75c30..9e166bbb00c 100644 --- a/drivers/staging/xgifb/vgatypes.h +++ b/drivers/staging/xgifb/vgatypes.h @@ -51,8 +51,6 @@ struct xgi_hw_device_info { unsigned long ulExternalChip; /* NO VB or other video bridge*/ /* if ujVBChipID = VB_CHIP_UNKNOWN, */ - unsigned char *pjVirtualRomBase; /* ROM image */ - void __iomem *pjVideoMemoryAddress;/* base virtual memory address */ /* of Linear VGA memory */ diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index 56c1f9c80dc..642840c612a 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -787,7 +787,7 @@ static ssize_t zv_max_zsize_store(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - err = strict_strtoul(buf, 10, &val); + err = kstrtoul(buf, 10, &val); if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7)) return -EINVAL; zv_max_zsize = val; @@ -819,7 +819,7 @@ static ssize_t zv_max_mean_zsize_store(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - err = strict_strtoul(buf, 10, &val); + err = kstrtoul(buf, 10, &val); if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7)) return -EINVAL; zv_max_mean_zsize = val; @@ -853,7 +853,7 @@ static ssize_t zv_page_count_policy_percent_store(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - err = strict_strtoul(buf, 10, &val); + err = kstrtoul(buf, 10, &val); if (err || (val == 0) || (val > 150)) return -EINVAL; zv_page_count_policy_percent = val; diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 09de99fbb7e..2a2a92d389e 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -653,7 +653,8 @@ int zram_init_device(struct zram *zram) goto fail_no_table; } - zram->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1); + zram->compress_buffer = + (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); if (!zram->compress_buffer) { pr_err("Error allocating compressor buffer space\n"); ret = -ENOMEM; diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c index 0ea8ed296a9..d521122826f 100644 --- a/drivers/staging/zram/zram_sysfs.c +++ b/drivers/staging/zram/zram_sysfs.c @@ -58,7 +58,7 @@ static ssize_t disksize_store(struct device *dev, u64 disksize; struct zram *zram = dev_to_zram(dev); - ret = strict_strtoull(buf, 10, &disksize); + ret = kstrtoull(buf, 10, &disksize); if (ret) return ret; @@ -88,7 +88,7 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { int ret; - unsigned long do_reset; + unsigned short do_reset; struct zram *zram; struct block_device *bdev; @@ -99,7 +99,7 @@ static ssize_t reset_store(struct device *dev, if (bdev->bd_holders) return -EBUSY; - ret = strict_strtoul(buf, 10, &do_reset); + ret = kstrtou16(buf, 10, &do_reset); if (ret) return ret; diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index 83d3fe7ec9a..4ea17dc3258 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig @@ -1,6 +1,6 @@ menuconfig FB_OMAP2 tristate "OMAP2+ frame buffer support" - depends on FB && OMAP2_DSS + depends on FB && OMAP2_DSS && !DRM_OMAP select OMAP2_VRAM select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 12ec328481d..62b908e0e59 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -35,7 +35,7 @@ #include <linux/mod_devicetable.h> -#define MAX_PAGE_BUFFER_COUNT 16 +#define MAX_PAGE_BUFFER_COUNT 18 #define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */ #pragma pack(push, 1) |